Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ksh93/sh/deparse.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1982-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* David Korn <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* David Korn
23
* AT&T Labs
24
*
25
* shell deparser
26
*
27
*/
28
29
#include "defs.h"
30
#include "shnodes.h"
31
#include "test.h"
32
33
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
40
41
42
/* flags that can be specified with p_tree() */
43
#define NO_NEWLINE 1
44
#define NEED_BRACE 2
45
#define NO_BRACKET 4
46
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);
55
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 = "";
64
65
extern void sh_deparse(Sfio_t*, const Shnode_t*,int);
66
67
void sh_deparse(Sfio_t *out, const Shnode_t *t,int tflags)
68
{
69
outfile = out;
70
p_tree(t,tflags);
71
}
72
/*
73
* print script corresponding to shell tree <t>
74
*/
75
static void p_tree(register const Shnode_t *t,register int tflags)
76
{
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)
86
{
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;
96
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;
103
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;
112
113
case TFORK:
114
if(needbrace)
115
tflags |= NEED_BRACE;
116
if(t->tre.tretyp&(FAMP|FCOOP))
117
{
118
tflags = NEED_BRACE|NO_NEWLINE;
119
end_line = ' ';
120
}
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)
127
{
128
sfputr(outfile,"|&",'\n');
129
begin_line = 1;
130
}
131
else if(t->tre.tretyp&FAMP)
132
{
133
sfputr(outfile,"&",'\n');
134
begin_line = 1;
135
}
136
break;
137
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)
144
{
145
p_keyword("else",MIDDLE);
146
p_tree(t->if_.eltre,0);
147
}
148
p_keyword("fi",END);
149
break;
150
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)
160
{
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);
167
}
168
else
169
p_tree(t->wh.whtre,0);
170
t = t->wh.dotre;
171
goto dolist;
172
173
case TLST:
174
{
175
Shnode_t *tr = t->lst.lstrit;
176
if(tr->tre.tretyp==TWH && tr->wh.whinc && t->lst.lstlef->tre.tretyp==TARITH)
177
{
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;
183
}
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;
193
}
194
195
case TAND:
196
cp = "&&";
197
goto andor;
198
case TORF:
199
cp = "||";
200
goto andor;
201
case TFIL:
202
cp = "|";
203
andor:
204
{
205
int bracket = 0;
206
if(t->tre.tretyp&TTEST)
207
{
208
tflags |= NO_NEWLINE;
209
if(!(tflags&NO_BRACKET))
210
{
211
p_keyword("[[",BEGIN);
212
tflags |= NO_BRACKET;
213
bracket=1;
214
}
215
}
216
p_tree(t->lst.lstlef,NEED_BRACE|NO_NEWLINE|(tflags&NO_BRACKET));
217
if(tflags&FALTPIPE)
218
{
219
Shnode_t *tt = t->lst.lstrit;
220
if(tt->tre.tretyp!=TFIL || !(tt->lst.lstlef->tre.tretyp&FALTPIPE))
221
{
222
sfputc(outfile,'\n');
223
return;
224
}
225
}
226
sfputr(outfile,cp,here_doc?'\n':' ');
227
if(here_doc)
228
{
229
here_body(here_doc);
230
here_doc = 0;
231
}
232
level++;
233
p_tree(t->lst.lstrit,tflags|NEED_BRACE);
234
if(bracket)
235
p_keyword("]]",END);
236
level--;
237
break;
238
}
239
240
case TPAR:
241
p_keyword("(",BEGIN);
242
p_tree(t->par.partre,0);
243
p_keyword(")",END);
244
break;
245
246
case TARITH:
247
{
248
register struct argnod *ap = t->ar.arexpr;
249
if(begin_line && level)
250
sfnputc(outfile,'\t',level);
251
sfprintf(outfile,"(( %s ))%c",ap->argval,end_line);
252
if(!(tflags&NO_NEWLINE))
253
begin_line=1;
254
break;
255
}
256
257
case TFOR:
258
cp = ((t->tre.tretyp&COMSCAN)?"select":"for");
259
p_keyword(cp,BEGIN);
260
sfputr(outfile,t->for_.fornam,' ');
261
if(t->for_.forlst)
262
{
263
sfputr(outfile,"in",' ');
264
tflags = end_line;
265
end_line = '\n';
266
p_comarg(t->for_.forlst);
267
end_line = tflags;
268
}
269
else
270
sfputc(outfile,'\n');
271
begin_line = 1;
272
t = t->for_.fortre;
273
dolist:
274
p_keyword("do",MIDDLE);
275
p_tree(t,0);
276
p_keyword("done",END);
277
break;
278
279
case TSW:
280
p_keyword("case",BEGIN);
281
p_arg(t->sw.swarg,' ',0);
282
if(t->sw.swlst)
283
{
284
begin_line = 1;
285
sfputr(outfile,"in",'\n');
286
tflags = end_line;
287
end_line = '\n';
288
p_switch(t->sw.swlst);
289
end_line = tflags;
290
}
291
p_keyword("esac",END);
292
break;
293
294
case TFUN:
295
if(t->tre.tretyp&FPOSIX)
296
{
297
sfprintf(outfile,"%s",t->funct.functnam);
298
p_keyword("()\n",BEGIN);
299
}
300
else
301
{
302
p_keyword("function",BEGIN);
303
tflags = (t->funct.functargs?' ':'\n');
304
sfputr(outfile,t->funct.functnam,tflags);
305
if(t->funct.functargs)
306
{
307
tflags = end_line;
308
end_line = '\n';
309
p_comarg(t->funct.functargs);
310
end_line = tflags;
311
}
312
}
313
begin_line = 1;
314
p_keyword("{\n",MIDDLE);
315
begin_line = 1;
316
p_tree(t->funct.functtre,0);
317
p_keyword("}",END);
318
break;
319
/* new test compound command */
320
case TTST:
321
if(!(tflags&NO_BRACKET))
322
p_keyword("[[",BEGIN);
323
if((t->tre.tretyp&TPAREN)==TPAREN)
324
{
325
p_keyword("(",BEGIN);
326
p_tree(t->lst.lstlef,NO_BRACKET|NO_NEWLINE);
327
p_keyword(")",END);
328
}
329
else
330
{
331
int flags = (t->tre.tretyp)>>TSHIFT;
332
if(t->tre.tretyp&TNEGATE)
333
sfputr(outfile,"!",' ');
334
if(t->tre.tretyp&TUNARY)
335
{
336
un_op[1] = flags;
337
sfputr(outfile,un_op,' ');
338
}
339
else
340
cp = ((char*)(shtab_testops+(flags&037)-1)->sh_name);
341
p_arg(&(t->lst.lstlef->arg),' ',0);
342
if(t->tre.tretyp&TBINARY)
343
{
344
sfputr(outfile,cp,' ');
345
p_arg(&(t->lst.lstrit->arg),' ',0);
346
}
347
}
348
if(!(tflags&NO_BRACKET))
349
p_keyword("]]",END);
350
}
351
while(begin_line && here_doc)
352
{
353
here_body(here_doc);
354
here_doc = 0;
355
}
356
end_line = save;
357
return;
358
}
359
360
/*
361
* print a keyword
362
* increment indent level for flag==BEGIN
363
* decrement indent level for flag==END
364
*/
365
static void p_keyword(const char *word,int flag)
366
{
367
register int sep;
368
if(flag==END)
369
sep = end_line;
370
else if(*word=='[' || *word=='(')
371
sep = ' ';
372
else
373
sep = '\t';
374
if(flag!=BEGIN)
375
level--;
376
if(begin_line && level)
377
sfnputc(outfile,'\t',level);
378
sfputr(outfile,word,sep);
379
if(sep=='\n')
380
begin_line=1;
381
else
382
begin_line=0;
383
if(flag!=END)
384
level++;
385
}
386
387
static void p_arg(register const struct argnod *arg,register int endchar,int opts)
388
{
389
register const char *cp;
390
register int flag;
391
do
392
{
393
if(!arg->argnxt.ap)
394
flag = endchar;
395
else if(opts&PRE)
396
{
397
/* case alternation lists in reverse order */
398
p_arg(arg->argnxt.ap,'|',opts);
399
flag = endchar;
400
}
401
else if(opts)
402
flag = ' ';
403
cp = arg->argval;
404
if(*cp==0 && (arg->argflag&ARG_EXP) && arg->argchn.ap)
405
{
406
int c = (arg->argflag&ARG_RAW)?'>':'<';
407
sfputc(outfile,c);
408
sfputc(outfile,'(');
409
p_tree((Shnode_t*)arg->argchn.ap,0);
410
sfputc(outfile,')');
411
}
412
else if(*cp==0 && opts==POST && arg->argchn.ap)
413
{
414
/* compound assignment */
415
struct fornod *fp=(struct fornod*)arg->argchn.ap;
416
sfprintf(outfile,"%s=(\n",fp->fornam);
417
sfnputc(outfile,'\t',++level);
418
p_tree(fp->fortre,0);
419
if(--level)
420
sfnputc(outfile,'\t',level);
421
sfputc(outfile,')');
422
}
423
else if((arg->argflag&ARG_RAW) && (cp[1] || (*cp!='[' && *cp!=']')))
424
cp = sh_fmtq(cp);
425
sfputr(outfile,cp,flag);
426
if(flag=='\n')
427
begin_line = 1;
428
arg = arg->argnxt.ap;
429
}
430
while((opts&POST) && arg);
431
return;
432
}
433
434
static void p_redirect(register const struct ionod *iop)
435
{
436
register char *cp;
437
register int iof,iof2;
438
for(;iop;iop=iop->ionxt)
439
{
440
iof=iop->iofile;
441
cp = io_op;
442
if(iop->iovname)
443
{
444
sfwrite(outfile,"(;",2);
445
sfputr(outfile,iop->iovname,')');
446
cp++;
447
}
448
else
449
*cp = '0'+(iof&IOUFD);
450
if(iof&IOPUT)
451
{
452
if(*cp == '1' && !iop->iovname)
453
cp++;
454
io_op[1] = '>';
455
}
456
else
457
{
458
if(*cp == '0' && !iop->iovname)
459
cp++;
460
io_op[1] = '<';
461
}
462
io_op[2] = 0;
463
io_op[3] = 0;
464
if(iof&IOLSEEK)
465
{
466
io_op[1] = '#';
467
if(iof&IOARITH)
468
strcpy(&io_op[3]," ((");
469
}
470
else if(iof&IOMOV)
471
io_op[2] = '&';
472
else if(iof&(IORDW|IOAPP))
473
io_op[2] = '>';
474
else if(iof&IOCLOB)
475
io_op[2] = '|';
476
if(iop->iodelim)
477
{
478
/* here document */
479
#ifdef xxx
480
iop->iolink = (char*)here_doc;
481
#endif
482
here_doc = iop;
483
io_op[2] = '<';
484
#ifdef future
485
if(iof&IOSTRIP)
486
io_op[3] = '-';
487
#endif
488
}
489
sfputr(outfile,cp,' ');
490
if(iop->ionxt)
491
iof = ' ';
492
else
493
{
494
if((iof=end_line)=='\n')
495
begin_line = 1;
496
}
497
if((iof&IOLSEEK) && (iof&IOARITH))
498
iof2 = iof, iof = ' ';
499
if(iop->iodelim)
500
{
501
if(!(iop->iofile&IODOC))
502
sfwrite(outfile,"''",2);
503
sfputr(outfile,sh_fmtq(iop->iodelim),iof);
504
}
505
else if(iop->iofile&IORAW)
506
sfputr(outfile,sh_fmtq(iop->ioname),iof);
507
else
508
sfputr(outfile,iop->ioname,iof);
509
if((iof&IOLSEEK) && (iof&IOARITH))
510
sfputr(outfile, "))", iof2);
511
}
512
return;
513
}
514
515
static void p_comarg(register const struct comnod *com)
516
{
517
register int flag = end_line;
518
if(com->comtyp&FAMP)
519
sfwrite(outfile,"& ",2);
520
if(com->comarg || com->comio)
521
flag = ' ';
522
if(com->comset)
523
p_arg(com->comset,flag,POST);
524
if(com->comarg)
525
{
526
if(!com->comio)
527
flag = end_line;
528
if(com->comtyp&COMSCAN)
529
p_arg(com->comarg,flag,POST);
530
else
531
p_comlist((struct dolnod*)com->comarg,flag);
532
}
533
if(com->comio)
534
p_redirect(com->comio);
535
return;
536
}
537
538
static void p_comlist(const struct dolnod *dol,int endchar)
539
{
540
register char *cp, *const*argv;
541
register int flag = ' ', special;
542
argv = dol->dolval+ARG_SPARE;
543
cp = *argv;
544
special = (*cp=='[' && cp[1]==0);
545
do
546
{
547
if(cp)
548
argv++;
549
else
550
cp = "";
551
if(*argv==0)
552
{
553
if((flag=endchar)=='\n')
554
begin_line = 1;
555
special = (*cp==']' && cp[1]==0);
556
}
557
sfputr(outfile,special?cp:sh_fmtq(cp),flag);
558
special = 0;
559
}
560
while(cp = *argv);
561
return;
562
}
563
564
static void p_switch(register const struct regnod *reg)
565
{
566
if(level>1)
567
sfnputc(outfile,'\t',level-1);
568
p_arg(reg->regptr,')',PRE);
569
begin_line = 0;
570
sfputc(outfile,'\t');
571
if(reg->regcom)
572
p_tree(reg->regcom,0);
573
level++;
574
if(reg->regflag)
575
p_keyword(";&",END);
576
else
577
p_keyword(";;",END);
578
if(reg->regnxt)
579
p_switch(reg->regnxt);
580
return;
581
}
582
583
/*
584
* output here documents
585
*/
586
static void here_body(register const struct ionod *iop)
587
{
588
Sfio_t *infile;
589
#ifdef xxx
590
if(iop->iolink)
591
here_body((struct inode*)iop->iolink);
592
iop->iolink = 0;
593
#endif
594
if(iop->iofile&IOSTRG)
595
infile = sfnew((Sfio_t*)0,iop->ioname,iop->iosize,-1,SF_STRING|SF_READ);
596
else
597
sfseek(infile=sh.heredocs,iop->iooffset,SEEK_SET);
598
sfmove(infile,outfile,iop->iosize,-1);
599
if(iop->iofile&IOSTRG)
600
sfclose(infile);
601
sfputr(outfile,iop->iodelim,'\n');
602
}
603
604
605