minimal plan9port to cross-build Jehanne
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| *.o | ||||
							
								
								
									
										21
									
								
								LICENSE.Plan9Foundation.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								LICENSE.Plan9Foundation.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| Copyright © 2021 Plan 9 Foundation | ||||
| Portions Copyright © 2005 Russ Cox, MIT | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person obtaining | ||||
| a copy of this software and associated documentation files (the | ||||
| "Software"), to deal in the Software without restriction, including | ||||
| without limitation the rights to use, copy, modify, merge, publish, | ||||
| distribute, sublicense, and/or sell copies of the Software, and to | ||||
| permit persons to whom the Software is furnished to do so, subject to | ||||
| the following conditions: | ||||
|  | ||||
| The above copyright notice and this permission notice shall be | ||||
| included in all copies or substantial portions of the Software. | ||||
|  | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||||
| IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||||
| CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||||
| TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||||
| SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
							
								
								
									
										27
									
								
								README.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								README.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| A minimal plan9port fork designed just to cross-build Jehanne | ||||
| ============================================================= | ||||
|  | ||||
| The sole goal of these tools is to cross-build Jehanne in a way | ||||
| that can be more easily ported to Jehanne itself.  | ||||
|  | ||||
|  | ||||
| Tools available | ||||
| --------------- | ||||
| - lib | ||||
|   - lib9: stripped down lib9 from plan9port | ||||
|           uses $JEHANNE/hacking instead of $PLAN9 to not mess with | ||||
|           more useful plan9port installation | ||||
|   - bio: plan9port libbio | ||||
|   - yaccpar and yaccpars (parts of "yacc runtime") | ||||
|  | ||||
| - cmd | ||||
|   - yacc (9yacc in $JEHANNE/hacking/bin) | ||||
|   - rc | ||||
|  | ||||
| Commands will be installed in $JEHANNE/hacking/bin | ||||
| Libraries will be installed in $JEHANNE/hacking/lib | ||||
|  | ||||
| WARNING | ||||
| ------- | ||||
|  | ||||
| Do not use these tools for anything else. | ||||
							
								
								
									
										12
									
								
								build.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										12
									
								
								build.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| #!/bin/sh -e | ||||
|  | ||||
| TARGET=$JEHANNE/hacking/bin/ | ||||
| TRAMPOLINE=$JEHANNE/hacking/src/trampoline | ||||
|  | ||||
|  | ||||
| (cd $TRAMPOLINE/lib/lib9/ && ./lib9.sh.build) | ||||
| (cd $TRAMPOLINE/lib/bio/ && ./libbio.sh.build) | ||||
| (cd $TRAMPOLINE/cmd/ && \ | ||||
| cc yacc.c -DPLAN9PORT -I$TRAMPOLINE/include -L$JEHANNE/hacking/lib -O0 -lbio -l9 -o $TARGET/9yacc) | ||||
| (cp lib/yacc* $TARGET/../lib) | ||||
| (cd $TRAMPOLINE/cmd/rc/ && ./rc.sh.build) | ||||
							
								
								
									
										496
									
								
								cmd/rc/code.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										496
									
								
								cmd/rc/code.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,496 @@ | ||||
| #include "rc.h" | ||||
| #include "io.h" | ||||
| #include "exec.h" | ||||
| #include "fns.h" | ||||
| #include "getflags.h" | ||||
| #define	c0	t->child[0] | ||||
| #define	c1	t->child[1] | ||||
| #define	c2	t->child[2] | ||||
| int codep, ncode; | ||||
| #define	emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f = (x), codep++) | ||||
| #define	emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i = (x), codep++) | ||||
| #define	emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s = (x), codep++) | ||||
| void stuffdot(int); | ||||
| char *fnstr(tree*); | ||||
| void outcode(tree*, int); | ||||
| void codeswitch(tree*, int); | ||||
| int iscase(tree*); | ||||
| code *codecopy(code*); | ||||
| void codefree(code*); | ||||
|  | ||||
| int | ||||
| morecode(void) | ||||
| { | ||||
| 	ncode+=100; | ||||
| 	codebuf = (code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]); | ||||
| 	if(codebuf==0) | ||||
| 		panic("Can't realloc %d bytes in morecode!", | ||||
| 				ncode*sizeof codebuf[0]); | ||||
| 	memset(codebuf+ncode-100, 0, 100*sizeof codebuf[0]); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void | ||||
| stuffdot(int a) | ||||
| { | ||||
| 	if(a<0 || codep<=a) | ||||
| 		panic("Bad address %d in stuffdot", a); | ||||
| 	codebuf[a].i = codep; | ||||
| } | ||||
|  | ||||
| int | ||||
| compile(tree *t) | ||||
| { | ||||
| 	if(flag['D']) { | ||||
| 		struct io *s; | ||||
| 		s = openstr(); | ||||
| 		pfmt(s, "compile: %u\n", t); | ||||
| 		write(2, s->strp, strlen(s->strp)); | ||||
| 		closeio(s); | ||||
| 		if(eflagok) // made it out of rcmain - stop executing commands, just print them | ||||
| 			t = nil; | ||||
| 	} | ||||
|  | ||||
| 	ncode = 100; | ||||
| 	codebuf = (code *)emalloc(ncode*sizeof codebuf[0]); | ||||
| 	codep = 0; | ||||
| 	emiti(0);			/* reference count */ | ||||
| 	outcode(t, flag['e']?1:0); | ||||
| 	if(nerror){ | ||||
| 		efree((char *)codebuf); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	readhere(); | ||||
| 	emitf(Xreturn); | ||||
| 	emitf(0); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void | ||||
| cleanhere(char *f) | ||||
| { | ||||
| 	emitf(Xdelhere); | ||||
| 	emits(strdup(f)); | ||||
| } | ||||
|  | ||||
| char* | ||||
| fnstr(tree *t) | ||||
| { | ||||
| 	io *f = openstr(); | ||||
| 	char *v; | ||||
| 	extern char nl; | ||||
| 	char svnl = nl; | ||||
| 	nl=';'; | ||||
| 	pfmt(f, "%t", t); | ||||
| 	nl = svnl; | ||||
| 	v = f->strp; | ||||
| 	f->strp = 0; | ||||
| 	closeio(f); | ||||
| 	return v; | ||||
| } | ||||
|  | ||||
| void | ||||
| outcode(tree *t, int eflag) | ||||
| { | ||||
| 	int p, q; | ||||
| 	tree *tt; | ||||
| 	if(t==0) | ||||
| 		return; | ||||
| 	if(t->type!=NOT && t->type!=';') | ||||
| 		runq->iflast = 0; | ||||
| 	switch(t->type){ | ||||
| 	default: | ||||
| 		pfmt(err, "bad type %d in outcode\n", t->type); | ||||
| 		break; | ||||
| 	case '$': | ||||
| 		emitf(Xmark); | ||||
| 		outcode(c0, eflag); | ||||
| 		emitf(Xdol); | ||||
| 		break; | ||||
| 	case '"': | ||||
| 		emitf(Xmark); | ||||
| 		outcode(c0, eflag); | ||||
| 		emitf(Xqdol); | ||||
| 		break; | ||||
| 	case SUB: | ||||
| 		emitf(Xmark); | ||||
| 		outcode(c0, eflag); | ||||
| 		emitf(Xmark); | ||||
| 		outcode(c1, eflag); | ||||
| 		emitf(Xsub); | ||||
| 		break; | ||||
| 	case '&': | ||||
| 		emitf(Xasync); | ||||
| 		if(havefork){ | ||||
| 			p = emiti(0); | ||||
| 			outcode(c0, eflag); | ||||
| 			emitf(Xexit); | ||||
| 			stuffdot(p); | ||||
| 		} else | ||||
| 			emits(fnstr(c0)); | ||||
| 		break; | ||||
| 	case ';': | ||||
| 		outcode(c0, eflag); | ||||
| 		outcode(c1, eflag); | ||||
| 		break; | ||||
| 	case '^': | ||||
| 		emitf(Xmark); | ||||
| 		outcode(c1, eflag); | ||||
| 		emitf(Xmark); | ||||
| 		outcode(c0, eflag); | ||||
| 		emitf(Xconc); | ||||
| 		break; | ||||
| 	case '`': | ||||
| 		emitf(Xbackq); | ||||
| 		if(havefork){ | ||||
| 			p = emiti(0); | ||||
| 			outcode(c0, 0); | ||||
| 			emitf(Xexit); | ||||
| 			stuffdot(p); | ||||
| 		} else | ||||
| 			emits(fnstr(c0)); | ||||
| 		break; | ||||
| 	case ANDAND: | ||||
| 		outcode(c0, 0); | ||||
| 		emitf(Xtrue); | ||||
| 		p = emiti(0); | ||||
| 		outcode(c1, eflag); | ||||
| 		stuffdot(p); | ||||
| 		break; | ||||
| 	case ARGLIST: | ||||
| 		outcode(c1, eflag); | ||||
| 		outcode(c0, eflag); | ||||
| 		break; | ||||
| 	case BANG: | ||||
| 		outcode(c0, eflag); | ||||
| 		emitf(Xbang); | ||||
| 		break; | ||||
| 	case PCMD: | ||||
| 	case BRACE: | ||||
| 		outcode(c0, eflag); | ||||
| 		break; | ||||
| 	case COUNT: | ||||
| 		emitf(Xmark); | ||||
| 		outcode(c0, eflag); | ||||
| 		emitf(Xcount); | ||||
| 		break; | ||||
| 	case FN: | ||||
| 		emitf(Xmark); | ||||
| 		outcode(c0, eflag); | ||||
| 		if(c1){ | ||||
| 			emitf(Xfn); | ||||
| 			p = emiti(0); | ||||
| 			emits(fnstr(c1)); | ||||
| 			outcode(c1, eflag); | ||||
| 			emitf(Xunlocal);	/* get rid of $* */ | ||||
| 			emitf(Xreturn); | ||||
| 			stuffdot(p); | ||||
| 		} | ||||
| 		else | ||||
| 			emitf(Xdelfn); | ||||
| 		break; | ||||
| 	case IF: | ||||
| 		outcode(c0, 0); | ||||
| 		emitf(Xif); | ||||
| 		p = emiti(0); | ||||
| 		outcode(c1, eflag); | ||||
| 		emitf(Xwastrue); | ||||
| 		stuffdot(p); | ||||
| 		break; | ||||
| 	case NOT: | ||||
| 		if(!runq->iflast) | ||||
| 			yyerror("`if not' does not follow `if(...)'"); | ||||
| 		emitf(Xifnot); | ||||
| 		p = emiti(0); | ||||
| 		outcode(c0, eflag); | ||||
| 		stuffdot(p); | ||||
| 		break; | ||||
| 	case OROR: | ||||
| 		outcode(c0, 0); | ||||
| 		emitf(Xfalse); | ||||
| 		p = emiti(0); | ||||
| 		outcode(c1, eflag); | ||||
| 		stuffdot(p); | ||||
| 		break; | ||||
| 	case PAREN: | ||||
| 		outcode(c0, eflag); | ||||
| 		break; | ||||
| 	case SIMPLE: | ||||
| 		emitf(Xmark); | ||||
| 		outcode(c0, eflag); | ||||
| 		emitf(Xsimple); | ||||
| 		if(eflag) | ||||
| 			emitf(Xeflag); | ||||
| 		break; | ||||
| 	case SUBSHELL: | ||||
| 		emitf(Xsubshell); | ||||
| 		if(havefork){ | ||||
| 			p = emiti(0); | ||||
| 			outcode(c0, eflag); | ||||
| 			emitf(Xexit); | ||||
| 			stuffdot(p); | ||||
| 		} else | ||||
| 			emits(fnstr(c0)); | ||||
| 		if(eflag) | ||||
| 			emitf(Xeflag); | ||||
| 		break; | ||||
| 	case SWITCH: | ||||
| 		codeswitch(t, eflag); | ||||
| 		break; | ||||
| 	case TWIDDLE: | ||||
| 		emitf(Xmark); | ||||
| 		outcode(c1, eflag); | ||||
| 		emitf(Xmark); | ||||
| 		outcode(c0, eflag); | ||||
| 		emitf(Xmatch); | ||||
| 		if(eflag) | ||||
| 			emitf(Xeflag); | ||||
| 		break; | ||||
| 	case WHILE: | ||||
| 		q = codep; | ||||
| 		outcode(c0, 0); | ||||
| 		if(q==codep) | ||||
| 			emitf(Xsettrue);	/* empty condition == while(true) */ | ||||
| 		emitf(Xtrue); | ||||
| 		p = emiti(0); | ||||
| 		outcode(c1, eflag); | ||||
| 		emitf(Xjump); | ||||
| 		emiti(q); | ||||
| 		stuffdot(p); | ||||
| 		break; | ||||
| 	case WORDS: | ||||
| 		outcode(c1, eflag); | ||||
| 		outcode(c0, eflag); | ||||
| 		break; | ||||
| 	case FOR: | ||||
| 		emitf(Xmark); | ||||
| 		if(c1){ | ||||
| 			outcode(c1, eflag); | ||||
| 			emitf(Xglob); | ||||
| 		} | ||||
| 		else{ | ||||
| 			emitf(Xmark); | ||||
| 			emitf(Xword); | ||||
| 			emits(strdup("*")); | ||||
| 			emitf(Xdol); | ||||
| 		} | ||||
| 		emitf(Xmark);		/* dummy value for Xlocal */ | ||||
| 		emitf(Xmark); | ||||
| 		outcode(c0, eflag); | ||||
| 		emitf(Xlocal); | ||||
| 		p = emitf(Xfor); | ||||
| 		q = emiti(0); | ||||
| 		outcode(c2, eflag); | ||||
| 		emitf(Xjump); | ||||
| 		emiti(p); | ||||
| 		stuffdot(q); | ||||
| 		emitf(Xunlocal); | ||||
| 		break; | ||||
| 	case WORD: | ||||
| 		emitf(Xword); | ||||
| 		emits(strdup(t->str)); | ||||
| 		break; | ||||
| 	case DUP: | ||||
| 		if(t->rtype==DUPFD){ | ||||
| 			emitf(Xdup); | ||||
| 			emiti(t->fd0); | ||||
| 			emiti(t->fd1); | ||||
| 		} | ||||
| 		else{ | ||||
| 			emitf(Xclose); | ||||
| 			emiti(t->fd0); | ||||
| 		} | ||||
| 		outcode(c1, eflag); | ||||
| 		emitf(Xpopredir); | ||||
| 		break; | ||||
| 	case PIPEFD: | ||||
| 		emitf(Xpipefd); | ||||
| 		emiti(t->rtype); | ||||
| 		if(havefork){ | ||||
| 			p = emiti(0); | ||||
| 			outcode(c0, eflag); | ||||
| 			emitf(Xexit); | ||||
| 			stuffdot(p); | ||||
| 		} else { | ||||
| 			emits(fnstr(c0)); | ||||
| 		} | ||||
| 		break; | ||||
| 	case REDIR: | ||||
| 		emitf(Xmark); | ||||
| 		outcode(c0, eflag); | ||||
| 		emitf(Xglob); | ||||
| 		switch(t->rtype){ | ||||
| 		case APPEND: | ||||
| 			emitf(Xappend); | ||||
| 			break; | ||||
| 		case WRITE: | ||||
| 			emitf(Xwrite); | ||||
| 			break; | ||||
| 		case READ: | ||||
| 		case HERE: | ||||
| 			emitf(Xread); | ||||
| 			break; | ||||
| 		case RDWR: | ||||
| 			emitf(Xrdwr); | ||||
| 			break; | ||||
| 		} | ||||
| 		emiti(t->fd0); | ||||
| 		outcode(c1, eflag); | ||||
| 		emitf(Xpopredir); | ||||
| 		break; | ||||
| 	case '=': | ||||
| 		tt = t; | ||||
| 		for(;t && t->type=='=';t = c2); | ||||
| 		if(t){ | ||||
| 			for(t = tt;t->type=='=';t = c2){ | ||||
| 				emitf(Xmark); | ||||
| 				outcode(c1, eflag); | ||||
| 				emitf(Xmark); | ||||
| 				outcode(c0, eflag); | ||||
| 				emitf(Xlocal); | ||||
| 			} | ||||
| 			outcode(t, eflag); | ||||
| 			for(t = tt; t->type=='='; t = c2) | ||||
| 				emitf(Xunlocal); | ||||
| 		} | ||||
| 		else{ | ||||
| 			for(t = tt;t;t = c2){ | ||||
| 				emitf(Xmark); | ||||
| 				outcode(c1, eflag); | ||||
| 				emitf(Xmark); | ||||
| 				outcode(c0, eflag); | ||||
| 				emitf(Xassign); | ||||
| 			} | ||||
| 		} | ||||
| 		t = tt;	/* so tests below will work */ | ||||
| 		break; | ||||
| 	case PIPE: | ||||
| 		emitf(Xpipe); | ||||
| 		emiti(t->fd0); | ||||
| 		emiti(t->fd1); | ||||
| 		if(havefork){ | ||||
| 			p = emiti(0); | ||||
| 			q = emiti(0); | ||||
| 			outcode(c0, eflag); | ||||
| 			emitf(Xexit); | ||||
| 			stuffdot(p); | ||||
| 		} else { | ||||
| 			emits(fnstr(c0)); | ||||
| 			q = emiti(0); | ||||
| 		} | ||||
| 		outcode(c1, eflag); | ||||
| 		emitf(Xreturn); | ||||
| 		stuffdot(q); | ||||
| 		emitf(Xpipewait); | ||||
| 		break; | ||||
| 	} | ||||
| 	if(t->type!=NOT && t->type!=';') | ||||
| 		runq->iflast = t->type==IF; | ||||
| 	else if(c0) runq->iflast = c0->type==IF; | ||||
| } | ||||
| /* | ||||
|  * switch code looks like this: | ||||
|  *	Xmark | ||||
|  *	(get switch value) | ||||
|  *	Xjump	1f | ||||
|  * out:	Xjump	leave | ||||
|  * 1:	Xmark | ||||
|  *	(get case values) | ||||
|  *	Xcase	1f | ||||
|  *	(commands) | ||||
|  *	Xjump	out | ||||
|  * 1:	Xmark | ||||
|  *	(get case values) | ||||
|  *	Xcase	1f | ||||
|  *	(commands) | ||||
|  *	Xjump	out | ||||
|  * 1: | ||||
|  * leave: | ||||
|  *	Xpopm | ||||
|  */ | ||||
|  | ||||
| void | ||||
| codeswitch(tree *t, int eflag) | ||||
| { | ||||
| 	int leave;		/* patch jump address to leave switch */ | ||||
| 	int out;		/* jump here to leave switch */ | ||||
| 	int nextcase;	/* patch jump address to next case */ | ||||
| 	tree *tt; | ||||
| 	if(c1->child[0]==nil | ||||
| 	|| c1->child[0]->type!=';' | ||||
| 	|| !iscase(c1->child[0]->child[0])){ | ||||
| 		yyerror("case missing in switch"); | ||||
| 		return; | ||||
| 	} | ||||
| 	emitf(Xmark); | ||||
| 	outcode(c0, eflag); | ||||
| 	emitf(Xjump); | ||||
| 	nextcase = emiti(0); | ||||
| 	out = emitf(Xjump); | ||||
| 	leave = emiti(0); | ||||
| 	stuffdot(nextcase); | ||||
| 	t = c1->child[0]; | ||||
| 	while(t->type==';'){ | ||||
| 		tt = c1; | ||||
| 		emitf(Xmark); | ||||
| 		for(t = c0->child[0];t->type==ARGLIST;t = c0) outcode(c1, eflag); | ||||
| 		emitf(Xcase); | ||||
| 		nextcase = emiti(0); | ||||
| 		t = tt; | ||||
| 		for(;;){ | ||||
| 			if(t->type==';'){ | ||||
| 				if(iscase(c0)) break; | ||||
| 				outcode(c0, eflag); | ||||
| 				t = c1; | ||||
| 			} | ||||
| 			else{ | ||||
| 				if(!iscase(t)) outcode(t, eflag); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		emitf(Xjump); | ||||
| 		emiti(out); | ||||
| 		stuffdot(nextcase); | ||||
| 	} | ||||
| 	stuffdot(leave); | ||||
| 	emitf(Xpopm); | ||||
| } | ||||
|  | ||||
| int | ||||
| iscase(tree *t) | ||||
| { | ||||
| 	if(t->type!=SIMPLE) | ||||
| 		return 0; | ||||
| 	do t = c0; while(t->type==ARGLIST); | ||||
| 	return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0; | ||||
| } | ||||
|  | ||||
| code* | ||||
| codecopy(code *cp) | ||||
| { | ||||
| 	cp[0].i++; | ||||
| 	return cp; | ||||
| } | ||||
|  | ||||
| void | ||||
| codefree(code *cp) | ||||
| { | ||||
| 	code *p; | ||||
| 	if(--cp[0].i!=0) | ||||
| 		return; | ||||
| 	for(p = cp+1;p->f;p++){ | ||||
| 		if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite | ||||
| 		|| p->f==Xrdwr | ||||
| 		|| p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse | ||||
| 		|| p->f==Xfor || p->f==Xjump | ||||
| 		|| p->f==Xsubshell || p->f==Xtrue) p++; | ||||
| 		else if(p->f==Xdup || p->f==Xpipefd) p+=2; | ||||
| 		else if(p->f==Xpipe) p+=4; | ||||
| 		else if(p->f==Xword || p->f==Xdelhere) efree((++p)->s); | ||||
| 		else if(p->f==Xfn){ | ||||
| 			efree(p[2].s); | ||||
| 			p+=2; | ||||
| 		} | ||||
| 	} | ||||
| 	efree((char *)cp); | ||||
| } | ||||
							
								
								
									
										1001
									
								
								cmd/rc/exec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1001
									
								
								cmd/rc/exec.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										76
									
								
								cmd/rc/exec.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								cmd/rc/exec.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| /* | ||||
|  * Definitions used in the interpreter | ||||
|  */ | ||||
| extern void Xappend(void), Xasync(void), Xbackq(void), Xbang(void), Xclose(void); | ||||
| extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqdol(void), Xdup(void); | ||||
| extern void Xexit(void), Xfalse(void), Xfn(void), Xfor(void), Xglob(void); | ||||
| extern void Xjump(void), Xmark(void), Xmatch(void), Xpipe(void), Xread(void); | ||||
| extern void Xrdwr(void); | ||||
| extern void Xrdfn(void), Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void); | ||||
| extern void Xtrue(void), Xword(void), Xwrite(void), Xpipefd(void), Xcase(void); | ||||
| extern void Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(void); | ||||
| extern void Xrdcmds(void), Xwastrue(void), Xif(void), Xifnot(void), Xpipewait(void); | ||||
| extern void Xdelhere(void), Xpopredir(void), Xsub(void), Xeflag(void), Xsettrue(void); | ||||
| extern void Xerror(char*); | ||||
| extern void Xerror1(char*); | ||||
| /* | ||||
|  * word lists are in correct order, | ||||
|  * i.e. word0->word1->word2->word3->0 | ||||
|  */ | ||||
| struct word{ | ||||
| 	char *word; | ||||
| 	word *next; | ||||
| }; | ||||
| struct list{ | ||||
| 	word *words; | ||||
| 	list *next; | ||||
| }; | ||||
| word *newword(char *, word *), *copywords(word *, word *); | ||||
| struct redir{ | ||||
| 	char type;			/* what to do */ | ||||
| 	short from, to;			/* what to do it to */ | ||||
| 	struct redir *next;		/* what else to do (reverse order) */ | ||||
| }; | ||||
| #define	NSTATUS	ERRMAX			/* length of status (from plan 9) */ | ||||
| /* | ||||
|  * redir types | ||||
|  */ | ||||
| #define	ROPEN	1			/* dup2(from, to); close(from); */ | ||||
| #define	RDUP	2			/* dup2(from, to); */ | ||||
| #define	RCLOSE	3			/* close(from); */ | ||||
| struct thread{ | ||||
| 	union code *code;		/* code for this thread */ | ||||
| 	int pc;				/* code[pc] is the next instruction */ | ||||
| 	struct list *argv;		/* argument stack */ | ||||
| 	struct redir *redir;		/* redirection stack */ | ||||
| 	struct redir *startredir;	/* redir inheritance point */ | ||||
| 	struct var *local;		/* list of local variables */ | ||||
| 	char *cmdfile;			/* file name in Xrdcmd */ | ||||
| 	struct io *cmdfd;		/* file descriptor for Xrdcmd */ | ||||
| 	int iflast;			/* static `if not' checking */ | ||||
| 	int eof;			/* is cmdfd at eof? */ | ||||
| 	int iflag;			/* interactive? */ | ||||
| 	int lineno;			/* linenumber */ | ||||
| 	int pid;			/* process for Xpipewait to wait for */ | ||||
| 	char status[NSTATUS];		/* status for Xpipewait */ | ||||
| 	tree *treenodes;		/* tree nodes created by this process */ | ||||
| 	thread *ret;		/* who continues when this finishes */ | ||||
| }; | ||||
| thread *runq; | ||||
| code *codecopy(code*); | ||||
| code *codebuf;				/* compiler output */ | ||||
| int ntrap;				/* number of outstanding traps */ | ||||
| int trap[NSIG];				/* number of outstanding traps per type */ | ||||
| struct builtin{ | ||||
| 	char *name; | ||||
| 	void (*fnc)(void); | ||||
| }; | ||||
| extern struct builtin Builtin[]; | ||||
| int eflagok;			/* kludge flag so that -e doesn't exit in startup */ | ||||
| extern int havefork; | ||||
|  | ||||
| void execcd(void), execwhatis(void), execeval(void), execexec(void); | ||||
| int execforkexec(void); | ||||
| void execexit(void), execshift(void); | ||||
| void execwait(void), execumask(void), execdot(void), execflag(void); | ||||
| void execfunc(var*), execcmds(io *); | ||||
							
								
								
									
										162
									
								
								cmd/rc/fmtquote.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								cmd/rc/fmtquote.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,162 @@ | ||||
| /* | ||||
|  * The authors of this software are Rob Pike and Ken Thompson. | ||||
|  *              Copyright (c) 2002 by Lucent Technologies. | ||||
|  * Permission to use, copy, modify, and distribute this software for any | ||||
|  * purpose without fee is hereby granted, provided that this entire notice | ||||
|  * is included in all copies of any software which is or includes a copy | ||||
|  * or modification of this software and in all copies of the supporting | ||||
|  * documentation for such software. | ||||
|  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED | ||||
|  * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY | ||||
|  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY | ||||
|  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. | ||||
|  */ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include "fmt.h" | ||||
| #include "fmtdef.h" | ||||
|  | ||||
| extern int (*doquote)(int); | ||||
|  | ||||
| /* | ||||
|  * How many bytes of output UTF will be produced by quoting (if necessary) this string? | ||||
|  * How many runes? How much of the input will be consumed? | ||||
|  * The parameter q is filled in by _quotesetup. | ||||
|  * The string may be UTF or Runes (s or r). | ||||
|  * Return count does not include NUL. | ||||
|  * Terminate the scan at the first of: | ||||
|  *	NUL in input | ||||
|  *	count exceeded in input | ||||
|  *	count exceeded on output | ||||
|  * *ninp is set to number of input bytes accepted. | ||||
|  * nin may be <0 initially, to avoid checking input by count. | ||||
|  */ | ||||
| void | ||||
| __quotesetup(char *s, int nin, int nout, Quoteinfo *q, int sharp) | ||||
| { | ||||
| 	int c; | ||||
|  | ||||
| 	q->quoted = 0; | ||||
| 	q->nbytesout = 0; | ||||
| 	q->nrunesout = 0; | ||||
| 	q->nbytesin = 0; | ||||
| 	q->nrunesin = 0; | ||||
| 	if(sharp || nin==0 || *s=='\0'){ | ||||
| 		if(nout < 2) | ||||
| 			return; | ||||
| 		q->quoted = 1; | ||||
| 		q->nbytesout = 2; | ||||
| 		q->nrunesout = 2; | ||||
| 	} | ||||
| 	for(; nin!=0; nin-=1){ | ||||
| 		c = *s; | ||||
|  | ||||
| 		if(c == '\0') | ||||
| 			break; | ||||
| 		if(q->nrunesout+1 > nout) | ||||
| 			break; | ||||
|  | ||||
| 		if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){ | ||||
| 			if(!q->quoted){ | ||||
| 				if(1+q->nrunesout+1+1 > nout)	/* no room for quotes */ | ||||
| 					break; | ||||
| 				q->nrunesout += 2;	/* include quotes */ | ||||
| 				q->nbytesout += 2;	/* include quotes */ | ||||
| 				q->quoted = 1; | ||||
| 			} | ||||
| 			if(c == '\'')	{ | ||||
| 				q->nbytesout++; | ||||
| 				q->nrunesout++;	/* quotes reproduce as two characters */ | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/* advance input */ | ||||
| 		s++; | ||||
| 		q->nbytesin++; | ||||
| 		q->nrunesin++; | ||||
|  | ||||
| 		/* advance output */ | ||||
| 		q->nbytesout++; | ||||
| 		q->nrunesout++; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int | ||||
| qstrfmt(char *sin, Quoteinfo *q, Fmt *f) | ||||
| { | ||||
| 	int r; | ||||
| 	char *t, *s, *m, *me; | ||||
| 	ulong fl; | ||||
| 	int nc, w; | ||||
|  | ||||
| 	m = sin; | ||||
| 	me = m + q->nbytesin; | ||||
|  | ||||
| 	w = f->width; | ||||
| 	fl = f->flags; | ||||
| 	if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0) | ||||
| 		return -1; | ||||
| 	t = f->to; | ||||
| 	s = f->stop; | ||||
| 	FMTCHAR(f, t, s, '\''); | ||||
| 	for(nc = q->nrunesin; nc > 0; nc--){ | ||||
| 		r = *(uchar*)m++; | ||||
| 		FMTCHAR(f, t, s, r); | ||||
| 		if(r == '\'') | ||||
| 			FMTCHAR(f, t, s, r); | ||||
| 	} | ||||
|  | ||||
| 	FMTCHAR(f, t, s, '\''); | ||||
| 	f->nfmt += t - (char *)f->to; | ||||
| 	f->to = t; | ||||
| 	if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0) | ||||
| 		return -1; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| __quotestrfmt(int runesin, Fmt *f) | ||||
| { | ||||
| 	int outlen; | ||||
| 	char *s; | ||||
| 	Quoteinfo q; | ||||
|  | ||||
| 	f->flags &= ~FmtPrec;	/* ignored for %q %Q, so disable for %s %S in easy case */ | ||||
| 	s = va_arg(f->args, char *); | ||||
| 	if(!s) | ||||
| 		return __fmtcpy(f, "<nil>", 5, 5); | ||||
|  | ||||
| 	if(f->flush) | ||||
| 		outlen = 0x7FFFFFFF;	/* if we can flush, no output limit */ | ||||
| 	else | ||||
| 		outlen = (char*)f->stop - (char*)f->to; | ||||
|  | ||||
| 	__quotesetup(s, -1, outlen, &q, f->flags&FmtSharp); | ||||
|  | ||||
| 	if(!q.quoted) | ||||
| 		return __fmtcpy(f, s, q.nrunesin, q.nbytesin); | ||||
| 	return qstrfmt(s, &q, f); | ||||
| } | ||||
|  | ||||
| int | ||||
| quotestrfmt(Fmt *f) | ||||
| { | ||||
| 	return __quotestrfmt(0, f); | ||||
| } | ||||
|  | ||||
| void | ||||
| quotefmtinstall(void) | ||||
| { | ||||
| 	fmtinstall('q', quotestrfmt); | ||||
| } | ||||
|  | ||||
| int | ||||
| __needsquotes(char *s, int *quotelenp) | ||||
| { | ||||
| 	Quoteinfo q; | ||||
|  | ||||
| 	__quotesetup(s, -1, 0x7FFFFFFF, &q, 0); | ||||
| 	*quotelenp = q.nbytesout; | ||||
|  | ||||
| 	return q.quoted; | ||||
| } | ||||
							
								
								
									
										68
									
								
								cmd/rc/fns.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								cmd/rc/fns.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| void	Abort(void); | ||||
| void	Closedir(int); | ||||
| int	Creat(char*); | ||||
| int	Dup(int, int); | ||||
| int	Dup1(int); | ||||
| int	Eintr(void); | ||||
| int	Executable(char*); | ||||
| void	Execute(word*,  word*); | ||||
| void	Exit(char*); | ||||
| int	ForkExecute(char*, char**, int, int, int); | ||||
| int	Globsize(char*); | ||||
| int	Isatty(int); | ||||
| void	Memcpy(char*, char*, long); | ||||
| void	Noerror(void); | ||||
| int	Opendir(char*); | ||||
| long	Read(int, char*, long); | ||||
| int	Readdir(int, char*, int); | ||||
| long	Seek(int, long, long); | ||||
| void	Trapinit(void); | ||||
| void	Unlink(char*); | ||||
| void	Updenv(void); | ||||
| void	Vinit(void); | ||||
| int	Waitfor(int, int); | ||||
| long	Write(int, char*, long); | ||||
| void	addwaitpid(int); | ||||
| int	advance(void); | ||||
| int	back(int); | ||||
| void	cleanhere(char*); | ||||
| void	codefree(code*); | ||||
| int	compile(tree*); | ||||
| char *	list2str(word*); | ||||
| int	count(word*); | ||||
| void	deglob(char*); | ||||
| void	delwaitpid(int); | ||||
| void	dotrap(void); | ||||
| void	freenodes(void); | ||||
| void	freewords(word*); | ||||
| void	globlist(void); | ||||
| int	havewaitpid(int); | ||||
| int	idchr(int); | ||||
| void	inttoascii(char*, long); | ||||
| void	kinit(void); | ||||
| int	mapfd(int); | ||||
| int	match(char*, char*, int); | ||||
| int	matchfn(char*, char*); | ||||
| char**	mkargv(word*); | ||||
| void	clearwaitpids(void); | ||||
| void	panic(char*, int); | ||||
| void	pathinit(void); | ||||
| void	poplist(void); | ||||
| void	popword(void); | ||||
| void	pprompt(void); | ||||
| void	pushlist(void); | ||||
| void	pushredir(int, int, int); | ||||
| void	pushword(char*); | ||||
| void	readhere(void); | ||||
| word*	searchpath(char*); | ||||
| void	setstatus(char*); | ||||
| void	setvar(char*, word*); | ||||
| void	skipnl(void); | ||||
| void	start(code*, int, var*); | ||||
| int	truestatus(void); | ||||
| void	usage(char*); | ||||
| int	wordchr(int); | ||||
| void	yyerror(char*); | ||||
| int	yylex(void); | ||||
| int	yyparse(void); | ||||
| int	parse(void); | ||||
							
								
								
									
										244
									
								
								cmd/rc/getflags.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								cmd/rc/getflags.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,244 @@ | ||||
| /*% cyntax -DTEST % && cc -DTEST -go # % | ||||
|  */ | ||||
| #include "rc.h" | ||||
| #include "getflags.h" | ||||
| #include "fns.h" | ||||
| char *flagset[] = {"<flag>"}; | ||||
| char **flag[NFLAG]; | ||||
| char cmdline[NCMDLINE+1]; | ||||
| char *cmdname; | ||||
| static char *flagarg=""; | ||||
| static void reverse(char**, char**); | ||||
| static int scanflag(int, char*); | ||||
| static void errn(char*, int); | ||||
| static void errs(char*); | ||||
| static void errc(int); | ||||
| static int reason; | ||||
| #define	RESET	1 | ||||
| #define	FEWARGS	2 | ||||
| #define	FLAGSYN	3 | ||||
| #define	BADFLAG	4 | ||||
| static int badflag; | ||||
|  | ||||
| int | ||||
| getflags(int argc, char *argv[], char *flags, int stop) | ||||
| { | ||||
| 	char *s, *t; | ||||
| 	int i, j, c, count; | ||||
| 	flagarg = flags; | ||||
| 	if(cmdname==0) | ||||
| 		cmdname = argv[0]; | ||||
| 	s = cmdline; | ||||
| 	for(i = 0;i!=argc;i++){ | ||||
| 		for(t = argv[i];*t;t++) | ||||
| 			if(s!=&cmdline[NCMDLINE]) | ||||
| 				*s++=*t; | ||||
| 		if(i!=argc-1 && s!=&cmdline[NCMDLINE]) | ||||
| 			*s++=' '; | ||||
| 	} | ||||
| 	*s='\0'; | ||||
| 	i = 1; | ||||
| 	while(i!=argc){ | ||||
| 		if(argv[i][0]!='-' || argv[i][1]=='\0'){ | ||||
| 			if(stop) | ||||
| 				return argc; | ||||
| 			i++; | ||||
| 			continue; | ||||
| 		} | ||||
| 		s = argv[i]+1; | ||||
| 		while(*s){ | ||||
| 			c=*s++; | ||||
| 			count = scanflag(c, flags); | ||||
| 			if(count==-1) | ||||
| 				return -1; | ||||
| 			if(flag[c]){ reason = RESET; badflag = c; return -1; } | ||||
| 			if(count==0){ | ||||
| 				flag[c] = flagset; | ||||
| 				if(*s=='\0'){ | ||||
| 					for(j = i+1;j<=argc;j++) | ||||
| 						argv[j-1] = argv[j]; | ||||
| 					--argc; | ||||
| 				} | ||||
| 			} | ||||
| 			else{ | ||||
| 				if(*s=='\0'){ | ||||
| 					for(j = i+1;j<=argc;j++) | ||||
| 						argv[j-1] = argv[j]; | ||||
| 					--argc; | ||||
| 					s = argv[i]; | ||||
| 				} | ||||
| 				if(argc-i<count){ | ||||
| 					reason = FEWARGS; | ||||
| 					badflag = c; | ||||
| 					return -1; | ||||
| 				} | ||||
| 				reverse(argv+i, argv+argc); | ||||
| 				reverse(argv+i, argv+argc-count); | ||||
| 				reverse(argv+argc-count+1, argv+argc); | ||||
| 				argc-=count; | ||||
| 				flag[c] = argv+argc+1; | ||||
| 				flag[c][0] = s; | ||||
| 				s=""; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return argc; | ||||
| } | ||||
|  | ||||
| static void | ||||
| reverse(char **p, char **q) | ||||
| { | ||||
| 	char *t; | ||||
| 	for(;p<q;p++,--q){ t=*p; *p=*q; *q = t; } | ||||
| } | ||||
|  | ||||
| static int | ||||
| scanflag(int c, char *f) | ||||
| { | ||||
| 	int fc, count; | ||||
| 	if(0<=c && c<NFLAG) | ||||
| 		while(*f){ | ||||
| 			if(*f==' '){ | ||||
| 				f++; | ||||
| 				continue; | ||||
| 			} | ||||
| 			fc=*f++; | ||||
| 			if(*f==':'){ | ||||
| 				f++; | ||||
| 				if(*f<'0' || '9'<*f){ reason = FLAGSYN; return -1; } | ||||
| 				count = 0; | ||||
| 				while('0'<=*f && *f<='9') count = count*10+*f++-'0'; | ||||
| 			} | ||||
| 			else | ||||
| 				count = 0; | ||||
| 			if(*f=='['){ | ||||
| 				do{ | ||||
| 					f++; | ||||
| 					if(*f=='\0'){ reason = FLAGSYN; return -1; } | ||||
| 				}while(*f!=']'); | ||||
| 				f++; | ||||
| 			} | ||||
| 			if(c==fc) | ||||
| 				return count; | ||||
| 		} | ||||
| 	reason = BADFLAG; | ||||
| 	badflag = c; | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| void | ||||
| usage(char *tail) | ||||
| { | ||||
| 	char *s, *t, c; | ||||
| 	int count, nflag = 0; | ||||
| 	switch(reason){ | ||||
| 	case RESET: | ||||
| 		errs("Flag -"); | ||||
| 		errc(badflag); | ||||
| 		errs(": set twice\n"); | ||||
| 		break; | ||||
| 	case FEWARGS: | ||||
| 		errs("Flag -"); | ||||
| 		errc(badflag); | ||||
| 		errs(": too few arguments\n"); | ||||
| 		break; | ||||
| 	case FLAGSYN: | ||||
| 		errs("Bad argument to getflags!\n"); | ||||
| 		break; | ||||
| 	case BADFLAG: | ||||
| 		errs("Illegal flag -"); | ||||
| 		errc(badflag); | ||||
| 		errc('\n'); | ||||
| 		break; | ||||
| 	} | ||||
| 	errs("Usage: "); | ||||
| 	errs(cmdname); | ||||
| 	for(s = flagarg;*s;){ | ||||
| 		c=*s; | ||||
| 		if(*s++==' ') | ||||
| 			continue; | ||||
| 		if(*s==':'){ | ||||
| 			s++; | ||||
| 			count = 0; | ||||
| 			while('0'<=*s && *s<='9') count = count*10+*s++-'0'; | ||||
| 		} | ||||
| 		else count = 0; | ||||
| 		if(count==0){ | ||||
| 			if(nflag==0) | ||||
| 				errs(" [-"); | ||||
| 			nflag++; | ||||
| 			errc(c); | ||||
| 		} | ||||
| 		if(*s=='['){ | ||||
| 			s++; | ||||
| 			while(*s!=']' && *s!='\0') s++; | ||||
| 			if(*s==']') | ||||
| 				s++; | ||||
| 		} | ||||
| 	} | ||||
| 	if(nflag) | ||||
| 		errs("]"); | ||||
| 	for(s = flagarg;*s;){ | ||||
| 		c=*s; | ||||
| 		if(*s++==' ') | ||||
| 			continue; | ||||
| 		if(*s==':'){ | ||||
| 			s++; | ||||
| 			count = 0; | ||||
| 			while('0'<=*s && *s<='9') count = count*10+*s++-'0'; | ||||
| 		} | ||||
| 		else count = 0; | ||||
| 		if(count!=0){ | ||||
| 			errs(" [-"); | ||||
| 			errc(c); | ||||
| 			if(*s=='['){ | ||||
| 				s++; | ||||
| 				t = s; | ||||
| 				while(*s!=']' && *s!='\0') s++; | ||||
| 				errs(" "); | ||||
| 				errn(t, s-t); | ||||
| 				if(*s==']') | ||||
| 					s++; | ||||
| 			} | ||||
| 			else | ||||
| 				while(count--) errs(" arg"); | ||||
| 			errs("]"); | ||||
| 		} | ||||
| 		else if(*s=='['){ | ||||
| 			s++; | ||||
| 			while(*s!=']' && *s!='\0') s++; | ||||
| 			if(*s==']') | ||||
| 				s++; | ||||
| 		} | ||||
| 	} | ||||
| 	if(tail){ | ||||
| 		errs(" "); | ||||
| 		errs(tail); | ||||
| 	} | ||||
| 	errs("\n"); | ||||
| 	Exit("bad flags"); | ||||
| } | ||||
|  | ||||
| static void | ||||
| errn(char *s, int count) | ||||
| { | ||||
| 	while(count){ errc(*s++); --count; } | ||||
| } | ||||
|  | ||||
| static void | ||||
| errs(char *s) | ||||
| { | ||||
| 	while(*s) errc(*s++); | ||||
| } | ||||
| #define	NBUF	80 | ||||
| static char buf[NBUF], *bufp = buf; | ||||
|  | ||||
| static void | ||||
| errc(int c) | ||||
| { | ||||
| 	*bufp++=c; | ||||
| 	if(bufp==&buf[NBUF] || c=='\n'){ | ||||
| 		Write(2, buf, bufp-buf); | ||||
| 		bufp = buf; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										7
									
								
								cmd/rc/getflags.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								cmd/rc/getflags.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| #define	NFLAG	128 | ||||
| #define	NCMDLINE	512 | ||||
| extern char **flag[NFLAG]; | ||||
| extern char cmdline[NCMDLINE+1]; | ||||
| extern char *cmdname; | ||||
| extern char *flagset[]; | ||||
| int getflags(int, char*[], char*, int); | ||||
							
								
								
									
										267
									
								
								cmd/rc/glob.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										267
									
								
								cmd/rc/glob.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,267 @@ | ||||
| #include "rc.h" | ||||
| #include "exec.h" | ||||
| #include "fns.h" | ||||
| char *globname; | ||||
| struct word *globv; | ||||
| /* | ||||
|  * delete all the GLOB marks from s, in place | ||||
|  */ | ||||
|  | ||||
| void | ||||
| deglob(char *s) | ||||
| { | ||||
| 	char *t = s; | ||||
| 	do{ | ||||
| 		if(*t==GLOB) | ||||
| 			t++; | ||||
| 		*s++=*t; | ||||
| 	}while(*t++); | ||||
| } | ||||
|  | ||||
| int | ||||
| globcmp(const void *s, const void *t) | ||||
| { | ||||
| 	return strcmp(*(char**)s, *(char**)t); | ||||
| } | ||||
|  | ||||
| void | ||||
| globsort(word *left, word *right) | ||||
| { | ||||
| 	char **list; | ||||
| 	word *a; | ||||
| 	int n = 0; | ||||
| 	for(a = left;a!=right;a = a->next) n++; | ||||
| 	list = (char **)emalloc(n*sizeof(char *)); | ||||
| 	for(a = left,n = 0;a!=right;a = a->next,n++) list[n] = a->word; | ||||
| 	qsort((void *)list, n, sizeof(void *), globcmp); | ||||
| 	for(a = left,n = 0;a!=right;a = a->next,n++) a->word = list[n]; | ||||
| 	efree((char *)list); | ||||
| } | ||||
| /* | ||||
|  * Push names prefixed by globname and suffixed by a match of p onto the astack. | ||||
|  * namep points to the end of the prefix in globname. | ||||
|  */ | ||||
|  | ||||
| void | ||||
| globdir(char *p, char *namep) | ||||
| { | ||||
| 	char *t, *newp; | ||||
| 	int f; | ||||
| 	/* scan the pattern looking for a component with a metacharacter in it */ | ||||
| 	if(*p=='\0'){ | ||||
| 		globv = newword(globname, globv); | ||||
| 		return; | ||||
| 	} | ||||
| 	t = namep; | ||||
| 	newp = p; | ||||
| 	while(*newp){ | ||||
| 		if(*newp==GLOB) | ||||
| 			break; | ||||
| 		*t=*newp++; | ||||
| 		if(*t++=='/'){ | ||||
| 			namep = t; | ||||
| 			p = newp; | ||||
| 		} | ||||
| 	} | ||||
| 	/* If we ran out of pattern, append the name if accessible */ | ||||
| 	if(*newp=='\0'){ | ||||
| 		*t='\0'; | ||||
| 		if(access(globname, 0)==0) | ||||
| 			globv = newword(globname, globv); | ||||
| 		return; | ||||
| 	} | ||||
| 	/* read the directory and recur for any entry that matches */ | ||||
| 	*namep='\0'; | ||||
| 	if((f = Opendir(globname[0]?globname:"."))<0) return; | ||||
| 	while(*newp!='/' && *newp!='\0') newp++; | ||||
| 	while(Readdir(f, namep, *newp=='/')){ | ||||
| 		if(matchfn(namep, p)){ | ||||
| 			for(t = namep;*t;t++); | ||||
| 			globdir(newp, t); | ||||
| 		} | ||||
| 	} | ||||
| 	Closedir(f); | ||||
| } | ||||
| /* | ||||
|  * Push all file names matched by p on the current thread's stack. | ||||
|  * If there are no matches, the list consists of p. | ||||
|  */ | ||||
|  | ||||
| void | ||||
| glob(char *p) | ||||
| { | ||||
| 	word *svglobv = globv; | ||||
| 	int globlen = Globsize(p); | ||||
| 	if(!globlen){ | ||||
| 		deglob(p); | ||||
| 		globv = newword(p, globv); | ||||
| 		return; | ||||
| 	} | ||||
| 	globname = emalloc(globlen); | ||||
| 	globname[0]='\0'; | ||||
| 	globdir(p, globname); | ||||
| 	efree(globname); | ||||
| 	if(svglobv==globv){ | ||||
| 		deglob(p); | ||||
| 		globv = newword(p, globv); | ||||
| 	} | ||||
| 	else | ||||
| 		globsort(globv, svglobv); | ||||
| } | ||||
| /* | ||||
|  * Do p and q point at equal utf codes | ||||
|  */ | ||||
|  | ||||
| int | ||||
| equtf(char *p, char *q) | ||||
| { | ||||
| 	if(*p!=*q) | ||||
| 		return 0; | ||||
| 	if(twobyte(*p)) return p[1]==q[1]; | ||||
| 	if(threebyte(*p)){ | ||||
| 		if(p[1]!=q[1]) | ||||
| 			return 0; | ||||
| 		if(p[1]=='\0') | ||||
| 			return 1;	/* broken code at end of string! */ | ||||
| 		return p[2]==q[2]; | ||||
| 	} | ||||
| 	if(fourbyte(*p)){ | ||||
| 		if(p[1]!=q[1]) | ||||
| 			return 0; | ||||
| 		if(p[1]=='\0') | ||||
| 			return 1; | ||||
| 		if(p[2]!=q[2]) | ||||
| 			return 0; | ||||
| 		if(p[2]=='\0') | ||||
| 			return 1; | ||||
| 		return p[3]==q[3]; | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
| /* | ||||
|  * Return a pointer to the next utf code in the string, | ||||
|  * not jumping past nuls in broken utf codes! | ||||
|  */ | ||||
|  | ||||
| char* | ||||
| nextutf(char *p) | ||||
| { | ||||
| 	if(twobyte(*p)) return p[1]=='\0'?p+1:p+2; | ||||
| 	if(threebyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p+3; | ||||
| 	if(fourbyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p[3]=='\0'?p+3:p+4; | ||||
| 	return p+1; | ||||
| } | ||||
| /* | ||||
|  * Convert the utf code at *p to a unicode value | ||||
|  */ | ||||
|  | ||||
| int | ||||
| unicode(char *p) | ||||
| { | ||||
| 	int u=*p&0xff; | ||||
| 	if(twobyte(u)) return ((u&0x1f)<<6)|(p[1]&0x3f); | ||||
| 	if(threebyte(u)) return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f); | ||||
| 	if(fourbyte(u)) return (u<<18)|((p[1]&0x3f)<<12)|((p[2]&0x3f)<<6)|(p[3]&0x3f); | ||||
| 	return u; | ||||
| } | ||||
| /* | ||||
|  * Does the string s match the pattern p | ||||
|  * . and .. are only matched by patterns starting with . | ||||
|  * * matches any sequence of characters | ||||
|  * ? matches any single character | ||||
|  * [...] matches the enclosed list of characters | ||||
|  */ | ||||
|  | ||||
| int | ||||
| matchfn(char *s, char *p) | ||||
| { | ||||
| 	if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.') | ||||
| 		return 0; | ||||
| 	return match(s, p, '/'); | ||||
| } | ||||
|  | ||||
| int | ||||
| match(char *s, char *p, int stop) | ||||
| { | ||||
| 	int compl, hit, lo, hi, t, c; | ||||
| 	for(;*p!=stop && *p!='\0';s = nextutf(s),p = nextutf(p)){ | ||||
| 		if(*p!=GLOB){ | ||||
| 			if(!equtf(p, s)) return 0; | ||||
| 		} | ||||
| 		else switch(*++p){ | ||||
| 		case GLOB: | ||||
| 			if(*s!=GLOB) | ||||
| 				return 0; | ||||
| 			break; | ||||
| 		case '*': | ||||
| 			for(;;){ | ||||
| 				if(match(s, nextutf(p), stop)) return 1; | ||||
| 				if(!*s) | ||||
| 					break; | ||||
| 				s = nextutf(s); | ||||
| 			} | ||||
| 			return 0; | ||||
| 		case '?': | ||||
| 			if(*s=='\0') | ||||
| 				return 0; | ||||
| 			break; | ||||
| 		case '[': | ||||
| 			if(*s=='\0') | ||||
| 				return 0; | ||||
| 			c = unicode(s); | ||||
| 			p++; | ||||
| 			compl=*p=='~'; | ||||
| 			if(compl) | ||||
| 				p++; | ||||
| 			hit = 0; | ||||
| 			while(*p!=']'){ | ||||
| 				if(*p=='\0') | ||||
| 					return 0;		/* syntax error */ | ||||
| 				lo = unicode(p); | ||||
| 				p = nextutf(p); | ||||
| 				if(*p!='-') | ||||
| 					hi = lo; | ||||
| 				else{ | ||||
| 					p++; | ||||
| 					if(*p=='\0') | ||||
| 						return 0;	/* syntax error */ | ||||
| 					hi = unicode(p); | ||||
| 					p = nextutf(p); | ||||
| 					if(hi<lo){ t = lo; lo = hi; hi = t; } | ||||
| 				} | ||||
| 				if(lo<=c && c<=hi) | ||||
| 					hit = 1; | ||||
| 			} | ||||
| 			if(compl) | ||||
| 				hit=!hit; | ||||
| 			if(!hit) | ||||
| 				return 0; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	return *s=='\0'; | ||||
| } | ||||
|  | ||||
| void | ||||
| globlist1(word *gl) | ||||
| { | ||||
| 	if(gl){ | ||||
| 		globlist1(gl->next); | ||||
| 		glob(gl->word); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void | ||||
| globlist(void) | ||||
| { | ||||
| 	word *a; | ||||
| 	globv = 0; | ||||
| 	globlist1(runq->argv->words); | ||||
| 	poplist(); | ||||
| 	pushlist(); | ||||
| 	if(globv){ | ||||
| 		for(a = globv;a->next;a = a->next); | ||||
| 		a->next = runq->argv->words; | ||||
| 		runq->argv->words = globv; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										298
									
								
								cmd/rc/havefork.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										298
									
								
								cmd/rc/havefork.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,298 @@ | ||||
| #include <u.h> | ||||
| #include <signal.h> | ||||
| #if defined(PLAN9PORT) && defined(__sun__) | ||||
| #	define BSD_COMP	/* sigh.  for TIOCNOTTY */ | ||||
| #endif | ||||
| #include <sys/ioctl.h> | ||||
| #include "rc.h" | ||||
| #include "getflags.h" | ||||
| #include "exec.h" | ||||
| #include "io.h" | ||||
| #include "fns.h" | ||||
|  | ||||
| int havefork = 1; | ||||
|  | ||||
| void | ||||
| Xasync(void) | ||||
| { | ||||
| 	int null = open("/dev/null", 0); | ||||
| 	int tty; | ||||
| 	int pid; | ||||
| 	char npid[10]; | ||||
| 	if(null<0){ | ||||
| 		Xerror("Can't open /dev/null\n"); | ||||
| 		return; | ||||
| 	} | ||||
| 	switch(pid = rfork(RFFDG|RFPROC|RFNOTEG)){ | ||||
| 	case -1: | ||||
| 		close(null); | ||||
| 		Xerror("try again"); | ||||
| 		break; | ||||
| 	case 0: | ||||
| 		clearwaitpids(); | ||||
| 		/* | ||||
| 		 * I don't know what the right thing to do here is, | ||||
| 		 * so this is all experimentally determined. | ||||
| 		 * If we just dup /dev/null onto 0, then running | ||||
| 		 * ssh foo & will reopen /dev/tty, try to read a password, | ||||
| 		 * get a signal, and repeat, in a tight loop, forever. | ||||
| 		 * Arguably this is a bug in ssh (it behaves the same | ||||
| 		 * way under bash as under rc) but I'm fixing it here | ||||
| 		 * anyway.  If we dissociate the process from the tty, | ||||
| 		 * then it won't be able to open /dev/tty ever again. | ||||
| 		 * The SIG_IGN on SIGTTOU makes writing the tty | ||||
| 		 * (via fd 1 or 2, for example) succeed even though | ||||
| 		 * our pgrp is not the terminal's controlling pgrp. | ||||
| 		 */ | ||||
| 		if((tty = open("/dev/tty", OREAD)) >= 0){ | ||||
| 			/* | ||||
| 			 * Should make reads of tty fail, writes succeed. | ||||
| 			 */ | ||||
| 			signal(SIGTTIN, SIG_IGN); | ||||
| 			signal(SIGTTOU, SIG_IGN); | ||||
| 			ioctl(tty, TIOCNOTTY); | ||||
| 			close(tty); | ||||
| 		} | ||||
| 		if(isatty(0)) | ||||
| 			pushredir(ROPEN, null, 0); | ||||
| 		else | ||||
| 			close(null); | ||||
| 		start(runq->code, runq->pc+1, runq->local); | ||||
| 		runq->ret = 0; | ||||
| 		break; | ||||
| 	default: | ||||
| 		addwaitpid(pid); | ||||
| 		close(null); | ||||
| 		runq->pc = runq->code[runq->pc].i; | ||||
| 		inttoascii(npid, pid); | ||||
| 		setvar("apid", newword(npid, (word *)0)); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void | ||||
| Xpipe(void) | ||||
| { | ||||
| 	struct thread *p = runq; | ||||
| 	int pc = p->pc, forkid; | ||||
| 	int lfd = p->code[pc++].i; | ||||
| 	int rfd = p->code[pc++].i; | ||||
| 	int pfd[2]; | ||||
| 	if(pipe(pfd)<0){ | ||||
| 		Xerror("can't get pipe"); | ||||
| 		return; | ||||
| 	} | ||||
| 	switch(forkid = fork()){ | ||||
| 	case -1: | ||||
| 		Xerror("try again"); | ||||
| 		break; | ||||
| 	case 0: | ||||
| 		clearwaitpids(); | ||||
| 		start(p->code, pc+2, runq->local); | ||||
| 		runq->ret = 0; | ||||
| 		close(pfd[PRD]); | ||||
| 		pushredir(ROPEN, pfd[PWR], lfd); | ||||
| 		break; | ||||
| 	default: | ||||
| 		addwaitpid(forkid); | ||||
| 		start(p->code, p->code[pc].i, runq->local); | ||||
| 		close(pfd[PWR]); | ||||
| 		pushredir(ROPEN, pfd[PRD], rfd); | ||||
| 		p->pc = p->code[pc+1].i; | ||||
| 		p->pid = forkid; | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Who should wait for the exit from the fork? | ||||
|  */ | ||||
| void | ||||
| Xbackq(void) | ||||
| { | ||||
| 	struct thread *p = runq; | ||||
| 	char wd[8193]; | ||||
| 	int c, n; | ||||
| 	char *s, *ewd=&wd[8192], *stop, *q; | ||||
| 	struct io *f; | ||||
| 	var *ifs = vlook("ifs"); | ||||
| 	word *v, *nextv; | ||||
| 	int pfd[2]; | ||||
| 	int pid; | ||||
| 	Rune r; | ||||
| 	stop = ifs->val?ifs->val->word:""; | ||||
| 	if(pipe(pfd)<0){ | ||||
| 		Xerror("can't make pipe"); | ||||
| 		return; | ||||
| 	} | ||||
| 	switch(pid = fork()){ | ||||
| 	case -1: | ||||
| 		Xerror("try again"); | ||||
| 		close(pfd[PRD]); | ||||
| 		close(pfd[PWR]); | ||||
| 		return; | ||||
| 	case 0: | ||||
| 		clearwaitpids(); | ||||
| 		close(pfd[PRD]); | ||||
| 		start(runq->code, runq->pc+1, runq->local); | ||||
| 		pushredir(ROPEN, pfd[PWR], 1); | ||||
| 		return; | ||||
| 	default: | ||||
| 		addwaitpid(pid); | ||||
| 		close(pfd[PWR]); | ||||
| 		f = openfd(pfd[PRD]); | ||||
| 		s = wd; | ||||
| 		v = 0; | ||||
| 		while((c = rchr(f))!=EOF){ | ||||
| 			if(s != ewd) { | ||||
| 				*s++ = c; | ||||
| 				for(q=stop; *q; q+=n) { | ||||
| 					n = chartorune(&r, q); | ||||
| 					if(s-wd >= n && memcmp(s-n, q, n) == 0) { | ||||
| 						s -= n; | ||||
| 						goto stop; | ||||
| 					} | ||||
| 				} | ||||
| 				continue; | ||||
| 			} | ||||
| 		stop: | ||||
| 			if(s != wd) { | ||||
| 				*s = '\0'; | ||||
| 				v = newword(wd, v); | ||||
| 			} | ||||
| 			s = wd; | ||||
| 		} | ||||
| 		if(s!=wd){ | ||||
| 			*s='\0'; | ||||
| 			v = newword(wd, v); | ||||
| 		} | ||||
| 		closeio(f); | ||||
| 		Waitfor(pid, 0); | ||||
| 		/* v points to reversed arglist -- reverse it onto argv */ | ||||
| 		while(v){ | ||||
| 			nextv = v->next; | ||||
| 			v->next = runq->argv->words; | ||||
| 			runq->argv->words = v; | ||||
| 			v = nextv; | ||||
| 		} | ||||
| 		p->pc = p->code[p->pc].i; | ||||
| 		return; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void | ||||
| Xpipefd(void) | ||||
| { | ||||
| 	struct thread *p = runq; | ||||
| 	int pc = p->pc, pid; | ||||
| 	char name[40]; | ||||
| 	int pfd[2]; | ||||
| 	struct { int sidefd, mainfd; } fd[2], *r, *w; | ||||
|  | ||||
| 	r = &fd[0]; | ||||
| 	w = &fd[1]; | ||||
| 	switch(p->code[pc].i){ | ||||
| 	case READ: | ||||
| 		w = nil; | ||||
| 		break; | ||||
| 	case WRITE: | ||||
| 		r = nil; | ||||
| 	} | ||||
|  | ||||
| 	if(r){ | ||||
| 		if(pipe(pfd)<0){ | ||||
| 			Xerror("can't get pipe"); | ||||
| 			return; | ||||
| 		} | ||||
|  		r->sidefd = pfd[PWR]; | ||||
|  		r->mainfd = pfd[PRD]; | ||||
| 	} | ||||
| 	if(w){ | ||||
| 		if(pipe(pfd)<0){ | ||||
| 			Xerror("can't get pipe"); | ||||
| 			return; | ||||
| 		} | ||||
|  		w->sidefd = pfd[PRD]; | ||||
|  		w->mainfd = pfd[PWR]; | ||||
| 	} | ||||
| 	switch(pid = fork()){ | ||||
| 	case -1: | ||||
| 		Xerror("try again"); | ||||
| 		break; | ||||
| 	case 0: | ||||
| 		clearwaitpids(); | ||||
| 		start(p->code, pc+2, runq->local); | ||||
| 		if(r){ | ||||
| 			close(r->mainfd); | ||||
| 			pushredir(ROPEN, r->sidefd, 1); | ||||
| 		} | ||||
| 		if(w){ | ||||
| 			close(w->mainfd); | ||||
| 			pushredir(ROPEN, w->sidefd, 0); | ||||
| 		} | ||||
| 		runq->ret = 0; | ||||
| 		break; | ||||
| 	default: | ||||
| 		addwaitpid(pid); | ||||
| 		if(w){ | ||||
| 			close(w->sidefd); | ||||
| 			pushredir(ROPEN, w->mainfd, w->mainfd);	/* so that Xpopredir can close it later */ | ||||
| 			strcpy(name, Fdprefix); | ||||
| 			inttoascii(name+strlen(name), w->mainfd); | ||||
| 			pushword(name); | ||||
| 		} | ||||
| 		if(r){ | ||||
| 			close(r->sidefd); | ||||
| 			pushredir(ROPEN, r->mainfd, r->mainfd); | ||||
| 			strcpy(name, Fdprefix); | ||||
| 			inttoascii(name+strlen(name), r->mainfd); | ||||
| 			pushword(name); | ||||
| 		} | ||||
| 		p->pc = p->code[pc+1].i; | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void | ||||
| Xsubshell(void) | ||||
| { | ||||
| 	int pid; | ||||
| 	switch(pid = fork()){ | ||||
| 	case -1: | ||||
| 		Xerror("try again"); | ||||
| 		break; | ||||
| 	case 0: | ||||
| 		clearwaitpids(); | ||||
| 		start(runq->code, runq->pc+1, runq->local); | ||||
| 		runq->ret = 0; | ||||
| 		break; | ||||
| 	default: | ||||
| 		addwaitpid(pid); | ||||
| 		Waitfor(pid, 1); | ||||
| 		runq->pc = runq->code[runq->pc].i; | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int | ||||
| execforkexec(void) | ||||
| { | ||||
| 	int pid; | ||||
| 	int n; | ||||
| 	char buf[ERRMAX]; | ||||
|  | ||||
| 	switch(pid = fork()){ | ||||
| 	case -1: | ||||
| 		return -1; | ||||
| 	case 0: | ||||
| 		clearwaitpids(); | ||||
| 		pushword("exec"); | ||||
| 		execexec(); | ||||
| 		strcpy(buf, "can't exec: "); | ||||
| 		n = strlen(buf); | ||||
| 		errstr(buf+n, ERRMAX-n); | ||||
| 		Exit(buf); | ||||
| 	} | ||||
| 	addwaitpid(pid); | ||||
| 	return pid; | ||||
| } | ||||
							
								
								
									
										211
									
								
								cmd/rc/haventfork.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								cmd/rc/haventfork.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,211 @@ | ||||
| #include "rc.h" | ||||
| #include "getflags.h" | ||||
| #include "exec.h" | ||||
| #include "io.h" | ||||
| #include "fns.h" | ||||
|  | ||||
| int havefork = 0; | ||||
|  | ||||
| static char ** | ||||
| rcargv(char *s) | ||||
| { | ||||
| 	int argc; | ||||
| 	char **argv; | ||||
| 	word *p; | ||||
|  | ||||
| 	p = vlook("*")->val; | ||||
| 	argv = malloc((count(p)+6)*sizeof(char*)); | ||||
| 	argc = 0; | ||||
| 	argv[argc++] = argv0; | ||||
| 	if(flag['e']) | ||||
| 		argv[argc++] = "-Se"; | ||||
| 	else | ||||
| 		argv[argc++] = "-S"; | ||||
| 	argv[argc++] = "-c"; | ||||
| 	argv[argc++] = s; | ||||
| 	for(p = vlook("*")->val; p; p = p->next) | ||||
| 		argv[argc++] = p->word; | ||||
| 	argv[argc] = 0; | ||||
| 	return argv; | ||||
| } | ||||
|  | ||||
| void | ||||
| Xasync(void) | ||||
| { | ||||
| 	uint pid; | ||||
| 	char buf[20], **argv; | ||||
|  | ||||
| 	Updenv(); | ||||
|  | ||||
| 	argv = rcargv(runq->code[runq->pc].s); | ||||
| 	pid = ForkExecute(argv0, argv, -1, 1, 2); | ||||
| 	free(argv); | ||||
|  | ||||
| 	if(pid == 0) { | ||||
| 		Xerror("proc failed"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	runq->pc++; | ||||
| 	sprint(buf, "%d", pid); | ||||
| 	setvar("apid", newword(buf, (word *)0)); | ||||
| } | ||||
|  | ||||
| void | ||||
| Xbackq(void) | ||||
| { | ||||
| 	char wd[8193], **argv; | ||||
| 	int c; | ||||
| 	char *s, *ewd=&wd[8192], *stop; | ||||
| 	struct io *f; | ||||
| 	var *ifs = vlook("ifs"); | ||||
| 	word *v, *nextv; | ||||
| 	int pfd[2]; | ||||
| 	int pid; | ||||
|  | ||||
| 	stop = ifs->val?ifs->val->word:""; | ||||
| 	if(pipe(pfd)<0){ | ||||
| 		Xerror("can't make pipe"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	Updenv(); | ||||
|  | ||||
| 	argv = rcargv(runq->code[runq->pc].s); | ||||
| 	pid = ForkExecute(argv0, argv, -1, pfd[1], 2); | ||||
| 	free(argv); | ||||
|  | ||||
| 	close(pfd[1]); | ||||
|  | ||||
| 	if(pid == 0) { | ||||
| 		Xerror("proc failed"); | ||||
| 		close(pfd[0]); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	f = openfd(pfd[0]); | ||||
| 	s = wd; | ||||
| 	v = 0; | ||||
| 	while((c=rchr(f))!=EOF){ | ||||
| 		if(strchr(stop, c) || s==ewd){ | ||||
| 			if(s!=wd){ | ||||
| 				*s='\0'; | ||||
| 				v=newword(wd, v); | ||||
| 				s=wd; | ||||
| 			} | ||||
| 		} | ||||
| 		else *s++=c; | ||||
| 	} | ||||
| 	if(s!=wd){ | ||||
| 		*s='\0'; | ||||
| 		v=newword(wd, v); | ||||
| 	} | ||||
| 	closeio(f); | ||||
| 	Waitfor(pid, 1); | ||||
| 	/* v points to reversed arglist -- reverse it onto argv */ | ||||
| 	while(v){ | ||||
| 		nextv=v->next; | ||||
| 		v->next=runq->argv->words; | ||||
| 		runq->argv->words=v; | ||||
| 		v=nextv; | ||||
| 	} | ||||
| 	runq->pc++; | ||||
| } | ||||
|  | ||||
| void | ||||
| Xpipe(void) | ||||
| { | ||||
| 	thread *p=runq; | ||||
| 	int pc=p->pc, pid; | ||||
| 	int rfd=p->code[pc+1].i; | ||||
| 	int pfd[2]; | ||||
| 	char **argv; | ||||
|  | ||||
| 	if(pipe(pfd)<0){ | ||||
| 		Xerror1("can't get pipe"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	Updenv(); | ||||
|  | ||||
| 	argv = rcargv(runq->code[pc+2].s); | ||||
| 	pid = ForkExecute(argv0, argv, 0, pfd[1], 2); | ||||
| 	free(argv); | ||||
| 	close(pfd[1]); | ||||
|  | ||||
| 	if(pid == 0) { | ||||
| 		Xerror("proc failed"); | ||||
| 		close(pfd[0]); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	start(p->code, pc+4, runq->local); | ||||
| 	pushredir(ROPEN, pfd[0], rfd); | ||||
| 	p->pc=p->code[pc+3].i; | ||||
| 	p->pid=pid; | ||||
| } | ||||
|  | ||||
| void | ||||
| Xpipefd(void) | ||||
| { | ||||
| 	Abort(); | ||||
| } | ||||
|  | ||||
| void | ||||
| Xsubshell(void) | ||||
| { | ||||
| 	char **argv; | ||||
| 	int pid; | ||||
|  | ||||
| 	Updenv(); | ||||
|  | ||||
| 	argv = rcargv(runq->code[runq->pc].s); | ||||
| 	pid = ForkExecute(argv0, argv, -1, 1, 2); | ||||
| 	free(argv); | ||||
|  | ||||
| 	if(pid < 0) { | ||||
| 		Xerror("proc failed"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	Waitfor(pid, 1); | ||||
| 	runq->pc++; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  *  start a process running the cmd on the stack and return its pid. | ||||
|  */ | ||||
| int | ||||
| execforkexec(void) | ||||
| { | ||||
| 	char **argv; | ||||
| 	char file[1024]; | ||||
| 	int nc; | ||||
| 	word *path; | ||||
| 	int pid; | ||||
|  | ||||
| 	if(runq->argv->words==0) | ||||
| 		return -1; | ||||
| 	argv = mkargv(runq->argv->words); | ||||
|  | ||||
| 	for(path = searchpath(runq->argv->words->word);path;path = path->next){ | ||||
| 		nc = strlen(path->word); | ||||
| 		if(nc<sizeof(file)){ | ||||
| 			strcpy(file, path->word); | ||||
| 			if(file[0]){ | ||||
| 				strcat(file, "/"); | ||||
| 				nc++; | ||||
| 			} | ||||
| 			if(nc+strlen(argv[1])<sizeof(file)){ | ||||
| 				strcat(file, argv[1]); | ||||
| 				pid = ForkExecute(file, argv+1, mapfd(0), mapfd(1), mapfd(2)); | ||||
| 				if(pid >= 0){ | ||||
| 					free(argv); | ||||
| 					return pid; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	free(argv); | ||||
| 	return -1; | ||||
| } | ||||
							
								
								
									
										150
									
								
								cmd/rc/here.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								cmd/rc/here.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,150 @@ | ||||
| #include "rc.h" | ||||
| #include "exec.h" | ||||
| #include "io.h" | ||||
| #include "fns.h" | ||||
| struct here *here, **ehere; | ||||
| int ser = 0; | ||||
| char tmp[]="/tmp/here0000.0000"; | ||||
| char hex[]="0123456789abcdef"; | ||||
| void psubst(io*, char*); | ||||
| void pstrs(io*, word*); | ||||
|  | ||||
| void | ||||
| hexnum(char *p, int n) | ||||
| { | ||||
| 	*p++=hex[(n>>12)&0xF]; | ||||
| 	*p++=hex[(n>>8)&0xF]; | ||||
| 	*p++=hex[(n>>4)&0xF]; | ||||
| 	*p = hex[n&0xF]; | ||||
| } | ||||
|  | ||||
| tree* | ||||
| heredoc(tree *tag) | ||||
| { | ||||
| 	struct here *h = new(struct here); | ||||
| 	if(tag->type!=WORD) | ||||
| 		yyerror("Bad here tag"); | ||||
| 	h->next = 0; | ||||
| 	if(here) | ||||
| 		*ehere = h; | ||||
| 	else | ||||
| 		here = h; | ||||
| 	ehere=&h->next; | ||||
| 	h->tag = tag; | ||||
| 	hexnum(&tmp[9], getpid()); | ||||
| 	hexnum(&tmp[14], ser++); | ||||
| 	h->name = strdup(tmp); | ||||
| 	return token(tmp, WORD); | ||||
| } | ||||
| /* | ||||
|  * bug: lines longer than NLINE get split -- this can cause spurious | ||||
|  * missubstitution, or a misrecognized EOF marker. | ||||
|  */ | ||||
| #define	NLINE	4096 | ||||
|  | ||||
| void | ||||
| readhere(void) | ||||
| { | ||||
| 	struct here *h, *nexth; | ||||
| 	io *f; | ||||
| 	char *s, *tag; | ||||
| 	int c, subst; | ||||
| 	char line[NLINE+1]; | ||||
| 	for(h = here;h;h = nexth){ | ||||
| 		subst=!h->tag->quoted; | ||||
| 		tag = h->tag->str; | ||||
| 		c = Creat(h->name); | ||||
| 		if(c<0) | ||||
| 			yyerror("can't create here document"); | ||||
| 		f = openfd(c); | ||||
| 		s = line; | ||||
| 		pprompt(); | ||||
| 		while((c = rchr(runq->cmdfd))!=EOF){ | ||||
| 			if(c=='\n' || s==&line[NLINE]){ | ||||
| 				*s='\0'; | ||||
| 				if(tag && strcmp(line, tag)==0) break; | ||||
| 				if(subst) | ||||
| 					psubst(f, line); | ||||
| 				else pstr(f, line); | ||||
| 				s = line; | ||||
| 				if(c=='\n'){ | ||||
| 					pprompt(); | ||||
| 					pchr(f, c); | ||||
| 				} | ||||
| 				else *s++=c; | ||||
| 			} | ||||
| 			else *s++=c; | ||||
| 		} | ||||
| 		flush(f); | ||||
| 		closeio(f); | ||||
| 		cleanhere(h->name); | ||||
| 		nexth = h->next; | ||||
| 		efree((char *)h); | ||||
| 	} | ||||
| 	here = 0; | ||||
| 	doprompt = 1; | ||||
| } | ||||
|  | ||||
| void | ||||
| psubst(io *f, char *s) | ||||
| { | ||||
| 	char *t, *u; | ||||
| 	int savec, n; | ||||
| 	word *star; | ||||
| 	while(*s){ | ||||
| 		if(*s!='$'){ | ||||
| 			if(0xa0<=(*s&0xff) && (*s&0xff)<=0xf5){ | ||||
| 				pchr(f, *s++); | ||||
| 				if(*s=='\0') | ||||
| 					break; | ||||
| 			} | ||||
| 			else if(0xf6<=(*s&0xff) && (*s&0xff)<=0xf7){ | ||||
| 				pchr(f, *s++); | ||||
| 				if(*s=='\0') | ||||
| 					break; | ||||
| 				pchr(f, *s++); | ||||
| 				if(*s=='\0') | ||||
| 					break; | ||||
| 			} | ||||
| 			pchr(f, *s++); | ||||
| 		} | ||||
| 		else{ | ||||
| 			t=++s; | ||||
| 			if(*t=='$') | ||||
| 				pchr(f, *t++); | ||||
| 			else{ | ||||
| 				while(*t && idchr(*t)) t++; | ||||
| 				savec=*t; | ||||
| 				*t='\0'; | ||||
| 				n = 0; | ||||
| 				for(u = s;*u && '0'<=*u && *u<='9';u++) n = n*10+*u-'0'; | ||||
| 				if(n && *u=='\0'){ | ||||
| 					star = vlook("*")->val; | ||||
| 					if(star && 1<=n && n<=count(star)){ | ||||
| 						while(--n) star = star->next; | ||||
| 						pstr(f, star->word); | ||||
| 					} | ||||
| 				} | ||||
| 				else | ||||
| 					pstrs(f, vlook(s)->val); | ||||
| 				*t = savec; | ||||
| 				if(savec=='^') | ||||
| 					t++; | ||||
| 			} | ||||
| 			s = t; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void | ||||
| pstrs(io *f, word *a) | ||||
| { | ||||
| 	if(a){ | ||||
| 		while(a->next && a->next->word){ | ||||
| 			pstr(f, a->word); | ||||
| 			pchr(f, ' '); | ||||
| 			a = a->next; | ||||
| 		} | ||||
| 		pstr(f, a->word); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										273
									
								
								cmd/rc/io.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								cmd/rc/io.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,273 @@ | ||||
| #include <limits.h> | ||||
| #include <errno.h> | ||||
| #include "rc.h" | ||||
| #include "exec.h" | ||||
| #include "io.h" | ||||
| #include "fns.h" | ||||
| int pfmtnest = 0; | ||||
|  | ||||
| void | ||||
| pfmt(io *f, char *fmt, ...) | ||||
| { | ||||
| 	va_list ap; | ||||
| 	char err[ERRMAX]; | ||||
| 	va_start(ap, fmt); | ||||
| 	pfmtnest++; | ||||
| 	for(;*fmt;fmt++) | ||||
| 		if(*fmt!='%') | ||||
| 			pchr(f, *fmt); | ||||
| 		else switch(*++fmt){ | ||||
| 		case '\0': | ||||
| 			va_end(ap); | ||||
| 			return; | ||||
| 		case 'c': | ||||
| 			pchr(f, va_arg(ap, int)); | ||||
| 			break; | ||||
| 		case 'd': | ||||
| 			pdec(f, va_arg(ap, int)); | ||||
| 			break; | ||||
| 		case 'o': | ||||
| 			poct(f, va_arg(ap, unsigned)); | ||||
| 			break; | ||||
| 		case 'p': | ||||
| 			pptr(f, va_arg(ap, void*)); | ||||
| 			break; | ||||
| 		case 'Q': | ||||
| 			pquo(f, va_arg(ap, char *)); | ||||
| 			break; | ||||
| 		case 'q': | ||||
| 			pwrd(f, va_arg(ap, char *)); | ||||
| 			break; | ||||
| 		case 'r': | ||||
| 			rerrstr(err, sizeof err); pstr(f, err); | ||||
| 			break; | ||||
| 		case 's': | ||||
| 			pstr(f, va_arg(ap, char *)); | ||||
| 			break; | ||||
| 		case 't': | ||||
| 			pcmd(f, va_arg(ap, tree *)); | ||||
| 			break; | ||||
| 		case 'u': | ||||
| 			pcmdu(f, va_arg(ap, tree *)); | ||||
| 			break; | ||||
| 		case 'v': | ||||
| 			pval(f, va_arg(ap, struct word *)); | ||||
| 			break; | ||||
| 		default: | ||||
| 			pchr(f, *fmt); | ||||
| 			break; | ||||
| 		} | ||||
| 	va_end(ap); | ||||
| 	if(--pfmtnest==0) | ||||
| 		flush(f); | ||||
| } | ||||
|  | ||||
| void | ||||
| pchr(io *b, int c) | ||||
| { | ||||
| 	if(b->bufp==b->ebuf) | ||||
| 		fullbuf(b, c); | ||||
| 	else *b->bufp++=c; | ||||
| } | ||||
|  | ||||
| int | ||||
| rchr(io *b) | ||||
| { | ||||
| 	if(b->bufp==b->ebuf) | ||||
| 		return emptybuf(b); | ||||
| 	return *b->bufp++ & 0xFF; | ||||
| } | ||||
|  | ||||
| void | ||||
| pquo(io *f, char *s) | ||||
| { | ||||
| 	pchr(f, '\''); | ||||
| 	for(;*s;s++) | ||||
| 		if(*s=='\'') | ||||
| 			pfmt(f, "''"); | ||||
| 		else pchr(f, *s); | ||||
| 	pchr(f, '\''); | ||||
| } | ||||
|  | ||||
| void | ||||
| pwrd(io *f, char *s) | ||||
| { | ||||
| 	char *t; | ||||
| 	for(t = s;*t;t++) if(!wordchr(*t)) break; | ||||
| 	if(t==s || *t) | ||||
| 		pquo(f, s); | ||||
| 	else pstr(f, s); | ||||
| } | ||||
|  | ||||
| void | ||||
| pptr(io *f, void *v) | ||||
| { | ||||
| 	int n; | ||||
| 	uintptr p; | ||||
|  | ||||
| 	p = (uintptr)v; | ||||
| 	if(sizeof(uintptr) == sizeof(uvlong) && p>>32) | ||||
| 		for(n = 60;n>=32;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]); | ||||
|  | ||||
| 	for(n = 28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]); | ||||
| } | ||||
|  | ||||
| void | ||||
| pstr(io *f, char *s) | ||||
| { | ||||
| 	if(s==0) | ||||
| 		s="(null)"; | ||||
| 	while(*s) pchr(f, *s++); | ||||
| } | ||||
|  | ||||
| void | ||||
| pdec(io *f, int n) | ||||
| { | ||||
| 	if(n<0){ | ||||
| 		if(n!=INT_MIN){ | ||||
| 			pchr(f, '-'); | ||||
| 			pdec(f, -n); | ||||
| 			return; | ||||
| 		} | ||||
| 		/* n is two's complement minimum integer */ | ||||
| 		n = -(INT_MIN+1); | ||||
| 		pchr(f, '-'); | ||||
| 		pdec(f, n/10); | ||||
| 		pchr(f, n%10+'1'); | ||||
| 		return; | ||||
| 	} | ||||
| 	if(n>9) | ||||
| 		pdec(f, n/10); | ||||
| 	pchr(f, n%10+'0'); | ||||
| } | ||||
|  | ||||
| void | ||||
| poct(io *f, unsigned n) | ||||
| { | ||||
| 	if(n>7) | ||||
| 		poct(f, n>>3); | ||||
| 	pchr(f, (n&7)+'0'); | ||||
| } | ||||
|  | ||||
| void | ||||
| pval(io *f, word *a) | ||||
| { | ||||
| 	if(a){ | ||||
| 		while(a->next && a->next->word){ | ||||
| 			pwrd(f, a->word); | ||||
| 			pchr(f, ' '); | ||||
| 			a = a->next; | ||||
| 		} | ||||
| 		pwrd(f, a->word); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int | ||||
| fullbuf(io *f, int c) | ||||
| { | ||||
| 	flush(f); | ||||
| 	return *f->bufp++=c; | ||||
| } | ||||
|  | ||||
| void | ||||
| flush(io *f) | ||||
| { | ||||
| 	int n; | ||||
| 	char *s; | ||||
| 	if(f->strp){ | ||||
| 		n = f->ebuf-f->strp; | ||||
| 		f->strp = realloc(f->strp, n+101); | ||||
| 		if(f->strp==0) | ||||
| 			panic("Can't realloc %d bytes in flush!", n+101); | ||||
| 		f->bufp = f->strp+n; | ||||
| 		f->ebuf = f->bufp+100; | ||||
| 		for(s = f->bufp;s<=f->ebuf;s++) *s='\0'; | ||||
| 	} | ||||
| 	else{ | ||||
| 		n = f->bufp-f->buf; | ||||
| 		if(n && Write(f->fd, f->buf, n) < 0){ | ||||
| 			Write(3, "Write error\n", 12); | ||||
| 			if(ntrap) | ||||
| 				dotrap(); | ||||
| 		} | ||||
| 		f->bufp = f->buf; | ||||
| 		f->ebuf = f->buf+NBUF; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| io* | ||||
| openfd(int fd) | ||||
| { | ||||
| 	io *f = new(struct io); | ||||
| 	f->fd = fd; | ||||
| 	f->bufp = f->ebuf = f->buf; | ||||
| 	f->strp = 0; | ||||
| 	return f; | ||||
| } | ||||
|  | ||||
| io* | ||||
| openstr(void) | ||||
| { | ||||
| 	io *f = new(struct io); | ||||
| 	char *s; | ||||
| 	f->fd=-1; | ||||
| 	f->bufp = f->strp = emalloc(101); | ||||
| 	f->ebuf = f->bufp+100; | ||||
| 	for(s = f->bufp;s<=f->ebuf;s++) *s='\0'; | ||||
| 	return f; | ||||
| } | ||||
| /* | ||||
|  * Open a corebuffer to read.  EOF occurs after reading len | ||||
|  * characters from buf. | ||||
|  */ | ||||
|  | ||||
| io* | ||||
| opencore(char *s, int len) | ||||
| { | ||||
| 	io *f = new(struct io); | ||||
| 	char *buf = emalloc(len); | ||||
| 	f->fd= -1 /*open("/dev/null", 0)*/; | ||||
| 	f->bufp = f->strp = buf; | ||||
| 	f->ebuf = buf+len; | ||||
| 	Memcpy(buf, s, len); | ||||
| 	return f; | ||||
| } | ||||
|  | ||||
| void | ||||
| iorewind(io *io) | ||||
| { | ||||
| 	if(io->fd==-1) | ||||
| 		io->bufp = io->strp; | ||||
| 	else{ | ||||
| 		io->bufp = io->ebuf = io->buf; | ||||
| 		Seek(io->fd, 0L, 0); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void | ||||
| closeio(io *io) | ||||
| { | ||||
| 	if(io->fd>=0) | ||||
| 		close(io->fd); | ||||
| 	if(io->strp) | ||||
| 		efree(io->strp); | ||||
| 	efree((char *)io); | ||||
| } | ||||
|  | ||||
| int | ||||
| emptybuf(io *f) | ||||
| { | ||||
| 	int n; | ||||
| 	if(f->fd==-1) | ||||
| 		return EOF; | ||||
| Loop: | ||||
| 	errno = 0; | ||||
| 	n = Read(f->fd, f->buf, NBUF); | ||||
| 	if(n < 0 && errno == EINTR) | ||||
| 		goto Loop; | ||||
| 	if(n <= 0) | ||||
| 		return EOF; | ||||
| 	f->bufp = f->buf; | ||||
| 	f->ebuf = f->buf+n; | ||||
| 	return *f->bufp++&0xff; | ||||
| } | ||||
							
								
								
									
										31
									
								
								cmd/rc/io.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								cmd/rc/io.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| /* | ||||
|  * on Mac OS X, err is something else, | ||||
|  * and assigning to it causes a bus error. | ||||
|  * what a crappy linker. | ||||
|  */ | ||||
| #define err rc_err | ||||
| #define	EOF	(-1) | ||||
| #define	NBUF	512 | ||||
| struct io{ | ||||
| 	int fd; | ||||
| 	char *bufp, *ebuf, *strp, buf[NBUF]; | ||||
| }; | ||||
| io *err; | ||||
| io *openfd(int), *openstr(void), *opencore(char *, int); | ||||
| int emptybuf(io*); | ||||
| void pchr(io*, int); | ||||
| int rchr(io*); | ||||
| void closeio(io*); | ||||
| void flush(io*); | ||||
| int fullbuf(io*, int); | ||||
| void pdec(io*, int); | ||||
| void poct(io*, unsigned); | ||||
| void pptr(io*, void*); | ||||
| void pquo(io*, char*); | ||||
| void pwrd(io*, char*); | ||||
| void pstr(io*, char*); | ||||
| void pcmd(io*, tree*); | ||||
| void pcmdu(io*, tree*); | ||||
| void pval(io*, word*); | ||||
| void pfnc(io*, thread*); | ||||
| void pfmt(io*, char*, ...); | ||||
							
								
								
									
										396
									
								
								cmd/rc/lex.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										396
									
								
								cmd/rc/lex.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,396 @@ | ||||
| #include "rc.h" | ||||
| #include "exec.h" | ||||
| #include "io.h" | ||||
| #include "getflags.h" | ||||
| #include "fns.h" | ||||
| int getnext(void); | ||||
|  | ||||
| int | ||||
| wordchr(int c) | ||||
| { | ||||
| 	return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF; | ||||
| } | ||||
|  | ||||
| int | ||||
| idchr(int c) | ||||
| { | ||||
| 	/* | ||||
| 	 * Formerly: | ||||
| 	 * return 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9' | ||||
| 	 *	|| c=='_' || c=='*'; | ||||
| 	 */ | ||||
| 	return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c); | ||||
| } | ||||
| int future = EOF; | ||||
| int doprompt = 1; | ||||
| int inquote; | ||||
| int incomm; | ||||
| /* | ||||
|  * Look ahead in the input stream | ||||
|  */ | ||||
|  | ||||
| int | ||||
| nextc(void) | ||||
| { | ||||
| 	if(future==EOF) | ||||
| 		future = getnext(); | ||||
| 	return future; | ||||
| } | ||||
| /* | ||||
|  * Consume the lookahead character. | ||||
|  */ | ||||
|  | ||||
| int | ||||
| advance(void) | ||||
| { | ||||
| 	int c = nextc(); | ||||
| 	lastc = future; | ||||
| 	future = EOF; | ||||
| 	return c; | ||||
| } | ||||
| /* | ||||
|  * read a character from the input stream | ||||
|  */ | ||||
|  | ||||
| int | ||||
| getnext(void) | ||||
| { | ||||
| 	int c; | ||||
| 	static int peekc = EOF; | ||||
| 	if(peekc!=EOF){ | ||||
| 		c = peekc; | ||||
| 		peekc = EOF; | ||||
| 		return c; | ||||
| 	} | ||||
| 	if(runq->eof) | ||||
| 		return EOF; | ||||
| 	if(doprompt) | ||||
| 		pprompt(); | ||||
| 	c = rchr(runq->cmdfd); | ||||
| 	if(!inquote && c=='\\'){ | ||||
| 		c = rchr(runq->cmdfd); | ||||
| 		if(c=='\n' && !incomm){		/* don't continue a comment */ | ||||
| 			doprompt = 1; | ||||
| 			c=' '; | ||||
| 		} | ||||
| 		else{ | ||||
| 			peekc = c; | ||||
| 			c='\\'; | ||||
| 		} | ||||
| 	} | ||||
| 	doprompt = doprompt || c=='\n' || c==EOF; | ||||
| 	if(c==EOF) | ||||
| 		runq->eof++; | ||||
| 	else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c); | ||||
| 	return c; | ||||
| } | ||||
|  | ||||
| void | ||||
| pprompt(void) | ||||
| { | ||||
| 	var *prompt; | ||||
| 	if(runq->iflag){ | ||||
| 		pstr(err, promptstr); | ||||
| 		flush(err); | ||||
| 		prompt = vlook("prompt"); | ||||
| 		if(prompt->val && prompt->val->next) | ||||
| 			promptstr = prompt->val->next->word; | ||||
| 		else | ||||
| 			promptstr="\t"; | ||||
| 	} | ||||
| 	runq->lineno++; | ||||
| 	doprompt = 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| skipwhite(void) | ||||
| { | ||||
| 	int c, skipped; | ||||
| 	skipped = 0; | ||||
| 	for(;;){ | ||||
| 		c = nextc(); | ||||
| 		/* Why did this used to be  if(!inquote && c=='#') ?? */ | ||||
| 		if(c=='#'){ | ||||
| 			incomm = 1; | ||||
| 			skipped = 1; | ||||
| 			for(;;){ | ||||
| 				c = nextc(); | ||||
| 				if(c=='\n' || c==EOF) { | ||||
| 					incomm = 0; | ||||
| 					break; | ||||
| 				} | ||||
| 				advance(); | ||||
| 			} | ||||
| 		} | ||||
| 		if(c==' ' || c=='\t') { | ||||
| 			skipped = 1; | ||||
| 			advance(); | ||||
| 		} | ||||
| 		else | ||||
| 			return skipped; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void | ||||
| skipnl(void) | ||||
| { | ||||
| 	int c; | ||||
| 	for(;;){ | ||||
| 		skipwhite(); | ||||
| 		c = nextc(); | ||||
| 		if(c!='\n') | ||||
| 			return; | ||||
| 		advance(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int | ||||
| nextis(int c) | ||||
| { | ||||
| 	if(nextc()==c){ | ||||
| 		advance(); | ||||
| 		return 1; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| char* | ||||
| addtok(char *p, int val) | ||||
| { | ||||
| 	if(p==0) | ||||
| 		return 0; | ||||
| 	if(p==&tok[NTOK-1]){ | ||||
| 		*p = 0; | ||||
| 		yyerror("token buffer too short"); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	*p++=val; | ||||
| 	return p; | ||||
| } | ||||
|  | ||||
| char* | ||||
| addutf(char *p, int c) | ||||
| { | ||||
| 	p = addtok(p, c); | ||||
| 	if(twobyte(c))	 /* 2-byte escape */ | ||||
| 		return addtok(p, advance()); | ||||
| 	if(threebyte(c)){	/* 3-byte escape */ | ||||
| 		p = addtok(p, advance()); | ||||
| 		return addtok(p, advance()); | ||||
| 	} | ||||
| 	if(fourbyte(c)){	/* 4-byte escape */ | ||||
| 		p = addtok(p, advance()); | ||||
| 		p = addtok(p, advance()); | ||||
| 		return addtok(p, advance()); | ||||
| 	} | ||||
| 	return p; | ||||
| } | ||||
| int lastdol;	/* was the last token read '$' or '$#' or '"'? */ | ||||
| int lastword;	/* was the last token read a word or compound word terminator? */ | ||||
|  | ||||
| int | ||||
| yylex(void) | ||||
| { | ||||
| 	int c, d = nextc(); | ||||
| 	char *w = tok; | ||||
| 	tree *t; | ||||
| 	yylval.tree = 0; | ||||
| 	/* | ||||
| 	 * Embarassing sneakiness:  if the last token read was a quoted or unquoted | ||||
| 	 * WORD then we alter the meaning of what follows.  If the next character | ||||
| 	 * is `(', we return SUB (a subscript paren) and consume the `('.  Otherwise, | ||||
| 	 * if the next character is the first character of a simple or compound word, | ||||
| 	 * we insert a `^' before it. | ||||
| 	 */ | ||||
| 	if(lastword && flag['Y']){ | ||||
| 		lastword = 0; | ||||
| 		if(d=='('){ | ||||
| 			advance(); | ||||
| 			strcpy(tok, "("); | ||||
| 			return SUB; | ||||
| 		} | ||||
| 		if(wordchr(d) || d=='\'' || d=='`' || d=='$' || d=='"'){ | ||||
| 			strcpy(tok, "^"); | ||||
| 			return '^'; | ||||
| 		} | ||||
| 	} | ||||
| 	inquote = 0; | ||||
| 	if(skipwhite() && !flag['Y']) | ||||
| 		return ' '; | ||||
| 	switch(c = advance()){ | ||||
| 	case EOF: | ||||
| 		lastdol = 0; | ||||
| 		strcpy(tok, "EOF"); | ||||
| 		return EOF; | ||||
| 	case '$': | ||||
| 		lastdol = 1; | ||||
| 		if(nextis('#')){ | ||||
| 			strcpy(tok, "$#"); | ||||
| 			return COUNT; | ||||
| 		} | ||||
| 		if(nextis('"')){ | ||||
| 			strcpy(tok, "$\""); | ||||
| 			return '"'; | ||||
| 		} | ||||
| 		strcpy(tok, "$"); | ||||
| 		return '$'; | ||||
| 	case '&': | ||||
| 		lastdol = 0; | ||||
| 		if(nextis('&')){ | ||||
| 			if(flag['Y']) | ||||
| 				skipnl(); | ||||
| 			strcpy(tok, "&&"); | ||||
| 			return ANDAND; | ||||
| 		} | ||||
| 		strcpy(tok, "&"); | ||||
| 		return '&'; | ||||
| 	case '|': | ||||
| 		lastdol = 0; | ||||
| 		if(nextis(c)){ | ||||
| 			if(flag['Y']) | ||||
| 				skipnl(); | ||||
| 			strcpy(tok, "||"); | ||||
| 			return OROR; | ||||
| 		} | ||||
| 	case '<': | ||||
| 	case '>': | ||||
| 		lastdol = 0; | ||||
| 		/* | ||||
| 		 * funny redirection tokens: | ||||
| 		 *	redir:	arrow | arrow '[' fd ']' | ||||
| 		 *	arrow:	'<' | '<<' | '>' | '>>' | '|' | ||||
| 		 *	fd:	digit | digit '=' | digit '=' digit | ||||
| 		 *	digit:	'0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' | ||||
| 		 * some possibilities are nonsensical and get a message. | ||||
| 		 */ | ||||
| 		*w++=c; | ||||
| 		t = newtree(); | ||||
| 		switch(c){ | ||||
| 		case '|': | ||||
| 			t->type = PIPE; | ||||
| 			t->fd0 = 1; | ||||
| 			t->fd1 = 0; | ||||
| 			break; | ||||
| 		case '>': | ||||
| 			t->type = REDIR; | ||||
| 			if(nextis(c)){ | ||||
| 				t->rtype = APPEND; | ||||
| 				*w++=c; | ||||
| 			} | ||||
| 			else t->rtype = WRITE; | ||||
| 			t->fd0 = 1; | ||||
| 			break; | ||||
| 		case '<': | ||||
| 			t->type = REDIR; | ||||
| 			if(nextis(c)){ | ||||
| 				t->rtype = HERE; | ||||
| 				*w++=c; | ||||
| 			} else if (nextis('>')){ | ||||
| 				t->rtype = RDWR; | ||||
| 				*w++=c; | ||||
| 			} else t->rtype = READ; | ||||
| 			t->fd0 = 0; | ||||
| 			break; | ||||
| 		} | ||||
| 		if(nextis('[')){ | ||||
| 			*w++='['; | ||||
| 			c = advance(); | ||||
| 			*w++=c; | ||||
| 			if(c<'0' || '9'<c){ | ||||
| 			RedirErr: | ||||
| 				*w = 0; | ||||
| 				yyerror(t->type==PIPE?"pipe syntax" | ||||
| 						:"redirection syntax"); | ||||
| 				return EOF; | ||||
| 			} | ||||
| 			t->fd0 = 0; | ||||
| 			do{ | ||||
| 				t->fd0 = t->fd0*10+c-'0'; | ||||
| 				*w++=c; | ||||
| 				c = advance(); | ||||
| 			}while('0'<=c && c<='9'); | ||||
| 			if(c=='='){ | ||||
| 				*w++='='; | ||||
| 				if(t->type==REDIR) | ||||
| 					t->type = DUP; | ||||
| 				c = advance(); | ||||
| 				if('0'<=c && c<='9'){ | ||||
| 					t->rtype = DUPFD; | ||||
| 					t->fd1 = t->fd0; | ||||
| 					t->fd0 = 0; | ||||
| 					do{ | ||||
| 						t->fd0 = t->fd0*10+c-'0'; | ||||
| 						*w++=c; | ||||
| 						c = advance(); | ||||
| 					}while('0'<=c && c<='9'); | ||||
| 				} | ||||
| 				else{ | ||||
| 					if(t->type==PIPE) | ||||
| 						goto RedirErr; | ||||
| 					t->rtype = CLOSE; | ||||
| 				} | ||||
| 			} | ||||
| 			if(c!=']' | ||||
| 			|| t->type==DUP && (t->rtype==HERE || t->rtype==APPEND)) | ||||
| 				goto RedirErr; | ||||
| 			*w++=']'; | ||||
| 		} | ||||
| 		*w='\0'; | ||||
| 		yylval.tree = t; | ||||
| 		if(t->type==PIPE && flag['Y']) | ||||
| 			skipnl(); | ||||
| 		if(t->type==REDIR) { | ||||
| 			skipwhite(); | ||||
| 			if(nextc() == '{') | ||||
| 				t->type = REDIRW; | ||||
| 		} | ||||
| 		return t->type; | ||||
| 	case '\'': | ||||
| 		lastdol = 0; | ||||
| 		lastword = 1; | ||||
| 		inquote = 1; | ||||
| 		for(;;){ | ||||
| 			c = advance(); | ||||
| 			if(c==EOF) | ||||
| 				break; | ||||
| 			if(c=='\''){ | ||||
| 				if(nextc()!='\'') | ||||
| 					break; | ||||
| 				advance(); | ||||
| 			} | ||||
| 			w = addutf(w, c); | ||||
| 		} | ||||
| 		if(w!=0) | ||||
| 			*w='\0'; | ||||
| 		t = token(tok, WORD); | ||||
| 		t->quoted = 1; | ||||
| 		yylval.tree = t; | ||||
| 		return t->type; | ||||
| 	} | ||||
| 	if(!wordchr(c)){ | ||||
| 		lastdol = 0; | ||||
| 		tok[0] = c; | ||||
| 		tok[1]='\0'; | ||||
| 		return c; | ||||
| 	} | ||||
| 	for(;;){ | ||||
| 		/* next line should have (char)c==GLOB, but ken's compiler is broken */ | ||||
| 		if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB) | ||||
| 			w = addtok(w, GLOB); | ||||
| 		w = addutf(w, c); | ||||
| 		c = nextc(); | ||||
| 		if(lastdol?!idchr(c):!wordchr(c)) break; | ||||
| 		advance(); | ||||
| 	} | ||||
|  | ||||
| 	lastword = 1; | ||||
| 	lastdol = 0; | ||||
| 	if(w!=0) | ||||
| 		*w='\0'; | ||||
| 	t = klook(tok); | ||||
| 	if(t->type!=WORD) | ||||
| 		lastword = 0; | ||||
| 	t->quoted = 0; | ||||
| 	yylval.tree = t; | ||||
| 	return t->type; | ||||
| } | ||||
							
								
								
									
										38
									
								
								cmd/rc/mkfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								cmd/rc/mkfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| <$PLAN9/src/mkhdr | ||||
|  | ||||
| TARG=rc | ||||
|  | ||||
| OFILES=\ | ||||
| 	code.$O\ | ||||
| 	exec.$O\ | ||||
| 	getflags.$O\ | ||||
| 	glob.$O\ | ||||
| 	here.$O\ | ||||
| 	io.$O\ | ||||
| 	lex.$O\ | ||||
| 	parse.$O\ | ||||
| 	pcmd.$O\ | ||||
| 	pfnc.$O\ | ||||
| 	simple.$O\ | ||||
| 	subr.$O\ | ||||
| 	trap.$O\ | ||||
| 	tree.$O\ | ||||
| 	unixcrap.$O\ | ||||
| 	var.$O\ | ||||
| 	y.tab.$O\ | ||||
| 	plan9ish.$O\ | ||||
| 	havefork.$O\ | ||||
|  | ||||
| HFILES=\ | ||||
| 	rc.h\ | ||||
| 	x.tab.h\ | ||||
| 	io.h\ | ||||
| 	exec.h\ | ||||
| 	fns.h\ | ||||
|  | ||||
| YFILES=syn.y | ||||
|  | ||||
| <$PLAN9/src/mkone | ||||
|  | ||||
| x.tab.h: y.tab.h | ||||
| 	cmp -s x.tab.h y.tab.h || cp y.tab.h x.tab.h | ||||
							
								
								
									
										552
									
								
								cmd/rc/parse.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										552
									
								
								cmd/rc/parse.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,552 @@ | ||||
| #include "rc.h" | ||||
| #include "io.h" | ||||
| #include "fns.h" | ||||
|  | ||||
| static tree*	body(int tok, int *ptok); | ||||
| static tree*	brace(int tok); | ||||
| static tree*	cmd(int tok, int *ptok); | ||||
| static tree*	cmd2(int tok, int *ptok); | ||||
| static tree*	cmd3(int tok, int *ptok); | ||||
| static tree*	cmds(int tok, int *ptok, int nlok); | ||||
| static tree*	epilog(int tok, int *ptok); | ||||
| static int	iswordtok(int tok); | ||||
| static tree*	line(int tok, int *ptok); | ||||
| static tree*	paren(int tok); | ||||
| static tree*	yyredir(int tok, int *ptok); | ||||
| static tree*	yyword(int tok, int *ptok, int eqok); | ||||
| static tree*	word1(int tok, int *ptok); | ||||
| static tree*	words(int tok, int *ptok); | ||||
|  | ||||
| static jmp_buf yyjmp; | ||||
|  | ||||
| static int | ||||
| dropnl(int tok) | ||||
| { | ||||
| 	while(tok == ' ' || tok == '\n') | ||||
| 		tok = yylex(); | ||||
| 	return tok; | ||||
| } | ||||
|  | ||||
| static int | ||||
| dropsp(int tok) | ||||
| { | ||||
| 	while(tok == ' ') | ||||
| 		tok = yylex(); | ||||
| 	return tok; | ||||
| } | ||||
|  | ||||
| static void | ||||
| syntax(int tok) | ||||
| { | ||||
| 	USED(tok); | ||||
| 	yyerror("syntax error"); | ||||
| 	longjmp(yyjmp, 1); | ||||
| } | ||||
|  | ||||
| int | ||||
| parse(void) | ||||
| { | ||||
| 	tree *t; | ||||
| 	int tok; | ||||
|  | ||||
| 	if(setjmp(yyjmp)) | ||||
| 		return 1; | ||||
|  | ||||
| 	// rc:				{ return 1;} | ||||
| 	// |	line '\n'		{return !compile($1);} | ||||
|  | ||||
| 	tok = dropsp(yylex()); | ||||
| 	if(tok == EOF) | ||||
| 		return 1; | ||||
| 	t = line(tok, &tok); | ||||
| 	if(tok != '\n') | ||||
| 		yyerror("missing newline at end of line"); | ||||
| 	yylval.tree = t; | ||||
| 	return !compile(t); | ||||
| } | ||||
|  | ||||
| static tree* | ||||
| line(int tok, int *ptok) | ||||
| { | ||||
| 	return cmds(tok, ptok, 0); | ||||
| } | ||||
|  | ||||
| static tree* | ||||
| body(int tok, int *ptok) | ||||
| { | ||||
| 	return cmds(tok, ptok, 1); | ||||
| } | ||||
|  | ||||
| static tree* | ||||
| cmds(int tok, int *ptok, int nlok) | ||||
| { | ||||
| 	tree *t, **last, *t2; | ||||
|  | ||||
| 	// line:	cmd | ||||
| 	// |	cmdsa line		{$$=tree2(';', $1, $2);} | ||||
| 	// cmdsa:	cmd ';' | ||||
| 	// |	cmd '&'			{$$=tree1('&', $1);} | ||||
|  | ||||
| 	// body:	cmd | ||||
| 	// |	cmdsan body		{$$=tree2(';', $1, $2);} | ||||
| 	// cmdsan:	cmdsa | ||||
| 	// |	cmd '\n' | ||||
|  | ||||
| 	t = nil; | ||||
| 	last = nil; | ||||
| 	for(;;) { | ||||
| 		t2 = cmd(tok, &tok); | ||||
| 		if(tok == '&') | ||||
| 			t2 = tree1('&', t2); | ||||
| 		if(t2 != nil) { | ||||
| 			// slot into list t | ||||
| 			if(last == nil) { | ||||
| 				t = t2; | ||||
| 				last = &t; | ||||
| 			} else { | ||||
| 				*last = tree2(';', *last, t2); | ||||
| 				last = &(*last)->child[1]; | ||||
| 			} | ||||
| 		} | ||||
| 		if(tok != ';' && tok != '&' && (!nlok || tok != '\n')) | ||||
| 			break; | ||||
| 		tok = yylex(); | ||||
| 	} | ||||
| 	*ptok = tok; | ||||
| 	return t; | ||||
| } | ||||
|  | ||||
| static tree* | ||||
| brace(int tok) | ||||
| { | ||||
| 	tree *t; | ||||
|  | ||||
| 	// brace:	'{' body '}'		{$$=tree1(BRACE, $2);} | ||||
|  | ||||
| 	tok = dropsp(tok); | ||||
| 	if(tok != '{') | ||||
| 		syntax(tok); | ||||
| 	t = body(yylex(), &tok); | ||||
| 	if(tok != '}') | ||||
| 		syntax(tok); | ||||
| 	return tree1(BRACE, t); | ||||
| } | ||||
|  | ||||
| static tree* | ||||
| paren(int tok) | ||||
| { | ||||
| 	tree *t; | ||||
|  | ||||
| 	// paren:	'(' body ')'		{$$=tree1(PCMD, $2);} | ||||
|  | ||||
| 	tok = dropsp(tok); | ||||
| 	if(tok != '(') | ||||
| 		syntax(tok); | ||||
| 	t = body(yylex(), &tok); | ||||
| 	if(tok != ')') | ||||
| 		syntax(tok); | ||||
| 	return tree1(PCMD, t); | ||||
| } | ||||
|  | ||||
| static tree* | ||||
| epilog(int tok, int *ptok) | ||||
| { | ||||
| 	tree *t, *r; | ||||
|  | ||||
| 	// epilog:				{$$=0;} | ||||
| 	// |	redir epilog		{$$=mung2($1, $1->child[0], $2);} | ||||
|  | ||||
| 	if(tok != REDIR && tok != DUP) { | ||||
| 		*ptok = tok; | ||||
| 		return nil; | ||||
| 	} | ||||
|  | ||||
| 	r = yyredir(tok, &tok); | ||||
| 	t = epilog(tok, &tok); | ||||
| 	*ptok = tok; | ||||
| 	return mung2(r, r->child[0], t); | ||||
| } | ||||
|  | ||||
| static tree* | ||||
| yyredir(int tok, int *ptok) | ||||
| { | ||||
| 	tree *r, *w; | ||||
|  | ||||
| 	// redir:	REDIR word		{$$=mung1($1, $1->rtype==HERE?heredoc($2):$2);} | ||||
| 	// |	DUP | ||||
|  | ||||
| 	switch(tok) { | ||||
| 	default: | ||||
| 		syntax(tok); | ||||
| 	case DUP: | ||||
| 		r = yylval.tree; | ||||
| 		*ptok = dropsp(yylex()); | ||||
| 		break; | ||||
| 	case REDIR: | ||||
| 		r = yylval.tree; | ||||
| 		w = yyword(yylex(), &tok, 1); | ||||
| 		*ptok = dropsp(tok); | ||||
| 		r = mung1(r, r->rtype==HERE?heredoc(w):w); | ||||
| 		break; | ||||
| 	} | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| static tree* | ||||
| cmd(int tok, int *ptok) | ||||
| { | ||||
| 	int op; | ||||
| 	tree *t1, *t2; | ||||
|  | ||||
| 	// |	cmd ANDAND cmd		{$$=tree2(ANDAND, $1, $3);} | ||||
| 	// |	cmd OROR cmd		{$$=tree2(OROR, $1, $3);} | ||||
|  | ||||
| 	tok = dropsp(tok); | ||||
| 	t1 = cmd2(tok, &tok); | ||||
| 	while(tok == ANDAND || tok == OROR) { | ||||
| 		op = tok; | ||||
| 		t2 = cmd2(dropnl(yylex()), &tok); | ||||
| 		t1 = tree2(op, t1, t2); | ||||
| 	} | ||||
| 	*ptok = tok; | ||||
| 	return t1; | ||||
| } | ||||
|  | ||||
| static tree* | ||||
| cmd2(int tok, int *ptok) | ||||
| { | ||||
| 	tree *t1, *t2, *t3; | ||||
|  | ||||
| 	// |	cmd PIPE cmd		{$$=mung2($2, $1, $3);} | ||||
| 	t1 = cmd3(tok, &tok); | ||||
| 	while(tok == PIPE) { | ||||
| 		t2 = yylval.tree; | ||||
| 		t3 = cmd3(dropnl(yylex()), &tok); | ||||
| 		t1 = mung2(t2, t1, t3); | ||||
| 	} | ||||
| 	*ptok = tok; | ||||
| 	return t1; | ||||
| } | ||||
|  | ||||
| static tree* | ||||
| cmd3(int tok, int *ptok) | ||||
| { | ||||
| 	tree *t1, *t2, *t3, *t4; | ||||
|  | ||||
| 	tok = dropsp(tok); | ||||
| 	switch(tok) { | ||||
| 	case ';': | ||||
| 	case '&': | ||||
| 	case '\n': | ||||
| 		*ptok = tok; | ||||
| 		return nil; | ||||
|  | ||||
| 	case IF: | ||||
| 		// |	IF paren {skipnl();} cmd	{$$=mung2($1, $2, $4);} | ||||
| 		// |	IF NOT {skipnl();} cmd	{$$=mung1($2, $4);} | ||||
| 		t1 = yylval.tree; | ||||
| 		tok = dropsp(yylex()); | ||||
| 		if(tok == NOT) { | ||||
| 			t1 = yylval.tree; | ||||
| 			t2 = cmd(dropnl(yylex()), ptok); | ||||
| 			return mung1(t1, t2); | ||||
| 		} | ||||
| 		t2 = paren(tok); | ||||
| 		t3 = cmd(dropnl(yylex()), ptok); | ||||
| 		return mung2(t1, t2, t3); | ||||
|  | ||||
| 	case FOR: | ||||
| 		// |	FOR '(' word IN words ')' {skipnl();} cmd | ||||
| 		//		{$$=mung3($1, $3, $5 ? $5 : tree1(PAREN, $5), $8);} | ||||
| 		// |	FOR '(' word ')' {skipnl();} cmd | ||||
| 		//		{$$=mung3($1, $3, (tree *)0, $6);} | ||||
| 		t1 = yylval.tree; | ||||
| 		tok = dropsp(yylex()); | ||||
| 		if(tok != '(') | ||||
| 			syntax(tok); | ||||
| 		t2 = yyword(yylex(), &tok, 1); | ||||
| 		switch(tok) { | ||||
| 		default: | ||||
| 			syntax(tok); | ||||
| 		case ')': | ||||
| 			t3 = nil; | ||||
| 			break; | ||||
| 		case IN: | ||||
| 			t3 = words(yylex(), &tok); | ||||
| 			if(t3 == nil) | ||||
| 				t3 = tree1(PAREN, nil); | ||||
| 			if(tok != ')') | ||||
| 				syntax(tok); | ||||
| 			break; | ||||
| 		} | ||||
| 		t4 = cmd(dropnl(yylex()), ptok); | ||||
| 		return mung3(t1, t2, t3, t4); | ||||
|  | ||||
| 	case WHILE: | ||||
| 		// |	WHILE paren {skipnl();} cmd | ||||
| 		//		{$$=mung2($1, $2, $4);} | ||||
| 		t1 = yylval.tree; | ||||
| 		t2 = paren(yylex()); | ||||
| 		t3 = cmd(dropnl(yylex()), ptok); | ||||
| 		return mung2(t1, t2, t3); | ||||
|  | ||||
| 	case SWITCH: | ||||
| 		// |	SWITCH word {skipnl();} brace | ||||
| 		//		{$$=tree2(SWITCH, $2, $4);} | ||||
| 		t1 = yyword(yylex(), &tok, 1); | ||||
| 		tok = dropnl(tok); // doesn't work in yacc grammar but works here! | ||||
| 		t2 = brace(tok); | ||||
| 		*ptok = dropsp(yylex()); | ||||
| 		return tree2(SWITCH, t1, t2); | ||||
| 		// Note: cmd: a && for(x) y && b is a && {for (x) {y && b}}. | ||||
| 		return cmd(tok, ptok); | ||||
|  | ||||
| 	case FN: | ||||
| 		// |	FN words brace		{$$=tree2(FN, $2, $3);} | ||||
| 		// |	FN words		{$$=tree1(FN, $2);} | ||||
| 		t1 = words(yylex(), &tok); | ||||
| 		if(tok != '{') { | ||||
| 			*ptok = tok; | ||||
| 			return tree1(FN, t1); | ||||
| 		} | ||||
| 		t2 = brace(tok); | ||||
| 		*ptok = dropsp(yylex()); | ||||
| 		return tree2(FN, t1, t2); | ||||
|  | ||||
| 	case TWIDDLE: | ||||
| 		// |	TWIDDLE word words	{$$=mung2($1, $2, $3);} | ||||
| 		t1 = yylval.tree; | ||||
| 		t2 = yyword(yylex(), &tok, 1); | ||||
| 		t3 = words(tok, ptok); | ||||
| 		return mung2(t1, t2, t3); | ||||
|  | ||||
| 	case BANG: | ||||
| 	case SUBSHELL: | ||||
| 		// |	BANG cmd		{$$=mung1($1, $2);} | ||||
| 		// |	SUBSHELL cmd		{$$=mung1($1, $2);} | ||||
| 		// Note: cmd2: ! x | y is !{x | y} not {!x} | y. | ||||
| 		t1 = yylval.tree; | ||||
| 		return mung1(t1, cmd2(yylex(), ptok)); | ||||
|  | ||||
| 	case REDIR: | ||||
| 	case DUP: | ||||
| 		// |	redir cmd  %prec BANG	{$$=mung2($1, $1->child[0], $2);} | ||||
| 		// Note: cmd2: {>x echo a | tr a-z A-Z} writes A to x. | ||||
| 		t1 = yyredir(tok, &tok); | ||||
| 		t2 = cmd2(tok, ptok); | ||||
| 		return mung2(t1, t1->child[0], t2); | ||||
|  | ||||
| 	case '{': | ||||
| 		// |	brace epilog		{$$=epimung($1, $2);} | ||||
| 		t1 = brace(tok); | ||||
| 		tok = dropsp(yylex()); | ||||
| 		t2 = epilog(tok, ptok); | ||||
| 		return epimung(t1, t2); | ||||
| 	} | ||||
|  | ||||
| 	if(!iswordtok(tok)) { | ||||
| 		*ptok = tok; | ||||
| 		return nil; | ||||
| 	} | ||||
|  | ||||
| 	// cmd: ... | ||||
| 	// |	simple			{$$=simplemung($1);} | ||||
| 	// |	assign cmd %prec BANG	{$$=mung3($1, $1->child[0], $1->child[1], $2);} | ||||
| 	// assign:	first '=' word		{$$=tree2('=', $1, $3);} | ||||
| 	// Note: first is same as word except for disallowing all the leading keywords, | ||||
| 	// but all those keywords have been picked off in the switch above. | ||||
| 	// Except NOT, but disallowing that in yacc was likely a mistake anyway: | ||||
| 	// there's no ambiguity in not=1 or not x y z. | ||||
| 	t1 = yyword(tok, &tok, 0); | ||||
| 	if(tok == '=') { | ||||
| 		// assignment | ||||
| 		// Note: cmd2: {x=1 true | echo $x} echoes 1. | ||||
| 		t1 = tree2('=', t1, yyword(yylex(), &tok, 1)); | ||||
| 		t2 = cmd2(tok, ptok); | ||||
| 		return mung3(t1, t1->child[0], t1->child[1], t2); | ||||
| 	} | ||||
|  | ||||
| 	// simple:	first | ||||
| 	// |	simple word		{$$=tree2(ARGLIST, $1, $2);} | ||||
| 	// |	simple redir		{$$=tree2(ARGLIST, $1, $2);} | ||||
| 	for(;;) { | ||||
| 		if(tok == REDIR || tok == DUP) { | ||||
| 			t1 = tree2(ARGLIST, t1, yyredir(tok, &tok)); | ||||
| 		} else if(iswordtok(tok)) { | ||||
| 			t1 = tree2(ARGLIST, t1, yyword(tok, &tok, 1)); | ||||
| 		} else { | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	*ptok = tok; | ||||
| 	return simplemung(t1); | ||||
| } | ||||
|  | ||||
| static tree* | ||||
| words(int tok, int *ptok) | ||||
| { | ||||
| 	tree *t; | ||||
|  | ||||
| 	// words:				{$$=(tree*)0;} | ||||
| 	// |	words word		{$$=tree2(WORDS, $1, $2);} | ||||
|  | ||||
| 	t = nil; | ||||
| 	tok = dropsp(tok); | ||||
| 	while(iswordtok(tok)) | ||||
| 		t = tree2(WORDS, t, yyword(tok, &tok, 1)); | ||||
| 	*ptok = tok; | ||||
| 	return t; | ||||
| } | ||||
|  | ||||
| static tree* | ||||
| yyword(int tok, int *ptok, int eqok) | ||||
| { | ||||
| 	tree *t; | ||||
|  | ||||
| 	// word:	keyword			{lastword=1; $1->type=WORD;} | ||||
| 	// |	comword | ||||
| 	// |	word '^' word		{$$=tree2('^', $1, $3);} | ||||
| 	// comword: '$' word		{$$=tree1('$', $2);} | ||||
| 	// |	'$' word SUB words ')'	{$$=tree2(SUB, $2, $4);} | ||||
| 	// |	'"' word		{$$=tree1('"', $2);} | ||||
| 	// |	COUNT word		{$$=tree1(COUNT, $2);} | ||||
| 	// |	WORD | ||||
| 	// |	'`' brace		{$$=tree1('`', $2);} | ||||
| 	// |	'(' words ')'		{$$=tree1(PAREN, $2);} | ||||
| 	// |	REDIR brace		{$$=mung1($1, $2); $$->type=PIPEFD;} | ||||
| 	// keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN | ||||
| 	// | ||||
| 	// factored into: | ||||
| 	// | ||||
| 	// word: word1 | ||||
| 	// | word '^' word1 | ||||
| 	// | ||||
| 	// word1: keyword | comword | ||||
|  | ||||
| 	t = word1(tok, &tok); | ||||
| 	if(tok == '=' && !eqok) | ||||
| 		goto out; | ||||
| 	for(;;) { | ||||
| 		if(iswordtok(tok)) { | ||||
| 			// No free carats around parens. | ||||
| 			if(t->type == PAREN || tok == '(') | ||||
| 				syntax(tok); | ||||
| 			t = tree2('^', t, word1(tok, &tok)); | ||||
| 			continue; | ||||
| 		} | ||||
| 		tok = dropsp(tok); | ||||
| 		if(tok == '^') { | ||||
| 			t = tree2('^', t, word1(yylex(), &tok)); | ||||
| 			continue; | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
| out: | ||||
| 	*ptok = dropsp(tok); | ||||
| 	return t; | ||||
| } | ||||
|  | ||||
| static tree* | ||||
| word1(int tok, int *ptok) | ||||
| { | ||||
| 	tree *w, *sub, *t; | ||||
|  | ||||
| 	tok = dropsp(tok); | ||||
| 	switch(tok) { | ||||
| 	default: | ||||
| 		syntax(tok); | ||||
|  | ||||
| 	case WORD: | ||||
| 	case FOR: | ||||
| 	case IN: | ||||
| 	case WHILE: | ||||
| 	case IF: | ||||
| 	case NOT: | ||||
| 	case TWIDDLE: | ||||
| 	case BANG: | ||||
| 	case SUBSHELL: | ||||
| 	case SWITCH: | ||||
| 	case FN: | ||||
| 		// |	WORD | ||||
| 		// keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN | ||||
| 		t = yylval.tree; | ||||
| 		t->type = WORD; | ||||
| 		*ptok = yylex(); | ||||
| 		return t; | ||||
|  | ||||
| 	case '=': | ||||
| 		*ptok = yylex(); | ||||
| 		return token("=", WORD); | ||||
|  | ||||
| 	case '$': | ||||
| 		// comword: '$' word1		{$$=tree1('$', $2);} | ||||
| 		// |	'$' word1 SUB words ')'	{$$=tree2(SUB, $2, $4);} | ||||
| 		w = word1(yylex(), &tok); | ||||
| 		if(tok == '(') { | ||||
| 			sub = words(yylex(), &tok); | ||||
| 			if(tok != ')') | ||||
| 				syntax(tok); | ||||
| 			*ptok = yylex(); | ||||
| 			return tree2(SUB, w, sub); | ||||
| 		} | ||||
| 		*ptok = tok; | ||||
| 		return tree1('$', w); | ||||
|  | ||||
| 	case '"': | ||||
| 		// |	'"' word1		{$$=tree1('"', $2);} | ||||
| 		return tree1('"', word1(yylex(), ptok)); | ||||
|  | ||||
| 	case COUNT: | ||||
| 		// |	COUNT word1		{$$=tree1(COUNT, $2);} | ||||
| 		return tree1(COUNT, word1(yylex(), ptok)); | ||||
|  | ||||
| 	case '`': | ||||
| 		// |	'`' brace		{$$=tree1('`', $2);} | ||||
| 		t = tree1('`', brace(yylex())); | ||||
| 		*ptok = yylex(); | ||||
| 		return t; | ||||
|  | ||||
| 	case '(': | ||||
| 		// |	'(' words ')'		{$$=tree1(PAREN, $2);} | ||||
| 		t = tree1(PAREN, words(yylex(), &tok)); | ||||
| 		if(tok != ')') | ||||
| 			syntax(tok); | ||||
| 		*ptok = yylex(); | ||||
| 		return t; | ||||
|  | ||||
| 	case REDIRW: | ||||
| 		// |	REDIRW brace		{$$=mung1($1, $2); $$->type=PIPEFD;} | ||||
| 		t = yylval.tree; | ||||
| 		t = mung1(t, brace(yylex())); | ||||
| 		t->type = PIPEFD; | ||||
| 		*ptok = yylex(); | ||||
| 		return t; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int | ||||
| iswordtok(int tok) | ||||
| { | ||||
| 	switch(tok) { | ||||
| 	case FOR: | ||||
| 	case IN: | ||||
| 	case WHILE: | ||||
| 	case IF: | ||||
| 	case NOT: | ||||
| 	case TWIDDLE: | ||||
| 	case BANG: | ||||
| 	case SUBSHELL: | ||||
| 	case SWITCH: | ||||
| 	case FN: | ||||
| 	case '$': | ||||
| 	case '"': | ||||
| 	case COUNT: | ||||
| 	case WORD: | ||||
| 	case '`': | ||||
| 	case '(': | ||||
| 	case REDIRW: | ||||
| 	case '=': | ||||
| 		return 1; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										265
									
								
								cmd/rc/pcmd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								cmd/rc/pcmd.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,265 @@ | ||||
| #include "rc.h" | ||||
| #include "io.h" | ||||
| #include "fns.h" | ||||
| char nl='\n';		/* change to semicolon for bourne-proofing */ | ||||
| #define	c0	t->child[0] | ||||
| #define	c1	t->child[1] | ||||
| #define	c2	t->child[2] | ||||
|  | ||||
| void | ||||
| pdeglob(io *f, char *s) | ||||
| { | ||||
| 	while(*s){ | ||||
| 		if(*s==GLOB) | ||||
| 			s++; | ||||
| 		pchr(f, *s++); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void | ||||
| pcmd(io *f, tree *t) | ||||
| { | ||||
| 	if(t==0) | ||||
| 		return; | ||||
| 	switch(t->type){ | ||||
| 	default:	pfmt(f, "bad %d %p %p %p", t->type, c0, c1, c2); | ||||
| 	break; | ||||
| 	case '$':	pfmt(f, "$%t", c0); | ||||
| 	break; | ||||
| 	case '"':	pfmt(f, "$\"%t", c0); | ||||
| 	break; | ||||
| 	case '&':	pfmt(f, "%t&", c0); | ||||
| 	break; | ||||
| 	case '^':	pfmt(f, "%t^%t", c0, c1); | ||||
| 	break; | ||||
| 	case '`':	pfmt(f, "`%t", c0); | ||||
| 	break; | ||||
| 	case ANDAND:	pfmt(f, "%t && %t", c0, c1); | ||||
| 	break; | ||||
| 	case BANG:	pfmt(f, "! %t", c0); | ||||
| 	break; | ||||
| 	case BRACE:	pfmt(f, "{%t}", c0); | ||||
| 	break; | ||||
| 	case COUNT:	pfmt(f, "$#%t", c0); | ||||
| 	break; | ||||
| 	case FN:	pfmt(f, "fn %t %t", c0, c1); | ||||
| 	break; | ||||
| 	case IF:	pfmt(f, "if%t%t", c0, c1); | ||||
| 	break; | ||||
| 	case NOT:	pfmt(f, "if not %t", c0); | ||||
| 	break; | ||||
| 	case OROR:	pfmt(f, "%t || %t", c0, c1); | ||||
| 	break; | ||||
| 	case PCMD: | ||||
| 	case PAREN:	pfmt(f, "(%t)", c0); | ||||
| 	break; | ||||
| 	case SUB:	pfmt(f, "$%t(%t)", c0, c1); | ||||
| 	break; | ||||
| 	case SIMPLE:	pfmt(f, "%t", c0); | ||||
| 	break; | ||||
| 	case SUBSHELL:	pfmt(f, "@ %t", c0); | ||||
| 	break; | ||||
| 	case SWITCH:	pfmt(f, "switch %t %t", c0, c1); | ||||
| 	break; | ||||
| 	case TWIDDLE:	pfmt(f, "~ %t %t", c0, c1); | ||||
| 	break; | ||||
| 	case WHILE:	pfmt(f, "while %t%t", c0, c1); | ||||
| 	break; | ||||
| 	case ARGLIST: | ||||
| 		if(c0==0) | ||||
| 			pfmt(f, "%t", c1); | ||||
| 		else if(c1==0) | ||||
| 			pfmt(f, "%t", c0); | ||||
| 		else | ||||
| 			pfmt(f, "%t %t", c0, c1); | ||||
| 		break; | ||||
| 	case ';': | ||||
| 		if(c0){ | ||||
| 			if(c1) | ||||
| 				pfmt(f, "%t%c%t", c0, nl, c1); | ||||
| 			else pfmt(f, "%t", c0); | ||||
| 		} | ||||
| 		else pfmt(f, "%t", c1); | ||||
| 		break; | ||||
| 	case WORDS: | ||||
| 		if(c0) | ||||
| 			pfmt(f, "%t ", c0); | ||||
| 		pfmt(f, "%t", c1); | ||||
| 		break; | ||||
| 	case FOR: | ||||
| 		pfmt(f, "for(%t", c0); | ||||
| 		if(c1) | ||||
| 			pfmt(f, " in %t", c1); | ||||
| 		pfmt(f, ")%t", c2); | ||||
| 		break; | ||||
| 	case WORD: | ||||
| 		if(t->quoted) | ||||
| 			pfmt(f, "%Q", t->str); | ||||
| 		else pdeglob(f, t->str); | ||||
| 		break; | ||||
| 	case DUP: | ||||
| 		if(t->rtype==DUPFD) | ||||
| 			pfmt(f, ">[%d=%d]", t->fd1, t->fd0); /* yes, fd1, then fd0; read lex.c */ | ||||
| 		else | ||||
| 			pfmt(f, ">[%d=]", t->fd0); | ||||
| 		pfmt(f, "%t", c1); | ||||
| 		break; | ||||
| 	case PIPEFD: | ||||
| 	case REDIR: | ||||
| 		switch(t->rtype){ | ||||
| 		case HERE: | ||||
| 			pchr(f, '<'); | ||||
| 		case READ: | ||||
| 		case RDWR: | ||||
| 			pchr(f, '<'); | ||||
| 			if(t->rtype==RDWR) | ||||
| 				pchr(f, '>'); | ||||
| 			if(t->fd0!=0) | ||||
| 				pfmt(f, "[%d]", t->fd0); | ||||
| 			break; | ||||
| 		case APPEND: | ||||
| 			pchr(f, '>'); | ||||
| 		case WRITE: | ||||
| 			pchr(f, '>'); | ||||
| 			if(t->fd0!=1) | ||||
| 				pfmt(f, "[%d]", t->fd0); | ||||
| 			break; | ||||
| 		} | ||||
| 		pfmt(f, "%t", c0); | ||||
| 		if(c1) | ||||
| 			pfmt(f, " %t", c1); | ||||
| 		break; | ||||
| 	case '=': | ||||
| 		pfmt(f, "%t=%t", c0, c1); | ||||
| 		if(c2) | ||||
| 			pfmt(f, " %t", c2); | ||||
| 		break; | ||||
| 	case PIPE: | ||||
| 		pfmt(f, "%t|", c0); | ||||
| 		if(t->fd1==0){ | ||||
| 			if(t->fd0!=1) | ||||
| 				pfmt(f, "[%d]", t->fd0); | ||||
| 		} | ||||
| 		else pfmt(f, "[%d=%d]", t->fd0, t->fd1); | ||||
| 		pfmt(f, "%t", c1); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void | ||||
| pcmdu(io *f, tree *t) /* unambiguous */ | ||||
| { | ||||
| 	if(t==0) { | ||||
| 		pfmt(f, "<nil>"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	switch(t->type){ | ||||
| 	default:	pfmt(f, "(bad %d %p %p %p)", t->type, c0, c1, c2); | ||||
| 	break; | ||||
| 	case '$':	pfmt(f, "($ %u)", c0); | ||||
| 	break; | ||||
| 	case '"':	pfmt(f, "($\" %u)", c0); | ||||
| 	break; | ||||
| 	case '&':	pfmt(f, "(& %u)", c0); | ||||
| 	break; | ||||
| 	case '^':	pfmt(f, "(^ %u %u)", c0, c1); | ||||
| 	break; | ||||
| 	case '`':	pfmt(f, "(` %u)", c0); | ||||
| 	break; | ||||
| 	case ANDAND:	pfmt(f, "(&& %u %u)", c0, c1); | ||||
| 	break; | ||||
| 	case BANG:	pfmt(f, "(! %u)", c0); | ||||
| 	break; | ||||
| 	case BRACE:	pfmt(f, "(brace %u)", c0); | ||||
| 	break; | ||||
| 	case COUNT:	pfmt(f, "($# %u)", c0); | ||||
| 	break; | ||||
| 	case FN:	pfmt(f, "(fn %u %u)", c0, c1); | ||||
| 	break; | ||||
| 	case IF:	pfmt(f, "(if %u %u)", c0, c1); | ||||
| 	break; | ||||
| 	case NOT:	pfmt(f, "(if not %u)", c0); | ||||
| 	break; | ||||
| 	case OROR:	pfmt(f, "(|| %u %u)", c0, c1); | ||||
| 	break; | ||||
| 	case PCMD: | ||||
| 	case PAREN:	pfmt(f, "(paren %u)", c0); | ||||
| 	break; | ||||
| 	case SUB:	pfmt(f, "($sub %u %u)", c0, c1); | ||||
| 	break; | ||||
| 	case SIMPLE:	pfmt(f, "(simple %u)", c0); | ||||
| 	break; | ||||
| 	case SUBSHELL:	pfmt(f, "(@ %u)", c0); | ||||
| 	break; | ||||
| 	case SWITCH:	pfmt(f, "(switch %u %u)", c0, c1); | ||||
| 	break; | ||||
| 	case TWIDDLE:	pfmt(f, "(~ %u %u)", c0, c1); | ||||
| 	break; | ||||
| 	case WHILE:	pfmt(f, "(while %u %u)", c0, c1); | ||||
| 	break; | ||||
| 	case ARGLIST: | ||||
| 		pfmt(f, "(arglist %u %u)", c0, c1); | ||||
| 		break; | ||||
| 	case ';': | ||||
| 		pfmt(f, "(; %u %u)", c0, c1); | ||||
| 		break; | ||||
| 	case WORDS: | ||||
| 		pfmt(f, "(words %u %u)", c0, c1); | ||||
| 		break; | ||||
| 	case FOR: | ||||
| 		pfmt(f, "(for %u %u %u)", c0, c1, c2); | ||||
| 		break; | ||||
| 	case WORD: | ||||
| 		if(t->quoted) | ||||
| 			pfmt(f, "%Q", t->str); | ||||
| 		else pdeglob(f, t->str); | ||||
| 		break; | ||||
| 	case DUP: | ||||
| 		if(t->rtype==DUPFD) | ||||
| 			pfmt(f, "(>[%d=%d]", t->fd1, t->fd0); /* yes, fd1, then fd0; read lex.c */ | ||||
| 		else | ||||
| 			pfmt(f, "(>[%d=]", t->fd0); /*)*/ | ||||
| 		pfmt(f, " %u)", c1); | ||||
| 		break; | ||||
| 	case PIPEFD: | ||||
| 	case REDIR: | ||||
| 		pfmt(f, "("); | ||||
| 		switch(t->rtype){ | ||||
| 		case HERE: | ||||
| 			pchr(f, '<'); | ||||
| 		case READ: | ||||
| 		case RDWR: | ||||
| 			pchr(f, '<'); | ||||
| 			if(t->rtype==RDWR) | ||||
| 				pchr(f, '>'); | ||||
| 			if(t->fd0!=0) | ||||
| 				pfmt(f, "[%d]", t->fd0); | ||||
| 			break; | ||||
| 		case APPEND: | ||||
| 			pchr(f, '>'); | ||||
| 		case WRITE: | ||||
| 			pchr(f, '>'); | ||||
| 			if(t->fd0!=1) | ||||
| 				pfmt(f, "[%d]", t->fd0); | ||||
| 			break; | ||||
| 		} | ||||
| 		if(t->rtype == HERE) | ||||
| 			pfmt(f, "HERE %u)", c1); | ||||
| 		else | ||||
| 			pfmt(f, "%u %u)", c0, c1); | ||||
| 		break; | ||||
| 	case '=': | ||||
| 		pfmt(f, "(%u=%u %u)", c0, c1, c2); | ||||
| 		break; | ||||
| 	case PIPE: | ||||
| 		pfmt(f, "(|"); | ||||
| 		if(t->fd1==0){ | ||||
| 			if(t->fd0!=1) | ||||
| 				pfmt(f, "[%d]", t->fd0); | ||||
| 		} | ||||
| 		else pfmt(f, "[%d=%d]", t->fd0, t->fd1); | ||||
| 		pfmt(f, " %u %u", c0, c1); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										71
									
								
								cmd/rc/pfnc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								cmd/rc/pfnc.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| #include "rc.h" | ||||
| #include "exec.h" | ||||
| #include "io.h" | ||||
| #include "fns.h" | ||||
| struct{ | ||||
| 	void (*f)(void); | ||||
| 	char *name; | ||||
| }fname[] = { | ||||
| 	Xappend, "Xappend", | ||||
| 	Xasync, "Xasync", | ||||
| 	Xbang, "Xbang", | ||||
| 	Xclose, "Xclose", | ||||
| 	Xdup, "Xdup", | ||||
| 	Xeflag, "Xeflag", | ||||
| 	Xexit, "Xexit", | ||||
| 	Xfalse, "Xfalse", | ||||
| 	Xifnot, "Xifnot", | ||||
| 	Xjump, "Xjump", | ||||
| 	Xmark, "Xmark", | ||||
| 	Xpopm, "Xpopm", | ||||
| 	Xrdwr, "Xrdwr", | ||||
| 	Xread, "Xread", | ||||
| 	Xreturn, "Xreturn", | ||||
| 	Xtrue, "Xtrue", | ||||
| 	Xif, "Xif", | ||||
| 	Xwastrue, "Xwastrue", | ||||
| 	Xword, "Xword", | ||||
| 	Xwrite, "Xwrite", | ||||
| 	Xmatch, "Xmatch", | ||||
| 	Xcase, "Xcase", | ||||
| 	Xconc, "Xconc", | ||||
| 	Xassign, "Xassign", | ||||
| 	Xdol, "Xdol", | ||||
| 	Xcount, "Xcount", | ||||
| 	Xlocal, "Xlocal", | ||||
| 	Xunlocal, "Xunlocal", | ||||
| 	Xfn, "Xfn", | ||||
| 	Xdelfn, "Xdelfn", | ||||
| 	Xpipe, "Xpipe", | ||||
| 	Xpipewait, "Xpipewait", | ||||
| 	Xrdcmds, "Xrdcmds", | ||||
| 	(void (*)(void))Xerror, "Xerror", | ||||
| 	Xbackq, "Xbackq", | ||||
| 	Xpipefd, "Xpipefd", | ||||
| 	Xsubshell, "Xsubshell", | ||||
| 	Xdelhere, "Xdelhere", | ||||
| 	Xfor, "Xfor", | ||||
| 	Xglob, "Xglob", | ||||
| 	Xrdfn, "Xrdfn", | ||||
| 	Xsimple, "Xsimple", | ||||
| 	Xrdfn, "Xrdfn", | ||||
| 	Xqdol, "Xqdol", | ||||
| 0}; | ||||
|  | ||||
| void | ||||
| pfnc(io *fd, thread *t) | ||||
| { | ||||
| 	int i; | ||||
| 	void (*fn)(void) = t->code[t->pc].f; | ||||
| 	list *a; | ||||
| 	pfmt(fd, "pid %d cycle %p %d ", getpid(), t->code, t->pc); | ||||
| 	for(i = 0;fname[i].f;i++) if(fname[i].f==fn){ | ||||
| 		pstr(fd, fname[i].name); | ||||
| 		break; | ||||
| 	} | ||||
| 	if(!fname[i].f) | ||||
| 		pfmt(fd, "%p", fn); | ||||
| 	for(a = t->argv;a;a = a->next) pfmt(fd, " (%v)", a->words); | ||||
| 	pchr(fd, '\n'); | ||||
| 	flush(fd); | ||||
| } | ||||
							
								
								
									
										604
									
								
								cmd/rc/plan9ish.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										604
									
								
								cmd/rc/plan9ish.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,604 @@ | ||||
| /* | ||||
|  * Plan 9 versions of system-specific functions | ||||
|  *	By convention, exported routines herein have names beginning with an | ||||
|  *	upper case letter. | ||||
|  */ | ||||
| #include "rc.h" | ||||
| #include "exec.h" | ||||
| #include "io.h" | ||||
| #include "fns.h" | ||||
| #include "getflags.h" | ||||
| char *Signame[]={ | ||||
| 	"sigexit",	"sighup",	"sigint",	"sigquit", | ||||
| 	"sigalrm",	"sigkill",	"sigfpe",	"sigterm", | ||||
| 	0 | ||||
| }; | ||||
| char *syssigname[]={ | ||||
| 	"exit",		/* can't happen */ | ||||
| 	"hangup", | ||||
| 	"interrupt", | ||||
| 	"quit",		/* can't happen */ | ||||
| 	"alarm", | ||||
| 	"kill", | ||||
| 	"sys: fp: ", | ||||
| 	"term", | ||||
| 	0 | ||||
| }; | ||||
| char* | ||||
| Rcmain(void) | ||||
| { | ||||
| 	return unsharp("#9/rcmain"); | ||||
| } | ||||
|  | ||||
| char Fdprefix[]="/dev/fd/"; | ||||
| long readnb(int, char *, long); | ||||
| void execfinit(void); | ||||
| void execbind(void); | ||||
| void execmount(void); | ||||
| void execulimit(void); | ||||
| void execumask(void); | ||||
| void execrfork(void); | ||||
| builtin Builtin[]={ | ||||
| 	"cd",		execcd, | ||||
| 	"whatis",	execwhatis, | ||||
| 	"eval",		execeval, | ||||
| 	"exec",		execexec,	/* but with popword first */ | ||||
| 	"exit",		execexit, | ||||
| 	"shift",	execshift, | ||||
| 	"wait",		execwait, | ||||
| 	".",		execdot, | ||||
| 	"finit",	execfinit, | ||||
| 	"flag",		execflag, | ||||
| 	"ulimit",	execulimit, | ||||
| 	"umask",	execumask, | ||||
| 	"rfork",	execrfork, | ||||
| 	0 | ||||
| }; | ||||
|  | ||||
| void | ||||
| execrfork(void) | ||||
| { | ||||
| 	int arg; | ||||
| 	char *s; | ||||
|  | ||||
| 	switch(count(runq->argv->words)){ | ||||
| 	case 1: | ||||
| 		arg = RFENVG|RFNOTEG|RFNAMEG; | ||||
| 		break; | ||||
| 	case 2: | ||||
| 		arg = 0; | ||||
| 		for(s = runq->argv->words->next->word;*s;s++) switch(*s){ | ||||
| 		default: | ||||
| 			goto Usage; | ||||
| 		case 'n': | ||||
| 			arg|=RFNAMEG;  break; | ||||
| 		case 'N': | ||||
| 			arg|=RFCNAMEG; | ||||
| 			break; | ||||
| 		case 'e': | ||||
| 			/* arg|=RFENVG; */  break; | ||||
| 		case 'E': | ||||
| 			arg|=RFCENVG;  break; | ||||
| 		case 's': | ||||
| 			arg|=RFNOTEG;  break; | ||||
| 		case 'f': | ||||
| 			arg|=RFFDG;    break; | ||||
| 		case 'F': | ||||
| 			arg|=RFCFDG;   break; | ||||
| 		} | ||||
| 		break; | ||||
| 	default: | ||||
| 	Usage: | ||||
| 		pfmt(err, "Usage: %s [nNeEsfF]\n", runq->argv->words->word); | ||||
| 		setstatus("rfork usage"); | ||||
| 		poplist(); | ||||
| 		return; | ||||
| 	} | ||||
| 	if(rfork(arg)==-1){ | ||||
| 		pfmt(err, "rc: %s failed\n", runq->argv->words->word); | ||||
| 		setstatus("rfork failed"); | ||||
| 	} | ||||
| 	else | ||||
| 		setstatus(""); | ||||
| 	poplist(); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| #define	SEP	'\1' | ||||
| char **environp; | ||||
| struct word *enval(s) | ||||
| register char *s; | ||||
| { | ||||
| 	register char *t, c; | ||||
| 	register struct word *v; | ||||
| 	for(t=s;*t && *t!=SEP;t++); | ||||
| 	c=*t; | ||||
| 	*t='\0'; | ||||
| 	v=newword(s, c=='\0'?(struct word *)0:enval(t+1)); | ||||
| 	*t=c; | ||||
| 	return v; | ||||
| } | ||||
| void Vinit(void){ | ||||
| 	extern char **environ; | ||||
| 	register char *s; | ||||
| 	register char **env=environ; | ||||
| 	environp=env; | ||||
| 	for(;*env;env++){ | ||||
| 		for(s=*env;*s && *s!='(' && *s!='=';s++); | ||||
| 		switch(*s){ | ||||
| 		case '\0': | ||||
| 		/*	pfmt(err, "rc: odd environment %q?\n", *env); */ | ||||
| 			break; | ||||
| 		case '=': | ||||
| 			*s='\0'; | ||||
| 			setvar(*env, enval(s+1)); | ||||
| 			*s='='; | ||||
| 			break; | ||||
| 		case '(':	/* ignore functions for now */ | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| char **envp; | ||||
| void Xrdfn(void){ | ||||
| 	char *p; | ||||
| 	register char *s; | ||||
| 	register int len; | ||||
| 	for(;*envp;envp++){ | ||||
| 		s = *envp; | ||||
| 		if(strncmp(s, "fn#", 3) == 0){ | ||||
| 			p = strchr(s, '='); | ||||
| 			if(p == nil) | ||||
| 				continue; | ||||
| 			*p = ' '; | ||||
| 			s[2] = ' '; | ||||
| 			len = strlen(s); | ||||
| 			execcmds(opencore(s, len)); | ||||
| 			s[len] = '\0'; | ||||
| 			return; | ||||
| 		} | ||||
| #if 0 | ||||
| 		for(s=*envp;*s && *s!='(' && *s!='=';s++); | ||||
| 		switch(*s){ | ||||
| 		case '\0': | ||||
| 			pfmt(err, "environment %q?\n", *envp); | ||||
| 			break; | ||||
| 		case '=':	/* ignore variables */ | ||||
| 			break; | ||||
| 		case '(':		/* Bourne again */ | ||||
| 			s=*envp+3; | ||||
| 			envp++; | ||||
| 			len=strlen(s); | ||||
| 			s[len]='\n'; | ||||
| 			execcmds(opencore(s, len+1)); | ||||
| 			s[len]='\0'; | ||||
| 			return; | ||||
| 		} | ||||
| #endif | ||||
| 	} | ||||
| 	Xreturn(); | ||||
| } | ||||
| union code rdfns[4]; | ||||
| void execfinit(void){ | ||||
| 	static int first=1; | ||||
| 	if(first){ | ||||
| 		rdfns[0].i=1; | ||||
| 		rdfns[1].f=Xrdfn; | ||||
| 		rdfns[2].f=Xjump; | ||||
| 		rdfns[3].i=1; | ||||
| 		first=0; | ||||
| 	} | ||||
| 	Xpopm(); | ||||
| 	envp=environp; | ||||
| 	start(rdfns, 1, runq->local); | ||||
| } | ||||
| extern int mapfd(int); | ||||
| int Waitfor(int pid, int unused0){ | ||||
| 	thread *p; | ||||
| 	Waitmsg *w; | ||||
| 	char errbuf[ERRMAX]; | ||||
|  | ||||
| 	if(pid >= 0 && !havewaitpid(pid)) | ||||
| 		return 0; | ||||
| 	while((w = wait()) != nil){ | ||||
| 		delwaitpid(w->pid); | ||||
| 		if(w->pid==pid){ | ||||
| 			if(strncmp(w->msg, "signal: ", 8) == 0) | ||||
| 				fprint(mapfd(2), "%d: %s\n", w->pid, w->msg); | ||||
| 			setstatus(w->msg); | ||||
| 			free(w); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		if(runq->iflag && strncmp(w->msg, "signal: ", 8) == 0) | ||||
| 			fprint(2, "%d: %s\n", w->pid, w->msg); | ||||
| 		for(p=runq->ret;p;p=p->ret) | ||||
| 			if(p->pid==w->pid){ | ||||
| 				p->pid=-1; | ||||
| 				strcpy(p->status, w->msg); | ||||
| 			} | ||||
| 		free(w); | ||||
| 	} | ||||
|  | ||||
| 	rerrstr(errbuf, sizeof errbuf); | ||||
| 	if(strcmp(errbuf, "interrupted")==0) return -1; | ||||
| 	return 0; | ||||
| } | ||||
| char **mkargv(word *a) | ||||
| { | ||||
| 	char **argv=(char **)emalloc((count(a)+2)*sizeof(char *)); | ||||
| 	char **argp=argv+1;	/* leave one at front for runcoms */ | ||||
| 	for(;a;a=a->next) *argp++=a->word; | ||||
| 	*argp=0; | ||||
| 	return argv; | ||||
| } | ||||
| /* | ||||
| void addenv(var *v) | ||||
| { | ||||
| 	char envname[256]; | ||||
| 	word *w; | ||||
| 	int f; | ||||
| 	io *fd; | ||||
| 	if(v->changed){ | ||||
| 		v->changed=0; | ||||
| 		snprint(envname, sizeof envname, "/env/%s", v->name); | ||||
| 		if((f=Creat(envname))<0) | ||||
| 			pfmt(err, "rc: can't open %s: %r\n", envname); | ||||
| 		else{ | ||||
| 			for(w=v->val;w;w=w->next) | ||||
| 				write(f, w->word, strlen(w->word)+1L); | ||||
| 			close(f); | ||||
| 		} | ||||
| 	} | ||||
| 	if(v->fnchanged){ | ||||
| 		v->fnchanged=0; | ||||
| 		snprint(envname, sizeof envname, "/env/fn#%s", v->name); | ||||
| 		if((f=Creat(envname))<0) | ||||
| 			pfmt(err, "rc: can't open %s: %r\n", envname); | ||||
| 		else{ | ||||
| 			if(v->fn){ | ||||
| 				fd=openfd(f); | ||||
| 				pfmt(fd, "fn %s %s\n", v->name, v->fn[v->pc-1].s); | ||||
| 				closeio(fd); | ||||
| 			} | ||||
| 			close(f); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| void updenvlocal(var *v) | ||||
| { | ||||
| 	if(v){ | ||||
| 		updenvlocal(v->next); | ||||
| 		addenv(v); | ||||
| 	} | ||||
| } | ||||
| void Updenv(void){ | ||||
| 	var *v, **h; | ||||
| 	for(h=gvar;h!=&gvar[NVAR];h++) | ||||
| 		for(v=*h;v;v=v->next) | ||||
| 			addenv(v); | ||||
| 	if(runq) updenvlocal(runq->local); | ||||
| } | ||||
| */ | ||||
| int | ||||
| cmpenv(const void *a, const void *b) | ||||
| { | ||||
| 	return strcmp(*(char**)a, *(char**)b); | ||||
| } | ||||
| char **mkenv(){ | ||||
| 	register char **env, **ep, *p, *q; | ||||
| 	register struct var **h, *v; | ||||
| 	register struct word *a; | ||||
| 	register int nvar=0, nchr=0, sep; | ||||
| 	/* | ||||
| 	 * Slightly kludgy loops look at locals then globals | ||||
| 	 */ | ||||
| 	for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){ | ||||
| 		if((v==vlook(v->name)) && v->val){ | ||||
| 			nvar++; | ||||
| 			nchr+=strlen(v->name)+1; | ||||
| 			for(a=v->val;a;a=a->next) | ||||
| 				nchr+=strlen(a->word)+1; | ||||
| 		} | ||||
| 		if(v->fn){ | ||||
| 			nvar++; | ||||
| 			nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8; | ||||
| 		} | ||||
| 	} | ||||
| 	env=(char **)emalloc((nvar+1)*sizeof(char *)+nchr); | ||||
| 	ep=env; | ||||
| 	p=(char *)&env[nvar+1]; | ||||
| 	for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){ | ||||
| 		if((v==vlook(v->name)) && v->val){ | ||||
| 			*ep++=p; | ||||
| 			q=v->name; | ||||
| 			while(*q) *p++=*q++; | ||||
| 			sep='='; | ||||
| 			for(a=v->val;a;a=a->next){ | ||||
| 				*p++=sep; | ||||
| 				sep=SEP; | ||||
| 				q=a->word; | ||||
| 				while(*q) *p++=*q++; | ||||
| 			} | ||||
| 			*p++='\0'; | ||||
| 		} | ||||
| 		if(v->fn){ | ||||
| 			*ep++=p; | ||||
| #if 0 | ||||
| 			*p++='#'; *p++='('; *p++=')';	/* to fool Bourne */ | ||||
| 			*p++='f'; *p++='n'; *p++=' '; | ||||
| 			q=v->name; | ||||
| 			while(*q) *p++=*q++; | ||||
| 			*p++=' '; | ||||
| #endif | ||||
| 			*p++='f'; *p++='n'; *p++='#'; | ||||
| 			q=v->name; | ||||
| 			while(*q) *p++=*q++; | ||||
| 			*p++='='; | ||||
| 			q=v->fn[v->pc-1].s; | ||||
| 			while(*q) *p++=*q++; | ||||
| 			*p++='\n'; | ||||
| 			*p++='\0'; | ||||
| 		} | ||||
| 	} | ||||
| 	*ep=0; | ||||
| 	qsort((char *)env, nvar, sizeof ep[0], cmpenv); | ||||
| 	return env; | ||||
| } | ||||
| void Updenv(void){} | ||||
| void Execute(word *args, word *path) | ||||
| { | ||||
| 	char **argv=mkargv(args); | ||||
| 	char **env=mkenv(); | ||||
| 	char file[1024]; | ||||
| 	int nc; | ||||
| 	Updenv(); | ||||
| 	for(;path;path=path->next){ | ||||
| 		nc=strlen(path->word); | ||||
| 		if(nc<1024){ | ||||
| 			strcpy(file, path->word); | ||||
| 			if(file[0]){ | ||||
| 				strcat(file, "/"); | ||||
| 				nc++; | ||||
| 			} | ||||
| 			if(nc+strlen(argv[1])<1024){ | ||||
| 				strcat(file, argv[1]); | ||||
| 				execve(file, argv+1, env); | ||||
| 			} | ||||
| 			else werrstr("command name too long"); | ||||
| 		} | ||||
| 	} | ||||
| 	rerrstr(file, sizeof file); | ||||
| 	pfmt(err, "%s: %s\n", argv[1], file); | ||||
| 	efree((char *)argv); | ||||
| } | ||||
| #define	NDIR	256		/* shoud be a better way */ | ||||
| int Globsize(char *p) | ||||
| { | ||||
| 	ulong isglob=0, globlen=NDIR+1; | ||||
| 	for(;*p;p++){ | ||||
| 		if(*p==GLOB){ | ||||
| 			p++; | ||||
| 			if(*p!=GLOB) isglob++; | ||||
| 			globlen+=*p=='*'?NDIR:1; | ||||
| 		} | ||||
| 		else | ||||
| 			globlen++; | ||||
| 	} | ||||
| 	return isglob?globlen:0; | ||||
| } | ||||
| #define	NFD	50 | ||||
| #define	NDBUF	32 | ||||
| struct{ | ||||
| 	Dir	*dbuf; | ||||
| 	int	i; | ||||
| 	int	n; | ||||
| }dir[NFD]; | ||||
| int Opendir(char *name) | ||||
| { | ||||
| 	Dir *db; | ||||
| 	int f; | ||||
| 	f=open(name, 0); | ||||
| 	if(f==-1) | ||||
| 		return f; | ||||
| 	db = dirfstat(f); | ||||
| 	if(db!=nil && (db->mode&DMDIR)){ | ||||
| 		if(f<NFD){ | ||||
| 			dir[f].i=0; | ||||
| 			dir[f].n=0; | ||||
| 		} | ||||
| 		free(db); | ||||
| 		return f; | ||||
| 	} | ||||
| 	free(db); | ||||
| 	close(f); | ||||
| 	return -1; | ||||
| } | ||||
| int Readdir(int f, char *p, int onlydirs) | ||||
| { | ||||
| 	int n; | ||||
| 	USED(onlydirs);	/* only advisory */ | ||||
|  | ||||
| 	if(f<0 || f>=NFD) | ||||
| 		return 0; | ||||
| 	if(dir[f].i==dir[f].n){	/* read */ | ||||
| 		free(dir[f].dbuf); | ||||
| 		dir[f].dbuf=0; | ||||
| 		n=dirread(f, &dir[f].dbuf); | ||||
| 		if(n>=0) | ||||
| 			dir[f].n=n; | ||||
| 		else | ||||
| 			dir[f].n=0; | ||||
| 		dir[f].i=0; | ||||
| 	} | ||||
| 	if(dir[f].i==dir[f].n) | ||||
| 		return 0; | ||||
| 	strcpy(p, dir[f].dbuf[dir[f].i].name); | ||||
| 	dir[f].i++; | ||||
| 	return 1; | ||||
| } | ||||
| void Closedir(int f){ | ||||
| 	if(f>=0 && f<NFD){ | ||||
| 		free(dir[f].dbuf); | ||||
| 		dir[f].i=0; | ||||
| 		dir[f].n=0; | ||||
| 		dir[f].dbuf=0; | ||||
| 	} | ||||
| 	close(f); | ||||
| } | ||||
| int interrupted = 0; | ||||
| void | ||||
| notifyf(void *unused0, char *s) | ||||
| { | ||||
| 	int i; | ||||
| 	for(i=0;syssigname[i];i++) | ||||
| 		if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){ | ||||
| 			if(strncmp(s, "sys: ", 5)!=0){ | ||||
| 				if(kidpid && !interrupted){ | ||||
| 					interrupted=1; | ||||
| 					postnote(PNGROUP, kidpid, s); | ||||
| 				} | ||||
| 				interrupted = 1; | ||||
| 			} | ||||
| 			goto Out; | ||||
| 		} | ||||
| 	if(strcmp(s, "sys: window size change") != 0) | ||||
| 	if(strcmp(s, "sys: write on closed pipe") != 0) | ||||
| 	if(strcmp(s, "sys: child") != 0) | ||||
| 		pfmt(err, "rc: note: %s\n", s); | ||||
| 	noted(NDFLT); | ||||
| 	return; | ||||
| Out: | ||||
| 	if(strcmp(s, "interrupt")!=0 || trap[i]==0){ | ||||
| 		trap[i]++; | ||||
| 		ntrap++; | ||||
| 	} | ||||
| 	if(ntrap>=32){	/* rc is probably in a trap loop */ | ||||
| 		pfmt(err, "rc: Too many traps (trap %s), aborting\n", s); | ||||
| 		abort(); | ||||
| 	} | ||||
| 	noted(NCONT); | ||||
| } | ||||
| void Trapinit(void){ | ||||
| 	notify(notifyf); | ||||
| } | ||||
| void Unlink(char *name) | ||||
| { | ||||
| 	remove(name); | ||||
| } | ||||
| long Write(int fd, char *buf, long cnt) | ||||
| { | ||||
| 	return write(fd, buf, (long)cnt); | ||||
| } | ||||
| long Read(int fd, char *buf, long cnt) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	i = readnb(fd, buf, cnt); | ||||
| 	if(ntrap) dotrap(); | ||||
| 	return i; | ||||
| } | ||||
| long Seek(int fd, long cnt, long whence) | ||||
| { | ||||
| 	return seek(fd, cnt, whence); | ||||
| } | ||||
| int Executable(char *file) | ||||
| { | ||||
| 	Dir *statbuf; | ||||
| 	int ret; | ||||
|  | ||||
| 	statbuf = dirstat(file); | ||||
| 	if(statbuf == nil) return 0; | ||||
| 	ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0); | ||||
| 	free(statbuf); | ||||
| 	return ret; | ||||
| } | ||||
| int Creat(char *file) | ||||
| { | ||||
| 	return create(file, 1, 0666L); | ||||
| } | ||||
| int Dup(int a, int b){ | ||||
| 	return dup(a, b); | ||||
| } | ||||
| int Dup1(int a){ | ||||
| 	return dup(a, -1); | ||||
| } | ||||
| void Exit(char *stat) | ||||
| { | ||||
| 	Updenv(); | ||||
| 	setstatus(stat); | ||||
| 	exits(truestatus()?"":getstatus()); | ||||
| } | ||||
| int Eintr(void){ | ||||
| 	return interrupted; | ||||
| } | ||||
| void Noerror(void){ | ||||
| 	interrupted=0; | ||||
| } | ||||
| int | ||||
| Isatty(int fd){ | ||||
| 	return isatty(fd); | ||||
| } | ||||
| void Abort(void){ | ||||
| 	pfmt(err, "aborting\n"); | ||||
| 	flush(err); | ||||
| 	Exit("aborting"); | ||||
| } | ||||
| void Memcpy(char *a, char *b, long n) | ||||
| { | ||||
| 	memmove(a, b, (long)n); | ||||
| } | ||||
| void *Malloc(ulong n){ | ||||
| 	return malloc(n); | ||||
| } | ||||
|  | ||||
| int | ||||
| exitcode(char *msg) | ||||
| { | ||||
| 	int n; | ||||
|  | ||||
| 	n = atoi(msg); | ||||
| 	if(n == 0) | ||||
| 		n = 1; | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| int *waitpids; | ||||
| int nwaitpids; | ||||
|  | ||||
| void | ||||
| addwaitpid(int pid) | ||||
| { | ||||
| 	waitpids = realloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]); | ||||
| 	if(waitpids == 0) | ||||
| 		panic("Can't realloc %d waitpids", nwaitpids+1); | ||||
| 	waitpids[nwaitpids++] = pid; | ||||
| } | ||||
|  | ||||
| void | ||||
| delwaitpid(int pid) | ||||
| { | ||||
| 	int r, w; | ||||
|  | ||||
| 	for(r=w=0; r<nwaitpids; r++) | ||||
| 		if(waitpids[r] != pid) | ||||
| 			waitpids[w++] = waitpids[r]; | ||||
| 	nwaitpids = w; | ||||
| } | ||||
|  | ||||
| void | ||||
| clearwaitpids(void) | ||||
| { | ||||
| 	nwaitpids = 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| havewaitpid(int pid) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for(i=0; i<nwaitpids; i++) | ||||
| 		if(waitpids[i] == pid) | ||||
| 			return 1; | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										153
									
								
								cmd/rc/rc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								cmd/rc/rc.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,153 @@ | ||||
| /* | ||||
|  * Plan9 is defined for plan 9 | ||||
|  * V9 is defined for 9th edition | ||||
|  * Sun is defined for sun-os | ||||
|  * Please don't litter the code with ifdefs.  The three below (and one in | ||||
|  * getflags) should be enough. | ||||
|  */ | ||||
| #define	Plan9 | ||||
| #ifdef	Plan9 | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #undef NSIG | ||||
| #undef SIGINT | ||||
| #undef SIGQUIT | ||||
| #define	NSIG	32 | ||||
| #define	SIGINT	2 | ||||
| #define	SIGQUIT	3 | ||||
| #endif | ||||
| #ifdef	V9 | ||||
| #include <signal.h> | ||||
| #include <libc.h> | ||||
| #endif | ||||
| #ifdef Sun | ||||
| #include <signal.h> | ||||
| #endif | ||||
| #define	YYMAXDEPTH	500 | ||||
| #ifndef PAREN | ||||
| #ifndef YYMAJOR | ||||
| #include "x.tab.h" | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #undef pipe	/* so that /dev/fd works */ | ||||
| #define searchpath rcsearchpath	/* avoid new libc function */ | ||||
|  | ||||
| /* some systems define a global "var", "thread" */ | ||||
| #undef var | ||||
| #define var rcvar | ||||
| #undef thread | ||||
| #define thread rcthread | ||||
|  | ||||
| typedef struct tree tree; | ||||
| typedef struct word word; | ||||
| typedef struct io io; | ||||
| typedef union code code; | ||||
| typedef struct var var; | ||||
| typedef struct list list; | ||||
| typedef struct redir redir; | ||||
| typedef struct thread thread; | ||||
| typedef struct builtin builtin; | ||||
|  | ||||
| struct tree{ | ||||
| 	int type; | ||||
| 	int rtype, fd0, fd1;		/* details of REDIR PIPE DUP tokens */ | ||||
| 	char *str; | ||||
| 	int quoted; | ||||
| 	int iskw; | ||||
| 	tree *child[3]; | ||||
| 	tree *next; | ||||
| }; | ||||
| tree *newtree(void); | ||||
| tree *token(char*, int), *klook(char*), *tree1(int, tree*); | ||||
| tree *tree2(int, tree*, tree*), *tree3(int, tree*, tree*, tree*); | ||||
| tree *mung1(tree*, tree*), *mung2(tree*, tree*, tree*); | ||||
| tree *mung3(tree*, tree*, tree*, tree*), *epimung(tree*, tree*); | ||||
| tree *simplemung(tree*), *heredoc(tree*); | ||||
| void freetree(tree*); | ||||
| tree *cmdtree; | ||||
| /* | ||||
|  * The first word of any code vector is a reference count. | ||||
|  * Always create a new reference to a code vector by calling codecopy(.). | ||||
|  * Always call codefree(.) when deleting a reference. | ||||
|  */ | ||||
| union code{ | ||||
| 	void (*f)(void); | ||||
| 	int i; | ||||
| 	char *s; | ||||
| }; | ||||
| char *promptstr; | ||||
| #define	NTOK	8192 | ||||
| char tok[NTOK]; | ||||
| #define	APPEND	1 | ||||
| #define	WRITE	2 | ||||
| #define	READ	3 | ||||
| #define	HERE	4 | ||||
| #define	DUPFD	5 | ||||
| #define	CLOSE	6 | ||||
| #define	RDWR	7 | ||||
| struct var{ | ||||
| 	char *name;		/* ascii name */ | ||||
| 	word *val;	/* value */ | ||||
| 	int changed; | ||||
| 	code *fn;		/* pointer to function's code vector */ | ||||
| 	int fnchanged; | ||||
| 	int pc;			/* pc of start of function */ | ||||
| 	var *next;	/* next on hash or local list */ | ||||
| 	void	(*changefn)(var*); | ||||
| }; | ||||
| var *vlook(char*), *gvlook(char*), *newvar(char*, var*); | ||||
| #define	NVAR	521 | ||||
| var *gvar[NVAR];				/* hash for globals */ | ||||
| #define	new(type)	((type *)emalloc(sizeof(type))) | ||||
| char *emalloc(long); | ||||
| void *Malloc(ulong); | ||||
| void efree(char*); | ||||
| #define	NOFILE	128		/* should come from <param.h> */ | ||||
| struct here{ | ||||
| 	tree *tag; | ||||
| 	char *name; | ||||
| 	struct here *next; | ||||
| }; | ||||
| int mypid; | ||||
| /* | ||||
|  * Glob character escape in strings: | ||||
|  *	In a string, GLOB must be followed by *?[ or GLOB. | ||||
|  *	GLOB* matches any string | ||||
|  *	GLOB? matches any single character | ||||
|  *	GLOB[...] matches anything in the brackets | ||||
|  *	GLOBGLOB matches GLOB | ||||
|  */ | ||||
| #define	GLOB	((char)0x01) | ||||
| /* | ||||
|  * onebyte(c), twobyte(c), threebyte(c) | ||||
|  * Is c the first character of a one- two- or three-byte utf sequence? | ||||
|  */ | ||||
| #define	onebyte(c)	((c&0x80)==0x00) | ||||
| #define	twobyte(c)	((c&0xe0)==0xc0) | ||||
| #define	threebyte(c)	((c&0xf0)==0xe0) | ||||
| #define	fourbyte(c)	((c&0xf8)==0xf0) | ||||
|  | ||||
| char **argp; | ||||
| char **args; | ||||
| int nerror;		/* number of errors encountered during compilation */ | ||||
| extern int doprompt;		/* is it time for a prompt? */ | ||||
| /* | ||||
|  * Which fds are the reading/writing end of a pipe? | ||||
|  * Unfortunately, this can vary from system to system. | ||||
|  * 9th edition Unix doesn't care, the following defines | ||||
|  * work on plan 9. | ||||
|  */ | ||||
| #define	PRD	0 | ||||
| #define	PWR	1 | ||||
| extern char *Rcmain(), Fdprefix[]; | ||||
| #define	register | ||||
| /* | ||||
|  * How many dot commands have we executed? | ||||
|  * Used to ensure that -v flag doesn't print rcmain. | ||||
|  */ | ||||
| int ndot; | ||||
| char *getstatus(void); | ||||
| int lastc; | ||||
| int lastword; | ||||
| int kidpid; | ||||
							
								
								
									
										80
									
								
								cmd/rc/rc.sh.build
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										80
									
								
								cmd/rc/rc.sh.build
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| mkdir -p $JEHANNE/hacking/bin/ | ||||
| TARGET=rc #$JEHANNE/hacking/bin/rc | ||||
|  | ||||
| git clean -xdf . | ||||
|  | ||||
| 9yacc -d syn.y  | ||||
| cp y.tab.h x.tab.h  | ||||
|   | ||||
| cc -c \ | ||||
|     -DPLAN9PORT \ | ||||
|     -I$JEHANNE/hacking/src/trampoline/include \ | ||||
|     -O2 \ | ||||
|     -c \ | ||||
|     -Wall \ | ||||
|     -Wno-parentheses \ | ||||
|     -Wno-missing-braces \ | ||||
|     -Wno-switch \ | ||||
|     -Wno-comment \ | ||||
|     -Wno-sign-compare \ | ||||
|     -Wno-unknown-pragmas \ | ||||
|     -Wno-misleading-indentation \ | ||||
|     -Wno-stringop-truncation \ | ||||
|     -Wno-stringop-overflow \ | ||||
|     -Wno-format-truncation \ | ||||
|     -fno-omit-frame-pointer \ | ||||
|     -fsigned-char \ | ||||
|     -fcommon \ | ||||
|     -ggdb \ | ||||
|     code.c \ | ||||
|     exec.c \ | ||||
|     getflags.c \ | ||||
|     glob.c \ | ||||
|     havefork.c \ | ||||
|     here.c \ | ||||
|     io.c \ | ||||
|     plan9ish.c \ | ||||
|     unixcrap.c \ | ||||
|     lex.c \ | ||||
| 	parse.c \ | ||||
|     pcmd.c \ | ||||
|     pfnc.c \ | ||||
|     simple.c \ | ||||
|     subr.c \ | ||||
|     trap.c \ | ||||
|     tree.c \ | ||||
|     var.c \ | ||||
|     y.tab.c | ||||
|  | ||||
|  | ||||
|  | ||||
| gcc -pie -o $TARGET     \ | ||||
|     code.o \ | ||||
|     exec.o \ | ||||
|     getflags.o \ | ||||
|     glob.o \ | ||||
|     here.o \ | ||||
|     io.o \ | ||||
|     lex.o \ | ||||
|     parse.o \ | ||||
|     pcmd.o \ | ||||
|     pfnc.o \ | ||||
|     simple.o \ | ||||
|     subr.o \ | ||||
|     trap.o \ | ||||
|     tree.o \ | ||||
|     unixcrap.o \ | ||||
|     var.o \ | ||||
|     y.tab.o \ | ||||
|     plan9ish.o \ | ||||
|     havefork.o \ | ||||
| 	-L$JEHANNE/hacking/lib  -lutil -lresolv -lpthread -l9 -lm \ | ||||
|     -lutil \ | ||||
|     -lresolv \ | ||||
|     -lpthread \ | ||||
|     -lc  | ||||
|   | ||||
|  | ||||
| #git clean -xdf . | ||||
							
								
								
									
										505
									
								
								cmd/rc/simple.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										505
									
								
								cmd/rc/simple.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,505 @@ | ||||
| /* | ||||
|  * Maybe `simple' is a misnomer. | ||||
|  */ | ||||
| #include "rc.h" | ||||
| #include "getflags.h" | ||||
| #include "exec.h" | ||||
| #include "io.h" | ||||
| #include "fns.h" | ||||
| /* | ||||
|  * Search through the following code to see if we're just going to exit. | ||||
|  */ | ||||
| int | ||||
| exitnext(void){ | ||||
| 	union code *c=&runq->code[runq->pc]; | ||||
| 	while(c->f==Xpopredir) c++; | ||||
| 	return c->f==Xexit; | ||||
| } | ||||
|  | ||||
| void | ||||
| Xsimple(void) | ||||
| { | ||||
| 	word *a; | ||||
| 	thread *p = runq; | ||||
| 	var *v; | ||||
| 	struct builtin *bp; | ||||
| 	int pid; | ||||
| 	globlist(); | ||||
| 	a = runq->argv->words; | ||||
| 	if(a==0){ | ||||
| 		Xerror1("empty argument list"); | ||||
| 		return; | ||||
| 	} | ||||
| 	if(flag['x']) | ||||
| 		pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */ | ||||
| 	v = gvlook(a->word); | ||||
| 	if(v->fn) | ||||
| 		execfunc(v); | ||||
| 	else{ | ||||
| 		if(strcmp(a->word, "builtin")==0){ | ||||
| 			if(count(a)==1){ | ||||
| 				pfmt(err, "builtin: empty argument list\n"); | ||||
| 				setstatus("empty arg list"); | ||||
| 				poplist(); | ||||
| 				return; | ||||
| 			} | ||||
| 			a = a->next; | ||||
| 			popword(); | ||||
| 		} | ||||
| 		for(bp = Builtin;bp->name;bp++) | ||||
| 			if(strcmp(a->word, bp->name)==0){ | ||||
| 				(*bp->fnc)(); | ||||
| 				return; | ||||
| 			} | ||||
| 		if(exitnext()){ | ||||
| 			/* fork and wait is redundant */ | ||||
| 			pushword("exec"); | ||||
| 			execexec(); | ||||
| 			Xexit(); | ||||
| 		} | ||||
| 		else{ | ||||
| 			flush(err); | ||||
| 			Updenv();	/* necessary so changes don't go out again */ | ||||
| 			if((pid = execforkexec()) < 0){ | ||||
| 				Xerror("try again"); | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			/* interrupts don't get us out */ | ||||
| 			poplist(); | ||||
| 			while(Waitfor(pid, 1) < 0) | ||||
| 				; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| struct word nullpath = { "", 0}; | ||||
|  | ||||
| void | ||||
| doredir(redir *rp) | ||||
| { | ||||
| 	if(rp){ | ||||
| 		doredir(rp->next); | ||||
| 		switch(rp->type){ | ||||
| 		case ROPEN: | ||||
| 			if(rp->from!=rp->to){ | ||||
| 				Dup(rp->from, rp->to); | ||||
| 				close(rp->from); | ||||
| 			} | ||||
| 			break; | ||||
| 		case RDUP: | ||||
| 			Dup(rp->from, rp->to); | ||||
| 			break; | ||||
| 		case RCLOSE: | ||||
| 			close(rp->from); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| word* | ||||
| searchpath(char *w) | ||||
| { | ||||
| 	word *path; | ||||
| 	if(strncmp(w, "/", 1)==0 | ||||
| /*	|| strncmp(w, "#", 1)==0 */ | ||||
| 	|| strncmp(w, "./", 2)==0 | ||||
| 	|| strncmp(w, "../", 3)==0 | ||||
| 	|| (path = vlook("path")->val)==0) | ||||
| 		path=&nullpath; | ||||
| 	return path; | ||||
| } | ||||
|  | ||||
| void | ||||
| execexec(void) | ||||
| { | ||||
| 	popword();	/* "exec" */ | ||||
| 	if(runq->argv->words==0){ | ||||
| 		Xerror1("empty argument list"); | ||||
| 		return; | ||||
| 	} | ||||
| 	doredir(runq->redir); | ||||
| 	Execute(runq->argv->words, searchpath(runq->argv->words->word)); | ||||
| 	poplist(); | ||||
| } | ||||
|  | ||||
| void | ||||
| execfunc(var *func) | ||||
| { | ||||
| 	word *starval; | ||||
| 	popword(); | ||||
| 	starval = runq->argv->words; | ||||
| 	runq->argv->words = 0; | ||||
| 	poplist(); | ||||
| 	start(func->fn, func->pc, runq->local); | ||||
| 	runq->local = newvar(strdup("*"), runq->local); | ||||
| 	runq->local->val = starval; | ||||
| 	runq->local->changed = 1; | ||||
| } | ||||
|  | ||||
| int | ||||
| dochdir(char *word) | ||||
| { | ||||
| 	/* report to /dev/wdir if it exists and we're interactive */ | ||||
| 	static int wdirfd = -2; | ||||
| 	if(chdir(word)<0) return -1; | ||||
| 	if(flag['i']!=0){ | ||||
| 		if(wdirfd==-2)	/* try only once */ | ||||
| 			wdirfd = open("/dev/wdir", OWRITE|OCEXEC); | ||||
| 		if(wdirfd>=0) | ||||
| 			write(wdirfd, word, strlen(word)); | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void | ||||
| execcd(void) | ||||
| { | ||||
| 	word *a = runq->argv->words; | ||||
| 	word *cdpath; | ||||
| 	char dir[512]; | ||||
| 	setstatus("can't cd"); | ||||
| 	cdpath = vlook("cdpath")->val; | ||||
| 	switch(count(a)){ | ||||
| 	default: | ||||
| 		pfmt(err, "Usage: cd [directory]\n"); | ||||
| 		break; | ||||
| 	case 2: | ||||
| 		if(a->next->word[0]=='/' || cdpath==0) | ||||
| 			cdpath=&nullpath; | ||||
| 		for(;cdpath;cdpath = cdpath->next){ | ||||
| 			strcpy(dir, cdpath->word); | ||||
| 			if(dir[0]) | ||||
| 				strcat(dir, "/"); | ||||
| 			strcat(dir, a->next->word); | ||||
| 			if(dochdir(dir)>=0){ | ||||
| 				if(strlen(cdpath->word) | ||||
| 				&& strcmp(cdpath->word, ".")!=0) | ||||
| 					pfmt(err, "%s\n", dir); | ||||
| 				setstatus(""); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		if(cdpath==0) | ||||
| 			pfmt(err, "Can't cd %s: %r\n", a->next->word); | ||||
| 		break; | ||||
| 	case 1: | ||||
| 		a = vlook("home")->val; | ||||
| 		if(count(a)>=1){ | ||||
| 			if(dochdir(a->word)>=0) | ||||
| 				setstatus(""); | ||||
| 			else | ||||
| 				pfmt(err, "Can't cd %s: %r\n", a->word); | ||||
| 		} | ||||
| 		else | ||||
| 			pfmt(err, "Can't cd -- $home empty\n"); | ||||
| 		break; | ||||
| 	} | ||||
| 	poplist(); | ||||
| } | ||||
|  | ||||
| void | ||||
| execexit(void) | ||||
| { | ||||
| 	switch(count(runq->argv->words)){ | ||||
| 	default: | ||||
| 		pfmt(err, "Usage: exit [status]\nExiting anyway\n"); | ||||
| 	case 2: | ||||
| 		setstatus(runq->argv->words->next->word); | ||||
| 	case 1:	Xexit(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void | ||||
| execshift(void) | ||||
| { | ||||
| 	int n; | ||||
| 	word *a; | ||||
| 	var *star; | ||||
| 	switch(count(runq->argv->words)){ | ||||
| 	default: | ||||
| 		pfmt(err, "Usage: shift [n]\n"); | ||||
| 		setstatus("shift usage"); | ||||
| 		poplist(); | ||||
| 		return; | ||||
| 	case 2: | ||||
| 		n = atoi(runq->argv->words->next->word); | ||||
| 		break; | ||||
| 	case 1: | ||||
| 		n = 1; | ||||
| 		break; | ||||
| 	} | ||||
| 	star = vlook("*"); | ||||
| 	for(;n && star->val;--n){ | ||||
| 		a = star->val->next; | ||||
| 		efree(star->val->word); | ||||
| 		efree((char *)star->val); | ||||
| 		star->val = a; | ||||
| 		star->changed = 1; | ||||
| 	} | ||||
| 	setstatus(""); | ||||
| 	poplist(); | ||||
| } | ||||
|  | ||||
| int | ||||
| octal(char *s) | ||||
| { | ||||
| 	int n = 0; | ||||
| 	while(*s==' ' || *s=='\t' || *s=='\n') s++; | ||||
| 	while('0'<=*s && *s<='7') n = n*8+*s++-'0'; | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| int | ||||
| mapfd(int fd) | ||||
| { | ||||
| 	redir *rp; | ||||
| 	for(rp = runq->redir;rp;rp = rp->next){ | ||||
| 		switch(rp->type){ | ||||
| 		case RCLOSE: | ||||
| 			if(rp->from==fd) | ||||
| 				fd=-1; | ||||
| 			break; | ||||
| 		case RDUP: | ||||
| 		case ROPEN: | ||||
| 			if(rp->to==fd) | ||||
| 				fd = rp->from; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	return fd; | ||||
| } | ||||
| union code rdcmds[4]; | ||||
|  | ||||
| void | ||||
| execcmds(io *f) | ||||
| { | ||||
| 	static int first = 1; | ||||
| 	if(first){ | ||||
| 		rdcmds[0].i = 1; | ||||
| 		rdcmds[1].f = Xrdcmds; | ||||
| 		rdcmds[2].f = Xreturn; | ||||
| 		first = 0; | ||||
| 	} | ||||
| 	start(rdcmds, 1, runq->local); | ||||
| 	runq->cmdfd = f; | ||||
| 	runq->iflast = 0; | ||||
| } | ||||
|  | ||||
| void | ||||
| execeval(void) | ||||
| { | ||||
| 	char *cmdline, *s, *t; | ||||
| 	int len = 0; | ||||
| 	word *ap; | ||||
| 	if(count(runq->argv->words)<=1){ | ||||
| 		Xerror1("Usage: eval cmd ..."); | ||||
| 		return; | ||||
| 	} | ||||
| 	eflagok = 1; | ||||
| 	for(ap = runq->argv->words->next;ap;ap = ap->next) | ||||
| 		len+=1+strlen(ap->word); | ||||
| 	cmdline = emalloc(len); | ||||
| 	s = cmdline; | ||||
| 	for(ap = runq->argv->words->next;ap;ap = ap->next){ | ||||
| 		for(t = ap->word;*t;) *s++=*t++; | ||||
| 		*s++=' '; | ||||
| 	} | ||||
| 	s[-1]='\n'; | ||||
| 	poplist(); | ||||
| 	execcmds(opencore(cmdline, len)); | ||||
| 	efree(cmdline); | ||||
| } | ||||
| union code dotcmds[14]; | ||||
|  | ||||
| void | ||||
| execdot(void) | ||||
| { | ||||
| 	int iflag = 0; | ||||
| 	int fd; | ||||
| 	list *av; | ||||
| 	thread *p = runq; | ||||
| 	char *zero; | ||||
| 	static int first = 1; | ||||
| 	char file[512]; | ||||
| 	word *path; | ||||
|  | ||||
| 	if(first){ | ||||
| 		dotcmds[0].i = 1; | ||||
| 		dotcmds[1].f = Xmark; | ||||
| 		dotcmds[2].f = Xword; | ||||
| 		dotcmds[3].s="0"; | ||||
| 		dotcmds[4].f = Xlocal; | ||||
| 		dotcmds[5].f = Xmark; | ||||
| 		dotcmds[6].f = Xword; | ||||
| 		dotcmds[7].s="*"; | ||||
| 		dotcmds[8].f = Xlocal; | ||||
| 		dotcmds[9].f = Xrdcmds; | ||||
| 		dotcmds[10].f = Xunlocal; | ||||
| 		dotcmds[11].f = Xunlocal; | ||||
| 		dotcmds[12].f = Xreturn; | ||||
| 		first = 0; | ||||
| 	} | ||||
| 	else | ||||
| 		eflagok = 1; | ||||
| 	popword(); | ||||
| 	if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){ | ||||
| 		iflag = 1; | ||||
| 		popword(); | ||||
| 	} | ||||
| 	/* get input file */ | ||||
| 	if(p->argv->words==0){ | ||||
| 		Xerror1("Usage: . [-i] file [arg ...]"); | ||||
| 		return; | ||||
| 	} | ||||
| 	zero = strdup(p->argv->words->word); | ||||
| 	popword(); | ||||
| 	fd=-1; | ||||
| 	for(path = searchpath(zero);path;path = path->next){ | ||||
| 		strcpy(file, path->word); | ||||
| 		if(file[0]) | ||||
| 			strcat(file, "/"); | ||||
| 		strcat(file, zero); | ||||
| 		if((fd = open(file, 0))>=0) break; | ||||
| 		if(strcmp(file, "/dev/stdin")==0){	/* for sun & ucb */ | ||||
| 			fd = Dup1(0); | ||||
| 			if(fd>=0) | ||||
| 				break; | ||||
| 		} | ||||
| 	} | ||||
| 	if(fd<0){ | ||||
| 		pfmt(err, "%s: ", zero); | ||||
| 		setstatus("can't open"); | ||||
| 		Xerror(".: can't open"); | ||||
| 		return; | ||||
| 	} | ||||
| 	/* set up for a new command loop */ | ||||
| 	start(dotcmds, 1, (struct var *)0); | ||||
| 	pushredir(RCLOSE, fd, 0); | ||||
| 	runq->cmdfile = zero; | ||||
| 	runq->cmdfd = openfd(fd); | ||||
| 	runq->iflag = iflag; | ||||
| 	runq->iflast = 0; | ||||
| 	/* push $* value */ | ||||
| 	pushlist(); | ||||
| 	runq->argv->words = p->argv->words; | ||||
| 	/* free caller's copy of $* */ | ||||
| 	av = p->argv; | ||||
| 	p->argv = av->next; | ||||
| 	efree((char *)av); | ||||
| 	/* push $0 value */ | ||||
| 	pushlist(); | ||||
| 	pushword(zero); | ||||
| 	ndot++; | ||||
| } | ||||
|  | ||||
| void | ||||
| execflag(void) | ||||
| { | ||||
| 	char *letter, *val; | ||||
| 	switch(count(runq->argv->words)){ | ||||
| 	case 2: | ||||
| 		setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set"); | ||||
| 		break; | ||||
| 	case 3: | ||||
| 		letter = runq->argv->words->next->word; | ||||
| 		val = runq->argv->words->next->next->word; | ||||
| 		if(strlen(letter)==1){ | ||||
| 			if(strcmp(val, "+")==0){ | ||||
| 				flag[(uchar)letter[0]] = flagset; | ||||
| 				break; | ||||
| 			} | ||||
| 			if(strcmp(val, "-")==0){ | ||||
| 				flag[(uchar)letter[0]] = 0; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	default: | ||||
| 		Xerror1("Usage: flag [letter] [+-]"); | ||||
| 		return; | ||||
| 	} | ||||
| 	poplist(); | ||||
| } | ||||
|  | ||||
| void | ||||
| execwhatis(void){	/* mildly wrong -- should fork before writing */ | ||||
| 	word *a, *b, *path; | ||||
| 	var *v; | ||||
| 	struct builtin *bp; | ||||
| 	char file[512]; | ||||
| 	struct io out[1]; | ||||
| 	int found, sep; | ||||
| 	a = runq->argv->words->next; | ||||
| 	if(a==0){ | ||||
| 		Xerror1("Usage: whatis name ..."); | ||||
| 		return; | ||||
| 	} | ||||
| 	setstatus(""); | ||||
| 	out->fd = mapfd(1); | ||||
| 	out->bufp = out->buf; | ||||
| 	out->ebuf = &out->buf[NBUF]; | ||||
| 	out->strp = 0; | ||||
| 	for(;a;a = a->next){ | ||||
| 		v = vlook(a->word); | ||||
| 		if(v->val){ | ||||
| 			pfmt(out, "%s=", a->word); | ||||
| 			if(v->val->next==0) | ||||
| 				pfmt(out, "%q\n", v->val->word); | ||||
| 			else{ | ||||
| 				sep='('; | ||||
| 				for(b = v->val;b && b->word;b = b->next){ | ||||
| 					pfmt(out, "%c%q", sep, b->word); | ||||
| 					sep=' '; | ||||
| 				} | ||||
| 				pfmt(out, ")\n"); | ||||
| 			} | ||||
| 			found = 1; | ||||
| 		} | ||||
| 		else | ||||
| 			found = 0; | ||||
| 		v = gvlook(a->word); | ||||
| 		if(v->fn) | ||||
| 			pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s); | ||||
| 		else{ | ||||
| 			for(bp = Builtin;bp->name;bp++) | ||||
| 				if(strcmp(a->word, bp->name)==0){ | ||||
| 					pfmt(out, "builtin %s\n", a->word); | ||||
| 					break; | ||||
| 				} | ||||
| 			if(!bp->name){ | ||||
| 				for(path = searchpath(a->word);path;path = path->next){ | ||||
| 					strcpy(file, path->word); | ||||
| 					if(file[0]) | ||||
| 						strcat(file, "/"); | ||||
| 					strcat(file, a->word); | ||||
| 					if(Executable(file)){ | ||||
| 						pfmt(out, "%s\n", file); | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 				if(!path && !found){ | ||||
| 					pfmt(err, "%s: not found\n", a->word); | ||||
| 					setstatus("not found"); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	poplist(); | ||||
| 	flush(err); | ||||
| } | ||||
|  | ||||
| void | ||||
| execwait(void) | ||||
| { | ||||
| 	switch(count(runq->argv->words)){ | ||||
| 	default: | ||||
| 		Xerror1("Usage: wait [pid]"); | ||||
| 		return; | ||||
| 	case 2: | ||||
| 		Waitfor(atoi(runq->argv->words->next->word), 0); | ||||
| 		break; | ||||
| 	case 1: | ||||
| 		Waitfor(-1, 0); | ||||
| 		break; | ||||
| 	} | ||||
| 	poplist(); | ||||
| } | ||||
							
								
								
									
										77
									
								
								cmd/rc/subr.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								cmd/rc/subr.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| #include "rc.h" | ||||
| #include "exec.h" | ||||
| #include "io.h" | ||||
| #include "fns.h" | ||||
|  | ||||
| char* | ||||
| emalloc(long n) | ||||
| { | ||||
| 	char *p = (char *)Malloc(n); | ||||
| 	if(p==0) | ||||
| 		panic("Can't malloc %d bytes", n); | ||||
| /*	if(err){ pfmt(err, "malloc %d->%p\n", n, p); flush(err); } /**/ | ||||
| 	memset(p, 0, n); | ||||
| 	return p; | ||||
| } | ||||
|  | ||||
| void | ||||
| efree(char *p) | ||||
| { | ||||
| /*	pfmt(err, "free %p\n", p); flush(err); /**/ | ||||
| 	if(p) | ||||
| 		free(p); | ||||
| 	else pfmt(err, "free 0\n"); | ||||
| } | ||||
| extern int lastword, lastdol; | ||||
|  | ||||
| void | ||||
| yyerror(char *m) | ||||
| { | ||||
| 	pfmt(err, "rc: "); | ||||
| 	if(runq->cmdfile && !runq->iflag) | ||||
| 		pfmt(err, "%s:%d: ", runq->cmdfile, runq->lineno); | ||||
| 	else if(runq->cmdfile) | ||||
| 		pfmt(err, "%s: ", runq->cmdfile); | ||||
| 	else if(!runq->iflag) | ||||
| 		pfmt(err, "line %d: ", runq->lineno); | ||||
| 	if(tok[0] && tok[0]!='\n') | ||||
| 		pfmt(err, "token %q: ", tok); | ||||
| 	pfmt(err, "%s\n", m); | ||||
| 	flush(err); | ||||
| 	lastword = 0; | ||||
| 	lastdol = 0; | ||||
| 	while(lastc!='\n' && lastc!=EOF) advance(); | ||||
| 	nerror++; | ||||
| 	setvar("status", newword(m, (word *)0)); | ||||
| } | ||||
| char *bp; | ||||
|  | ||||
| static void | ||||
| iacvt(int n) | ||||
| { | ||||
| 	if(n<0){ | ||||
| 		*bp++='-'; | ||||
| 		n=-n;	/* doesn't work for n==-inf */ | ||||
| 	} | ||||
| 	if(n/10) | ||||
| 		iacvt(n/10); | ||||
| 	*bp++=n%10+'0'; | ||||
| } | ||||
|  | ||||
| void | ||||
| inttoascii(char *s, long n) | ||||
| { | ||||
| 	bp = s; | ||||
| 	iacvt(n); | ||||
| 	*bp='\0'; | ||||
| } | ||||
|  | ||||
| void | ||||
| panic(char *s, int n) | ||||
| { | ||||
| 	pfmt(err, "rc: "); | ||||
| 	pfmt(err, s, n); | ||||
| 	pchr(err, '\n'); | ||||
| 	flush(err); | ||||
| 	Abort(); | ||||
| } | ||||
							
								
								
									
										91
									
								
								cmd/rc/syn.y
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								cmd/rc/syn.y
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | ||||
| %term FOR IN WHILE IF NOT TWIDDLE BANG SUBSHELL SWITCH FN | ||||
| %term WORD REDIR REDIRW DUP PIPE SUB | ||||
| %term SIMPLE ARGLIST WORDS BRACE PAREN PCMD PIPEFD /* not used in syntax */ | ||||
| /* operator priorities -- lowest first */ | ||||
| %left IF WHILE FOR SWITCH ')' NOT | ||||
| %left ANDAND OROR | ||||
| %left BANG SUBSHELL | ||||
| %left PIPE | ||||
| %left '^' | ||||
| %right '$' COUNT '"' | ||||
| %left SUB | ||||
| %{ | ||||
| #include "rc.h" | ||||
| #include "fns.h" | ||||
| %} | ||||
| %union{ | ||||
| 	struct tree *tree; | ||||
| }; | ||||
| %type<tree> line paren brace body cmdsa cmdsan assign epilog redir | ||||
| %type<tree> cmd simple first word comword keyword words | ||||
| %type<tree> NOT FOR IN WHILE IF TWIDDLE BANG SUBSHELL SWITCH FN | ||||
| %type<tree> WORD REDIR REDIRW DUP PIPE | ||||
| %% | ||||
| rc:				{ return 1;} | ||||
| |	line '\n'		{return !compile($1);} | ||||
| line:	cmd | ||||
| |	cmdsa line		{$$=tree2(';', $1, $2);} | ||||
| body:	cmd | ||||
| |	cmdsan body		{$$=tree2(';', $1, $2);} | ||||
| cmdsa:	cmd ';' | ||||
| |	cmd '&'			{$$=tree1('&', $1);} | ||||
| cmdsan:	cmdsa | ||||
| |	cmd '\n' | ||||
| brace:	'{' body '}'		{$$=tree1(BRACE, $2);} | ||||
| paren:	'(' body ')'		{$$=tree1(PCMD, $2);} | ||||
| assign:	first '=' word		{$$=tree2('=', $1, $3);} | ||||
| epilog:				{$$=0;} | ||||
| |	redir epilog		{$$=mung2($1, $1->child[0], $2);} | ||||
| redir:	REDIR word		{$$=mung1($1, $1->rtype==HERE?heredoc($2):$2);} | ||||
| |	DUP | ||||
| cmd:				{$$=0;} | ||||
| |	brace epilog		{$$=epimung($1, $2);} | ||||
| |	IF paren {skipnl();} cmd | ||||
| 				{$$=mung2($1, $2, $4);} | ||||
| |	IF NOT {skipnl();} cmd	{$$=mung1($2, $4);} | ||||
| |	FOR '(' word IN words ')' {skipnl();} cmd | ||||
| 	/* | ||||
| 	 * if ``words'' is nil, we need a tree element to distinguish between | ||||
| 	 * for(i in ) and for(i), the former being a loop over the empty set | ||||
| 	 * and the latter being the implicit argument loop.  so if $5 is nil | ||||
| 	 * (the empty set), we represent it as "()".  don't parenthesize non-nil | ||||
| 	 * functions, to avoid growing parentheses every time we reread the | ||||
| 	 * definition. | ||||
| 	 */ | ||||
| 				{$$=mung3($1, $3, $5 ? $5 : tree1(PAREN, $5), $8);} | ||||
| |	FOR '(' word ')' {skipnl();} cmd | ||||
| 				{$$=mung3($1, $3, (struct tree *)0, $6);} | ||||
| |	WHILE paren {skipnl();} cmd | ||||
| 				{$$=mung2($1, $2, $4);} | ||||
| |	SWITCH word {skipnl();} brace | ||||
| 				{$$=tree2(SWITCH, $2, $4);} | ||||
| |	simple			{$$=simplemung($1);} | ||||
| |	TWIDDLE word words	{$$=mung2($1, $2, $3);} | ||||
| |	cmd ANDAND cmd		{$$=tree2(ANDAND, $1, $3);} | ||||
| |	cmd OROR cmd		{$$=tree2(OROR, $1, $3);} | ||||
| |	cmd PIPE cmd		{$$=mung2($2, $1, $3);} | ||||
| |	redir cmd  %prec BANG	{$$=mung2($1, $1->child[0], $2);} | ||||
| |	assign cmd %prec BANG	{$$=mung3($1, $1->child[0], $1->child[1], $2);} | ||||
| |	BANG cmd		{$$=mung1($1, $2);} | ||||
| |	SUBSHELL cmd		{$$=mung1($1, $2);} | ||||
| |	FN words brace		{$$=tree2(FN, $2, $3);} | ||||
| |	FN words		{$$=tree1(FN, $2);} | ||||
| simple:	first | ||||
| |	simple word		{$$=tree2(ARGLIST, $1, $2);} | ||||
| |	simple redir		{$$=tree2(ARGLIST, $1, $2);} | ||||
| first:	comword | ||||
| |	first '^' word		{$$=tree2('^', $1, $3);} | ||||
| word:	keyword			{lastword=1; $1->type=WORD;} | ||||
| |	comword | ||||
| |	word '^' word		{$$=tree2('^', $1, $3);} | ||||
| comword: '$' word		{$$=tree1('$', $2);} | ||||
| |	'$' word SUB words ')'	{$$=tree2(SUB, $2, $4);} | ||||
| |	'"' word		{$$=tree1('"', $2);} | ||||
| |	COUNT word		{$$=tree1(COUNT, $2);} | ||||
| |	WORD | ||||
| |	'`' brace		{$$=tree1('`', $2);} | ||||
| |	'(' words ')'		{$$=tree1(PAREN, $2);} | ||||
| |	REDIRW brace		{$$=mung1($1, $2); $$->type=PIPEFD;} | ||||
| keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN | ||||
| words:				{$$=(struct tree*)0;} | ||||
| |	words word		{$$=tree2(WORDS, $1, $2);} | ||||
							
								
								
									
										37
									
								
								cmd/rc/trap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								cmd/rc/trap.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| #include "rc.h" | ||||
| #include "exec.h" | ||||
| #include "fns.h" | ||||
| #include "io.h" | ||||
| extern char *Signame[]; | ||||
|  | ||||
| void | ||||
| dotrap(void) | ||||
| { | ||||
| 	int i; | ||||
| 	struct var *trapreq; | ||||
| 	struct word *starval; | ||||
| 	starval = vlook("*")->val; | ||||
| 	while(ntrap) for(i = 0;i!=NSIG;i++) while(trap[i]){ | ||||
| 		--trap[i]; | ||||
| 		--ntrap; | ||||
| 		if(getpid()!=mypid) Exit(getstatus()); | ||||
| 		trapreq = vlook(Signame[i]); | ||||
| 		if(trapreq->fn){ | ||||
| 			start(trapreq->fn, trapreq->pc, (struct var *)0); | ||||
| 			runq->local = newvar(strdup("*"), runq->local); | ||||
| 			runq->local->val = copywords(starval, (struct word *)0); | ||||
| 			runq->local->changed = 1; | ||||
| 			runq->redir = runq->startredir = 0; | ||||
| 		} | ||||
| 		else if(i==SIGINT || i==SIGQUIT){ | ||||
| 			/* | ||||
| 			 * run the stack down until we uncover the | ||||
| 			 * command reading loop.  Xreturn will exit | ||||
| 			 * if there is none (i.e. if this is not | ||||
| 			 * an interactive rc.) | ||||
| 			 */ | ||||
| 			while(!runq->iflag) Xreturn(); | ||||
| 		} | ||||
| 		else Exit(getstatus()); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										146
									
								
								cmd/rc/tree.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								cmd/rc/tree.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| #include "rc.h" | ||||
| #include "exec.h" | ||||
| #include "io.h" | ||||
| #include "fns.h" | ||||
| tree *treenodes; | ||||
| /* | ||||
|  * create and clear a new tree node, and add it | ||||
|  * to the node list. | ||||
|  */ | ||||
|  | ||||
| tree* | ||||
| newtree(void) | ||||
| { | ||||
| 	tree *t = new(tree); | ||||
| 	t->iskw = 0; | ||||
| 	t->str = 0; | ||||
| 	t->child[0] = t->child[1] = t->child[2] = 0; | ||||
| 	t->next = treenodes; | ||||
| 	treenodes = t; | ||||
| 	return t; | ||||
| } | ||||
|  | ||||
| void | ||||
| freenodes(void) | ||||
| { | ||||
| 	tree *t, *u; | ||||
| 	for(t = treenodes;t;t = u){ | ||||
| 		u = t->next; | ||||
| 		if(t->str) | ||||
| 			efree(t->str); | ||||
| 		efree((char *)t); | ||||
| 	} | ||||
| 	treenodes = 0; | ||||
| } | ||||
|  | ||||
| tree* | ||||
| tree1(int type, tree *c0) | ||||
| { | ||||
| 	return tree3(type, c0, (tree *)0, (tree *)0); | ||||
| } | ||||
|  | ||||
| tree* | ||||
| tree2(int type, tree *c0, tree *c1) | ||||
| { | ||||
| 	return tree3(type, c0, c1, (tree *)0); | ||||
| } | ||||
|  | ||||
| tree* | ||||
| tree3(int type, tree *c0, tree *c1, tree *c2) | ||||
| { | ||||
| 	tree *t; | ||||
| 	if(type==';'){ | ||||
| 		if(c0==0) | ||||
| 			return c1; | ||||
| 		if(c1==0) | ||||
| 			return c0; | ||||
| 	} | ||||
| 	t = newtree(); | ||||
| 	t->type = type; | ||||
| 	t->child[0] = c0; | ||||
| 	t->child[1] = c1; | ||||
| 	t->child[2] = c2; | ||||
| 	return t; | ||||
| } | ||||
|  | ||||
| tree* | ||||
| mung1(tree *t, tree *c0) | ||||
| { | ||||
| 	t->child[0] = c0; | ||||
| 	return t; | ||||
| } | ||||
|  | ||||
| tree* | ||||
| mung2(tree *t, tree *c0, tree *c1) | ||||
| { | ||||
| 	t->child[0] = c0; | ||||
| 	t->child[1] = c1; | ||||
| 	return t; | ||||
| } | ||||
|  | ||||
| tree* | ||||
| mung3(tree *t, tree *c0, tree *c1, tree *c2) | ||||
| { | ||||
| 	t->child[0] = c0; | ||||
| 	t->child[1] = c1; | ||||
| 	t->child[2] = c2; | ||||
| 	return t; | ||||
| } | ||||
|  | ||||
| tree* | ||||
| epimung(tree *comp, tree *epi) | ||||
| { | ||||
| 	tree *p; | ||||
| 	if(epi==0) | ||||
| 		return comp; | ||||
| 	for(p = epi;p->child[1];p = p->child[1]); | ||||
| 	p->child[1] = comp; | ||||
| 	return epi; | ||||
| } | ||||
| /* | ||||
|  * Add a SIMPLE node at the root of t and percolate all the redirections | ||||
|  * up to the root. | ||||
|  */ | ||||
|  | ||||
| tree* | ||||
| simplemung(tree *t) | ||||
| { | ||||
| 	tree *u; | ||||
| 	struct io *s; | ||||
| 	t = tree1(SIMPLE, t); | ||||
| 	s = openstr(); | ||||
| 	pfmt(s, "%t", t); | ||||
| 	t->str = strdup(s->strp); | ||||
| 	closeio(s); | ||||
| 	for(u = t->child[0];u->type==ARGLIST;u = u->child[0]){ | ||||
| 		if(u->child[1]->type==DUP | ||||
| 		|| u->child[1]->type==REDIR){ | ||||
| 			u->child[1]->child[1] = t; | ||||
| 			t = u->child[1]; | ||||
| 			u->child[1] = 0; | ||||
| 		} | ||||
| 	} | ||||
| 	return t; | ||||
| } | ||||
|  | ||||
| tree* | ||||
| token(char *str, int type) | ||||
| { | ||||
| 	tree *t = newtree(); | ||||
| 	t->type = type; | ||||
| 	t->str = strdup(str); | ||||
| 	return t; | ||||
| } | ||||
|  | ||||
| void | ||||
| freetree(tree *p) | ||||
| { | ||||
| 	if(p==0) | ||||
| 		return; | ||||
| 	freetree(p->child[0]); | ||||
| 	freetree(p->child[1]); | ||||
| 	freetree(p->child[2]); | ||||
| 	if(p->str) | ||||
| 		efree(p->str); | ||||
| 	efree((char *)p); | ||||
| } | ||||
							
								
								
									
										242
									
								
								cmd/rc/unixcrap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										242
									
								
								cmd/rc/unixcrap.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,242 @@ | ||||
| #include <u.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/resource.h> | ||||
| #include <errno.h> | ||||
| #include <fcntl.h> | ||||
| #include <libc.h> | ||||
| #include "rc.h" | ||||
| #include "exec.h" | ||||
| #include "io.h" | ||||
| #include "fns.h" | ||||
| #include "getflags.h" | ||||
|  | ||||
| extern char **mkargv(word*); | ||||
| extern int mapfd(int); | ||||
|  | ||||
| static char *eargs = "cdflmnstuv"; | ||||
| static int rlx[] = { | ||||
| 	RLIMIT_CORE, | ||||
| 	RLIMIT_DATA, | ||||
| 	RLIMIT_FSIZE, | ||||
| #ifdef RLIMIT_MEMLOCK | ||||
| 	RLIMIT_MEMLOCK, | ||||
| #else | ||||
| 	0, | ||||
| #endif | ||||
| #ifdef RLIMIT_RSS | ||||
| 	RLIMIT_RSS, | ||||
| #else | ||||
| 	0, | ||||
| #endif | ||||
| 	RLIMIT_NOFILE, | ||||
| 	RLIMIT_STACK, | ||||
| 	RLIMIT_CPU, | ||||
| #ifdef RLIMIT_NPROC | ||||
| 	RLIMIT_NPROC, | ||||
| #else | ||||
| 	0, | ||||
| #endif | ||||
| #ifdef RLIMIT_RSS | ||||
| 	RLIMIT_RSS, | ||||
| #else | ||||
| 	0, | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| static void | ||||
| eusage(void) | ||||
| { | ||||
| 	fprint(mapfd(2), "usage: ulimit [-SHa%s [limit]]\n", eargs); | ||||
| } | ||||
|  | ||||
| #define Notset -4 | ||||
| #define Unlimited -3 | ||||
| #define Hard -2 | ||||
| #define Soft -1 | ||||
|  | ||||
| void | ||||
| execulimit(void) | ||||
| { | ||||
| 	rlim_t n; | ||||
| 	int fd, argc, sethard, setsoft, limit; | ||||
| 	int flag[256]; | ||||
| 	char **argv, **oargv, *p; | ||||
| 	char *argv0; | ||||
| 	struct rlimit rl; | ||||
|  | ||||
| 	argv0 = nil; | ||||
| 	setstatus(""); | ||||
| 	oargv = mkargv(runq->argv->words); | ||||
| 	argv = oargv+1; | ||||
| 	for(argc=0; argv[argc]; argc++) | ||||
| 		; | ||||
|  | ||||
| 	memset(flag, 0, sizeof flag); | ||||
| 	ARGBEGIN{ | ||||
| 	default: | ||||
| 		if(strchr(eargs, ARGC()) == nil){ | ||||
| 			eusage(); | ||||
| 			return; | ||||
| 		} | ||||
| 	case 'S': | ||||
| 	case 'H': | ||||
| 	case 'a': | ||||
| 		flag[ARGC()] = 1; | ||||
| 		break; | ||||
| 	}ARGEND | ||||
|  | ||||
| 	if(argc > 1){ | ||||
| 		eusage(); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	fd = mapfd(1); | ||||
|  | ||||
| 	sethard = 1; | ||||
| 	setsoft = 1; | ||||
| 	if(flag['S'] && flag['H']) | ||||
| 		; | ||||
| 	else if(flag['S']) | ||||
| 		sethard = 0; | ||||
| 	else if(flag['H']) | ||||
| 		setsoft = 0; | ||||
|  | ||||
| 	limit = Notset; | ||||
| 	if(argc>0){ | ||||
| 		if(strcmp(argv[0], "unlimited") == 0) | ||||
| 			limit = Unlimited; | ||||
| 		else if(strcmp(argv[0], "hard") == 0) | ||||
| 			limit = Hard; | ||||
| 		else if(strcmp(argv[0], "soft") == 0) | ||||
| 			limit = Soft; | ||||
| 		else if((limit = strtol(argv[0], &p, 0)) < 0 || *p != 0){ | ||||
| 			eusage(); | ||||
| 			goto out; | ||||
| 		} | ||||
| 	} | ||||
| 	if(flag['a']){ | ||||
| 		for(p=eargs; *p; p++){ | ||||
| 			getrlimit(rlx[p-eargs], &rl); | ||||
| 			n = flag['H'] ? rl.rlim_max : rl.rlim_cur; | ||||
| 			if(n == RLIM_INFINITY) | ||||
| 				fprint(fd, "ulimit -%c unlimited\n", *p); | ||||
| 			else | ||||
| 				fprint(fd, "ulimit -%c %llud\n", *p, (uvlong)n); | ||||
| 		} | ||||
| 		goto out; | ||||
| 	} | ||||
| 	for(p=eargs; *p; p++){ | ||||
| 		if(flag[(uchar)*p]){ | ||||
| 			n = 0; | ||||
| 			getrlimit(rlx[p-eargs], &rl); | ||||
| 			switch(limit){ | ||||
| 			case Notset: | ||||
| 				n = flag['H'] ? rl.rlim_max : rl.rlim_cur; | ||||
| 				if(n == RLIM_INFINITY) | ||||
| 					fprint(fd, "ulimit -%c unlimited\n", *p); | ||||
| 				else | ||||
| 					fprint(fd, "ulimit -%c %llud\n", *p, (uvlong)n); | ||||
| 				break; | ||||
| 			case Hard: | ||||
| 				n = rl.rlim_max; | ||||
| 				goto set; | ||||
| 			case Soft: | ||||
| 				n = rl.rlim_cur; | ||||
| 				goto set; | ||||
| 			case Unlimited: | ||||
| 				n = RLIM_INFINITY; | ||||
| 				goto set; | ||||
| 			default: | ||||
| 				n = limit; | ||||
| 			set: | ||||
| 				if(setsoft) | ||||
| 					rl.rlim_cur = n; | ||||
| 				if(sethard) | ||||
| 					rl.rlim_max = n; | ||||
| 				if(setrlimit(rlx[p-eargs], &rl) < 0) | ||||
| 					fprint(mapfd(2), "setrlimit: %r\n"); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| out: | ||||
| 	free(oargv); | ||||
| 	poplist(); | ||||
| 	flush(err); | ||||
| } | ||||
|  | ||||
| void | ||||
| execumask(void) | ||||
| { | ||||
| 	int n, argc; | ||||
| 	char **argv, **oargv, *p; | ||||
| 	char *argv0; | ||||
|  | ||||
| 	argv0 = nil; | ||||
| 	setstatus(""); | ||||
| 	oargv = mkargv(runq->argv->words); | ||||
| 	argv = oargv+1; | ||||
| 	for(argc=0; argv[argc]; argc++) | ||||
| 		; | ||||
|  | ||||
| 	ARGBEGIN{ | ||||
| 	default: | ||||
| 	usage: | ||||
| 		fprint(mapfd(2), "usage: umask [mode]\n"); | ||||
| 		goto out; | ||||
| 	}ARGEND | ||||
|  | ||||
| 	if(argc > 1) | ||||
| 		goto usage; | ||||
|  | ||||
| 	if(argc == 1){ | ||||
| 		n = strtol(argv[0], &p, 8); | ||||
| 		if(*p != 0 || p == argv[0]) | ||||
| 			goto usage; | ||||
| 		umask(n); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	n = umask(0); | ||||
| 	umask(n); | ||||
| 	if(n < 0){ | ||||
| 		fprint(mapfd(2), "umask: %r\n"); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	fprint(mapfd(1), "umask %03o\n", n); | ||||
|  | ||||
| out: | ||||
| 	free(oargv); | ||||
| 	poplist(); | ||||
| 	flush(err); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Cope with non-blocking read. | ||||
|  */ | ||||
| long | ||||
| readnb(int fd, char *buf, long cnt) | ||||
| { | ||||
| 	int n, didreset; | ||||
| 	int flgs; | ||||
|  | ||||
| 	didreset = 0; | ||||
| again: | ||||
| 	n = read(fd, buf, cnt); | ||||
| 	if(n == -1) | ||||
| 	if(errno == EAGAIN){ | ||||
| 		if(!didreset){ | ||||
| 			if((flgs = fcntl(fd, F_GETFL, 0)) == -1) | ||||
| 				return -1; | ||||
| 			flgs &= ~O_NONBLOCK; | ||||
| 			if(fcntl(fd, F_SETFL, flgs) == -1) | ||||
| 				return -1; | ||||
| 			didreset = 1; | ||||
| 		} | ||||
| 		goto again; | ||||
| 	} | ||||
|  | ||||
| 	return n; | ||||
| } | ||||
							
								
								
									
										173
									
								
								cmd/rc/var.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								cmd/rc/var.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,173 @@ | ||||
| #include "rc.h" | ||||
| #include "exec.h" | ||||
| #include "fns.h" | ||||
|  | ||||
| int | ||||
| hash(char *s, int n) | ||||
| { | ||||
| 	int h = 0, i = 1; | ||||
| 	while(*s) h+=*s++*i++; | ||||
| 	h%=n; | ||||
| 	return h<0?h+n:h; | ||||
| } | ||||
| #define	NKW	30 | ||||
| struct kw{ | ||||
| 	char *name; | ||||
| 	int type; | ||||
| 	struct kw *next; | ||||
| }*kw[NKW]; | ||||
|  | ||||
| void | ||||
| kenter(int type, char *name) | ||||
| { | ||||
| 	int h = hash(name, NKW); | ||||
| 	struct kw *p = new(struct kw); | ||||
| 	p->type = type; | ||||
| 	p->name = name; | ||||
| 	p->next = kw[h]; | ||||
| 	kw[h] = p; | ||||
| } | ||||
|  | ||||
| void | ||||
| kinit(void) | ||||
| { | ||||
| 	kenter(FOR, "for"); | ||||
| 	kenter(IN, "in"); | ||||
| 	kenter(WHILE, "while"); | ||||
| 	kenter(IF, "if"); | ||||
| 	kenter(NOT, "not"); | ||||
| 	kenter(TWIDDLE, "~"); | ||||
| 	kenter(BANG, "!"); | ||||
| 	kenter(SUBSHELL, "@"); | ||||
| 	kenter(SWITCH, "switch"); | ||||
| 	kenter(FN, "fn"); | ||||
| } | ||||
|  | ||||
| tree* | ||||
| klook(char *name) | ||||
| { | ||||
| 	struct kw *p; | ||||
| 	tree *t = token(name, WORD); | ||||
| 	for(p = kw[hash(name, NKW)];p;p = p->next) | ||||
| 		if(strcmp(p->name, name)==0){ | ||||
| 			t->type = p->type; | ||||
| 			t->iskw = 1; | ||||
| 			break; | ||||
| 		} | ||||
| 	return t; | ||||
| } | ||||
|  | ||||
| var* | ||||
| gvlook(char *name) | ||||
| { | ||||
| 	int h = hash(name, NVAR); | ||||
| 	var *v; | ||||
| 	for(v = gvar[h];v;v = v->next) if(strcmp(v->name, name)==0) return v; | ||||
| 	return gvar[h] = newvar(strdup(name), gvar[h]); | ||||
| } | ||||
|  | ||||
| var* | ||||
| vlook(char *name) | ||||
| { | ||||
| 	var *v; | ||||
| 	if(runq) | ||||
| 		for(v = runq->local;v;v = v->next) | ||||
| 			if(strcmp(v->name, name)==0) return v; | ||||
| 	return gvlook(name); | ||||
| } | ||||
|  | ||||
| void | ||||
| _setvar(char *name, word *val, int callfn) | ||||
| { | ||||
| 	struct var *v = vlook(name); | ||||
| 	freewords(v->val); | ||||
| 	v->val=val; | ||||
| 	v->changed=1; | ||||
| 	if(callfn && v->changefn) | ||||
| 		v->changefn(v); | ||||
| } | ||||
|  | ||||
| void | ||||
| setvar(char *name, word *val) | ||||
| { | ||||
| 	_setvar(name, val, 1); | ||||
| } | ||||
|  | ||||
| void | ||||
| bigpath(var *v) | ||||
| { | ||||
| 	/* convert $PATH to $path */ | ||||
| 	char *p, *q; | ||||
| 	word **l, *w; | ||||
|  | ||||
| 	if(v->val == nil){ | ||||
| 		_setvar("path", nil, 0); | ||||
| 		return; | ||||
| 	} | ||||
| 	p = v->val->word; | ||||
| 	w = nil; | ||||
| 	l = &w; | ||||
| 	/* | ||||
| 	 * Doesn't handle escaped colon nonsense. | ||||
| 	 */ | ||||
| 	if(p[0] == 0) | ||||
| 		p = nil; | ||||
| 	while(p){ | ||||
| 		q = strchr(p, ':'); | ||||
| 		if(q) | ||||
| 			*q = 0; | ||||
| 		*l = newword(p[0] ? p : ".", nil); | ||||
| 		l = &(*l)->next; | ||||
| 		if(q){ | ||||
| 			*q = ':'; | ||||
| 			p = q+1; | ||||
| 		}else | ||||
| 			p = nil; | ||||
| 	} | ||||
| 	_setvar("path", w, 0); | ||||
| } | ||||
|  | ||||
| char* | ||||
| list2strcolon(word *words) | ||||
| { | ||||
| 	char *value, *s, *t; | ||||
| 	int len = 0; | ||||
| 	word *ap; | ||||
| 	for(ap = words;ap;ap = ap->next) | ||||
| 		len+=1+strlen(ap->word); | ||||
| 	value = emalloc(len+1); | ||||
| 	s = value; | ||||
| 	for(ap = words;ap;ap = ap->next){ | ||||
| 		for(t = ap->word;*t;) *s++=*t++; | ||||
| 		*s++=':'; | ||||
| 	} | ||||
| 	if(s==value) | ||||
| 		*s='\0'; | ||||
| 	else s[-1]='\0'; | ||||
| 	return value; | ||||
| } | ||||
| void | ||||
| littlepath(var *v) | ||||
| { | ||||
| 	/* convert $path to $PATH */ | ||||
| 	char *p; | ||||
| 	word *w; | ||||
|  | ||||
| 	p = list2strcolon(v->val); | ||||
| 	w = new(word); | ||||
| 	w->word = p; | ||||
| 	w->next = nil; | ||||
| 	_setvar("PATH", w, 1);	/* 1: recompute $path to expose colon problems */ | ||||
| } | ||||
|  | ||||
| void | ||||
| pathinit(void) | ||||
| { | ||||
| 	var *v; | ||||
|  | ||||
| 	v = gvlook("path"); | ||||
| 	v->changefn = littlepath; | ||||
| 	v = gvlook("PATH"); | ||||
| 	v->changefn = bigpath; | ||||
| 	bigpath(v); | ||||
| } | ||||
							
								
								
									
										2993
									
								
								cmd/yacc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2993
									
								
								cmd/yacc.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										91
									
								
								include/bio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								include/bio.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | ||||
| #ifndef _BIO_H_ | ||||
| #define _BIO_H_ 1 | ||||
| #if defined(__cplusplus) | ||||
| extern "C" {  | ||||
| #endif | ||||
|  | ||||
| #ifdef AUTOLIB | ||||
| AUTOLIB(bio) | ||||
| #endif | ||||
|  | ||||
| #include <fcntl.h>	/* for O_RDONLY, O_WRONLY */ | ||||
|  | ||||
| typedef	struct	Biobuf	Biobuf; | ||||
|  | ||||
| enum | ||||
| { | ||||
| 	Bsize		= 8*1024, | ||||
| 	Bungetsize	= 4,		/* space for ungetc */ | ||||
| 	Bmagic		= 0x314159, | ||||
| 	Beof		= -1, | ||||
| 	Bbad		= -2, | ||||
|  | ||||
| 	Binactive	= 0,		/* states */ | ||||
| 	Bractive, | ||||
| 	Bwactive, | ||||
| 	Bracteof, | ||||
|  | ||||
| 	Bend | ||||
| }; | ||||
|  | ||||
| struct	Biobuf | ||||
| { | ||||
| 	int	icount;		/* neg num of bytes at eob */ | ||||
| 	int	ocount;		/* num of bytes at bob */ | ||||
| 	int	rdline;		/* num of bytes after rdline */ | ||||
| 	int	runesize;	/* num of bytes of last getrune */ | ||||
| 	int	state;		/* r/w/inactive */ | ||||
| 	int	fid;		/* open file */ | ||||
| 	int	flag;		/* magic if malloc'ed */ | ||||
| 	long long	offset;		/* offset of buffer in file */ | ||||
| 	int	bsize;		/* size of buffer */ | ||||
| 	unsigned char*	bbuf;		/* pointer to beginning of buffer */ | ||||
| 	unsigned char*	ebuf;		/* pointer to end of buffer */ | ||||
| 	unsigned char*	gbuf;		/* pointer to good data in buf */ | ||||
| 	unsigned char	b[Bungetsize+Bsize]; | ||||
| }; | ||||
|  | ||||
| #define	BGETC(bp)\ | ||||
| 	((bp)->icount?(bp)->bbuf[(bp)->bsize+(bp)->icount++]:Bgetc((bp))) | ||||
| #define	BPUTC(bp,c)\ | ||||
| 	((bp)->ocount?(bp)->bbuf[(bp)->bsize+(bp)->ocount++]=(c),0:Bputc((bp),(c))) | ||||
| #define	BOFFSET(bp)\ | ||||
| 	(((bp)->state==Bractive)?\ | ||||
| 		(bp)->offset + (bp)->icount:\ | ||||
| 	(((bp)->state==Bwactive)?\ | ||||
| 		(bp)->offset + ((bp)->bsize + (bp)->ocount):\ | ||||
| 		-1)) | ||||
| #define	BLINELEN(bp)\ | ||||
| 	(bp)->rdline | ||||
| #define	BFILDES(bp)\ | ||||
| 	(bp)->fid | ||||
|  | ||||
| int	Bbuffered(Biobuf*); | ||||
| Biobuf*	Bfdopen(int, int); | ||||
| int	Bfildes(Biobuf*); | ||||
| int	Bflush(Biobuf*); | ||||
| int	Bgetc(Biobuf*); | ||||
| int	Bgetd(Biobuf*, double*); | ||||
| long	Bgetrune(Biobuf*); | ||||
| int	Binit(Biobuf*, int, int); | ||||
| int	Binits(Biobuf*, int, int, unsigned char*, int); | ||||
| int	Blinelen(Biobuf*); | ||||
| long long	Boffset(Biobuf*); | ||||
| Biobuf*	Bopen(char*, int); | ||||
| int	Bprint(Biobuf*, char*, ...); | ||||
| int	Bputc(Biobuf*, int); | ||||
| int	Bputrune(Biobuf*, long); | ||||
| void*	Brdline(Biobuf*, int); | ||||
| char*	Brdstr(Biobuf*, int, int); | ||||
| long	Bread(Biobuf*, void*, long); | ||||
| long long	Bseek(Biobuf*, long long, int); | ||||
| int	Bterm(Biobuf*); | ||||
| int	Bungetc(Biobuf*); | ||||
| int	Bungetrune(Biobuf*); | ||||
| long	Bwrite(Biobuf*, void*, long); | ||||
| int	Bvprint(Biobuf*, char*, va_list); | ||||
|  | ||||
| #if defined(__cplusplus) | ||||
| } | ||||
| #endif | ||||
| #endif | ||||
							
								
								
									
										116
									
								
								include/fmt.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								include/fmt.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | ||||
| #ifndef _FMT_H_ | ||||
| #define _FMT_H_ 1 | ||||
| #if defined(__cplusplus) | ||||
| extern "C" {  | ||||
| #endif | ||||
| /* | ||||
|  * The authors of this software are Rob Pike and Ken Thompson. | ||||
|  *              Copyright (c) 2002 by Lucent Technologies. | ||||
|  * Permission to use, copy, modify, and distribute this software for any | ||||
|  * purpose without fee is hereby granted, provided that this entire notice | ||||
|  * is included in all copies of any software which is or includes a copy | ||||
|  * or modification of this software and in all copies of the supporting | ||||
|  * documentation for such software. | ||||
|  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED | ||||
|  * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY | ||||
|  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY | ||||
|  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. | ||||
|  */ | ||||
|  | ||||
| #include <stdarg.h> | ||||
| #include <utf.h> | ||||
|  | ||||
| typedef struct Fmt	Fmt; | ||||
| struct Fmt{ | ||||
| 	unsigned char	runes;		/* output buffer is runes or chars? */ | ||||
| 	void	*start;			/* of buffer */ | ||||
| 	void	*to;			/* current place in the buffer */ | ||||
| 	void	*stop;			/* end of the buffer; overwritten if flush fails */ | ||||
| 	int	(*flush)(Fmt *);	/* called when to == stop */ | ||||
| 	void	*farg;			/* to make flush a closure */ | ||||
| 	int	nfmt;			/* num chars formatted so far */ | ||||
| 	va_list	args;			/* args passed to dofmt */ | ||||
| 	Rune	r;			/* % format Rune */ | ||||
| 	int	width; | ||||
| 	int	prec; | ||||
| 	unsigned long	flags; | ||||
| 	char	*decimal;	/* decimal point; cannot be "" */ | ||||
|  | ||||
| 	/* For %'d */ | ||||
| 	char *thousands;	/* separator for thousands */ | ||||
| 	 | ||||
| 	/*  | ||||
| 	 * Each char is an integer indicating #digits before next separator. Values: | ||||
| 	 *	\xFF: no more grouping (or \x7F; defined to be CHAR_MAX in POSIX) | ||||
| 	 *	\x00: repeat previous indefinitely | ||||
| 	 *	\x**: count that many | ||||
| 	 */ | ||||
| 	char	*grouping;		/* descriptor of separator placement */ | ||||
| }; | ||||
|  | ||||
| enum{ | ||||
| 	FmtWidth	= 1, | ||||
| 	FmtLeft		= FmtWidth << 1, | ||||
| 	FmtPrec		= FmtLeft << 1, | ||||
| 	FmtSharp	= FmtPrec << 1, | ||||
| 	FmtSpace	= FmtSharp << 1, | ||||
| 	FmtSign		= FmtSpace << 1, | ||||
| 	FmtApost		= FmtSign << 1, | ||||
| 	FmtZero		= FmtApost << 1, | ||||
| 	FmtUnsigned	= FmtZero << 1, | ||||
| 	FmtShort	= FmtUnsigned << 1, | ||||
| 	FmtLong		= FmtShort << 1, | ||||
| 	FmtVLong	= FmtLong << 1, | ||||
| 	FmtComma	= FmtVLong << 1, | ||||
| 	FmtByte		= FmtComma << 1, | ||||
| 	FmtLDouble	= FmtByte << 1, | ||||
|  | ||||
| 	FmtFlag		= FmtLDouble << 1 | ||||
| }; | ||||
|  | ||||
| extern	int	(*fmtdoquote)(int); | ||||
|  | ||||
| /* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/fmt/?*.c | grep -v static |grep -v __ */ | ||||
| int		dofmt(Fmt *f, char *fmt); | ||||
| int		dorfmt(Fmt *f, const Rune *fmt); | ||||
| double		fmtcharstod(int(*f)(void*), void *vp); | ||||
| int		fmtfdflush(Fmt *f); | ||||
| int		fmtfdinit(Fmt *f, int fd, char *buf, int size); | ||||
| int		fmtinstall(int c, int (*f)(Fmt*)); | ||||
| int		fmtnullinit(Fmt*); | ||||
| void		fmtlocaleinit(Fmt*, char*, char*, char*); | ||||
| int		fmtprint(Fmt *f, char *fmt, ...); | ||||
| int		fmtrune(Fmt *f, int r); | ||||
| int		fmtrunestrcpy(Fmt *f, Rune *s); | ||||
| int		fmtstrcpy(Fmt *f, char *s); | ||||
| char*		fmtstrflush(Fmt *f); | ||||
| int		fmtstrinit(Fmt *f); | ||||
| double		fmtstrtod(const char *as, char **aas); | ||||
| int		fmtvprint(Fmt *f, char *fmt, va_list args); | ||||
| int		fprint(int fd, char *fmt, ...); | ||||
| int		print(char *fmt, ...); | ||||
| void		quotefmtinstall(void); | ||||
| int		quoterunestrfmt(Fmt *f); | ||||
| int		quotestrfmt(Fmt *f); | ||||
| Rune*		runefmtstrflush(Fmt *f); | ||||
| int		runefmtstrinit(Fmt *f); | ||||
| Rune*		runeseprint(Rune *buf, Rune *e, char *fmt, ...); | ||||
| Rune*		runesmprint(char *fmt, ...); | ||||
| int		runesnprint(Rune *buf, int len, char *fmt, ...); | ||||
| int		runesprint(Rune *buf, char *fmt, ...); | ||||
| Rune*		runevseprint(Rune *buf, Rune *e, char *fmt, va_list args); | ||||
| Rune*		runevsmprint(char *fmt, va_list args); | ||||
| int		runevsnprint(Rune *buf, int len, char *fmt, va_list args); | ||||
| char*		seprint(char *buf, char *e, char *fmt, ...); | ||||
| char*		smprint(char *fmt, ...); | ||||
| int		snprint(char *buf, int len, char *fmt, ...); | ||||
| int		sprint(char *buf, char *fmt, ...); | ||||
| int		vfprint(int fd, char *fmt, va_list args); | ||||
| char*		vseprint(char *buf, char *e, char *fmt, va_list args); | ||||
| char*		vsmprint(char *fmt, va_list args); | ||||
| int		vsnprint(char *buf, int len, char *fmt, va_list args); | ||||
|  | ||||
| #if defined(__cplusplus) | ||||
| } | ||||
| #endif | ||||
| #endif | ||||
							
								
								
									
										2
									
								
								include/lib9.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								include/lib9.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
							
								
								
									
										950
									
								
								include/libc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										950
									
								
								include/libc.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,950 @@ | ||||
| // This file originated as Plan 9's /sys/include/libc.h. | ||||
| // The plan9port-specific changes may be distributed | ||||
| // using the license in ../src/lib9/LICENSE. | ||||
|  | ||||
| /* | ||||
|  * Lib9 is miscellany from the Plan 9 C library that doesn't | ||||
|  * fit into libutf or into libfmt, but is still missing from traditional | ||||
|  * Unix C libraries. | ||||
|  */ | ||||
| #ifndef _LIBC_H_ | ||||
| #define _LIBC_H_ 1 | ||||
| #if defined(__cplusplus) | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #include <utf.h> | ||||
| #include <fmt.h> | ||||
|  | ||||
| /* | ||||
|  * Begin usual libc.h | ||||
|  */ | ||||
|  | ||||
| #ifndef nil | ||||
| #define	nil	((void*)0) | ||||
| #endif | ||||
| #define	nelem(x)	(sizeof(x)/sizeof((x)[0])) | ||||
|  | ||||
| #ifndef offsetof | ||||
| #define offsetof(s, m)	(ulong)(&(((s*)0)->m)) | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * mem routines (provided by system <string.h>) | ||||
|  * | ||||
| extern	void*	memccpy(void*, void*, int, ulong); | ||||
| extern	void*	memset(void*, int, ulong); | ||||
| extern	int	memcmp(void*, void*, ulong); | ||||
| extern	void*	memcpy(void*, void*, ulong); | ||||
| extern	void*	memmove(void*, void*, ulong); | ||||
| extern	void*	memchr(void*, int, ulong); | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * string routines (provided by system <string.h>) | ||||
|  * | ||||
| extern	char*	strcat(char*, char*); | ||||
| extern	char*	strchr(char*, int); | ||||
| extern	int	strcmp(char*, char*); | ||||
| extern	char*	strcpy(char*, char*); | ||||
|  */ | ||||
| extern	char*	strecpy(char*, char*, char*); | ||||
| extern	char*	p9strdup(char*); | ||||
| /* | ||||
| extern	char*	strncat(char*, char*, long); | ||||
| extern	char*	strncpy(char*, char*, long); | ||||
| extern	int	strncmp(char*, char*, long); | ||||
| extern	char*	strpbrk(char*, char*); | ||||
| extern	char*	strrchr(char*, int); | ||||
| extern	char*	strtok(char*, char*); | ||||
| extern	long	strlen(char*); | ||||
| extern	long	strspn(char*, char*); | ||||
| extern	long	strcspn(char*, char*); | ||||
| extern	char*	strstr(char*, char*); | ||||
|  */ | ||||
| extern	int	cistrncmp(char*, char*, int); | ||||
| extern	int	cistrcmp(char*, char*); | ||||
| extern	char*	cistrstr(char*, char*); | ||||
| extern	int	tokenize(char*, char**, int); | ||||
|  | ||||
| /* | ||||
| enum | ||||
| { | ||||
| 	UTFmax		= 4, | ||||
| 	Runesync	= 0x80, | ||||
| 	Runeself	= 0x80, | ||||
| 	Runeerror	= 0xFFFD, | ||||
| 	Runemax	= 0x10FFFF, | ||||
| }; | ||||
| */ | ||||
|  | ||||
| /* | ||||
|  * rune routines (provided by <utf.h> | ||||
|  * | ||||
| extern	int	runetochar(char*, Rune*); | ||||
| extern	int	chartorune(Rune*, char*); | ||||
| extern	int	runelen(long); | ||||
| extern	int	runenlen(Rune*, int); | ||||
| extern	int	fullrune(char*, int); | ||||
| extern	int	utflen(char*); | ||||
| extern	int	utfnlen(char*, long); | ||||
| extern	char*	utfrune(char*, long); | ||||
| extern	char*	utfrrune(char*, long); | ||||
| extern	char*	utfutf(char*, char*); | ||||
| extern	char*	utfecpy(char*, char*, char*); | ||||
|  | ||||
| extern	Rune*	runestrcat(Rune*, Rune*); | ||||
| extern	Rune*	runestrchr(Rune*, Rune); | ||||
| extern	int	runestrcmp(Rune*, Rune*); | ||||
| extern	Rune*	runestrcpy(Rune*, Rune*); | ||||
| extern	Rune*	runestrncpy(Rune*, Rune*, long); | ||||
| extern	Rune*	runestrecpy(Rune*, Rune*, Rune*); | ||||
| extern	Rune*	runestrdup(Rune*); | ||||
| extern	Rune*	runestrncat(Rune*, Rune*, long); | ||||
| extern	int	runestrncmp(Rune*, Rune*, long); | ||||
| extern	Rune*	runestrrchr(Rune*, Rune); | ||||
| extern	long	runestrlen(Rune*); | ||||
| extern	Rune*	runestrstr(Rune*, Rune*); | ||||
|  | ||||
| extern	Rune	tolowerrune(Rune); | ||||
| extern	Rune	totitlerune(Rune); | ||||
| extern	Rune	toupperrune(Rune); | ||||
| extern	int	isalpharune(Rune); | ||||
| extern	int	islowerrune(Rune); | ||||
| extern	int	isspacerune(Rune); | ||||
| extern	int	istitlerune(Rune); | ||||
| extern	int	isupperrune(Rune); | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * malloc (provied by system <stdlib.h>) | ||||
|  * | ||||
| extern	void*	malloc(ulong); | ||||
|  */ | ||||
| extern	void*	p9malloc(ulong); | ||||
| extern	void*	mallocz(ulong, int); | ||||
| extern	void	p9free(void*); | ||||
| extern	void*	p9calloc(ulong, ulong); | ||||
| extern	void*	p9realloc(void*, ulong); | ||||
| extern	void		setmalloctag(void*, ulong); | ||||
| extern	void		setrealloctag(void*, ulong); | ||||
| extern	ulong	getmalloctag(void*); | ||||
| extern	ulong	getrealloctag(void*); | ||||
| /* | ||||
| extern	void*	malloctopoolblock(void*); | ||||
| */ | ||||
| #ifndef NOPLAN9DEFINES | ||||
| #define	malloc	p9malloc | ||||
| #define	realloc	p9realloc | ||||
| #define	calloc	p9calloc | ||||
| #define	free	p9free | ||||
| #undef strdup | ||||
| #define	strdup	p9strdup | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * print routines (provided by <fmt.h>) | ||||
|  * | ||||
| typedef struct Fmt	Fmt; | ||||
| struct Fmt{ | ||||
| 	uchar	runes; | ||||
| 	void	*start; | ||||
| 	void	*to; | ||||
| 	void	*stop; | ||||
| 	int	(*flush)(Fmt *); | ||||
| 	void	*farg; | ||||
| 	int	nfmt; | ||||
| 	va_list	args; | ||||
| 	int	r; | ||||
| 	int	width; | ||||
| 	int	prec; | ||||
| 	ulong	flags; | ||||
| }; | ||||
|  | ||||
| enum{ | ||||
| 	FmtWidth	= 1, | ||||
| 	FmtLeft		= FmtWidth << 1, | ||||
| 	FmtPrec		= FmtLeft << 1, | ||||
| 	FmtSharp	= FmtPrec << 1, | ||||
| 	FmtSpace	= FmtSharp << 1, | ||||
| 	FmtSign		= FmtSpace << 1, | ||||
| 	FmtZero		= FmtSign << 1, | ||||
| 	FmtUnsigned	= FmtZero << 1, | ||||
| 	FmtShort	= FmtUnsigned << 1, | ||||
| 	FmtLong		= FmtShort << 1, | ||||
| 	FmtVLong	= FmtLong << 1, | ||||
| 	FmtComma	= FmtVLong << 1, | ||||
| 	FmtByte	= FmtComma << 1, | ||||
|  | ||||
| 	FmtFlag		= FmtByte << 1 | ||||
| }; | ||||
|  | ||||
| extern	int	print(char*, ...); | ||||
| extern	char*	seprint(char*, char*, char*, ...); | ||||
| extern	char*	vseprint(char*, char*, char*, va_list); | ||||
| extern	int	snprint(char*, int, char*, ...); | ||||
| extern	int	vsnprint(char*, int, char*, va_list); | ||||
| extern	char*	smprint(char*, ...); | ||||
| extern	char*	vsmprint(char*, va_list); | ||||
| extern	int	sprint(char*, char*, ...); | ||||
| extern	int	fprint(int, char*, ...); | ||||
| extern	int	vfprint(int, char*, va_list); | ||||
|  | ||||
| extern	int	runesprint(Rune*, char*, ...); | ||||
| extern	int	runesnprint(Rune*, int, char*, ...); | ||||
| extern	int	runevsnprint(Rune*, int, char*, va_list); | ||||
| extern	Rune*	runeseprint(Rune*, Rune*, char*, ...); | ||||
| extern	Rune*	runevseprint(Rune*, Rune*, char*, va_list); | ||||
| extern	Rune*	runesmprint(char*, ...); | ||||
| extern	Rune*	runevsmprint(char*, va_list); | ||||
|  | ||||
| extern	int	fmtfdinit(Fmt*, int, char*, int); | ||||
| extern	int	fmtfdflush(Fmt*); | ||||
| extern	int	fmtstrinit(Fmt*); | ||||
| extern	char*	fmtstrflush(Fmt*); | ||||
| extern	int	runefmtstrinit(Fmt*); | ||||
| extern	Rune*	runefmtstrflush(Fmt*); | ||||
|  | ||||
| extern	int	fmtinstall(int, int (*)(Fmt*)); | ||||
| extern	int	dofmt(Fmt*, char*); | ||||
| extern	int	dorfmt(Fmt*, Rune*); | ||||
| extern	int	fmtprint(Fmt*, char*, ...); | ||||
| extern	int	fmtvprint(Fmt*, char*, va_list); | ||||
| extern	int	fmtrune(Fmt*, int); | ||||
| extern	int	fmtstrcpy(Fmt*, char*); | ||||
| extern	int	fmtrunestrcpy(Fmt*, Rune*); | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * error string for %r | ||||
|  * supplied on per os basis, not part of fmt library | ||||
|  * | ||||
|  * (provided by lib9, but declared in fmt.h) | ||||
|  * | ||||
| extern	int	errfmt(Fmt *f); | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * quoted strings | ||||
|  */ | ||||
| extern	char	*unquotestrdup(char*); | ||||
| extern	Rune	*unquoterunestrdup(Rune*); | ||||
| extern	char	*quotestrdup(char*); | ||||
| extern	Rune	*quoterunestrdup(Rune*); | ||||
| /* | ||||
|  * in fmt.h | ||||
|  * | ||||
| extern	void	quotefmtinstall(void); | ||||
| extern	int	quotestrfmt(Fmt*); | ||||
| extern	int	quoterunestrfmt(Fmt*); | ||||
|  */ | ||||
| #ifndef NOPLAN9DEFINES | ||||
| #define doquote fmtdoquote | ||||
| #endif | ||||
| extern	int	needsrcquote(int); | ||||
|  | ||||
| /* | ||||
|  * random number | ||||
|  */ | ||||
| extern	void	p9srand(long); | ||||
| extern	int	p9rand(void); | ||||
|  | ||||
| extern	int	p9nrand(int); | ||||
| extern	long	p9lrand(void); | ||||
| extern	long	p9lnrand(long); | ||||
| extern	double	p9frand(void); | ||||
| extern	ulong	truerand(void);			/* uses /dev/random */ | ||||
| extern	ulong	ntruerand(ulong);		/* uses /dev/random */ | ||||
|  | ||||
| #ifndef NOPLAN9DEFINES | ||||
| #define	srand	p9srand | ||||
| #define	rand	p9rand | ||||
| #define	nrand	p9nrand | ||||
| #define	lrand	p9lrand | ||||
| #define	lnrand	p9lnrand | ||||
| #define	frand	p9frand | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * math | ||||
|  */ | ||||
| extern	ulong	getfcr(void); | ||||
| extern	void	setfsr(ulong); | ||||
| extern	ulong	getfsr(void); | ||||
| extern	void	setfcr(ulong); | ||||
| extern	double	NaN(void); | ||||
| extern	double	Inf(int); | ||||
| extern	int	isNaN(double); | ||||
| extern	int	isInf(double, int); | ||||
| extern	ulong	umuldiv(ulong, ulong, ulong); | ||||
| extern	long	muldiv(long, long, long); | ||||
|  | ||||
| /* | ||||
|  * provided by math.h | ||||
|  * | ||||
| extern	double	pow(double, double); | ||||
| extern	double	atan2(double, double); | ||||
| extern	double	fabs(double); | ||||
| extern	double	atan(double); | ||||
| extern	double	log(double); | ||||
| extern	double	log10(double); | ||||
| extern	double	exp(double); | ||||
| extern	double	floor(double); | ||||
| extern	double	ceil(double); | ||||
| extern	double	hypot(double, double); | ||||
| extern	double	sin(double); | ||||
| extern	double	cos(double); | ||||
| extern	double	tan(double); | ||||
| extern	double	asin(double); | ||||
| extern	double	acos(double); | ||||
| extern	double	sinh(double); | ||||
| extern	double	cosh(double); | ||||
| extern	double	tanh(double); | ||||
| extern	double	sqrt(double); | ||||
| extern	double	fmod(double, double); | ||||
| #define	HUGE	3.4028234e38 | ||||
| #define	PIO2	1.570796326794896619231e0 | ||||
| #define	PI	(PIO2+PIO2) | ||||
|  */ | ||||
| #define PI	M_PI | ||||
| #define	PIO2	M_PI_2 | ||||
|  | ||||
| /* | ||||
|  * Time-of-day | ||||
|  */ | ||||
|  | ||||
| typedef | ||||
| struct Tm | ||||
| { | ||||
| 	int	sec; | ||||
| 	int	min; | ||||
| 	int	hour; | ||||
| 	int	mday; | ||||
| 	int	mon; | ||||
| 	int	year; | ||||
| 	int	wday; | ||||
| 	int	yday; | ||||
| 	char	zone[4]; | ||||
| 	int	tzoff; | ||||
| } Tm; | ||||
|  | ||||
| extern	Tm*	p9gmtime(long); | ||||
| extern	Tm*	p9localtime(long); | ||||
| extern	char*	p9asctime(Tm*); | ||||
| extern	char*	p9ctime(long); | ||||
| extern	double	p9cputime(void); | ||||
| extern	long	p9times(long*); | ||||
| extern	long	p9tm2sec(Tm*); | ||||
| extern	vlong	p9nsec(void); | ||||
|  | ||||
| #ifndef NOPLAN9DEFINES | ||||
| #define	gmtime		p9gmtime | ||||
| #define	localtime	p9localtime | ||||
| #define	asctime		p9asctime | ||||
| #define	ctime		p9ctime | ||||
| #define	cputime		p9cputime | ||||
| #define	times		p9times | ||||
| #define	tm2sec		p9tm2sec | ||||
| #define	nsec		p9nsec | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * one-of-a-kind | ||||
|  */ | ||||
| enum | ||||
| { | ||||
| 	PNPROC		= 1, | ||||
| 	PNGROUP		= 2 | ||||
| }; | ||||
|  | ||||
| /* extern	int	abs(int); <stdlib.h> */ | ||||
| extern	int	p9atexit(void(*)(void)); | ||||
| extern	void	p9atexitdont(void(*)(void)); | ||||
| extern	int	atnotify(int(*)(void*, char*), int); | ||||
| /* | ||||
|  * <stdlib.h> | ||||
| extern	double	atof(char*); <stdlib.h> | ||||
|  */ | ||||
| extern	int	p9atoi(char*); | ||||
| extern	long	p9atol(char*); | ||||
| extern	vlong	p9atoll(char*); | ||||
| extern	double	fmtcharstod(int(*)(void*), void*); | ||||
| extern	char*	cleanname(char*); | ||||
| extern	int	p9decrypt(void*, void*, int); | ||||
| extern	int	p9encrypt(void*, void*, int); | ||||
| extern	int	netcrypt(void*, void*); | ||||
| extern	int	dec64(uchar*, int, char*, int); | ||||
| extern	int	enc64(char*, int, uchar*, int); | ||||
| extern	int	dec32(uchar*, int, char*, int); | ||||
| extern	int	enc32(char*, int, uchar*, int); | ||||
| extern	int	dec16(uchar*, int, char*, int); | ||||
| extern	int	enc16(char*, int, uchar*, int); | ||||
| extern	int	encodefmt(Fmt*); | ||||
| extern	int	dirmodefmt(Fmt*); | ||||
| extern	int	exitcode(char*); | ||||
| extern	void	exits(char*); | ||||
| extern	double	p9frexp(double, int*); | ||||
| extern	ulong	getcallerpc(void*); | ||||
| #if defined(__GNUC__) || defined(__clang__) || defined(__IBMC__) | ||||
| #define getcallerpc(x) ((ulong)__builtin_return_address(0)) | ||||
| #endif | ||||
| extern	char*	p9getenv(char*); | ||||
| extern	int	p9putenv(char*, char*); | ||||
| extern	int	getfields(char*, char**, int, int, char*); | ||||
| extern	int	gettokens(char *, char **, int, char *); | ||||
| extern	char*	getuser(void); | ||||
| extern	char*	p9getwd(char*, int); | ||||
| extern	int	iounit(int); | ||||
| /* extern	long	labs(long); <math.h> */ | ||||
| /* extern	double	ldexp(double, int); <math.h> */ | ||||
| extern	void	p9longjmp(p9jmp_buf, int); | ||||
| extern	char*	mktemp(char*); | ||||
| extern	int		opentemp(char*, int); | ||||
| /* extern	double	modf(double, double*); <math.h> */ | ||||
| extern	void	p9notejmp(void*, p9jmp_buf, int); | ||||
| extern	void	perror(const char*); | ||||
| extern	int	postnote(int, int, char *); | ||||
| extern	double	p9pow10(int); | ||||
| /* extern	int	putenv(char*, char*); <stdlib.h. */ | ||||
| /* extern	void	qsort(void*, long, long, int (*)(void*, void*)); <stdlib.h> */ | ||||
| extern	char*	searchpath(char*); | ||||
| /* extern	int	p9setjmp(p9jmp_buf); */ | ||||
| #define p9setjmp(b)	sigsetjmp((void*)(b), 1) | ||||
| /* | ||||
|  * <stdlib.h> | ||||
| extern	long	strtol(char*, char**, int); | ||||
| extern	ulong	strtoul(char*, char**, int); | ||||
| extern	vlong	strtoll(char*, char**, int); | ||||
| extern	uvlong	strtoull(char*, char**, int); | ||||
|  */ | ||||
| extern	void	sysfatal(char*, ...); | ||||
| extern	void	p9syslog(int, char*, char*, ...); | ||||
| extern	long	p9time(long*); | ||||
| /* extern	int	tolower(int); <ctype.h> */ | ||||
| /* extern	int	toupper(int); <ctype.h> */ | ||||
| extern	void	needstack(int); | ||||
| extern	char*	readcons(char*, char*, int); | ||||
|  | ||||
| extern	void	(*_pin)(void); | ||||
| extern	void	(*_unpin)(void); | ||||
|  | ||||
| #ifndef NOPLAN9DEFINES | ||||
| #define atexit		p9atexit | ||||
| #define atexitdont	p9atexitdont | ||||
| #define atoi		p9atoi | ||||
| #define atol		p9atol | ||||
| #define atoll		p9atoll | ||||
| #define encrypt		p9encrypt | ||||
| #define decrypt		p9decrypt | ||||
| #undef frexp | ||||
| #define frexp		p9frexp | ||||
| #define getenv		p9getenv | ||||
| #define	getwd		p9getwd | ||||
| #define	longjmp		p9longjmp | ||||
| #undef  setjmp | ||||
| #define setjmp		p9setjmp | ||||
| #define putenv		p9putenv | ||||
| #define notejmp		p9notejmp | ||||
| #define jmp_buf		p9jmp_buf | ||||
| #define time		p9time | ||||
| #define pow10		p9pow10 | ||||
| #define strtod		fmtstrtod | ||||
| #define charstod	fmtcharstod | ||||
| #define syslog		p9syslog | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  *  just enough information so that libc can be | ||||
|  *  properly locked without dragging in all of libthread | ||||
|  */ | ||||
| typedef struct _Thread _Thread; | ||||
| typedef struct _Threadlist _Threadlist; | ||||
| struct _Threadlist | ||||
| { | ||||
| 	_Thread	*head; | ||||
| 	_Thread	*tail; | ||||
| }; | ||||
|  | ||||
| extern	_Thread	*(*threadnow)(void); | ||||
|  | ||||
| /* | ||||
|  *  synchronization | ||||
|  */ | ||||
| typedef struct Lock Lock; | ||||
| struct Lock | ||||
| { | ||||
| 	int init; | ||||
| 	pthread_mutex_t mutex; | ||||
| 	int held; | ||||
| }; | ||||
|  | ||||
| extern	void	lock(Lock*); | ||||
| extern	void	unlock(Lock*); | ||||
| extern	int	canlock(Lock*); | ||||
| extern	int	(*_lock)(Lock*, int, ulong); | ||||
| extern	void	(*_unlock)(Lock*, ulong); | ||||
|  | ||||
| typedef struct QLock QLock; | ||||
| struct QLock | ||||
| { | ||||
| 	Lock		l; | ||||
| 	_Thread	*owner; | ||||
| 	_Threadlist	waiting; | ||||
| }; | ||||
|  | ||||
| extern	void	qlock(QLock*); | ||||
| extern	void	qunlock(QLock*); | ||||
| extern	int	canqlock(QLock*); | ||||
| extern	int	(*_qlock)(QLock*, int, ulong);	/* do not use */ | ||||
| extern	void	(*_qunlock)(QLock*, ulong); | ||||
|  | ||||
| typedef struct Rendez Rendez; | ||||
| struct Rendez | ||||
| { | ||||
| 	QLock	*l; | ||||
| 	_Threadlist	waiting; | ||||
| }; | ||||
|  | ||||
| extern	void	rsleep(Rendez*);	/* unlocks r->l, sleeps, locks r->l again */ | ||||
| extern	int	rwakeup(Rendez*); | ||||
| extern	int	rwakeupall(Rendez*); | ||||
| extern	void	(*_rsleep)(Rendez*, ulong);	/* do not use */ | ||||
| extern	int	(*_rwakeup)(Rendez*, int, ulong); | ||||
|  | ||||
| typedef struct RWLock RWLock; | ||||
| struct RWLock | ||||
| { | ||||
| 	Lock		l; | ||||
| 	int	readers; | ||||
| 	_Thread	*writer; | ||||
| 	_Threadlist	rwaiting; | ||||
| 	_Threadlist	wwaiting; | ||||
| }; | ||||
|  | ||||
| extern	void	rlock(RWLock*); | ||||
| extern	void	runlock(RWLock*); | ||||
| extern	int		canrlock(RWLock*); | ||||
| extern	void	wlock(RWLock*); | ||||
| extern	void	wunlock(RWLock*); | ||||
| extern	int		canwlock(RWLock*); | ||||
| extern	int	(*_rlock)(RWLock*, int, ulong);	/* do not use */ | ||||
| extern	int	(*_wlock)(RWLock*, int, ulong); | ||||
| extern	void	(*_runlock)(RWLock*, ulong); | ||||
| extern	void	(*_wunlock)(RWLock*, ulong); | ||||
|  | ||||
| /* | ||||
|  * per-process private data | ||||
|  */ | ||||
| extern	void**	privalloc(void); | ||||
| extern	void	privfree(void**); | ||||
|  | ||||
| /* | ||||
|  *  network dialing | ||||
|  */ | ||||
| #define NETPATHLEN 40 | ||||
| extern	int	p9accept(int, char*); | ||||
| extern	int	p9announce(char*, char*); | ||||
| extern	int	p9dial(char*, char*, char*, int*); | ||||
| extern	int	p9dialparse(char *ds, char **net, char **unixa, void *ip, int *port); | ||||
| extern	void	p9setnetmtpt(char*, int, char*); | ||||
| extern	int	p9listen(char*, char*); | ||||
| extern	char*	p9netmkaddr(char*, char*, char*); | ||||
| extern	int	p9reject(int, char*, char*); | ||||
|  | ||||
| #ifndef NOPLAN9DEFINES | ||||
| #define	accept		p9accept | ||||
| #define	announce	p9announce | ||||
| #define	dial		p9dial | ||||
| #define	setnetmtpt	p9setnetmtpt | ||||
| #define	listen		p9listen | ||||
| #define	netmkaddr	p9netmkaddr | ||||
| #define	reject		p9reject | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  *  encryption | ||||
|  */ | ||||
| extern	int	pushssl(int, char*, char*, char*, int*); | ||||
| extern	int	pushtls(int, char*, char*, int, char*, char*); | ||||
|  | ||||
| /* | ||||
|  *  network services | ||||
|  */ | ||||
| typedef struct NetConnInfo NetConnInfo; | ||||
| struct NetConnInfo | ||||
| { | ||||
| 	char	*dir;		/* connection directory */ | ||||
| 	char	*root;		/* network root */ | ||||
| 	char	*spec;		/* binding spec */ | ||||
| 	char	*lsys;		/* local system */ | ||||
| 	char	*lserv;		/* local service */ | ||||
| 	char	*rsys;		/* remote system */ | ||||
| 	char	*rserv;		/* remote service */ | ||||
| 	char *laddr; | ||||
| 	char *raddr; | ||||
| }; | ||||
| extern	NetConnInfo*	getnetconninfo(char*, int); | ||||
| extern	void		freenetconninfo(NetConnInfo*); | ||||
|  | ||||
| /* | ||||
|  * system calls | ||||
|  * | ||||
|  */ | ||||
| #define	STATMAX	65535U	/* max length of machine-independent stat structure */ | ||||
| #define	DIRMAX	(sizeof(Dir)+STATMAX)	/* max length of Dir structure */ | ||||
| #define	ERRMAX	128	/* max length of error string */ | ||||
|  | ||||
| #define	MORDER	0x0003	/* mask for bits defining order of mounting */ | ||||
| #define	MREPL	0x0000	/* mount replaces object */ | ||||
| #define	MBEFORE	0x0001	/* mount goes before others in union directory */ | ||||
| #define	MAFTER	0x0002	/* mount goes after others in union directory */ | ||||
| #define	MCREATE	0x0004	/* permit creation in mounted directory */ | ||||
| #define	MCACHE	0x0010	/* cache some data */ | ||||
| #define	MMASK	0x0017	/* all bits on */ | ||||
|  | ||||
| #define	OREAD	0	/* open for read */ | ||||
| #define	OWRITE	1	/* write */ | ||||
| #define	ORDWR	2	/* read and write */ | ||||
| #define	OEXEC	3	/* execute, == read but check execute permission */ | ||||
| #define	OTRUNC	16	/* or'ed in (except for exec), truncate file first */ | ||||
| #define	OCEXEC	32	/* or'ed in, close on exec */ | ||||
| #define	ORCLOSE	64	/* or'ed in, remove on close */ | ||||
| #define	ODIRECT	128	/* or'ed in, direct access */ | ||||
| #define	ONONBLOCK 256	/* or'ed in, non-blocking call */ | ||||
| #define	OEXCL	0x1000	/* or'ed in, exclusive use (create only) */ | ||||
| #define	OLOCK	0x2000	/* or'ed in, lock after opening */ | ||||
| #define	OAPPEND	0x4000	/* or'ed in, append only */ | ||||
|  | ||||
| #define	AEXIST	0	/* accessible: exists */ | ||||
| #define	AEXEC	1	/* execute access */ | ||||
| #define	AWRITE	2	/* write access */ | ||||
| #define	AREAD	4	/* read access */ | ||||
|  | ||||
| /* Segattch */ | ||||
| #define	SG_RONLY	0040	/* read only */ | ||||
| #define	SG_CEXEC	0100	/* detach on exec */ | ||||
|  | ||||
| #define	NCONT	0	/* continue after note */ | ||||
| #define	NDFLT	1	/* terminate after note */ | ||||
| #define	NSAVE	2	/* clear note but hold state */ | ||||
| #define	NRSTR	3	/* restore saved state */ | ||||
|  | ||||
| /* bits in Qid.type */ | ||||
| #define QTDIR		0x80		/* type bit for directories */ | ||||
| #define QTAPPEND	0x40		/* type bit for append only files */ | ||||
| #define QTEXCL		0x20		/* type bit for exclusive use files */ | ||||
| #define QTMOUNT		0x10		/* type bit for mounted channel */ | ||||
| #define QTAUTH		0x08		/* type bit for authentication file */ | ||||
| #define QTTMP		0x04		/* type bit for non-backed-up file */ | ||||
| #define QTSYMLINK	0x02		/* type bit for symbolic link */ | ||||
| #define QTFILE		0x00		/* type bits for plain file */ | ||||
|  | ||||
| /* bits in Dir.mode */ | ||||
| #define DMDIR		0x80000000	/* mode bit for directories */ | ||||
| #define DMAPPEND	0x40000000	/* mode bit for append only files */ | ||||
| #define DMEXCL		0x20000000	/* mode bit for exclusive use files */ | ||||
| #define DMMOUNT		0x10000000	/* mode bit for mounted channel */ | ||||
| #define DMAUTH		0x08000000	/* mode bit for authentication file */ | ||||
| #define DMTMP		0x04000000	/* mode bit for non-backed-up file */ | ||||
| #define DMSYMLINK	0x02000000	/* mode bit for symbolic link (Unix, 9P2000.u) */ | ||||
| #define DMDEVICE	0x00800000	/* mode bit for device file (Unix, 9P2000.u) */ | ||||
| #define DMNAMEDPIPE	0x00200000	/* mode bit for named pipe (Unix, 9P2000.u) */ | ||||
| #define DMSOCKET	0x00100000	/* mode bit for socket (Unix, 9P2000.u) */ | ||||
| #define DMSETUID	0x00080000	/* mode bit for setuid (Unix, 9P2000.u) */ | ||||
| #define DMSETGID	0x00040000	/* mode bit for setgid (Unix, 9P2000.u) */ | ||||
|  | ||||
| #define DMREAD		0x4		/* mode bit for read permission */ | ||||
| #define DMWRITE		0x2		/* mode bit for write permission */ | ||||
| #define DMEXEC		0x1		/* mode bit for execute permission */ | ||||
|  | ||||
| #ifdef RFMEM	/* FreeBSD, OpenBSD */ | ||||
| #undef RFFDG | ||||
| #undef RFNOTEG | ||||
| #undef RFPROC | ||||
| #undef RFMEM | ||||
| #undef RFNOWAIT | ||||
| #undef RFCFDG | ||||
| #undef RFNAMEG | ||||
| #undef RFENVG | ||||
| #undef RFCENVG | ||||
| #undef RFCFDG | ||||
| #undef RFCNAMEG | ||||
| #endif | ||||
|  | ||||
| enum | ||||
| { | ||||
| 	RFNAMEG		= (1<<0), | ||||
| 	RFENVG		= (1<<1), | ||||
| 	RFFDG		= (1<<2), | ||||
| 	RFNOTEG		= (1<<3), | ||||
| 	RFPROC		= (1<<4), | ||||
| 	RFMEM		= (1<<5), | ||||
| 	RFNOWAIT	= (1<<6), | ||||
| 	RFCNAMEG	= (1<<10), | ||||
| 	RFCENVG		= (1<<11), | ||||
| 	RFCFDG		= (1<<12) | ||||
| /*	RFREND		= (1<<13), */ | ||||
| /*	RFNOMNT		= (1<<14) */ | ||||
| }; | ||||
|  | ||||
| typedef | ||||
| struct Qid | ||||
| { | ||||
| 	uvlong	path; | ||||
| 	ulong	vers; | ||||
| 	uchar	type; | ||||
| } Qid; | ||||
|  | ||||
| typedef | ||||
| struct Dir { | ||||
| 	/* system-modified data */ | ||||
| 	ushort	type;	/* server type */ | ||||
| 	uint	dev;	/* server subtype */ | ||||
| 	/* file data */ | ||||
| 	Qid	qid;	/* unique id from server */ | ||||
| 	ulong	mode;	/* permissions */ | ||||
| 	ulong	atime;	/* last read time */ | ||||
| 	ulong	mtime;	/* last write time */ | ||||
| 	vlong	length;	/* file length */ | ||||
| 	char	*name;	/* last element of path */ | ||||
| 	char	*uid;	/* owner name */ | ||||
| 	char	*gid;	/* group name */ | ||||
| 	char	*muid;	/* last modifier name */ | ||||
|  | ||||
| 	/* 9P2000.u extensions */ | ||||
| 	uint	uidnum;		/* numeric uid */ | ||||
| 	uint	gidnum;		/* numeric gid */ | ||||
| 	uint	muidnum;	/* numeric muid */ | ||||
| 	char	*ext;		/* extended info */ | ||||
| } Dir; | ||||
|  | ||||
| /* keep /sys/src/ape/lib/ap/plan9/sys9.h in sync with this -rsc */ | ||||
| typedef | ||||
| struct Waitmsg | ||||
| { | ||||
| 	int pid;	/* of loved one */ | ||||
| 	ulong time[3];	/* of loved one & descendants */ | ||||
| 	char	*msg; | ||||
| } Waitmsg; | ||||
|  | ||||
| typedef | ||||
| struct IOchunk | ||||
| { | ||||
| 	void	*addr; | ||||
| 	ulong	len; | ||||
| } IOchunk; | ||||
|  | ||||
| extern	void	_exits(char*); | ||||
|  | ||||
| extern	void	abort(void); | ||||
| /* extern	int	access(char*, int); */ | ||||
| extern	long	p9alarm(ulong); | ||||
| extern	int	await(char*, int); | ||||
| extern	int	awaitfor(int, char*, int); | ||||
| extern	int	awaitnohang(char*, int); | ||||
| /* extern	int	bind(char*, char*, int); give up */ | ||||
| /* extern	int	brk(void*); <unistd.h> */ | ||||
| extern	int	p9chdir(char*); | ||||
| extern	int	p9close(int); | ||||
| extern	int	p9create(char*, int, ulong); | ||||
| extern	int	p9dup(int, int); | ||||
| extern	int	errstr(char*, uint); | ||||
| extern	int	p9exec(char*, char*[]); | ||||
| extern	int	p9execl(char*, ...); | ||||
| /* extern	int	p9fork(void); */ | ||||
| extern	int	p9rfork(int); | ||||
| /* not implemented | ||||
| extern	int	fauth(int, char*); | ||||
| extern	int	fstat(int, uchar*, int); | ||||
| extern	int	fwstat(int, uchar*, int); | ||||
| extern	int	fversion(int, int, char*, int); | ||||
| extern	int	mount(int, int, char*, int, char*); | ||||
| extern	int	unmount(char*, char*); | ||||
| */ | ||||
| extern	int	noted(int); | ||||
| extern	int	notify(void(*)(void*, char*)); | ||||
| extern	int	noteenable(char*); | ||||
| extern	int	notedisable(char*); | ||||
| extern	int	notifyon(char*); | ||||
| extern	int	notifyoff(char*); | ||||
| extern	int	p9open(char*, int); | ||||
| extern	int	fd2path(int, char*, int); | ||||
| extern	int	p9pipe(int*); | ||||
| /* | ||||
|  * use defs from <unistd.h> | ||||
| extern	long	pread(int, void*, long, vlong); | ||||
| extern	long	preadv(int, IOchunk*, int, vlong); | ||||
| extern	long	pwrite(int, void*, long, vlong); | ||||
| extern	long	pwritev(int, IOchunk*, int, vlong); | ||||
| extern	long	read(int, void*, long); | ||||
|  */ | ||||
| extern	long	readn(int, void*, long); | ||||
| /* extern	long	readv(int, IOchunk*, int); <unistd.h> */ | ||||
| extern	int	remove(const char*); | ||||
| /* extern	void*	sbrk(ulong); <unistd.h> */ | ||||
| /* extern	long	oseek(int, long, int); */ | ||||
| extern	vlong	p9seek(int, vlong, int); | ||||
| /* give up | ||||
| extern	long	segattach(int, char*, void*, ulong); | ||||
| extern	int	segbrk(void*, void*); | ||||
| extern	int	segdetach(void*); | ||||
| extern	int	segflush(void*, ulong); | ||||
| extern	int	segfree(void*, ulong); | ||||
| */ | ||||
| extern	int	p9sleep(long); | ||||
| /* extern	int	stat(char*, uchar*, int); give up */ | ||||
| extern	Waitmsg*	p9wait(void); | ||||
| extern	Waitmsg*	p9waitfor(int); | ||||
| extern	Waitmsg*	waitnohang(void); | ||||
| extern	int	p9waitpid(void); | ||||
| /* <unistd.h> | ||||
| extern	long	write(int, void*, long); | ||||
| extern	long	writev(int, IOchunk*, int); | ||||
| */ | ||||
| extern	long	p9write(int, void*, long); | ||||
| /* extern	int	wstat(char*, uchar*, int); give up */ | ||||
| extern	ulong	rendezvous(ulong, ulong); | ||||
|  | ||||
| #ifndef NOPLAN9DEFINES | ||||
| #define alarm		p9alarm | ||||
| #define	dup		p9dup | ||||
| #define	exec		p9exec | ||||
| #define	execl	p9execl | ||||
| #define	seek		p9seek | ||||
| #define sleep		p9sleep | ||||
| #define wait		p9wait | ||||
| #define waitpid		p9waitpid | ||||
| /* #define fork		p9fork */ | ||||
| #define rfork		p9rfork | ||||
| /* #define access		p9access */ | ||||
| #define create		p9create | ||||
| #undef open | ||||
| #define open		p9open | ||||
| #undef close | ||||
| #define close		p9close | ||||
| #define pipe		p9pipe | ||||
| #define	waitfor		p9waitfor | ||||
| #define write		p9write | ||||
| #endif | ||||
|  | ||||
| extern	Dir*	dirstat(char*); | ||||
| extern	Dir*	dirfstat(int); | ||||
| extern	int	dirwstat(char*, Dir*); | ||||
| extern	int	dirfwstat(int, Dir*); | ||||
| extern	long	dirread(int, Dir**); | ||||
| extern	void	nulldir(Dir*); | ||||
| extern	long	dirreadall(int, Dir**); | ||||
| /* extern	int	getpid(void); <unistd.h> */ | ||||
| /* extern	int	getppid(void); */ | ||||
| extern	void	rerrstr(char*, uint); | ||||
| extern	char*	sysname(void); | ||||
| extern	void	werrstr(char*, ...); | ||||
| extern	char*	getns(void); | ||||
| extern	char*	get9root(void); | ||||
| extern	char*	unsharp(char*); | ||||
| extern	int	sendfd(int, int); | ||||
| extern	int	recvfd(int); | ||||
| extern	int	post9pservice(int, char*, char*); | ||||
| extern	int	chattyfuse; | ||||
|  | ||||
| /* external names that we don't want to step on */ | ||||
| #ifndef NOPLAN9DEFINES | ||||
| #define main	p9main | ||||
| #endif | ||||
|  | ||||
| #ifdef VARARGCK | ||||
| #pragma	varargck	type	"lld"	vlong | ||||
| #pragma	varargck	type	"llx"	vlong | ||||
| #pragma	varargck	type	"lld"	uvlong | ||||
| #pragma	varargck	type	"llx"	uvlong | ||||
| #pragma	varargck	type	"ld"	long | ||||
| #pragma	varargck	type	"lx"	long | ||||
| #pragma	varargck	type	"ld"	ulong | ||||
| #pragma	varargck	type	"lx"	ulong | ||||
| #pragma	varargck	type	"d"	int | ||||
| #pragma	varargck	type	"x"	int | ||||
| #pragma	varargck	type	"c"	int | ||||
| #pragma	varargck	type	"C"	int | ||||
| #pragma	varargck	type	"d"	uint | ||||
| #pragma	varargck	type	"x"	uint | ||||
| #pragma	varargck	type	"c"	uint | ||||
| #pragma	varargck	type	"C"	uint | ||||
| #pragma	varargck	type	"f"	double | ||||
| #pragma	varargck	type	"e"	double | ||||
| #pragma	varargck	type	"g"	double | ||||
| #pragma	varargck	type	"lf"	long double | ||||
| #pragma	varargck	type	"le"	long double | ||||
| #pragma	varargck	type	"lg"	long double | ||||
| #pragma	varargck	type	"s"	char* | ||||
| #pragma	varargck	type	"q"	char* | ||||
| #pragma	varargck	type	"S"	Rune* | ||||
| #pragma	varargck	type	"Q"	Rune* | ||||
| #pragma	varargck	type	"r"	void | ||||
| #pragma	varargck	type	"%"	void | ||||
| #pragma	varargck	type	"n"	int* | ||||
| #pragma	varargck	type	"p"	void* | ||||
| #pragma	varargck	type	"<"	void* | ||||
| #pragma	varargck	type	"["	void* | ||||
| #pragma	varargck	type	"H"	void* | ||||
| #pragma	varargck	type	"lH"	void* | ||||
|  | ||||
| #pragma	varargck	flag	' ' | ||||
| #pragma	varargck	flag	'#' | ||||
| #pragma	varargck	flag	'+' | ||||
| #pragma	varargck	flag	',' | ||||
| #pragma	varargck	flag	'-' | ||||
| #pragma	varargck	flag	'u' | ||||
|  | ||||
| #pragma	varargck	argpos	fmtprint	2 | ||||
| #pragma	varargck	argpos	fprint	2 | ||||
| #pragma	varargck	argpos	print	1 | ||||
| #pragma	varargck	argpos	runeseprint	3 | ||||
| #pragma	varargck	argpos	runesmprint	1 | ||||
| #pragma	varargck	argpos	runesnprint	3 | ||||
| #pragma	varargck	argpos	runesprint	2 | ||||
| #pragma	varargck	argpos	seprint	3 | ||||
| #pragma	varargck	argpos	smprint	1 | ||||
| #pragma	varargck	argpos	snprint	3 | ||||
| #pragma	varargck	argpos	sprint	2 | ||||
| #pragma	varargck	argpos	sysfatal	1 | ||||
| #pragma	varargck	argpos	p9syslog	3 | ||||
| #pragma	varargck	argpos	werrstr	1 | ||||
| #endif | ||||
|  | ||||
| /* compiler directives on plan 9 */ | ||||
| #define	SET(x)	((x)=0) | ||||
| #define	USED(x)	if(x){}else{} | ||||
| #ifdef __GNUC__ | ||||
| #	if __GNUC__ >= 3 | ||||
| #		undef USED | ||||
| #		define USED(x) ((void)(x)) | ||||
| #	endif | ||||
| #endif | ||||
|  | ||||
| /* command line */ | ||||
| extern char	*argv0; | ||||
| extern void __fixargv0(void); | ||||
| #define	ARGBEGIN	for((argv0?0:(argv0=(__fixargv0(),*argv))),argv++,argc--;\ | ||||
| 			    argv[0] && argv[0][0]=='-' && argv[0][1];\ | ||||
| 			    argc--, argv++) {\ | ||||
| 				char *_args, *_argt;\ | ||||
| 				Rune _argc;\ | ||||
| 				_args = &argv[0][1];\ | ||||
| 				if(_args[0]=='-' && _args[1]==0){\ | ||||
| 					argc--; argv++; break;\ | ||||
| 				}\ | ||||
| 				_argc = 0;\ | ||||
| 				while(*_args && (_args += chartorune(&_argc, _args)))\ | ||||
| 				switch(_argc) | ||||
| #define	ARGEND		SET(_argt);USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc); | ||||
| #define	ARGF()		(_argt=_args, _args="",\ | ||||
| 				(*_argt? _argt: argv[1]? (argc--, *++argv): 0)) | ||||
| #define	EARGF(x)	(_argt=_args, _args="",\ | ||||
| 				(*_argt? _argt: argv[1]? (argc--, *++argv): ((x), abort(), (char*)0))) | ||||
|  | ||||
| #define	ARGC()		_argc | ||||
|  | ||||
| #if defined(__cplusplus) | ||||
| } | ||||
| #endif | ||||
| #endif	/* _LIB9_H_ */ | ||||
							
								
								
									
										195
									
								
								include/u.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								include/u.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,195 @@ | ||||
| // See ../src/lib9/LICENSE | ||||
|  | ||||
| #ifndef _U_H_ | ||||
| #define _U_H_ 1 | ||||
| #if defined(__cplusplus) | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #define HAS_SYS_TERMIOS 1 | ||||
|  | ||||
| #define __BSD_VISIBLE 1 /* FreeBSD 5.x */ | ||||
| #if defined(__sun__) | ||||
| #	define __EXTENSIONS__ 1 /* SunOS */ | ||||
| #	if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5_8__) || defined(__SunOS5_9__) || defined(__SunOS5_10__) | ||||
| 		/* NOT USING #define __MAKECONTEXT_V2_SOURCE 1 / * SunOS */ | ||||
| #	else | ||||
| 		/* What's left? */ | ||||
| #		define __MAKECONTEXT_V2_SOURCE 1 | ||||
| #	endif | ||||
| #endif | ||||
| #define _BSD_SOURCE 1 | ||||
| #define _NETBSD_SOURCE 1	/* NetBSD */ | ||||
| #define _SVID_SOURCE 1 | ||||
| #define _DEFAULT_SOURCE 1 | ||||
| #if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__AIX__) | ||||
| #	define _XOPEN_SOURCE 1000 | ||||
| #	define _XOPEN_SOURCE_EXTENDED 1 | ||||
| #endif | ||||
| #if defined(__FreeBSD__) | ||||
| #	include <sys/cdefs.h> | ||||
| 	/* for strtoll */ | ||||
| #	undef __ISO_C_VISIBLE | ||||
| #	define __ISO_C_VISIBLE 1999 | ||||
| #	undef __LONG_LONG_SUPPORTED | ||||
| #	define __LONG_LONG_SUPPORTED | ||||
| #endif | ||||
| #if defined(__AIX__) | ||||
| #	define _ALL_SOURCE | ||||
| #	undef HAS_SYS_TERMIOS | ||||
| #endif | ||||
| #define _LARGEFILE64_SOURCE 1 | ||||
| #define _FILE_OFFSET_BITS 64 | ||||
|  | ||||
| #include <inttypes.h> | ||||
|  | ||||
| #include <unistd.h> | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdarg.h> | ||||
| #include <fcntl.h> | ||||
| #include <assert.h> | ||||
| #include <setjmp.h> | ||||
| #include <stddef.h> | ||||
| #include <math.h> | ||||
| #include <ctype.h>	/* for tolower */ | ||||
|  | ||||
| /* | ||||
|  * OS-specific crap | ||||
|  */ | ||||
| #define _NEEDUCHAR 1 | ||||
| #define _NEEDUSHORT 1 | ||||
| #define _NEEDUINT 1 | ||||
| #define _NEEDULONG 1 | ||||
|  | ||||
| typedef long p9jmp_buf[sizeof(sigjmp_buf)/sizeof(long)]; | ||||
|  | ||||
| #if defined(__linux__) | ||||
| #	include <sys/types.h> | ||||
| #	include <pthread.h> | ||||
| #	if defined(__USE_MISC) | ||||
| #		undef _NEEDUSHORT | ||||
| #		undef _NEEDUINT | ||||
| #		undef _NEEDULONG | ||||
| #	endif | ||||
| #elif defined(__sun__) | ||||
| #	include <sys/types.h> | ||||
| #	include <pthread.h> | ||||
| #	undef _NEEDUSHORT | ||||
| #	undef _NEEDUINT | ||||
| #	undef _NEEDULONG | ||||
| #	define nil 0	/* no cast to void* */ | ||||
| #elif defined(__FreeBSD__) | ||||
| #	include <sys/types.h> | ||||
| #	include <osreldate.h> | ||||
| #	include <pthread.h> | ||||
| #	if !defined(_POSIX_SOURCE) | ||||
| #		undef _NEEDUSHORT | ||||
| #		undef _NEEDUINT | ||||
| #	endif | ||||
| #elif defined(__APPLE__) | ||||
| #	include <sys/types.h> | ||||
| #	include <pthread.h> | ||||
| #	if __GNUC__ < 4 | ||||
| #		undef _NEEDUSHORT | ||||
| #		undef _NEEDUINT | ||||
| #	endif | ||||
| #	undef _ANSI_SOURCE | ||||
| #	undef _POSIX_C_SOURCE | ||||
| #	undef _XOPEN_SOURCE | ||||
| #	if !defined(NSIG) | ||||
| #		define NSIG 32 | ||||
| #	endif | ||||
| #	define _NEEDLL 1 | ||||
| #elif defined(__NetBSD__) | ||||
| #	include <sched.h> | ||||
| #	include <sys/types.h> | ||||
| #	include <pthread.h> | ||||
| #	undef _NEEDUSHORT | ||||
| #	undef _NEEDUINT | ||||
| #	undef _NEEDULONG | ||||
| #elif defined(__OpenBSD__) | ||||
| #	include <sys/types.h> | ||||
| #	include <pthread.h> | ||||
| #	undef _NEEDUSHORT | ||||
| #	undef _NEEDUINT | ||||
| #	undef _NEEDULONG | ||||
| #else | ||||
| 	/* No idea what system this is -- try some defaults */ | ||||
| #	include <pthread.h> | ||||
| #endif | ||||
|  | ||||
| #ifndef O_DIRECT | ||||
| #define O_DIRECT 0 | ||||
| #endif | ||||
|  | ||||
| typedef signed char schar; | ||||
|  | ||||
| #ifdef _NEEDUCHAR | ||||
| 	typedef unsigned char uchar; | ||||
| #endif | ||||
| #ifdef _NEEDUSHORT | ||||
| 	typedef unsigned short ushort; | ||||
| #endif | ||||
| #ifdef _NEEDUINT | ||||
| 	typedef unsigned int uint; | ||||
| #endif | ||||
| #ifdef _NEEDULONG | ||||
| 	typedef unsigned long ulong; | ||||
| #endif | ||||
| typedef unsigned long long uvlong; | ||||
| typedef long long vlong; | ||||
|  | ||||
| typedef uvlong u64int; | ||||
| typedef vlong s64int; | ||||
| typedef uint8_t u8int; | ||||
| typedef int8_t s8int; | ||||
| typedef uint16_t u16int; | ||||
| typedef int16_t s16int; | ||||
| typedef uintptr_t uintptr; | ||||
| typedef intptr_t intptr; | ||||
| typedef uint u32int; | ||||
| typedef int s32int; | ||||
|  | ||||
| typedef u32int uint32; | ||||
| typedef s32int int32; | ||||
| typedef u16int uint16; | ||||
| typedef s16int int16; | ||||
| typedef u64int uint64; | ||||
| typedef s64int int64; | ||||
| typedef u8int uint8; | ||||
| typedef s8int int8; | ||||
|  | ||||
| #undef _NEEDUCHAR | ||||
| #undef _NEEDUSHORT | ||||
| #undef _NEEDUINT | ||||
| #undef _NEEDULONG | ||||
|  | ||||
| /* | ||||
|  * Funny-named symbols to tip off 9l to autolink. | ||||
|  */ | ||||
| #define AUTOLIB(x)	static int __p9l_autolib_ ## x = 1; | ||||
| #define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x = 1; | ||||
|  | ||||
| /* | ||||
|  * Gcc is too smart for its own good. | ||||
|  */ | ||||
| #if defined(__GNUC__) | ||||
| #	undef strcmp	/* causes way too many warnings */ | ||||
| #	if __GNUC__ >= 4 || (__GNUC__==3 && !defined(__APPLE_CC__)) | ||||
| #		undef AUTOLIB | ||||
| #		define AUTOLIB(x) int __p9l_autolib_ ## x __attribute__ ((weak)); | ||||
| #		undef AUTOFRAMEWORK | ||||
| #		define AUTOFRAMEWORK(x) int __p9l_autoframework_ ## x __attribute__ ((weak)); | ||||
| #	else | ||||
| #		undef AUTOLIB | ||||
| #		define AUTOLIB(x) static int __p9l_autolib_ ## x __attribute__ ((unused)); | ||||
| #		undef AUTOFRAMEWORK | ||||
| #		define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x __attribute__ ((unused)); | ||||
| #	endif | ||||
| #endif | ||||
|  | ||||
| #if defined(__cplusplus) | ||||
| } | ||||
| #endif | ||||
| #endif | ||||
							
								
								
									
										54
									
								
								include/utf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								include/utf.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| #ifndef _UTF_H_ | ||||
| #define _UTF_H_ 1 | ||||
| #if defined(__cplusplus) | ||||
| extern "C" {  | ||||
| #endif | ||||
|  | ||||
| typedef unsigned int Rune;	/* 32 bits */ | ||||
|  | ||||
| enum | ||||
| { | ||||
| 	UTFmax		= 4,		/* maximum bytes per rune */ | ||||
| 	Runesync	= 0x80,		/* cannot represent part of a UTF sequence (<) */ | ||||
| 	Runeself	= 0x80,		/* rune and UTF sequences are the same (<) */ | ||||
| 	Runeerror	= 0xFFFD,	/* decoding error in UTF */ | ||||
| 	Runemax = 0x10FFFF	/* maximum rune value */ | ||||
| }; | ||||
|  | ||||
| /* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/utf/?*.c | grep -v static |grep -v __ */ | ||||
| int		chartorune(Rune *rune, char *str); | ||||
| int		fullrune(char *str, int n); | ||||
| int		isalpharune(Rune c); | ||||
| int		islowerrune(Rune c); | ||||
| int		isspacerune(Rune c); | ||||
| int		istitlerune(Rune c); | ||||
| int		isupperrune(Rune c); | ||||
| int		runelen(long c); | ||||
| int		runenlen(Rune *r, int nrune); | ||||
| Rune*		runestrcat(Rune *s1, Rune *s2); | ||||
| Rune*		runestrchr(Rune *s, Rune c); | ||||
| int		runestrcmp(Rune *s1, Rune *s2); | ||||
| Rune*		runestrcpy(Rune *s1, Rune *s2); | ||||
| Rune*		runestrdup(Rune *s) ; | ||||
| Rune*		runestrecpy(Rune *s1, Rune *es1, Rune *s2); | ||||
| long		runestrlen(Rune *s); | ||||
| Rune*		runestrncat(Rune *s1, Rune *s2, long n); | ||||
| int		runestrncmp(Rune *s1, Rune *s2, long n); | ||||
| Rune*		runestrncpy(Rune *s1, Rune *s2, long n); | ||||
| Rune*		runestrrchr(Rune *s, Rune c); | ||||
| Rune*		runestrstr(Rune *s1, Rune *s2); | ||||
| int		runetochar(char *str, Rune *rune); | ||||
| Rune		tolowerrune(Rune c); | ||||
| Rune		totitlerune(Rune c); | ||||
| Rune		toupperrune(Rune c); | ||||
| char*		utfecpy(char *to, char *e, char *from); | ||||
| int		utflen(char *s); | ||||
| int		utfnlen(char *s, long m); | ||||
| char*		utfrrune(char *s, long c); | ||||
| char*		utfrune(char *s, long c); | ||||
| char*		utfutf(char *s1, char *s2); | ||||
|  | ||||
| #if defined(__cplusplus) | ||||
| } | ||||
| #endif | ||||
| #endif | ||||
							
								
								
									
										12
									
								
								lib/bio/_lib9.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								lib/bio/_lib9.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| #include <fmt.h> | ||||
| #include <fcntl.h> | ||||
| #include	<string.h> | ||||
| #include	<unistd.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| #define OREAD O_RDONLY | ||||
| #define OWRITE O_WRONLY | ||||
|  | ||||
| #include <utf.h> | ||||
|  | ||||
| #define nil ((void*)0) | ||||
							
								
								
									
										20
									
								
								lib/bio/bbuffered.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								lib/bio/bbuffered.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| #include	"lib9.h" | ||||
| #include	<bio.h> | ||||
|  | ||||
| int | ||||
| Bbuffered(Biobuf *bp) | ||||
| { | ||||
| 	switch(bp->state) { | ||||
| 	case Bracteof: | ||||
| 	case Bractive: | ||||
| 		return -bp->icount; | ||||
|  | ||||
| 	case Bwactive: | ||||
| 		return bp->bsize + bp->ocount; | ||||
|  | ||||
| 	case Binactive: | ||||
| 		return 0; | ||||
| 	} | ||||
| 	fprint(2, "Bbuffered: unknown state %d\n", bp->state); | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										46
									
								
								lib/bio/bcat.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								lib/bio/bcat.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| #include <fmt.h> | ||||
| #include "bio.h" | ||||
|  | ||||
| Biobuf bout; | ||||
|  | ||||
| void | ||||
| bcat(Biobuf *b, char *name) | ||||
| { | ||||
| 	char buf[1000]; | ||||
| 	int n; | ||||
|  | ||||
| 	while((n = Bread(b, buf, sizeof buf)) > 0){ | ||||
| 		if(Bwrite(&bout, buf, n) < 0) | ||||
| 			fprint(2, "writing during %s: %r\n", name); | ||||
| 	} | ||||
| 	if(n < 0) | ||||
| 		fprint(2, "reading %s: %r\n", name); | ||||
| } | ||||
|  | ||||
| int | ||||
| main(int argc, char **argv) | ||||
| { | ||||
| 	int i; | ||||
| 	Biobuf b, *bp; | ||||
| 	Fmt fmt; | ||||
|  | ||||
| 	Binit(&bout, 1, O_WRONLY); | ||||
| 	Bfmtinit(&fmt, &bout); | ||||
| 	fmtprint(&fmt, "hello, world\n"); | ||||
| 	Bfmtflush(&fmt); | ||||
|  | ||||
| 	if(argc == 1){ | ||||
| 		Binit(&b, 0, O_RDONLY); | ||||
| 		bcat(&b, "<stdin>"); | ||||
| 	}else{ | ||||
| 		for(i=1; i<argc; i++){ | ||||
| 			if((bp = Bopen(argv[i], O_RDONLY)) == 0){ | ||||
| 				fprint(2, "Bopen %s: %r\n", argv[i]); | ||||
| 				continue; | ||||
| 			} | ||||
| 			bcat(bp, argv[i]); | ||||
| 			Bterm(bp); | ||||
| 		} | ||||
| 	} | ||||
| 	exit(0); | ||||
| } | ||||
							
								
								
									
										9
									
								
								lib/bio/bfildes.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								lib/bio/bfildes.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| #include	"lib9.h" | ||||
| #include	<bio.h> | ||||
|  | ||||
| int | ||||
| Bfildes(Biobuf *bp) | ||||
| { | ||||
|  | ||||
| 	return bp->fid; | ||||
| } | ||||
							
								
								
									
										33
									
								
								lib/bio/bflush.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								lib/bio/bflush.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| #include	"lib9.h" | ||||
| #include	<bio.h> | ||||
|  | ||||
| int | ||||
| Bflush(Biobuf *bp) | ||||
| { | ||||
| 	int n, c; | ||||
|  | ||||
| 	switch(bp->state) { | ||||
| 	case Bwactive: | ||||
| 		n = bp->bsize+bp->ocount; | ||||
| 		if(n == 0) | ||||
| 			return 0; | ||||
| 		c = write(bp->fid, bp->bbuf, n); | ||||
| 		if(n == c) { | ||||
| 			bp->offset += n; | ||||
| 			bp->ocount = -bp->bsize; | ||||
| 			return 0; | ||||
| 		} | ||||
| 		bp->state = Binactive; | ||||
| 		bp->ocount = 0; | ||||
| 		break; | ||||
|  | ||||
| 	case Bracteof: | ||||
| 		bp->state = Bractive; | ||||
|  | ||||
| 	case Bractive: | ||||
| 		bp->icount = 0; | ||||
| 		bp->gbuf = bp->ebuf; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	return Beof; | ||||
| } | ||||
							
								
								
									
										53
									
								
								lib/bio/bgetc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								lib/bio/bgetc.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| #include	"lib9.h" | ||||
| #include	<bio.h> | ||||
|  | ||||
| int | ||||
| Bgetc(Biobuf *bp) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| loop: | ||||
| 	i = bp->icount; | ||||
| 	if(i != 0) { | ||||
| 		bp->icount = i+1; | ||||
| 		return bp->ebuf[i]; | ||||
| 	} | ||||
| 	if(bp->state != Bractive) { | ||||
| 		if(bp->state == Bracteof) | ||||
| 			bp->state = Bractive; | ||||
| 		return Beof; | ||||
| 	} | ||||
| 	/* | ||||
| 	 * get next buffer, try to keep Bungetsize | ||||
| 	 * characters pre-catenated from the previous | ||||
| 	 * buffer to allow that many ungets. | ||||
| 	 */ | ||||
| 	memmove(bp->bbuf-Bungetsize, bp->ebuf-Bungetsize, Bungetsize); | ||||
| 	i = read(bp->fid, bp->bbuf, bp->bsize); | ||||
| 	bp->gbuf = bp->bbuf; | ||||
| 	if(i <= 0) { | ||||
| 		bp->state = Bracteof; | ||||
| 		if(i < 0) | ||||
| 			bp->state = Binactive; | ||||
| 		return Beof; | ||||
| 	} | ||||
| 	if(i < bp->bsize) { | ||||
| 		memmove(bp->ebuf-i-Bungetsize, bp->bbuf-Bungetsize, i+Bungetsize); | ||||
| 		bp->gbuf = bp->ebuf-i; | ||||
| 	} | ||||
| 	bp->icount = -i; | ||||
| 	bp->offset += i; | ||||
| 	goto loop; | ||||
| } | ||||
|  | ||||
| int | ||||
| Bungetc(Biobuf *bp) | ||||
| { | ||||
|  | ||||
| 	if(bp->state == Bracteof) | ||||
| 		bp->state = Bractive; | ||||
| 	if(bp->state != Bractive) | ||||
| 		return Beof; | ||||
| 	bp->icount--; | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										36
									
								
								lib/bio/bgetd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								lib/bio/bgetd.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| #include "lib9.h" | ||||
| #include <bio.h> | ||||
|  | ||||
| struct	bgetd | ||||
| { | ||||
| 	Biobuf*	b; | ||||
| 	int		eof; | ||||
| }; | ||||
|  | ||||
| static int | ||||
| Bgetdf(void *vp) | ||||
| { | ||||
| 	int c; | ||||
| 	struct bgetd *bg = vp; | ||||
|  | ||||
| 	c = Bgetc(bg->b); | ||||
| 	if(c == Beof) | ||||
| 		bg->eof = 1; | ||||
| 	return c; | ||||
| } | ||||
|  | ||||
| int | ||||
| Bgetd(Biobuf *bp, double *dp) | ||||
| { | ||||
| 	double d; | ||||
| 	struct bgetd b; | ||||
|  | ||||
| 	b.b = bp; | ||||
| 	b.eof = 0; | ||||
| 	d = fmtcharstod(Bgetdf, &b); | ||||
| 	if(b.eof) | ||||
| 		return -1; | ||||
| 	Bungetc(bp); | ||||
| 	*dp = d; | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										47
									
								
								lib/bio/bgetrune.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								lib/bio/bgetrune.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| #include	"lib9.h" | ||||
| #include	<bio.h> | ||||
| #include	<utf.h> | ||||
|  | ||||
| long | ||||
| Bgetrune(Biobuf *bp) | ||||
| { | ||||
| 	int c, i; | ||||
| 	Rune rune; | ||||
| 	char str[UTFmax]; | ||||
|  | ||||
| 	c = Bgetc(bp); | ||||
| 	if(c < Runeself) {		/* one char */ | ||||
| 		bp->runesize = 1; | ||||
| 		return c; | ||||
| 	} | ||||
| 	str[0] = c; | ||||
|  | ||||
| 	for(i=1;;) { | ||||
| 		c = Bgetc(bp); | ||||
| 		if(c < 0) | ||||
| 			return c; | ||||
| 		str[i++] = c; | ||||
|  | ||||
| 		if(fullrune(str, i)) { | ||||
| 			bp->runesize = chartorune(&rune, str); | ||||
| 			while(i > bp->runesize) { | ||||
| 				Bungetc(bp); | ||||
| 				i--; | ||||
| 			} | ||||
| 			return rune; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int | ||||
| Bungetrune(Biobuf *bp) | ||||
| { | ||||
|  | ||||
| 	if(bp->state == Bracteof) | ||||
| 		bp->state = Bractive; | ||||
| 	if(bp->state != Bractive) | ||||
| 		return Beof; | ||||
| 	bp->icount -= bp->runesize; | ||||
| 	bp->runesize = 0; | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										155
									
								
								lib/bio/binit.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								lib/bio/binit.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,155 @@ | ||||
| #include	"lib9.h" | ||||
| #include	<bio.h> | ||||
|  | ||||
| enum | ||||
| { | ||||
| 	MAXBUFS	= 20 | ||||
| }; | ||||
|  | ||||
| static	Biobuf*	wbufs[MAXBUFS]; | ||||
| static	int		atexitflag; | ||||
|  | ||||
| static | ||||
| void | ||||
| batexit(void) | ||||
| { | ||||
| 	Biobuf *bp; | ||||
| 	int i; | ||||
|  | ||||
| 	for(i=0; i<MAXBUFS; i++) { | ||||
| 		bp = wbufs[i]; | ||||
| 		if(bp != 0) { | ||||
| 			wbufs[i] = 0; | ||||
| 			Bflush(bp); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static | ||||
| void | ||||
| deinstall(Biobuf *bp) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for(i=0; i<MAXBUFS; i++) | ||||
| 		if(wbufs[i] == bp) | ||||
| 			wbufs[i] = 0; | ||||
| } | ||||
|  | ||||
| static | ||||
| void | ||||
| install(Biobuf *bp) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	deinstall(bp); | ||||
| 	for(i=0; i<MAXBUFS; i++) | ||||
| 		if(wbufs[i] == 0) { | ||||
| 			wbufs[i] = bp; | ||||
| 			break; | ||||
| 		} | ||||
| 	if(atexitflag == 0) { | ||||
| 		atexitflag = 1; | ||||
| 		atexit(batexit); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int | ||||
| Binits(Biobuf *bp, int f, int mode, unsigned char *p, int size) | ||||
| { | ||||
|  | ||||
| 	p += Bungetsize;	/* make room for Bungets */ | ||||
| 	size -= Bungetsize; | ||||
|  | ||||
| 	switch(mode&~(OCEXEC|ORCLOSE|OTRUNC)) { | ||||
| 	default: | ||||
| 		fprint(2, "Bopen: unknown mode %d\n", mode); | ||||
| 		return Beof; | ||||
|  | ||||
| 	case OREAD: | ||||
| 		bp->state = Bractive; | ||||
| 		bp->ocount = 0; | ||||
| 		break; | ||||
|  | ||||
| 	case OWRITE: | ||||
| 		install(bp); | ||||
| 		bp->state = Bwactive; | ||||
| 		bp->ocount = -size; | ||||
| 		break; | ||||
| 	} | ||||
| 	bp->bbuf = p; | ||||
| 	bp->ebuf = p+size; | ||||
| 	bp->bsize = size; | ||||
| 	bp->icount = 0; | ||||
| 	bp->gbuf = bp->ebuf; | ||||
| 	bp->fid = f; | ||||
| 	bp->flag = 0; | ||||
| 	bp->rdline = 0; | ||||
| 	bp->offset = 0; | ||||
| 	bp->runesize = 0; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| int | ||||
| Binit(Biobuf *bp, int f, int mode) | ||||
| { | ||||
| 	return Binits(bp, f, mode, bp->b, sizeof(bp->b)); | ||||
| } | ||||
|  | ||||
| Biobuf* | ||||
| Bfdopen(int f, int mode) | ||||
| { | ||||
| 	Biobuf *bp; | ||||
|  | ||||
| 	bp = malloc(sizeof(Biobuf)); | ||||
| 	if(bp == 0) | ||||
| 		return 0; | ||||
| 	Binits(bp, f, mode, bp->b, sizeof(bp->b)); | ||||
| 	bp->flag = Bmagic; | ||||
| 	return bp; | ||||
| } | ||||
|  | ||||
| Biobuf* | ||||
| Bopen(char *name, int mode) | ||||
| { | ||||
| 	Biobuf *bp; | ||||
| 	int f; | ||||
|  | ||||
| 	switch(mode&~(OCEXEC|ORCLOSE|OTRUNC)) { | ||||
| 	default: | ||||
| 		fprint(2, "Bopen: unknown mode %d\n", mode); | ||||
| 		return 0; | ||||
|  | ||||
| 	case OREAD: | ||||
| 		f = open(name, mode); | ||||
| 		if(f < 0) | ||||
| 			return 0; | ||||
| 		break; | ||||
|  | ||||
| 	case OWRITE: | ||||
| 		f = create(name, mode, 0666); | ||||
| 		if(f < 0) | ||||
| 			return 0; | ||||
| 	} | ||||
| 	bp = Bfdopen(f, mode); | ||||
| 	if(bp == 0) | ||||
| 		close(f); | ||||
| 	return bp; | ||||
| } | ||||
|  | ||||
| int | ||||
| Bterm(Biobuf *bp) | ||||
| { | ||||
| 	int ret; | ||||
|  | ||||
| 	deinstall(bp); | ||||
| 	ret = Bflush(bp); | ||||
| 	if(bp->flag == Bmagic) { | ||||
| 		bp->flag = 0; | ||||
| 		if(close(bp->fid) < 0) | ||||
| 			ret = -1; | ||||
| 		free(bp); | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
							
								
								
									
										25
									
								
								lib/bio/boffset.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								lib/bio/boffset.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| #include	"lib9.h" | ||||
| #include	<bio.h> | ||||
|  | ||||
| vlong | ||||
| Boffset(Biobuf *bp) | ||||
| { | ||||
| 	vlong n; | ||||
|  | ||||
| 	switch(bp->state) { | ||||
| 	default: | ||||
| 		fprint(2, "Boffset: unknown state %d\n", bp->state); | ||||
| 		n = Beof; | ||||
| 		break; | ||||
|  | ||||
| 	case Bracteof: | ||||
| 	case Bractive: | ||||
| 		n = bp->offset + bp->icount; | ||||
| 		break; | ||||
|  | ||||
| 	case Bwactive: | ||||
| 		n = bp->offset + (bp->bsize + bp->ocount); | ||||
| 		break; | ||||
| 	} | ||||
| 	return n; | ||||
| } | ||||
							
								
								
									
										14
									
								
								lib/bio/bprint.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								lib/bio/bprint.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| #include	"lib9.h" | ||||
| #include	<bio.h> | ||||
|  | ||||
| int | ||||
| Bprint(Biobuf *bp, char *fmt, ...) | ||||
| { | ||||
| 	int n; | ||||
| 	va_list arg; | ||||
|  | ||||
| 	va_start(arg, fmt); | ||||
| 	n = Bvprint(bp, fmt, arg); | ||||
| 	va_end(arg); | ||||
| 	return n; | ||||
| } | ||||
							
								
								
									
										20
									
								
								lib/bio/bputc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								lib/bio/bputc.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| #include	"lib9.h" | ||||
| #include	<bio.h> | ||||
|  | ||||
| int | ||||
| Bputc(Biobuf *bp, int c) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for(;;) { | ||||
| 		i = bp->ocount; | ||||
| 		if(i) { | ||||
| 			bp->ebuf[i++] = c; | ||||
| 			bp->ocount = i; | ||||
| 			return 0; | ||||
| 		} | ||||
| 		if(Bflush(bp) == Beof) | ||||
| 			break; | ||||
| 	} | ||||
| 	return Beof; | ||||
| } | ||||
							
								
								
									
										23
									
								
								lib/bio/bputrune.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								lib/bio/bputrune.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| #include	"lib9.h" | ||||
| #include	<bio.h> | ||||
| #include	<utf.h> | ||||
|  | ||||
| int | ||||
| Bputrune(Biobuf *bp, long c) | ||||
| { | ||||
| 	Rune rune; | ||||
| 	char str[UTFmax]; | ||||
| 	int n; | ||||
|  | ||||
| 	rune = c; | ||||
| 	if(rune < Runeself) { | ||||
| 		Bputc(bp, rune); | ||||
| 		return 1; | ||||
| 	} | ||||
| 	n = runetochar(str, &rune); | ||||
| 	if(n == 0) | ||||
| 		return Bbad; | ||||
| 	if(Bwrite(bp, str, n) != n) | ||||
| 		return Beof; | ||||
| 	return n; | ||||
| } | ||||
							
								
								
									
										94
									
								
								lib/bio/brdline.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								lib/bio/brdline.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | ||||
| #include	"lib9.h" | ||||
| #include	<bio.h> | ||||
|  | ||||
| void* | ||||
| Brdline(Biobuf *bp, int delim) | ||||
| { | ||||
| 	char *ip, *ep; | ||||
| 	int i, j; | ||||
|  | ||||
| 	i = -bp->icount; | ||||
| 	if(i == 0) { | ||||
| 		/* | ||||
| 		 * eof or other error | ||||
| 		 */ | ||||
| 		if(bp->state != Bractive) { | ||||
| 			if(bp->state == Bracteof) | ||||
| 				bp->state = Bractive; | ||||
| 			bp->rdline = 0; | ||||
| 			bp->gbuf = bp->ebuf; | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * first try in remainder of buffer (gbuf doesn't change) | ||||
| 	 */ | ||||
| 	ip = (char*)bp->ebuf - i; | ||||
| 	ep = memchr(ip, delim, i); | ||||
| 	if(ep) { | ||||
| 		j = (ep - ip) + 1; | ||||
| 		bp->rdline = j; | ||||
| 		bp->icount += j; | ||||
| 		return ip; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * copy data to beginning of buffer | ||||
| 	 */ | ||||
| 	if(i < bp->bsize) | ||||
| 		memmove(bp->bbuf, ip, i); | ||||
| 	bp->gbuf = bp->bbuf; | ||||
|  | ||||
| 	/* | ||||
| 	 * append to buffer looking for the delim | ||||
| 	 */ | ||||
| 	ip = (char*)bp->bbuf + i; | ||||
| 	while(i < bp->bsize) { | ||||
| 		j = read(bp->fid, ip, bp->bsize-i); | ||||
| 		if(j <= 0) { | ||||
| 			/* | ||||
| 			 * end of file with no delim | ||||
| 			 */ | ||||
| 			memmove(bp->ebuf-i, bp->bbuf, i); | ||||
| 			bp->rdline = i; | ||||
| 			bp->icount = -i; | ||||
| 			bp->gbuf = bp->ebuf-i; | ||||
| 			return 0; | ||||
| 		} | ||||
| 		bp->offset += j; | ||||
| 		i += j; | ||||
| 		ep = memchr(ip, delim, j); | ||||
| 		if(ep) { | ||||
| 			/* | ||||
| 			 * found in new piece | ||||
| 			 * copy back up and reset everything | ||||
| 			 */ | ||||
| 			ip = (char*)bp->ebuf - i; | ||||
| 			if(i < bp->bsize){ | ||||
| 				memmove(ip, bp->bbuf, i); | ||||
| 				bp->gbuf = (unsigned char*)ip; | ||||
| 			} | ||||
| 			j = (ep - (char*)bp->bbuf) + 1; | ||||
| 			bp->rdline = j; | ||||
| 			bp->icount = j - i; | ||||
| 			return ip; | ||||
| 		} | ||||
| 		ip += j; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * full buffer without finding | ||||
| 	 */ | ||||
| 	bp->rdline = bp->bsize; | ||||
| 	bp->icount = -bp->bsize; | ||||
| 	bp->gbuf = bp->bbuf; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| Blinelen(Biobuf *bp) | ||||
| { | ||||
|  | ||||
| 	return bp->rdline; | ||||
| } | ||||
							
								
								
									
										111
									
								
								lib/bio/brdstr.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								lib/bio/brdstr.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | ||||
| #include	"lib9.h" | ||||
| #include	<bio.h> | ||||
|  | ||||
| static char* | ||||
| badd(char *p, int *np, char *data, int ndata, int delim, int nulldelim) | ||||
| { | ||||
| 	int n; | ||||
|  | ||||
| 	n = *np; | ||||
| 	p = realloc(p, n+ndata+1); | ||||
| 	if(p){ | ||||
| 		memmove(p+n, data, ndata); | ||||
| 		n += ndata; | ||||
| 		if(n>0 && nulldelim && p[n-1]==delim) | ||||
| 			p[--n] = '\0'; | ||||
| 		else | ||||
| 			p[n] = '\0'; | ||||
| 		*np = n; | ||||
| 	} | ||||
| 	return p; | ||||
| } | ||||
|  | ||||
| char* | ||||
| Brdstr(Biobuf *bp, int delim, int nulldelim) | ||||
| { | ||||
| 	char *ip, *ep, *p; | ||||
| 	int i, j; | ||||
|  | ||||
| 	i = -bp->icount; | ||||
| 	bp->rdline = 0; | ||||
| 	if(i == 0) { | ||||
| 		/* | ||||
| 		 * eof or other error | ||||
| 		 */ | ||||
| 		if(bp->state != Bractive) { | ||||
| 			if(bp->state == Bracteof) | ||||
| 				bp->state = Bractive; | ||||
| 			bp->gbuf = bp->ebuf; | ||||
| 			return nil; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * first try in remainder of buffer (gbuf doesn't change) | ||||
| 	 */ | ||||
| 	ip = (char*)bp->ebuf - i; | ||||
| 	ep = memchr(ip, delim, i); | ||||
| 	if(ep) { | ||||
| 		j = (ep - ip) + 1; | ||||
| 		bp->icount += j; | ||||
| 		return badd(nil, &bp->rdline, ip, j, delim, nulldelim); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * copy data to beginning of buffer | ||||
| 	 */ | ||||
| 	if(i < bp->bsize) | ||||
| 		memmove(bp->bbuf, ip, i); | ||||
| 	bp->gbuf = bp->bbuf; | ||||
|  | ||||
| 	/* | ||||
| 	 * append to buffer looking for the delim | ||||
| 	 */ | ||||
| 	p = nil; | ||||
| 	for(;;){ | ||||
| 		ip = (char*)bp->bbuf + i; | ||||
| 		while(i < bp->bsize) { | ||||
| 			j = read(bp->fid, ip, bp->bsize-i); | ||||
| 			if(j <= 0 && i == 0) | ||||
| 				return p; | ||||
| 			if(j <= 0 && i > 0){ | ||||
| 				/* | ||||
| 				 * end of file but no delim. pretend we got a delim | ||||
| 				 * by making the delim \0 and smashing it with nulldelim. | ||||
| 				 */ | ||||
| 				j = 1; | ||||
| 				ep = ip; | ||||
| 				delim = '\0'; | ||||
| 				nulldelim = 1; | ||||
| 				*ep = delim;	/* there will be room for this */ | ||||
| 			}else{ | ||||
| 				bp->offset += j; | ||||
| 				ep = memchr(ip, delim, j); | ||||
| 			} | ||||
| 			i += j; | ||||
| 			if(ep) { | ||||
| 				/* | ||||
| 				 * found in new piece | ||||
| 				 * copy back up and reset everything | ||||
| 				 */ | ||||
| 				ip = (char*)bp->ebuf - i; | ||||
| 				if(i < bp->bsize){ | ||||
| 					memmove(ip, bp->bbuf, i); | ||||
| 					bp->gbuf = (unsigned char*)ip; | ||||
| 				} | ||||
| 				j = (ep - (char*)bp->bbuf) + 1; | ||||
| 				bp->icount = j - i; | ||||
| 				return badd(p, &bp->rdline, ip, j, delim, nulldelim); | ||||
| 			} | ||||
| 			ip += j; | ||||
| 		} | ||||
|  | ||||
| 		/* | ||||
| 		 * full buffer without finding; add to user string and continue | ||||
| 		 */ | ||||
| 		p = badd(p, &bp->rdline, (char*)bp->bbuf, bp->bsize, 0, 0); | ||||
| 		i = 0; | ||||
| 		bp->icount = 0; | ||||
| 		bp->gbuf = bp->ebuf; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										45
									
								
								lib/bio/bread.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								lib/bio/bread.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| #include	"lib9.h" | ||||
| #include	<bio.h> | ||||
|  | ||||
| long | ||||
| Bread(Biobuf *bp, void *ap, long count) | ||||
| { | ||||
| 	long c; | ||||
| 	unsigned char *p; | ||||
| 	int i, n, ic; | ||||
|  | ||||
| 	p = ap; | ||||
| 	c = count; | ||||
| 	ic = bp->icount; | ||||
|  | ||||
| 	while(c > 0) { | ||||
| 		n = -ic; | ||||
| 		if(n > c) | ||||
| 			n = c; | ||||
| 		if(n == 0) { | ||||
| 			if(bp->state != Bractive) | ||||
| 				break; | ||||
| 			i = read(bp->fid, bp->bbuf, bp->bsize); | ||||
| 			if(i <= 0) { | ||||
| 				bp->state = Bracteof; | ||||
| 				if(i < 0) | ||||
| 					bp->state = Binactive; | ||||
| 				break; | ||||
| 			} | ||||
| 			bp->gbuf = bp->bbuf; | ||||
| 			bp->offset += i; | ||||
| 			if(i < bp->bsize) { | ||||
| 				memmove(bp->ebuf-i, bp->bbuf, i); | ||||
| 				bp->gbuf = bp->ebuf-i; | ||||
| 			} | ||||
| 			ic = -i; | ||||
| 			continue; | ||||
| 		} | ||||
| 		memmove(p, bp->ebuf+ic, n); | ||||
| 		c -= n; | ||||
| 		ic += n; | ||||
| 		p += n; | ||||
| 	} | ||||
| 	bp->icount = ic; | ||||
| 	return count-c; | ||||
| } | ||||
							
								
								
									
										60
									
								
								lib/bio/bseek.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								lib/bio/bseek.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| #include	"lib9.h" | ||||
| #include	<bio.h> | ||||
|  | ||||
| long long | ||||
| Bseek(Biobuf *bp, long long offset, int base) | ||||
| { | ||||
| 	vlong n, d; | ||||
| 	int bufsz; | ||||
|  | ||||
| 	switch(bp->state) { | ||||
| 	default: | ||||
| 		fprint(2, "Bseek: unknown state %d\n", bp->state); | ||||
| 		return Beof; | ||||
|  | ||||
| 	case Bracteof: | ||||
| 		bp->state = Bractive; | ||||
| 		bp->icount = 0; | ||||
| 		bp->gbuf = bp->ebuf; | ||||
|  | ||||
| 	case Bractive: | ||||
| 		n = offset; | ||||
| 		if(base == 1) { | ||||
| 			n += Boffset(bp); | ||||
| 			base = 0; | ||||
| 		} | ||||
|  | ||||
| 		/* | ||||
| 		 * try to seek within buffer | ||||
| 		 */ | ||||
| 		if(base == 0) { | ||||
| 			d = n - Boffset(bp); | ||||
| 			bufsz = bp->ebuf - bp->gbuf; | ||||
| 			if(-bufsz <= d && d <= bufsz){ | ||||
| 				bp->icount += d; | ||||
| 				if(d >= 0) { | ||||
| 					if(bp->icount <= 0) | ||||
| 						return n; | ||||
| 				} else { | ||||
| 					if(bp->ebuf - bp->gbuf >= -bp->icount) | ||||
| 						return n; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/* | ||||
| 		 * reset the buffer | ||||
| 		 */ | ||||
| 		n = lseek(bp->fid, n, base); | ||||
| 		bp->icount = 0; | ||||
| 		bp->gbuf = bp->ebuf; | ||||
| 		break; | ||||
|  | ||||
| 	case Bwactive: | ||||
| 		Bflush(bp); | ||||
| 		n = seek(bp->fid, offset, base); | ||||
| 		break; | ||||
| 	} | ||||
| 	bp->offset = n; | ||||
| 	return n; | ||||
| } | ||||
							
								
								
									
										38
									
								
								lib/bio/bvprint.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								lib/bio/bvprint.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| #include "lib9.h" | ||||
| #include <bio.h> | ||||
|  | ||||
| static int | ||||
| fmtBflush(Fmt *f) | ||||
| { | ||||
| 	Biobuf *bp; | ||||
|  | ||||
| 	bp = f->farg; | ||||
| 	bp->ocount = (char*)f->to - (char*)f->stop; | ||||
| 	if(Bflush(bp) < 0) | ||||
| 		return 0; | ||||
| 	f->stop = bp->ebuf; | ||||
| 	f->to = (char*)f->stop + bp->ocount; | ||||
| 	f->start = f->to; | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int | ||||
| Bvprint(Biobuf *bp, char *fmt, va_list arg) | ||||
| { | ||||
| 	int n; | ||||
| 	Fmt f; | ||||
|  | ||||
| 	f.runes = 0; | ||||
| 	f.stop = bp->ebuf; | ||||
| 	f.start = (char*)f.stop + bp->ocount; | ||||
| 	f.to = f.start; | ||||
| 	f.flush = fmtBflush; | ||||
| 	f.farg = bp; | ||||
| 	f.nfmt = 0; | ||||
| 	fmtlocaleinit(&f, nil, nil, nil); | ||||
| 	n = fmtvprint(&f, fmt, arg); | ||||
| 	bp->ocount = (char*)f.to - (char*)f.stop; | ||||
| 	if(n == 0) | ||||
| 		n = f.nfmt; | ||||
| 	return n; | ||||
| } | ||||
							
								
								
									
										38
									
								
								lib/bio/bwrite.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								lib/bio/bwrite.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| #include	"lib9.h" | ||||
| #include	<bio.h> | ||||
|  | ||||
| long | ||||
| Bwrite(Biobuf *bp, void *ap, long count) | ||||
| { | ||||
| 	long c; | ||||
| 	unsigned char *p; | ||||
| 	int i, n, oc; | ||||
|  | ||||
| 	p = ap; | ||||
| 	c = count; | ||||
| 	oc = bp->ocount; | ||||
|  | ||||
| 	while(c > 0) { | ||||
| 		n = -oc; | ||||
| 		if(n > c) | ||||
| 			n = c; | ||||
| 		if(n == 0) { | ||||
| 			if(bp->state != Bwactive) | ||||
| 				return Beof; | ||||
| 			i = write(bp->fid, bp->bbuf, bp->bsize); | ||||
| 			if(i != bp->bsize) { | ||||
| 				bp->state = Binactive; | ||||
| 				return Beof; | ||||
| 			} | ||||
| 			bp->offset += i; | ||||
| 			oc = -bp->bsize; | ||||
| 			continue; | ||||
| 		} | ||||
| 		memmove(bp->ebuf+oc, p, n); | ||||
| 		oc += n; | ||||
| 		c -= n; | ||||
| 		p += n; | ||||
| 	} | ||||
| 	bp->ocount = oc; | ||||
| 	return count-c; | ||||
| } | ||||
							
								
								
									
										25
									
								
								lib/bio/lib9.std.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								lib/bio/lib9.std.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| #define _FILE_OFFSET_BITS 64 | ||||
| #define _LARGEFILE64_SOURCE | ||||
|  | ||||
| #include <utf.h> | ||||
| #include <fmt.h> | ||||
|  | ||||
| #include <fcntl.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| #define OREAD		O_RDONLY | ||||
| #define OWRITE	O_WRONLY | ||||
|  | ||||
| #define	OCEXEC 0 | ||||
| #define	ORCLOSE	0 | ||||
| #define	OTRUNC	0 | ||||
|  | ||||
| #define nil ((void*)0) | ||||
|  | ||||
| typedef long long vlong; | ||||
| typedef unsigned long long uvlong; | ||||
|  | ||||
| #define seek(fd, offset, whence) lseek(fd, offset, whence) | ||||
| #define create(name, mode, perm) creat(name, perm) | ||||
							
								
								
									
										47
									
								
								lib/bio/libbio.sh.build
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										47
									
								
								lib/bio/libbio.sh.build
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| git clean -xdf . | ||||
|  | ||||
| cc \ | ||||
|     -I ../../include\ | ||||
|     -DPLAN9PORT \ | ||||
| 	-O0 \ | ||||
| 	-c \ | ||||
| 	-g -ggdb \ | ||||
| 	-Wall \ | ||||
| 	-Wno-parentheses \ | ||||
| 	-Wno-missing-braces \ | ||||
| 	-Wno-switch \ | ||||
| 	-Wno-comment \ | ||||
| 	-Wno-sign-compare \ | ||||
| 	-Wno-unknown-pragmas \ | ||||
| 	-Wno-misleading-indentation \ | ||||
| 	-Wno-stringop-truncation \ | ||||
| 	-Wno-stringop-overflow \ | ||||
| 	-Wno-format-truncation \ | ||||
| 	-fno-omit-frame-pointer \ | ||||
| 	-fsigned-char \ | ||||
| 	-fcommon \ | ||||
| 	bbuffered.c\ | ||||
| 	bfildes.c\ | ||||
| 	bflush.c\ | ||||
| 	bgetc.c\ | ||||
| 	bgetrune.c\ | ||||
| 	bgetd.c\ | ||||
| 	binit.c\ | ||||
| 	boffset.c\ | ||||
| 	bprint.c\ | ||||
| 	bputc.c\ | ||||
| 	bputrune.c\ | ||||
| 	brdline.c\ | ||||
| 	brdstr.c\ | ||||
| 	bread.c\ | ||||
| 	bseek.c\ | ||||
| 	bvprint.c\ | ||||
| 	bwrite.c | ||||
|  | ||||
| mkdir -p $JEHANNE/hacking/lib/ | ||||
| ar rcs $JEHANNE/hacking/lib/libbio.a *.o | ||||
|  | ||||
| git clean -xdf . | ||||
|  | ||||
							
								
								
									
										31
									
								
								lib/bio/mkfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								lib/bio/mkfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| <$PLAN9/src/mkhdr | ||||
|  | ||||
| LIB=libbio.a | ||||
|  | ||||
| OFILES=\ | ||||
| 	bbuffered.$O\ | ||||
| 	bfildes.$O\ | ||||
| 	bflush.$O\ | ||||
| 	bgetc.$O\ | ||||
| 	bgetrune.$O\ | ||||
| 	bgetd.$O\ | ||||
| 	binit.$O\ | ||||
| 	boffset.$O\ | ||||
| 	bprint.$O\ | ||||
| 	bputc.$O\ | ||||
| 	bputrune.$O\ | ||||
| 	brdline.$O\ | ||||
| 	brdstr.$O\ | ||||
| 	bread.$O\ | ||||
| 	bseek.$O\ | ||||
| 	bvprint.$O\ | ||||
| 	bwrite.$O\ | ||||
|  | ||||
| HFILES=\ | ||||
| 	$PLAN9/include/bio.h\ | ||||
|  | ||||
| <$PLAN9/src/mksyslib | ||||
|  | ||||
| bcat: bcat.$O $PLAN9/lib/$LIB | ||||
| 	$LD -o bcat bcat.$O -lbio -l9 | ||||
|  | ||||
							
								
								
									
										18
									
								
								lib/bio/portdate
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								lib/bio/portdate
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| bbuffered.c		2004/1225 | ||||
| bcat.c		2004/1225 | ||||
| bfildes.c		2004/1225 | ||||
| bflush.c		2004/1225 | ||||
| bfmt.c		2004/1225 | ||||
| bgetc.c		2004/1225 | ||||
| bgetd.c		2004/1225 | ||||
| bgetrune.c		2004/1225 | ||||
| binit.c		2004/1225 | ||||
| boffset.c		2004/1225 | ||||
| bprint.c		2004/1225 | ||||
| bputc.c		2004/1225 | ||||
| bputrune.c		2004/1225 | ||||
| brdline.c		2004/1225 | ||||
| brdstr.c		2004/1225 | ||||
| bread.c		2004/1225 | ||||
| bseek.c		2004/1225 | ||||
| bwrite.c		2004/1225 | ||||
							
								
								
									
										92
									
								
								lib/lib9/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								lib/lib9/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | ||||
| The files listed below were written from scrach for plan9port | ||||
| and do not derive from the Plan 9 from Bell Labs distribution. | ||||
| They are made available under an MIT-style license, using the | ||||
| same terms as the main distribution. | ||||
|  | ||||
| 	../../include/u.h | ||||
| 	non-Plan 9 code in ../../include/libc.h | ||||
| 	_exits.c | ||||
| 	_p9dialparse.c | ||||
| 	_p9dir.c | ||||
| 	_p9translate.c | ||||
| 	announce.c | ||||
| 	argv0.c | ||||
| 	atoi.c | ||||
| 	atol.c | ||||
| 	atoll.c | ||||
| 	await.c | ||||
| 	create.c | ||||
| 	debugmalloc.c | ||||
| 	dial.c | ||||
| 	dirfstat.c | ||||
| 	dirfwstat.c | ||||
| 	dirstat.c | ||||
| 	dirwstat.c | ||||
| 	dup.c | ||||
| 	errstr.c | ||||
| 	exec.c | ||||
| 	execl.c | ||||
| 	exitcode.c | ||||
| 	fmtlock2.c | ||||
| 	fork.c | ||||
| 	get9root.c | ||||
| 	getcallerpc-386.c | ||||
| 	getcallerpc-arm.c | ||||
| 	getcallerpc-power.c | ||||
| 	getcallerpc-sun4u.s | ||||
| 	getcallerpc-x86_64.c | ||||
| 	getenv.c | ||||
| 	getnetconn.c | ||||
| 	getns.c | ||||
| 	getuser.c | ||||
| 	getwd.c | ||||
| 	jmp.c | ||||
| 	lock.c | ||||
| 	main.c | ||||
| 	malloc.c | ||||
| 	malloctag.c | ||||
| 	mallocz.c | ||||
| 	nan.c | ||||
| 	needstack.c | ||||
| 	notify.c | ||||
| 	open.c | ||||
| 	opentemp.c | ||||
| 	pin.c | ||||
| 	pipe.c | ||||
| 	post9p.c | ||||
| 	postnote.c | ||||
| 	priv.c | ||||
| 	qlock.c | ||||
| 	readcons.c | ||||
| 	rfork.c | ||||
| 	searchpath.c | ||||
| 	seek.c | ||||
| 	sendfd.c | ||||
| 	sleep.c | ||||
| 	strdup.c | ||||
| 	sysfatal.c | ||||
| 	sysname.c | ||||
| 	time.c | ||||
| 	truerand.c | ||||
| 	udp.c | ||||
| 	unsharp.c | ||||
|  | ||||
| Copyright 2001-2007 Russ Cox.  All Rights Reserved. | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
|  | ||||
| The above copyright notice and this permission notice shall be included in | ||||
| all copies or substantial portions of the Software. | ||||
|  | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
| THE SOFTWARE. | ||||
							
								
								
									
										10
									
								
								lib/lib9/_exits.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								lib/lib9/_exits.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| void | ||||
| _exits(char *s) | ||||
| { | ||||
| 	if(s == 0 || *s == 0) | ||||
| 		_exit(0); | ||||
| 	_exit(exitcode(s)); | ||||
| } | ||||
							
								
								
									
										185
									
								
								lib/lib9/_p9dialparse.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								lib/lib9/_p9dialparse.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,185 @@ | ||||
| #include <u.h> | ||||
| #define NOPLAN9DEFINES | ||||
| #include <libc.h> | ||||
|  | ||||
| #include <sys/types.h> | ||||
| #include <sys/socket.h> | ||||
| #include <netdb.h> | ||||
| #include <sys/un.h> | ||||
| #include <netinet/in.h> | ||||
|  | ||||
| static char *nets[] = { "tcp", "udp", nil }; | ||||
| #define CLASS(p) ((*(uchar*)(p))>>6) | ||||
|  | ||||
| static struct { | ||||
| 	char *net; | ||||
| 	char *service; | ||||
| 	int port; | ||||
| } porttbl[] = { | ||||
| 	"tcp",	"9fs",	564, | ||||
| 	"tcp",	"whoami",	565, | ||||
| 	"tcp",	"guard",	566, | ||||
| 	"tcp",	"ticket",	567, | ||||
| 	"tcp",	"exportfs",	17007, | ||||
| 	"tcp",	"rexexec",	17009, | ||||
| 	"tcp",	"ncpu",	17010, | ||||
| 	"tcp",	"cpu",	17013, | ||||
| 	"tcp",	"venti",	17034, | ||||
| 	"tcp",	"wiki",	17035, | ||||
| 	"tcp",	"secstore",	5356, | ||||
| 	"udp",	"dns",	53, | ||||
| 	"tcp",	"dns",	53, | ||||
| }; | ||||
|  | ||||
| static int | ||||
| setport(struct sockaddr_storage *ss, int port) | ||||
| { | ||||
| 	switch(ss->ss_family){ | ||||
| 	case AF_INET: | ||||
| 		((struct sockaddr_in*)ss)->sin_port = htons(port); | ||||
| 		break; | ||||
| 	case AF_INET6: | ||||
| 		((struct sockaddr_in6*)ss)->sin6_port = htons(port); | ||||
| 		break; | ||||
| 	default: | ||||
| 		errstr("unknown protocol family %d", ss->ss_family); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| p9dialparse(char *addr, char **pnet, char **punix, void *phost, int *pport) | ||||
| { | ||||
| 	char *net, *host, *port, *e; | ||||
| 	int i; | ||||
| 	struct servent *se; | ||||
| 	struct hostent *he; | ||||
| 	struct sockaddr_storage *ss; | ||||
| 	struct addrinfo *result; | ||||
|  | ||||
| 	ss = phost; | ||||
|  | ||||
| 	memset(ss, 0, sizeof *ss); | ||||
|  | ||||
| 	*punix = nil; | ||||
| 	net = addr; | ||||
| 	if((host = strchr(net, '!')) == nil){ | ||||
| 		werrstr("malformed address"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	*host++ = 0; | ||||
| 	if((port = strchr(host, '!')) == nil){ | ||||
| 		if(strcmp(net, "unix")==0 || strcmp(net, "net")==0){ | ||||
| 		Unix: | ||||
| 			if(strlen(host)+1 > sizeof ((struct sockaddr_un*)ss)->sun_path){ | ||||
| 				werrstr("unix socket name too long"); | ||||
| 				return -1; | ||||
| 			} | ||||
| 			*punix = host; | ||||
| 			*pnet = "unix"; | ||||
| 			ss->ss_family = AF_UNIX; | ||||
| 			strcpy(((struct sockaddr_un*)ss)->sun_path, host); | ||||
| 			*pport = 0; | ||||
| 			return 0; | ||||
| 		} | ||||
| 		werrstr("malformed address"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	*port++ = 0; | ||||
|  | ||||
| 	if(*host == 0){ | ||||
| 		werrstr("malformed address (empty host)"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if(*port == 0){ | ||||
| 		werrstr("malformed address (empty port)"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if(strcmp(net, "unix") == 0) | ||||
| 		goto Unix; | ||||
|  | ||||
| 	if(strcmp(net, "tcp")!=0 && strcmp(net, "udp")!=0 && strcmp(net, "net") != 0){ | ||||
| 		werrstr("bad network %s!%s!%s", net, host, port); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* translate host */ | ||||
| 	if(strcmp(host, "*") == 0){ | ||||
| 		ss->ss_family = AF_INET6; | ||||
| 		((struct sockaddr_in6*)ss)->sin6_addr = in6addr_any; | ||||
| 	}else if((he = gethostbyname(host)) != nil && he->h_addr_list[0] != nil){ | ||||
| 		ss->ss_family = he->h_addrtype; | ||||
| 		switch(ss->ss_family){ | ||||
| 		case AF_INET: | ||||
| 			((struct sockaddr_in*)ss)->sin_addr = *(struct in_addr*) *(he->h_addr_list); | ||||
| 			break; | ||||
| 		case AF_INET6: | ||||
| 			((struct sockaddr_in6*)ss)->sin6_addr = *(struct in6_addr*) *(he->h_addr_list); | ||||
| 			break; | ||||
| 		default: | ||||
| 			errstr("unknown protocol family %d", ss->ss_family); | ||||
| 			return -1; | ||||
| 		} | ||||
| 	}else if(getaddrinfo(host, NULL, NULL, &result) == 0) { | ||||
| 		switch (result->ai_family) { | ||||
| 		case AF_INET: | ||||
| 			memmove((struct sockaddr_in*)ss, result->ai_addr, result->ai_addrlen); | ||||
| 			break; | ||||
| 		case AF_INET6: | ||||
| 			memmove((struct sockaddr_in6*)ss, result->ai_addr, result->ai_addrlen); | ||||
| 			break; | ||||
| 		default: | ||||
| 			errstr("unknown protocol family %d", ss->ss_family); | ||||
| 			return -1; | ||||
| 		} | ||||
| 	}else{ | ||||
| 		werrstr("unknown host %s", host); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* translate network and port; should return list rather than first */ | ||||
| 	if(strcmp(net, "net") == 0){ | ||||
| 		for(i=0; nets[i]; i++){ | ||||
| 			if((se = getservbyname(port, nets[i])) != nil){ | ||||
| 				*pnet = nets[i]; | ||||
| 				*pport = ntohs(se->s_port); | ||||
| 				return setport(ss, *pport); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for(i=0; i<nelem(porttbl); i++){ | ||||
| 		if(strcmp(net, "net") == 0 || strcmp(porttbl[i].net, net) == 0) | ||||
| 		if(strcmp(porttbl[i].service, port) == 0){ | ||||
| 			*pnet = porttbl[i].net; | ||||
| 			*pport = porttbl[i].port; | ||||
| 			return setport(ss, *pport); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if(strcmp(net, "net") == 0){ | ||||
| 		werrstr("unknown service net!*!%s", port); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if(strcmp(net, "tcp") != 0 && strcmp(net, "udp") != 0){ | ||||
| 		werrstr("unknown network %s", net); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	*pnet = net; | ||||
| 	i = strtol(port, &e, 0); | ||||
| 	if(*e == 0){ | ||||
| 		*pport = i; | ||||
| 		return setport(ss, *pport); | ||||
| 	} | ||||
|  | ||||
| 	if((se = getservbyname(port, net)) != nil){ | ||||
| 		*pport = ntohs(se->s_port); | ||||
| 		return setport(ss, *pport); | ||||
| 	} | ||||
| 	werrstr("unknown service %s!*!%s", net, port); | ||||
| 	return -1; | ||||
| } | ||||
							
								
								
									
										242
									
								
								lib/lib9/_p9dir.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										242
									
								
								lib/lib9/_p9dir.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,242 @@ | ||||
| #include <u.h> | ||||
| #define NOPLAN9DEFINES | ||||
| #include <libc.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <dirent.h> | ||||
| #include <pwd.h> | ||||
| #include <grp.h> | ||||
|  | ||||
| #if defined(__APPLE__) | ||||
| #define _HAVESTGEN | ||||
| #include <sys/disk.h> | ||||
| static vlong | ||||
| disksize(int fd, struct stat *st) | ||||
| { | ||||
| 	u64int bc; | ||||
| 	u32int bs; | ||||
|  | ||||
| 	bs = 0; | ||||
| 	bc = 0; | ||||
| 	ioctl(fd, DKIOCGETBLOCKSIZE, &bs); | ||||
| 	ioctl(fd, DKIOCGETBLOCKCOUNT, &bc); | ||||
| 	if(bs >0 && bc > 0) | ||||
| 		return bc*bs; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #elif defined(__FreeBSD__) | ||||
| #define _HAVESTGEN | ||||
| #include <sys/disk.h> | ||||
| #include <sys/disklabel.h> | ||||
| #include <sys/ioctl.h> | ||||
| static vlong | ||||
| disksize(int fd, struct stat *st) | ||||
| { | ||||
| 	off_t mediasize; | ||||
|  | ||||
| 	if(ioctl(fd, DIOCGMEDIASIZE, &mediasize) >= 0) | ||||
| 		return mediasize; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #elif defined(__OpenBSD__) | ||||
| #define _HAVESTGEN | ||||
| #include <sys/disklabel.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <sys/dkio.h> | ||||
| static vlong | ||||
| disksize(int fd, struct stat *st) | ||||
| { | ||||
| 	struct disklabel lab; | ||||
| 	int n; | ||||
|  | ||||
| 	if(!S_ISCHR(st->st_mode)) | ||||
| 		return 0; | ||||
| 	if(ioctl(fd, DIOCGDINFO, &lab) < 0) | ||||
| 		return 0; | ||||
| 	n = minor(st->st_rdev)&7; | ||||
| 	if(n >= lab.d_npartitions) | ||||
| 		return 0; | ||||
| 	return (vlong)lab.d_partitions[n].p_size * lab.d_secsize; | ||||
| } | ||||
|  | ||||
| #elif defined(__linux__) | ||||
| #include <linux/hdreg.h> | ||||
| #include <linux/fs.h> | ||||
| #include <sys/ioctl.h> | ||||
| #undef major | ||||
| #define major(dev) ((int)(((dev) >> 8) & 0xff)) | ||||
| static vlong | ||||
| disksize(int fd, struct stat *st) | ||||
| { | ||||
| 	u64int u64; | ||||
| 	long l; | ||||
| 	struct hd_geometry geo; | ||||
|  | ||||
| 	memset(&geo, 0, sizeof geo); | ||||
| 	l = 0; | ||||
| 	u64 = 0; | ||||
| #ifdef BLKGETSIZE64 | ||||
| 	if(ioctl(fd, BLKGETSIZE64, &u64) >= 0) | ||||
| 		return u64; | ||||
| #endif | ||||
| 	if(ioctl(fd, BLKGETSIZE, &l) >= 0) | ||||
| 		return l*512; | ||||
| 	if(ioctl(fd, HDIO_GETGEO, &geo) >= 0) | ||||
| 		return (vlong)geo.heads*geo.sectors*geo.cylinders*512; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #else | ||||
| static vlong | ||||
| disksize(int fd, struct stat *st) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| int _p9usepwlibrary = 1; | ||||
| /* | ||||
|  * Caching the last group and passwd looked up is | ||||
|  * a significant win (stupidly enough) on most systems. | ||||
|  * It's not safe for threaded programs, but neither is using | ||||
|  * getpwnam in the first place, so I'm not too worried. | ||||
|  */ | ||||
| int | ||||
| _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *estr) | ||||
| { | ||||
| 	char *s; | ||||
| 	char tmp[20]; | ||||
| 	static struct group *g; | ||||
| 	static struct passwd *p; | ||||
| 	static int gid, uid; | ||||
| 	int sz, fd; | ||||
|  | ||||
| 	fd = -1; | ||||
| 	USED(fd); | ||||
| 	sz = 0; | ||||
| 	if(d) | ||||
| 		memset(d, 0, sizeof *d); | ||||
|  | ||||
| 	/* name */ | ||||
| 	s = strrchr(name, '/'); | ||||
| 	if(s) | ||||
| 		s++; | ||||
| 	if(!s || !*s) | ||||
| 		s = name; | ||||
| 	if(*s == '/') | ||||
| 		s++; | ||||
| 	if(*s == 0) | ||||
| 		s = "/"; | ||||
| 	if(d){ | ||||
| 		if(*str + strlen(s)+1 > estr) | ||||
| 			d->name = "oops"; | ||||
| 		else{ | ||||
| 			strcpy(*str, s); | ||||
| 			d->name = *str; | ||||
| 			*str += strlen(*str)+1; | ||||
| 		} | ||||
| 	} | ||||
| 	sz += strlen(s)+1; | ||||
|  | ||||
| 	/* user */ | ||||
| 	if(p && st->st_uid == uid && p->pw_uid == uid) | ||||
| 		; | ||||
| 	else if(_p9usepwlibrary){ | ||||
| 		p = getpwuid(st->st_uid); | ||||
| 		uid = st->st_uid; | ||||
| 	} | ||||
| 	if(p == nil || st->st_uid != uid || p->pw_uid != uid){ | ||||
| 		snprint(tmp, sizeof tmp, "%d", (int)st->st_uid); | ||||
| 		s = tmp; | ||||
| 	}else | ||||
| 		s = p->pw_name; | ||||
| 	sz += strlen(s)+1; | ||||
| 	if(d){ | ||||
| 		if(*str+strlen(s)+1 > estr) | ||||
| 			d->uid = "oops"; | ||||
| 		else{ | ||||
| 			strcpy(*str, s); | ||||
| 			d->uid = *str; | ||||
| 			*str += strlen(*str)+1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* group */ | ||||
| 	if(g && st->st_gid == gid && g->gr_gid == gid) | ||||
| 		; | ||||
| 	else if(_p9usepwlibrary){ | ||||
| 		g = getgrgid(st->st_gid); | ||||
| 		gid = st->st_gid; | ||||
| 	} | ||||
| 	if(g == nil || st->st_gid != gid || g->gr_gid != gid){ | ||||
| 		snprint(tmp, sizeof tmp, "%d", (int)st->st_gid); | ||||
| 		s = tmp; | ||||
| 	}else | ||||
| 		s = g->gr_name; | ||||
| 	sz += strlen(s)+1; | ||||
| 	if(d){ | ||||
| 		if(*str + strlen(s)+1 > estr) | ||||
| 			d->gid = "oops"; | ||||
| 		else{ | ||||
| 			strcpy(*str, s); | ||||
| 			d->gid = *str; | ||||
| 			*str += strlen(*str)+1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if(d){ | ||||
| 		d->type = 'M'; | ||||
|  | ||||
| 		d->muid = ""; | ||||
| 		d->qid.path = st->st_ino; | ||||
| 		/* | ||||
| 		 * do not include st->st_dev in path, because | ||||
| 		 * automounters give the same file system different | ||||
| 		 * st_dev values for successive mounts, causing | ||||
| 		 * spurious write warnings in acme and sam. | ||||
| 		d->qid.path |= (uvlong)st->st_dev<<32; | ||||
| 		 */ | ||||
| #ifdef _HAVESTGEN | ||||
| 		d->qid.vers = st->st_gen; | ||||
| #endif | ||||
| 		if(d->qid.vers == 0) | ||||
| 			d->qid.vers = st->st_mtime + st->st_ctime; | ||||
| 		d->mode = st->st_mode&0777; | ||||
| 		d->atime = st->st_atime; | ||||
| 		d->mtime = st->st_mtime; | ||||
| 		d->length = st->st_size; | ||||
|  | ||||
| 		if(S_ISLNK(lst->st_mode)){	/* yes, lst not st */ | ||||
| 			d->mode |= DMSYMLINK; | ||||
| 			d->length = lst->st_size; | ||||
| 		} | ||||
| 		else if(S_ISDIR(st->st_mode)){ | ||||
| 			d->length = 0; | ||||
| 			d->mode |= DMDIR; | ||||
| 			d->qid.type = QTDIR; | ||||
| 		} | ||||
| 		else if(S_ISFIFO(st->st_mode)) | ||||
| 			d->mode |= DMNAMEDPIPE; | ||||
| 		else if(S_ISSOCK(st->st_mode)) | ||||
| 			d->mode |= DMSOCKET; | ||||
| 		else if(S_ISBLK(st->st_mode)){ | ||||
| 			d->mode |= DMDEVICE; | ||||
| 			d->qid.path = ('b'<<16)|st->st_rdev; | ||||
| 		} | ||||
| 		else if(S_ISCHR(st->st_mode)){ | ||||
| 			d->mode |= DMDEVICE; | ||||
| 			d->qid.path = ('c'<<16)|st->st_rdev; | ||||
| 		} | ||||
| 		/* fetch real size for disks */ | ||||
| 		if(S_ISBLK(lst->st_mode)){ | ||||
| 			if((fd = open(name, O_RDONLY)) >= 0){ | ||||
| 				d->length = disksize(fd, st); | ||||
| 				close(fd); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return sz; | ||||
| } | ||||
							
								
								
									
										155
									
								
								lib/lib9/announce.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								lib/lib9/announce.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,155 @@ | ||||
| #include <u.h> | ||||
| #define NOPLAN9DEFINES | ||||
| #include <libc.h> | ||||
|  | ||||
| #include <sys/socket.h> | ||||
| #include <netinet/in.h> | ||||
| #include <netinet/tcp.h> | ||||
| #include <sys/un.h> | ||||
| #include <errno.h> | ||||
|  | ||||
| #undef sun | ||||
| #define sun sockun | ||||
|  | ||||
| int | ||||
| _p9netfd(char *dir) | ||||
| { | ||||
| 	int fd; | ||||
|  | ||||
| 	if(strncmp(dir, "/dev/fd/", 8) != 0) | ||||
| 		return -1; | ||||
| 	fd = strtol(dir+8, &dir, 0); | ||||
| 	if(*dir != 0) | ||||
| 		return -1; | ||||
| 	return fd; | ||||
| } | ||||
|  | ||||
| static void | ||||
| putfd(char *dir, int fd) | ||||
| { | ||||
| 	snprint(dir, NETPATHLEN, "/dev/fd/%d", fd); | ||||
| } | ||||
|  | ||||
| #undef unix | ||||
| #define unix sockunix | ||||
|  | ||||
| static int | ||||
| addrlen(struct sockaddr_storage *ss) | ||||
| { | ||||
| 	switch(ss->ss_family){ | ||||
| 	case AF_INET: | ||||
| 		return sizeof(struct sockaddr_in); | ||||
| 	case AF_INET6: | ||||
| 		return sizeof(struct sockaddr_in6); | ||||
| 	case AF_UNIX: | ||||
| 		return sizeof(struct sockaddr_un); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| p9announce(char *addr, char *dir) | ||||
| { | ||||
| 	int proto; | ||||
| 	char *buf, *unix; | ||||
| 	char *net; | ||||
| 	int port, s; | ||||
| 	int n; | ||||
| 	socklen_t sn; | ||||
| 	struct sockaddr_storage ss; | ||||
|  | ||||
| 	buf = strdup(addr); | ||||
| 	if(buf == nil) | ||||
| 		return -1; | ||||
|  | ||||
| 	if(p9dialparse(buf, &net, &unix, &ss, &port) < 0){ | ||||
| 		free(buf); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if(strcmp(net, "tcp") == 0) | ||||
| 		proto = SOCK_STREAM; | ||||
| 	else if(strcmp(net, "udp") == 0) | ||||
| 		proto = SOCK_DGRAM; | ||||
| 	else if(strcmp(net, "unix") == 0) | ||||
| 		goto Unix; | ||||
| 	else{ | ||||
| 		werrstr("can only handle tcp, udp, and unix: not %s", net); | ||||
| 		free(buf); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	free(buf); | ||||
|  | ||||
| 	if((s = socket(ss.ss_family, proto, 0)) < 0) | ||||
| 		return -1; | ||||
| 	sn = sizeof n; | ||||
| 	if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0 | ||||
| 	&& n == SOCK_STREAM){ | ||||
| 		n = 1; | ||||
| 		setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n); | ||||
| 	} | ||||
| 	if(bind(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0){ | ||||
| 		close(s); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if(proto == SOCK_STREAM){ | ||||
| 		listen(s, 8); | ||||
| 		putfd(dir, s); | ||||
| 	} | ||||
| 	return s; | ||||
|  | ||||
| Unix: | ||||
| 	if((s = socket(ss.ss_family, SOCK_STREAM, 0)) < 0) | ||||
| 		return -1; | ||||
| 	if(bind(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0){ | ||||
| 		if(errno == EADDRINUSE | ||||
| 		&& connect(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0 | ||||
| 		&& errno == ECONNREFUSED){ | ||||
| 			/* dead socket, so remove it */ | ||||
| 			remove(unix); | ||||
| 			close(s); | ||||
| 			if((s = socket(ss.ss_family, SOCK_STREAM, 0)) < 0) | ||||
| 				return -1; | ||||
| 			if(bind(s, (struct sockaddr*)&ss, addrlen(&ss)) >= 0) | ||||
| 				goto Success; | ||||
| 		} | ||||
| 		close(s); | ||||
| 		return -1; | ||||
| 	} | ||||
| Success: | ||||
| 	listen(s, 8); | ||||
| 	putfd(dir, s); | ||||
| 	return s; | ||||
| } | ||||
|  | ||||
| int | ||||
| p9listen(char *dir, char *newdir) | ||||
| { | ||||
| 	int fd, one; | ||||
|  | ||||
| 	if((fd = _p9netfd(dir)) < 0){ | ||||
| 		werrstr("bad 'directory' in listen: %s", dir); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if((fd = accept(fd, nil, nil)) < 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	one = 1; | ||||
| 	setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof one); | ||||
|  | ||||
| 	putfd(newdir, fd); | ||||
| 	return fd; | ||||
| } | ||||
|  | ||||
| int | ||||
| p9accept(int cfd, char *dir) | ||||
| { | ||||
| 	int fd; | ||||
|  | ||||
| 	if((fd = _p9netfd(dir)) < 0){ | ||||
| 		werrstr("bad 'directory' in accept"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	/* need to dup because the listen fd will be closed */ | ||||
| 	return dup(fd); | ||||
| } | ||||
							
								
								
									
										9
									
								
								lib/lib9/argv0.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								lib/lib9/argv0.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| #include <lib9.h> | ||||
|  | ||||
| char *argv0; | ||||
|  | ||||
| /* | ||||
|  * Mac OS can't deal with files that only declare data. | ||||
|  * ARGBEGIN mentions this function so that this file gets pulled in. | ||||
|  */ | ||||
| void __fixargv0(void) { } | ||||
							
								
								
									
										56
									
								
								lib/lib9/atexit.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								lib/lib9/atexit.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| #define	NEXIT	33 | ||||
|  | ||||
| static Lock onexlock; | ||||
| static struct | ||||
| { | ||||
| 	void	(*f)(void); | ||||
| 	int	pid; | ||||
| }onex[NEXIT]; | ||||
|  | ||||
| int | ||||
| atexit(void (*f)(void)) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	lock(&onexlock); | ||||
| 	for(i=0; i<NEXIT; i++) | ||||
| 		if(onex[i].f == 0) { | ||||
| 			onex[i].pid = getpid(); | ||||
| 			onex[i].f = f; | ||||
| 			unlock(&onexlock); | ||||
| 			return 1; | ||||
| 		} | ||||
| 	unlock(&onexlock); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void | ||||
| atexitdont(void (*f)(void)) | ||||
| { | ||||
| 	int i, pid; | ||||
|  | ||||
| 	pid = getpid(); | ||||
| 	for(i=0; i<NEXIT; i++) | ||||
| 		if(onex[i].f == f && onex[i].pid == pid) | ||||
| 			onex[i].f = 0; | ||||
| } | ||||
|  | ||||
| void | ||||
| exits(char *s) | ||||
| { | ||||
| 	int i, pid; | ||||
| 	void (*f)(void); | ||||
|  | ||||
| 	pid = getpid(); | ||||
| 	for(i = NEXIT-1; i >= 0; i--) | ||||
| 		if((f = onex[i].f) && pid == onex[i].pid) { | ||||
| 			onex[i].f = 0; | ||||
| 			(*f)(); | ||||
| 		} | ||||
| 	if(s == 0 || *s == 0) | ||||
| 		exit(0); | ||||
| 	exit(exitcode(s)); | ||||
| } | ||||
							
								
								
									
										58
									
								
								lib/lib9/atnotify.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								lib/lib9/atnotify.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| #define	NFN	33 | ||||
| static	int	(*onnot[NFN])(void*, char*); | ||||
| static	Lock	onnotlock; | ||||
|  | ||||
| static | ||||
| void | ||||
| notifier(void *v, char *s) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for(i=0; i<NFN; i++) | ||||
| 		if(onnot[i] && ((*onnot[i])(v, s))){ | ||||
| 			noted(NCONT); | ||||
| 			return; | ||||
| 		} | ||||
| 	noted(NDFLT); | ||||
| } | ||||
|  | ||||
| int | ||||
| atnotify(int (*f)(void*, char*), int in) | ||||
| { | ||||
| 	int i, n, ret; | ||||
| 	static int init; | ||||
|  | ||||
| 	if(!init){ | ||||
| 		notify(notifier); | ||||
| 		init = 1;		/* assign = */ | ||||
| 	} | ||||
| 	ret = 0; | ||||
| 	lock(&onnotlock); | ||||
| 	if(in){ | ||||
| 		for(i=0; i<NFN; i++) | ||||
| 			if(onnot[i] == 0) { | ||||
| 				onnot[i] = f; | ||||
| 				ret = 1; | ||||
| 				break; | ||||
| 			} | ||||
| 	}else{ | ||||
| 		n = 0; | ||||
| 		for(i=0; i<NFN; i++) | ||||
| 			if(onnot[i]){ | ||||
| 				if(ret==0 && onnot[i]==f){ | ||||
| 					onnot[i] = 0; | ||||
| 					ret = 1; | ||||
| 				}else | ||||
| 					n++; | ||||
| 			} | ||||
| 		if(n == 0){ | ||||
| 			init = 0; | ||||
| 			notify(0); | ||||
| 		} | ||||
| 	} | ||||
| 	unlock(&onnotlock); | ||||
| 	return ret; | ||||
| } | ||||
							
								
								
									
										8
									
								
								lib/lib9/atoi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/lib9/atoi.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| int | ||||
| atoi(char *s) | ||||
| { | ||||
| 	return strtol(s, 0, 0); | ||||
| } | ||||
							
								
								
									
										8
									
								
								lib/lib9/atol.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/lib9/atol.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| long | ||||
| atol(char *s) | ||||
| { | ||||
| 	return strtol(s, 0, 0); | ||||
| } | ||||
							
								
								
									
										8
									
								
								lib/lib9/atoll.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/lib9/atoll.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| vlong | ||||
| atoll(char *s) | ||||
| { | ||||
| 	return strtoll(s, 0, 0); | ||||
| } | ||||
							
								
								
									
										136
									
								
								lib/lib9/await.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								lib/lib9/await.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,136 @@ | ||||
| #define NOPLAN9DEFINES | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| #include <signal.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/wait.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/resource.h> | ||||
|  | ||||
| #ifndef WCOREDUMP	/* not on Mac OS X Tiger */ | ||||
| #define WCOREDUMP(status) 0 | ||||
| #endif | ||||
|  | ||||
| static struct { | ||||
| 	int sig; | ||||
| 	char *str; | ||||
| } tab[] = { | ||||
| 	SIGHUP,		"hangup", | ||||
| 	SIGINT,		"interrupt", | ||||
| 	SIGQUIT,		"quit", | ||||
| 	SIGILL,		"sys: illegal instruction", | ||||
| 	SIGTRAP,		"sys: breakpoint", | ||||
| 	SIGABRT,		"sys: abort", | ||||
| #ifdef SIGEMT | ||||
| 	SIGEMT,		"sys: emulate instruction executed", | ||||
| #endif | ||||
| 	SIGFPE,		"sys: fp: trap", | ||||
| 	SIGKILL,		"sys: kill", | ||||
| 	SIGBUS,		"sys: bus error", | ||||
| 	SIGSEGV,		"sys: segmentation violation", | ||||
| 	SIGALRM,		"alarm", | ||||
| 	SIGTERM,		"kill", | ||||
| 	SIGURG,		"sys: urgent condition on socket", | ||||
| 	SIGSTOP,		"sys: stop", | ||||
| 	SIGTSTP,		"sys: tstp", | ||||
| 	SIGCONT,		"sys: cont", | ||||
| 	SIGCHLD,		"sys: child", | ||||
| 	SIGTTIN,		"sys: ttin", | ||||
| 	SIGTTOU,		"sys: ttou", | ||||
| #ifdef SIGIO	/* not on Mac OS X Tiger */ | ||||
| 	SIGIO,		"sys: i/o possible on fd", | ||||
| #endif | ||||
| 	SIGXCPU,		"sys: cpu time limit exceeded", | ||||
| 	SIGXFSZ,		"sys: file size limit exceeded", | ||||
| 	SIGVTALRM,	"sys: virtual time alarm", | ||||
| 	SIGPROF,		"sys: profiling timer alarm", | ||||
| #ifdef SIGWINCH	/* not on Mac OS X Tiger */ | ||||
| 	SIGWINCH,	"sys: window size change", | ||||
| #endif | ||||
| #ifdef SIGINFO | ||||
| 	SIGINFO,		"sys: status request", | ||||
| #endif | ||||
| 	SIGUSR1,		"sys: usr1", | ||||
| 	SIGUSR2,		"sys: usr2", | ||||
| 	SIGPIPE,		"sys: write on closed pipe", | ||||
| }; | ||||
|  | ||||
| char* | ||||
| _p9sigstr(int sig, char *tmp) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for(i=0; i<nelem(tab); i++) | ||||
| 		if(tab[i].sig == sig) | ||||
| 			return tab[i].str; | ||||
| 	if(tmp == nil) | ||||
| 		return nil; | ||||
| 	sprint(tmp, "sys: signal %d", sig); | ||||
| 	return tmp; | ||||
| } | ||||
|  | ||||
| int | ||||
| _p9strsig(char *s) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for(i=0; i<nelem(tab); i++) | ||||
| 		if(strcmp(s, tab[i].str) == 0) | ||||
| 			return tab[i].sig; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| _await(int pid4, char *str, int n, int opt) | ||||
| { | ||||
| 	int pid, status, cd; | ||||
| 	struct rusage ru; | ||||
| 	char buf[128], tmp[64]; | ||||
| 	uint64_t u, s; | ||||
|  | ||||
| 	for(;;){ | ||||
| 		/* On Linux, pid==-1 means anyone; on SunOS, it's pid==0. */ | ||||
| 		if(pid4 == -1) | ||||
| 			pid = wait3(&status, opt, &ru); | ||||
| 		else | ||||
| 			pid = wait4(pid4, &status, opt, &ru); | ||||
| 		if(pid <= 0) | ||||
| 			return -1; | ||||
| 		u = ru.ru_utime.tv_sec*1000+((ru.ru_utime.tv_usec+500)/1000); | ||||
| 		s = ru.ru_stime.tv_sec*1000+((ru.ru_stime.tv_usec+500)/1000); | ||||
| 		if(WIFEXITED(status)){ | ||||
| 			status = WEXITSTATUS(status); | ||||
| 			if(status) | ||||
| 				snprint(buf, sizeof buf, "%d %lud %lud %lud %d", pid, u, s, u+s, status); | ||||
| 			else | ||||
| 				snprint(buf, sizeof buf, "%d %lud %lud %lud ''", pid, u, s, u+s, status); | ||||
| 			strecpy(str, str+n, buf); | ||||
| 			return strlen(str); | ||||
| 		} | ||||
| 		if(WIFSIGNALED(status)){ | ||||
| 			cd = WCOREDUMP(status); | ||||
| 			snprint(buf, sizeof buf, "%d %lud %lud %lud 'signal: %s%s'", pid, u, s, u+s, _p9sigstr(WTERMSIG(status), tmp), cd ? " (core dumped)" : ""); | ||||
| 			strecpy(str, str+n, buf); | ||||
| 			return strlen(str); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int | ||||
| await(char *str, int n) | ||||
| { | ||||
| 	return _await(-1, str, n, 0); | ||||
| } | ||||
|  | ||||
| int | ||||
| awaitnohang(char *str, int n) | ||||
| { | ||||
| 	return _await(-1, str, n, WNOHANG); | ||||
| } | ||||
|  | ||||
| int | ||||
| awaitfor(int pid, char *str, int n) | ||||
| { | ||||
| 	return _await(pid, str, n, 0); | ||||
| } | ||||
							
								
								
									
										26
									
								
								lib/lib9/cistrcmp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								lib/lib9/cistrcmp.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| int | ||||
| cistrcmp(char *s1, char *s2) | ||||
| { | ||||
| 	int c1, c2; | ||||
|  | ||||
| 	while(*s1){ | ||||
| 		c1 = *(uchar*)s1++; | ||||
| 		c2 = *(uchar*)s2++; | ||||
|  | ||||
| 		if(c1 == c2) | ||||
| 			continue; | ||||
|  | ||||
| 		if(c1 >= 'A' && c1 <= 'Z') | ||||
| 			c1 -= 'A' - 'a'; | ||||
|  | ||||
| 		if(c2 >= 'A' && c2 <= 'Z') | ||||
| 			c2 -= 'A' - 'a'; | ||||
|  | ||||
| 		if(c1 != c2) | ||||
| 			return c1 - c2; | ||||
| 	} | ||||
| 	return -*s2; | ||||
| } | ||||
							
								
								
									
										28
									
								
								lib/lib9/cistrncmp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								lib/lib9/cistrncmp.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| int | ||||
| cistrncmp(char *s1, char *s2, int n) | ||||
| { | ||||
| 	int c1, c2; | ||||
|  | ||||
| 	while(*s1 && n-- > 0){ | ||||
| 		c1 = *(uchar*)s1++; | ||||
| 		c2 = *(uchar*)s2++; | ||||
|  | ||||
| 		if(c1 == c2) | ||||
| 			continue; | ||||
|  | ||||
| 		if(c1 >= 'A' && c1 <= 'Z') | ||||
| 			c1 -= 'A' - 'a'; | ||||
|  | ||||
| 		if(c2 >= 'A' && c2 <= 'Z') | ||||
| 			c2 -= 'A' - 'a'; | ||||
|  | ||||
| 		if(c1 != c2) | ||||
| 			return c1 - c2; | ||||
| 	} | ||||
| 	if(n <= 0) | ||||
| 		return 0; | ||||
| 	return -*s2; | ||||
| } | ||||
							
								
								
									
										23
									
								
								lib/lib9/cistrstr.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								lib/lib9/cistrstr.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| char* | ||||
| cistrstr(char *s, char *sub) | ||||
| { | ||||
| 	int c, csub, n; | ||||
|  | ||||
| 	csub = *sub; | ||||
| 	if(csub == '\0') | ||||
| 		return s; | ||||
| 	if(csub >= 'A' && csub <= 'Z') | ||||
| 		csub -= 'A' - 'a'; | ||||
| 	sub++; | ||||
| 	n = strlen(sub); | ||||
| 	for(; c = *s; s++){ | ||||
| 		if(c >= 'A' && c <= 'Z') | ||||
| 			c -= 'A' - 'a'; | ||||
| 		if(c == csub && cistrncmp(s+1, sub, n) == 0) | ||||
| 			return s; | ||||
| 	} | ||||
| 	return nil; | ||||
| } | ||||
							
								
								
									
										52
									
								
								lib/lib9/cleanname.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								lib/lib9/cleanname.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| /* | ||||
|  * In place, rewrite name to compress multiple /, eliminate ., and process .. | ||||
|  */ | ||||
| #define SEP(x)	((x)=='/' || (x) == 0) | ||||
| char* | ||||
| cleanname(char *name) | ||||
| { | ||||
| 	char *p, *q, *dotdot; | ||||
| 	int rooted; | ||||
|  | ||||
| 	rooted = name[0] == '/'; | ||||
|  | ||||
| 	/* | ||||
| 	 * invariants: | ||||
| 	 *	p points at beginning of path element we're considering. | ||||
| 	 *	q points just past the last path element we wrote (no slash). | ||||
| 	 *	dotdot points just past the point where .. cannot backtrack | ||||
| 	 *		any further (no slash). | ||||
| 	 */ | ||||
| 	p = q = dotdot = name+rooted; | ||||
| 	while(*p) { | ||||
| 		if(p[0] == '/')	/* null element */ | ||||
| 			p++; | ||||
| 		else if(p[0] == '.' && SEP(p[1])) | ||||
| 			p += 1;	/* don't count the separator in case it is nul */ | ||||
| 		else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) { | ||||
| 			p += 2; | ||||
| 			if(q > dotdot) {	/* can backtrack */ | ||||
| 				while(--q > dotdot && *q != '/') | ||||
| 					; | ||||
| 			} else if(!rooted) {	/* /.. is / but ./../ is .. */ | ||||
| 				if(q != name) | ||||
| 					*q++ = '/'; | ||||
| 				*q++ = '.'; | ||||
| 				*q++ = '.'; | ||||
| 				dotdot = q; | ||||
| 			} | ||||
| 		} else {	/* real path element */ | ||||
| 			if(q != name+rooted) | ||||
| 				*q++ = '/'; | ||||
| 			while((*q = *p) != '/' && *q != 0) | ||||
| 				p++, q++; | ||||
| 		} | ||||
| 	} | ||||
| 	if(q == name)	/* empty string is really ``.'' */ | ||||
| 		*q++ = '.'; | ||||
| 	*q = '\0'; | ||||
| 	return name; | ||||
| } | ||||
							
								
								
									
										101
									
								
								lib/lib9/convD2M.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								lib/lib9/convD2M.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| #include	<u.h> | ||||
| #include	<libc.h> | ||||
| #include	<fcall.h> | ||||
|  | ||||
| uint | ||||
| sizeD2M(Dir *d) | ||||
| { | ||||
| 	char *sv[5]; | ||||
| 	int i, ns, nstr, fixlen; | ||||
|  | ||||
| 	sv[0] = d->name; | ||||
| 	sv[1] = d->uid; | ||||
| 	sv[2] = d->gid; | ||||
| 	sv[3] = d->muid; | ||||
|  | ||||
| 	fixlen = STATFIXLEN; | ||||
| 	nstr = 4; | ||||
|  | ||||
| 	ns = 0; | ||||
| 	for(i = 0; i < nstr; i++) | ||||
| 		if(sv[i]) | ||||
| 			ns += strlen(sv[i]); | ||||
|  | ||||
| 	return fixlen + ns; | ||||
| } | ||||
|  | ||||
| uint | ||||
| convD2M(Dir *d, uchar *buf, uint nbuf) | ||||
| { | ||||
| 	uchar *p, *ebuf; | ||||
| 	char *sv[5]; | ||||
| 	int i, ns, nsv[5], ss, nstr, fixlen; | ||||
|  | ||||
| 	if(nbuf < BIT16SZ) | ||||
| 		return 0; | ||||
|  | ||||
| 	p = buf; | ||||
| 	ebuf = buf + nbuf; | ||||
|  | ||||
| 	sv[0] = d->name; | ||||
| 	sv[1] = d->uid; | ||||
| 	sv[2] = d->gid; | ||||
| 	sv[3] = d->muid; | ||||
|  | ||||
| 	fixlen = STATFIXLEN; | ||||
| 	nstr = 4; | ||||
|  | ||||
| 	ns = 0; | ||||
| 	for(i = 0; i < nstr; i++){ | ||||
| 		if(sv[i]) | ||||
| 			nsv[i] = strlen(sv[i]); | ||||
| 		else | ||||
| 			nsv[i] = 0; | ||||
| 		ns += nsv[i]; | ||||
| 	} | ||||
|  | ||||
| 	ss = fixlen + ns; | ||||
|  | ||||
| 	/* set size befor erroring, so user can know how much is needed */ | ||||
| 	/* note that length excludes count field itself */ | ||||
| 	PBIT16(p, ss-BIT16SZ); | ||||
| 	p += BIT16SZ; | ||||
|  | ||||
| 	if(ss > nbuf) | ||||
| 		return BIT16SZ; | ||||
|  | ||||
| 	PBIT16(p, d->type); | ||||
| 	p += BIT16SZ; | ||||
| 	PBIT32(p, d->dev); | ||||
| 	p += BIT32SZ; | ||||
| 	PBIT8(p, d->qid.type); | ||||
| 	p += BIT8SZ; | ||||
| 	PBIT32(p, d->qid.vers); | ||||
| 	p += BIT32SZ; | ||||
| 	PBIT64(p, d->qid.path); | ||||
| 	p += BIT64SZ; | ||||
| 	PBIT32(p, d->mode); | ||||
| 	p += BIT32SZ; | ||||
| 	PBIT32(p, d->atime); | ||||
| 	p += BIT32SZ; | ||||
| 	PBIT32(p, d->mtime); | ||||
| 	p += BIT32SZ; | ||||
| 	PBIT64(p, d->length); | ||||
| 	p += BIT64SZ; | ||||
|  | ||||
| 	for(i = 0; i < nstr; i++){ | ||||
| 		ns = nsv[i]; | ||||
| 		if(p + ns + BIT16SZ > ebuf) | ||||
| 			return 0; | ||||
| 		PBIT16(p, ns); | ||||
| 		p += BIT16SZ; | ||||
| 		if(ns) | ||||
| 			memmove(p, sv[i], ns); | ||||
| 		p += ns; | ||||
| 	} | ||||
|  | ||||
| 	if(ss != p - buf) | ||||
| 		return 0; | ||||
|  | ||||
| 	return p - buf; | ||||
| } | ||||
							
								
								
									
										98
									
								
								lib/lib9/convM2D.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								lib/lib9/convM2D.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| #include	<u.h> | ||||
| #include	<libc.h> | ||||
| #include	<fcall.h> | ||||
|  | ||||
| int | ||||
| statcheck(uchar *buf, uint nbuf) | ||||
| { | ||||
| 	uchar *ebuf; | ||||
| 	int i, nstr; | ||||
|  | ||||
| 	ebuf = buf + nbuf; | ||||
|  | ||||
| 	if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf)) | ||||
| 		return -1; | ||||
|  | ||||
| 	buf += STATFIXLEN - 4 * BIT16SZ; | ||||
|  | ||||
| 	nstr = 4; | ||||
| 	for(i = 0; i < nstr; i++){ | ||||
| 		if(buf + BIT16SZ > ebuf) | ||||
| 			return -1; | ||||
| 		buf += BIT16SZ + GBIT16(buf); | ||||
| 	} | ||||
|  | ||||
| 	if(buf != ebuf) | ||||
| 		return -1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static char nullstring[] = ""; | ||||
|  | ||||
| uint | ||||
| convM2D(uchar *buf, uint nbuf, Dir *d, char *strs) | ||||
| { | ||||
| 	uchar *p, *ebuf; | ||||
| 	char *sv[5]; | ||||
| 	int i, ns, nstr; | ||||
|  | ||||
| 	if(nbuf < STATFIXLEN) | ||||
| 		return 0; | ||||
|  | ||||
| 	p = buf; | ||||
| 	ebuf = buf + nbuf; | ||||
|  | ||||
| 	p += BIT16SZ;	/* ignore size */ | ||||
| 	d->type = GBIT16(p); | ||||
| 	p += BIT16SZ; | ||||
| 	d->dev = GBIT32(p); | ||||
| 	p += BIT32SZ; | ||||
| 	d->qid.type = GBIT8(p); | ||||
| 	p += BIT8SZ; | ||||
| 	d->qid.vers = GBIT32(p); | ||||
| 	p += BIT32SZ; | ||||
| 	d->qid.path = GBIT64(p); | ||||
| 	p += BIT64SZ; | ||||
| 	d->mode = GBIT32(p); | ||||
| 	p += BIT32SZ; | ||||
| 	d->atime = GBIT32(p); | ||||
| 	p += BIT32SZ; | ||||
| 	d->mtime = GBIT32(p); | ||||
| 	p += BIT32SZ; | ||||
| 	d->length = GBIT64(p); | ||||
| 	p += BIT64SZ; | ||||
|  | ||||
| 	nstr = 4; | ||||
| 	for(i = 0; i < nstr; i++){ | ||||
| 		if(p + BIT16SZ > ebuf) | ||||
| 			return 0; | ||||
| 		ns = GBIT16(p); | ||||
| 		p += BIT16SZ; | ||||
| 		if(p + ns > ebuf) | ||||
| 			return 0; | ||||
| 		if(strs){ | ||||
| 			sv[i] = strs; | ||||
| 			memmove(strs, p, ns); | ||||
| 			strs += ns; | ||||
| 			*strs++ = '\0'; | ||||
| 		} | ||||
| 		p += ns; | ||||
| 	} | ||||
|  | ||||
| 	if(strs){ | ||||
| 		d->name = sv[0]; | ||||
| 		d->uid = sv[1]; | ||||
| 		d->gid = sv[2]; | ||||
| 		d->muid = sv[3]; | ||||
| 		d->ext = nullstring; | ||||
| 	}else{ | ||||
| 		d->name = nullstring; | ||||
| 		d->uid = nullstring; | ||||
| 		d->gid = nullstring; | ||||
| 		d->muid = nullstring; | ||||
| 		d->ext = nullstring; | ||||
| 	} | ||||
|  | ||||
| 	return p - buf; | ||||
| } | ||||
							
								
								
									
										326
									
								
								lib/lib9/convM2S.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										326
									
								
								lib/lib9/convM2S.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,326 @@ | ||||
| #include	<u.h> | ||||
| #include	<libc.h> | ||||
| #include	<fcall.h> | ||||
|  | ||||
| static | ||||
| uchar* | ||||
| gstring(uchar *p, uchar *ep, char **s) | ||||
| { | ||||
| 	uint n; | ||||
|  | ||||
| 	if(p+BIT16SZ > ep) | ||||
| 		return nil; | ||||
| 	n = GBIT16(p); | ||||
| 	p += BIT16SZ - 1; | ||||
| 	if(p+n+1 > ep) | ||||
| 		return nil; | ||||
| 	/* move it down, on top of count, to make room for '\0' */ | ||||
| 	memmove(p, p + 1, n); | ||||
| 	p[n] = '\0'; | ||||
| 	*s = (char*)p; | ||||
| 	p += n+1; | ||||
| 	return p; | ||||
| } | ||||
|  | ||||
| static | ||||
| uchar* | ||||
| gqid(uchar *p, uchar *ep, Qid *q) | ||||
| { | ||||
| 	if(p+QIDSZ > ep) | ||||
| 		return nil; | ||||
| 	q->type = GBIT8(p); | ||||
| 	p += BIT8SZ; | ||||
| 	q->vers = GBIT32(p); | ||||
| 	p += BIT32SZ; | ||||
| 	q->path = GBIT64(p); | ||||
| 	p += BIT64SZ; | ||||
| 	return p; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * no syntactic checks. | ||||
|  * three causes for error: | ||||
|  *  1. message size field is incorrect | ||||
|  *  2. input buffer too short for its own data (counts too long, etc.) | ||||
|  *  3. too many names or qids | ||||
|  * gqid() and gstring() return nil if they would reach beyond buffer. | ||||
|  * main switch statement checks range and also can fall through | ||||
|  * to test at end of routine. | ||||
|  */ | ||||
| uint | ||||
| convM2S(uchar *ap, uint nap, Fcall *f) | ||||
| { | ||||
| 	uchar *p, *ep; | ||||
| 	uint i, size; | ||||
|  | ||||
| 	p = ap; | ||||
| 	ep = p + nap; | ||||
|  | ||||
| 	if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep) | ||||
| 		return 0; | ||||
| 	size = GBIT32(p); | ||||
| 	p += BIT32SZ; | ||||
|  | ||||
| 	if(size < BIT32SZ+BIT8SZ+BIT16SZ) | ||||
| 		return 0; | ||||
|  | ||||
| 	f->type = GBIT8(p); | ||||
| 	p += BIT8SZ; | ||||
| 	f->tag = GBIT16(p); | ||||
| 	p += BIT16SZ; | ||||
|  | ||||
| 	switch(f->type) | ||||
| 	{ | ||||
| 	default: | ||||
| 		return 0; | ||||
|  | ||||
| 	case Tversion: | ||||
| 		if(p+BIT32SZ > ep) | ||||
| 			return 0; | ||||
| 		f->msize = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		p = gstring(p, ep, &f->version); | ||||
| 		break; | ||||
|  | ||||
| 	case Tflush: | ||||
| 		if(p+BIT16SZ > ep) | ||||
| 			return 0; | ||||
| 		f->oldtag = GBIT16(p); | ||||
| 		p += BIT16SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Tauth: | ||||
| 		if(p+BIT32SZ > ep) | ||||
| 			return 0; | ||||
| 		f->afid = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		p = gstring(p, ep, &f->uname); | ||||
| 		if(p == nil) | ||||
| 			break; | ||||
| 		p = gstring(p, ep, &f->aname); | ||||
| 		if(p == nil) | ||||
| 			break; | ||||
| 		f->uidnum = NOUID; | ||||
| 		break; | ||||
|  | ||||
| 	case Tattach: | ||||
| 		if(p+BIT32SZ > ep) | ||||
| 			return 0; | ||||
| 		f->fid = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		if(p+BIT32SZ > ep) | ||||
| 			return 0; | ||||
| 		f->afid = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		p = gstring(p, ep, &f->uname); | ||||
| 		if(p == nil) | ||||
| 			break; | ||||
| 		p = gstring(p, ep, &f->aname); | ||||
| 		if(p == nil) | ||||
| 			break; | ||||
| 		f->uidnum = NOUID; | ||||
| 		break; | ||||
|  | ||||
| 	case Twalk: | ||||
| 		if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep) | ||||
| 			return 0; | ||||
| 		f->fid = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		f->newfid = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		f->nwname = GBIT16(p); | ||||
| 		p += BIT16SZ; | ||||
| 		if(f->nwname > MAXWELEM) | ||||
| 			return 0; | ||||
| 		for(i=0; i<f->nwname; i++){ | ||||
| 			p = gstring(p, ep, &f->wname[i]); | ||||
| 			if(p == nil) | ||||
| 				break; | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case Topen: | ||||
| 	case Topenfd: | ||||
| 		if(p+BIT32SZ+BIT8SZ > ep) | ||||
| 			return 0; | ||||
| 		f->fid = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		f->mode = GBIT8(p); | ||||
| 		p += BIT8SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Tcreate: | ||||
| 		if(p+BIT32SZ > ep) | ||||
| 			return 0; | ||||
| 		f->fid = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		p = gstring(p, ep, &f->name); | ||||
| 		if(p == nil) | ||||
| 			break; | ||||
| 		if(p+BIT32SZ+BIT8SZ > ep) | ||||
| 			return 0; | ||||
| 		f->perm = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		f->mode = GBIT8(p); | ||||
| 		p += BIT8SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Tread: | ||||
| 		if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) | ||||
| 			return 0; | ||||
| 		f->fid = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		f->offset = GBIT64(p); | ||||
| 		p += BIT64SZ; | ||||
| 		f->count = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Twrite: | ||||
| 		if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) | ||||
| 			return 0; | ||||
| 		f->fid = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		f->offset = GBIT64(p); | ||||
| 		p += BIT64SZ; | ||||
| 		f->count = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		if(p+f->count > ep) | ||||
| 			return 0; | ||||
| 		f->data = (char*)p; | ||||
| 		p += f->count; | ||||
| 		break; | ||||
|  | ||||
| 	case Tclunk: | ||||
| 	case Tremove: | ||||
| 		if(p+BIT32SZ > ep) | ||||
| 			return 0; | ||||
| 		f->fid = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Tstat: | ||||
| 		if(p+BIT32SZ > ep) | ||||
| 			return 0; | ||||
| 		f->fid = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Twstat: | ||||
| 		if(p+BIT32SZ+BIT16SZ > ep) | ||||
| 			return 0; | ||||
| 		f->fid = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		f->nstat = GBIT16(p); | ||||
| 		p += BIT16SZ; | ||||
| 		if(p+f->nstat > ep) | ||||
| 			return 0; | ||||
| 		f->stat = p; | ||||
| 		p += f->nstat; | ||||
| 		break; | ||||
|  | ||||
| /* | ||||
|  */ | ||||
| 	case Rversion: | ||||
| 		if(p+BIT32SZ > ep) | ||||
| 			return 0; | ||||
| 		f->msize = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		p = gstring(p, ep, &f->version); | ||||
| 		break; | ||||
|  | ||||
| 	case Rerror: | ||||
| 		p = gstring(p, ep, &f->ename); | ||||
| 		f->errornum = 0; | ||||
| 		break; | ||||
|  | ||||
| 	case Rflush: | ||||
| 		break; | ||||
|  | ||||
| 	case Rauth: | ||||
| 		p = gqid(p, ep, &f->aqid); | ||||
| 		if(p == nil) | ||||
| 			break; | ||||
| 		break; | ||||
|  | ||||
| 	case Rattach: | ||||
| 		p = gqid(p, ep, &f->qid); | ||||
| 		if(p == nil) | ||||
| 			break; | ||||
| 		break; | ||||
|  | ||||
| 	case Rwalk: | ||||
| 		if(p+BIT16SZ > ep) | ||||
| 			return 0; | ||||
| 		f->nwqid = GBIT16(p); | ||||
| 		p += BIT16SZ; | ||||
| 		if(f->nwqid > MAXWELEM) | ||||
| 			return 0; | ||||
| 		for(i=0; i<f->nwqid; i++){ | ||||
| 			p = gqid(p, ep, &f->wqid[i]); | ||||
| 			if(p == nil) | ||||
| 				break; | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case Ropen: | ||||
| 	case Ropenfd: | ||||
| 	case Rcreate: | ||||
| 		p = gqid(p, ep, &f->qid); | ||||
| 		if(p == nil) | ||||
| 			break; | ||||
| 		if(p+BIT32SZ > ep) | ||||
| 			return 0; | ||||
| 		f->iounit = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		if(f->type == Ropenfd){ | ||||
| 			if(p+BIT32SZ > ep) | ||||
| 				return 0; | ||||
| 			f->unixfd = GBIT32(p); | ||||
| 			p += BIT32SZ; | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case Rread: | ||||
| 		if(p+BIT32SZ > ep) | ||||
| 			return 0; | ||||
| 		f->count = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		if(p+f->count > ep) | ||||
| 			return 0; | ||||
| 		f->data = (char*)p; | ||||
| 		p += f->count; | ||||
| 		break; | ||||
|  | ||||
| 	case Rwrite: | ||||
| 		if(p+BIT32SZ > ep) | ||||
| 			return 0; | ||||
| 		f->count = GBIT32(p); | ||||
| 		p += BIT32SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Rclunk: | ||||
| 	case Rremove: | ||||
| 		break; | ||||
|  | ||||
| 	case Rstat: | ||||
| 		if(p+BIT16SZ > ep) | ||||
| 			return 0; | ||||
| 		f->nstat = GBIT16(p); | ||||
| 		p += BIT16SZ; | ||||
| 		if(p+f->nstat > ep) | ||||
| 			return 0; | ||||
| 		f->stat = p; | ||||
| 		p += f->nstat; | ||||
| 		break; | ||||
|  | ||||
| 	case Rwstat: | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	if(p==nil || p>ep) | ||||
| 		return 0; | ||||
| 	if(ap+size == p) | ||||
| 		return size; | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										399
									
								
								lib/lib9/convS2M.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										399
									
								
								lib/lib9/convS2M.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,399 @@ | ||||
| #include	<u.h> | ||||
| #include	<libc.h> | ||||
| #include	<fcall.h> | ||||
|  | ||||
| static | ||||
| uchar* | ||||
| pstring(uchar *p, char *s) | ||||
| { | ||||
| 	uint n; | ||||
|  | ||||
| 	if(s == nil){ | ||||
| 		PBIT16(p, 0); | ||||
| 		p += BIT16SZ; | ||||
| 		return p; | ||||
| 	} | ||||
|  | ||||
| 	n = strlen(s); | ||||
| 	PBIT16(p, n); | ||||
| 	p += BIT16SZ; | ||||
| 	memmove(p, s, n); | ||||
| 	p += n; | ||||
| 	return p; | ||||
| } | ||||
|  | ||||
| static | ||||
| uchar* | ||||
| pqid(uchar *p, Qid *q) | ||||
| { | ||||
| 	PBIT8(p, q->type); | ||||
| 	p += BIT8SZ; | ||||
| 	PBIT32(p, q->vers); | ||||
| 	p += BIT32SZ; | ||||
| 	PBIT64(p, q->path); | ||||
| 	p += BIT64SZ; | ||||
| 	return p; | ||||
| } | ||||
|  | ||||
| static | ||||
| uint | ||||
| stringsz(char *s) | ||||
| { | ||||
| 	if(s == nil) | ||||
| 		return BIT16SZ; | ||||
|  | ||||
| 	return BIT16SZ+strlen(s); | ||||
| } | ||||
|  | ||||
| uint | ||||
| sizeS2M(Fcall *f) | ||||
| { | ||||
| 	uint n; | ||||
| 	int i; | ||||
|  | ||||
| 	n = 0; | ||||
| 	n += BIT32SZ;	/* size */ | ||||
| 	n += BIT8SZ;	/* type */ | ||||
| 	n += BIT16SZ;	/* tag */ | ||||
|  | ||||
| 	switch(f->type) | ||||
| 	{ | ||||
| 	default: | ||||
| 		return 0; | ||||
|  | ||||
| 	case Tversion: | ||||
| 		n += BIT32SZ; | ||||
| 		n += stringsz(f->version); | ||||
| 		break; | ||||
|  | ||||
| 	case Tflush: | ||||
| 		n += BIT16SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Tauth: | ||||
| 		n += BIT32SZ; | ||||
| 		n += stringsz(f->uname); | ||||
| 		n += stringsz(f->aname); | ||||
| 		break; | ||||
|  | ||||
| 	case Tattach: | ||||
| 		n += BIT32SZ; | ||||
| 		n += BIT32SZ; | ||||
| 		n += stringsz(f->uname); | ||||
| 		n += stringsz(f->aname); | ||||
| 		break; | ||||
|  | ||||
| 	case Twalk: | ||||
| 		n += BIT32SZ; | ||||
| 		n += BIT32SZ; | ||||
| 		n += BIT16SZ; | ||||
| 		for(i=0; i<f->nwname; i++) | ||||
| 			n += stringsz(f->wname[i]); | ||||
| 		break; | ||||
|  | ||||
| 	case Topen: | ||||
| 	case Topenfd: | ||||
| 		n += BIT32SZ; | ||||
| 		n += BIT8SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Tcreate: | ||||
| 		n += BIT32SZ; | ||||
| 		n += stringsz(f->name); | ||||
| 		n += BIT32SZ; | ||||
| 		n += BIT8SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Tread: | ||||
| 		n += BIT32SZ; | ||||
| 		n += BIT64SZ; | ||||
| 		n += BIT32SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Twrite: | ||||
| 		n += BIT32SZ; | ||||
| 		n += BIT64SZ; | ||||
| 		n += BIT32SZ; | ||||
| 		n += f->count; | ||||
| 		break; | ||||
|  | ||||
| 	case Tclunk: | ||||
| 	case Tremove: | ||||
| 		n += BIT32SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Tstat: | ||||
| 		n += BIT32SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Twstat: | ||||
| 		n += BIT32SZ; | ||||
| 		n += BIT16SZ; | ||||
| 		n += f->nstat; | ||||
| 		break; | ||||
| /* | ||||
|  */ | ||||
|  | ||||
| 	case Rversion: | ||||
| 		n += BIT32SZ; | ||||
| 		n += stringsz(f->version); | ||||
| 		break; | ||||
|  | ||||
| 	case Rerror: | ||||
| 		n += stringsz(f->ename); | ||||
| 		break; | ||||
|  | ||||
| 	case Rflush: | ||||
| 		break; | ||||
|  | ||||
| 	case Rauth: | ||||
| 		n += QIDSZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Rattach: | ||||
| 		n += QIDSZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Rwalk: | ||||
| 		n += BIT16SZ; | ||||
| 		n += f->nwqid*QIDSZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Ropen: | ||||
| 	case Rcreate: | ||||
| 		n += QIDSZ; | ||||
| 		n += BIT32SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Ropenfd: | ||||
| 		n += QIDSZ; | ||||
| 		n += BIT32SZ; | ||||
| 		n += BIT32SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Rread: | ||||
| 		n += BIT32SZ; | ||||
| 		n += f->count; | ||||
| 		break; | ||||
|  | ||||
| 	case Rwrite: | ||||
| 		n += BIT32SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Rclunk: | ||||
| 		break; | ||||
|  | ||||
| 	case Rremove: | ||||
| 		break; | ||||
|  | ||||
| 	case Rstat: | ||||
| 		n += BIT16SZ; | ||||
| 		n += f->nstat; | ||||
| 		break; | ||||
|  | ||||
| 	case Rwstat: | ||||
| 		break; | ||||
| 	} | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| uint | ||||
| convS2M(Fcall *f, uchar *ap, uint nap) | ||||
| { | ||||
| 	uchar *p; | ||||
| 	uint i, size; | ||||
|  | ||||
| 	size = sizeS2M(f); | ||||
| 	if(size == 0) | ||||
| 		return 0; | ||||
| 	if(size > nap) | ||||
| 		return 0; | ||||
|  | ||||
| 	p = (uchar*)ap; | ||||
|  | ||||
| 	PBIT32(p, size); | ||||
| 	p += BIT32SZ; | ||||
| 	PBIT8(p, f->type); | ||||
| 	p += BIT8SZ; | ||||
| 	PBIT16(p, f->tag); | ||||
| 	p += BIT16SZ; | ||||
|  | ||||
| 	switch(f->type) | ||||
| 	{ | ||||
| 	default: | ||||
| 		return 0; | ||||
|  | ||||
| 	case Tversion: | ||||
| 		PBIT32(p, f->msize); | ||||
| 		p += BIT32SZ; | ||||
| 		p = pstring(p, f->version); | ||||
| 		break; | ||||
|  | ||||
| 	case Tflush: | ||||
| 		PBIT16(p, f->oldtag); | ||||
| 		p += BIT16SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Tauth: | ||||
| 		PBIT32(p, f->afid); | ||||
| 		p += BIT32SZ; | ||||
| 		p  = pstring(p, f->uname); | ||||
| 		p  = pstring(p, f->aname); | ||||
| 		break; | ||||
|  | ||||
| 	case Tattach: | ||||
| 		PBIT32(p, f->fid); | ||||
| 		p += BIT32SZ; | ||||
| 		PBIT32(p, f->afid); | ||||
| 		p += BIT32SZ; | ||||
| 		p  = pstring(p, f->uname); | ||||
| 		p  = pstring(p, f->aname); | ||||
| 		break; | ||||
|  | ||||
| 	case Twalk: | ||||
| 		PBIT32(p, f->fid); | ||||
| 		p += BIT32SZ; | ||||
| 		PBIT32(p, f->newfid); | ||||
| 		p += BIT32SZ; | ||||
| 		PBIT16(p, f->nwname); | ||||
| 		p += BIT16SZ; | ||||
| 		if(f->nwname > MAXWELEM) | ||||
| 			return 0; | ||||
| 		for(i=0; i<f->nwname; i++) | ||||
| 			p = pstring(p, f->wname[i]); | ||||
| 		break; | ||||
|  | ||||
| 	case Topen: | ||||
| 	case Topenfd: | ||||
| 		PBIT32(p, f->fid); | ||||
| 		p += BIT32SZ; | ||||
| 		PBIT8(p, f->mode); | ||||
| 		p += BIT8SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Tcreate: | ||||
| 		PBIT32(p, f->fid); | ||||
| 		p += BIT32SZ; | ||||
| 		p = pstring(p, f->name); | ||||
| 		PBIT32(p, f->perm); | ||||
| 		p += BIT32SZ; | ||||
| 		PBIT8(p, f->mode); | ||||
| 		p += BIT8SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Tread: | ||||
| 		PBIT32(p, f->fid); | ||||
| 		p += BIT32SZ; | ||||
| 		PBIT64(p, f->offset); | ||||
| 		p += BIT64SZ; | ||||
| 		PBIT32(p, f->count); | ||||
| 		p += BIT32SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Twrite: | ||||
| 		PBIT32(p, f->fid); | ||||
| 		p += BIT32SZ; | ||||
| 		PBIT64(p, f->offset); | ||||
| 		p += BIT64SZ; | ||||
| 		PBIT32(p, f->count); | ||||
| 		p += BIT32SZ; | ||||
| 		memmove(p, f->data, f->count); | ||||
| 		p += f->count; | ||||
| 		break; | ||||
|  | ||||
| 	case Tclunk: | ||||
| 	case Tremove: | ||||
| 		PBIT32(p, f->fid); | ||||
| 		p += BIT32SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Tstat: | ||||
| 		PBIT32(p, f->fid); | ||||
| 		p += BIT32SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Twstat: | ||||
| 		PBIT32(p, f->fid); | ||||
| 		p += BIT32SZ; | ||||
| 		PBIT16(p, f->nstat); | ||||
| 		p += BIT16SZ; | ||||
| 		memmove(p, f->stat, f->nstat); | ||||
| 		p += f->nstat; | ||||
| 		break; | ||||
| /* | ||||
|  */ | ||||
|  | ||||
| 	case Rversion: | ||||
| 		PBIT32(p, f->msize); | ||||
| 		p += BIT32SZ; | ||||
| 		p = pstring(p, f->version); | ||||
| 		break; | ||||
|  | ||||
| 	case Rerror: | ||||
| 		p = pstring(p, f->ename); | ||||
| 		break; | ||||
|  | ||||
| 	case Rflush: | ||||
| 		break; | ||||
|  | ||||
| 	case Rauth: | ||||
| 		p = pqid(p, &f->aqid); | ||||
| 		break; | ||||
|  | ||||
| 	case Rattach: | ||||
| 		p = pqid(p, &f->qid); | ||||
| 		break; | ||||
|  | ||||
| 	case Rwalk: | ||||
| 		PBIT16(p, f->nwqid); | ||||
| 		p += BIT16SZ; | ||||
| 		if(f->nwqid > MAXWELEM) | ||||
| 			return 0; | ||||
| 		for(i=0; i<f->nwqid; i++) | ||||
| 			p = pqid(p, &f->wqid[i]); | ||||
| 		break; | ||||
|  | ||||
| 	case Ropen: | ||||
| 	case Rcreate: | ||||
| 	case Ropenfd: | ||||
| 		p = pqid(p, &f->qid); | ||||
| 		PBIT32(p, f->iounit); | ||||
| 		p += BIT32SZ; | ||||
| 		if(f->type == Ropenfd){ | ||||
| 			PBIT32(p, f->unixfd); | ||||
| 			p += BIT32SZ; | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case Rread: | ||||
| 		PBIT32(p, f->count); | ||||
| 		p += BIT32SZ; | ||||
| 		memmove(p, f->data, f->count); | ||||
| 		p += f->count; | ||||
| 		break; | ||||
|  | ||||
| 	case Rwrite: | ||||
| 		PBIT32(p, f->count); | ||||
| 		p += BIT32SZ; | ||||
| 		break; | ||||
|  | ||||
| 	case Rclunk: | ||||
| 		break; | ||||
|  | ||||
| 	case Rremove: | ||||
| 		break; | ||||
|  | ||||
| 	case Rstat: | ||||
| 		PBIT16(p, f->nstat); | ||||
| 		p += BIT16SZ; | ||||
| 		memmove(p, f->stat, f->nstat); | ||||
| 		p += f->nstat; | ||||
| 		break; | ||||
|  | ||||
| 	case Rwstat: | ||||
| 		break; | ||||
| 	} | ||||
| 	if(size != p-ap) | ||||
| 		return 0; | ||||
| 	return size; | ||||
| } | ||||
							
								
								
									
										68
									
								
								lib/lib9/crypt.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								lib/lib9/crypt.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| /* | ||||
|  *	Data Encryption Standard | ||||
|  *	D.P.Mitchell  83/06/08. | ||||
|  * | ||||
|  *	block_cipher(key, block, decrypting) | ||||
|  * | ||||
|  *	these routines use the non-standard 7 byte format | ||||
|  *	for DES keys. | ||||
|  */ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <auth.h> | ||||
| #include <libsec.h> | ||||
|  | ||||
| /* | ||||
|  * destructively encrypt the buffer, which | ||||
|  * must be at least 8 characters long. | ||||
|  */ | ||||
| int | ||||
| encrypt(void *key, void *vbuf, int n) | ||||
| { | ||||
| 	ulong ekey[32]; | ||||
| 	uchar *buf; | ||||
| 	int i, r; | ||||
|  | ||||
| 	if(n < 8) | ||||
| 		return 0; | ||||
| 	key_setup(key, ekey); | ||||
| 	buf = vbuf; | ||||
| 	n--; | ||||
| 	r = n % 7; | ||||
| 	n /= 7; | ||||
| 	for(i = 0; i < n; i++){ | ||||
| 		block_cipher(ekey, buf, 0); | ||||
| 		buf += 7; | ||||
| 	} | ||||
| 	if(r) | ||||
| 		block_cipher(ekey, buf - 7 + r, 0); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * destructively decrypt the buffer, which | ||||
|  * must be at least 8 characters long. | ||||
|  */ | ||||
| int | ||||
| decrypt(void *key, void *vbuf, int n) | ||||
| { | ||||
| 	ulong ekey[128]; | ||||
| 	uchar *buf; | ||||
| 	int i, r; | ||||
|  | ||||
| 	if(n < 8) | ||||
| 		return 0; | ||||
| 	key_setup(key, ekey); | ||||
| 	buf = vbuf; | ||||
| 	n--; | ||||
| 	r = n % 7; | ||||
| 	n /= 7; | ||||
| 	buf += n * 7; | ||||
| 	if(r) | ||||
| 		block_cipher(ekey, buf - 7 + r, 1); | ||||
| 	for(i = 0; i < n; i++){ | ||||
| 		buf -= 7; | ||||
| 		block_cipher(ekey, buf, 1); | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										180
									
								
								lib/lib9/ctime.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								lib/lib9/ctime.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,180 @@ | ||||
| /* | ||||
|  * This routine converts time as follows. | ||||
|  * The epoch is 0000 Jan 1 1970 GMT. | ||||
|  * The argument time is in seconds since then. | ||||
|  * The localtime(t) entry returns a pointer to an array | ||||
|  * containing | ||||
|  * | ||||
|  *	seconds (0-59) | ||||
|  *	minutes (0-59) | ||||
|  *	hours (0-23) | ||||
|  *	day of month (1-31) | ||||
|  *	month (0-11) | ||||
|  *	year-1970 | ||||
|  *	weekday (0-6, Sun is 0) | ||||
|  *	day of the year | ||||
|  *	daylight savings flag | ||||
|  * | ||||
|  * The routine gets the daylight savings time from the environment. | ||||
|  * | ||||
|  * asctime(tvec)) | ||||
|  * where tvec is produced by localtime | ||||
|  * returns a ptr to a character string | ||||
|  * that has the ascii time in the form | ||||
|  * | ||||
|  *	                            \\ | ||||
|  *	Thu Jan 01 00:00:00 GMT 1970n0 | ||||
|  *	012345678901234567890123456789 | ||||
|  *	0	  1	    2 | ||||
|  * | ||||
|  * ctime(t) just calls localtime, then asctime. | ||||
|  */ | ||||
|  | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| #include "zoneinfo.h" | ||||
|  | ||||
| static	char	dmsize[12] = | ||||
| { | ||||
| 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 | ||||
| }; | ||||
|  | ||||
| #define dysize ctimedysize | ||||
| static	int	dysize(int); | ||||
| static	void	ct_numb(char*, int); | ||||
|  | ||||
| char* | ||||
| ctime(long t) | ||||
| { | ||||
| 	return asctime(localtime(t)); | ||||
| } | ||||
|  | ||||
| Tm* | ||||
| localtime(long tim) | ||||
| { | ||||
| 	Tinfo ti; | ||||
| 	Tm *ct; | ||||
|  | ||||
| 	if (zonelookuptinfo(&ti, tim)!=-1) { | ||||
| 		ct = gmtime(tim+ti.tzoff); | ||||
| 		strncpy(ct->zone, ti.zone, sizeof ct->zone - 1); | ||||
| 		ct->zone[sizeof ct->zone-1] = 0; | ||||
| 		ct->tzoff = ti.tzoff; | ||||
| 		return ct; | ||||
| 	} | ||||
| 	return gmtime(tim); | ||||
| } | ||||
|  | ||||
| Tm* | ||||
| gmtime(long tim) | ||||
| { | ||||
| 	int d0, d1; | ||||
| 	long hms, day; | ||||
| 	static Tm xtime; | ||||
|  | ||||
| 	/* | ||||
| 	 * break initial number into days | ||||
| 	 */ | ||||
| 	hms = tim % 86400L; | ||||
| 	day = tim / 86400L; | ||||
| 	if(hms < 0) { | ||||
| 		hms += 86400L; | ||||
| 		day -= 1; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * generate hours:minutes:seconds | ||||
| 	 */ | ||||
| 	xtime.sec = hms % 60; | ||||
| 	d1 = hms / 60; | ||||
| 	xtime.min = d1 % 60; | ||||
| 	d1 /= 60; | ||||
| 	xtime.hour = d1; | ||||
|  | ||||
| 	/* | ||||
| 	 * day is the day number. | ||||
| 	 * generate day of the week. | ||||
| 	 * The addend is 4 mod 7 (1/1/1970 was Thursday) | ||||
| 	 */ | ||||
|  | ||||
| 	xtime.wday = (day + 7340036L) % 7; | ||||
|  | ||||
| 	/* | ||||
| 	 * year number | ||||
| 	 */ | ||||
| 	if(day >= 0) | ||||
| 		for(d1 = 1970; day >= dysize(d1); d1++) | ||||
| 			day -= dysize(d1); | ||||
| 	else | ||||
| 		for (d1 = 1970; day < 0; d1--) | ||||
| 			day += dysize(d1-1); | ||||
| 	xtime.year = d1-1900; | ||||
| 	xtime.yday = d0 = day; | ||||
|  | ||||
| 	/* | ||||
| 	 * generate month | ||||
| 	 */ | ||||
|  | ||||
| 	if(dysize(d1) == 366) | ||||
| 		dmsize[1] = 29; | ||||
| 	for(d1 = 0; d0 >= dmsize[d1]; d1++) | ||||
| 		d0 -= dmsize[d1]; | ||||
| 	dmsize[1] = 28; | ||||
| 	xtime.mday = d0 + 1; | ||||
| 	xtime.mon = d1; | ||||
| 	strcpy(xtime.zone, "GMT"); | ||||
| 	return &xtime; | ||||
| } | ||||
|  | ||||
| char* | ||||
| asctime(Tm *t) | ||||
| { | ||||
| 	const char *ncp; | ||||
| 	static char cbuf[30]; | ||||
|  | ||||
| 	strcpy(cbuf, "Thu Jan 01 00:00:00 GMT 1970\n"); | ||||
| 	ncp = &"SunMonTueWedThuFriSat"[t->wday*3]; | ||||
| 	cbuf[0] = *ncp++; | ||||
| 	cbuf[1] = *ncp++; | ||||
| 	cbuf[2] = *ncp; | ||||
| 	ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->mon*3]; | ||||
| 	cbuf[4] = *ncp++; | ||||
| 	cbuf[5] = *ncp++; | ||||
| 	cbuf[6] = *ncp; | ||||
| 	ct_numb(cbuf+8, t->mday); | ||||
| 	ct_numb(cbuf+11, t->hour+100); | ||||
| 	ct_numb(cbuf+14, t->min+100); | ||||
| 	ct_numb(cbuf+17, t->sec+100); | ||||
| 	ncp = t->zone; | ||||
| 	cbuf[20] = *ncp++; | ||||
| 	cbuf[21] = *ncp++; | ||||
| 	cbuf[22] = *ncp; | ||||
| 	if(t->year >= 100) { | ||||
| 		cbuf[24] = '2'; | ||||
| 		cbuf[25] = '0'; | ||||
| 	} | ||||
| 	ct_numb(cbuf+26, t->year+100); | ||||
| 	return cbuf; | ||||
| } | ||||
|  | ||||
| static | ||||
| int | ||||
| dysize(int y) | ||||
| { | ||||
|  | ||||
| 	if(y%4 == 0 && (y%100 != 0 || y%400 == 0)) | ||||
| 		return 366; | ||||
| 	return 365; | ||||
| } | ||||
|  | ||||
| static | ||||
| void | ||||
| ct_numb(char *cp, int n) | ||||
| { | ||||
|  | ||||
| 	cp[0] = ' '; | ||||
| 	if(n >= 10) | ||||
| 		cp[0] = (n/10)%10 + '0'; | ||||
| 	cp[1] = n%10 + '0'; | ||||
| } | ||||
							
								
								
									
										157
									
								
								lib/lib9/debugmalloc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								lib/lib9/debugmalloc.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,157 @@ | ||||
| #include <u.h> | ||||
| #define NOPLAN9DEFINES | ||||
| #include <libc.h> | ||||
|  | ||||
| /* | ||||
|  * The Unix libc routines cannot be trusted to do their own locking. | ||||
|  * Sad but apparently true. | ||||
|  */ | ||||
| static int mallocpid; | ||||
|  | ||||
| /* | ||||
|  * The Unix mallocs don't do nearly enough error checking | ||||
|  * for my tastes.  We'll waste another 24 bytes per guy so that | ||||
|  * we can.  This is severely antisocial, since now free and p9free | ||||
|  * are not interchangeable. | ||||
|  */ | ||||
| int debugmalloc; | ||||
|  | ||||
| #define Overhead (debugmalloc ? (6*sizeof(ulong)) : 0) | ||||
| #define MallocMagic 0xA110C09 | ||||
| #define ReallocMagic 0xB110C09 | ||||
| #define CallocMagic 0xC110C09 | ||||
| #define FreeMagic 0xF533F533 | ||||
| #define CheckMagic 0 | ||||
| #define END "\x7F\x2E\x55\x23" | ||||
|  | ||||
| static void | ||||
| whoops(void *v) | ||||
| { | ||||
| 	fprint(2, "bad malloc block %p\n", v); | ||||
| 	abort(); | ||||
| } | ||||
|  | ||||
| static void* | ||||
| mark(void *v, ulong pc, ulong n, ulong magic) | ||||
| { | ||||
| 	ulong *u; | ||||
| 	char *p; | ||||
|  | ||||
| 	if(!debugmalloc) | ||||
| 		return v; | ||||
|  | ||||
| 	if(v == nil) | ||||
| 		return nil; | ||||
|  | ||||
| 	if(magic == FreeMagic || magic == CheckMagic){ | ||||
| 		u = (ulong*)((char*)v-4*sizeof(ulong)); | ||||
| 		if(u[0] != MallocMagic && u[0] != ReallocMagic && u[0] != CallocMagic) | ||||
| 			whoops(v); | ||||
| 		n = u[1]; | ||||
| 		p = (char*)v+n; | ||||
| 		if(memcmp(p, END, 4) != 0) | ||||
| 			whoops(v); | ||||
| 		if(magic != CheckMagic){ | ||||
| 			u[0] = FreeMagic; | ||||
| 			u[1] = u[2] = u[3] = pc; | ||||
| 			if(n > 16){ | ||||
| 				u[4] = u[5] = u[6] = u[7] = pc; | ||||
| 				memset((char*)v+16, 0xFB, n-16); | ||||
| 			} | ||||
| 		} | ||||
| 		return u; | ||||
| 	}else{ | ||||
| 		u = v; | ||||
| 		u[0] = magic; | ||||
| 		u[1] = n; | ||||
| 		u[2] = 0; | ||||
| 		u[3] = 0; | ||||
| 		if(magic == ReallocMagic) | ||||
| 			u[3] = pc; | ||||
| 		else | ||||
| 			u[2] = pc; | ||||
| 		p = (char*)(u+4)+n; | ||||
| 		memmove(p, END, 4); | ||||
| 		return u+4; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void | ||||
| setmalloctag(void *v, ulong t) | ||||
| { | ||||
| 	ulong *u; | ||||
|  | ||||
| 	if(!debugmalloc) | ||||
| 		return; | ||||
|  | ||||
| 	if(v == nil) | ||||
| 		return; | ||||
| 	u = mark(v, 0, 0, 0); | ||||
| 	u[2] = t; | ||||
| } | ||||
|  | ||||
| void | ||||
| setrealloctag(void *v, ulong t) | ||||
| { | ||||
| 	ulong *u; | ||||
|  | ||||
| 	if(!debugmalloc) | ||||
| 		return; | ||||
|  | ||||
| 	if(v == nil) | ||||
| 		return; | ||||
| 	u = mark(v, 0, 0, 0); | ||||
| 	u[3] = t; | ||||
| } | ||||
|  | ||||
| void* | ||||
| p9malloc(ulong n) | ||||
| { | ||||
| 	void *v; | ||||
| 	if(n == 0) | ||||
| 		n++; | ||||
| /*fprint(2, "%s %d malloc\n", argv0, getpid()); */ | ||||
| 	mallocpid = getpid(); | ||||
| 	v = malloc(n+Overhead); | ||||
| 	v = mark(v, getcallerpc(&n), n, MallocMagic); | ||||
| /*fprint(2, "%s %d donemalloc\n", argv0, getpid()); */ | ||||
| 	return v; | ||||
| } | ||||
|  | ||||
| void | ||||
| p9free(void *v) | ||||
| { | ||||
| 	if(v == nil) | ||||
| 		return; | ||||
|  | ||||
| /*fprint(2, "%s %d free\n", argv0, getpid()); */ | ||||
| 	mallocpid = getpid(); | ||||
| 	v = mark(v, getcallerpc(&v), 0, FreeMagic); | ||||
| 	free(v); | ||||
| /*fprint(2, "%s %d donefree\n", argv0, getpid()); */ | ||||
| } | ||||
|  | ||||
| void* | ||||
| p9calloc(ulong a, ulong b) | ||||
| { | ||||
| 	void *v; | ||||
|  | ||||
| /*fprint(2, "%s %d calloc\n", argv0, getpid()); */ | ||||
| 	mallocpid = getpid(); | ||||
| 	v = calloc(a*b+Overhead, 1); | ||||
| 	v = mark(v, getcallerpc(&a), a*b, CallocMagic); | ||||
| /*fprint(2, "%s %d donecalloc\n", argv0, getpid()); */ | ||||
| 	return v; | ||||
| } | ||||
|  | ||||
| void* | ||||
| p9realloc(void *v, ulong n) | ||||
| { | ||||
| /*fprint(2, "%s %d realloc\n", argv0, getpid()); */ | ||||
| 	mallocpid = getpid(); | ||||
| 	v = mark(v, getcallerpc(&v), 0, CheckMagic); | ||||
| 	v = realloc(v, n+Overhead); | ||||
| 	v = mark(v, getcallerpc(&v), n, ReallocMagic); | ||||
| /*fprint(2, "%s %d donerealloc\n", argv0, getpid()); */ | ||||
| 	return v; | ||||
| } | ||||
							
								
								
									
										159
									
								
								lib/lib9/dial.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								lib/lib9/dial.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,159 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| #undef	accept | ||||
| #undef	announce | ||||
| #undef	dial | ||||
| #undef	setnetmtpt | ||||
| #undef	hangup | ||||
| #undef	listen | ||||
| #undef	netmkaddr | ||||
| #undef	reject | ||||
|  | ||||
| #include <sys/socket.h> | ||||
| #include <netinet/in.h> | ||||
| #include <netinet/tcp.h> | ||||
| #include <sys/un.h> | ||||
| #include <netdb.h> | ||||
|  | ||||
| #undef unix | ||||
| #define unix xunix | ||||
|  | ||||
| static int | ||||
| isany(struct sockaddr_storage *ss) | ||||
| { | ||||
| 	switch(ss->ss_family){ | ||||
| 	case AF_INET: | ||||
| 		return (((struct sockaddr_in*)ss)->sin_addr.s_addr == INADDR_ANY); | ||||
| 	case AF_INET6: | ||||
| 		return (memcmp(((struct sockaddr_in6*)ss)->sin6_addr.s6_addr, | ||||
| 			in6addr_any.s6_addr, sizeof (struct in6_addr)) == 0); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| addrlen(struct sockaddr_storage *ss) | ||||
| { | ||||
| 	switch(ss->ss_family){ | ||||
| 	case AF_INET: | ||||
| 		return sizeof(struct sockaddr_in); | ||||
| 	case AF_INET6: | ||||
| 		return sizeof(struct sockaddr_in6); | ||||
| 	case AF_UNIX: | ||||
| 		return sizeof(struct sockaddr_un); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| p9dial(char *addr, char *local, char *dummy2, int *dummy3) | ||||
| { | ||||
| 	char *buf; | ||||
| 	char *net, *unix; | ||||
| 	int port; | ||||
| 	int proto; | ||||
| 	socklen_t sn; | ||||
| 	int n; | ||||
| 	struct sockaddr_storage ss, ssl; | ||||
| 	int s; | ||||
|  | ||||
| 	if(dummy2 || dummy3){ | ||||
| 		werrstr("cannot handle extra arguments in dial"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	buf = strdup(addr); | ||||
| 	if(buf == nil) | ||||
| 		return -1; | ||||
|  | ||||
| 	if(p9dialparse(buf, &net, &unix, &ss, &port) < 0){ | ||||
| 		free(buf); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if(strcmp(net, "unix") != 0 && isany(&ss)){ | ||||
| 		werrstr("invalid dial address 0.0.0.0 (aka *)"); | ||||
| 		free(buf); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if(strcmp(net, "tcp") == 0) | ||||
| 		proto = SOCK_STREAM; | ||||
| 	else if(strcmp(net, "udp") == 0) | ||||
| 		proto = SOCK_DGRAM; | ||||
| 	else if(strcmp(net, "unix") == 0) | ||||
| 		goto Unix; | ||||
| 	else{ | ||||
| 		werrstr("can only handle tcp, udp, and unix: not %s", net); | ||||
| 		free(buf); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	free(buf); | ||||
|  | ||||
| 	if((s = socket(ss.ss_family, proto, 0)) < 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	if(local){ | ||||
| 		buf = strdup(local); | ||||
| 		if(buf == nil){ | ||||
| 			close(s); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		if(p9dialparse(buf, &net, &unix, &ss, &port) < 0){ | ||||
| 		badlocal: | ||||
| 			free(buf); | ||||
| 			close(s); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		if(unix){ | ||||
| 			werrstr("bad local address %s for dial %s", local, addr); | ||||
| 			goto badlocal; | ||||
| 		} | ||||
| 		sn = sizeof n; | ||||
| 		if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0 | ||||
| 		&& n == SOCK_STREAM){ | ||||
| 			n = 1; | ||||
| 			setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n); | ||||
| 		} | ||||
| 		if(bind(s, (struct sockaddr*)&ssl, addrlen(&ssl)) < 0) | ||||
| 			goto badlocal; | ||||
| 		free(buf); | ||||
| 	} | ||||
|  | ||||
| 	n = 1; | ||||
| 	setsockopt(s, SOL_SOCKET, SO_BROADCAST, &n, sizeof n); | ||||
| 	if(!isany(&ss)){ | ||||
| 		if(connect(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0){ | ||||
| 			close(s); | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
| 	if(proto == SOCK_STREAM){ | ||||
| 		int one = 1; | ||||
| 		setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof one); | ||||
| 	} | ||||
| 	return s; | ||||
|  | ||||
| Unix: | ||||
| 	if(local){ | ||||
| 		werrstr("local address not supported on unix network"); | ||||
| 		free(buf); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	/* Allow regular files in addition to Unix sockets. */ | ||||
| 	if((s = open(unix, ORDWR)) >= 0){ | ||||
| 		free(buf); | ||||
| 		return s; | ||||
| 	} | ||||
| 	free(buf); | ||||
| 	if((s = socket(ss.ss_family, SOCK_STREAM, 0)) < 0){ | ||||
| 		werrstr("socket: %r"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if(connect(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0){ | ||||
| 		werrstr("connect %s: %r", ((struct sockaddr_un*)&ss)->sun_path); | ||||
| 		close(s); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	return s; | ||||
| } | ||||
							
								
								
									
										28
									
								
								lib/lib9/dirfstat.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								lib/lib9/dirfstat.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| #include <u.h> | ||||
| #define NOPLAN9DEFINES | ||||
| #include <libc.h> | ||||
|  | ||||
| #include <sys/stat.h> | ||||
|  | ||||
| extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*); | ||||
|  | ||||
| Dir* | ||||
| dirfstat(int fd) | ||||
| { | ||||
| 	struct stat st; | ||||
| 	int nstr; | ||||
| 	Dir *d; | ||||
| 	char *str, tmp[100]; | ||||
|  | ||||
| 	if(fstat(fd, &st) < 0) | ||||
| 		return nil; | ||||
|  | ||||
| 	snprint(tmp, sizeof tmp, "/dev/fd/%d", fd); | ||||
| 	nstr = _p9dir(&st, &st, tmp, nil, nil, nil); | ||||
| 	d = mallocz(sizeof(Dir)+nstr, 1); | ||||
| 	if(d == nil) | ||||
| 		return nil; | ||||
| 	str = (char*)&d[1]; | ||||
| 	_p9dir(&st, &st, tmp, d, &str, str+nstr); | ||||
| 	return d; | ||||
| } | ||||
							
								
								
									
										56
									
								
								lib/lib9/dirfwstat.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								lib/lib9/dirfwstat.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| #define NOPLAN9DEFINES | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/stat.h> | ||||
|  | ||||
| #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__linux__) | ||||
| /* do nothing -- futimes exists and is fine */ | ||||
|  | ||||
| #elif defined(__SunOS5_9__) | ||||
| /* use futimesat */ | ||||
| static int | ||||
| futimes(int fd, struct timeval *tv) | ||||
| { | ||||
| 	return futimesat(fd, 0, tv); | ||||
| } | ||||
|  | ||||
| #else | ||||
| /* provide dummy */ | ||||
| /* rename just in case -- linux provides an unusable one */ | ||||
| #undef futimes | ||||
| #define futimes myfutimes | ||||
| static int | ||||
| futimes(int fd, struct timeval *tv) | ||||
| { | ||||
| 	werrstr("futimes not available"); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
| int | ||||
| dirfwstat(int fd, Dir *dir) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct timeval tv[2]; | ||||
|  | ||||
| 	ret = 0; | ||||
| 	if(~dir->mode != 0){ | ||||
| 		if(fchmod(fd, dir->mode) < 0) | ||||
| 			ret = -1; | ||||
| 	} | ||||
| 	if(~dir->mtime != 0){ | ||||
| 		tv[0].tv_sec = dir->mtime; | ||||
| 		tv[0].tv_usec = 0; | ||||
| 		tv[1].tv_sec = dir->mtime; | ||||
| 		tv[1].tv_usec = 0; | ||||
| 		if(futimes(fd, tv) < 0) | ||||
| 			ret = -1; | ||||
| 	} | ||||
| 	if(~dir->length != 0){ | ||||
| 		if(ftruncate(fd, dir->length) < 0) | ||||
| 			ret = -1; | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
							
								
								
									
										62
									
								
								lib/lib9/dirmodefmt.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								lib/lib9/dirmodefmt.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| static char *modes[] = | ||||
| { | ||||
| 	"---", | ||||
| 	"--x", | ||||
| 	"-w-", | ||||
| 	"-wx", | ||||
| 	"r--", | ||||
| 	"r-x", | ||||
| 	"rw-", | ||||
| 	"rwx", | ||||
| }; | ||||
|  | ||||
| static void | ||||
| rwx(long m, char *s) | ||||
| { | ||||
| 	strncpy(s, modes[m], 3); | ||||
| } | ||||
|  | ||||
| int | ||||
| dirmodefmt(Fmt *f) | ||||
| { | ||||
| 	static char buf[16]; | ||||
| 	ulong m; | ||||
|  | ||||
| 	m = va_arg(f->args, ulong); | ||||
|  | ||||
| 	if(m & DMDIR) | ||||
| 		buf[0]='d'; | ||||
| 	else if(m & DMAPPEND) | ||||
| 		buf[0]='a'; | ||||
| 	else if(m & DMAUTH) | ||||
| 		buf[0]='A'; | ||||
| 	else if(m & DMDEVICE) | ||||
| 		buf[0] = 'D'; | ||||
| 	else if(m & DMSOCKET) | ||||
| 		buf[0] = 'S'; | ||||
| 	else if(m & DMNAMEDPIPE) | ||||
| 		buf[0] = 'P'; | ||||
| 	else | ||||
| 		buf[0]='-'; | ||||
|  | ||||
| 	/* | ||||
| 	 * It's a little weird to have DMSYMLINK conflict with DMEXCL | ||||
| 	 * here, but since you can have symlinks to any of the above | ||||
| 	 * things, this is a better display.  Especially since we don't do | ||||
| 	 * DMEXCL on any of the supported systems. | ||||
| 	 */ | ||||
| 	if(m & DMEXCL) | ||||
| 		buf[1]='l'; | ||||
| 	else if(m & DMSYMLINK) | ||||
| 		buf[1] = 'L'; | ||||
| 	else | ||||
| 		buf[1]='-'; | ||||
| 	rwx((m>>6)&7, buf+2); | ||||
| 	rwx((m>>3)&7, buf+5); | ||||
| 	rwx((m>>0)&7, buf+8); | ||||
| 	buf[11] = 0; | ||||
| 	return fmtstrcpy(f, buf); | ||||
| } | ||||
							
								
								
									
										31
									
								
								lib/lib9/dirstat.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								lib/lib9/dirstat.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| #include <u.h> | ||||
| #define NOPLAN9DEFINES | ||||
| #include <libc.h> | ||||
|  | ||||
| #include <sys/stat.h> | ||||
|  | ||||
| extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*); | ||||
|  | ||||
| Dir* | ||||
| dirstat(char *file) | ||||
| { | ||||
| 	struct stat lst; | ||||
| 	struct stat st; | ||||
| 	int nstr; | ||||
| 	Dir *d; | ||||
| 	char *str; | ||||
|  | ||||
| 	if(lstat(file, &lst) < 0) | ||||
| 		return nil; | ||||
| 	st = lst; | ||||
| 	if((lst.st_mode&S_IFMT) == S_IFLNK) | ||||
| 		stat(file, &st); | ||||
|  | ||||
| 	nstr = _p9dir(&lst, &st, file, nil, nil, nil); | ||||
| 	d = mallocz(sizeof(Dir)+nstr, 1); | ||||
| 	if(d == nil) | ||||
| 		return nil; | ||||
| 	str = (char*)&d[1]; | ||||
| 	_p9dir(&lst, &st, file, d, &str, str+nstr); | ||||
| 	return d; | ||||
| } | ||||
							
								
								
									
										31
									
								
								lib/lib9/dirwstat.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								lib/lib9/dirwstat.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| #include <u.h> | ||||
| #define NOPLAN9DEFINES | ||||
| #include <libc.h> | ||||
| #include <sys/time.h> | ||||
| #include <utime.h> | ||||
| #include <sys/stat.h> | ||||
|  | ||||
| int | ||||
| dirwstat(char *file, Dir *dir) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct utimbuf ub; | ||||
|  | ||||
| 	/* BUG handle more */ | ||||
| 	ret = 0; | ||||
| 	if(~dir->mode != 0){ | ||||
| 		if(chmod(file, dir->mode) < 0) | ||||
| 			ret = -1; | ||||
| 	} | ||||
| 	if(~dir->mtime != 0){ | ||||
| 		ub.actime = dir->mtime; | ||||
| 		ub.modtime = dir->mtime; | ||||
| 		if(utime(file, &ub) < 0) | ||||
| 			ret = -1; | ||||
| 	} | ||||
| 	if(~dir->length != 0){ | ||||
| 		if(truncate(file, dir->length) < 0) | ||||
| 			ret = -1; | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
							
								
								
									
										12
									
								
								lib/lib9/dup.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								lib/lib9/dup.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| #undef dup | ||||
|  | ||||
| int | ||||
| p9dup(int old, int new) | ||||
| { | ||||
| 	if(new == -1) | ||||
| 		return dup(old); | ||||
| 	return dup2(old, new); | ||||
| } | ||||
							
								
								
									
										76
									
								
								lib/lib9/encodefmt.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								lib/lib9/encodefmt.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| #include <lib9.h> | ||||
|  | ||||
| int | ||||
| encodefmt(Fmt *f) | ||||
| { | ||||
| 	char *out; | ||||
| 	char *buf, *p; | ||||
| 	int len; | ||||
| 	int ilen; | ||||
| 	int rv; | ||||
| 	uchar *b; | ||||
| 	char obuf[64];	/* rsc optimization */ | ||||
|  | ||||
| 	b = va_arg(f->args, uchar*); | ||||
| 	if(b == 0) | ||||
| 		return fmtstrcpy(f, "<nil>"); | ||||
|  | ||||
| 	ilen = f->prec; | ||||
| 	f->prec = 0; | ||||
|  | ||||
| 	if(!(f->flags&FmtPrec) || ilen < 0) | ||||
| 		goto error; | ||||
|  | ||||
| 	f->flags &= ~FmtPrec; | ||||
|  | ||||
| 	switch(f->r){ | ||||
| 	case '<': | ||||
| 		len = (8*ilen+4)/5 + 3; | ||||
| 		break; | ||||
| 	case '[': | ||||
| 		len = (8*ilen+5)/6 + 4; | ||||
| 		break; | ||||
| 	case 'H': | ||||
| 		len = 2*ilen + 1; | ||||
| 		break; | ||||
| 	default: | ||||
| 		goto error; | ||||
| 	} | ||||
|  | ||||
| 	if(len > sizeof(obuf)){ | ||||
| 		buf = malloc(len); | ||||
| 		if(buf == nil) | ||||
| 			goto error; | ||||
| 	} else | ||||
| 		buf = obuf; | ||||
|  | ||||
| 	/* convert */ | ||||
| 	out = buf; | ||||
| 	switch(f->r){ | ||||
| 	case '<': | ||||
| 		rv = enc32(out, len, b, ilen); | ||||
| 		break; | ||||
| 	case '[': | ||||
| 		rv = enc64(out, len, b, ilen); | ||||
| 		break; | ||||
| 	case 'H': | ||||
| 		rv = enc16(out, len, b, ilen); | ||||
| 		if(rv >= 0 && (f->flags & FmtLong)) | ||||
| 			for(p = buf; *p; p++) | ||||
| 				*p = tolower((uchar)*p); | ||||
| 		break; | ||||
| 	default: | ||||
| 		rv = -1; | ||||
| 		break; | ||||
| 	} | ||||
| 	if(rv < 0) | ||||
| 		goto error; | ||||
|  | ||||
| 	fmtstrcpy(f, buf); | ||||
| 	if(buf != obuf) | ||||
| 		free(buf); | ||||
| 	return 0; | ||||
|  | ||||
| error: | ||||
| 	return fmtstrcpy(f, "<encodefmt>"); | ||||
| } | ||||
							
								
								
									
										80
									
								
								lib/lib9/errstr.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								lib/lib9/errstr.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| /* | ||||
|  * We assume there's only one error buffer for the whole system. | ||||
|  * If you use ffork, you need to provide a _syserrstr.  Since most | ||||
|  * people will use libthread (which provides a _syserrstr), this is | ||||
|  * okay. | ||||
|  */ | ||||
|  | ||||
| #include <u.h> | ||||
| #include <errno.h> | ||||
| #include <string.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| enum | ||||
| { | ||||
| 	EPLAN9 = 0x19283745 | ||||
| }; | ||||
|  | ||||
| char *(*_syserrstr)(void); | ||||
| static char xsyserr[ERRMAX]; | ||||
| static char* | ||||
| getsyserr(void) | ||||
| { | ||||
| 	char *s; | ||||
|  | ||||
| 	s = nil; | ||||
| 	if(_syserrstr) | ||||
| 		s = (*_syserrstr)(); | ||||
| 	if(s == nil) | ||||
| 		s = xsyserr; | ||||
| 	return s; | ||||
| } | ||||
|  | ||||
| int | ||||
| errstr(char *err, uint n) | ||||
| { | ||||
| 	char tmp[ERRMAX]; | ||||
| 	char *syserr; | ||||
|  | ||||
| 	strecpy(tmp, tmp+ERRMAX, err); | ||||
| 	rerrstr(err, n); | ||||
| 	syserr = getsyserr(); | ||||
| 	strecpy(syserr, syserr+ERRMAX, tmp); | ||||
| 	errno = EPLAN9; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void | ||||
| rerrstr(char *err, uint n) | ||||
| { | ||||
| 	char *syserr; | ||||
|  | ||||
| 	syserr = getsyserr(); | ||||
| 	if(errno == EINTR) | ||||
| 		strcpy(syserr, "interrupted"); | ||||
| 	else if(errno != EPLAN9) | ||||
| 		strcpy(syserr, strerror(errno)); | ||||
| 	strecpy(err, err+n, syserr); | ||||
| } | ||||
|  | ||||
| /* replaces __errfmt in libfmt */ | ||||
|  | ||||
| int | ||||
| __errfmt(Fmt *f) | ||||
| { | ||||
| 	if(errno == EPLAN9) | ||||
| 		return fmtstrcpy(f, getsyserr()); | ||||
| 	return fmtstrcpy(f, strerror(errno)); | ||||
| } | ||||
|  | ||||
| void | ||||
| werrstr(char *fmt, ...) | ||||
| { | ||||
| 	va_list arg; | ||||
| 	char buf[ERRMAX]; | ||||
|  | ||||
| 	va_start(arg, fmt); | ||||
| 	vseprint(buf, buf+ERRMAX, fmt, arg); | ||||
| 	va_end(arg); | ||||
| 	errstr(buf, ERRMAX); | ||||
| } | ||||
							
								
								
									
										9
									
								
								lib/lib9/exec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								lib/lib9/exec.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| int | ||||
| exec(char *prog, char *argv[]) | ||||
| { | ||||
| 	/* to mimic plan 9 should be just exec, but execvp is a better fit for unix */ | ||||
| 	return execvp(prog, argv); | ||||
| } | ||||
							
								
								
									
										28
									
								
								lib/lib9/execl.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								lib/lib9/execl.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| int | ||||
| execl(char *prog, ...) | ||||
| { | ||||
| 	int i; | ||||
| 	va_list arg; | ||||
| 	char **argv; | ||||
|  | ||||
| 	va_start(arg, prog); | ||||
| 	for(i=0; va_arg(arg, char*) != nil; i++) | ||||
| 		; | ||||
| 	va_end(arg); | ||||
|  | ||||
| 	argv = malloc((i+1)*sizeof(char*)); | ||||
| 	if(argv == nil) | ||||
| 		return -1; | ||||
|  | ||||
| 	va_start(arg, prog); | ||||
| 	for(i=0; (argv[i] = va_arg(arg, char*)) != nil; i++) | ||||
| 		; | ||||
| 	va_end(arg); | ||||
|  | ||||
| 	exec(prog, argv); | ||||
| 	free(argv); | ||||
| 	return -1; | ||||
| } | ||||
							
								
								
									
										8
									
								
								lib/lib9/exitcode.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/lib9/exitcode.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
|  | ||||
| int | ||||
| exitcode(char *s) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										253
									
								
								lib/lib9/fcallfmt.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										253
									
								
								lib/lib9/fcallfmt.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,253 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <fcall.h> | ||||
|  | ||||
| static uint dumpsome(char*, char*, char*, long); | ||||
| static void fdirconv(char*, char*, Dir*); | ||||
| static char *qidtype(char*, uchar); | ||||
|  | ||||
| #define	QIDFMT	"(%.16llux %lud %s)" | ||||
|  | ||||
| int | ||||
| fcallfmt(Fmt *fmt) | ||||
| { | ||||
| 	Fcall *f; | ||||
| 	int fid, type, tag, i; | ||||
| 	char buf[512], tmp[200]; | ||||
| 	char *p, *e; | ||||
| 	Dir *d; | ||||
| 	Qid *q; | ||||
|  | ||||
| 	e = buf+sizeof(buf); | ||||
| 	f = va_arg(fmt->args, Fcall*); | ||||
| 	type = f->type; | ||||
| 	fid = f->fid; | ||||
| 	tag = f->tag; | ||||
| 	switch(type){ | ||||
| 	case Tversion:	/* 100 */ | ||||
| 		seprint(buf, e, "Tversion tag %ud msize %ud version '%s'", tag, f->msize, f->version); | ||||
| 		break; | ||||
| 	case Rversion: | ||||
| 		seprint(buf, e, "Rversion tag %ud msize %ud version '%s'", tag, f->msize, f->version); | ||||
| 		break; | ||||
| 	case Tauth:	/* 102 */ | ||||
| 		seprint(buf, e, "Tauth tag %ud afid %d uname %s aname %s", tag, | ||||
| 			f->afid, f->uname, f->aname); | ||||
| 		break; | ||||
| 	case Rauth: | ||||
| 		seprint(buf, e, "Rauth tag %ud qid " QIDFMT, tag, | ||||
| 			f->aqid.path, f->aqid.vers, qidtype(tmp, f->aqid.type)); | ||||
| 		break; | ||||
| 	case Tattach:	/* 104 */ | ||||
| 		seprint(buf, e, "Tattach tag %ud fid %d afid %d uname %s aname %s", tag, | ||||
| 			fid, f->afid, f->uname, f->aname); | ||||
| 		break; | ||||
| 	case Rattach: | ||||
| 		seprint(buf, e, "Rattach tag %ud qid " QIDFMT, tag, | ||||
| 			f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type)); | ||||
| 		break; | ||||
| 	case Rerror:	/* 107; 106 (Terror) illegal */ | ||||
| 		seprint(buf, e, "Rerror tag %ud ename %s", tag, f->ename); | ||||
| 		break; | ||||
| 	case Tflush:	/* 108 */ | ||||
| 		seprint(buf, e, "Tflush tag %ud oldtag %ud", tag, f->oldtag); | ||||
| 		break; | ||||
| 	case Rflush: | ||||
| 		seprint(buf, e, "Rflush tag %ud", tag); | ||||
| 		break; | ||||
| 	case Twalk:	/* 110 */ | ||||
| 		p = seprint(buf, e, "Twalk tag %ud fid %d newfid %d nwname %d ", tag, fid, f->newfid, f->nwname); | ||||
| 		if(f->nwname <= MAXWELEM) | ||||
| 			for(i=0; i<f->nwname; i++) | ||||
| 				p = seprint(p, e, "%d:%s ", i, f->wname[i]); | ||||
| 		break; | ||||
| 	case Rwalk: | ||||
| 		p = seprint(buf, e, "Rwalk tag %ud nwqid %ud ", tag, f->nwqid); | ||||
| 		if(f->nwqid <= MAXWELEM) | ||||
| 			for(i=0; i<f->nwqid; i++){ | ||||
| 				q = &f->wqid[i]; | ||||
| 				p = seprint(p, e, "%d:" QIDFMT " ", i, | ||||
| 					q->path, q->vers, qidtype(tmp, q->type)); | ||||
| 			} | ||||
| 		break; | ||||
| 	case Topen:	/* 112 */ | ||||
| 		seprint(buf, e, "Topen tag %ud fid %ud mode %d", tag, fid, f->mode); | ||||
| 		break; | ||||
| 	case Ropen: | ||||
| 		seprint(buf, e, "Ropen tag %ud qid " QIDFMT " iounit %ud", tag, | ||||
| 			f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit); | ||||
| 		break; | ||||
| 	case Topenfd:	/* 98 */ | ||||
| 		seprint(buf, e, "Topenfd tag %ud fid %ud mode %d", tag, fid, f->mode); | ||||
| 		break; | ||||
| 	case Ropenfd: | ||||
| 		seprint(buf, e, "Ropenfd tag %ud qid " QIDFMT " iounit %ud unixfd %d", tag, | ||||
| 			f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit, f->unixfd); | ||||
| 		break; | ||||
| 	case Tcreate:	/* 114 */ | ||||
| 		seprint(buf, e, "Tcreate tag %ud fid %ud name %s perm %M mode %d", tag, fid, f->name, (ulong)f->perm, f->mode); | ||||
| 		break; | ||||
| 	case Rcreate: | ||||
| 		seprint(buf, e, "Rcreate tag %ud qid " QIDFMT " iounit %ud ", tag, | ||||
| 			f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit); | ||||
| 		break; | ||||
| 	case Tread:	/* 116 */ | ||||
| 		seprint(buf, e, "Tread tag %ud fid %d offset %lld count %ud", | ||||
| 			tag, fid, f->offset, f->count); | ||||
| 		break; | ||||
| 	case Rread: | ||||
| 		p = seprint(buf, e, "Rread tag %ud count %ud ", tag, f->count); | ||||
| 			dumpsome(p, e, f->data, f->count); | ||||
| 		break; | ||||
| 	case Twrite:	/* 118 */ | ||||
| 		p = seprint(buf, e, "Twrite tag %ud fid %d offset %lld count %ud ", | ||||
| 			tag, fid, f->offset, f->count); | ||||
| 		dumpsome(p, e, f->data, f->count); | ||||
| 		break; | ||||
| 	case Rwrite: | ||||
| 		seprint(buf, e, "Rwrite tag %ud count %ud", tag, f->count); | ||||
| 		break; | ||||
| 	case Tclunk:	/* 120 */ | ||||
| 		seprint(buf, e, "Tclunk tag %ud fid %ud", tag, fid); | ||||
| 		break; | ||||
| 	case Rclunk: | ||||
| 		seprint(buf, e, "Rclunk tag %ud", tag); | ||||
| 		break; | ||||
| 	case Tremove:	/* 122 */ | ||||
| 		seprint(buf, e, "Tremove tag %ud fid %ud", tag, fid); | ||||
| 		break; | ||||
| 	case Rremove: | ||||
| 		seprint(buf, e, "Rremove tag %ud", tag); | ||||
| 		break; | ||||
| 	case Tstat:	/* 124 */ | ||||
| 		seprint(buf, e, "Tstat tag %ud fid %ud", tag, fid); | ||||
| 		break; | ||||
| 	case Rstat: | ||||
| 		p = seprint(buf, e, "Rstat tag %ud ", tag); | ||||
| 		if(f->stat == nil || f->nstat > sizeof tmp) | ||||
| 			seprint(p, e, " stat(%d bytes)", f->nstat); | ||||
| 		else{ | ||||
| 			d = (Dir*)tmp; | ||||
| 			convM2D(f->stat, f->nstat, d, (char*)(d+1)); | ||||
| 			seprint(p, e, " stat "); | ||||
| 			fdirconv(p+6, e, d); | ||||
| 		} | ||||
| 		break; | ||||
| 	case Twstat:	/* 126 */ | ||||
| 		p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid); | ||||
| 		if(f->stat == nil || f->nstat > sizeof tmp) | ||||
| 			seprint(p, e, " stat(%d bytes)", f->nstat); | ||||
| 		else{ | ||||
| 			d = (Dir*)tmp; | ||||
| 			convM2D(f->stat, f->nstat, d, (char*)(d+1)); | ||||
| 			seprint(p, e, " stat "); | ||||
| 			fdirconv(p+6, e, d); | ||||
| 		} | ||||
| 		break; | ||||
| 	case Rwstat: | ||||
| 		seprint(buf, e, "Rwstat tag %ud", tag); | ||||
| 		break; | ||||
| 	default: | ||||
| 		seprint(buf, e,  "unknown type %d", type); | ||||
| 	} | ||||
| 	return fmtstrcpy(fmt, buf); | ||||
| } | ||||
|  | ||||
| static char* | ||||
| qidtype(char *s, uchar t) | ||||
| { | ||||
| 	char *p; | ||||
|  | ||||
| 	p = s; | ||||
| 	if(t & QTDIR) | ||||
| 		*p++ = 'd'; | ||||
| 	if(t & QTAPPEND) | ||||
| 		*p++ = 'a'; | ||||
| 	if(t & QTEXCL) | ||||
| 		*p++ = 'l'; | ||||
| 	if(t & QTAUTH) | ||||
| 		*p++ = 'A'; | ||||
| 	*p = '\0'; | ||||
| 	return s; | ||||
| } | ||||
|  | ||||
| int | ||||
| dirfmt(Fmt *fmt) | ||||
| { | ||||
| 	char buf[160]; | ||||
|  | ||||
| 	fdirconv(buf, buf+sizeof buf, va_arg(fmt->args, Dir*)); | ||||
| 	return fmtstrcpy(fmt, buf); | ||||
| } | ||||
|  | ||||
| static void | ||||
| fdirconv(char *buf, char *e, Dir *d) | ||||
| { | ||||
| 	char tmp[16]; | ||||
|  | ||||
| 	seprint(buf, e, "'%s' '%s' '%s' '%s' " | ||||
| 		"q " QIDFMT " m %#luo " | ||||
| 		"at %ld mt %ld l %lld " | ||||
| 		"t %d d %d", | ||||
| 			d->name, d->uid, d->gid, d->muid, | ||||
| 			d->qid.path, d->qid.vers, qidtype(tmp, d->qid.type), d->mode, | ||||
| 			d->atime, d->mtime, d->length, | ||||
| 			d->type, d->dev); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * dump out count (or DUMPL, if count is bigger) bytes from | ||||
|  * buf to ans, as a string if they are all printable, | ||||
|  * else as a series of hex bytes | ||||
|  */ | ||||
| #define DUMPL 64 | ||||
|  | ||||
| static uint | ||||
| dumpsome(char *ans, char *e, char *buf, long count) | ||||
| { | ||||
| 	int i, printable; | ||||
| 	char *p; | ||||
|  | ||||
| 	if(buf == nil){ | ||||
| 		seprint(ans, e, "<no data>"); | ||||
| 		return strlen(ans); | ||||
| 	} | ||||
| 	printable = 1; | ||||
| 	if(count > DUMPL) | ||||
| 		count = DUMPL; | ||||
| 	for(i=0; i<count && printable; i++) | ||||
| 		if((buf[i]!=0 && buf[i]<32) || (uchar)buf[i]>127) | ||||
| 			printable = 0; | ||||
| 	p = ans; | ||||
| 	*p++ = '\''; | ||||
| 	if(printable){ | ||||
| 		if(2*count > e-p-2) | ||||
| 			count = (e-p-2)/2; | ||||
| 		for(i=0; i<count; i++){ | ||||
| 			if(buf[i] == 0){ | ||||
| 				*p++ = '\\'; | ||||
| 				*p++ = '0'; | ||||
| 			}else if(buf[i] == '\t'){ | ||||
| 				*p++ = '\\'; | ||||
| 				*p++ = 't'; | ||||
| 			}else if(buf[i] == '\n'){ | ||||
| 				*p++ = '\\'; | ||||
| 				*p++ = 'n'; | ||||
| 			}else | ||||
| 				*p++ = buf[i]; | ||||
| 		} | ||||
| 	}else{ | ||||
| 		if(2*count > e-p-2) | ||||
| 			count = (e-p-2)/2; | ||||
| 		for(i=0; i<count; i++){ | ||||
| 			if(i>0 && i%4==0) | ||||
| 				*p++ = ' '; | ||||
| 			sprint(p, "%2.2ux", (uchar)buf[i]); | ||||
| 			p += 2; | ||||
| 		} | ||||
| 	} | ||||
| 	*p++ = '\''; | ||||
| 	*p = 0; | ||||
| 	assert(p < e); | ||||
| 	return p - ans; | ||||
| } | ||||
							
								
								
									
										22
									
								
								lib/lib9/fmt/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								lib/lib9/fmt/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| /* | ||||
|  * The authors of this software are Rob Pike and Ken Thompson, | ||||
|  * with contributions from Mike Burrows and Sean Dorward. | ||||
|  * | ||||
|  *     Copyright (c) 2002-2006 by Lucent Technologies. | ||||
|  *     Portions Copyright (c) 2004 Google Inc. | ||||
|  *  | ||||
|  * Permission to use, copy, modify, and distribute this software for any | ||||
|  * purpose without fee is hereby granted, provided that this entire notice | ||||
|  * is included in all copies of any software which is or includes a copy | ||||
|  * or modification of this software and in all copies of the supporting | ||||
|  * documentation for such software. | ||||
|  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED | ||||
|  * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES  | ||||
|  * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING  | ||||
|  * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. | ||||
|  */ | ||||
|  | ||||
| This is a Unix port of the Plan 9 formatted I/O package. | ||||
|  | ||||
| Please send comments about the packaging to Russ Cox <rsc@swtch.com>. | ||||
|  | ||||
							
								
								
									
										19
									
								
								lib/lib9/fmt/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								lib/lib9/fmt/README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| /* | ||||
|  * The authors of this software are Rob Pike and Ken Thompson. | ||||
|  *		Copyright (c) 2002 by Lucent Technologies. | ||||
|  * Permission to use, copy, modify, and distribute this software for any | ||||
|  * purpose without fee is hereby granted, provided that this entire notice | ||||
|  * is included in all copies of any software which is or includes a copy | ||||
|  * or modification of this software and in all copies of the supporting | ||||
|  * documentation for such software. | ||||
|  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED | ||||
|  * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY | ||||
|  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY | ||||
|  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. | ||||
| */ | ||||
|  | ||||
| This is a Unix port of the Plan 9 formatted I/O package. | ||||
|  | ||||
| Please send comments about the packaging | ||||
| to Russ Cox <rsc@post.harvard.edu>. | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user