From: "Rafael García" Newsgroups: comp.os.msdos.djgpp Subject: continuous file reading Date: Tue, 20 Feb 2001 20:12:30 +0100 Organization: BT Tel. Netnews service (readers) Lines: 561 Message-ID: <3a92c201@filemon.telecable.es> NNTP-Posting-Host: filemon.telecable.es Mime-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit X-Trace: titan.bt.es 982696375 5567 212.89.0.4 (20 Feb 2001 19:12:55 GMT) X-Complaints-To: abuse AT bt DOT es NNTP-Posting-Date: 20 Feb 2001 19:12:55 GMT X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 5.00.2615.200 X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2615.200 X-Original-NNTP-Posting-Host: cm05118.telecable.es To: djgpp AT delorie DOT com DJ-Gateway: from newsgroup comp.os.msdos.djgpp Reply-To: djgpp AT delorie DOT com I have programs that writes LOG files. I can try a process and then I can revise that LOG to debug, p.e. But I wrote this program to view the LOG _while_ in execution. Now, my question is about the main loop, where I try to read all the time, because I don't know if it is possible to use some kind of signal to read only where file had grown. Any suggestion? Thanks char description[]= "View indented LOG file while it is being written.\n" "You can select detail level based on indentation with +/- keys.\n" "Press ENTER to pause/continue end tracking.\n" "\n" "Syntax: vilog [-fN] [-cN] [-dN] file\n" "fN N=Number of fixed columns, not indented, pe. date/time (def=guess)\n" "cN N=Number of columns by indentation level (def=2)\n" "dN N=Initial detail level (def=4)\n" "\n" "Version 1.0 beta 1\n" "By Rafael García González (rafael AT geninfor DOT com)\n" "You can copy it freely\n"; #include #include #include #include #include #include #include #include #include #define MAXLIN 4096 #define TRUE 1 #define FALSE 0 #define BOOL int #define MAXSHOWCOLS 256 #define MAINATTRIB ((BLUE <<4)|LIGHTGRAY) // main data colors // could be parameters #define CURSORATTRIB ((CYAN <<4)|WHITE) // cursor line colors #define STLINEATTRIB ((LIGHTGRAY<<4)|BLUE) // status line colors #define TABINDENTVAL 8 // nr of spaces for a TAB // could be parameter #define ESC 27 #define ENTER '\r' #define LEFT (75 <<8) #define RIGHT (77 <<8) #define UP (72 <<8) #define DOWN (80 <<8) #define PGUP (73 <<8) #define PGDN (81 <<8) #define HOME (71 <<8) #define END (79 <<8) #define CTLHOME (119<<8) #define CTLEND (117<<8) #define CTLLEFT (115<<8) #define CTLRIGHT (116<<8) int mainloop(int fd); ssize_t load(int fd, BOOL bigfirst); int useraction(void); void show(); void showline(char *line,int row,int attrib); void showstatusline(int row); int procbuf(char *buf,ssize_t tbuf); int indentlevel(char *line); void strncpyno0(char *dest, char *source, int max); int getchext(void); void countspaces(char *newline); int defstaticzone(void); char *filename=NULL; char **text=NULL; /* this will hold the content of file in memory to speed up detail level changes and scrolling */ long nlines=0; /* loaded */ long nlinesalloc=0; /* allocated */ int hposition=0; /* horizontal scroll */ int vposition=0; /* vertical scroll */ int detlevel=4; // detail show level int detstep=2; // number of columns for each detail level int logstaticzone=-1; /* number of columns without indentation significance in LOG file at line start. For example, I have this kind of file: 16/02/01 18:27:30.890 * *********************************************** 16/02/01 18:27:30.890 * Sesión 16/02/01 18:27 Gestión comercial V3.2 16/02/01 18:27:31.050 f faopen(Configuración) 16/02/01 18:27:39.900 o Menú principal: Albaranes 16/02/01 18:27:37.430 e memlibre: limiteinicial=-49152 16/02/01 18:27:37.480 e memlibre: limite=-49152 16/02/01 18:27:37.480 a [arriba] 16/02/01 18:27:37.700 f faclose(Configuración) 16/02/01 18:27:39.900 a a 16/02/01 18:27:39.950 f faopen(Terminales) .............................................................. this is 26 static columns */ BOOL tracking=TRUE; /* if program show new lines logged "online" */ int screenrows,screencols; int datarows; int cspacc[MAXLIN]; // number of spaces in each column /*****************************************************************/ int main(int argc,char **argv) { int fd; int ret; int n; for (n=1;n=0); break; case 'c': detstep=atoi(parm+2); assert(detstep>0); break; case 'd': detlevel=atoi(parm+2); assert(detlevel>=0); break; default: fprintf(stderr,"Syntax error: %s\n\n",parm); fprintf(stderr,description); return 1; } } else { // filename if (filename) { fprintf(stderr,"Sorry, can only open one file at a time\n"); fprintf(stderr,description); return 1; } filename=parm; } } if (!filename) { fprintf(stderr,description); return 1; } screencols=ScreenCols(); screenrows=ScreenRows(); assert(screencols!=0); assert(screenrows!=0); assert(screencols<=MAXSHOWCOLS); datarows=screenrows-1; // 1 line reserved for status line if ((fd=open(filename,O_RDONLY))<0) { perror(filename); return 2; } ret=mainloop(fd); close(fd); clrscr(); return ret; } int mainloop(int fd) { BOOL bigfirst=TRUE; ssize_t newdata=0; /* I don't know how to detect when file has changed so I try to read all the time */ while ((newdata=load(fd,bigfirst))>=0) { if (bigfirst) { bigfirst=FALSE; vposition=nlines-1; // begin showing end of file if (logstaticzone<0) { // if not given by caller logstaticzone=defstaticzone(); // guess it if (logstaticzone) printf("\nFixed zone could be %d\n",logstaticzone); } } if (newdata) { // I don't want to be writing to screen continuosly if file don't change if (tracking) vposition=nlines-1; show(); } if (useraction()) break; // let the user move it if (!kbhit()) { /* give some rest to the system */ #ifdef DELAY delay(50); // y have found sometimes this to work better than pause() #else pause(); #endif } } return 0; } // read data available from logfile // returns number of bytes read, 0 if nothing done, or <0 on error ssize_t load(int fd, BOOL bigfirst) { ssize_t bytesread; ssize_t totalread=0; char buf[8192]; static off_t filepos=0; // read all data available now while ((bytesread=read(fd,buf,sizeof(buf)))>0) { filepos+=bytesread; totalread+=bytesread; if (bigfirst) { // show the user that program is working (file could be large) printf("Reading %s %ld...\r",filename,(long)filepos); if (kbhit() && getch()==ESC) return -2; } procbuf(buf,bytesread); } if (bytesread<0) { perror(filename); return -1; } return totalread; } // let user change variables // returns !0 to terminate program int useraction(void) { if (kbhit()) { int c=getchext(); switch (c) { case '+': detlevel++; show(); break; case '-': if (detlevel>0) { detlevel--; show(); } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': detlevel=c-'0'; show(); break; case LEFT: if (hposition>0) { hposition--; show(); } break; case RIGHT: hposition++; show(); break; case UP: // go to previous visible line if (vposition>0) { for (vposition--; vposition>0 && indentlevel(text[vposition])>detlevel ; vposition-- ); } tracking=FALSE; // and stop following tail of file show(); break; case DOWN: // go to next visible line if (vpositiondetlevel ; vposition++ ); } tracking=FALSE; show(); break; case PGUP: if (vposition>0) { int skipvisiblelines; for (skipvisiblelines=0,vposition--; vposition>0; vposition--) { if (indentlevel(text[vposition])<=detlevel) { skipvisiblelines++; if (skipvisiblelines==datarows) break; } } tracking=FALSE; show(); } break; case PGDN: if (vposition=nlinesalloc) { nlinesalloc*=2; if ((text=(char**)realloc(text,nlinesalloc*sizeof(char*)))==NULL) { fprintf(stderr,"Sorry, not enough memory (line %ld)\n",(long)nlines); exit(4); } } } else { // add a char to the line buffer *plinebuf++=*p; if (++ncharsline>=MAXLIN) { // I hope this never occurs fprintf(stderr,"Line too long (%ld)\n",(long)nlines); goto newline; // ...but if it happens, I don't want program to stop } } } return 0; } void show() { int n,linesfound,row; assert(vposition0 && linesfoundhposition) strncpyno0(buf,line+hposition,screencols); ScreenPutString(buf, attrib, 0, row); } /* copy string with length limit and not copying terminator */ void strncpyno0(char *dest, char *source, int max) { while (max--) { if (!*source) break; *dest++=*source++; } } // get number of indentation levels of a line int indentlevel(char *line) { int spaces=9999; // this makes a line not significant if (strlen(line)>logstaticzone) { char *p; for (spaces=0,p=line+logstaticzone;*p;p++) { if (*p==' ') spaces++; else if (*p=='\t') spaces+=TABINDENTVAL; else break; } } return spaces/detstep; } void showstatusline(int row) { static char buf[500]; sprintf(buf," %s ¦ pos %ld / %ld ¦ detlevel=%d ¦ tracking=%s", filename,1+vposition,nlines,detlevel, tracking?"YES":"NO"); showline(buf,row,STLINEATTRIB); } /* get key pressed code, shifting extended codes 8 bits left */ int getchext(void) { int c=getch(); if (c) return c; else return getch()<<8; } /* Count spaces in each column to assign logstaticzone automatically */ void countspaces(char *newline) { char *p; int coln; for (coln=0,p=newline; *p && coln