Make for Lattice C
Walter Bright
bright at dataio.UUCP
Sat Aug 10 03:27:14 AEST 1985
Well, I got the make posted by grayson at uiucuxc.Uiuc.ARPA, and it
compiled and worked fine. However, the overhead incurred by
the program was 96k! This meant that I couldn't use much of a ramdisk.
The solution was to recompile it with the Lattice 2.14 C compiler,
which doesn't hog 64k for its data segment when it isn't necessary. Also,
the Lattice compiler dropped the size of the .EXE file from 28k (the
Microsoft version) to 20k, making the total overhead of make only
24k bytes! Obviously, for those of us with less than 640k of memory,
a large improvement.
Converting to Lattice C required numerous changes to the source:
o Lattice can't handle unsigned longs.
o Convert the spawnlp() call to forklp() call. WARNING: the
fork functions in Lattice 2.14 are screwed up, so the
way I wrote it is a little funny. If you have 2.15, you
may have to change the fork.
o I had to write a couple of missing library routines, and
kludge up a realloc() function.
o The code had a couple of spots where storage was freed,
but was later referenced. I fixed these.
o I recompiled it with small model.
Anyhow, here's the new source. It's not a shell script, someday I'll
figger out how to write one.
Files are makefile, mstring.h, make.c and mstring.c.
-------------- makefile ------------------
make.exe: make.obj mstring.obj
# link make+mstring/STACK:9000;
link cs+make+mstring,make,make,lcs/map
*.obj : *.c
# msc /AL /Ota $*.c;
lc1 $* -dLATTICE
lc2 $*
mstring.obj : mstring.h
make.obj : mstring.h
-------------- mstring.h -----------------
/* mstring.h */
typedef char * mstring;
mstring mfgets(), mstrcat(), msubstr(), talloc();
-------------- make.c --------------------
/*
* make.c
*
* An imitation of the Unix MAKE facility
*
* Copyright (C) 1984 by Larry Campbell, 73 Concord St., Maynard, Mass.
* Rewritten w/modifications by Mike Hickey, University of DC
*
* This software may be freely copied and disseminated for noncommercial
* purposes, if and only if this entire copyright statement and notice
* is included intact. This software, and the information contained
* herein, may not be used for commercial purposes without my prior
* written permission.
*
* This program runs a new shell (COMMAND.COM) for each command specified
* in the makefile. This, I recommend that you put a copy of the shell in
* ramdisk (if you have one). Assuming your ramdisk is called, say, drive
* F:, you would:
*
*
* COPY A:\COMMAND.COM F:
* SET COMSPEC=F:\COMMAND.COM
*
*/
/* Certain portions of this software are Copyright (C) 1985 by Dan Grayson,
2409 S. Vine St, Urbana, IL 61801, namely all those lines which differ
between versions 2.10 and 2.11. Qualitative descriptions of these
changes are described in the edit history below.
Provided this copyright notice is not changed, and VERS211 below
is not changed, and VERS211 is still prints when 'usage()' runs, these
portions may be freely copied and used for any purpose, with one exception,
namely: those persons or corporations who claim a copyright on this
program or a part of it may not use these portions for any commercial
purpose whatsoever. In particular, they may not collect royalties on
any version of this program which includes these portions. */
/*
* Edit history:
*
* 2.12 Made it compilable by Lattice C version 2.14. Use '-dLATTICE'
* on the command line for this. Default is Microsoft C.
* 2.11 Fixed breakout_symbols, which tried to return a pointer to
a local variable!
Made symbol substitution occur in all lines, not just shell
command lines.
Fixed breakout_symbols, which blew up when a symbol was
undefined.
Allowed blank lines, which are ignored now.
Change command line length to 1000.
Fixed it so MAKE, when no targets are specified on the command
line, will simply make the first target in the makefile.
Remove the command line symbol definition option.
Changed the line continuation character to \ (it was - )
Now symbol definition lines do NOT begin with $.
Fixed numerous bugs dealing with character arrays and their
lengths.
Now a shell command line which begins with @ is not echoed.
A shell command line beginning with + is executed through
command.com ; this makes io redirection and pipes
available, but the exit code of the program cannot
be checked due to a misfeature of command.com.
A shell command line beginning with - may return a nonzero
exit code without halting 'make'.
Fixed it so a target:prerequisite line followed by no how-to
lines is interpreted not as an error, and not as
sharing the how-to lines following the next
target:prerequisite line, but is considered fulfilled
by no action other than making all the
prerequisites.
Fixed the bug which meant the return code from the commmand
was never dicovered. This resulted from using
"system", which uses "command.com", which hides the
return code of the program it runs. Resident
commands can still be used, nevertheless.
Error messages now include the line number of the makefile,
if relevant.
Made the return code of the command print out if nonzero.
Now the copyright notice only prints when the usage appears.
Convert to Microsoft vers 3.00, large memory model.
- dan grayson
* 2.10 Fix bug in abort routine, update copyright notice
* 2.09 Set up for command line parsing of macros
* 2.08 Remove edit 2.05; keep debug a compile-time option
* 2.07 Finish macro parsing
* 2.06 Add initial code for macro handling
* 2.05 Add -d (debug) switch
* 2.04 Add error message handling (doserror).
* 2.03 Add -i (ignore errors) switch.
* 2.02 Add -s (silent run) switch.
* 2.01 Convert to Lattice 2.14. Clean up code for faster execution.
* 1.11 Make default makefilename be MAKEFILE.
* 1.10 Add -n (trace) switch.
* 1.09 Allow multiple targets before colon.
* 1.08 Cleanup and speedup of makefile parsing.
* 1.07 Add continuation lines (hyphen as last char of line)
* 1.06 Don't need to make dummy FCBs, zero seems to work OK.
* 1.05 Fix bug finding COMSPEC when it's not first env variable
* 1.04 Wordier usage text, including copyright notice.
* Remove printf's (except when DEBUG on) to shrink EXE
* 1.03 Don't uppercase shell command and fix datetime bug
* 1.02 Random cleanup
* 1.01 The beginning
*/
#define VERSION "MAKE ver. 2.10 Copyright (C) 1984 by Larry Campbell, Maynard Mass."
#define VERS211 "MAKE ver. 2.12 Portions copyright (C) 1985 by Dan Grayson, Urbana IL."
#ifdef LATTICE
#define assert(a)
#define perror error
#undef LATTICE
#include <dos.h>
#include <stdio.h>
#include <ctype.h>
#include "mstring.h"
extern char *strchr();
typedef long ulong;
#else
#define LINT_ARGS /* for Microsoft v. 3.00 */
#include <assert.h>
#include <process.h>
#include <dos.h>
#include <stdio.h>
#include <malloc.h>
#include <ctype.h>
#include "mstring.h"
#include <string.h>
typedef unsigned long ulong;
#endif
char *dos_commands[] = {
"dir", "type", "rem", "pause", "date", "time",
"ren", "rename", "ver", "vol", "break", "verify",
"mkdir", "md", "exit", "ctty", "echo", "if", "cls",
"chdir", "cd", "rmdir", "rd", "copy", "del", "erase",
NULL };
#define PREREQ_MAGIC 123
#define FILE_MAGIC 543
#define SHELL_MAGIC 678
#define TARG_MAGIC 987
#define SYMBOL_MAGIC 653
#define MAXLIN 1000
#define SYMLEN 1000
#define MAXTARGETS 100
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#define EOS '\0' /* End Of String */
#endif
#define LINESIZE 1000 /* max length of input line */
#define MAXCOMMON 8 /* max no. of targets with common prereqs */
#define tfree(x) if (x) free(x),x=NULL
#ifdef LATTICE
extern char _dos;
#else
extern unsigned char _osmajor; /* in MS ver 3, gives version of OS to left of point */
extern int _doserrno;
#endif
extern int linenumber; /* defined in mstring.c */
char *talloc(), *strperm();
ulong getdatetime ();
static int dontworry=0;
union REGS inregs, outregs;
struct SREGS segregs;
struct SREGS seg;
struct {
char reserved[21];
char attr;
unsigned time, date, size_l, size_h;
char pname[13];
}
find_buf;
/*
* MAKE parses the make file and constructs a somewhat tangled
* directed graph describing dependencies. There is a list of
* TargNode structures, each of which points to a list of
* prereq_node structures. These both point to FileNode structures,
* which contain information about files such as date-time of write
* and the filename. To keep things simple, MAKE insures that only
* one FileNode exists for any given file.
*/
typedef struct FileNode {
#ifndef NDEBUG
int magic;
#endif
char *fname;
struct FileNode *chain;
} *fileptr;
fileptr FileNodeList, NewFileNode ();
typedef struct TargNode {
#ifndef NDEBUG
int magic;
#endif
struct TargNode *next;
fileptr file;
struct prereq_node *PreqList;
struct shell_node *shell_list;
} *targptr;
targptr target_list, new_target (), lookup_target ();
typedef struct prereq_node {
#ifndef NDEBUG
int magic;
#endif
struct prereq_node *next;
fileptr file;
} *preqptr;
preqptr NewPreqNode ();
typedef struct shell_node {
#ifndef NDEBUG
int magic;
#endif
struct shell_node *next;
char *command;
unsigned quiet : 1, ignore : 1, useshell : 1;
} *shellptr;
typedef struct symbol_node {
#ifndef NDEBUG
int magic;
#endif
char *token, *value;
struct symbol_node *next;
} *symbptr;
symbptr SymbolList;
static char *makefilename;
static int status, tracing, quietly, ignore_errors;
usage ()
{
puts (VERS211);
puts (VERSION);
puts ("This program may be copied freely for noncommercial purposes. It may");
puts ("not be copied for commercial use without the author's written permission.\n");
puts ("This program is an imitation of the MAKE program supplied with Unix.");
puts ("It works somewhat like Unix MAKE (and VAX/VMS MMS) except that it has");
puts ("no default rules.\n");
puts ("Usage: make [target ...] [options ...]");
puts ("Options:");
puts (" -f filename specify makefile, default is MAKEFILE");
puts (" -i ignore errors while processing");
puts (" -n trace and print, but don't execute commands");
puts (" -s suppress MAKE echoing commands");
exit (1);
}
main (argc, argv)
int argc;
char **argv;
{
int
argi,
targi,
linlen;
char *targname[MAXTARGETS];
#ifdef LATTICE
if (_dos < 2) error ("Must have DOS 2.XX or higher");
#else
if (_osmajor < 2) error ("Must have DOS 2.XX or higher");
#endif
makefilename = "MAKEFILE";
tracing = quietly = ignore_errors = FALSE;
target_list = 0;
SymbolList = 0;
FileNodeList = 0;
targi = 0;
for (argi = 1; argi < argc; argi++) {
if (argv[argi][0] == '-') /* switch */
switch (argv[argi][1]) { /* switch character */
case 'f':
if (argi < (argc - 1)) makefilename = argv[++argi];
else usage ();
break;
case 'i': ignore_errors = TRUE; break;
case 'n': tracing = TRUE; break;
case 's': quietly = TRUE; break;
default: usage ();
}
else { /* target name */
if (targi == MAXTARGETS) error ("Too many target files");
targname[targi] = strperm (argv[argi]);
targi++;
}
}
if (tracing && quietly) quietly = 0;
parse (makefilename);
if (target_list == NULL) error ("No targets in makefile");
if (targi)
for (argi = 0; argi < targi; argi++) make (targname[argi]);
else {
targptr p;
for (p=target_list; p->next ; p = p->next );
assert (p->magic == TARG_MAGIC);
make(p->file->fname); /* make first target in makefile
i.e. the last one on the list */
}
return 0; /* need good return code */
}
parse (makefilename)
char *makefilename;
{
FILE *fd;
int targi=0, i;
char c, *sp, *dp;
mstring input=NULL;
targptr targ[MAXTARGETS];
fd = fopen (makefilename, "r");
if (fd == NULL) error ("Can't open makefile");
while (1) {
tfree(input);
input = mfgets(fd);
if (input==NULL) break;
#if DEBUG
printf ("Makefile Input: \"%s\"\n", input);
#endif
sp = input;
passpace(&sp);
if (*sp==0 || *sp=='!' || *sp=='#') continue;
/* ignore comment lines and blank lines */
if (isspace(*input)) { /* if leading space, then this is a shell line */
if (targi == 0) error ("Target line must come before shell lines");
sp = input; passpace(&sp);
for (i = 0; i < targi; i++) NewShellLine (targ[i], sp);
continue;
}
{ /* substitute for symbols - this will be done later
for shell lines, to take special symbols like $*
into account, which can only be known at run time
*/
breakout_symbols(&input);
}
{ /*** check for the form 'name = value' ***/
char *endword;
sp=input;
password(&sp); endword = sp;
passpace(&sp);
if (*sp == '=') {
targi=0;
sp++;
*endword = EOS;
SetSymbol (input, sp) ;
continue;
}
} /* end of macro parsing */
/**** now we know this is a 'targets : prerequisite' line ***/
targi=0;
for ( dp = sp = input; 1 ; sp++) /*** collect the targets ***/
if (*sp == ':' || isspace (*sp)) { /* space or colon ends target name */
if (targi == MAXTARGETS) error ("Too many targets in one line");
c = *sp; *sp = EOS;
targ[targi++] = new_target (dp);
*sp = c;
passpace(&sp);
if (*sp == ':') break;
dp = sp;
}
else if (*sp == EOS) error ("no colon");
sp++;
if (targi == 0) error ("No target file before ':' ");
while(1) { /*** collect the prerequisites ***/
passpace(&sp);
if (*sp == EOS) break; /* end of line */
dp = sp; /* beginning of prereq word */
passnonsp(&sp);
c = *sp;
*sp = EOS ; /* end of prereq word */
for (i = 0; i < targi; i++) LinkPreq (targ[i], NewFileNode(dp) );
*sp = c;
}
} /* end while */
tfree(input);
fclose (fd);
linenumber = 0;
}
/*
* new_target
*
* We think we have a new target; this routine scans the
* target list and if we've already seen this name returns
* the node we already built. Otherwise, a new node is
* allocated and linked.
*/
targptr new_target (name)
char *name;
{
targptr targ ;
#if DEBUG
printf ("new_target (\"%s\")\n", name);
#endif
for ( targ = target_list; targ ; targ = targ->next ) {
assert (targ->magic == TARG_MAGIC);
if (strcmp (targ->file->fname, name) == 0) return targ;
}
targ = (targptr) talloc (sizeof (struct TargNode));
#ifndef NDEBUG
targ->magic = TARG_MAGIC;
#endif
targ->file = NewFileNode (name);
targ->next = target_list;
targ->shell_list = NULL;
targ->PreqList = NULL;
target_list = targ;
return targ;
}
SetSymbol (name, value)
char *name, *value;
{
symbptr sym;
for (sym = SymbolList; sym; sym = sym->next)
if (0==strcmp(sym->token,name)) {
free(sym->value);
sym->value = strperm(value) ;
return;
}
sym = (symbptr) talloc (sizeof (struct symbol_node));
#ifndef NDEBUG
sym->magic = SYMBOL_MAGIC;
#endif
sym->token = strperm (name);
sym->value = strperm (value);
sym->next = SymbolList;
SymbolList = sym;
}
/*
* NewShellLine
*
* Add a shell command to the list of commands needed to update
* a target file
*/
NewShellLine (targ, line)
targptr targ;
char *line;
{
shellptr snode, new;
#if DEBUG
printf ("NewShellLine (%x, \"%s\")\n", targ, line);
#endif
new = (shellptr) talloc (sizeof (struct shell_node));
new->next = 0;
#ifndef NDEBUG
new->magic = SHELL_MAGIC;
#endif
new->useshell = new->ignore = 0;
new -> quiet = quietly ;
for ( ; 1 ; line++, passpace(&line) )
if (line[0] == '@') new->quiet = 1;
else if (line[0] == '+') new->useshell = 1;
else if (line[0] == '-') new->ignore = 1;
else break;
new->command = strperm (line);
snode = targ->shell_list;
if (snode) {
assert (snode->magic == SHELL_MAGIC);
while (snode->next) {
snode = snode->next;
assert (snode->magic == SHELL_MAGIC);
}
snode->next = new;
}
else
targ->shell_list = new;
}
/*
* LinkPreq
*
* Link a new prerequisite file onto prereq list for a target.
*/
LinkPreq (targ, fnode)
targptr targ; fileptr fnode; { preqptr p;
#if DEBUG
printf ("LinkPreq (\"%s\")\n", fnode->fname );
#endif
p = targ->PreqList;
( targ->PreqList = NewPreqNode(fnode) ) -> next = p;
}
/*
* NewPreqNode
*
* Allocate and return a new prerequisite node
*/
preqptr
NewPreqNode (fnode)
fileptr fnode;
{
preqptr new;
#if DEBUG
printf ("NewPreqNode (struct FileNode *%x, \"%s\")\n",fnode,fnode->fname);
#endif
new = (preqptr) talloc (sizeof (struct prereq_node));
new->next = NULL;
#ifndef NDEBUG
new->magic = PREREQ_MAGIC;
#endif
new->file = fnode;
return new;
}
/*
* NewFileNode
*
* Return FileNode pointer for a file; returns pointer to
* existing FileNode if this file already seen, else allocates
* and inits a new node
*/
fileptr
NewFileNode (name)
char *name;
{
fileptr fnode;
#if DEBUG
printf ("NewFileNode (\"%s\")\n", name);
#endif
for ( fnode = FileNodeList; fnode; fnode = fnode->chain) {
assert (fnode->magic == FILE_MAGIC);
if (strcmp (name, fnode->fname) == 0) {
#if DEBUG
printf ("NewFileNode returning existing node\n");
#endif
return fnode;
}
}
fnode = (fileptr) talloc (sizeof (struct FileNode));
fnode->fname = strperm (name);
fnode->chain = 0;
#ifndef NDEBUG
fnode->magic = FILE_MAGIC;
#endif
fnode -> chain = FileNodeList;
FileNodeList = fnode;
return fnode;
}
/*
* getdatetime
*
* Return date-time of a file squished into a ulong so compares
* are easy
*/
ulong getdatetime (name)
char *name;
{
ulong datetime;
int dma_off, dma_seg;
#ifdef LATTICE
struct SREGS sregs;
segread(&sregs);
#define FP_SEG(p) (sregs.ds)
#define FP_OFF(p) ((int)(p))
#endif
#ifdef DEBUG
printf("getdatetime(\"%s\")\n",name);
#endif
inregs.x.ax = 0x2F00; /* get current DMA address */
intdosx (&inregs, &outregs, &segregs); /* .. */
dma_off = outregs.x.bx; /* and save for later restoration */
dma_seg = segregs.es;
{ char *p = (char *) & find_buf;
segregs.ds = FP_SEG(p);
inregs.x.dx = FP_OFF(p); /* set DMA to GNJFN block */
}
inregs.x.ax = 0x1A00;
intdosx (&inregs, &outregs, &segregs);
segregs.ds = FP_SEG(name);
inregs.x.dx = FP_OFF(name); /* pathname */
inregs.x.cx = 0; /* attributes */
inregs.x.ax = 0x4E00; /* GTJFN */
#ifdef LATTICE
status = intdosx (&inregs, &outregs, &segregs);
if (status & 1) {
#else
outregs.x.cflag = 0;
status = intdosx (&inregs, &outregs, &segregs);
if (outregs.x.cflag || (status & 1)) {
#endif
#if DEBUG
printf ("File \"%s\" does not exist\n", name);
#endif
return 0L;
}
segregs.ds = dma_seg; /* restore DMA address */
inregs.x.dx = dma_off;
inregs.x.ax = 0x1A00;
intdosx (&inregs, &outregs, &segregs);
#if DEBUG
printf ("filespec = \"%s\", date = %4x, time = %4x, sizel = %d\n",
find_buf.pname, find_buf.date, find_buf.time, find_buf.size_l);
#endif
datetime = (ulong) find_buf.date;
datetime = datetime << 16;
datetime = datetime + find_buf.time;
printf("'%s' %ld\n",find_buf.pname,datetime);
return datetime;
}
/*
* make (name)
*
* This routine actually does the work. It scans the list of
* targets parsed from the makefile, and checks the target's
* prerequisites date/time values against the target's. If
* the prerequisite is itself a target (present in target_list),
* we call make recursively to check it. Then, if any of our
* prerequisites are newer than we are, we execute all our shell
* commands. If there are no prerequisites specified at all, then
* also execute all our shell commands.
*/
int
make (targname) /* use fnode instead of fname here */
char *targname;
{
targptr targ;
preqptr prereq;
ulong NewestPreq=0;
#if DEBUG
printf ("Making %s\n", targname);
#endif
if ((targ = lookup_target (targname)) == 0)
return TryDefault( targname );
prereq = targ->PreqList;
if (prereq)
{
for ( ; prereq; prereq = prereq->next) {
ulong date;
make (prereq->file->fname); /* recursively make */
date = getdatetime(prereq->file->fname);
if (date > NewestPreq) NewestPreq = date;
}
#if DEBUG
printf ("Target \"%s\" datetime is %08lx, newest prereq is %08lx\n",
targ->file->fname, getdatetime(targ->file->fname), NewestPreq);
#endif
if (getdatetime(targ->file->fname) < NewestPreq) build (targ);
}
else build(targ); /* if no prerequisites were listed, do it ! */
if (targ->shell_list == NULL) {
int i;
dontworry ++;
i = TryDefault( targname );
dontworry --;
return i;
}
return 1;
}
TryDefault(targname)
char *targname;{
targptr targ;
char * ext = strchr (targname, '.');
dontworry ++;
if (ext != NULL)
for (targ = target_list ; targ ; targ = targ -> next )
if (targ->file->fname[0] == '*' &&
0 == strcmp ( ext , targ->file->fname+1 ) ) {
char * root = msubstr( targname , 0 , ext-targname );
char *cname;
int worked;
cname = mstrcat( root ,targ->PreqList->file->fname+1 );
worked = make ( cname ) ;
SetSymbol ( "*" , root ) ;
free(root);
if (!worked) {free(cname); goto ret0;}
if (getdatetime(cname) <= getdatetime(targname))
{ free(cname);
goto ret1;
}
free(cname);
build ( targ ) ;
goto ret1;
}
if (getdatetime(targname) > 0) goto ret1;
ret0: /* unsuccessful return */
if (--dontworry) return 0;
else error ("Don't know how to make %s",targname);
ret1: /* successful return */
dontworry--;
return 1;
}
/*
* build
*
* Invoke shell commands to build a target file
*/
build (targ)
targptr targ;
{
shellptr snode;
char *cmd;
int runsts = 0;
#if DEBUG
printf ("Building \"%s\"\n", targ->file->fname);
#endif
for ( snode = targ->shell_list; snode; snode = snode->next, free(cmd) ) {
char *p, **q, *cmdname;
assert (snode->magic == SHELL_MAGIC);
cmd = strperm(snode->command);
breakout_symbols(&cmd); /* notice that this may introduce a space at the beginning of the command line */
cmdname = cmd; passpace(&cmdname);
if (!snode->quiet) fputs (cmdname, stdout);
if (tracing) {
puts (""); /* EXEC does newline, so must be faked */
continue;
}
p = cmdname ; passnonsp(&p);
if (*p) *p++ = EOS ; /* terminate the name of the cmd */
/* find whether it is a dos command */
strlwr(cmdname); /* lower case for comparison */
for (q=dos_commands ; *q ; q++) if (0==strcmp(*q,cmdname)) break;
if (*q || snode->useshell) /* must we use command.com ? */
#ifndef LATTICE
if (0==strcmp(cmdname,"chdir") || 0==strcmp(cmdname,"cd"))
if (passpace (&p) , *p) { /* chdir with arg */
char *q=p;
passnonsp(&q); *q = EOS;
runsts = chdir(p);
}
else { /* chdir without arg */
char name[200];
if (getcwd(name,200)) {
if (!snode->quiet) putchar('\n');
fputs(name,stdout);
}
else error("path name too long");
}
else
#endif
{ /* resident command */
if (*p) *--p = ' '; /* splice command line */
if (strlen(cmdname) > 128) error("shell command line too long");
runsts = system(cmdname);
}
else { /* transient command */
if (strlen(p)+1 > 128) error("shell command line too long");
if (!snode->quiet) putchar ('\n');
#ifdef LATTICE
runsts = forklp(cmdname,cmdname,"",p,NULL);
if (runsts) /* error */
runsts = -1;
else
runsts = wait(); /* get return status */
#else
runsts = spawnlp (P_WAIT, cmdname, "", p, NULL);
#endif
/* can't use 'system()' here, because command.com does not
return the exit code of the program */
}
putchar('\n'); /* some programs do not end with return */
if (runsts == -1) perror("program not found : "), exit(1);
if (runsts > 0 && !snode->ignore && !ignore_errors)
printf ( " --- return code %d ---\7", runsts),
exit(runsts);
}
}
targptr
lookup_target (name)
char *name;
{
targptr targ;
for ( targ = target_list; targ ; targ = targ->next)
if (strcmp (name, targ->file->fname) == 0) break;
return targ;
}
breakout_symbols (cmdlinptr)
char **cmdlinptr; {
char *cmdlin = *cmdlinptr, *cmd = talloc(LINESIZE+100);
symbptr sym;
char symcmp[SYMLEN];
int i, paren, cmdptr;
#if DEBUG
printf("breakout_symbols (\"%s\")\n", cmdlin);
#endif
/* this routine doesn't check for overflow of the line ! */
strcpy ( cmd, "");
cmdptr = 0;
while (1) {
while (*cmdlin != '$' && *cmdlin != EOS) {
if (cmdptr >= LINESIZE) error ("Line too long after symbol substitution");
cmd[cmdptr++] = *cmdlin++;
}
if (cmdptr >= LINESIZE) error ("Line too long after symbol substitution");
cmd[cmdptr] = EOS;
if (0==*cmdlin) break; /* end of line */
cmdlin++; /* pass the $ */
/* now we know we are looking at a symbol */
if (*cmdlin == '(') paren = 1, cmdlin++; else paren=0;
for (i = 0; i < SYMLEN-1 && (*cmdlin == '*' || isalnum (*cmdlin)); )
symcmp[i++] = *cmdlin++;
symcmp[i] = EOS;
if (paren)
if (*cmdlin == ')') cmdlin++;
else puts ("No closing paren on shell line macro");
for ( sym = SymbolList; 1 ; sym = sym->next) {
if (sym==NULL) error ("Undefined symbol %s", symcmp );
assert (sym->magic == SYMBOL_MAGIC);
if (strcmp (sym->token, symcmp) == 0) break;
}
strcpy ( cmd + cmdptr , sym->value );
cmdptr = strlen ( cmd ) ;
}
free(*cmdlinptr);
*cmdlinptr = strperm(cmd);
free(cmd);
#if DEBUG
printf ("breakout_symbols returning (\"%s\")\n", *cmdlinptr);
#endif
}
#ifdef LATTICE
strlwr(p)
char *p;
{
while (*p)
{ *p = tolower(*p);
p++;
}
}
#endif
-------------- mstring.c -----------------
/* mstring.c */
/* The purpose of this file is to provide subroutines for handling
strings whose space is allocated with malloc - in this way we remove
all limitations on length of strings */
#ifdef LATTICE
#include "mstring.h"
#include <ctype.h>
#include <stdio.h>
#else
#include "mstring.h"
#include <ctype.h>
#include <malloc.h>
#include <stdio.h>
#endif
#define DLEN 80
int linenumber = 0;
#ifdef LATTICE
char *realloc(p,newsize)
char *p;
int newsize;
{ char *pnew,*malloc();
pnew = malloc(newsize);
if (pnew)
strcpy(pnew,p);
free(p);
return pnew;
}
#endif
char
lastchar(p)
char *p;{
char c=0;
while (*p) c = *p++;
return c;
}
char *
endptr(p)
char *p;{
while (*p) p++;
return p;
}
mstring
mfgets (stream)
FILE *stream;{
mstring p; int plen;
if (feof(stream)) return NULL;
p = talloc(plen = DLEN);
p[0] = '\0';
while (1) {
if (strlen(p) + DLEN > plen) {
p = realloc(p, plen += DLEN);
if (p==NULL) puts("no more memory (mfgets)"), exit(1);
}
if (NULL == fgets(endptr(p),DLEN,stream))
if (*p) return p;
else {
free(p);
return NULL;
}
if (lastchar(p) != '\n') continue;
linenumber++;
endptr(p)[-1] = 0;
if (lastchar(p) != '\\') {
p = realloc (p,strlen(p)+1) ;
if (p==NULL) puts("no more memory (mfgets)"), exit(1);
return p;
}
endptr(p)[-1] = 0;
}
}
mstring
msubstr(p,i,l) /* creates a string from p[i],p[i+1],...,p[i+l-1] */
mstring p;{
mstring q;
q = talloc(l+1);
strncpy(q,p+i,l);
q[l] = '\0';
return q;
}
mstring
mstrcat(p,q)
mstring p,q;{
mstring r = talloc (strlen(p) + strlen(q) + 1);
strcpy(r,p);
strcat(r,q);
return r;
}
mstring
strperm(s)
char *s;{ /* allocate space for s, return new pointer */
char *t = talloc(strlen(s)+1);
strcpy(t,s);
return t;
}
passpace(p)
char **p;{
while (isspace (**p)) (*p)++;
}
passnonsp(p)
char **p;{
while (**p && !isspace(**p)) (*p)++;
}
password(p)
char **p;{
while (isalnum(**p)) (*p)++;
}
error (errmsg,a,b,c,d,e,f,g,h)
char *errmsg;long a,b,c,d,e,f,g,h;
{
/* unfortunately, this assumes only one file is being used */
if (linenumber) fprintf(stderr,"at line %d : ",linenumber);
fprintf(stderr,errmsg,a,b,c,d,e,f,g,h);
exit (1);
}
mstring
talloc(i)
int i;{
char *p;
char *malloc();
p = malloc(i);
if (p==NULL) error ("no more memory");
return p;
}
More information about the Comp.sources.unix
mailing list