Merge pull request #11 from esorton/bugfix/add-constexpr-keyword-to-arduino-ctags
[arduino-ctags.git] / argproc.c
blobe06182f80c6bbfe303e9a8d1ddc091ac986851eb
1 /*
2 * $Id: argproc.c 443 2006-05-30 04:37:13Z darren $
4 * Copyright (c) 1989, Mark Pizzolato (mark@infopiz.uucp)
6 * This source code is released for free distribution under the terms of the
7 * GNU General Public License.
9 * Provided by Stephen P. Wall <swall@redcom.com>
10 * Extracted from the VMS port of GNU patch-2.1.
12 * This module provides redirection support for the VAX DECC port of
13 * Exuberant Ctags.
16 * @(#)argproc.c 1.0 89/02/01 Mark Pizzolato (mark@infopiz.uucp)
19 #ifndef lint
20 char argproc_version [] = "@(#)argproc.c VMS uucp Version infopiz-1.0";
21 #endif
23 #include <ctype.h>
24 #include <descrip.h>
25 #include <dvidef.h>
26 #include <errno.h>
27 #include <iodef.h>
28 #include <lib$routines.h>
29 #include <starlet.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <syidef.h> /* System Information Definitions */
35 #define EXIT_OK 1 /* image exit code */
36 #define EXIT_ERR 0x10000000 /* image exit code */
39 * getredirection() is intended to aid in porting C programs
40 * to VMS (Vax-11 C) which does not support '>' and '<'
41 * I/O redirection, along with a command line pipe mechanism
42 * using the '|' AND background command execution '&'.
43 * The piping mechanism will probably work with almost any 'filter' type
44 * of program. With suitable modification, it may useful for other
45 * portability problems as well.
47 * Author: Mark Pizzolato mark@infopiz.UUCP
48 * Mods: Steve Wall Don't return a full path unless the
49 * original filename included a path.
51 struct list_item
53 struct list_item *next;
54 char *value;
57 static expand_wild_cards ();
58 static char *pipe_and_fork ();
60 int
61 getredirection (ac, av)
62 int *ac;
63 char ***av;
65 * Process vms redirection arg's. Exit if any error is seen.
66 * If getredirection() processes an argument, it is erased
67 * from the vector. getredirection () returns a new argc and argv value.
68 * In the event that a background command is requested (by a trailing "&"),
69 * this routine creates a background subprocess, and simply exits the program.
71 * Warning: do not try to simplify the code for vms. The code
72 * presupposes that getredirection() is called before any data is
73 * read from stdin or written to stdout.
75 * Normal usage is as follows:
77 * main (argc, argv)
78 * int argc;
79 * char *argv [];
80 * {
81 * getredirection (&argc, &argv);
82 * }
85 int argc = *ac; /* Argument Count */
86 char **argv = *av; /* Argument Vector */
87 char *ap; /* Argument pointer */
88 int j; /* argv [] index */
89 extern int errno; /* Last vms i/o error */
90 int item_count = 0; /* Count of Items in List */
91 struct list_item *list_head = 0; /* First Item in List */
92 struct list_item *list_tail; /* Last Item in List */
93 char *in = NULL; /* Input File Name */
94 char *out = NULL; /* Output File Name */
95 char *outmode = "w"; /* Mode to Open Output File */
96 int cmargc = 0; /* Piped Command Arg Count */
97 char **cmargv = NULL;/* Piped Command Arg Vector */
100 * First handle the case where the last thing on the line ends with
101 * a '&'. This indicates the desire for the command to be run in a
102 * subprocess, so we satisfy that desire.
105 extern background_process ();
106 ap = argv [argc-1];
107 if (0 == strcmp ("&", ap))
108 exit (background_process (--argc, argv));
109 if ('&' == ap [strlen (ap)-1])
111 ap [strlen (ap)-1] = '\0';
112 exit (background_process (argc, argv));
116 * Now we handle the general redirection cases that involve '>', '>>',
117 * '<', and pipes '|'.
119 for (j = 0; j < argc; ++j)
121 if (0 == strcmp ("<", argv [j]))
123 if (j+1 >= argc)
125 errno = EINVAL;
126 perror ("No input file");
127 exit (EXIT_ERR);
129 in = argv [++j];
130 continue;
132 if ('<' == *(ap = argv [j]))
134 in = 1 + ap;
135 continue;
137 if (0 == strcmp (">", ap))
139 if (j+1 >= argc)
141 errno = EINVAL;
142 perror ("No output file");
143 exit (EXIT_ERR);
145 out = argv [++j];
146 continue;
148 if ('>' == *ap)
150 if ('>' == ap [1])
152 outmode = "a";
153 if ('\0' == ap [2])
154 out = argv [++j];
155 else
156 out = 2 + ap;
158 else
159 out = 1 + ap;
160 continue;
162 if (0 == strcmp ("|", argv [j]))
164 if (j+1 >= argc)
166 errno = EPIPE;
167 perror ("No command to Pipe to");
168 exit (EXIT_ERR);
170 cmargc = argc- (j+1);
171 cmargv = &argv [j+1];
172 argc = j;
173 continue;
175 if ('|' == *(ap = argv [j]))
177 ++argv [j];
178 cmargc = argc-j;
179 cmargv = &argv [j];
180 argc = j;
181 continue;
183 expand_wild_cards (ap, &list_head, &list_tail, &item_count);
186 * Allocate and fill in the new argument vector, Some Unix's terminate
187 * the list with an extra null pointer.
189 argv = *av = calloc (item_count+1, sizeof (char *));
190 for (j = 0; j < item_count; ++j, list_head = list_head->next)
191 argv [j] = list_head->value;
192 *ac = item_count;
193 if (cmargv != NULL)
195 char subcmd [1024];
197 if (out != NULL)
199 errno = EINVAL;
200 perror ("Invalid '|' and '>' specified");
201 exit (EXIT_ERR);
203 strcpy (subcmd, cmargv [0]);
204 for (j = 1; j < cmargc; ++j)
206 strcat (subcmd, " \"");
207 strcat (subcmd, cmargv [j]);
208 strcat (subcmd, "\"");
210 out = pipe_and_fork (subcmd);
212 if ((in != NULL) && (NULL == freopen (in, "r", stdin, "mbc=32", "mbf=2")))
214 perror (in); /* Can't find file */
215 exit (EXIT_ERR); /* Is a fatal error */
217 if ((out != NULL) && (NULL == freopen (out, outmode, stdout, "mbc=32", "mbf=2")))
219 perror (ap); /* Error, can't write or append */
220 exit (EXIT_ERR); /* Is a fatal error */
222 #ifdef DEBUG
223 fprintf (stderr, "Arglist:\n");
224 for (j = 0; j < *ac; ++j)
225 fprintf (stderr, "argv[%d] = '%s'\n", j, argv [j]);
226 #endif
227 return 0;
230 static add_item (head, tail, value, count)
231 struct list_item **head;
232 struct list_item **tail;
233 char *value;
234 int *count;
236 if (*head == 0)
238 if (NULL == (*head = calloc (1, sizeof (**head))))
240 errno = ENOMEM;
241 perror ("");
242 exit (EXIT_ERR);
244 *tail = *head;
246 else
247 if (NULL == ((*tail)->next = calloc (1, sizeof (**head))))
249 errno = ENOMEM;
250 perror ("");
251 exit (EXIT_ERR);
253 else
254 *tail = (*tail)->next;
255 (*tail)->value = value;
256 ++ (*count);
259 static expand_wild_cards (item, head, tail, count)
260 char *item;
261 struct list_item **head;
262 struct list_item **tail;
263 int *count;
265 int expcount = 0;
266 int context = 0;
267 int status;
268 int status_value;
269 char *had_version;
270 int had_path;
271 $DESCRIPTOR (filespec, item);
272 /*$DESCRIPTOR (defaultspec, "SYS$DISK:[]*.*;");*/
273 $DESCRIPTOR (defaultspec, "");
274 $DESCRIPTOR (resultspec, "");
276 if (strcspn (item, "*%") == strlen (item))
278 add_item (head, tail, item, count);
279 return;
281 resultspec.dsc$b_dtype = DSC$K_DTYPE_T;
282 resultspec.dsc$b_class = DSC$K_CLASS_D;
283 resultspec.dsc$a_pointer = NULL;
284 filespec.dsc$w_length = strlen (item);
286 * Only return version specs, if the caller specified a version
288 had_version = strchr (item, ';');
290 * Only return full path if the caller specified a path
292 had_path = (strchr (item, ']') || strchr (item, ':'));
293 while (1 == (1&lib$find_file (&filespec, &resultspec, &context,
294 &defaultspec, 0, &status_value, &0)))
296 char *string;
297 char *c;
299 if (NULL == (string = calloc (1, resultspec.dsc$w_length+1)))
301 errno = ENOMEM;
302 perror ("");
303 exit (EXIT_ERR);
305 strncpy (string, resultspec.dsc$a_pointer, resultspec.dsc$w_length);
306 string [resultspec.dsc$w_length] = '\0';
307 if (NULL == had_version)
308 *((char *) strrchr (string, ';')) = '\0';
309 if (!had_path) {
310 char *s = strrchr (string, ']');
311 if ( s == NULL ) s = strrchr (string, ':');
312 if ( s != NULL ) strcpy (string, s+1);
315 * Be consistent with what the C RTL has already done to the rest of
316 * the argv items and lowercase all of these names.
318 for (c = string; *c; ++c)
319 if (isupper (*c))
320 *c = tolower (*c);
321 add_item (head, tail, string, count);
322 ++expcount;
324 if (expcount == 0)
325 add_item (head, tail, item, count);
326 lib$sfree1_dd (&resultspec);
327 lib$find_file_end (&context);
330 static int child_st [2]; /* Event Flag set when child process completes */
332 static short child_chan;/* I/O Channel for Pipe Mailbox */
334 static exit_handler (status)
335 int *status;
337 short iosb [4];
339 if (0 == child_st [0])
341 #ifdef DEBUG
342 fprintf (stderr, "Waiting for Child Process to Finnish . . .\n");
343 #endif
344 sys$qiow (0, child_chan, IO$_WRITEOF, iosb, 0, 0, 0, 0, 0, 0, 0, 0);
345 sys$dassgn (child_chan);
346 fclose (stdout);
347 sys$synch (0, child_st);
352 static sig_child (chan)
353 int chan;
355 #ifdef DEBUG
356 fprintf (stderr, "Child Completion AST\n");
357 #endif
358 if (child_st [0] == 0)
359 child_st [0] = 1;
362 static struct exit_control_block
364 struct exit_control_block *flink;
365 int (*exit_routine) ();
366 int arg_count;
367 int *status_address;
368 int exit_status;
369 } exit_block =
372 exit_handler,
374 &exit_block.exit_status,
378 static char *pipe_and_fork (cmd)
379 char *cmd;
381 $DESCRIPTOR (cmddsc, cmd);
382 static char mbxname [64];
383 $DESCRIPTOR (mbxdsc, mbxname);
384 short iosb [4];
385 int status;
386 int pid;
387 struct
389 short dna_buflen;
390 short dna_itmcod;
391 char *dna_buffer;
392 unsigned short *dna_retlen;
393 int listend;
394 } itmlst =
396 sizeof (mbxname),
397 DVI$_DEVNAM,
398 mbxname,
399 &mbxdsc.dsc$w_length,
402 int mbxsize;
403 struct
405 short mbf_buflen;
406 short mbf_itmcod;
407 int *mbf_maxbuf;
408 unsigned short *mbf_retlen;
409 int listend;
410 } syiitmlst =
412 sizeof (mbxsize),
413 SYI$_MAXBUF,
414 &mbxsize,
419 cmddsc.dsc$w_length = strlen (cmd);
421 * Get the SYSGEN parameter MAXBUF, and the smaller of it and 2048 as
422 * the size of the 'pipe' mailbox.
424 if (1 == (1& (vaxc$errno = sys$getsyiw (0, 0, 0, &syiitmlst, iosb, 0, 0, 0))))
425 vaxc$errno = iosb [0];
426 if (0 == (1&vaxc$errno))
428 errno = EVMSERR;
429 perror ("Can't get SYSGEN parameter value for MAXBUF");
430 exit (EXIT_ERR);
432 if (mbxsize > 2048)
433 mbxsize = 2048;
434 if (0 == (1& (vaxc$errno = sys$crembx (0, &child_chan, mbxsize, mbxsize, 0, 0, 0))))
436 errno = EVMSERR;
437 perror ("Can't create pipe mailbox");
438 exit (EXIT_ERR);
440 if (1 == (1& (vaxc$errno = sys$getdviw (0, child_chan, 0, &itmlst, iosb,
441 0, 0, 0))))
442 vaxc$errno = iosb [0];
443 if (0 == (1&vaxc$errno))
445 errno = EVMSERR;
446 perror ("Can't get pipe mailbox device name");
447 exit (EXIT_ERR);
449 mbxname [mbxdsc.dsc$w_length] = '\0';
450 #ifdef DEBUG
451 fprintf (stderr, "Pipe Mailbox Name = '%s'\n", mbxname);
452 #endif
453 if (0 == (1& (vaxc$errno = lib$spawn (&cmddsc, &mbxdsc, 0, &1,
454 0, &pid, child_st, &0, sig_child,
455 &child_chan))))
457 errno = EVMSERR;
458 perror ("Can't spawn subprocess");
459 exit (EXIT_ERR);
461 #ifdef DEBUG
462 fprintf (stderr, "Subprocess's Pid = %08X\n", pid);
463 #endif
464 sys$dclexh (&exit_block);
465 return (mbxname);
468 background_process (argc, argv)
469 int argc;
470 char **argv;
472 char command [2048] = "$";
473 $DESCRIPTOR (value, command);
474 $DESCRIPTOR (cmd, "BACKGROUND$COMMAND");
475 $DESCRIPTOR (null, "NLA0:");
476 int pid;
478 strcat (command, argv [0]);
479 while (--argc)
481 strcat (command, " \"");
482 strcat (command, *(++argv));
483 strcat (command, "\"");
485 value.dsc$w_length = strlen (command);
486 if (0 == (1& (vaxc$errno = lib$set_symbol (&cmd, &value))))
488 errno = EVMSERR;
489 perror ("Can't create symbol for subprocess command");
490 exit (EXIT_ERR);
492 if (0 == (1& (vaxc$errno = lib$spawn (&cmd, &null, 0, &17, 0, &pid))))
494 errno = EVMSERR;
495 perror ("Can't spawn subprocess");
496 exit (EXIT_ERR);
498 #ifdef DEBUG
499 fprintf (stderr, "%s\n", command);
500 #endif
501 fprintf (stderr, "%08X\n", pid);
502 return (EXIT_OK);
505 /* vi:set tabstop=4 shiftwidth=4: */