| top | | | ^ | | | | | | section top | |
Obj r = incr(Tcl_NewObj()),p;
int n; chars s; char c;
int class;
if (strbegins("%q",format)) {
class = va_arg(L,int); format += 2;
}else
class = ' ';
switch (class) {
case TCL_OK: case TCL_RETURN: class = 'R'; break;
case TCL_ERROR: class = 'E'; break;
case TCL_BREAK: class = 'B'; break;
case TCL_CONTINUE: class = 'C'; break;
}
int max;
if (perm>=0) {
if (perm>26) perm = 26;
<Timestamp current clock>
Tcl_AppendObjToObj(r,(p=oprintf("%c%s.",perm+'A',hhmmss))); decr(p);
addPidToObj;
Tcl_AppendObjToObj(r,(p=oprintf("%c.",class))); decr(p);
max = 865;
}else {
max = 80;
}
int e = Tcl_GetCharLength(r);
while (*format && Tcl_GetCharLength(r)<max) {
int n;
if (*format!='%') {
Tcl_AppendToObj(r,format,1); format++;
}else if (format++, isdigit(*format) ? ((n=strtol(format+1,&format,0)),*format=='s') : false) {
s = va_arg(L,chars);
if (strlen(s)<n) n = strlen(s);
goto string;
}else switch (*format++) {
case 's':
s = va_arg(L,chars); n = 255;
if (strlen(s)<n) n = strlen(s);
string:
while (n-->0) {
c = *s++;
if (!isascii(c)) c = '.';
else if (isspace(c)) c = ' ';
else if (iscntrl(c)) c = '.';
Tcl_AppendToObj(r,&c,1);
}
break;
case 'o': {
Obj arg = va_arg(L,Obj);
s = Tcl_GetStringFromObj(arg,&n);
if (n>255) n = 255;
} goto string;
case 'r': {
Intr arg = va_arg(L,Intr);
Obj obj = incr(Tcl_GetObjResult(arg));
s = Tcl_GetStringFromObj(obj,&n);
if (n>255) n = 255;
} goto string;
case 'c':
c = va_arg(L,int); s = &c; n = 1;
goto string;
case 'b':
Tcl_AppendObjToObj(r,(p=oprintf("%02X",va_arg(L,unsigned)))); decr(p);
break;
case 'h':
Tcl_AppendObjToObj(r,(p=oprintf("%04X",va_arg(L,unsigned)))); decr(p);
break;
case 'w':
Tcl_AppendObjToObj(r,(p=oprintf("%08lX",va_arg(L,unsigned long)))); decr(p);
break;
case 'x':
Tcl_AppendObjToObj(r,(p=oprintf("%016llX",va_arg(L,unsigned long long)))); decr(p);
break;
case 'd':
Tcl_AppendObjToObj(r,(p=oprintf("%ld",va_arg(L,long)))); decr(p);
break;
case 'D':
Tcl_AppendObjToObj(r,(p=oprintf("%lld",va_arg(L,long long)))); decr(p);
break;
default:
s = format-1; n = 1;
goto string;
}
}
if (Tcl_GetCharLength(r)>max) Tcl_SetObjLength(r,max);
| ^ | | | | | | section top | |
#define addPidToObj (Tcl_AppendObjToObj(r,(p=oprintf("%04X.",getpid()))), decr(p))
| ^ | | | | | | section top | |
static chars argv0 = "?";
static char line[2][81] = {{0},{0}};
| ^ | Definition continued at: 54, 93. | | | | | section top | |
case o_dayfilep:
if (N==3) {
class = ' ';
goto o_dayfile;
}else if (N==4) {
s = Tcl_GetStringFromObj(P[2],&n);
if (n!=1) return rprintf(intr,"%!dayfile message class must be one character",TCL_ERROR);
class = *s;
goto o_dayfile;
}else {
Tcl_WrongNumArgs(intr,1,P0,"[permanency] [class] message");
return TCL_ERROR;
}
case o_dayfilec:
class = *s;
if (N==3) {
perm = 0;
goto o_dayfile;
}else if (N==4) {
if (Tcl_GetIntFromObj(intr,P[2],&perm)!=TCL_OK) return TCL_ERROR;
goto o_dayfile;
}else {
Tcl_WrongNumArgs(intr,1,P0,"[class] [permanency] message");
return TCL_ERROR;
}
o_dayfile:
wyrm_dayfile(perm,"%q%o",class,P[N-1]);
Tcl_ResetResult(intr);
return TCL_OK;
| ^ | | | | | | section top | |
static void vdayfile(int perm,chars format0,va_list L) {
chars format = format0;
<Encode a message>
va_end(L);
if (perm<=0) {
int l = perm?-perm-1:0;
int n; chars s = Tcl_GetStringFromObj(r,&n);
n -= e; s += e;
if (n>80) n = 80;
memcpy(line[l],s,n); line[l][n] = 0;
<Update shell status>
if (anyStatusWidget) {
<Update line 1/line2 status widgets>
}
}
Tcl_AppendToObj(r,"\n",1);
s = Tcl_GetStringFromObj(r,&n);
if (perm>=0) {
addBufferMessage(m,s,0,n,0);
}
if (perm==0 && anyLogWidget) {
<Update log widgets>
}
decr(r);
}
static void dayfile(int perm,chars format,...) {
va_list L;
if (m==0 && perm>0) return;
va_start(L,format);
vdayfile(perm,format,L);
}
void wyrm_dayfile(int perm,chars format,...) {
va_list L;
if (m==0 && perm>0) return;
va_start(L,format);
<Lock access to dayfile data>
vdayfile(perm,format,L);
<Unlock access to dayfile data>
}
| ^ | | | | | | section top | |
static void vdayfile(int perm,chars format0,va_list L);
static void dayfile(int perm,chars format,...);
| ^ | | | | | | section top | |
void wyrm_dayfile(int perm,chars format,...);
| ^ | | | | | | section top | |
time_t t = time(0); struct tm *tm = localtime(&t); char hhmmss[20];
strftime(hhmmss,sizeof(hhmmss),"%H.%M.%S",tm);
| ^ | | | | | | section top | |
time_t t = time(0); struct tm *tm = localtime(&t); char yyyymmdd[20];
strftime(yyyymmdd,sizeof(yyyymmdd),"%Y/%m/%d",tm);
| ^ | | | | | | section top | |
static int displayMessage(Tcl_Channel ch,chars buffer,int o,int n,int m,int c) {
while (n>0) {
if (m>0 && o==m) o = 0;
else if (buffer[o]=='\n') {cputc(ch,'\n'); o++; n--; c = 0; break;}
else if (c==90) {cputs(ch,"\n.. "); cputc(ch,buffer[o++]); n--; c = 5;}
else {cputc(ch,buffer[o++]); n--; c++;}
}
return c;
}
| ^ | | | | | | section top | |
static int displayMessage(Tcl_Channel ch,chars buffer,int o,int n,int m,int c);
| ^ | Definition continued at: 35, 43, 58, 94. | | | | | section top | | 26. Hierarchy ::
Each message is assigned a permanency p, the lower the value of p
the more permanent the message. All p=0 messages are written out to disk.
If p>0, the message might not appear. Dayfile messages are cascaded
through a series of m circular buffers. If p>m, it is
treated as if equal to m. All messages are added to the mth buffer
first. If the jth buffer is full, so that the new message would overwrite
an old message, if the overwritten message permanency p<i, the
overwritten message is first copied to the i-1 buffer, possibly cascading
all the way to buffer 1. If instead the overwritten message is already at its
maximum permanency, it is discarded. A message that is copied out of buffer 1
(its p=0) is written to disk.
In the normal course of events, permanent (p=0) messages percolate through
the buffers and are written to disk, and all other messages are ignored. Seems rather
pointless. However the concatenation of the file with buffer 1 through buffer m
gives a kind of logarithmic back off based on message permanency. Old permanent message
are followed by slightly younger messages less permanent, through younger and younger
and lesser and lesser permanent to the youngest and most temporary messages. By scaling
the importance of debugging and trace information, this allows a dayfile to capture
the most critical information at the time of dayfile dump without permanently
recording far too many irrelevant messages.
Note also that buffer i will retain messages with p<=i,
so that permanent message can be found in buffer m after a dump.
If m=0, only permanent messages are retained.
Two special permanencies, -1 and -2, are also called line 1 and line 2. Line 1
and 2 messages are never permanent (though the last permanent message does
overwrite line 1), and only buffer a single message. Line 1 is intended for
ongoing status information. Line 2 is intended for alert messages. When
the dayfile status is returned, it returns line 2 if it is not empty,
otherwise line 2. The dayfile status widget display line 1 or line 2; when displaying
line 2, it flashes the message to get the user's attention.
struct Buffer {
chars p;
int in,out,avail;
};
static Buffer *buffer = 0;
static int m = 0;
| ^ | Referenced at: 3, 5, 6, 7, 8. | | | | | section top | |
case o_buffer:
if (N==3) {
int nb;
if (Tcl_GetIntFromObj(intr,P[2],&nb)!=TCL_OK) return TCL_ERROR;
wyrm_dayfileBufferCount(nb);
Tcl_ResetResult(intr);
return TCL_OK;
}else {
Tcl_WrongNumArgs(intr,2,P0,"number-of-buffers");
return TCL_ERROR;
}
| ^ | | | | | | section top | |
void wyrm_dayfileBufferCount(int m1) {
<Lock access to dayfile data>
int i;
if (m1>100) m1 = 100;
if (m1<m) {
flushBuffer(m1+1,m);
for (i=m; i>m1; i--) {
dispose(buffer[i].p);
}
}
buffer = reheap(m1+1,Buffer,buffer);
buffer[0].p = 0;
buffer[0].in = 0;
buffer[0].out = 0;
buffer[0].avail = 0;
for (i=m+1; i<=m1; i++) {
buffer[i].p = nheap(BufferSize,char);
buffer[i].in = 0;
buffer[i].out = 0;
buffer[i].avail = BufferSize;
}
m = m1;
<Unlock access to dayfile data>
}
| ^ | | | | | | section top | |
void wyrm_dayfileBufferCount(int m);
| ^ | Definition continued at: 44. | | | | | section top | |
static void flushBuffer(int l,int u) {
int i;
for (i=u; i>=l && i>0; i--) {
if (attachedSys) {
while (buffer[i].avail<BufferSize) {
freeBufferMessage(i);
}
}else {
buffer[i].avail = BufferSize;
}
}
}
| ^ | | | | | | section top | |
static void freeBufferMessage(int i) {
<Extract a message from buffer i>
if (buffer[i].p[buffer[i].out]-'A'<i) {
addBufferMessage(i-1,buffer[i].p,buffer[i].out,n,BufferSize);
}
buffer[i].out = o; buffer[i].avail += n;
}
| ^ | | | | | | section top | |
static void addBufferMessage(int i,chars b,int o,int n,int m) {
announceSys();
if (i==0) {
outputMessage(b,o+1,n-1,m);
}else {
while (buffer[i].avail<n) freeBufferMessage(i);
while (n-->0) {
buffer[i].p[buffer[i].in] = b[o++];
buffer[i].in = (buffer[i].in+1)&(BufferSize-1);
if (m>0) o = o&(m-1);
buffer[i].avail -= 1;
}
}
}
| ^ | | | | | | section top | |
int n,o;
for (o=buffer[i].out,n=0; buffer[i].p[o]!='\n'; o=(o+1)&(BufferSize-1)) n++;
o = (o+1)&(BufferSize-1); n++;
| ^ | | | | | | section top | |
typedef struct Buffer Buffer;
enum {BufferSize = 4096};
| ^ | | | | | | section top | |
static void flushBuffer(int l,int u);
static void freeBufferMessage(int i);
static void addBufferMessage(int i,chars buffer,int o,int n,int m);
| ^ | Definition continued at: 43, 58, 94. | |
| |