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
29static const char usage[] =
30"[-?\n@(#)$Id: shcomp (AT&T Research) 2003-03-02 $\n]"
31USAGE_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
68static const char header[6] = { CNTL('k'),CNTL('s'),CNTL('h'),0,VERSION,0 };
69
70int 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