📄 make.c
字号:
/*
* make.c - a program for maintaining computer programs
* written by MORI, Koichiro (kmori@mixcosy)
*/
static char rcsID[] = "$Header: RCS/make.c 1.13 90/11/02 11:48:00 kmori Exp $";
/*
* Compile switch
* -DOLDLSIFASHION Set if '<' & '.PATH' required
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <time.h>
#include <dos.h>
#pragma nonrec
char Usage[] = "\
Make (C) 1987-1990 by MORI, Koichiro $Revision: 1.13 $\n\
Usage: make [options] [MACRO=value] [targets...]\n\
options:\n\
-f FILE read make command from file 'FILE'\n\
-i ignore return code\n\
-k make targets as many as possible\n\
-n do not execute; print what will be done\n\
-r do not use makedef\n\
-s do work silently\n\
-t only update timestamps\n\
";
typedef char bool;
#define YES 1
#define NO 0
typedef struct command {
struct command *next;
char body[0];
} command;
typedef struct atom {
struct atom *next;
char *name;
char *macro;
struct list *src;
command *commands;
time_t uptime;
bool visit;
bool userdef;
char type;
} ATOM;
typedef struct list {
struct list *next;
struct atom *atom;
} LIST;
bool Nflag, Tflag, Sflag, Iflag, Dflag, Kflag; /* make options */
bool Case; /* true if differentiating upper/lower case */
bool BsdMacro; /* true if ${..} treated as macro expansion */
#define MAXBACK 2048
FILE *Mfp;
char *Mfile;
int Lineno;
char Backs[MAXBACK];
char *Backp = Backs;
#define MAXNAME 100
#define forall(x, y) for ((x) = (y); (x) != NULL; (x) = (x)->next)
/*
*
*/
void error(char *p, char *str)
{
fprintf(stderr, "make: ");
if (Mfp != NULL)
fprintf(stderr, "%s %d: ", Mfile, Lineno);
fprintf(stderr, p, str);
exit(1);
}
#define new(t, n) ((t *)rawnew(sizeof(t) * (n)))
void *rawnew(unsigned size)
{
void *p;
if ((p = calloc(size, 1)) == NULL)
error("out of memory\n", NULL);
return (p);
}
int cmpsym(char *s, char *t)
{
if (Case)
return (strcmp(s, t));
for (; *s && tolower(*s) == tolower(*t); s++, t++)
;
return (*s - *t);
}
#define NHASH 1024
static ATOM *Atoms[NHASH];
unsigned hash(char *s)
{
unsigned n;
n = 0;
while (*s)
n = n * 129 + tolower(*s++);
return (n % NHASH);
}
ATOM *lookup1(char *name, bool reg)
{
ATOM *a;
char *s;
unsigned n;
forall (a, Atoms[n = hash(name)]) {
if (cmpsym(a->name, name) == 0)
return (a);
}
if (*name != '.' && (s = getenv(name)) != NULL) {
a = new(ATOM, 1);
a->name = strcpy(new(char, strlen(name) + 1), name);
a->next = Atoms[n];
Atoms[n] = a;
a->macro = s;
return (a);
}
if (reg) {
a = new(ATOM, 1);
a->name = strcpy(new(char, strlen(name) + 1), name);
a->next = Atoms[n];
Atoms[n] = a;
return (a);
}
return (NULL);
}
#define lookup(name) lookup1(name, 0)
#define intern(name) lookup1(name, 1)
/*
* Module get/put
*/
int unget(int c)
{
if (c == EOF)
return (EOF);
if (Backp >= Backs + MAXBACK)
error("can't unget (maybe too long macro)\n", NULL);
return (*Backp++ = c);
}
void ungets(char *s)
{
char *p;
for (p = s + strlen(s); --p >= s; )
unget((int)*p);
}
int quoget()
{
int c;
if (Backp > Backs)
return (*--Backp);
if (Mfp == NULL)
return (EOF);
c = getc(Mfp);
if (c == '\n')
Lineno++;
}
static char Longmsg[] = "Too long identifier: %s...\n";
int get()
{
char name[MAXNAME + 1];
char *p;
int c, term;
ATOM *m;
for (;;) {
if ((c = quoget()) != '$' || (c = quoget()) == '$')
return (c);
if (!BsdMacro && c == '{')
return (-'{');
if (c == '@' || c == '<' || c == '*' || c == '>' || c == '?' ||
c == '#' || c == '&' || c == '[' || c == ':')
return (-c);
/* do macro evaluation */
p = name;
if (c == '(' || c == '{') {
term = c == '(' ? ')' : '}';
while ((c = quoget()) != term) {
if (p >= name + MAXNAME) {
*p = '\0';
error(Longmsg, name);
}
*p++ = c;
}
}
else if (!BsdMacro && (isalpha(c) || isdigit(c))) {
while (isalpha(c) || isdigit(c)) {
if (p >= name + MAXNAME) {
*p = '\0';
error(Longmsg, name);
}
*p++ = c;
c = quoget();
}
unget(c);
}
else
*p++ = c;
*p = '\0';
if ((m = lookup(name)) != NULL && m->macro != NULL)
ungets(m->macro);
}
}
/*
*/
static ATOM *Backtok = NULL;
bool isbreak(int c)
{
return (c == ' ' || c == '\t' || c == '\n' ||
c == EOF || c == '=' || c == '#' || c == '<');
}
bool ColonBreak = NO;
ATOM *gettok()
{
char buf[MAXNAME + 1];
char *p;
int c, b;
ATOM *a;
if ((a = Backtok) != NULL) {
Backtok = NULL;
return (a);
}
for (;;) {
while ((c = get()) == ' ' || c == '\t')
;
if (c != '\\')
break;
if ((b = get()) != '\n') {
unget(b);
break;
}
}
if (c == '#')
while ((c = quoget()) != '\n' && c != EOF)
;
p = buf;
if (c == EOF)
return (NULL);
else if (c == '\n' || c == ':' || c == '=' || c == '<' || c == ';')
*p++ = c;
else {
while (! isbreak(c)) {
if (c == ':' && ColonBreak && isbreak(unget(get())))
break;
if (p >= buf + MAXNAME) {
*p = '\0';
error(Longmsg, buf);
}
*p++ = c;
c = get();
}
unget(c);
}
*p = '\0';
return (intern(buf));
}
void ungettok(ATOM *a)
{
if (Backtok != NULL)
error("can't ungettok\n", NULL);
Backtok = a;
}
/* reserve some keywords */
ATOM *NEWLINE, *EQUAL, *COLON, *LESS, *SEMICOLON,
*SUFFIXES, *IGNORE, *SILENT, *MFLAGS, *MAKE, *CASE, *MACRO;
void initgettok()
{
NEWLINE = intern("\n");
EQUAL = intern("=");
COLON = intern(":");
LESS = intern("<");
SEMICOLON = intern(";");
SUFFIXES = intern(".SUFFIXES");
IGNORE = intern(".IGNORE");
SILENT = intern(".SILENT");
CASE = intern(".CASE");
MACRO = intern(".MACRO");
MFLAGS = intern("MFLAGS");
MAKE = intern("MAKE");
}
LIST *cons(ATOM *atom, LIST *next)
{
LIST *l;
l = new(LIST, 1);
l->next = next;
l->atom = atom;
return (l);
}
recursive LIST *append(LIST *x, LIST *y)
{
return (x == NULL ? y : cons(x->atom, append(x->next, y)));
}
recursive LIST *getlist()
{
ATOM *s;
if ((s = gettok()) == NULL || s == NEWLINE ||
s == LESS || s == EQUAL || s == COLON || s == SEMICOLON) {
ungettok(s);
return (NULL);
}
return (cons(s, getlist()));
}
static char Lines[2048];
command *getcom(ATOM *t)
{
int c;
char *s;
command *p, *q;
p = NULL;
for (;;) {
c = quoget();
if (c == '#') {
while ((c = quoget()) != '\n' && c != EOF)
;
continue;
} else if (t != SEMICOLON && c != '\t')
break;
t = NULL;
while (c == ' ' || c == '\t')
c = quoget();
s = Lines;
while (c != '\n' && c != EOF) {
*s++ = c;
c = quoget();
}
*s++ = '\n';
*s++ = '\0';
q = rawnew(sizeof(command) + (s - Lines));
strcpy(q->body, Lines);
q->next = p;
p = q;
}
unget(c);
return (p);
}
char *getline()
{
int c;
char *s;
while ((c = quoget()) == ' ' || c == '\t')
;
s = Lines;
while (c != '\n' && c != EOF) {
*s = c;
c = quoget();
if (*s == '\\' && c == '\n') {
while ((c = quoget()) == ' ' || c == '\t')
;
} else {
s++;
}
}
*s++ = '\0';
return (strcpy(new(char, s - Lines), Lines));
}
bool exist(char *file)
{
int fd;
if ((fd = open(file, 0)) < 0)
return (NO);
close(fd);
return (YES);
}
time_t timeof(ATOM *file)
{
time_t times[2];
if (file->uptime != 0)
return (file->uptime);
if (gftime(file->name, times))
return (0);
return (file->uptime = times[1]);
}
void touch(ATOM *file)
{
time_t times[2];
file->uptime = times[0] = times[1] = time(0);
utime(file->name, times);
}
void setcommand(ATOM *atom, command *com)
{
if (com == NULL)
return;
if (atom->name[0] != '.' &&
atom->commands != NULL && atom->commands != com)
error("2 or more commands for '%s'\n", atom->name);
atom->commands = com;
}
ATOM *readmake(char *fn)
{
ATOM *a, *deftar;
LIST *l, *r, *f;
char type;
command *com;
char *mac;
errno = 0;
Mfile = fn;
Lineno = 1;
if (strcmp(fn, "-") == 0)
Mfp = stdin;
else
if ((Mfp = fopen(fn, "r")) == NULL)
return (NULL);
deftar = NULL;
ColonBreak = YES;
while ((a = gettok()) != NULL) {
if (a == NEWLINE)
continue;
ungettok(a);
l = getlist();
if ((type = ':', (a = gettok()) == COLON) ||
(type = '<', a == LESS)) {
/* dependency line */
ColonBreak = NO;
r = getlist();
ColonBreak = YES;
if ((a = gettok()) != NEWLINE && a != SEMICOLON)
error("bad delimiter: '%s'\n", a->name);
com = getcom(a);
forall (f, l) {
if (f->atom == SILENT)
Sflag = YES;
else if (f->atom == IGNORE)
Iflag = YES;
else if (f->atom == SUFFIXES && r == NULL)
f->atom->src = NULL;
else if (f->atom == CASE)
Case = YES;
else if (f->atom == MACRO)
BsdMacro = YES;
setcommand(f->atom, com);
f->atom->src = append(f->atom->src, r);
if (deftar == NULL && f->atom->name[0] != '.')
deftar = f->atom;
f->atom->type = type;
}
} else if (a == EQUAL) {
/* macro definition */
mac = getline();
forall (f, l)
if (! f->atom->userdef)
f->atom->macro = mac;
} else
error("missing ':' after '%s'\n", l->atom->name);
}
fclose(Mfp);
Mfp = NULL;
return (deftar);
}
char *suffix(char *s)
{
char *p;
p = NULL;
while (*s) {
if (*s == '.')
p = s;
s++;
}
return (p ? p : s);
}
char *prefix(char *buf, char *s)
{
char *p, *d;
p = suffix(s);
d = buf;
while (s < p)
*d++ = *s++;
*d = '\0';
return (buf);
}
char *barename(char *s)
{
char *p, c;
p = s;
while (c = *p++)
if (c == ':' || c == '\\' || c == '/')
s = p;
return (s);
}
void complete_unix(ATOM *tar) /* complete commands */
{
LIST *l;
#ifdef OLDLSIFASHION
LIST *m;
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -