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
21 /*
22 * David Korn
23 * AT&T Labs
24 *
25 * shell script to shell binary converter
26 *
27 */
28
29 static const char usage[] =
30 "[-?\n@(#)$Id: shcomp (AT&T Research) 2003-03-02 $\n]"
31 USAGE_LICENSE
32 "[+NAME?shcomp - compile a shell script]"
33 "[+DESCRIPTION?Unless \b-D\b is specified, \bshcomp\b takes a shell script, "
34 "\ainfile\a, and creates a binary format file, \aoutfile\a, that "
35 "\bksh\b can read and execute with the same effect as the original "
36 "script.]"
37 "[+?Since aliases are processed as the script is read, alias definitions "
38 "whose value requires variable expansion will not work correctly.]"
39 "[+?If \b-D\b is specified, all double quoted strings that are preceded by "
40 "\b$\b are output. These are the messages that need to be "
41 "translated to locale specific versions for internationalization.]"
42 "[+?If \aoutfile\a is omitted, then the results will be written to "
43 "standard output. If \ainfile\a is also omitted, the shell script "
44 "will be read from standard input.]"
45 "[D:dictionary?Generate a list of strings that need to be placed in a message "
46 "catalog for internationalization.]"
47 "[n:noexec?Displays warning messages for obsolete or non-conforming "
48 "constructs.] "
49 "[v:verbose?Displays input from \ainfile\a onto standard error as it "
50 "reads it.]"
51 "\n"
52 "\n[infile [outfile]]\n"
53 "\n"
54 "[+EXIT STATUS?]{"
55 "[+0?Successful completion.]"
56 "[+>0?An error occurred.]"
57 "}"
58 "[+SEE ALSO?\bksh\b(1)]"
59 ;
60
61 #include <shell.h>
62 #include "defs.h"
63 #include "shnodes.h"
64 #include "sys/stat.h"
65
66 #define CNTL(x) ((x)&037)
67 #define VERSION 3
68 static const char header[6] = { CNTL('k'),CNTL('s'),CNTL('h'),0,VERSION,0 };
69
main(int argc,char * argv[])70 int main(int argc, char *argv[])
71 {
72 Sfio_t *in, *out;
73 Shell_t *shp;
74 Namval_t *np;
75 Shnode_t *t;
76 char *cp;
77 int n, nflag=0, vflag=0, dflag=0;
78 error_info.id = argv[0];
79 while(n = optget(argv, usage )) switch(n)
80 {
81 case 'D':
82 dflag=1;
83 break;
84 case 'v':
85 vflag=1;
86 break;
87 case 'n':
88 nflag=1;
89 break;
90 case ':':
91 errormsg(SH_DICT,2,"%s",opt_info.arg);
92 break;
93 case '?':
94 errormsg(SH_DICT,ERROR_usage(2),"%s",opt_info.arg);
95 break;
96 }
97 shp = sh_init(argc,argv,(Shinit_f)0);
98 shp->shcomp = 1;
99 argv += opt_info.index;
100 argc -= opt_info.index;
101 if(error_info.errors || argc>2)
102 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
103 if(cp= *argv)
104 {
105 argv++;
106 in = sh_pathopen(cp);
107 }
108 else
109 in = sfstdin;
110 if(cp= *argv)
111 {
112 struct stat statb;
113 if(!(out = sfopen((Sfio_t*)0,cp,"w")))
114 errormsg(SH_DICT,ERROR_system(1),"%s: cannot create",cp);
115 if(fstat(sffileno(out),&statb) >=0)
116 chmod(cp,(statb.st_mode&~S_IFMT)|S_IXUSR|S_IXGRP|S_IXOTH);
117 }
118 else
119 out = sfstdout;
120 if(dflag)
121 {
122 sh_onoption(SH_DICTIONARY);
123 sh_onoption(SH_NOEXEC);
124 }
125 if(nflag)
126 sh_onoption(SH_NOEXEC);
127 if(vflag)
128 sh_onoption(SH_VERBOSE);
129 if(!dflag)
130 sfwrite(out,header,sizeof(header));
131 shp->inlineno = 1;
132 #if SHOPT_BRACEPAT
133 sh_onoption(SH_BRACEEXPAND);
134 #endif
135 while(1)
136 {
137 stakset((char*)0,0);
138 if(t = (Shnode_t*)sh_parse(shp,in,0))
139 {
140 if((t->tre.tretyp&(COMMSK|COMSCAN))==0 && t->com.comnamp && strcmp(nv_name((Namval_t*)t->com.comnamp),"alias")==0)
141 sh_exec(t,0);
142 if(!dflag && sh_tdump(out,t) < 0)
143 errormsg(SH_DICT,ERROR_exit(1),"dump failed");
144 }
145 else if(sfeof(in))
146 break;
147 if(sferror(in))
148 errormsg(SH_DICT,ERROR_system(1),"I/O error");
149 if(t && ((t->tre.tretyp&COMMSK)==TCOM) && (np=t->com.comnamp) && (cp=nv_name(np)))
150 {
151 if(strcmp(cp,"exit")==0)
152 break;
153 /* check for exec of a command */
154 if(strcmp(cp,"exec")==0)
155 {
156 if(t->com.comtyp&COMSCAN)
157 {
158 if(t->com.comarg->argnxt.ap)
159 break;
160 }
161 else
162 {
163 struct dolnod *ap = (struct dolnod*)t->com.comarg;
164 if(ap->dolnum>1)
165 break;
166 }
167 }
168 }
169 }
170 /* copy any remaining input */
171 sfmove(in,out,SF_UNBOUND,-1);
172 if(in!=sfstdin)
173 sfclose(in);
174 if(out!=sfstdout)
175 sfclose(out);
176 return(0);
177 }
178