[The following is a code listing from the article "Error Messages and Documentation", by S. L. Sanders]
//============================ exstrng [main] ==========================
// Main program for CUJ article illustrating string extraction.
//   Scans a C source file, extracting the first string from each
//   function or macro definition. The string is writtten onto an
//   output file after removing any printf format specifiers.
//            Copyright (c) Sanders-Indev, Inc, 1997:
// Commercial use of any kind is prohibited without written consent of
// the owner. Personal and teaching use is permitted.
#include "exstrng.h"  // Includes ctype.h and
                      // parse2.h, which includes
                      //    stdio.h, stddef.h, and string.h

short main(int argc,char *argv[])

{ //BEGIN main

                   /*--Initialize for the run--*/
if(argc!=2){ //No filename argument on command line
  printf("\a  Usage:\nexstrng filenam   (filenam is input file.)\n");
  } //END No filename argument on command line
if((wrkf=fopen("wrkf.$$$","w"))==NULL) { //Open workfile for output
  printf("\nAborted: Can't create work file wrkf.$$$.\a");
  /* Can't open the report work file for output. */
  } //END Open workfile for output

strcpy(infnam,argv[1]); //Get input file name from command line
if((inf=fopen(infnam,"rt"))==NULL) { //Open input file
  printf("\nError: Can't open input file %s.",infnam);
  } //END Open input file
  /* Can't open an input file for XMan to analyze. */

                  /*--Process the input file--*/
while(err==0&&!feof(inf)){ //Each char of initialized input file
  csisav=csi;     //Save char-scan index and line counter, so they
  lctsav=linectr; //can be checked for change at end of loop.
  if(CIDCHR(currline,csi)){ //Valid C identifier-char (See parse.h)
    CIDSTORE //Store currline[csi] as next char in currname array
    if(err!=0) //err is set to 1 if name is too long
     break; //Name too long-- immediately exit "Each char..." loop
    } //END Valid C identifier-char (See parse.h)
  else{ //currline[csi] is endname (not a valid C identifier-char)
    CKENDRTN //Detect end of function or macro
    GETNOJNK(SKIP,err=1) //Skip blanks, empty lines, comments, strings
    if(err==1) //GETNOJNK 2nd parameter was executed-- read has failed
      break; //Immediately exit the "Each char..." loop
    if(morfndx>0){ //currname is not empty
      if(tstfmhdr()!=0){ //Test for function or macro header
        err=1; //Indicate bad input file
        break; //Immediately exit the "Each input file" loop
        } //END Test for function or macro header
      //ASSERT: If currname is not a function or macro header, csi
      //        indexes the endname char (or the first non-junk after);
      //        otherwise, it indexes the first char following the
      //        opening { of a function's or macro's defining compound
      //        statement. morfindx has been set to 0, and currname
      //        contains the name it had prior to the tstfmhdr call,
      //        but with kNUL appended.
      } //END currname is not empty
    } //END currline[csi] is endname (not a valid C identifier-char)

                     /*--Check for newline--*/
    READLINE(err=1) //READLINE parameter err=1 executed iff fgets()
  else             //fails to read a line from inf into currline.
    //Increment csi only if it indexes the same char of the same line
    //it indexed when the main loop started.
  } //END Each char of initialized input file

                        /*--Normal return--*/
if(fmcount==0){ //Nothing found
  printf("\nNo function or macro def found in file %s.",infnam);
  fprintf(wrkf,"\nNo function or macro def found in file %s.",infnam);
  } //END Nothing found
printf("\n(End %s; %d lines)\n",infnam,linectr);
fprintf(wrkf,"\n(End %s; %d lines)\n",infnam,linectr);
} //END main
Back to main article.