/* process.c - Process the log files. Copyright (c) 1989, Microsoft. All Rights Reserved. 10-07-89 Matt Saettler 10-10-89 Update for log,aBlock,EXTFile,files structures */ #include #include #include #include #include #include #include "types.h" #include "docfmt.h" #include "ventura.h" #include "rtf.h" #include "process.h" #include "misc.h" #include "errstr.h" void dumptable(int numfiles, files * ptable); /* * @doc INTERNAL * * @func void | processLog | This function processes all the Log files. * * @xref readLog, initLogs, processLogs, doneLogs */ void processLog(void) { logentry *cur_log; FILE *fpout; if(!head_log) return; cur_log=head_log; while(cur_log) { readLog(cur_log); cur_log=cur_log->next; } fpout=fopen(outputFile,"w"); if(!fpout) return; cur_log=head_log; initLogs(fpout, &head_log); while(cur_log) { if(verbose>1) fprintf(errfp," Processing Log file: %s\n",cur_log->pchlogname); processLogs(fpout, cur_log); cur_log=cur_log->next; } doneLogs(fpout, head_log); fclose(fpout); if(verbose) fprintf(errfp,"%s is complete.\n",outputFile); } /* * * @doc INTERNAL * * @func void | processLogs | This functions processes all the files within * the specified log file structure. * * @parm FILE * | fpout | This is the output file to process the files * to. * * @parm logentry * | cur_log | This is the current log file to process. * * @xref initFiles, processFiles, doneFiles */ void processLogs(FILE *fpout, logentry * cur_log) { initFiles(fpout, cur_log); if(cur_log->outheadMFile) processFiles(fpout, cur_log->outheadMFile); processFiles(fpout, cur_log->outheadFile); if(cur_log->outheadSUFile) processFiles(fpout, cur_log->outheadSUFile); doneFiles(fpout, cur_log->outheadFile); } /* * @doc INTERNAL * * @func void | cleanLogs | This function removes the log files structure * from memory and removes any files if the fCleanFiles flag is TRUE. * * @parm logentry * | cur_log | This specifies the log file structure to remove. * * @xref cleanFile, cleanLogs */ void cleanLogs(logentry *cur_log) { if(!cur_log) return; cleanFile(cur_log->outheadFile); cleanFile(cur_log->outheadMFile); cleanFile(cur_log->outheadSUFile); // structs go here... cleanLogs(cur_log->next); /* recursive !! */ if(fCleanFiles) unlink(cur_log->pchlogname); my_free(cur_log->pchlogname); my_free(cur_log); return; } /* * @doc INTERNAL PROCESS * * @func void | readLog | This function reads the logfile and creates * the logfile structure. * * @parm logentry * | cur_log | This specifies the logfile structure to * fill. The filename has been filled in. * * @xref parseFile */ void readLog(logentry *cur_log) { FILE * tFile; files curFile; files curMFile; files curSUFile; files curTFile; tFile = fopen(cur_log->pchlogname, "r"); if(tFile == NULL) { error(ERROR9, "xxx", cur_log->pchlogname ); Usage(); return; } cur_log->outheadFile=NULL; cur_log->outheadMFile=NULL; cur_log->outheadSUFile=NULL; fscanf(tFile, "%d\n",&cur_log->outputType); curTFile=(files)clear_alloc(sizeof (struct strfile) ); curMFile=NULL; curSUFile=NULL; curFile=NULL; curFile=cur_log->outheadFile; while(parseFile(tFile, curTFile)) { if(curTFile->blockType==MESSAGE && fSortMessage) { if(curMFile==NULL) { cur_log->outheadMFile=curTFile; } else { curMFile->next=curTFile; } curMFile=curTFile; } else if( (curTFile->blockType==STRUCTBLOCK) || (curTFile->blockType==STRUCTBLOCK)) { if(curSUFile==NULL) { cur_log->outheadSUFile=curTFile; } else { curSUFile->next=curTFile; } curSUFile=curTFile; } else { if(curFile==NULL) { cur_log->outheadFile=curTFile; } else { curFile->next=curTFile; } curFile=curTFile; } curTFile=(files)clear_alloc(sizeof (struct strfile) ); } my_free(curTFile); curFile->next=NULL; #ifdef MMWIN // This causes GP fault curMFile->next=NULL; // just to be sure. curSUFile->next=NULL; // just to be sure. #endif fclose( tFile ); } /* * @doc INTERNAL PROCESS * * @func int | initLogs | This function is called at the beginning of * processing the list of logs. * * @parm FILE * | phoutfile | This functions specifies the output file handle. * * @parm logentry **| phead_log | This specifies the pointer to the list of * log files to be processed. The head value may be modified due to sorting, * etc., by the output LogInit routine or . * * @rdesc The return value is TRUE if the operation succeds. * * @xref VenLogInit, RTFLogInit * */ int initLogs(FILE *phoutfile, logentry **phead_log) { switch(head_log->outputType) { case VENTURA: VenLogInit(phoutfile, phead_log); break; case RTFDOC: case RTFHELP: RTFLogInit(phoutfile, phead_log); break; default: fprintf(stderr, "Unknown Output Type"); break; } return(TRUE); } /* * @doc INTERNAL PROCESS * * @func int |initFiles| This function is called before processing each * log file. * * @parm FILE *|phoutfile| This parmameter specifies the output file. * * @parm logentry * | curlog | This is the log file containing the files * to be processed. * * @rdesc The return value is TRUE if the initialization was successful. * * @comm The files are sorted by function name * * @xref VenFileInit, RTFFileInit * */ int initFiles(FILE *phoutfile, logentry *curlog) { files curFile; int i; files *ptable; int numFiles; numFiles=0; curFile=curlog->outheadFile; if(!curFile) goto nofiles; while(curFile) { numFiles++; curFile=curFile->next; } /* sort the list */ ptable=(files *)clear_alloc( sizeof (struct s_log) * (numFiles + 1) ); curFile=curlog->outheadFile; for(i=0;inext; } /* dumptable(numFiles, ptable); */ qsort( ptable, numFiles, sizeof (files *), filecmp); /* dumptable(numFiles, ptable); */ curlog->outheadFile=ptable[0]; curFile=curlog->outheadFile; for(i=0;inext=ptable[i]; curFile=curFile->next; } curFile->next=NULL; my_free(ptable); nofiles: //////////////////////////////////////////////////////////////// // sort messages numFiles=0; curFile=curlog->outheadMFile; if(!curFile) goto nomessages; while(curFile) { numFiles++; curFile=curFile->next; } /* sort the list */ ptable=(files *)clear_alloc( sizeof (struct s_log) * (numFiles + 1) ); curFile=curlog->outheadMFile; for(i=0;inext; } /* dumptable(numFiles, ptable); */ qsort( ptable, numFiles, sizeof (files *), filecmp); /* dumptable(numFiles, ptable); */ curlog->outheadMFile=ptable[0]; curFile=curlog->outheadMFile; for(i=0;inext=ptable[i]; curFile=curFile->next; } curFile->next=NULL; my_free(ptable); nomessages: //////////////////////////////////////////////////////////////// // sort structs/unions numFiles=0; curFile=curlog->outheadSUFile; if(!curFile) goto nosu; while(curFile) { numFiles++; curFile=curFile->next; } /* sort the list */ ptable=(files *)clear_alloc( sizeof (struct s_log) * (numFiles + 1) ); curFile=curlog->outheadSUFile; for(i=0;inext; } /* dumptable(numFiles, ptable); */ qsort( ptable, numFiles, sizeof (files *), filecmp); /* dumptable(numFiles, ptable); */ curlog->outheadSUFile=ptable[0]; curFile=curlog->outheadSUFile; for(i=0;inext=ptable[i]; curFile=curFile->next; } curFile->next=NULL; my_free(ptable); nosu: ////////////////////////////////////////////////////////////// // Init file/section output // this is a little out of design because we now have multiple // files (text and messages and soon structs... switch(outputType) { case VENTURA: VenFileInit(phoutfile, curlog); break; case RTFDOC: case RTFHELP: RTFFileInit(phoutfile, curlog); break; default: fprintf(stderr, "Unknown Output Type"); break; } return(TRUE); } /* * @doc INTERNAL PROCESS * * @func void|dumptable| This is a debug function to dump the list of * files. * * @parm int| numfiles | Specifies the nmber of entries in the table. * * @parm files * | ptable | Specifies the table to dump. * * @xref initFiles * */ void dumptable(int numfiles, files * ptable) { int i; for(i=0;iname,ptable[i]->filename); } /* * @doc INTERNAL PROCESS * * @func int | filecmp | This routine is used in the qsort. It does a * case insensitive compare of the names. * * @parm files * | f1 | This is the first file to compare. * * @parm files * | f2 | This is the second file to compare. * * @rdesc The return is the same as . See . * * @xref qsort, strcmp, initFiles */ int filecmp(files * f1, files * f2) { int order; order=stricmp((*f1)->name,(*f2)->name); return(order); } /* * @doc INTERNAL PROCESS * * @func int | processFiles | This routine processes all the files in * a log file structure by calling the appropriate file output routine. * * @parm FILE * | phoutfile | This is the output file handle. * * @parm files |headFile| This is the head of the list of files to process. * * @xref VenFileProcess, RTFFileProcess */ int processFiles(FILE * phoutfile, files headFile) { files curFile; curFile=headFile; while(curFile && curFile->name) { if(verbose>1) fprintf(errfp," Copying Block %s\n",curFile->name); switch(outputType) { case VENTURA: VenFileProcess(phoutfile, curFile); break; case RTFDOC: case RTFHELP: RTFFileProcess(phoutfile, curFile); break; default: fprintf(stderr, "Unknown Output Type"); break; } curFile=curFile->next; } return TRUE; } /* * @doc INTERNAL PROCESS * * @func int | parseFile | This routine parses a file structure from a log file. * * @parm FILE * | pfh | The input file handle of the log file. * * @parm files | curFile| The file structure to place the data from the file. * */ int parseFile(FILE * pfh, files curFile) { char achbuf[80]; if(fscanf(pfh,"%d ",&(curFile->blockType)) == EOF) return(FALSE); if(fscanf(pfh, "%s",achbuf) == EOF) return(FALSE); curFile->name=cp_alloc(achbuf); if(fscanf(pfh, " %s\n",achbuf) == EOF) return(FALSE); curFile->filename=cp_alloc(achbuf); return(TRUE); } /* * @doc INTERNAL PROCESS * * @func void | doneLogs | This function is called after all the logs * in the list have been processed. * * @parm FILE *|phoutfile| Specifies the output file. * * @parm logentry * | headLog | Specifies the head of the list of log structure. * * @xref VenLogDone, RTFLogDone, cleanLogs * * @comm If the fCleanFiles flag is set, then the log files are cleaned. * */ void doneLogs(FILE *phoutfile, logentry *headLog) { switch(outputType) { case VENTURA: VenLogDone(phoutfile, headLog); break; case RTFDOC: case RTFHELP: RTFLogDone(phoutfile, headLog); break; default: fprintf(stderr, "Unknown Output Type"); break; } if(fCleanFiles) cleanLogs(headLog); return; } /* * @doc INTERNAL PROCESS * * @func void | doneFiles | This function is called when all the files * in the current log have been processed. * * @parm FILE *|phoutfile| Specifies the output file. * * @parm files | headFile| Specifies the list of files that have been processed. * * @xref VenFileDone, RTFFileDone */ void doneFiles(FILE *phoutfile, files headFile) { switch(outputType) { case VENTURA: VenFileDone(phoutfile, headFile); break; case RTFDOC: case RTFHELP: RTFFileDone(phoutfile, headFile); break; default: fprintf(stderr, "Unknown Output Type"); break; } return; } /* * @doc INTERNAL PROCESS * * @func int | cleanFile | This function removes all the memory and * DOS files associated with the files data structure. * * @parm files | headFile| Specifies the list of files to be cleaned. * */ int cleanFile(files headFile) { files curFile; files tcurFile; curFile=headFile; while(curFile && curFile->name) { unlink(curFile->filename); my_free(curFile->filename); my_free(curFile->name); tcurFile=curFile->next; my_free(curFile); curFile=tcurFile; } return TRUE; } /* * @doc INTERNAL PROCESS * * @func void | copyfile | This function appends the specified file name * to the specified output file. * * @parm FILE *|phoutfile| Specifies the output file. * * @parm char *| pchfilename| Specifies the input file. * */ void copyfile(FILE *phoutfile, char *pchfilename) { FILE *fpin; int i; char *pch; pch=findfile(pchfilename); if(!pch) return; fpin=fopen(pch,"r"); if(!fpin) return; while((i=fgetc(fpin))!=EOF) fputc(i,phoutfile); fclose(fpin); return; } /* * @doc INTERNAL PROCESS * * @func char * | findfile | This function tries to find the specified * file. It searches directories in this order: current, PATH, INIT * and finally INCLUDE. * * @parm char * |pch| Specifies the filename to find. * * @rdesc This function returns a pointer to the complete file/path * of the specified file. Just the file name is returned if it is * found in the current directory. NULL is returned if the file cannot * be found. * */ char * findfile(char * pch) { FILE *fp; static char ach[128]; static char *pchmode="r"; strcpy(ach,pch); fp=fopen(ach, pchmode); if(fp) { fclose(fp); return(ach); } _searchenv(pch,"PATH",ach); fp=fopen(ach, pchmode); if(fp) { fclose(fp); return(ach); } _searchenv(pch,"INIT",ach); fp=fopen(ach, pchmode); if(fp) { fclose(fp); return(ach); } _searchenv(pch,"INCLUDE",ach); fp=fopen(ach, pchmode); if(fp) { fclose(fp); return(ach); } return(NULL); } /* * @doc INTERNAL PROCESS * * @func logentry * | add_logtoprocess | This function adds the specified * log file name to the list of logs to be processed. * * @parm char * | pch| Specifies log file name to bo added. * * @rdesc The return value specifies the logentry that was created * for the specified log file. * * @xref newlog */ logentry * add_logtoprocess(char *pch) { logentry *cur_log; cur_log=newlog(&head_log); cur_log->pchlogname=cp_alloc(pch); return(cur_log); } /* * @doc INTERNAL PROCESS * * @func logentry * | newlog | This function creates a new log entry * in the specified list of logs. * * @parm logentry ** | start_log| Specifies the head of head of the list * of logs. * * @rdesc The return value specifies the logentry that was added. * * @comm The new log structure is added at the head of the list. * */ logentry * newlog(logentry **start_log) { logentry * cur_log; logentry * tmp_log; cur_log=(logentry *)clear_alloc(sizeof(struct s_log)); if(!*start_log) { *start_log=cur_log; } else { tmp_log=*start_log; while(tmp_log->next) tmp_log=tmp_log->next; tmp_log->next=cur_log; } return(cur_log); } /* * @doc INTERNAL PROCESS * * @func fileentry * | add_filetoprocess | This function adds an input * file to process to a log structure. * * @parm char * |pch| Specifies the filename to be added. * * @parm logentry *|curlog| Specifies the log structure. * * @rdesc The return value is the new file structure that is created * to hold the file entry in the log structure. * * @xref newfile */ fileentry * add_filetoprocess(char *pch, logentry *curlog) { fileentry *cur_file; cur_file=newfile(&(curlog->inheadFile)); cur_file->filename=cp_alloc(pch); cur_file->logfile=curlog; return(cur_file); } /* * @doc INTERNAL PROCESS * * @func fileentry * | newfile | This function creates a new file entry * in a list of files. It is similar to . * * @parm fileentry **|start_file| Specifies the head of the list of files. * * @rdesc The return value specifies the new file structure that was created * to hold the new file entry. * * @comm This routine inserts at the head of the list. * */ fileentry * newfile(fileentry **start_file) { fileentry * cur_file; fileentry * tmp_file; cur_file=(fileentry *)clear_alloc(sizeof(struct strfile)); if(!*start_file) { *start_file=cur_file; } else { tmp_file=*start_file; while(tmp_file->next) tmp_file=tmp_file->next; tmp_file->next=cur_file; } return(cur_file); }