|
|
1.1 root 1: /*
2: This 'C' module may be included prior to the ``main'' programs on VMS in
3: order to allow 'C' arguments to contain redirection symbols (<,>,>>) and
4: VMS wild cards (*,% ...], [-). By including this module, two programs
5: redirect() and expand() are run prior to turning control over to
6: your main() entry point.
7:
8: /*
9: redirect-- Gregg Townsend circa 1983,
10: expand-- John Campbell circa 1987
11:
12: This code is public domain, others may use it freely. Credit, however, to
13: Gregg Townsend (who wrote ``redirect()'') and John Campbell (who followed
14: with ``expand()'') would be appreciated. If someone writes the next
15: logical successor ``pipe()'', please email a copy to
16: ...!arizona!naucse!jdc (John Campbell) :-).
17: */
18:
19: #include <rms> /* No easy way to tell if this has already been included. */
20: #ifndef ERANGE /* Include only if missing. */
21: /* #include <stdlib> causes lots of warnings. */
22: #endif
23: #include <stdio.h> /* Stdio.h won't include itself twice. */
24:
25: /* Expansion of wild cards is done using RMS. */
26: typedef struct NAMBLK { struct NAM nam; /* VMS nam block structure */
27: char es[NAM$C_MAXRSS], /* Extended string */
28: rs[NAM$C_MAXRSS]; /* Resultant string */
29: };
30:
31: #define ErrorExit 2
32:
33: /* Allow the user to override _N_FARGS or _E_FLAG if they wish. */
34: #ifndef _N_FARGS
35: #define _N_FARGS 0
36: #endif
37: #ifndef _E_FLAG
38: #define _E_FLAG 2
39: #endif
40: /*
41: Since the following will possibly be included in a single module, try
42: hard to avoid name conflicts. (Just being static doesn't cut it if
43: compiled in the same module.)
44: */
45: #define redirect _r_edirect
46: #define filearg _f_ilearg
47: #define expand _e_xpand
48: #define wild_found _w_ild_found
49: #define wild_expand _w_ild_expand
50:
51: main(argc, argv, envp)
52: int argc;
53: char *argv[], *envp[];
54: {
55: char **expand();
56:
57: redirect (&argc, argv, _N_FARGS);
58: argv = expand (&argc, argv, _E_FLAG);
59:
60: /* Make the user's main entry point this routine's entry point. */
61: #define main _user_main
62: _user_main (argc, argv, envp);
63: }
64:
65: /*
66: * redirect(&argc,argv,nfargs) - redirect standard I/O
67: * int *argc number of command arguments (from call to main)
68: * char *argv[] command argument list (from call to main)
69: * int nfargs number of filename arguments to process
70: *
71: * argc and argv will be adjusted by redirect.
72: *
73: * redirect processes a program's command argument list and handles redirection
74: * of stdin, and stdout. Any arguments which redirect I/O are removed from the
75: * argument list, and argc is adjusted accordingly. redirect would typically be
76: * called as the first statement in the main program.
77: *
78: * Files are redirected based on syntax or position of command arguments.
79: * Arguments of the following forms always redirect a file:
80: *
81: * <file redirects standard input to read the given file
82: * >file redirects standard output to write to the given file
83: * >>file redirects standard output to append to the given file
84: *
85: * It is often useful to allow alternate input and output files as the
86: * first two command arguments without requiring the <file and >file
87: * syntax. If the nfargs argument to redirect is 2 or more then the
88: * first two command arguments, if supplied, will be interpreted in this
89: * manner: the first argument replaces stdin and the second stdout.
90: * A filename of "-" may be specified to occupy a position without
91: * performing any redirection.
92: *
93: * If nfargs is 1, only the first argument will be considered and will
94: * replace standard input if given. Any arguments processed by setting
95: * nfargs > 0 will be removed from the argument list, and again argc will
96: * be adjusted. Positional redirection follows syntax-specified
97: * redirection and therefore overrides it.
98: *
99: */
100:
101:
102: redirect(argc,argv,nfargs)
103: int *argc, nfargs;
104: char *argv[];
105: {
106: int i;
107:
108: i = 1;
109: while (i < *argc) { /* for every command argument... */
110: switch (argv[i][0]) { /* check first character */
111: case '<': /* <file redirects stdin */
112: filearg(argc,argv,i,1,stdin,"r");
113: break;
114: case '>': /* >file or >>file redirects stdout */
115: if (argv[i][1] == '>')
116: filearg(argc,argv,i,2,stdout,"a");
117: else
118: filearg(argc,argv,i,1,stdout,"w");
119: break;
120: default: /* not recognized, go on to next arg */
121: i++;
122: }
123: }
124: if (nfargs >= 1 && *argc > 1) /* if positional redirection & 1 arg */
125: filearg(argc,argv,1,0,stdin,"r"); /* then redirect stdin */
126: if (nfargs >= 2 && *argc > 1) /* likewise for 2nd arg if wanted */
127: filearg(argc,argv,1,0,stdout,"w");/* redirect stdout */
128: }
129:
130:
131:
132: /* filearg(&argc,argv,n,i,fp,mode) - redirect and remove file argument
133: * int *argc number of command arguments (from call to main)
134: * char *argv[] command argument list (from call to main)
135: * int n argv entry to use as file name and then delete
136: * int i first character of file name to use (skip '<' etc.)
137: * FILE *fp file pointer for file to reopen (typically stdin etc.)
138: * char mode[] file access mode (see freopen spec)
139: */
140:
141: filearg(argc,argv,n,i,fp,mode)
142: int *argc, n, i;
143: char *argv[], mode[];
144: FILE *fp;
145: {
146: if (strcmp(argv[n]+i,"-")) /* alter file if arg not "-" */
147: fp = freopen(argv[n]+i,mode,fp);
148: if (fp == NULL) { /* abort on error */
149: fprintf(stderr,"%%can't open %s",argv[n]+i);
150: exit(ErrorExit);
151: }
152: for ( ; n < *argc; n++) /* move down following arguments */
153: argv[n] = argv[n+1];
154: *argc = *argc - 1; /* decrement argument count */
155: }
156:
157: /* EXPAND code. */
158:
159: /* Global prototype. */
160: char **expand (int *argc, const char *argv[], const int flag);
161: /*-
162: ``expand()'' is a routine to expand wild-cards to file specifications.
163: This routine is often used in conjunction with ``redirect()'' to provide
164: both wild card expansion and standard file redirection prior to doing
165: any real work in a 'C' program.
166:
167: Normal usage is to include the following line prior to using argc or
168: argv in main():
169:
170: argv = expand (&argc, argv, 0);
171:
172: ``argc'' will be adjusted by ``expand()'', the return value from expand
173: will replace ``argv''.
174:
175: ``expand()'' processes a program's command argument list and expands any
176: wild cards into zero or more argv entries. Only arguments that posses VMS
177: wild-cards are expanded. Wild cards searched for are ``*'', ``%'',
178: ``...]'', and ``[-''. If the wild-card is found inside a single or double
179: quote ("*" or '%') then they are not counted as wild-cards. Be aware that
180: the expansion of a VMS wild card will match all VMS files, including
181: directory files (".DIR;1").
182:
183: NOTE: The use of quotes in VMS requires thinking about how the CLI expands
184: things before handing the argument line over to your program. Do not
185: expect "*" to avoid expansion, use """*""" instead. Likewise, expression
186: substitution precludes the use of (') to quote wild cards:
187: $ A := HELLO
188: $ ECHO 'a' ! 'C' program that calls ``expand()''
189: hello
190: The easiest way to escape a wild-card may be "'*'". The point is that
191: ``expand()'' will only recognize quotes passed into main().
192:
193: ``expand()'' references the VMS runtime routines, you will need to
194: link with the 'C' RTL whenever expand is used.
195:
196: Parameters:
197:
198: argc: Pointer to the number of command arguments (from main),
199: the contents of this parameter are modified.
200:
201: argv: Pointer to the initial command argument list (from main),
202: the contents are copied into a new array which is returned
203: from this routine.
204:
205: flag: Flag indicating how to expand wild-cards:
206: 0 - Complete file name expansion
207: 1 - only file name (no directory or version).
208: 2 - directory info and file name (no version).
209: 3 - file name and version info (no directory).
210: -*/
211:
212: /* Local prototypes. */
213: int wild_found (char *string);
214: char **wild_expand (const char *string, char **argv, int *argc,
215: int extra, int flag);
216: /*
217: General note: removing the prototyping and const keywords should
218: allow this code to compile with VMS 'C' compilers prior to version
219: 2.3-024.
220: */
221:
222:
223: char **expand (int *argc, char *argv[], int flag)
224: /*
225: Routine to expand all the arguments from main(argc,argv). The
226: return value is a pointer to a new (expanded) argv array.
227:
228: Parameters:
229:
230: argc: Pointer to the number of command arguments (from main),
231: the contents of this parameter are modified.
232:
233: argv: Pointer to the initial command argument list (from main),
234: the contents are copied into a new array which is returned
235: from this routine.
236:
237: flag: Flag indicating how to expand wild-card:
238: 0 - Complete file name expansion
239: 1 - only file name (no directory or version).
240: 2 - directory info and file name (no version).
241: 3 - file name and version info (no directory).
242: */
243: {
244: int i, nargc;
245: char **nargv, **wild_expand();
246: char *start, *end;
247:
248: /* Get an initial amount of memory for the master nargv array. */
249: if ((nargv = (char **)malloc ((*argc+1) * sizeof (char *))) == NULL) {
250: fprintf (stderr, "Not enough memory to expand argument list\n");
251: exit (ErrorExit);
252: }
253:
254: /*
255: Fix the command string so that it only has the name and not the path of
256: the function (more in line with what unix reports with argv[0]
257: */
258: start = argv[0];
259: end = argv[0] + strlen (argv[0]);
260: while (start < end) {
261: /* Scan from the back for the first '.' and replace it with a '\0' */
262: if (*end == '.') *end = '\0';
263: /* And trim off path if it is found. */
264: if (*end == ']') {
265: end++;
266: break;
267: }
268: --end;
269: }
270: nargv[0] = end;
271:
272: /* Copy each argument, expanding those that have wild characters. */
273: for (nargc = i = 1; i < *argc; i++) {
274: if (wild_found(argv[i]))
275: nargv = wild_expand(argv[i], nargv, &nargc, *argc-i, flag);
276: else
277: nargv[nargc++] = argv[i];
278: }
279: *argc = nargc;
280: nargv[nargc] = NULL; /* realloc always 0 fills, but... */
281:
282: return nargv;
283: }
284:
285:
286: static int wild_found (char *string)
287: /*
288: Routine to search the given string for a VMS wild-card pattern.
289: Returns 1 if "*", "%", "[-", or "...]" is found. (This may not
290: be all VMS wild-cards but it is enough for now--anyone that wants
291: to recognize others can change this code.)
292:
293: Parameter:
294:
295: string: '\0' terminated character array.
296: */
297: {
298: int state = 0;
299:
300: /*
301: State of 0 is "rest" state. State 1 on our way to [-, states 2-4
302: on our way to ...], negative states indicate the two quotes (' -10,
303: " -1).
304: */
305: for ( ;*string; string++) {
306: switch (*string) {
307: case '*':
308: case '%':
309: if (state >= 0)
310: return 1; /* Unquoted % or * found. */
311: break;
312: case '[':
313: if (state >= 0)
314: state = 1;
315: break;
316: case ']':
317: if (state == 4)
318: return 1; /* Unquoted ...] found. */
319: else if (state >= 0)
320: state = 0;
321: break;
322: case '-':
323: if (state == 1)
324: return 1; /* Unquoted [- found. */
325: else if (state >= 0)
326: state = 0;
327: break;
328: case '.':
329: if (state == 1 || state == 0)
330: state = 2; /* First '.' */
331: else if (state > 1 && state < 5)
332: state++; /* ... == states 2, 3, 4 */
333: else if (state >= 0)
334: state = 0;
335: break;
336: case '\'':
337: if (state <= -10)
338: state += 10; /* One ', possibly one " also */
339: else if (state < 0)
340: state -= 10; /* 0 ', possibly one " */
341: else
342: state = -10; /* No ' or " prior to this ' */
343: break;
344: case '"':
345: if (state == -11)
346: state = -10; /* Both " and ' prior to this. */
347: else if (state == -10)
348: state = -11; /* A ' prior to this. */
349: else if (state == -1)
350: state = 0; /* A " prior to this. */
351: else
352: state = -1; /* No ' or " prior to this " */
353: break;
354: }
355: }
356: return 0;
357: }
358:
359:
360: static char **wild_expand (const char *wild, char **argv,
361: int *argc, int extra, int flag)
362: /*
363: Routine to expand wild into new arguments appended to the end
364: of argv[*argc]. This routine must realloc in order to make room
365: for the individual arguments and malloc for enough space for each
366: of the arguments. The return value is a new **argv.
367:
368: Parameters:
369:
370: wild: '\0' terminated string that needs to be expanded.
371:
372: argv: initial starting address of the argv array.
373:
374: argc: pointer to an integer that tells the current end of the
375: argument list.
376:
377: extra: The number of extra pointers that the returned argv
378: must have available for future assignments.
379:
380: flag: Flag indicating how to expand wild-card:
381: 0 - Complete file name expansion
382: 1 - only file name (no directory or version).
383: 2 - directory info and file name (no version)
384: 3 - file name and version info (no directory).
385: */
386: {
387: int more_to_go = 1, err, length, status, len_wild;
388: char *namptr; /* , *strncpy(); Picky, but bothers other main programs */
389: struct FAB fab_blk;
390: struct NAMBLK nam_blk;
391:
392: len_wild = strlen(wild);
393:
394: /* Initialize all the fab and nam fields needed for parse and search */
395:
396: fab_blk = cc$rms_fab; /* Initialize FAB structure */
397:
398: nam_blk.nam = cc$rms_nam; /* Initialize NAM structure */
399: fab_blk.fab$l_dna = ".*"; /* Default file specif. */
400: fab_blk.fab$b_dns = 2; /* Length of default spec. */
401: fab_blk.fab$l_nam = &nam_blk.nam; /* Set address of NAM in FAB*/
402: nam_blk.nam.nam$b_ess = NAM$C_MAXRSS; /* Set extended string size*/
403: nam_blk.nam.nam$l_esa = &nam_blk.es; /* and address */
404: nam_blk.nam.nam$b_rss = NAM$C_MAXRSS; /* Set resultant string size*/
405: nam_blk.nam.nam$l_rsa = &nam_blk.rs; /* and address */
406: nam_blk.nam.nam$l_rlf = NULL; /* No related file address */
407:
408: fab_blk.fab$l_fna = wild; /* Address of file name string */
409: fab_blk.fab$b_fns = len_wild; /* Length of file name string */
410:
411: /* Prepare to enter the search loop, parse fab. */
412: err = SYS$PARSE (&fab_blk);
413:
414: /* Catch the directory not found error and return no files found. */
415: if (err != RMS$_NORMAL)
416: exit(err);
417:
418: while (more_to_go) {
419: err = SYS$SEARCH (&fab_blk);
420: if (err == RMS$_NMF || err == RMS$_FNF)
421: more_to_go = 0; /* Done, no more files found */
422: else if (err != RMS$_NORMAL)
423: exit (err);
424: else {
425: /* Count that we now have this many arguments. */
426: (*argc)++;
427:
428: /* Make sure there is room for a new pointer. */
429: if ((argv = realloc (argv, (*argc + extra)*sizeof(char *))) == NULL) {
430: fprintf (stderr, "Not enough memory to expand argument list\n");
431: exit(ErrorExit);
432: }
433:
434: /* Move the right name into the list. */
435: switch (flag) {
436: case 0: /* Complete file name */
437: length = nam_blk.nam.nam$b_rsl;
438: namptr = &nam_blk.rs;
439: break;
440: case 1: /* File name only (no directory or version). */
441: length = nam_blk.nam.nam$b_name + nam_blk.nam.nam$b_type;
442: namptr = nam_blk.nam.nam$l_name;
443: break;
444: case 2: /* directory and file name (no version) */
445: length = nam_blk.nam.nam$b_rsl - nam_blk.nam.nam$b_ver;
446: namptr = &nam_blk.rs;
447: break;
448: case 3: /* File name and version (no directory). */
449: length = nam_blk.nam.nam$b_name +
450: nam_blk.nam.nam$b_type +
451: nam_blk.nam.nam$b_ver;
452: namptr = nam_blk.nam.nam$l_name;
453: break;
454: default:
455: fprintf (stderr, "illegal flag used in VMS expand call\n");
456: exit (ErrorExit);
457: }
458: /* Copy the requested string into the argument array. */
459: if ((argv[*argc-1] = malloc (length+1)) == NULL) {
460: fprintf (stderr, "Not enough memory to expand argument list\n");
461: exit (ErrorExit);
462: }
463: (void )strncpy (argv[*argc-1], namptr, length);
464: argv[*argc-1][length] = '\0';
465: }
466: }
467: return (argv);
468: }
469:
470: /* Remove all the defines that might affect the user's code. */
471:
472: #undef redirect
473: #undef filearg
474: #undef expand
475: #undef wild_found
476: #undef wild_expand
477:
478: #ifdef __TST_ECHO /* Example code using expand(). */
479:
480: # ifndef __FILE
481: #include stdio
482: #endif
483:
484: main(argc, argv)
485: int argc;
486: char *argv[];
487: /*
488: This main program allows you to run experiments with ``expand()''.
489: Try $ echo *.*, $ echo -f1 [-...]*.*, $ echo -f[0-3] *.*.
490: Questions about using "%", "\", etc. may be answered by testing
491: with this version of echo.
492:
493: To use this, of course, you need to link directly with expand--
494: avoiding the substitution of main with _user_main above.
495: */
496: {
497: int i, flag=0;
498: char **expand();
499:
500: for(i=1; i<argc; i++)
501: printf("%s %c", argv[i], (i<argc-1) ? ' ':'\n');
502:
503: if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'f')
504: flag = atoi (&argv[1][2]);
505:
506: argv = expand (&argc, argv, flag);
507:
508: printf ("\n\n");
509: for(i=1; i<argc; i++)
510: printf("%s %c", argv[i], flag%2 == 0 ? '\n' : i%4 == 0 ? '\n':'\t');
511:
512: }
513: #endif /* __TST_ECHO */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.