750 lines · 10.6 KB · C
RawDownload
#include "a.h" enum{	MAXREQ = 100,	MAXRAW = 40,	MAXESC = 60,	MAXLINE = 1024,	MAXIF = 20,	MAXARG = 10,}; typedef struct Esc Esc;typedef struct Req Req;typedef struct Raw Raw; /* escape sequence handler, like for \c */struct Esc{	Rune r;	int (*f)(void);	int mode;}; /* raw request handler, like for .ie */struct Raw{	Rune *name;	void (*f)(Rune*);}; /* regular request handler, like for .ft */struct Req{	int argc;	Rune *name;	void (*f)(int, Rune**);}; int		dot = '.';int		tick = '\'';int		backslash = '\\'; int		inputmode;Req		req[MAXREQ];int		nreq;Raw		raw[MAXRAW];int		nraw;Esc		esc[MAXESC];int		nesc;int		iftrue[MAXIF];int		niftrue; int isoutput;int linepos;  voidaddraw(Rune *name, void (*f)(Rune*)){	Raw *r;		if(nraw >= nelem(raw)){		fprint(2, "too many raw requets\n");		return;	}	r = &raw[nraw++];	r->name = erunestrdup(name);	r->f = f;} voiddelraw(Rune *name){	int i;		for(i=0; i<nraw; i++){		if(runestrcmp(raw[i].name, name) == 0){			if(i != --nraw){				free(raw[i].name);				raw[i] = raw[nraw];			}			return;		}	}} voidrenraw(Rune *from, Rune *to){	int i;		delraw(to);	for(i=0; i<nraw; i++)		if(runestrcmp(raw[i].name, from) == 0){			free(raw[i].name);			raw[i].name = erunestrdup(to);			return;		}}  voidaddreq(Rune *s, void (*f)(int, Rune**), int argc){	Req *r; 	if(nreq >= nelem(req)){		fprint(2, "too many requests\n");		return;	}	r = &req[nreq++];	r->name = erunestrdup(s);	r->f = f;	r->argc = argc;} voiddelreq(Rune *name){	int i; 	for(i=0; i<nreq; i++){		if(runestrcmp(req[i].name, name) == 0){			if(i != --nreq){				free(req[i].name);				req[i] = req[nreq];			}			return;		}	}} voidrenreq(Rune *from, Rune *to){	int i;		delreq(to);	for(i=0; i<nreq; i++)		if(runestrcmp(req[i].name, from) == 0){			free(req[i].name);			req[i].name = erunestrdup(to);			return;		}} voidaddesc(Rune r, int (*f)(void), int mode){	Esc *e;		if(nesc >= nelem(esc)){		fprint(2, "too many escapes\n");		return;	}	e = &esc[nesc++];	e->r = r;	e->f = f;	e->mode = mode;} /* * Get the next logical character in the input stream. */intgetnext(void){	int i, r; next:	r = getrune();	if(r < 0)		return -1;	if(r == Uformatted){		br();		assert(!isoutput);		while((r = getrune()) >= 0 && r != Uunformatted){			if(r == Uformatted)				continue;			outrune(r);		}		goto next;	}	if(r == Uunformatted)		goto next;	if(r == backslash){		r = getrune();		if(r < 0)			return -1;		for(i=0; i<nesc; i++){			if(r == esc[i].r && (inputmode&esc[i].mode)==inputmode){				if(esc[i].f == e_warn)					warn("ignoring %C%C", backslash, r);				r = esc[i].f();				if(r <= 0)					goto next;				return r;			}		}		if(inputmode&(ArgMode|CopyMode)){			ungetrune(r);			r = backslash;		}	}	return r;} voidungetnext(Rune r){	/*	 * really we want to undo the getrunes that led us here,	 * since the call after ungetnext might be getrune!	 */	ungetrune(r);} int_readx(Rune *p, int n, int nmode, int line){	int c, omode;	Rune *e; 	while((c = getrune()) == ' ' || c == '\t')		;	ungetrune(c);	omode = inputmode;	inputmode = nmode;	e = p+n-1;	for(c=getnext(); p<e; c=getnext()){		if(c < 0)			break;		if(!line && (c == ' ' || c == '\t'))			break;		if(c == '\n'){			if(!line)				ungetnext(c);			break;		}		*p++ = c;	}	inputmode = omode;	*p = 0;	if(c < 0)		return -1;	return 0;} /* * Get the next argument from the current line. */Rune*copyarg(void){	static Rune buf[MaxLine];	int c;	Rune *r;		if(_readx(buf, sizeof buf, ArgMode, 0) < 0)		return nil;	r = runestrstr(buf, L("\\\""));	if(r){		*r = 0;		while((c = getrune()) >= 0 && c != '\n')			;		ungetrune('\n');	}	r = erunestrdup(buf);		return r;} /* * Read the current line in given mode.  Newline not kept. * Uses different buffer from copyarg! */Rune*readline(int m){	static Rune buf[MaxLine];	Rune *r; 	if(_readx(buf, sizeof buf, m, 1) < 0)		return nil;	r = erunestrdup(buf);	return r;} /* * Given the argument line (already read in copy+arg mode), * parse into arguments.  Note that \" has been left in place * during copy+arg mode parsing, so comments still need to be stripped. */intparseargs(Rune *p, Rune **argv){	int argc;	Rune *w; 	for(argc=0; argc<MAXARG; argc++){		while(*p == ' ' || *p == '\t')			p++;		if(*p == 0)			break;		argv[argc] = p;		if(*p == '"'){			/* quoted argument */			if(*(p+1) == '"'){				/* empty argument */				*p = 0;				p += 2;			}else{				/* parse quoted string */				w = p++;				for(; *p; p++){					if(*p == '"' && *(p+1) == '"')						*w++ = '"';					else if(*p == '"'){						p++;						break;					}else						*w++ = *p;				}				*w = 0;			}			}else{			/* unquoted argument - need to watch out for \" comment */			for(; *p; p++){				if(*p == ' ' || *p == '\t'){					*p++ = 0;					break;				}				if(*p == '\\' && *(p+1) == '"'){					*p = 0;					if(p != argv[argc])						argc++;					return argc;				}			}		}	}	return argc;} /* * Process a dot line.  The dot has been read. */voiddotline(int dot){	int argc, i;	Rune *a, *argv[1+MAXARG]; 	/*	 * Read request/macro name	 */	a = copyarg();	if(a == nil || a[0] == 0){		free(a);		getrune();	/* \n */		return;	}	argv[0] = a;	/*	 * Check for .if, .ie, and others with special parsing.	 */	for(i=0; i<nraw; i++){		if(runestrcmp(raw[i].name, a) == 0){			raw[i].f(raw[i].name);			free(a);			return;		}		} 	/*	 * Read rest of line in copy mode, invoke regular request.	 */	a = readline(ArgMode);	if(a == nil){		free(argv[0]);		return;	}	argc = 1+parseargs(a, argv+1);	for(i=0; i<nreq; i++){		if(runestrcmp(req[i].name, argv[0]) == 0){			if(req[i].argc != -1){				if(argc < 1+req[i].argc){					warn("not enough arguments for %C%S", dot, req[i].name);					free(argv[0]);					free(a);					return;				}				if(argc > 1+req[i].argc)					warn("too many arguments for %C%S", dot, req[i].name);			}			req[i].f(argc, argv);			free(argv[0]);			free(a);			return;		}	} 	/*	 * Invoke user-defined macros.	 */	runmacro(dot, argc, argv);	free(argv[0]);	free(a);} /* * newlines are magical in various ways. */int bol;voidnewline(void){	int n; 	if(bol)		sp(eval(L("1v")));	bol = 1;	if((n=getnr(L(".ce"))) > 0){		nr(L(".ce"), n-1);		br();	}	if(getnr(L(".fi")) == 0)		br();	outrune('\n');} voidstartoutput(void){	char *align;	double ps, vs, lm, rm, ti;	Rune buf[200]; 	if(isoutput)		return;	isoutput = 1; 	if(getnr(L(".paragraph")) == 0)		return; 	nr(L(".ns"), 0);	isoutput = 1;	ps = getnr(L(".s"));	if(ps <= 1)		ps = 10;	ps /= 72.0;	USED(ps); 	vs = getnr(L(".v"))*getnr(L(".ls")) * 1.0/UPI;	vs /= (10.0/72.0);	/* ps */	if(vs == 0)		vs = 1.2; 	lm = (getnr(L(".o"))+getnr(L(".i"))) * 1.0/UPI;	ti = getnr(L(".ti")) * 1.0/UPI;	nr(L(".ti"), 0); 	rm = 8.0 - getnr(L(".l"))*1.0/UPI - getnr(L(".o"))*1.0/UPI;	if(rm < 0)		rm = 0;	switch(getnr(L(".j"))){	default:	case 0:		align = "left";		break;	case 1:		align = "justify";		break;	case 3:		align = "center";		break;	case 5:		align = "right";		break;	}	if(getnr(L(".ce")))		align = "center";	if(!getnr(L(".margin")))		runesnprint(buf, nelem(buf), "<p style=\"line-height: %.1fem; text-indent: %.2fin; margin-top: 0; margin-bottom: 0; text-align: %s;\">\n",			vs, ti, align);	else		runesnprint(buf, nelem(buf), "<p style=\"line-height: %.1fem; margin-left: %.2fin; text-indent: %.2fin; margin-right: %.2fin; margin-top: 0; margin-bottom: 0; text-align: %s;\">\n",			vs, lm, ti, rm, align);	outhtml(buf);}voidbr(void){	if(!isoutput)		return;	isoutput = 0; 	nr(L(".dv"), 0);	dv(0);	hideihtml();

Lines 1–500 of 750.