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 <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