v04i033: fortran cross-reference utilities
Bill Silvert
silvert at dalcs.UUCP
Fri Aug 19 22:46:00 AEST 1988
Posting-number: Volume 4, Issue 33
Submitted-by: "Bill Silvert" <silvert at dalcs.UUCP>
Archive-name: fxref
This pair of utilities facilitate Fortran programming.
flink generates various displays of the linkages between subprogram
units, while fxref constructs a cross reference map. fxref is an
update to a program I posted aobut two yeears ago.
Warning -- these expect all Fortran expressions to be in upper
case. Please don't flame me about this, we write standard Fortran.
However, since I have no idea how many group readers use upper case,
I haven't made the effort to write a manual -- run the programs and
see how they work if you are interested. flink has all kinds of
options (type flink -h for a summary), fxref doesn't. They both
expect to be fed a list of Fortran source files.
You will need lex(1) to create C source code from the *.l files.
The only routine needed from -ll is yywrap(), so that is provided --
you can use lex on a Unix system and then compile on any machine
with a C compiler. If you don't have lex, I can mail you flink.c
and fxrefa.c, but these are BIG files.
------------------------------ cut here --------------------------
#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# Makefile
# flink.l
# fxref
# fxrefa.l
# fxrefb.c
# error.c
# yywrap.c
# This archive created: Fri Aug 19 09:39:42 1988
# By: Bill Silvert (Habitat Ecology Div., Bedford Inst. of Oceanography)
export PATH; PATH=/bin:$PATH
if test -f 'Makefile'
then
echo shar: over-writing existing file "'Makefile'"
fi
cat << \SHAR_EOF > 'Makefile'
# makefile for fxref, the f77 xref program from Bourne 8.2.2
CFLAGS = -O
all:
make fxrefa fxrefb flink
flink: flink.c error.o yywrap.o
cc -O -o flink flink.c error.o yywrap.o
fxrefa: fxrefa.c yywrap.o
cc -O -o fxrefa fxrefa.c yywrap.o
fxrefb: fxrefb.c
cc -O -o fxrefb fxrefb.c
flink.c: flink.l
lex flink.l
mv lex.yy.c flink.c
fxrefa.c: fxrefa.l
lex fxrefa.l
mv lex.yy.c fxrefa.c
clean:
rm -f flink.c fxrefa.c lex.yy.c Make.rec
cd SCCS; sccsclean ..
SHAR_EOF
if test -f 'flink.l'
then
echo shar: over-writing existing file "'flink.l'"
fi
cat << \SHAR_EOF > 'flink.l'
/* flink -- f77 call mapper -- from Bourne's C xref, p. 204 */
/* Written by Bill Silvert, August 1988 */
%k 100
%a 1000
%o 1000
%n 200
%e 200
%p 1000
%{
#undef ECHO
static char SCCSID[] = "@(#)flink.l Ver. 1.17, 88/08/17 10:11:33";
char *progname, *filename="-";
#define FWORD 8
#define ESIZE 10
#define SKIP 0
#define PROG 1
#define SUBR 2
#define FUNC 3
#define BLKD 4
#define ENTR 5
#define CALL 9
int status = SKIP; /* flags to define level of name */
char *routine[] = { "",
"PROGRAM",
"SUBROUTINE",
"FUNCTION",
"BLOCK DATA",
"ENTRY",
"",
"",
"",
"CALL"
};
#define OPTTBL 0
#define OPTCAL 1
#define OPTDEP 2
#define OPTENT 3
#define OPTFIL 4
#define OPTBLK 5
#define OPTUNU 6
#define OPTUNS 7
#define OPTSUB 8
int option = OPTTBL;
char *select = NULL; /* name selected as option */
int verbose=1;
int entered=0, linked=0; /* initialization flags */
char unit[FWORD];
typedef struct element { char name[FWORD];
char *file;
int level;
int hit;
int class;
struct element *next;
} ELEMENT;
typedef struct matrix { ELEMENT *i;
ELEMENT *j;
struct matrix *next;
} MATRIX;
/* arrays for data and pointers -- first element of each array is useless */
ELEMENT entry[ESIZE], *lentry=entry+ESIZE-1, *current, *rec;
ELEMENT *newrecord(), *altrecord(), *addrecord();
MATRIX link[ESIZE], *llink=link+ESIZE-1, *index=link;
int type[10]; /* how many subprograms of each type? */
main(argc,argv)
int argc;
char *argv[];
{
extern int optind;
extern char *optarg;
int count, ocount;
progname = argv[0];
strcpy(entry->name, "------"); /* safety defaults */
entry->next = NULL;
link->next = NULL;
for(count=0; count<10; count++)
type[count] = 0;
while((count = getopt(argc, argv, "bcdefqstuvxC:D:F:h")) != EOF)
switch(count) {
case 'b': option = OPTBLK; break;
case 'C': select = optarg;
case 'c': option = OPTCAL; break;
case 'D': select = optarg;
case 'd': option = OPTDEP; break;
case 'e': option = OPTENT; break;
case 'F': select = optarg;
case 'f': option = OPTFIL; break;
case 'q': verbose=0; break;
case 's': option = OPTSUB; break;
case 't': option = OPTTBL; break;
case 'u': option = OPTUNU; break;
case 'x': option = OPTUNS; break;
case 'v': verbose=2; break;
case 'h':
default:
fprintf(stderr,
"%s [-bcdefqtuvx] [-CDF name] file ...\n",
progname);
fprintf(stderr,
"\tb\tBLOCK DATA\n\tc\tCALLs\n\td\tDependencies (reverse of CALLs)\n\te\tENTRY points\n\tf\tFiles in which subprograms occur\n\tq\tQuiet mode\n\tt\tTabular output (default)\n\tu\tUnused subroutines\n\tv\tVerbose mode\n\tx\tunsatisfied eXternals\n\tC name\tCALLs from <name>\n\tD name\tDependencies on <name> (what CALLs it)\n\tF name\tFile in which <name> occurs\n");
exit(1);
}
if(optind >= argc) {
strcpy(unit, "------");
yylex();
if(current && verbose)
fprintf(stderr,
"Missing END statement at end of %s %s\n",
routine[current->class], current->name);
}
else {
for(; optind < argc; optind++) {
if(freopen(argv[optind],"r",stdin)==NULL) {
fprintf(stderr,"%s: %s: cannot open\n",
progname, argv[optind]);
}
else {
filename=argv[optind];
yylineno=1;
strcpy(unit, "------");
yylex();
if(current && verbose) {
fprintf(stderr,
"Missing END statement at end of %s %s in file %s\n",
routine[current->class],
current->name,
filename);
current = NULL;
}
}
}
}
/* Now find all of the dependencies */
switch(type[PROG]) {
case 0: /* no main PROGRAM defined */
status = 1; /* flag */
count = 0; /* test for blank input */
for(rec = entry; rec->class != SUBR; rec = rec->next) {
if(! rec->next) { /* oops -- made it to end */
if(! count)
error_("No program units in input");
/* at this stage, display what we have */
status = 0;
break;
}
else
count++; /* keep track of input */
}
if(status)
rec->level = 1; /* process first subroutine */
else
if(verbose)
fprintf(stderr, "No PROGRAM or SUBROUTINE in input\n");
break;
case 1: /* usual case */
break;
default: if(verbose)
fprintf(stderr, "There are %d PROGRAM units\n\n", type[PROG]);
}
count = type[PROG] + type[FUNC];
status = 1; /* change the use of status to a counter */
do {
ocount = count;
if(verbose>1)
printf("Level %d, count=%d\n", status-1, count);
status++;
for(index = link;;index=index->next) {
if(index->i->level && !index->j->level) {
index->j->hit = status;
}
if(! index->next) break;
}
for(rec=entry;;rec=rec->next) {
if(rec->hit && ! rec->level) {
rec->level = rec->hit;
count++;
}
if(! rec->next) break;
}
} while(count > ocount);
if(! entered)
error_("No subprograms encountered");
/* now generate output */
switch(option) {
case OPTTBL:
tabulate();
break;
case OPTCAL:
if(! linked) error_("No linkages found");
calls();
break;
case OPTDEP:
if(! linked) error_("No linkages found");
depends();
break;
case OPTENT:
if(! linked) error_("No linkages found");
enters();
break;
case OPTFIL:
file();
break;
case OPTBLK:
blocks();
break;
case OPTUNU:
unused();
break;
case OPTUNS:
external();
break;
case OPTSUB:
default:
errord("Option %d not implemented", option);
}
exit(0);
}
tabulate()
{
printf("\nSubroutines called:\nName\tLevel\tFile\n");
for(rec=entry;;rec=rec->next) {
int recl;
recl = rec->class;
if(rec->file && rec->level && recl != ENTR && recl != FUNC)
printf("%s\t%d\t%s\n", rec->name, rec->level-1,rec->file);
if(! rec->next) break;
}
if(type[FUNC]) {
printf("\nFunctions:\nName\tFile\n");
for(rec=entry;;rec=rec->next) {
if(rec->file && rec->class == FUNC) {
printf("%s\t%s\n", rec->name, rec->file);
rec->level++; /* don't list as unused */
}
if(! rec->next) break;
}
}
if(type[ENTR]) {
printf("\nAlternate entry points:\nName\tFile\n");
for(rec=entry;;rec=rec->next) {
if(rec->file && rec->class == ENTR) {
printf("%s\t%s\n", rec->name, rec->file);
rec->level++; /* don't list as unused */
}
if(! rec->next) break;
}
}
if(type[BLKD]) {
printf("\nBLOCK DATA subprograms:\nName\tFile\n");
blocks();
}
printf("\nUnused subprograms:\nName\tFile\n");
if(! unused())
printf("(none)\n");
printf("\nUnsatisfied externals:\nName\tLevel\n");
if(! external())
printf("(none)\n");
/* CALLS to subroutines called by unused subprograms are ignored */
}
blocks()
{
for(rec=entry;;rec=rec->next) {
if(rec->file && rec->class == BLKD) {
printf("%s\t%s\n", rec->name, rec->file);
rec->level++; /* don't list as unused */
}
if(! rec->next) break;
}
}
unused()
{
int k = 0;
for(rec=entry;;rec=rec->next) {
if(rec->file && ! rec->level) {
printf("%s\t%s\n", rec->name, rec->file);
k++;
}
if(! rec->next) break;
}
return k;
}
external()
{
int k = 0;
for(rec=entry;;rec=rec->next) {
if(rec->level && ! rec->file) {
printf("%s\t%d\n", rec->name, rec->level-1);
k++;
}
if(! rec->next) break;
}
return k;
}
calls()
{
if(verbose>1)
printf("Name\tSubroutine called\n");
for(index = link;;index=index->next) {
if(index->i->class != ENTR)
if(!select || !strcmp(index->i->name, select))
printf("%s\t%s\n", index->i->name,
index->j->name);
if(! index->next) break;
}
}
depends()
{
if(verbose>1)
printf("Name\tCalling subroutine\n");
for(index = link;;index=index->next) {
if(index->i->class != ENTR)
if(!select || !strcmp(index->j->name, select))
printf("%s\t%s\n", index->j->name,
index->i->name);
if(! index->next) break;
}
}
enters()
{
if(verbose>1)
printf("Name\tAlternate ENTRY\n");
for(index = link;;index=index->next) {
if(index->i->class == ENTR)
/* if(!select || !strcmp(index->j->name, select)) */
printf("%s\t%s\n", index->j->name,
index->i->name);
if(! index->next) break;
}
}
file()
{
if(verbose>1)
printf("Name\tFile\n");
for(rec=entry;;rec=rec->next) {
if(rec->file) {
if(!select || !strcmp(rec->name, select))
printf("%s\t%s\n", rec->name, rec->file);
}
if(! rec->next) break;
}
}
ELEMENT *newrecord(recname) /* encounter a new program unit */
char *recname;
{
if(current&& verbose)
fprintf(stderr, "%s %s starts before %s %s ends\n",
routine[status], recname,
routine[current->class], current->name);
return altrecord(recname);
}
ELEMENT *altrecord(recname) /* identify program unit or entry point */
char *recname;
{
ELEMENT *newrec;
newrec = addrecord(recname);
if(newrec->file)
errors("Duplicate declaration of %s", recname);
newrec->file = filename;
newrec->class = status;
return newrec;
}
ELEMENT *addrecord(recname) /* find or create matching entry */
char *recname;
{
ELEMENT *add;
if(entered) {
ELEMENT *next;
for(add=entry;;add=add->next) {
if(! strcmp(recname, add->name))
return add;
if(! add->next) /* end of list? */
break;
}
if(add < lentry)
next = add + 1;
else {
next = (ELEMENT *)
calloc(ESIZE,sizeof(ELEMENT));
lentry += ESIZE;
}
add->next = next;
add = next;
}
else {
entered = 1;
add = entry;
}
strcpy(add->name, recname);
add->file = NULL;
add->level = 0;
add->hit = 0;
add->class = 0;
add->next = NULL;
return add;
}
connect(i, j)
ELEMENT *i, *j;
{
if(linked) {
MATRIX *next;
if(index < llink)
next = index + 1;
else {
next = (MATRIX *) calloc(ESIZE, sizeof(MATRIX));
llink += ESIZE;
}
index->next = next;
index = next;
}
else {
linked = 1;
index = link;
}
index->i = i;
index->j = j;
index->next = NULL;
}
%}
%%
^[C*].*\n ; /* skip comments */
^[ \t]*PROGRAM status=PROG;
^[ \t]*SUBROUTINE status=SUBR;
FUNCTION status=FUNC;
^[ \t]*ENTRY status=ENTR;
^[ \t]*BLOCK[ \t]*DATA status=BLKD;
^[ \t]*END[ \t]*\n { strcpy(unit, "------"); current = NULL; }
CALL status=CALL;
^[ \t]*EXTERNAL ;
[0-9.]*[ED][-+0-9]* ; /* skip floating point numbers */
[A-Z][A-Z0-9]* { switch(status) {
case PROG: /* program definition */
strcpy(unit, yytext);
current = newrecord(unit);
current->level = 1;
break;
case SUBR: /* subroutine */
case BLKD: /* block data */
strcpy(unit, yytext);
current = newrecord(unit);
break;
case FUNC: /* function */
strcpy(unit, yytext);
current = newrecord(unit);
current->level = 1; /* assume function is used */
break;
case ENTR: /* entry point */
strcpy(unit, yytext);
connect(altrecord(unit), current);
break;
case CALL: /* call */
if(current)
connect(current, addrecord(yytext));
else
errors("CALL %s with no current subprogram",
yytext);
break;
default:
break;
} ++type[status]; status = SKIP; }
. ;
\n status=SKIP;
SHAR_EOF
if test -f 'fxref'
then
echo shar: over-writing existing file "'fxref'"
fi
cat << \SHAR_EOF > 'fxref'
:
# f77 xref based on Bourne 8.2.2
LIB=/usr/local/etc
# The following is for testing:
LIB=.
case $# in
0) ;;
*) case $1 in
-w*) arg=$1 ; shift ;;
-*) echo "`basename $0: do not understand $1`" ; exit 1 ;;
*) arg= ;;
esac
esac
$LIB/fxrefa $* | sort -ut: +0 -1 +1 -2 +2n -3 | $LIB/fxrefb $arg
SHAR_EOF
chmod +x 'fxref'
if test -f 'fxrefa.l'
then
echo shar: over-writing existing file "'fxrefa.l'"
fi
cat << \SHAR_EOF > 'fxrefa.l'
/* xref.a -- f77 cross reference mapper -- from Bourne's C xref, p. 204 */
%k 100
%a 5000
%o 5000
%n 1000
%e 1500
%p 5000
%{
#undef ECHO
static char SCCSID[] = "@(#)fxrefa.l Ver. 2.17, 88/08/10 15:11:25";
char *filename="-";
char flag, oldflag, equals;
char firstname[8]; /* where the first name encountered gets stored */
main(argc,argv)
int argc;
char *argv[];
{
register int rc=0;
flag = ' ';
oldflag = ' ';
if(argc <= 1) {
yylex();
}
else {
while(argc > 1) {
if(freopen(argv[1],"r",stdin)==NULL) {
fprintf(stderr,"%s: %s: cannot open\n",
argv[0],argv[1]);
rc++;
}
else {
filename=argv[1];
yylineno=1;
yylex();
}
argc--;
argv++;
}
}
return(rc);
}
%}
%%
AIMAG\ *"(" ;
AINT\ *"(" ;
CABS\ *"(" ;
CCOS\ *"(" ;
CEXP\ *"(" ;
CLOG\ *"(" ;
CMPLX\ *"(" ;
CONJG\ *"(" ;
CSIN\ *"(" ;
CSQRT\ *"(" ;
DABS\ *"(" ;
DATAN\ *"(" ;
DATAN2\ *"(" ;
DBLE\ *"(" ;
DCOS\ *"(" ;
DEXP\ *"(" ;
DLOG\ *"(" ;
DLOG10\ *"(" ;
DMAX1\ *"(" ;
DMIN1\ *"(" ;
DMOD\ *"(" ;
DSIGN\ *"(" ;
DSIN\ *"(" ;
DSQRT\ *"(" ;
IABS\ *"(" ;
IDIM\ *"(" ;
IDINT\ *"(" ;
ALOG\ *"(" ;
ALOG10\ *"(" ;
AMAX0\ *"(" ;
AMAX1\ *"(" ;
AMIN0\ *"(" ;
AMIN1\ *"(" ;
AMOD\ *"(" ;
COMPLEX flag = 'C';
DOUBLE\ *PRECISION flag = '#';
IMPLICIT.*\n oldflag=flag='\0';
ISIGN\ *"(" ;
MAX0\ *"(" ;
MAX1\ *"(" ;
MIN0\ *"(" ;
MIN1\ *"(" ;
^[C*].*\n ; /* skip comments */
FORMAT.*\n oldflag=flag='\0'; /* and ignore FORMAT statements */
"\'" {
while(yyinput() != '\''); /* skip quoted material */
}
^" "[^ ] flag=oldflag; /* continuation line */
ABS\ *"(" ;
".AND." ;
ATAN\ *"(" ;
ATAN2\ *"(" ;
BACKSPACE ;
BLOCK\ *DATA flag = 'h';
CALL flag = '@';
CHAR\ *"(" ;
ICHAR\ *"(" ;
CHARACTER flag = '$';
CLOSE\ *"(" ;
COMMON flag = 'c';
CONTINUE ;
COS\ *"(" ;
ACOS\ *"(" ;
DATA flag = 'i';
DIMENSION flag = 'd';
DO\ [0-9 \t,]* flag = 'D';
ELSE\ *IF[ \t]*"(" flag = '?';
ELSE ;
END\ *FILE ;
END\ *IF ;
END ;
ENTRY flag = 'h';
".EQ." ;
EQUIVALENCE\ *"(" flag = '~';
EXP\ *"(" ;
EXTERNAL flag = 'x';
".FALSE." ;
FILE ;
FLOAT\ *"(" ;
FUNCTION flag = 'h';
".GE." ;
GO\ *TO ;
".GT." ;
IF\ *"(" flag = '?';
IFIX\ *"(" ;
INDEX\ *"(" ;
INT\ *"(" ;
NINT\ *"(" ;
INTEGER flag = '%';
INTERNAL flag = 'p';
".LE." ;
LEN\ *"(" ;
LGE\ *"(" ;
LGT\ *"(" ;
LLE\ *"(" ;
LLT\ *"(" ;
LOG\ *"(" ;
LOG10\ *"(" ;
LOGICAL flag = 'L';
".LT." ;
MAX\ *"(" ;
MIN\ *"(" ;
MOD\ *"(" ;
".NE." ;
".NOT." ;
".OR." ;
OPEN\ *"(" flag = 'o';
PARAMETER\ *"(" flag = 'p';
PRINT flag = '>';
PROGRAM flag = 'h';
READ flag = '<';
REAL flag = '!';
REC ;
RECL ;
RETURN ;
REWIND\ *"(" ;
SAVE ;
SIGN\ *"(" ;
SIN\ *"(" ;
SQRT\ *"(" ;
STOP ;
SUBROUTINE flag = 'h';
TANH\ *"(" ;
THEN ;
TO ;
".TRUE." ;
WRITE\ *"(" flag = '>';
[0-9.]*[ED][-+0-9]* ; /* skip floating point numbers */
[A-Z][A-Z0-9]* { if(flag) /* at last we come to variable names! */
if(*firstname)
printf("%s\t%s\t%03d%c\n", yytext, filename, yylineno, flag);
else
strcpy(firstname, yytext); }
= equals++ ;
. ;
\n { if(*firstname) {
if(equals)
printf("%s\t%s\t%03d=\n", firstname, filename, yylineno-1);
else
printf("%s\t%s\t%03d%c\n", firstname,filename,yylineno-1,flag);
*firstname = '\0';
}
oldflag = flag; flag = ' '; equals = 0; }
SHAR_EOF
if test -f 'fxrefb.c'
then
echo shar: over-writing existing file "'fxrefb.c'"
fi
cat << \SHAR_EOF > 'fxrefb.c'
/* second part of f77 xref program. Developed from Bourne p. 207 */
#include <stdio.h>
static char SCCSID[] = "@(#)fxrefb.c Ver. 2.4, 88/08/08 15:53:37";
#define MAXW 256
char lastw[MAXW]; /* last word read */
char lastc;
main(argc,argv)
int argc;
char *argv[];
{
char f1[MAXW], f2[MAXW];
char first=0;
int width, col=0;
switch(argc) {
case 1:
width=80; /* default */
break;
case 2:
if(sscanf(argv[1], "-w%d", &width) == 1) {
width = 5 * (width / 5);
break;
}
default:
printf("%s: illegal argument\n", argv[0]);
exit(1);
}
f1[0]=0;
f2[0]=0;
printf("\t\t\tFlags mean:\n");
printf("h\tprogram unit header \t");
printf("p\tPARAMETER definition \n");
printf("c\tCOMMON statement \t");
printf("~\tEQUIVALENCE \n");
printf("d\tDIMENSION statement \t");
printf("$\tCHARACTER declaration\n");
printf("L\tLOGICAL declaration \t");
printf("%%\tINTEGER declaration \n");
printf("!\tREAL declaration \t");
printf("#\tDOUBLE PRECISION declaration\n");
printf("C\tCOMPLEX declaration \t");
printf("i\tDATA initialization \n");
printf("x\tEXTERNAL \t");
printf("@\tCALL \n");
printf("D\tDO loop control \t");
printf("?\tIF test \n");
printf("=\tassignment statement \t");
printf("o\tOPEN statement \n");
printf("<\tinput \t");
printf(">\toutput \n");
while(word() != EOF) {
if(lastw[0] != first) {
first = lastw[0];
printf("\n");
col=0;
}
if(col >= width) {
printf("\n ");
col=20;
}
if(strcmp(lastw, f1) == 0) {
word();
if( ! strcmp(lastw, f2) == 0) {
printf("\n %-10s", lastw);
col=20;
strcpy(f2, lastw);
}
}
else {
strcpy(f1, lastw);
printf("\n%-10s", f1);
col=10;
word();
strcpy(f2, lastw);
printf("%-10s", f2);
col += 10;
}
if(lastc != '\n') {
word();
printf("%5s", lastw);
col += 5;
}
lastc = 0;
}
printf("\n");
exit(0);
}
int word()
{
register char *p=lastw;
register int c;
if(lastc != '\n') {
while((c = getchar()) != '\t' && c != '\n' && c != EOF) {
if(p < &lastw[MAXW])
*p++ = c;
}
lastc=c;
}
*p++ = 0;
return(lastc);
}
SHAR_EOF
if test -f 'error.c'
then
echo shar: over-writing existing file "'error.c'"
fi
cat << \SHAR_EOF > 'error.c'
#include <stdio.h>
#include <ctype.h>
extern char *progname;
#define PROG if(progname)fprintf(stderr,"%s: ",progname)
/* This is the original version:
extern int errno, sys_nerr;
extern char *sys_errlist[];
#define DIE if(errno>0&&errno<sys_nerr)fprintf(stderr," (%s)",sys_errlist[errno]);fprintf(stderr,"\n");exit(1)
*/
#define DIE fprintf(stderr,"\007\n");exit(1)
error_(s) /* print error message and die -- from K&P p. 207 */
char *s;
{
PROG;
fprintf(stderr, s);
DIE;
}
errord(s, d)
char *s;
int d;
{
PROG;
fprintf(stderr, s, d);
DIE;
}
errors(s1, s2)
char *s1, *s2;
{
PROG;
fprintf(stderr, s1, s2);
DIE;
}
SHAR_EOF
if test -f 'yywrap.c'
then
echo shar: over-writing existing file "'yywrap.c'"
fi
cat << \SHAR_EOF > 'yywrap.c'
yywrap() { /* required for all LEX programs without -ll */
return(1); /* cf. section 9 of Lesk & Schmidt */
} /* if -ll is available, this comes later */
SHAR_EOF
# End of shell archive
exit 0
More information about the Comp.sources.misc
mailing list