Mercurial > ~dholland > hg > ag > index.cgi
view anagram/support/log.cpp @ 6:607e3be6bad8
Adjust to the moving target called the C++ standard.
Apparently nowadays it's not allowed to define an explicit copy
constructor but not an assignment operator. Consequently, defining the
explicit copy constructor in terms of the implicit/automatic
assignment operator for general convenience no longer works.
Add assignment operators.
Caution: not tested with the IBM compiler, but there's no particular
reason it shouldn't work.
author | David A. Holland |
---|---|
date | Mon, 30 May 2022 23:46:22 -0400 |
parents | 13d2b8934445 |
children |
line wrap: on
line source
/* * AnaGram, A System for Syntax Directed Programming * Copyright 1993-2002 Parsifal Software. All Rights Reserved. * Copyright 2006 David A. Holland. All Rights Reserved. * See the file COPYING for license and usage terms. * * log.cpp - logging module. * * To use the logging stuff, turn on INCLUDE_LOGGING here and in * the source files you want to log from. Then create a file called * "aglog.ctl" contaning lines of the form * +foo * -foo * to turn logging on or off (respectively) for LOGSECTION names * matching "foo". With Unix builds, "foo" can be a shell glob (like * "check_*") but owing to the lack of library support this is not * supported in Windows. The control settings are applied in order. * * The log entries land in the file "ag.log", which is truncated with * every new execution. */ #include <stdarg.h> #include <stdio.h> #include <string.h> #include <time.h> #ifdef AG_ON_UNIX #include <fnmatch.h> #endif #ifdef VACLGUI //#include <icritsec.hpp> //#include "resource.h" #endif #include "port.h" #include "agstring.h" #include "agstack.h" #include "textfile.h" //#define INCLUDE_LOGGING #include "log.h" #define PATH_LOGFILE "ag.log" #define PATH_CTLFILE "aglog.ctl" #define INDENT 3 #ifdef INCLUDE_LOGGING static int initialized = 0; static FILE *logfile = NULL; static LogSwitch masterswitch = LOG_OFF; static int indent = 0; static LogSection *sectionstack = NULL; // This must be a pointer, not a global object, in case someone wants to // log from a global constructor somewhere. static AgStack<AgString> *matches; //////////////////////////////////////////////////////////// static int readcontrol(void) { LOGSECTION_ON("readcontrol"); text_file control(PATH_CTLFILE); if ((char *)control == 0) { //printf("Log: failed to open control file %s\n", PATH_CTLFILE); return -1; } //printf("Log: control file read\n"); unsigned num_control_lines = control.size().y; //printf("Log: trying to log something\n"); LOGV(num_control_lines); //printf("Log: processing control file\n"); for (unsigned i = 0; i < num_control_lines; i++) { char *line = control.line(i); while (*line==' ') { line++; } char *p = strchr(line, '\n'); if (p) { *p = 0; if (p != line && p[-1]=='\r') { *(--p) = 0; } } else { p = line + strlen(line); } while (p != line && p[-1]==' ') { *(--p) = 0; } if (*line==0 || *line=='#') { continue; } LOGV(line); if ((*line!='+' && *line!='-') || strlen(line)==1) { LOGS("...line is invalid"); continue; } matches->push(AgString(line)); } return 0; } static LogSwitch checkcontrol(const char *name) { unsigned i, n = matches->size(); for (i=0; i<n; i++) { const char *ctl = (*matches)[i].pointer(); assert(ctl[0] == '+' || ctl[0] == '-'); int matched; #ifdef AG_ON_UNIX matched = !fnmatch(ctl+1, name, 0); #else if (!strcmp(ctl+1, "*")) { matched = 1; } else { matched = !strcmp(ctl+1, name); } #endif if (matched) { return ctl[0] == '+' ? LOG_ON : LOG_OFF; } } return LOG_MAYBE; } //////////////////////////////////////////////////////////// static int loginit(void) { if (initialized) { return 0; } //printf("Log: initializing\n"); logfile = fopen(PATH_LOGFILE, "w"); if (!logfile) { //printf("Log: failed to open output file %s\n", PATH_LOGFILE); return -1; } //printf("Log: opened output file\n"); fprintf(logfile, "*** AnaGram log file ***\n"); masterswitch = LOG_ON; initialized = 1; matches = new AgStack<AgString>; if (readcontrol()) { fprintf(logfile, "\nReading control file %s failed\n", PATH_CTLFILE); fclose(logfile); logfile = NULL; initialized = 0; delete matches; matches = NULL; masterswitch = LOG_OFF; return -1; } masterswitch = LOG_OFF; //printf("Log: done initializing\n"); return 0; } #if 0 /* no way to reach this */ static void logclose(void) { if (initialized) { assert(logfile != NULL); fclose(logfile); logfile = NULL; delete matches; matches = NULL; masterswitch = LOG_OFF; initialized = 0; } } #endif /* 0 */ LogSection::LogSection(const char *name_, LogSwitch caller_requested) { if (loginit()) return; previous = sectionstack; sectionstack = this; name = name_; saved_switch = masterswitch; // get setting instructed via the control file masterswitch = LOG_ON; LogSwitch ctl_setting = checkcontrol(name); masterswitch = LOG_OFF; // the control file takes precedence, unless it says "maybe" LogSwitch new_setting; if (ctl_setting != LOG_MAYBE) { new_setting = ctl_setting; } else { new_setting = caller_requested; } if (new_setting == LOG_ON) { masterswitch = LOG_ON; logeol(), dolog("BEGIN "), dolog(name), dolog(" "), logtime(); indent += INDENT; } } LogSection::~LogSection() { if (!initialized) return; if (masterswitch == LOG_ON) { indent -= INDENT; logeol(), dolog("END "), dolog(name), dolog(" "), logtime(); } masterswitch = saved_switch; sectionstack = previous; } void LogSection::logstack(void) { LOGSECTION("logsectionstack"); LogSection *s = sectionstack; while (s) { logeol(), dolog(s->name); s = s->previous; } } void logeol(void) { if (loginit() || masterswitch == LOG_OFF) return; assert(logfile != NULL); fprintf(logfile, "\n%*s", indent, ""); fflush(logfile); } static void logf(const char *fmt, ...) { if (loginit() || masterswitch == LOG_OFF) return; assert(logfile != NULL); va_list ap; va_start(ap, fmt); vfprintf(logfile, fmt, ap); va_end(ap); fflush(logfile); } void dolog(const char *s) { logf("%s", s); } void dolog(const AgString &s) { logf("%s", s.pointer()); } void dolog(void *p) { logf("%p", p); } void dolog(int n) { logf("%d", n); } void dolog(cint p) { logf("(%d, %d)", p.x, p.y); } void logtime(void) { char buf[64]; time_t timer = time(NULL); struct tm *t = gmtime(&timer); strftime(buf, sizeof(buf), "%Y%m%d %T", t); logf("%s", buf); } #ifdef VACLGUI void dolog(const IString &s) { logf("%s", (const char *) s); } void dolog(const IPair &p) { logf("%s", p.asString()); } void dolog(const IRectangle &r) { logf("%s", r.asString()); } void logexception(IException &ie) { if (loginit() || masterswitch == LOG_OFF) return; LOGSECTION_ON("Exception"); logeol(), dolog(ie.name()), dolog(ie.text()); int n = ie.locationCount(); for (int i = 0; i < n; i++) { const IExceptionLocation *loc = ie.locationAtIndex(i); logeol(), dolog("File: "), dolog(loc->fileName()); logeol(), dolog("Line: "), dolog(loc->lineNumber()); logeol(), dolog("Function: "), dolog(loc->functionName()); } } #endif /* VACLGUI */ #else /* not INCLUDE_LOGGING */ #ifdef __IBMCPP__ /* without this, the librarian bombs */ void ibmcpp_is_stupid_in_log_cpp(void) {} #endif #endif /* INCLUDE_LOGGING */