// // ac_log.c - debug logging // // Copyright (C) 2006 Nathan (Acorn) Pooley // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // version 2 as published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License (gpl.txt) for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // You can contact the author, Nathan (Acorn) Pooley, by writing // to Nathan (Acorn) Pooley, 949 Buckeye Drive, Sunnyvale, CA 94086, USA // or through the form at http://www.rawbw.com/~acorn/wand/feedback.html // //#@DOC@ debug logging functions //########################################################################### //############################### INCLUDES ################################## //########################################################################### #include "ac_log.h" #include <stdio.h> #include <stdarg.h> #include <stdlib.h> #include <string.h> #include <ctype.h> //########################################################################### //############################### DEFINES ################################### //########################################################################### #define DEFAULT_FILENAME "log.txt" //########################################################################### //############################### TYPEDEFS ################################## //########################################################################### struct AcLogRec { char *filename; FILE *fp; int source; char **sourceNames; int sourceCnt; int debugLevel; int lastPrintSource; int lastPrintLevel; int lastPrintCr; int lastLogSource; int lastLogCr; char *prompt; }; //########################################################################### //############################### PROTOTYPES ################################ //########################################################################### //########################################################################### //############################### GLOBALS ################################### //########################################################################### static AcLog g_default_log; //########################################################################### //############################### CODE ###################################### //########################################################################### //=========================================================================== // AcLogFlush() //=========================================================================== void AcLogFlush(AcLog *li) { if (!li) li = &g_default_log; if (li && li->fp) { fflush(li->fp); } } //=========================================================================== // AcLogDestroy() //=========================================================================== void AcLogDestroy(AcLog *li) { if (!li && g_default_log.fp) li = &g_default_log; if (li->fp) { fflush(li->fp); fclose(li->fp); li->fp = 0; } if (li->sourceNames) { int i; for (i=0; i<li->sourceCnt; i++) { if (li->sourceNames[i]) { free(li->sourceNames[i]); } } free(li->sourceNames); li->sourceNames = 0; } if (&g_default_log == li) { return; } if (li->filename) { free(li->filename); } if (li->prompt) { free(li->prompt); } free(li); } //=========================================================================== // AcLogCreate() //=========================================================================== AcLog *AcLogCreate(char *filename, int append, int isdefault) { AcLog *li; if (!filename) { li = &g_default_log; if (!li->filename) { li->filename = strdup(DEFAULT_FILENAME); } else if (li->fp && li->sourceNames && isdefault) { return li; } isdefault = 1; } else if (g_default_log.filename && !strcmp(g_default_log.filename, filename)) { li = &g_default_log; isdefault = 1; } else { if (isdefault) { li = &g_default_log; } else { li = calloc(1,sizeof(AcLog)); } if (li->filename) { if (li->fp && strcmp(filename,li->filename)) { fclose(li->fp); li->fp = 0; } free(li->filename); } li->filename = strdup(filename); } if (!li->fp) { if (append) { li->fp = fopen(li->filename,"a"); } else { li->fp = fopen(li->filename,"w"); } if (!li->fp) { fprintf(stderr,"AcLogCreate: Could not write %s\n",filename); return 0; } li->source = -1; } if (!li->sourceNames) { li->sourceNames = malloc(sizeof(char*)); li->sourceCnt = 1; li->sourceNames[0] = strdup("default"); } fprintf(li->fp,"\n======================= Begin log %s\n",li->filename); li->lastLogSource = -1; li->lastLogCr = 1; li->lastPrintSource = -1; li->lastPrintLevel = -1; li->lastPrintCr = 1; li->prompt = strdup("> "); return li; } //=========================================================================== // AcLogSetDebugLevel() //=========================================================================== void AcLogSetDebugLevel(AcLog *li, int val) { li->debugLevel = val; } //=========================================================================== // AcLogCreateSource() //=========================================================================== int AcLogCreateSource(AcLog *li, const char *name) { char **list; if (!li) { li = AcLogCreate(0,1,1); if (!li || !li->sourceNames) { return 0; } } list = realloc(li->sourceNames,sizeof(char*)*(li->sourceCnt + 1)); if (!list) return 0; li->sourceNames = list; list[li->sourceCnt] = strdup(name); return li->sourceCnt++; } //=========================================================================== // AcLogWrite() //=========================================================================== void AcLogWrite(AcLog *li, int source, const char *buf, unsigned int cnt) { char *sname = 0; char buf7[1000]; char buf8[1000]; char buf9[1000]; char *p7 = buf7; char *p8 = buf8; char *p9 = buf9; int i = 0; if (!li) { li = AcLogCreate(0,1,1); if (!li) { return; } } if (!li->fp) { return; } if (source >= 0 && source<li->sourceCnt) { sname = li->sourceNames[source]; } // // sources with names not beginning '+' print normally (no ascii hex) // if (sname && sname[0] && sname[0]!='+') { if (!cnt) return; if (li->lastLogSource != source) { if (!li->lastLogCr) { fprintf(li->fp,"\n"); } fprintf(li->fp,"#### Source %3d %s\n", source, sname?sname:""); } fprintf(li->fp,"%s",buf); if (buf[cnt-1] == '\n') { li->lastLogCr = 1; } else { li->lastLogCr = 0; } li->lastLogSource = source; return; } if (!li->lastLogCr) { fprintf(li->fp,"\n"); } fprintf(li->fp,"#### Source %3d %s\n", source, sname?sname:""); li->lastLogSource = source; li->lastLogCr = 1; while(1) { int c; if (i>=cnt || (i&0x7)==0) { if (p7!=buf7) { fprintf(li->fp," %-42s %-8s %s\n",buf7,buf8,buf9); p7 = buf7; p8 = buf8; p9 = buf9; } if (i>=cnt) break; } c = buf[i]; if (c<' ' || c>'}' || c=='\\') { p9 += sprintf(p9,"\\%02x",((unsigned char*)buf)[i]); } else { p9 += sprintf(p9,"%c",c); } if (c<=' ' || c>'}') c = '.'; p7 += sprintf(p7,"0x%02x ",((unsigned char*)buf)[i]); p8 += sprintf(p8,"%c",c); i++; } } //=========================================================================== // AcLogPrintf() //=========================================================================== int AcLogPrintf(AcLog *li, int source, const char *fmt, ...) { int cnt; va_list va; char buf[1000]; char *bufp = buf; int printLevel = 1000; if (!li) { li = AcLogCreate(0,1,1); if (!li) { return 0; } } va_start(va, fmt); cnt = vsnprintf(buf,sizeof(buf)-1,fmt,va); va_end(va); if (cnt>1 && buf[1]==':') { int val = buf[0]; if (isdigit(val)) { val = val - '0'; } else if (islower(val)) { val = val - 'a' + 10; } else if (isupper(val)) { val = val - 'A' + 10 + 26; } else { val = -1; } if (val >= 0) { printLevel = val; bufp = buf+2; cnt -= 2; } } if (!cnt) return 0; if (printLevel <= li->debugLevel) { if (li->lastPrintCr == 0 && (li->lastPrintSource != source || li->lastPrintLevel != printLevel)) { printf("\n"); } printf("%s",bufp); if (bufp[cnt-1] == '\n') { li->lastPrintCr = 1; } else { li->lastPrintCr = 0; } li->lastPrintSource = source; li->lastPrintLevel = printLevel; } AcLogWrite(li,source,bufp,cnt); return cnt; } //=========================================================================== // AcLogPrompt() //=========================================================================== // // Print prompt. // If prompt is NULL then print last prompt. // force: // 1 = always print prompt // 0 = only print prompt if something was printed since last one, or // if string has changed. // -1 = do not print prompt (just set it) // -2 = do not print prompt, but do print next time called with force=0 // void AcLogPrompt(AcLog *li, char *prompt, int force) { if (!li) { li = AcLogCreate(0,1,1); if (!li) { printf("\n%s",prompt?prompt:"> "); } } if (prompt && strcmp(prompt,li->prompt)) { free(li->prompt); li->prompt = strdup(prompt); if (force == 0) force = 1; } if (force == -2) { if (li->lastPrintLevel == -2) { li->lastPrintLevel = -1; } return; } // // printlevel -2 indicates prompt // if (force==0 && li->lastPrintLevel != -2) { force = 1; } if (force > 0) { if (li->lastPrintCr == 0) { printf("\n"); } printf("%s",li->prompt); fflush(stdout); li->lastPrintCr = 0; li->lastPrintLevel = -2; } } |
This file Copyright (C) 2006 by Nathan (Acorn) Pooley
Go to TOP Wand page
Go to Acorn's personal webpage
Go to Hogwarts website: www.gotohogwarts.com
Snout: www.snout.org/game
Gadgets of Justice Unlimited
Snout GC (Wiki)
Snout Wiki
File created by do_doc at Wed May 30 03:25:00 PDT 2007