| #include	"mk.h" | 
 |  | 
 | static	Word	*nextword(char**); | 
 |  | 
 | Word* | 
 | newword(char *s) | 
 | { | 
 | 	Word *w; | 
 |  | 
 | 	w = (Word *)Malloc(sizeof(Word)); | 
 | 	w->s = strdup(s); | 
 | 	w->next = 0; | 
 | 	return(w); | 
 | } | 
 |  | 
 | Word * | 
 | stow(char *s) | 
 | { | 
 | 	Word *head, *w, *new; | 
 |  | 
 | 	w = head = 0; | 
 | 	while(*s){ | 
 | 		new = nextword(&s); | 
 | 		if(new == 0) | 
 | 			break; | 
 | 		if (w) | 
 | 			w->next = new; | 
 | 		else | 
 | 			head = w = new; | 
 | 		while(w->next) | 
 | 			w = w->next; | 
 | 		 | 
 | 	} | 
 | 	if (!head) | 
 | 		head = newword(""); | 
 | 	return(head); | 
 | } | 
 |  | 
 | char * | 
 | wtos(Word *w, int sep) | 
 | { | 
 | 	Bufblock *buf; | 
 | 	char *cp; | 
 |  | 
 | 	buf = newbuf(); | 
 | 	for(; w; w = w->next){ | 
 | 		for(cp = w->s; *cp; cp++) | 
 | 			insert(buf, *cp); | 
 | 		if(w->next) | 
 | 			insert(buf, sep); | 
 | 	} | 
 | 	insert(buf, 0); | 
 | 	cp = strdup(buf->start); | 
 | 	freebuf(buf); | 
 | 	return(cp); | 
 | } | 
 |  | 
 | Word* | 
 | wdup(Word *w) | 
 | { | 
 | 	Word *v, *new, *base; | 
 |  | 
 | 	v = base = 0; | 
 | 	while(w){ | 
 | 		new = newword(w->s); | 
 | 		if(v) | 
 | 			v->next = new; | 
 | 		else | 
 | 			base = new; | 
 | 		v = new; | 
 | 		w = w->next; | 
 | 	} | 
 | 	return base; | 
 | } | 
 |  | 
 | void | 
 | delword(Word *w) | 
 | { | 
 | 	Word *v; | 
 |  | 
 | 	while(v = w){ | 
 | 		w = w->next; | 
 | 		if(v->s) | 
 | 			free(v->s); | 
 | 		free(v); | 
 | 	} | 
 | } | 
 |  | 
 | /* | 
 |  *	break out a word from a string handling quotes, executions, | 
 |  *	and variable expansions. | 
 |  */ | 
 | static Word* | 
 | nextword(char **s) | 
 | { | 
 | 	Bufblock *b; | 
 | 	Word *head, *tail, *w; | 
 | 	Rune r; | 
 | 	char *cp; | 
 | 	int empty; | 
 |  | 
 | 	cp = *s; | 
 | 	b = newbuf(); | 
 | restart: | 
 | 	head = tail = 0; | 
 | 	while(*cp == ' ' || *cp == '\t')		/* leading white space */ | 
 | 		cp++; | 
 | 	empty = 1; | 
 | 	while(*cp){ | 
 | 		cp += chartorune(&r, cp); | 
 | 		switch(r) | 
 | 		{ | 
 | 		case ' ': | 
 | 		case '\t': | 
 | 		case '\n': | 
 | 			goto out; | 
 | 		case '\\': | 
 | 		case '\'': | 
 | 		case '"': | 
 | 			empty = 0; | 
 | 			cp = shellt->expandquote(cp, r, b); | 
 | 			if(cp == 0){ | 
 | 				fprint(2, "missing closing quote: %s\n", *s); | 
 | 				Exit(); | 
 | 			} | 
 | 			break; | 
 | 		case '$': | 
 | 			w = varsub(&cp); | 
 | 			if(w == 0){ | 
 | 				if(empty) | 
 | 					goto restart; | 
 | 				break; | 
 | 			} | 
 | 			empty = 0; | 
 | 			if(b->current != b->start){ | 
 | 				bufcpy(b, w->s, strlen(w->s)); | 
 | 				insert(b, 0); | 
 | 				free(w->s); | 
 | 				w->s = strdup(b->start); | 
 | 				b->current = b->start; | 
 | 			} | 
 | 			if(head){ | 
 | 				bufcpy(b, tail->s, strlen(tail->s)); | 
 | 				bufcpy(b, w->s, strlen(w->s)); | 
 | 				insert(b, 0); | 
 | 				free(tail->s); | 
 | 				tail->s = strdup(b->start); | 
 | 				tail->next = w->next; | 
 | 				free(w->s); | 
 | 				free(w); | 
 | 				b->current = b->start; | 
 | 			} else | 
 | 				tail = head = w; | 
 | 			while(tail->next) | 
 | 				tail = tail->next; | 
 | 			break; | 
 | 		default: | 
 | 			empty = 0; | 
 | 			rinsert(b, r); | 
 | 			break; | 
 | 		} | 
 | 	} | 
 | out: | 
 | 	*s = cp; | 
 | 	if(b->current != b->start){ | 
 | 		if(head){ | 
 | 			cp = b->current; | 
 | 			bufcpy(b, tail->s, strlen(tail->s)); | 
 | 			bufcpy(b, b->start, cp-b->start); | 
 | 			insert(b, 0); | 
 | 			free(tail->s); | 
 | 			tail->s = strdup(cp); | 
 | 		} else { | 
 | 			insert(b, 0); | 
 | 			head = newword(b->start); | 
 | 		} | 
 | 	} | 
 | 	freebuf(b); | 
 | 	return head; | 
 | } | 
 |  | 
 | void | 
 | dumpw(char *s, Word *w) | 
 | { | 
 | 	Bprint(&bout, "%s", s); | 
 | 	for(; w; w = w->next) | 
 | 		Bprint(&bout, " '%s'", w->s); | 
 | 	Bputc(&bout, '\n'); | 
 | } |