Makefile: add 2 warning-inhibiting flags
[glg-sh.git] / main.c
blobde43967c392638945f0e9d354cde1ed85874bdce
1 #include <stdbool.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
6 typedef enum {
7 F_ALLEXPORT, // -a or -o allexport
8 F_ERREXIT, // -e or -o errexit
9 F_IGNOREEOF, // -o ignoreeof
10 F_MONITOR, // -m or -o monitor
11 F_NOCLOBBER, // -C or -o noclobb
12 F_NOGLOB, // -f or -o noglob
13 F_REMEMBER, // -h
14 F_NOEXEC, // -n or -o noexec
15 F_NOLOG, // -o nolog
16 F_NOTIFY, // -b or -o notify
17 F_NOUNSET, // -u or -o nounset
18 F_VERBOSE, // -v or -o verbose
19 F_VI, // -o vi
20 F_XTRACE, // -x or -o xtrace
22 F_D_ALLEXPORT, // +a or +o allexport
23 F_D_ERREXIT, // +e or +o errexit
24 F_D_IGNOREEOF, // +o ignoreeof
25 F_D_MONITOR, // +m or +o monitor
26 F_D_NOCLOBBER, // +C or +o noclobber
27 F_D_NOGLOB, // +f or +o noglob
28 F_D_REMEMBER, // +h
29 F_D_NOEXEC, // +n or +o noexec
30 F_D_NOLOG, // +o nolog
31 F_D_NOTIFY, // +b or +o notify
32 F_D_NOUNSET, // +u or +o nounset
33 F_D_VERBOSE, // +v or +o verbose
34 F_D_VI, // +o vi
35 F_D_XTRACE, // +x or +o xtrace
37 F_CMDSTR, // -c
38 F_CMDSTDIN, // -s
40 F_INTERACTIVE // -i
42 } Flag;
44 struct FlagList_ {
45 Flag flag;
46 struct FlagList_ *next;
49 typedef struct FlagList_ FlagList;
51 const char *progname = "sh";
53 static FlagList *cons_flag(Flag f, FlagList *l);
54 static FlagList *parse_argv();
55 static void usage(void);
57 /* used to build flag list */
58 FlagList *cons_flag(Flag f, FlagList *l)
60 FlagList *node = malloc(sizeof(FlagList));
61 if(node != NULL) {
62 node->flag = f;
63 node->next = l;
65 return node;
68 /* mostly for debugging at this point */
69 void print_flaglist(FlagList *l)
71 while(l != NULL) {
72 switch(l->flag) {
73 case F_ALLEXPORT:
74 printf("allexport\n");
75 break;
76 case F_ERREXIT:
77 printf("errexit\n");
78 break;
79 case F_IGNOREEOF:
80 printf("ignoreeof\n");
81 break;
82 case F_MONITOR:
83 printf("monitor\n");
84 break;
85 case F_NOCLOBBER:
86 printf("noclobber\n");
87 break;
88 case F_NOGLOB:
89 printf("noglob\n");
90 break;
91 case F_REMEMBER:
92 printf("remember\n");
93 break;
94 case F_NOEXEC:
95 printf("noexec\n");
96 break;
97 case F_NOLOG:
98 printf("nolog\n");
99 break;
100 case F_NOTIFY:
101 printf("notify\n");
102 break;
103 case F_NOUNSET:
104 printf("nounset\n");
105 break;
106 case F_VERBOSE:
107 printf("verbose\n");
108 break;
109 case F_VI:
110 printf("vi\n");
111 break;
112 case F_XTRACE:
113 printf("xtrace\n");
114 break;
115 case F_D_ALLEXPORT:
116 printf("d_allexport\n");
117 break;
118 case F_D_ERREXIT:
119 printf("d_errexit\n");
120 break;
121 case F_D_IGNOREEOF:
122 printf("d_ignoreeof\n");
123 break;
124 case F_D_MONITOR:
125 printf("d_monitor\n");
126 break;
127 case F_D_NOCLOBBER:
128 printf("d_noclobber\n");
129 break;
130 case F_D_NOGLOB:
131 printf("d_noglob\n");
132 break;
133 case F_D_REMEMBER:
134 printf("d_remember\n");
135 break;
136 case F_D_NOEXEC:
137 printf("d_noexec\n");
138 break;
139 case F_D_NOLOG:
140 printf("d_nolog\n");
141 break;
142 case F_D_NOTIFY:
143 printf("d_notify\n");
144 break;
145 case F_D_NOUNSET:
146 printf("d_nounset\n");
147 break;
148 case F_D_VERBOSE:
149 printf("d_verbose\n");
150 break;
151 case F_D_VI:
152 printf("d_vi\n");
153 break;
154 case F_D_XTRACE:
155 printf("d_xtrace\n");
156 break;
157 case F_CMDSTR:
158 printf("cmdstr\n");
159 break;
160 case F_CMDSTDIN:
161 printf("cmdstdin\n");
162 break;
163 case F_INTERACTIVE:
164 printf("interactive\n");
165 break;
167 l = l->next;
171 /* this function modifies the argc and argv so that when
172 * it returns, argv points to the 1st non-option and
173 * argc is the _actual_ count. We also assume that the
174 * caller decremented the argc and pointed argv to its
175 * second field before calling */
176 FlagList *parse_argv(int *argc, char *argv[])
178 int j,len;
179 char *str;
180 bool enable;
181 Flag flag;
182 FlagList *list = NULL;
184 while(*argc != 0)
186 str = argv[0];
187 len = strlen(str);
189 /* if not a flag, stop parsing flags */
190 if(str[0] != '-' && str[0] != '+')
191 break;
193 /* if its a single '-', discard and stop parsing */
194 if(str[0] == '-' && len == 1) {
195 argv += 1;
196 (*argc)--;
197 break;
200 /* if we get to this point, we can start analyzing
201 the string. First, we want to know if we enable
202 or disable: */
203 enable = str[0] == '-';
205 /* the -o <option> case is a little more complicated,
206 so let's treat it first */
207 if(str[1] == 'o') {
208 /* we are unforgiving on bad input format */
209 if(len != 2) {
210 fprintf(stderr,"ERROR: unrecognized flag: %s\n", str);
211 usage();
212 exit(1);
215 /* we need an option string */
216 if(*argc == 1) {
217 fprintf(stderr,"ERROR: option string needed for %s\n", str);
218 exit(1);
221 /* now we are sure we have one, let's jump to it */
222 (*argc)--;
223 argv += 1;
224 str = argv[0];
226 /* let's try to identify it. hold tight, it's gonna be ugly */
227 if(strcmp(str, "allexport") == 0) {
228 flag = enable ? F_ALLEXPORT : F_D_ALLEXPORT;
229 } else if(strcmp(str, "errexit") == 0) {
230 flag = enable ? F_ERREXIT : F_D_ERREXIT;
231 } else if(strcmp(str, "ignoreeof") == 0) {
232 flag = enable ? F_IGNOREEOF : F_D_IGNOREEOF;
233 } else if(strcmp(str, "monitor") == 0) {
234 flag = enable ? F_MONITOR : F_D_MONITOR;
235 } else if(strcmp(str, "noclobber") == 0) {
236 flag = enable ? F_NOCLOBBER : F_D_NOCLOBBER;
237 } else if(strcmp(str, "noglob") == 0) {
238 flag = enable ? F_NOGLOB : F_D_NOGLOB;
239 } else if(strcmp(str, "noexec") == 0) {
240 flag = enable ? F_NOEXEC : F_D_NOEXEC;
241 } else if(strcmp(str, "nolog") == 0) {
242 flag = enable ? F_NOLOG : F_D_NOLOG;
243 } else if(strcmp(str, "notify") == 0) {
244 flag = enable ? F_NOTIFY : F_D_NOTIFY;
245 } else if(strcmp(str, "nounset") == 0) {
246 flag = enable ? F_NOUNSET : F_D_NOUNSET;
247 } else if(strcmp(str, "verbose") == 0) {
248 flag = enable ? F_VERBOSE : F_D_VERBOSE;
249 } else if(strcmp(str, "vi") == 0) {
250 flag = enable ? F_VI : F_D_VI;
251 } else if(strcmp(str, "xtrace") == 0) {
252 flag = enable ? F_XTRACE : F_D_XTRACE;
253 } else {
254 /* ohoh, bad input! */
255 fprintf(stderr, "ERROR: invalid option string: %s\n", str);
256 exit(1);
259 /* well, that wasn't fun. lets add the flag to list of known flag
260 and move on */
261 list = cons_flag(flag,list);
262 (*argc)--;
263 argv += 1;
264 continue;
267 /* if we get here, we are looking for single character options.
268 we loop over all characters in the string. */
269 for(j = 1; j < len; j++)
271 /* try to identify char at position */
272 switch(str[j]) {
273 case 'a':
274 flag = enable ? F_ALLEXPORT : F_D_ALLEXPORT;
275 break;
276 case 'e':
277 flag = enable ? F_ERREXIT : F_D_ERREXIT;
278 break;
279 case 'm':
280 flag = enable ? F_MONITOR : F_D_MONITOR;
281 break;
282 case 'C':
283 flag = enable ? F_NOCLOBBER : F_D_NOCLOBBER;
284 break;
285 case 'f':
286 flag = enable ? F_NOGLOB : F_D_NOGLOB;
287 break;
288 case 'h':
289 flag = enable ? F_REMEMBER : F_D_REMEMBER;
290 break;
291 case 'n':
292 flag = enable ? F_NOEXEC : F_D_NOEXEC;
293 break;
294 case 'b':
295 flag = enable ? F_NOTIFY : F_D_NOTIFY;
296 break;
297 case 'u':
298 flag = enable ? F_NOUNSET : F_D_NOUNSET;
299 break;
300 case 'v':
301 flag = enable ? F_VERBOSE : F_D_VERBOSE;
302 break;
303 case 'x':
304 flag = enable ? F_XTRACE : F_D_XTRACE;
305 break;
306 case 'c':
307 flag = F_CMDSTR;
308 break;
309 case 's':
310 flag = F_CMDSTDIN;
311 break;
312 case 'i':
313 flag = F_INTERACTIVE;
314 break;
315 default:
316 /* oops, bad input! */
317 fprintf(stderr,"ERROR: unrecognized flag: %c\n", str[j]);
318 usage();
319 exit(1);
322 /* add it to the list of known flags */
323 list = cons_flag(flag,list);
326 /* we successfuly parsed the whole string! lets
327 decrement the argc, point the argv to the next
328 string and try again. */
329 (*argc)--;
330 argv += 1;
333 /* at last, we are done! */
334 return list;
338 /* print usage text */
339 void usage(void)
341 printf("usage: %s [-/+ abCefhimnuvz][-/+ o <option>] [<non-options>]\n"
342 "where <non-options> can be:\n"
343 " <command file> [<argument>...]\n"
344 " -c <command string> [<command name> [argument...]]\n"
345 " -s [argument]\n", progname);
348 int main(int argc, char *argv[])
350 /* Welcome to main! */
351 FlagList *flags;
353 /* our first task is parsing the argv.
354 the function parse_argv() requires us
355 to decrement argc and point argv to
356 its second field, so lets do that */
357 argc--;
358 argv += 1;
359 flags = parse_argv(&argc, argv);
361 print_flaglist(flags);
363 return 0;