Charles.Forsyth20060303644188019 years agoHistory
549 lines · 8.3 KB · C
RawDownload
#include "rc.h"#include <windows.h> enum {	Nchild	= 100,}; typedef struct Child	Child; struct Child {	int	pid;	HANDLE	handle;}; static Child child[Nchild]; static voidwinerror(void){	int e, r;	char buf[100], *p, *q; 	e = GetLastError();		r = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,		0, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),		buf, sizeof(buf), 0); 	if(r == 0)		snprint(buf, sizeof(buf), "windows error %d", e); 	for(p=q=buf; *p; p++) {		if(*p == '\r')			continue;		if(*p == '\n')			*q++ = ' ';		else			*q++ = *p;	}	*q = 0;	errstr(buf, sizeof buf);} static intbadentry(char *filename){	if(*filename == 0)		return 1;	if(filename[0] == '.'){		if(filename[1] == 0)			return 1;		if(filename[1] == '.' && filename[2] == 0)			return 1;	}	return 0;} Direntry*readdirect(char *path){	long n;	HANDLE h;	Direntry *d;	char fullpath[MAX_PATH];	WIN32_FIND_DATA data; 	snprint(fullpath, MAX_PATH, "%s\\*.*", path); 	h = FindFirstFile(fullpath, &data);	if(h == INVALID_HANDLE_VALUE)		return 0; 	n = 0;	d = 0;	for(;;){		if(!badentry(data.cFileName)){			d = realloc(d, (n+2)*sizeof(Direntry));			if(d == 0){				werrstr("memory allocation");				return 0;			}			d[n].name = malloc(strlen(data.cFileName)+1);			if(d[n].name == 0){				werrstr("memory allocation");				return 0;			}			strcpy(d[n].name, data.cFileName);			if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)				d[n].isdir = 1;			else				d[n].isdir = 0;			n++;		}		if(FindNextFile(h, &data) == 0)			break;	}	FindClose(h);	if(d){		d[n].name = 0;		d[n].isdir = 0;	}	return d;} voidfatal(char *fmt, ...){	char buf[512];	va_list arg; 	va_start(arg, fmt);	vseprint(buf, buf+sizeof(buf), fmt, arg);	va_end(arg); 	fprint(2, "rc: %s\n", buf);	_exits(buf);} static inttas(int *p){		int v;		_asm {		mov	eax, p		mov	ebx, 1		xchg	ebx, [eax]		mov	v, ebx	} 	return v;} static voidlock(Lock *lk){	int i; 	/* easy case */	if(!tas(&lk->val))		return; 	/* for muli processor machines */	for(i=0; i<100; i++)		if(!tas(&lk->val))			return; 	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);	for(;;) {		for(i=0; i<10000; i++) {			Sleep(0);			if(!tas(&lk->val)) {				SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);				return;			}		}	}} static voidunlock(Lock *lk){	lk->val = 0;} intrefinc(Ref *r){	int i; 	lock(&r->lk);	i = r->ref;	r->ref++;	unlock(&r->lk);	return i;} int	refdec(Ref *r){	int i; 	lock(&r->lk);	r->ref--;	i = r->ref;	unlock(&r->lk); 	return i;} /* * windows quoting rules - I think * Words are seperated by space or tab * Words containing a space or tab can be quoted using " * 2N backslashes + " ==> N backslashes and end quote * 2N+1 backslashes + " ==> N backslashes + literal " * N backslashes not followed by " ==> N backslashes */static char *dblquote(char *cmd, char *s){	int nb;	char *p; 	for(p=s; *p; p++)		if(*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == '"')			break; 	if(*p == 0){				/* easy case */		strcpy(cmd, s);		return cmd+(p-s);	} 	*cmd++ = '"';	for(;;) {		for(nb=0; *s=='\\'; nb++)			*cmd++ = *s++; 		if(*s == 0) {			/* trailing backslashes -> 2N */			while(nb-- > 0)				*cmd++ = '\\';			break;		} 		if(*s == '"') {			/* literal quote -> 2N+1 backslashes */			while(nb-- > 0)				*cmd++ = '\\';			*cmd++ = '\\';		/* escape the quote */		}		*cmd++ = *s++;	} 	*cmd++ = '"';	*cmd = 0; 	return cmd;} static char *proccmd(char **argv){	int i, n;	char *cmd, *p; 		/* conservatively calculate length of command;		 * backslash expansion can cause growth in dblquote().		 */	for(i=0,n=0; argv[i]; i++) {		n += 2*strlen(argv[i]);	}	n++;		cmd = malloc(n);	for(i=0,p=cmd; argv[i]; i++) {		p = dblquote(p, argv[i]);		*p++ = ' ';	}	if(p != cmd)		p--;	*p = 0; 	return cmd;} static char *exportenv(char **e){	int i, j, n;	char *buf; 	if(e == 0 || *e == 0)		return 0; 	buf = 0;	n = 0;	for(i = 0; *e; e++, i++) {		j = strlen(*e)+1;		buf = realloc(buf, n+j);		strcpy(buf+n, *e);		n += j;	}	/* final null */	buf = realloc(buf, n+1);	buf[n] = 0; 	return buf;} static intsetpath(char *path, char *file){	char *p, *last, tmp[MAX_PATH+1];	int n; 	if(strlen(file) >= MAX_PATH){		werrstr("file name too long");		return -1;	}	strcpy(tmp, file); 	for(p=tmp; *p; p++) {		if(*p == '/')			*p = '\\';	} 	if(tmp[0] != 0 && tmp[1] == ':') {		if(tmp[2] == 0) {			tmp[2] = '\\';			tmp[3] = 0;		} else if(tmp[2] != '\\') {			/* don't allow c:foo - only c:\foo */			werrstr("illegal file name");			return -1;		}	} 	path[0] = 0;	n = GetFullPathName(tmp, MAX_PATH, path, &last);	if(n >= MAX_PATH) {		werrstr("file name too long");		return -1;	}	if(n == 0 && tmp[0] == '\\' && tmp[1] == '\\' && tmp[2] != 0) {		strcpy(path, tmp);		return -1;	} 	if(n == 0) {		werrstr("bad file name");		return -1;	} 	for(p=path; *p; p++) {		if(*p < 32 || *p == '*' || *p == '?') {			werrstr("file not found");			return -1;		}	} 	/* get rid of trailling \ */	if(path[n-1] == '\\') {		if(n <= 2) {			werrstr("illegal file name");			return -1;		}		path[n-1] = 0;		n--;	} 	if(path[1] == ':' && path[2] == 0) {		path[2] = '\\';		path[3] = '.';		path[4] = 0;		return -1;	} 	if(path[0] != '\\' || path[1] != '\\')		return 0; 	for(p=path+2,n=0; *p; p++)		if(*p == '\\')			n++;	if(n == 0)		return -1;	if(n == 1)		return -1;	return 0;}  static intexecpath(char *path, char *file){	int n; 	if(setpath(path, file) < 0)		return 0; 	n = strlen(path)-4;	if(path[n] == '.') {		if(GetFileAttributes(path) != -1)			return 1;	}	strncat(path, ".exe", MAX_PATH);	path[MAX_PATH-1] = 0;	if(GetFileAttributes(path) != -1)		return 1;	return 0;} static HANDLEfdexport(int fd){	HANDLE h, r; 	if(fd < 0)		return INVALID_HANDLE_VALUE; 	h = (HANDLE)_get_osfhandle(fd);	if(h < 0)		return INVALID_HANDLE_VALUE; 	if(!DuplicateHandle(GetCurrentProcess(), h,				GetCurrentProcess(), &r, DUPLICATE_SAME_ACCESS,				1, DUPLICATE_SAME_ACCESS))		return INVALID_HANDLE_VALUE;	return r;} static intaddchild(int pid, HANDLE handle){	int i;		for(i=0; i<Nchild; i++) {		if(child[i].handle == 0) {			child[i].handle = handle;			child[i].pid = pid;			return 1;		}	}	werrstr("child table full");	return 0;} intprocwait(uint pid){	HANDLE h;	int i, exit;		if(pid == 0)		return 0; 	h = 0;	for(i = 0; i < Nchild; i++){		if(child[i].pid == pid){			h = child[i].handle;			child[i].pid = 0;			child[i].handle = 0;			break;		}	} 	if(h == 0){	/* we don't know about this one - let the system try to find it */		h = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);		if(h == 0)			return 0;		/* can't find it */	} 	if(WaitForSingleObject(h, INFINITE) == WAIT_FAILED) {		winerror();		fatal("procwait: ");	} 	if(!GetExitCodeProcess(h, &exit)) {		winerror();		exit = 1;	} 	CloseHandle(h);	return exit;} uintproc(char **argv, int stdin, int stdout, int stderr){	char *p, *arg0, *q, buf[MAX_PATH], path[MAX_PATH], *cmd, *eb;	STARTUPINFO si;	PROCESS_INFORMATION pi;	int r, found, full;	extern char **_environ;	Word *w; 	arg0 = argv[0];	if(arg0 == 0) {		werrstr("null argv[0]");		return 0;	} 	full = arg0[0] == '\\' || arg0[0] == '/' || arg0[0] == '.';	found = execpath(path, arg0); 	if(!found && !full) {		w = vlook("path")->val;		if(w)			p = w->word;		else			p = getenv("path");		for(; p && *p; p = q){			q = strchr(p, ';');			if(q)				*q = 0;			snprint(buf, sizeof(buf), "%s/%s", p, arg0);			if(q)				*q++ = ';';			found = execpath(path, buf);			if(found)				break;		}

Lines 1–500 of 549.