⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 acd.c

📁 操作系统源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
				name= allocate(name, (n*= 2) * sizeof(char));			getdesc();		} while (extalnum(dch));	} else {		/* $* */		name[i++]= dch;		getdesc();	}	name[i++]= 0;	name= allocate(name, i * sizeof(char));	tok->type= SUBST;	tok->subst= newcell();	tok->subst->type= WORD;	tok->subst->name= name;	tok->subst= inc(tok->subst);	return inc(tok);}typedef enum how { SUPERFICIAL, PARTIAL, FULL, EXPLODE, IMPLODE } how_t;cell_t *explode(cell_t *p, how_t how);cell_t *get_string(cell_t **pp)/* Get a string: A series of letters and substs.  Special tokens '=', '+', '-' * and '*' are also recognized if on their own.  A finished string is "exploded" * to a word if it consists of letters only. */{	cell_t *p= *pp, *s= nil, **ps= &s;	int quoted= 0;	while (p != nil) {		switch (p->type) {		case STRING:			quoted= 1;			dec(p);			break;		case EQUALS:		case PLUS:		case MINUS:		case STAR:		case SUBST:		case LETTER:			*ps= cons(STRING, p);			ps= &(*ps)->cdr;			break;		default:			goto got_string;		}		p= get_token();	}    got_string:	*pp= p;	/* A single special token must be folded up. */	if (!quoted && s != nil && s->cdr == nil) {		switch (s->car->type) {		case EQUALS:		case PLUS:		case MINUS:		case STAR:		case SUBST:			return go(s, s->car);		}	}	/* Go over the string changing '=', '+', '-', '*' to letters. */	for (p= s; p != nil; p= p->cdr) {		int c= 0;		switch (p->car->type) {		case EQUALS:			c= '='; break;		case PLUS:			c= '+'; break;		case MINUS:			c= '-'; break;		case STAR:			c= '*'; break;		}		if (c != 0) {			dec(p->car);			p->car= newcell();			p->car->type= LETTER;			p->car->letter= c;			p->car= inc(p->car);		}	}	return explode(s, SUPERFICIAL);}cell_t *get_list(cell_t **pp, type_t stop)/* Read a series of tokens upto a token of type "stop". */{	cell_t *p= *pp, *l= nil, **pl= &l;	while (p != nil && p->type != stop				&& !(stop == EOLN && p->type == SEMI)) {		switch (p->type) {		case WHITE:		case COMMENT:		case SEMI:		case EOLN:			dec(p);			p= get_token();			break;		case OPEN:			/* '(' words ')'. */			dec(p);			p= get_token();			*pl= cons(CELL, get_list(&p, CLOSE));			pl= &(*pl)->cdr;			dec(p);			p= get_token();			break;		case CLOSE:			/* Unexpected closing parenthesis. (*/			fprintf(stderr, "\"%s\", line %u: unmatched ')'\n",				descr, lineno);			action= 0;			dec(p);			p= get_token();			break;		case INPUT:		case OUTPUT:			*pl= cons(CELL, p);			pl= &(*pl)->cdr;			p= get_token();			break;		case STRING:		case EQUALS:		case PLUS:		case MINUS:		case STAR:		case LETTER:		case SUBST:			*pl= cons(CELL, get_string(&p));			pl= &(*pl)->cdr;			break;		default:			assert(0);		}	}	if (p == nil && stop == CLOSE) {		/* Couldn't get the closing parenthesis. */		fprintf(stderr, "\"%s\", lines %u-%u: unmatched '('\n",	/*)*/			descr, pc->lineno, lineno);		action= 0;	}	*pp= p;	return l;}program_t *get_line(cell_t *file){	program_t *l;	cell_t *p;	static keep_indent= 0;	static unsigned old_indent= 0;	/* Skip leading whitespace to determine the indentation level. */	indent= 0;	while ((p= get_token()) != nil && p->type == WHITE) dec(p);	if (p == nil) return nil;		/* EOF */	if (p->type == EOLN) indent= old_indent;	/* Empty line. */	/* Make a program line. */	pc= l= allocate(nil, sizeof(*l));	l->next= nil;	l->file= inc(file);	l->indent= keep_indent ? old_indent : indent;	l->lineno= lineno;	l->line= get_list(&p, EOLN);	/* If the line ended in a semicolon then keep the indentation level. */	keep_indent= (p != nil && p->type == SEMI);	old_indent= l->indent;	dec(p);	if (verbose >= 4) {		if (l->line == nil)			fputc('\n', stdout);		else {			printf("%*s", (int) l->indent, "");			prin2n(l->line);		}	}	return l;}program_t *get_prog(void)/* Read the description file into core. */{	cell_t *file;	program_t *prog, **ppg= &prog;	descr= copystr(descr);	if (descr[0] == '-' && descr[1] == 0) {		/* -descr -: Read from standard input. */		deallocate(descr);		descr= copystr("stdin");		dfp= stdin;	} else {		char *d= descr;		if (*d == '.' && *++d == '.') d++;		if (*d != '/') {			/* -descr name: Read /usr/lib/<name>/descr. */			d= allocate(nil, sizeof(LIB) +					(strlen(descr) + 7) * sizeof(*d));			sprintf(d, "%s/%s/descr", LIB, descr);			deallocate(descr);			descr= d;		}		if ((dfp= fopen(descr, "r")) == nil) fatal(descr);	}	file= findword(descr);	deallocate(descr);	descr= file->name;	/* Preread the first character. */	dch= 0;	lineno= 1;	indent= 0;	getdesc();	while ((*ppg= get_line(file)) != nil) ppg= &(*ppg)->next;	if (dfp != stdin) (void) fclose(dfp);	dec(file);	return prog;}void makenames(cell_t ***ppr, cell_t *s, char **name, size_t i, size_t *n)/* Turn a string of letters and lists into words.  A list denotes a choice * between several paths, like a search on $PATH. */{	cell_t *p, *q;	size_t len;	/* Simply add letters, skip empty lists. */	while (s != nil && (s->car == nil || s->car->type == LETTER)) {		if (s->car != nil) {			if (i == *n) *name= allocate(*name,						(*n *= 2) * sizeof(**name));			(*name)[i++]= s->car->letter;		}		s= s->cdr;	}	/* If the end is reached then make a word out of the result. */	if (s == nil) {		**ppr= cons(CELL, findnword(*name, i));		*ppr= &(**ppr)->cdr;		return;	}	/* Elements of a list must be tried one by one. */	p= s->car;	s= s->cdr;	while (p != nil) {		if (p->type == WORD) {			q= p; p= nil;		} else {			assert(p->type == CELL);			q= p->car; p= p->cdr;			assert(q != nil);			assert(q->type == WORD);		}		len= strlen(q->name);		if (i + len > *n) *name= allocate(*name,					(*n += i + len) * sizeof(**name));		memcpy(*name + i, q->name, len);		makenames(ppr, s, name, i+len, n);	}}int constant(cell_t *p)/* See if a string has been partially evaluated to a constant so that it * can be imploded to a word. */{	while (p != nil) {		switch (p->type) {		case CELL:		case STRING:			if (!constant(p->car)) return 0;			p= p->cdr;			break;		case SUBST:			return 0;		default:			return 1;		}	}	return 1;}cell_t *evaluate(cell_t *p, how_t how);cell_t *explode(cell_t *s, how_t how)/* Explode a string with several choices to just one list of choices. */{	cell_t *t, *r= nil, **pr= &r;	size_t i, n;	char *name;	struct stat st;	if (how >= PARTIAL) {		/* Evaluate the string, expanding substitutions. */		while (s != nil) {			assert(s->type == STRING);			t= inc(s->car);			s= go(s, s->cdr);			t= evaluate(t, how == IMPLODE ? EXPLODE : how);			/* A list of one element becomes that element. */			if (t != nil && t->type == CELL && t->cdr == nil)				t= go(t, t->car);			/* Append the result, trying to flatten it. */			*pr= t;			/* Find the end of what has just been added. */			while ((*pr) != nil) {				*pr= append(STRING, *pr);				pr= &(*pr)->cdr;			}		}		s= r;	}	/* Is the result a simple string of constants? */	if (how <= PARTIAL && !constant(s)) return s;	/* Explode the string to all possible choices, by now the string is	 * a series of characters, words and lists of words.	 */	r= nil; pr= &r;	name= allocate(nil, (n= 16) * sizeof(char));	i= 0;	makenames(&pr, s, &name, i, &n);	deallocate(name);	assert(r != nil);	dec(s);	s= r;	/* "How" may specify that a choice must be made. */	if (how == IMPLODE) {		if (s->cdr != nil) {			/* More than one choice, find the file. */			do {				assert(s->car->type == WORD);				if (stat(s->car->name, &st) >= 0)					return go(r, s->car);	/* Found. */			} while ((s= s->cdr) != nil);		}		/* The first name is the default if nothing is found. */		return go(r, r->car);	}	/* If the result is a list of one word then return that word, otherwise	 * turn it into a string again unless this explode has been called	 * by another explode.  (Exploding a string inside a string, the joys	 * of recursion.)	 */	if (s->cdr == nil) return go(s, s->car);	return how >= EXPLODE ? s : cons(STRING, s);}void modify(cell_t **pp, cell_t *p, type_t mode)/* Add or remove the element p from the list *pp. */{	while (*pp != nil) {		*pp= append(CELL, *pp);		if ((*pp)->car == p) {			/* Found it, if adding then exit, else remove. */			if (mode == PLUS) break;			*pp= go(*pp, (*pp)->cdr);		} else			pp= &(*pp)->cdr;	}	if (*pp == nil && mode == PLUS) {		/* Not found, add it. */		*pp= cons(CELL, p);	} else		dec(p);}int tainted(cell_t *p)/* A variable is tainted (must be substituted) if either it is marked as a * local variable, or some subst in its value is. */{	if (p == nil) return 0;	switch (p->type) {	case CELL:	case STRING:		return tainted(p->car) || tainted(p->cdr);	case SUBST:		return p->subst->flags & W_LOCAL || tainted(p->subst->value);	default:		return 0;	}}cell_t *evaluate(cell_t *p, how_t how)/* Evaluate an expression, usually the right hand side of an assignment. */{	cell_t *q, *t, *r= nil, **pr= &r;	type_t mode;	if (p == nil) return nil;	switch (p->type) {	case CELL:		break;	/* see below */	case STRING:		return explode(p, how);	case SUBST:		if (how >= FULL || tainted(p))			p= evaluate(go(p, p->subst->value), how);		return p;	case EQUALS:		fprintf(stderr,			"\"%s\", line %u: Can't do nested assignments\n",			descr, pc->lineno);		action= 0;		dec(p);		return nil;	case LETTER:	case WORD:	case INPUT:	case OUTPUT:	case PLUS:	case MINUS:		return p;	default:		assert(0);	}	/* It's a list, see if there is a '*' there forcing a full expansion,	 * or a '+' or '-' forcing an implosive expansion.  (Yeah, right.)	 * Otherwise evaluate each element.	 */	q = inc(p);	while (p != nil) {		if ((t= p->car) != nil) {			if (t->type == STAR) {				if (how < FULL) how= FULL;				dec(q);				*pr= evaluate(go(p, p->cdr), how);				return r;			}			if (how>=FULL && (t->type == PLUS || t->type == MINUS))				break;		}		t= evaluate(inc(t), how);		assert(p->type == CELL);		p= go(p, p->cdr);		if (how >= FULL) {			/* Flatten the list. */			*pr= t;		} else {			/* Keep the nested list structure. */			*pr= cons(CELL, t);		}		/* Find the end of what has just been added. */		while ((*pr) != nil) {			*pr= append(CELL, *pr);			pr= &(*pr)->cdr;		}	}	if (p == nil) {		/* No PLUS or MINUS: done. */		dec(q);		return r;	}	/* A PLUS or MINUS, reevaluate the original list implosively. */	if (how < IMPLODE) {		dec(r);		dec(p);		return evaluate(q, IMPLODE);	}	dec(q);	/* Execute the PLUSes and MINUSes. */	while (p != nil) {		t= inc(p->car);		p= go(p, p->cdr);		if (t != nil && (t->type == PLUS || t->type == MINUS)) {			/* Change the add/subtract mode. */			mode= t->type;			dec(t);			continue;		}		t= evaluate(t, IMPLODE);		/* Add or remove all elements of t to/from r. */		while (t != nil) {			if (t->type == CELL) {				modify(&r, inc(t->car), mode);			} else {				modify(&r, t, mode);				break;			}			t= go(t, t->cdr);		}	}	return r;}/* An ACD program can be in three phases: Initialization (the first run * of the program), argument scanning, and compilation. */typedef enum phase { INIT, SCAN, COMPILE } phase_t;phase_t phase;typedef struct rule {		/* Transformation rule. */	struct rule	*next;	char		type;		/* arg, transform, combine */	char		flags;	unsigned short	npaths;		/* Number of paths running through. */#	define	match	from		/* Arg matching strings. */	cell_t		*from;		/* Transformation source suffixe(s) */	cell_t		*to;		/* Destination suffix. */	cell_t		*wait;		/* Files waiting to be transformed. */	program_t	*prog;		/* Program to execute. */	struct rule	*path;		/* Transformation path. */} rule_t;typedef enum ruletype { ARG, PREFER, TRANSFORM, COMBINE } ruletype_t;#define R_PREFER	0x01		/* A preferred transformation. */rule_t *rules= nil;void newrule(ruletype_t type, cell_t *from, cell_t *to)/* Make a new rule cell. */{	rule_t *r= nil, **pr= &rules;	/* See if there is a rule with the same suffixes, probably a matching	 * transform and prefer, or a re-execution of the same arg command.	 */	while ((r= *pr) != nil) {		if (r->from == from && r->to == to) break;		pr= &r->next;	}	if (*pr == nil) {		/* Add a new rule. */		*pr= r= allocate(nil, sizeof(*r));		r->next= nil;		r->type= type;		r->flags= 0;		r->from= r->to= r->wait= nil;		r->path= nil;	}	if (type == TRANSFORM) r->type= TRANSFORM;	if (type == PREFER) r->flags|= R_PREFER;	if (type != PREFER) r->prog= pc;	dec(r->from); r->from= from;	dec(r->to); r->to= to;}int talk(void)/* True if verbose and if so indent what is to come. */{	if (verbose < 3) return 0;	printf("%*s", (int) pc->indent, "");	return 1;}void unix_exec(cell_t *c)/* Execute the list of words p as a UNIX command. */{	cell_t *v, *a;	int fd[2];	int *pf;	char **argv;	int i, n;	int r, pid, status;	if (action == 0) return;	/* Error mode. */	if (talk() || verbose >= 2) prin2n(c);	fd[0]= fd[1]= -1;	argv= allocate(nil, (n= 16) * sizeof(*argv));	i= 0;	/* Gather argv[] and scan for I/O redirection. */	for (v= c; v != nil; v= v->cdr) {		a= v->car;		pf= nil;		if (a->type == INPUT) pf= &fd[0];		if (a->type == OUTPUT) pf= &fd[1];		if (pf == nil) {			/* An argument. */			argv[i++]= a->name;			if (i==n) argv= allocate(argv, (n*= 2) * sizeof(*argv));			continue;		}		/* I/O redirection. */		if ((v= v->cdr) == nil || (a= v->car)->type != WORD) {			fprintf(stderr,			"\"%s\", line %u: I/O redirection without a file\n",				descr, pc->lineno);			action= 0;			if (v == nil) break;		}		if (*pf >= 0) close(*pf);		if (action >= 2			&& (*pf= open(a->name, pf == &fd[0] ? O_RDONLY				: O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0		) {			report(a->name);			action= 0;		}	}	argv[i]= nil;	if (i >= 0 && action > 0 && verbose == 1) {		char *name= strrchr(argv[0], '/');		if (name == nil) name= argv[0]; else name++;		printf("%s\n", name);	}	if (i >= 0 && action >= 2) {		/* Really execute the command. */		fflush(stdout);		switch (pid= fork()) {		case -1:			fatal("fork()");		case 0:			if (fd[0] >= 0) { dup2(fd[0], 0); close(fd[0]); }			if (fd[1] >= 0) { dup2(fd[1], 1); close(fd[1]); }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -