home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 3
/
goldfish_volume_3.bin
/
files
/
dev
/
misc
/
adoc
/
source
/
flist.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-13
|
15KB
|
692 lines
/* -*- C -*-
* FLIST.C
*
* (c)Copyright 1994 by Tobias Ferber, All Rights Reserved
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 1 of the License,
* or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $VER: $Id: flist.c,v 1.9 1995/03/20 18:14:59 tf Exp $ */
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "debug.h"
#include "flist.h"
/* My favorite macro */
#define NIL(type) (type)0
#ifdef __GNUC__
/* suggested parentheses around assignment used as truth value */
#define if(assignment) if( (assignment) )
#endif /* __GNUC__ */
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif /* !MAXPATHLEN */
/****** flist/--background-- *************************************************
*
* FLIST ist eine auf Dateinamen spezialisierte FIFO Implementierung.
* Der Haupt-Anwendungsbereich d"urfte wohl im Bereich des Command-Line
* Parsings liegen, dem Durchwandern der Argumente (Optionen) eines
* Programms.
*
* Meist liegen im argv[] Array die Optionen und die Dateinamen in
* gemischter Form vor. Da ein Umsortieren von argv[] kritisch ist
* empfiehlt es sich die Liste der Argumente von links nach rechts zu
* durchwandern und die Dateinamen in einer separaten Liste zu sammeln.
* Genau hier setzt FLIST an.
*
******************************************************************************
*
*/
typedef struct fnode { /* filename node */
struct fnode *next; /* next node (command line from left to right) */
char *filename; /* the input filename */
char *hostname; /* where `filename' appeared, NIL == command-line */
long hostline; /* line number in which `filename' appeared */
} fnode_t;
static fnode_t *flist= NIL(fnode_t *), /* very first node of the list */
*fcurr= NIL(fnode_t *), /* head of the remaining sub-list */
*ftail= NIL(fnode_t *); /* very last node of the list */
/*
* >>> PRIVATE <<<
*/
/****** flist/fnode_new ******************************************************
*
* NAME
* fnode_new -- fnode constructor (static)
*
* SYNOPSIS
* fn= fnode_new()
*
* static fnode_t *fnode_new();
*
* FUNCTION
*
* SEE ALSO
* fnode_dispose()
*
******************************************************************************
*
* Ich habe aus den ****i* xxx/yyy **** Kommentaren der `static functions'
* normale Kommentare gemacht, damit ich nicht zwei docfiles erstellen mu\3...
*/
static fnode_t *fnode_new(void)
{
fnode_t *fn;
DD(bug_enter("fnode_new"));
fn= (fnode_t *)malloc( sizeof(struct fnode) );
if(fn)
{
fn->next = NIL(fnode_t *);
fn->filename =
fn->hostname = NIL(char *);
fn->hostline = 0;
}
DD(bug_leave("fnode_new (%s)", fn ? "successful":"failed"));
return fn;
}
/****** flist/fnode_dispose **************************************************
*
* NAME
* fnode_dispose -- fnode destructor (static)
*
* SYNOPSIS
* nil= fnode_dispose(fn)
*
* static fnode_t *fnode_dispose(fnode_t *);
*
* FUNCTION
*
* SEE ALSO
* fnode_new()
*
******************************************************************************
*
*/
static fnode_t *fnode_dispose(fnode_t *fn)
{
DD(bug_enter("fnode_dispose"));
if(fn)
{
if(fn->filename)
{
free(fn->filename);
fn->filename= NIL(char *);
}
fn->hostname= NIL(char *);
free(fn);
}
DD(bug_leave("fnode_dispose"));
return NIL(fnode_t *);
}
/****** flist/flist_addnode **************************************************
*
* NAME
* flist_addnode -- F"ugt eine fnode in die flist ein (static)
*
* SYNOPSIS
* flist_addnode(fn)
*
* static void flist_addnode(fnode_t *);
*
* FUNCTION
* Diese Funktion h"angt die gegebene fnode `fn' an die Liste der fnode
* Strukturen an und aktualisiert `flist', `fcurr' und `ftail'.
*
*
* SEE ALSO
* flist_addfile(), flist_from_file()
*
******************************************************************************
*
*/
static void flist_addnode(fnode_t *fn)
{
DD(bug_enter("flist_addnode"));
if(fn)
{
if(!flist) flist= fn;
if(!fcurr) fcurr= fn;
if(ftail)
ftail->next= fn;
ftail= fn;
}
DD(bug_leave("flist_addnode"));
}
/****** flist/fnode_from_file ************************************************
*
* NAME
* fnode_from_file -- Erzeugt eine fnode aus dem n"achsten Dateinamen
*
* SYNOPSIS
* fn= fnode_from_file(fp);
*
* fnode_t *fnode_from_file(FILE *);
*
* FUNCTION
* Diese Funktion legt eine neue fnode Struktur an und liest deren
* Auspr"agung aus dem Stream `fp' ein. Dabei werden die Felder
* `filename' und `hostline' gesetzt, der hostname jedoch nicht.
* Ein Aufruf dieser Funktion mit NIL(FILE *) als Argument f"uhrt dazu,
* da\3 der line Counter auf 1 zur"uckgesetzt wird.
*
* INPUTS
* fp - Der Stream aus dem der n"achste Dateiname gelesen
* werden soll
*
* RESULT
* fn - Ein Zeiger auf die erstellte fnode Struktur
*
* SEE ALSO
* flist_from_file()
*
******************************************************************************
*
*/
static fnode_t *fnode_from_file(FILE *fp)
{
static long line= 1;
fnode_t *fn= NIL(fnode_t *);
typedef enum { outer_mode,
word_mode,
string_mode,
return_mode,
error_mode
} smode_t;
smode_t smode= outer_mode;
DD(bug_enter("fnode_from_file"));
if(fp) /* -> neue fnode anlegen und Auspr"agung einlesen */
{
if( fn= fnode_new() )
{
char *fname= (char *)malloc( MAXPATHLEN * sizeof(char) );
if( fname )
{
int c, n=0;
fn->filename= fname;
while( smode != return_mode && smode != error_mode && !feof(fp) )
{
c= fgetc(fp);
if(feof(fp) && c!=EOF)
c= EOF;
switch(c)
{
case ' ': case '\t':
switch(smode)
{
case word_mode:
fname[n++]= '\0';
smode= return_mode;
break;
case string_mode:
fname[n++]= c;
break;
case outer_mode:
case return_mode:
case error_mode:
break;
}
break;
case '\n': case '\r':
switch(smode)
{
case word_mode:
fname[n++]= '\0';
smode= return_mode;
break;
case string_mode:
sprintf(fname,"%ld: unterminated string at EOL; missing quotes `\"'",line);
smode= error_mode;
break;
case outer_mode:
case return_mode:
case error_mode:
break;
}
line++;
{ int d= fgetc(fp);
if(!( (c=='\n' && d=='\r') || (c=='\r' && d=='\n') ))
ungetc(d,fp);
}
break;
case '\"':
switch(smode)
{
case outer_mode:
smode= string_mode;
fn->hostline= line;
break;
case string_mode:
fname[n++]= '\0';
smode= return_mode;
break;
case word_mode:
fname[n++]= '\0';
ungetc(c,fp);
smode= return_mode;
break;
case return_mode:
case error_mode:
break;
}
break;
case EOF:
switch(smode)
{
case word_mode:
if( feof(fp) )
{
fname[n++]= '\0';
smode= return_mode;
}
else fname[n++]= c;
break;
case string_mode:
if( feof(fp) )
{
sprintf(fname,"%ld: unterminated string at EOF; missing quotes `\"'",line);
smode= error_mode;
}
else fname[n++]= c;
break;
case outer_mode:
case return_mode:
case error_mode:
break;
}
break;
default:
switch(smode)
{
case outer_mode:
smode= word_mode;
fn->hostline= line;
/* fall through */
case word_mode:
case string_mode:
fname[n++]= c;
break;
case return_mode:
case error_mode:
break;
}
break;
}
if(n >= MAXPATHLEN)
{
sprintf(fname,"%ld: line too long",line);
smode= error_mode;
}
} /* wend */
if(smode != error_mode)
fname[n]= '\0';
else
fn->hostline= 0;
}
else /* !fname */
fn= fnode_dispose(fn);
}
}
else /* !fp || !fname */
line= 1;
DD(bug_leave("fnode_from_file"));
return fn;
}
/*
* >>> PUBLIC <<<
*/
/****** flist/flist_dispose **************************************************
*
* NAME
* flist_dispose -- Gibt die Liste der Dateinamen frei
*
* SYNOPSIS
* flist_dispose()
*
* void flist_dispose(void);
*
* FUNCTION
*
* SEE ALSO
* flist_addfile(), flist_from_file()
*
******************************************************************************
*
*/
void flist_dispose(void)
{
D(bug_enter("flist_dispose"));
while(flist)
{
fnode_t *t= flist;
flist= flist->next;
(void)fnode_dispose(t);
}
fcurr=
ftail= NIL(fnode_t *);
D(bug_leave("flist_dispose"));
}
/****** flist/flist_addfile **************************************************
*
* NAME
* flist_addfile -- F"ugt einen Dateinamen in die Fileliste ein
*
* SYNOPSIS
* error = flist_addfile(filename)
*
* int flist_addfile(char *);
*
* FUNCTION
* Diese Funktion h"angt einen Dateinamen (wie er z.B. von der command
* line kommt) an das Ende der Liste der Dateinamen an.
*
* INPUTS
* filename - Der Name der Datei
*
* RESULT
* error - 0, wenn alles geklappt hat
* 1, wenn nicht genug Speicher verf"ugbar war
*
* SEE ALSO
* flist_dispose()
*
******************************************************************************
*
*/
int flist_addfile(char *fname)
{
fnode_t *fn= NIL(fnode_t *);
D(bug_enter("flist_addfile \"%s\"",fname));
if(fname)
{
if( fn= fnode_new() )
{
fn->hostname = NIL(char *);
fn->hostline = 0;
fn->filename = strdup(fname);
if(fn->filename)
flist_addnode(fn);
else fn= fnode_dispose(fn);
}
}
D(bug_leave("flist_addfile (%s)", fn ? "successful":"failed"));
return fn ? 0:1;
}
/****** flist/flist_from_file ************************************************
*
* NAME
* flist_from_file -- Baut eine Liste aus den Dateinamen in einem File
*
* SYNOPSIS
* error= flist_from_file(filename);
*
* int flist_from_file(char *);
*
* FUNCTION
* Diese Funktion h"angt alle in der angegebenen Datei aufgef"uhrten
* Dateinamen an die Fileliste an.
*
* INPUTS
* filename - Der Name der Datei mit den Filenamen
*
* RESULT
* error - 0, wenn alles geklappt hat
* 1, im Fehlerfall
*
* SEE ALSO
* flist_dispose()
*
******************************************************************************
*
*/
int flist_from_file(char *host)
{
int rc= 0;
FILE *fp;
D(bug_enter("flist_from_file \"%s\"",host));
if( (fp= fopen(host,"r")) )
{
fnode_t *fn;
/* reset the line counter */
fnode_from_file( NIL(FILE *) );
while( !rc && !feof(fp) && !ferror(fp) )
{
if( fn= fnode_from_file(fp) )
{
if(fn->hostline > 0)
{
if(fn->filename && *fn->filename)
{
fn->hostname= host;
flist_addnode(fn);
}
}
else if(fn->filename && *fn->filename)
{
/* fn->filename contains an error message */
fprintf(stderr,"%s: %s\n",host,fn->filename);
rc= 1;
}
else fn= fnode_dispose(fn); /* EOF */
}
else /* !fn */
{
fprintf(stderr,"%s: %ld: ran out of memory!\n", host, fn->hostline);
rc= 2;
}
}
}
else perror(host);
D(bug_leave("flist_from_file (%s)", rc ? "failed":"successful"));
return rc;
}
/**/
char *flist_getname(void)
{
D(bug("flist_getname()"));
return fcurr ? fcurr->filename : NIL(char *);
}
char *flist_gethost(void)
{
D(bug("flist_gethost()"));
return fcurr ? fcurr->hostname : NIL(char *);
}
long flist_gethostline(void)
{
D(bug("flist_gethostline()"));
return fcurr ? fcurr->hostline : 0L;
}
int flist_nextfile(void)
{
D(bug("flist_nextfile()"));
if(fcurr)
fcurr= fcurr->next;
return fcurr ? 1:0;
}
#if defined(DEBUG) || defined(TEST)
void flist_print(FILE *fp)
{
fnode_t *fn= flist;
D(bug_enter("flist_print"));
if(fn)
{
int n;
fprintf(fp,"list of input files:\n");
for(n=0; fn; n++, fn= fn->next)
fprintf(fp,"\t%s:%ld: \"%s\"\n",
(fn->hostname ? fn->hostname
: "command-line"), fn->hostline, fn->filename);
}
else fprintf(fp,"list of input files is empty\n");
D(bug_leave("flist_print"));
}
#endif /* DEBUG || TEST */
#ifdef TEST
int main(int argc, char **argv)
{
int rc= 0;
char *whoami= argv[0];
while(--argc > 0 && !rc)
{
char *arg= *++argv;
if(*arg == '@')
{
if(arg[1]) ++arg;
else arg= (--argc > 0) ? *(++argv) : (char *)0L;
if(arg && *arg)
{
if( rc= flist_from_file(arg) )
fprintf(stderr,"%s: reading filenames from `%s' failed\n",whoami,arg);
}
else
{
fprintf(stderr,"%s: missing filename after `%s'\n",whoami,*argv);
rc= 1;
}
}
else /* !@... */
{
if( rc= flist_addfile(arg) )
fprintf(stderr,"%s: out of memory... aaaiiiiiieeeeeeeee!\n",whoami);
}
}
if(!rc)
flist_print(stdout);
flist_dispose();
if(rc) fprintf(stderr,"%s: [%s] *** Error %d\n"
"%s terminated abnormally (error %d)\n", whoami, *argv, rc, whoami, rc);
return rc;
}
#endif /* TEST */