8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libshell / common / sh / deparse.c
blob4526a84550e1a6589c848b214dc5503586b89204
1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * David Korn <dgk@research.att.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
22 * David Korn
23 * AT&T Labs
25 * shell deparser
29 #include "defs.h"
30 #include "shnodes.h"
31 #include "test.h"
34 #define HUGE_INT (((unsigned)-1)>>1)
35 #define BEGIN 0
36 #define MIDDLE 1
37 #define END 2
38 #define PRE 1
39 #define POST 2
42 /* flags that can be specified with p_tree() */
43 #define NO_NEWLINE 1
44 #define NEED_BRACE 2
45 #define NO_BRACKET 4
47 static void p_comlist(const struct dolnod*,int);
48 static void p_arg(const struct argnod*, int endchar, int opts);
49 static void p_comarg(const struct comnod*);
50 static void p_keyword(const char*,int);
51 static void p_redirect(const struct ionod*);
52 static void p_switch(const struct regnod*);
53 static void here_body(const struct ionod*);
54 static void p_tree(const Shnode_t*,int);
56 static int level;
57 static int begin_line;
58 static int end_line;
59 static char io_op[7];
60 static char un_op[3] = "-?";
61 static const struct ionod *here_doc;
62 static Sfio_t *outfile;
63 static const char *forinit = "";
65 extern void sh_deparse(Sfio_t*, const Shnode_t*,int);
67 void sh_deparse(Sfio_t *out, const Shnode_t *t,int tflags)
69 outfile = out;
70 p_tree(t,tflags);
73 * print script corresponding to shell tree <t>
75 static void p_tree(register const Shnode_t *t,register int tflags)
77 register char *cp;
78 int save = end_line;
79 int needbrace = (tflags&NEED_BRACE);
80 tflags &= ~NEED_BRACE;
81 if(tflags&NO_NEWLINE)
82 end_line = ' ';
83 else
84 end_line = '\n';
85 switch(t->tre.tretyp&COMMSK)
87 case TTIME:
88 if(t->tre.tretyp&COMSCAN)
89 p_keyword("!",BEGIN);
90 else
91 p_keyword("time",BEGIN);
92 if(t->par.partre)
93 p_tree(t->par.partre,tflags);
94 level--;
95 break;
97 case TCOM:
98 if(begin_line && level>0)
99 sfnputc(outfile,'\t',level);
100 begin_line = 0;
101 p_comarg((struct comnod*)t);
102 break;
104 case TSETIO:
105 if(t->tre.tretyp&FPCL)
106 tflags |= NEED_BRACE;
107 else
108 tflags = NO_NEWLINE|NEED_BRACE;
109 p_tree(t->fork.forktre,tflags);
110 p_redirect(t->fork.forkio);
111 break;
113 case TFORK:
114 if(needbrace)
115 tflags |= NEED_BRACE;
116 if(t->tre.tretyp&(FAMP|FCOOP))
118 tflags = NEED_BRACE|NO_NEWLINE;
119 end_line = ' ';
121 else if(t->fork.forkio)
122 tflags = NO_NEWLINE;
123 p_tree(t->fork.forktre,tflags);
124 if(t->fork.forkio)
125 p_redirect(t->fork.forkio);
126 if(t->tre.tretyp&FCOOP)
128 sfputr(outfile,"|&",'\n');
129 begin_line = 1;
131 else if(t->tre.tretyp&FAMP)
133 sfputr(outfile,"&",'\n');
134 begin_line = 1;
136 break;
138 case TIF:
139 p_keyword("if",BEGIN);
140 p_tree(t->if_.iftre,0);
141 p_keyword("then",MIDDLE);
142 p_tree(t->if_.thtre,0);
143 if(t->if_.eltre)
145 p_keyword("else",MIDDLE);
146 p_tree(t->if_.eltre,0);
148 p_keyword("fi",END);
149 break;
151 case TWH:
152 if(t->wh.whinc)
153 cp = "for";
154 else if(t->tre.tretyp&COMSCAN)
155 cp = "until";
156 else
157 cp = "while";
158 p_keyword(cp,BEGIN);
159 if(t->wh.whinc)
161 struct argnod *arg = (t->wh.whtre)->ar.arexpr;
162 sfprintf(outfile,"(( %s; ",forinit);
163 forinit = "";
164 sfputr(outfile,arg->argval,';');
165 arg = (t->wh.whinc)->arexpr;
166 sfprintf(outfile," %s))\n",arg->argval);
168 else
169 p_tree(t->wh.whtre,0);
170 t = t->wh.dotre;
171 goto dolist;
173 case TLST:
175 Shnode_t *tr = t->lst.lstrit;
176 if(tr->tre.tretyp==TWH && tr->wh.whinc && t->lst.lstlef->tre.tretyp==TARITH)
178 /* arithmetic for statement */
179 struct argnod *init = (t->lst.lstlef)->ar.arexpr;
180 forinit= init->argval;
181 p_tree(t->lst.lstrit,tflags);
182 break;
184 if(needbrace)
185 p_keyword("{",BEGIN);
186 p_tree(t->lst.lstlef,0);
187 if(needbrace)
188 tflags = 0;
189 p_tree(t->lst.lstrit,tflags);
190 if(needbrace)
191 p_keyword("}",END);
192 break;
195 case TAND:
196 cp = "&&";
197 goto andor;
198 case TORF:
199 cp = "||";
200 goto andor;
201 case TFIL:
202 cp = "|";
203 andor:
205 int bracket = 0;
206 if(t->tre.tretyp&TTEST)
208 tflags |= NO_NEWLINE;
209 if(!(tflags&NO_BRACKET))
211 p_keyword("[[",BEGIN);
212 tflags |= NO_BRACKET;
213 bracket=1;
216 p_tree(t->lst.lstlef,NEED_BRACE|NO_NEWLINE|(tflags&NO_BRACKET));
217 sfputr(outfile,cp,here_doc?'\n':' ');
218 if(here_doc)
220 here_body(here_doc);
221 here_doc = 0;
223 level++;
224 p_tree(t->lst.lstrit,tflags|NEED_BRACE);
225 if(bracket)
226 p_keyword("]]",END);
227 level--;
228 break;
231 case TPAR:
232 p_keyword("(",BEGIN);
233 p_tree(t->par.partre,0);
234 p_keyword(")",END);
235 break;
237 case TARITH:
239 register struct argnod *ap = t->ar.arexpr;
240 if(begin_line && level)
241 sfnputc(outfile,'\t',level);
242 sfprintf(outfile,"(( %s ))%c",ap->argval,end_line);
243 if(!(tflags&NO_NEWLINE))
244 begin_line=1;
245 break;
248 case TFOR:
249 cp = ((t->tre.tretyp&COMSCAN)?"select":"for");
250 p_keyword(cp,BEGIN);
251 sfputr(outfile,t->for_.fornam,' ');
252 if(t->for_.forlst)
254 sfputr(outfile,"in",' ');
255 tflags = end_line;
256 end_line = '\n';
257 p_comarg(t->for_.forlst);
258 end_line = tflags;
260 else
261 sfputc(outfile,'\n');
262 begin_line = 1;
263 t = t->for_.fortre;
264 dolist:
265 p_keyword("do",MIDDLE);
266 p_tree(t,0);
267 p_keyword("done",END);
268 break;
270 case TSW:
271 p_keyword("case",BEGIN);
272 p_arg(t->sw.swarg,' ',0);
273 if(t->sw.swlst)
275 begin_line = 1;
276 sfputr(outfile,"in",'\n');
277 tflags = end_line;
278 end_line = '\n';
279 p_switch(t->sw.swlst);
280 end_line = tflags;
282 p_keyword("esac",END);
283 break;
285 case TFUN:
286 if(t->tre.tretyp&FPOSIX)
288 sfprintf(outfile,"%s",t->funct.functnam);
289 p_keyword("()\n",BEGIN);
291 else
293 p_keyword("function",BEGIN);
294 tflags = (t->funct.functargs?' ':'\n');
295 sfputr(outfile,t->funct.functnam,tflags);
296 if(t->funct.functargs)
298 tflags = end_line;
299 end_line = '\n';
300 p_comarg(t->funct.functargs);
301 end_line = tflags;
304 begin_line = 1;
305 p_keyword("{\n",MIDDLE);
306 begin_line = 1;
307 p_tree(t->funct.functtre,0);
308 p_keyword("}",END);
309 break;
310 /* new test compound command */
311 case TTST:
312 if(!(tflags&NO_BRACKET))
313 p_keyword("[[",BEGIN);
314 if((t->tre.tretyp&TPAREN)==TPAREN)
316 p_keyword("(",BEGIN);
317 p_tree(t->lst.lstlef,NO_BRACKET|NO_NEWLINE);
318 p_keyword(")",END);
320 else
322 int flags = (t->tre.tretyp)>>TSHIFT;
323 if(t->tre.tretyp&TNEGATE)
324 sfputr(outfile,"!",' ');
325 if(t->tre.tretyp&TUNARY)
327 un_op[1] = flags;
328 sfputr(outfile,un_op,' ');
330 else
331 cp = ((char*)(shtab_testops+(flags&037)-1)->sh_name);
332 p_arg(&(t->lst.lstlef->arg),' ',0);
333 if(t->tre.tretyp&TBINARY)
335 sfputr(outfile,cp,' ');
336 p_arg(&(t->lst.lstrit->arg),' ',0);
339 if(!(tflags&NO_BRACKET))
340 p_keyword("]]",END);
342 while(begin_line && here_doc)
344 here_body(here_doc);
345 here_doc = 0;
347 end_line = save;
348 return;
352 * print a keyword
353 * increment indent level for flag==BEGIN
354 * decrement indent level for flag==END
356 static void p_keyword(const char *word,int flag)
358 register int sep;
359 if(flag==END)
360 sep = end_line;
361 else if(*word=='[' || *word=='(')
362 sep = ' ';
363 else
364 sep = '\t';
365 if(flag!=BEGIN)
366 level--;
367 if(begin_line && level)
368 sfnputc(outfile,'\t',level);
369 sfputr(outfile,word,sep);
370 if(sep=='\n')
371 begin_line=1;
372 else
373 begin_line=0;
374 if(flag!=END)
375 level++;
378 static void p_arg(register const struct argnod *arg,register int endchar,int opts)
380 register const char *cp;
381 register int flag;
384 if(!arg->argnxt.ap)
385 flag = endchar;
386 else if(opts&PRE)
388 /* case alternation lists in reverse order */
389 p_arg(arg->argnxt.ap,'|',opts);
390 flag = endchar;
392 else if(opts)
393 flag = ' ';
394 cp = arg->argval;
395 if(*cp==0 && opts==POST && arg->argchn.ap)
397 /* compound assignment */
398 struct fornod *fp=(struct fornod*)arg->argchn.ap;
399 sfprintf(outfile,"%s=(\n",fp->fornam);
400 sfnputc(outfile,'\t',++level);
401 p_tree(fp->fortre,0);
402 if(--level)
403 sfnputc(outfile,'\t',level);
404 sfputc(outfile,')');
406 else if((arg->argflag&ARG_RAW) && (cp[1] || (*cp!='[' && *cp!=']')))
407 cp = sh_fmtq(cp);
408 sfputr(outfile,cp,flag);
409 if(flag=='\n')
410 begin_line = 1;
411 arg = arg->argnxt.ap;
413 while((opts&POST) && arg);
414 return;
417 static void p_redirect(register const struct ionod *iop)
419 register char *cp;
420 register int iof,iof2;
421 for(;iop;iop=iop->ionxt)
423 iof=iop->iofile;
424 cp = io_op;
425 if(iop->iovname)
427 sfwrite(outfile,"(;",2);
428 sfputr(outfile,iop->iovname,')');
429 cp++;
431 else
432 *cp = '0'+(iof&IOUFD);
433 if(iof&IOPUT)
435 if(*cp == '1' && !iop->iovname)
436 cp++;
437 io_op[1] = '>';
439 else
441 if(*cp == '0' && !iop->iovname)
442 cp++;
443 io_op[1] = '<';
445 io_op[2] = 0;
446 io_op[3] = 0;
447 if(iof&IOLSEEK)
449 io_op[1] = '#';
450 if(iof&IOARITH)
451 strcpy(&io_op[3]," ((");
453 else if(iof&IOMOV)
454 io_op[2] = '&';
455 else if(iof&(IORDW|IOAPP))
456 io_op[2] = '>';
457 else if(iof&IOCLOB)
458 io_op[2] = '|';
459 if(iop->iodelim)
461 /* here document */
462 #ifdef xxx
463 iop->iolink = (char*)here_doc;
464 #endif
465 here_doc = iop;
466 io_op[2] = '<';
467 #ifdef future
468 if(iof&IOSTRIP)
469 io_op[3] = '-';
470 #endif
472 sfputr(outfile,cp,' ');
473 if(iop->ionxt)
474 iof = ' ';
475 else
477 if((iof=end_line)=='\n')
478 begin_line = 1;
480 if((iof&IOLSEEK) && (iof&IOARITH))
481 iof2 = iof, iof = ' ';
482 if(iop->iodelim)
484 if(!(iop->iofile&IODOC))
485 sfwrite(outfile,"''",2);
486 sfputr(outfile,sh_fmtq(iop->iodelim),iof);
488 else if(iop->iofile&IORAW)
489 sfputr(outfile,sh_fmtq(iop->ioname),iof);
490 else
491 sfputr(outfile,iop->ioname,iof);
492 if((iof&IOLSEEK) && (iof&IOARITH))
493 sfputr(outfile, "))", iof2);
495 return;
498 static void p_comarg(register const struct comnod *com)
500 register int flag = end_line;
501 if(com->comarg || com->comio)
502 flag = ' ';
503 if(com->comset)
504 p_arg(com->comset,flag,POST);
505 if(com->comarg)
507 if(!com->comio)
508 flag = end_line;
509 if(com->comtyp&COMSCAN)
510 p_arg(com->comarg,flag,POST);
511 else
512 p_comlist((struct dolnod*)com->comarg,flag);
514 if(com->comio)
515 p_redirect(com->comio);
516 return;
519 static void p_comlist(const struct dolnod *dol,int endchar)
521 register char *cp, *const*argv;
522 register int flag = ' ', special;
523 argv = dol->dolval+ARG_SPARE;
524 cp = *argv;
525 special = (*cp=='[' && cp[1]==0);
528 if(cp)
529 argv++;
530 else
531 cp = "";
532 if(*argv==0)
534 if((flag=endchar)=='\n')
535 begin_line = 1;
536 special = (*cp==']' && cp[1]==0);
538 sfputr(outfile,special?cp:sh_fmtq(cp),flag);
539 special = 0;
541 while(cp = *argv);
542 return;
545 static void p_switch(register const struct regnod *reg)
547 if(level>1)
548 sfnputc(outfile,'\t',level-1);
549 p_arg(reg->regptr,')',PRE);
550 begin_line = 0;
551 sfputc(outfile,'\t');
552 if(reg->regcom)
553 p_tree(reg->regcom,0);
554 level++;
555 if(reg->regflag)
556 p_keyword(";&",END);
557 else
558 p_keyword(";;",END);
559 if(reg->regnxt)
560 p_switch(reg->regnxt);
561 return;
565 * output here documents
567 static void here_body(register const struct ionod *iop)
569 Sfio_t *infile;
570 #ifdef xxx
571 if(iop->iolink)
572 here_body((struct inode*)iop->iolink);
573 iop->iolink = 0;
574 #endif
575 if(iop->iofile&IOSTRG)
576 infile = sfnew((Sfio_t*)0,iop->ioname,iop->iosize,-1,SF_STRING|SF_READ);
577 else
578 sfseek(infile=sh.heredocs,iop->iooffset,SEEK_SET);
579 sfmove(infile,outfile,iop->iosize,-1);
580 if(iop->iofile&IOSTRG)
581 sfclose(infile);
582 sfputr(outfile,iop->iodelim,'\n');