#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*, uchar*);
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;

       if(tag->type!=WORD){
               yyerror("Bad here tag");
               return nil;
       }
       h = new(struct here);
       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 = estrdup(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, (uchar *)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;
               free(h);
       }
       here = 0;
       doprompt = 1;
}

void
psubst(io *f, uchar *s)
{
       int savec, n;
       uchar *t, *u;
       word *star;
       while(*s){
               if(*s!='$'){
                       if(0xa0 <= *s && *s <= 0xf5){
                               pchr(f, *s++);
                               if(*s=='\0')
                                       break;
                       }
                       else if(0xf6 <= *s && *s <= 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((char *)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);
       }
}