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

📄 roff.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#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();	if(getnr(L(".paragraph")))		outhtml(L("</p>"));}voidr_margin(int argc, Rune **argv){	USED(argc);	nr(L(".margin"), eval(argv[1]));}int inrequest;voidruninput(void){	int c;		bol = 1;	for(;;){		c = getnext();		if(c < 0)			break;		if((c == dot || c == tick) && bol){			inrequest = 1;			dotline(c);			bol = 1;			inrequest = 0;		}else if(c == '\n'){			newline();			itrap();			linepos = 0;		}else{			outtrap();			startoutput();			showihtml();			if(c == '\t'){				/* XXX do better */				outrune(' ');				while(++linepos%4)					outrune(' ');			}else{				outrune(c);				linepos++;			}			bol = 0;		}	}}voidrun(void){	t1init();	t2init();	t3init();	t4init();	t5init();	t6init();	t7init();	t8init();	/* t9init(); t9.c */	t10init();	t11init();	/* t12init(); t12.c */	t13init();	t14init();	t15init();	t16init();	t17init();	t18init();	t19init();	t20init();	htmlinit();	hideihtml();		addreq(L("margin"), r_margin, 1);	nr(L(".margin"), 1);	nr(L(".paragraph"), 1);	runinput();	while(popinput())		;	dot = '.';	if(verbose)		fprint(2, "eof\n");	runmacro1(L("eof"));	closehtml();}voidout(Rune *s){	if(s == nil)		return;	for(; *s; s++)		outrune(*s);}void (*outcb)(Rune);voidinroman(Rune r){	int f;		f = getnr(L(".f"));	nr(L(".f"), 1);	runmacro1(L("font"));	outrune(r);	nr(L(".f"), f);	runmacro1(L("font"));}voidBrune(Rune r){	if(r == '&')		Bprint(&bout, "&amp;");	else if(r == '<')		Bprint(&bout, "&lt;");	else if(r == '>')		Bprint(&bout, "&gt;");	else if(r < Runeself || utf8)		Bprint(&bout, "%C", r);	else		Bprint(&bout, "%S", rune2html(r));}voidouthtml(Rune *s){	Rune r;		for(; *s; s++){		switch(r = *s){		case '<':			r = Ult;			break;		case '>':			r = Ugt;			break;		case '&':			r = Uamp;			break;		case ' ':			r = Uspace;			break;		}		outrune(r);	}}voidoutrune(Rune r){	switch(r){	case ' ':		if(getnr(L(".fi")) == 0)			r = Unbsp;		break;	case Uformatted:	case Uunformatted:		abort();	}	if(outcb){		if(r == ' ')			r = Uspace;		outcb(r);		return;	}	/* writing to bout */	switch(r){	case Uempty:		return;	case Upl:		inroman('+');		return;	case Ueq:		inroman('=');		return;	case Umi:		inroman(0x2212);		return;	case Utick:		r = '\'';		break;	case Ubtick:		r = '`';		break;	case Uminus:		r = '-';		break;	case '\'':		Bprint(&bout, "&rsquo;");		return;	case '`':		Bprint(&bout, "&lsquo;");		return;	case Uamp:		Bputrune(&bout, '&');		return;	case Ult:		Bputrune(&bout, '<');		return;	case Ugt:		Bputrune(&bout, '>');		return;	case Uspace:		Bputrune(&bout, ' ');		return;	case 0x2032:		/*		 * In Firefox, at least, the prime is not		 * a superscript by default.		 */		Bprint(&bout, "<sup>");		Brune(r);		Bprint(&bout, "</sup>");		return;	}	Brune(r);}voidr_nop(int argc, Rune **argv){	USED(argc);	USED(argv);}voidr_warn(int argc, Rune **argv){	USED(argc);	warn("ignoring %C%S", dot, argv[0]);}inte_warn(void){	/* dispatch loop prints a warning for us */	return 0;}inte_nop(void){	return 0;}

⌨️ 快捷键说明

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