home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / dev / misc / adoc / source / flist.c < prev    next >
C/C++ Source or Header  |  1995-04-13  |  15KB  |  692 lines

  1. /*                                                               -*- C -*-
  2.  *  FLIST.C
  3.  *
  4.  *  (c)Copyright 1994 by Tobias Ferber,  All Rights Reserved
  5.  *
  6.  *  This file is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published
  8.  *  by the Free Software Foundation; either version 1 of the License,
  9.  *  or (at your option) any later version.
  10.  *
  11.  *  This file is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; see the file COPYING.  If not, write to
  18.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. /* $VER: $Id: flist.c,v 1.9 1995/03/20 18:14:59 tf Exp $ */
  22.  
  23. #include <ctype.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27.  
  28. #include "debug.h"
  29. #include "flist.h"
  30.  
  31. /* My favorite macro */
  32. #define NIL(type) (type)0
  33.  
  34. #ifdef __GNUC__
  35. /* suggested parentheses around assignment used as truth value */
  36. #define if(assignment)    if( (assignment) )
  37. #endif /* __GNUC__ */
  38.  
  39. #ifndef MAXPATHLEN
  40. #define MAXPATHLEN 1024
  41. #endif /* !MAXPATHLEN */
  42.  
  43. /****** flist/--background-- *************************************************
  44. *
  45. *    FLIST ist eine auf Dateinamen spezialisierte FIFO Implementierung.
  46. *    Der Haupt-Anwendungsbereich d"urfte wohl im Bereich des Command-Line
  47. *    Parsings liegen, dem Durchwandern der Argumente (Optionen) eines
  48. *    Programms.
  49. *
  50. *    Meist liegen im argv[] Array die Optionen und die Dateinamen in
  51. *    gemischter Form vor.  Da ein Umsortieren von argv[] kritisch ist
  52. *    empfiehlt es sich die Liste der Argumente von links nach rechts zu
  53. *    durchwandern und die Dateinamen in einer separaten Liste zu sammeln.
  54. *    Genau hier setzt FLIST an.
  55. *
  56. ******************************************************************************
  57. *
  58. */
  59.  
  60. typedef struct fnode {  /* filename node */
  61.   struct fnode *next;   /* next node (command line from left to right) */
  62.   char *filename;       /* the input filename */
  63.   char *hostname;       /* where `filename' appeared, NIL == command-line */
  64.   long hostline;        /* line number in which `filename' appeared */
  65. } fnode_t;
  66.  
  67. static fnode_t *flist= NIL(fnode_t *),  /* very first node of the list */
  68.                *fcurr= NIL(fnode_t *),  /* head of the remaining sub-list */
  69.                *ftail= NIL(fnode_t *);  /* very last node of the list */
  70.  
  71. /*
  72.  *  >>> PRIVATE <<<
  73.  */
  74.  
  75. /****** flist/fnode_new ******************************************************
  76. *
  77. *   NAME
  78. *    fnode_new -- fnode constructor (static)
  79. *
  80. *   SYNOPSIS
  81. *    fn= fnode_new()
  82. *
  83. *    static fnode_t *fnode_new();
  84. *
  85. *   FUNCTION
  86. *
  87. *   SEE ALSO
  88. *    fnode_dispose()
  89. *
  90. ******************************************************************************
  91. *
  92. *  Ich habe aus den ****i* xxx/yyy **** Kommentaren der `static functions'
  93. *  normale Kommentare gemacht, damit ich nicht zwei docfiles erstellen mu\3...
  94. */
  95.  
  96. static fnode_t *fnode_new(void)
  97. {
  98.   fnode_t *fn;
  99.  
  100.   DD(bug_enter("fnode_new"));
  101.  
  102.   fn= (fnode_t *)malloc( sizeof(struct fnode) );
  103.  
  104.   if(fn)
  105.   {
  106.     fn->next     = NIL(fnode_t *);
  107.     fn->filename =
  108.     fn->hostname = NIL(char *);
  109.     fn->hostline = 0;
  110.  
  111.   }
  112.  
  113.   DD(bug_leave("fnode_new (%s)", fn ? "successful":"failed"));
  114.  
  115.   return fn;
  116. }
  117.  
  118. /****** flist/fnode_dispose **************************************************
  119. *
  120. *   NAME
  121. *    fnode_dispose -- fnode destructor (static)
  122. *
  123. *   SYNOPSIS
  124. *    nil= fnode_dispose(fn)
  125. *
  126. *    static fnode_t *fnode_dispose(fnode_t *);
  127. *
  128. *   FUNCTION
  129. *
  130. *   SEE ALSO
  131. *    fnode_new()
  132. *
  133. ******************************************************************************
  134. *
  135. */
  136.  
  137. static fnode_t *fnode_dispose(fnode_t *fn)
  138. {
  139.   DD(bug_enter("fnode_dispose"));
  140.  
  141.   if(fn)
  142.   {
  143.     if(fn->filename)
  144.     {
  145.       free(fn->filename);
  146.       fn->filename= NIL(char *);
  147.     }
  148.  
  149.     fn->hostname= NIL(char *);
  150.     free(fn);
  151.   }
  152.  
  153.   DD(bug_leave("fnode_dispose"));
  154.  
  155.   return NIL(fnode_t *);
  156. }
  157.  
  158.  
  159.  
  160.  
  161. /****** flist/flist_addnode **************************************************
  162. *
  163. *   NAME
  164. *    flist_addnode -- F"ugt eine fnode in die flist ein (static)
  165. *
  166. *   SYNOPSIS
  167. *    flist_addnode(fn)
  168. *
  169. *    static void flist_addnode(fnode_t *);
  170. *
  171. *   FUNCTION
  172. *    Diese Funktion h"angt die gegebene fnode `fn' an die Liste der fnode
  173. *    Strukturen an und aktualisiert `flist', `fcurr' und `ftail'.
  174. *
  175. *
  176. *   SEE ALSO
  177. *    flist_addfile(), flist_from_file()
  178. *
  179. ******************************************************************************
  180. *
  181. */
  182.  
  183. static void flist_addnode(fnode_t *fn)
  184. {
  185.   DD(bug_enter("flist_addnode"));
  186.  
  187.   if(fn)
  188.   {
  189.     if(!flist)  flist= fn;
  190.     if(!fcurr)  fcurr= fn;
  191.  
  192.     if(ftail)
  193.       ftail->next= fn;
  194.  
  195.     ftail= fn;
  196.   }
  197.  
  198.   DD(bug_leave("flist_addnode"));
  199. }
  200.  
  201.  
  202. /****** flist/fnode_from_file ************************************************
  203. *
  204. *   NAME
  205. *    fnode_from_file -- Erzeugt eine fnode aus dem n"achsten Dateinamen
  206. *
  207. *   SYNOPSIS
  208. *    fn= fnode_from_file(fp);
  209. *
  210. *    fnode_t *fnode_from_file(FILE *);
  211. *
  212. *   FUNCTION
  213. *    Diese Funktion legt eine neue fnode Struktur an und liest deren
  214. *    Auspr"agung aus dem Stream `fp' ein.  Dabei werden die Felder
  215. *    `filename' und `hostline' gesetzt, der hostname jedoch nicht.
  216. *    Ein Aufruf dieser Funktion mit NIL(FILE *) als Argument f"uhrt dazu,
  217. *    da\3 der line Counter auf 1 zur"uckgesetzt wird.
  218. *
  219. *   INPUTS
  220. *    fp          - Der Stream aus dem der n"achste Dateiname gelesen
  221. *            werden soll
  222. *
  223. *   RESULT
  224. *    fn          - Ein Zeiger auf die erstellte fnode Struktur
  225. *
  226. *   SEE ALSO
  227. *    flist_from_file()
  228. *
  229. ******************************************************************************
  230. *
  231. */
  232.  
  233. static fnode_t *fnode_from_file(FILE *fp)
  234. {
  235.   static long line= 1;
  236.   fnode_t *fn= NIL(fnode_t *);
  237.  
  238.   typedef enum { outer_mode,
  239.                  word_mode,
  240.                  string_mode,
  241.                  return_mode,
  242.                  error_mode
  243.                } smode_t;
  244.  
  245.   smode_t smode= outer_mode;
  246.  
  247.   DD(bug_enter("fnode_from_file"));
  248.  
  249.   if(fp) /* -> neue fnode anlegen und Auspr"agung einlesen */
  250.   {
  251.     if( fn= fnode_new() )
  252.     {
  253.       char *fname= (char *)malloc( MAXPATHLEN * sizeof(char) );
  254.  
  255.       if( fname )
  256.       {
  257.         int c, n=0;
  258.         fn->filename= fname;
  259.  
  260.         while( smode != return_mode && smode != error_mode && !feof(fp) )
  261.         {
  262.           c= fgetc(fp);
  263.  
  264.           if(feof(fp) && c!=EOF)
  265.             c= EOF;
  266.  
  267.           switch(c)
  268.           {
  269.             case ' ': case '\t':
  270.               switch(smode)
  271.               {
  272.                 case word_mode:
  273.                   fname[n++]= '\0';
  274.                   smode= return_mode;
  275.                   break;
  276.  
  277.                 case string_mode:
  278.                   fname[n++]= c;
  279.                   break;
  280.  
  281.                 case outer_mode:
  282.                 case return_mode:
  283.                 case error_mode:
  284.                   break;
  285.               }
  286.               break;
  287.  
  288.             case '\n': case '\r':
  289.               switch(smode)
  290.               {
  291.                 case word_mode:
  292.                   fname[n++]= '\0';
  293.                   smode= return_mode;
  294.                   break;
  295.  
  296.                 case string_mode:
  297.                   sprintf(fname,"%ld: unterminated string at EOL; missing quotes `\"'",line);
  298.                   smode= error_mode;
  299.                   break;
  300.  
  301.                 case outer_mode:
  302.                 case return_mode:
  303.                 case error_mode:
  304.                   break;
  305.               }
  306.               line++;
  307.  
  308.               { int d= fgetc(fp);
  309.                 if(!( (c=='\n' && d=='\r') || (c=='\r' && d=='\n') ))
  310.                   ungetc(d,fp);
  311.               }
  312.               break;
  313.  
  314.             case '\"':
  315.               switch(smode)
  316.               {
  317.                 case outer_mode:
  318.                   smode= string_mode;
  319.                   fn->hostline= line;
  320.                   break;
  321.  
  322.                 case string_mode:
  323.                   fname[n++]= '\0';
  324.                   smode= return_mode;
  325.                   break;
  326.  
  327.                 case word_mode:
  328.                   fname[n++]= '\0';
  329.                   ungetc(c,fp);
  330.                   smode= return_mode;
  331.                   break;
  332.  
  333.                 case return_mode:
  334.                 case error_mode:
  335.                   break;
  336.               }
  337.               break;
  338.  
  339.             case EOF:
  340.               switch(smode)
  341.               {
  342.                 case word_mode:
  343.                   if( feof(fp) )
  344.                   {
  345.                     fname[n++]= '\0';
  346.                     smode= return_mode;
  347.                   }
  348.                   else fname[n++]= c;
  349.                   break;
  350.  
  351.                 case string_mode:
  352.                   if( feof(fp) )
  353.                   {
  354.                     sprintf(fname,"%ld: unterminated string at EOF; missing quotes `\"'",line);
  355.                     smode= error_mode;
  356.                   }
  357.                   else fname[n++]= c;
  358.                   break;
  359.  
  360.                 case outer_mode:
  361.                 case return_mode:
  362.                 case error_mode:
  363.                   break;
  364.               }
  365.               break;
  366.  
  367.             default:
  368.               switch(smode)
  369.               {
  370.                 case outer_mode:
  371.                   smode= word_mode;
  372.                   fn->hostline= line;
  373.                   /* fall through */
  374.  
  375.                 case word_mode:
  376.                 case string_mode:
  377.                   fname[n++]= c;
  378.                   break;
  379.  
  380.                 case return_mode:
  381.                 case error_mode:
  382.                   break;
  383.               }
  384.               break;
  385.           }
  386.  
  387.           if(n >= MAXPATHLEN)
  388.           {
  389.             sprintf(fname,"%ld: line too long",line);
  390.             smode= error_mode;
  391.           }
  392.  
  393.         } /* wend */
  394.  
  395.         if(smode != error_mode)
  396.           fname[n]= '\0';
  397.         else
  398.           fn->hostline= 0;
  399.       }
  400.       else /* !fname */
  401.         fn= fnode_dispose(fn);
  402.     }
  403.   }
  404.   else /* !fp || !fname */
  405.     line= 1;
  406.  
  407.   DD(bug_leave("fnode_from_file"));
  408.  
  409.   return fn;
  410. }
  411.  
  412.  
  413. /*
  414.  *  >>> PUBLIC <<<
  415.  */
  416.  
  417.  
  418. /****** flist/flist_dispose **************************************************
  419. *
  420. *   NAME
  421. *    flist_dispose -- Gibt die Liste der Dateinamen frei
  422. *
  423. *   SYNOPSIS
  424. *    flist_dispose()
  425. *
  426. *    void flist_dispose(void);
  427. *
  428. *   FUNCTION
  429. *
  430. *   SEE ALSO
  431. *    flist_addfile(), flist_from_file()
  432. *
  433. ******************************************************************************
  434. *
  435. */
  436.  
  437. void flist_dispose(void)
  438. {
  439.   D(bug_enter("flist_dispose"));
  440.  
  441.   while(flist)
  442.   {
  443.     fnode_t *t= flist;
  444.     flist= flist->next;
  445.  
  446.     (void)fnode_dispose(t);
  447.   }
  448.  
  449.   fcurr=
  450.   ftail= NIL(fnode_t *);
  451.  
  452.   D(bug_leave("flist_dispose"));
  453. }
  454.  
  455.  
  456. /****** flist/flist_addfile **************************************************
  457. *
  458. *   NAME
  459. *    flist_addfile -- F"ugt einen Dateinamen in die Fileliste ein
  460. *
  461. *   SYNOPSIS
  462. *    error = flist_addfile(filename)
  463. *
  464. *    int flist_addfile(char *);
  465. *
  466. *   FUNCTION
  467. *    Diese Funktion h"angt einen Dateinamen (wie er z.B. von der command
  468. *    line kommt) an das Ende der Liste der Dateinamen an.
  469. *
  470. *   INPUTS
  471. *    filename      - Der Name der Datei
  472. *
  473. *   RESULT
  474. *    error          - 0, wenn alles geklappt hat
  475. *            1, wenn nicht genug Speicher verf"ugbar war
  476. *
  477. *   SEE ALSO
  478. *    flist_dispose()
  479. *
  480. ******************************************************************************
  481. *
  482. */
  483.  
  484. int flist_addfile(char *fname)
  485. {
  486.   fnode_t *fn= NIL(fnode_t *);
  487.  
  488.   D(bug_enter("flist_addfile \"%s\"",fname));
  489.  
  490.   if(fname)
  491.   {
  492.     if( fn= fnode_new() )
  493.     {
  494.       fn->hostname = NIL(char *);
  495.       fn->hostline = 0;
  496.  
  497.       fn->filename = strdup(fname);
  498.  
  499.       if(fn->filename)
  500.         flist_addnode(fn);
  501.  
  502.       else fn= fnode_dispose(fn);
  503.     }
  504.   }
  505.  
  506.   D(bug_leave("flist_addfile (%s)", fn ? "successful":"failed"));
  507.  
  508.   return fn ? 0:1;
  509. }
  510.  
  511.  
  512. /****** flist/flist_from_file ************************************************
  513. *
  514. *   NAME
  515. *    flist_from_file -- Baut eine Liste aus den Dateinamen in einem File
  516. *
  517. *   SYNOPSIS
  518. *    error= flist_from_file(filename);
  519. *
  520. *    int flist_from_file(char *);
  521. *
  522. *   FUNCTION
  523. *    Diese Funktion h"angt alle in der angegebenen Datei aufgef"uhrten
  524. *    Dateinamen an die Fileliste an.
  525. *
  526. *   INPUTS
  527. *    filename      - Der Name der Datei mit den Filenamen
  528. *
  529. *   RESULT
  530. *    error          - 0, wenn alles geklappt hat
  531. *            1, im Fehlerfall
  532. *
  533. *   SEE ALSO
  534. *    flist_dispose()
  535. *
  536. ******************************************************************************
  537. *
  538. */
  539.  
  540. int flist_from_file(char *host)
  541. {
  542.   int rc= 0;
  543.   FILE *fp;
  544.  
  545.   D(bug_enter("flist_from_file \"%s\"",host));
  546.  
  547.   if( (fp= fopen(host,"r")) )
  548.   {
  549.     fnode_t *fn;
  550.  
  551.     /* reset the line counter */
  552.     fnode_from_file( NIL(FILE *) );
  553.  
  554.     while( !rc && !feof(fp) && !ferror(fp) )
  555.     {
  556.       if( fn= fnode_from_file(fp) )
  557.       {
  558.         if(fn->hostline > 0)
  559.         {
  560.           if(fn->filename && *fn->filename)
  561.           {
  562.             fn->hostname= host;
  563.             flist_addnode(fn);
  564.           }
  565.         }
  566.         else if(fn->filename && *fn->filename)
  567.         {
  568.           /* fn->filename contains an error message */
  569.           fprintf(stderr,"%s: %s\n",host,fn->filename);
  570.           rc= 1;
  571.         }
  572.         else fn= fnode_dispose(fn); /* EOF */
  573.       }
  574.       else /* !fn */
  575.       {
  576.         fprintf(stderr,"%s: %ld: ran out of memory!\n", host, fn->hostline);
  577.         rc= 2;
  578.       }
  579.     }
  580.   }
  581.   else perror(host);
  582.  
  583.   D(bug_leave("flist_from_file (%s)", rc ? "failed":"successful"));
  584.  
  585.   return rc;
  586. }
  587.  
  588. /**/
  589.  
  590. char *flist_getname(void)
  591. {
  592.   D(bug("flist_getname()"));
  593.   return fcurr ? fcurr->filename : NIL(char *);
  594. }
  595.  
  596.  
  597. char *flist_gethost(void)
  598. {
  599.   D(bug("flist_gethost()"));
  600.   return fcurr ? fcurr->hostname : NIL(char *);
  601. }
  602.  
  603.  
  604. long flist_gethostline(void)
  605. {
  606.   D(bug("flist_gethostline()"));
  607.   return fcurr ? fcurr->hostline : 0L;
  608. }
  609.  
  610. int flist_nextfile(void)
  611. {
  612.   D(bug("flist_nextfile()"));
  613.  
  614.   if(fcurr)
  615.     fcurr= fcurr->next;
  616.  
  617.   return fcurr ? 1:0;
  618. }
  619.  
  620.  
  621. #if defined(DEBUG) || defined(TEST)
  622.  
  623. void flist_print(FILE *fp)
  624. {
  625.   fnode_t *fn= flist;
  626.  
  627.   D(bug_enter("flist_print"));
  628.  
  629.   if(fn)
  630.   {
  631.     int n;
  632.     fprintf(fp,"list of input files:\n");
  633.  
  634.     for(n=0; fn; n++, fn= fn->next)
  635.       fprintf(fp,"\t%s:%ld: \"%s\"\n",
  636.         (fn->hostname ? fn->hostname
  637.                       : "command-line"), fn->hostline, fn->filename);
  638.   }
  639.   else fprintf(fp,"list of input files is empty\n");
  640.  
  641.   D(bug_leave("flist_print"));
  642. }
  643. #endif /* DEBUG || TEST */
  644.  
  645.  
  646. #ifdef TEST
  647.  
  648.  
  649. int main(int argc, char **argv)
  650. {
  651.   int rc= 0;
  652.   char *whoami= argv[0];
  653.  
  654.   while(--argc > 0 && !rc)
  655.   {
  656.     char *arg= *++argv;
  657.     if(*arg == '@')
  658.     {
  659.       if(arg[1]) ++arg;
  660.       else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  661.  
  662.       if(arg && *arg)
  663.       {
  664.         if( rc= flist_from_file(arg) )
  665.           fprintf(stderr,"%s: reading filenames from `%s' failed\n",whoami,arg);
  666.       }
  667.       else
  668.       {
  669.         fprintf(stderr,"%s: missing filename after `%s'\n",whoami,*argv);
  670.         rc= 1;
  671.       }
  672.     }
  673.     else /* !@... */
  674.     {
  675.       if( rc= flist_addfile(arg) )
  676.         fprintf(stderr,"%s: out of memory... aaaiiiiiieeeeeeeee!\n",whoami);
  677.     }
  678.   }
  679.  
  680.   if(!rc)
  681.     flist_print(stdout);
  682.  
  683.   flist_dispose();
  684.  
  685.   if(rc) fprintf(stderr,"%s: [%s] *** Error %d\n"
  686.                         "%s terminated abnormally (error %d)\n", whoami, *argv, rc, whoami, rc);
  687.  
  688.   return rc;
  689. }
  690.  
  691. #endif /* TEST */
  692.