#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);
	}
}
