~ubuntu-branches/ubuntu/trusty/exuberant-ctags/trusty

1 by Colin Watson
Import upstream version 5.5.4
1
/*
1.1.2 by Colin Watson
Import upstream version 5.7
2
*   $Id: argproc.c 443 2006-05-30 04:37:13Z darren $
1 by Colin Watson
Import upstream version 5.5.4
3
*
4
*   Copyright (c) 1989, Mark Pizzolato (mark@infopiz.uucp)
5
*
6
*   This source code is released for free distribution under the terms of the
7
*   GNU General Public License.
8
*
9
*   Provided by Stephen P. Wall <swall@redcom.com>
10
*   Extracted from the VMS port of GNU patch-2.1.
11
*
12
*   This module provides redirection support for the VAX DECC port of
13
*   Exuberant Ctags.
14
*/
15
/*
1.1.1 by Colin Watson
Import upstream version 5.6
16
 * @(#)argproc.c 1.0 89/02/01			Mark Pizzolato (mark@infopiz.uucp)
1 by Colin Watson
Import upstream version 5.5.4
17
 */
18
19
#ifndef lint
20
char argproc_version [] = "@(#)argproc.c VMS uucp Version infopiz-1.0";
21
#endif
22
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>
1.1.1 by Colin Watson
Import upstream version 5.6
33
#include <syidef.h>				/* System Information Definitions		*/
1 by Colin Watson
Import upstream version 5.5.4
34
1.1.1 by Colin Watson
Import upstream version 5.6
35
#define EXIT_OK 1				/* image exit code */
36
#define EXIT_ERR 0x10000000		/* image exit code */
1 by Colin Watson
Import upstream version 5.5.4
37
38
/*
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.
46
 *
1.1.1 by Colin Watson
Import upstream version 5.6
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.
1 by Colin Watson
Import upstream version 5.5.4
50
 */
51
struct list_item
1.1.1 by Colin Watson
Import upstream version 5.6
52
	{
53
	struct list_item *next;
54
	char *value;
55
	};
1 by Colin Watson
Import upstream version 5.5.4
56
57
static expand_wild_cards ();
58
static char *pipe_and_fork ();
59
60
int
61
getredirection (ac, av)
1.1.1 by Colin Watson
Import upstream version 5.6
62
int				*ac;
63
char			***av;
1 by Colin Watson
Import upstream version 5.5.4
64
/*
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.
70
 *
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.
74
 *
75
 * Normal usage is as follows:
76
 *
1.1.1 by Colin Watson
Import upstream version 5.6
77
 *		main (argc, argv)
78
 *		int				argc;
79
 *		char			*argv [];
80
 *		{
81
 *				getredirection (&argc, &argv);
82
 *		}
1 by Colin Watson
Import upstream version 5.5.4
83
 */
84
{
1.1.1 by Colin Watson
Import upstream version 5.6
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 */
98
99
	/*
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.
103
	 */
104
	{
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])
110
		{
111
		ap [strlen (ap)-1] = '\0';
112
		exit (background_process (argc, argv));
113
		}
114
	}
115
	/*
116
	 * Now we handle the general redirection cases that involve '>', '>>',
117
	 * '<', and pipes '|'.
118
	 */
119
	for (j = 0; j < argc; ++j)
120
		{
121
		if (0 == strcmp ("<", argv [j]))
122
			{
123
			if (j+1 >= argc)
124
				{
125
				errno = EINVAL;
126
				perror ("No input file");
127
				exit (EXIT_ERR);
128
				}
129
			in = argv [++j];
130
			continue;
131
			}
132
		if ('<' == *(ap = argv [j]))
133
			{
134
			in = 1 + ap;
135
			continue;
136
			}
137
		if (0 == strcmp (">", ap))
138
			{
139
			if (j+1 >= argc)
140
				{
141
				errno = EINVAL;
142
				perror ("No output file");
143
				exit (EXIT_ERR);
144
				}
145
			out = argv [++j];
146
			continue;
147
			}
148
		if ('>' == *ap)
149
			{
150
			if ('>' == ap [1])
151
				{
152
				outmode = "a";
153
				if ('\0' == ap [2])
154
					out = argv [++j];
155
				else
156
					out = 2 + ap;
157
				}
158
			else
159
				out = 1 + ap;
160
			continue;
161
			}
162
		if (0 == strcmp ("|", argv [j]))
163
			{
164
			if (j+1 >= argc)
165
				{
166
				errno = EPIPE;
167
				perror ("No command to Pipe to");
168
				exit (EXIT_ERR);
169
				}
170
			cmargc = argc- (j+1);
171
			cmargv = &argv [j+1];
172
			argc = j;
173
			continue;
174
			}
175
		if ('|' == *(ap = argv [j]))
176
			{
177
			++argv [j];
178
			cmargc = argc-j;
179
			cmargv = &argv [j];
180
			argc = j;
181
			continue;
182
			}
183
		expand_wild_cards (ap, &list_head, &list_tail, &item_count);
184
		}
185
	/*
186
	 * Allocate and fill in the new argument vector, Some Unix's terminate
187
	 * the list with an extra null pointer.
188
	 */
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)
194
		{
195
		char subcmd [1024];
196
197
		if (out != NULL)
198
			{
199
			errno = EINVAL;
200
			perror ("Invalid '|' and '>' specified");
201
			exit (EXIT_ERR);
202
			}
203
		strcpy (subcmd, cmargv [0]);
204
		for (j = 1; j < cmargc; ++j)
205
			{
206
			strcat (subcmd, " \"");
207
			strcat (subcmd, cmargv [j]);
208
			strcat (subcmd, "\"");
209
			}
210
		out = pipe_and_fork (subcmd);
211
		}
212
	if ((in != NULL) && (NULL == freopen (in, "r", stdin, "mbc=32", "mbf=2")))
213
		{
214
		perror (in);			/* Can't find file				*/
215
		exit (EXIT_ERR);				/* Is a fatal error				*/
216
		}
217
	if ((out != NULL) && (NULL == freopen (out, outmode, stdout, "mbc=32", "mbf=2")))
218
		{
219
		perror (ap);			/* Error, can't write or append	*/
220
		exit (EXIT_ERR);				/* Is a fatal error				*/
221
		}
1 by Colin Watson
Import upstream version 5.5.4
222
#ifdef DEBUG
1.1.1 by Colin Watson
Import upstream version 5.6
223
	fprintf (stderr, "Arglist:\n");
224
	for (j = 0; j < *ac;  ++j)
225
		fprintf (stderr, "argv[%d] = '%s'\n", j, argv [j]);
1 by Colin Watson
Import upstream version 5.5.4
226
#endif
1.1.1 by Colin Watson
Import upstream version 5.6
227
	return 0;
1 by Colin Watson
Import upstream version 5.5.4
228
}
229
230
static add_item (head, tail, value, count)
231
struct list_item **head;
232
struct list_item **tail;
233
char *value;
234
int *count;
235
{
1.1.1 by Colin Watson
Import upstream version 5.6
236
	if (*head == 0)
237
		{
238
		if (NULL == (*head = calloc (1, sizeof (**head))))
239
			{
240
			errno = ENOMEM;
241
			perror ("");
242
			exit (EXIT_ERR);
243
			}
244
		*tail = *head;
245
		}
1 by Colin Watson
Import upstream version 5.5.4
246
	else
1.1.1 by Colin Watson
Import upstream version 5.6
247
		if (NULL == ((*tail)->next = calloc (1, sizeof (**head))))
248
			{
249
			errno = ENOMEM;
250
			perror ("");
251
			exit (EXIT_ERR);
252
			}
253
		else
254
			*tail = (*tail)->next;
255
	(*tail)->value = value;
256
	++ (*count);
1 by Colin Watson
Import upstream version 5.5.4
257
}
258
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;
264
{
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, "");
275
1.1.1 by Colin Watson
Import upstream version 5.6
276
	if (strcspn (item, "*%") == strlen (item))
277
		{
278
		add_item (head, tail, item, count);
279
		return;
280
		}
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);
285
	/*
286
	 * Only return version specs, if the caller specified a version
287
	 */
288
	had_version = strchr (item, ';');
289
	/*
290
	 * Only return full path if the caller specified a path
291
	 */
292
	had_path = (strchr (item, ']') || strchr (item, ':'));
293
	while (1 == (1&lib$find_file (&filespec, &resultspec, &context,
294
								 &defaultspec, 0, &status_value, &0)))
295
		{
296
		char *string;
297
		char *c;
1 by Colin Watson
Import upstream version 5.5.4
298
1.1.1 by Colin Watson
Import upstream version 5.6
299
		if (NULL == (string = calloc (1, resultspec.dsc$w_length+1)))
300
			{
301
			errno = ENOMEM;
302
			perror ("");
303
			exit (EXIT_ERR);
304
			}
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);
313
		}
314
		/*
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.
317
		 */
318
		for (c = string; *c; ++c)
319
			if (isupper (*c))
320
				*c = tolower (*c);
321
		add_item (head, tail, string, count);
322
		++expcount;
323
		}
324
	if (expcount == 0)
325
		add_item (head, tail, item, count);
326
	lib$sfree1_dd (&resultspec);
327
	lib$find_file_end (&context);
1 by Colin Watson
Import upstream version 5.5.4
328
}
329
1.1.1 by Colin Watson
Import upstream version 5.6
330
static int child_st [2];		/* Event Flag set when child process completes	*/
1 by Colin Watson
Import upstream version 5.5.4
331
1.1.1 by Colin Watson
Import upstream version 5.6
332
static short child_chan;/* I/O Channel for Pipe Mailbox					*/
1 by Colin Watson
Import upstream version 5.5.4
333
334
static exit_handler (status)
335
int *status;
336
{
337
short iosb [4];
338
1.1.1 by Colin Watson
Import upstream version 5.6
339
	if (0 == child_st [0])
340
		{
1 by Colin Watson
Import upstream version 5.5.4
341
#ifdef DEBUG
1.1.1 by Colin Watson
Import upstream version 5.6
342
		fprintf (stderr, "Waiting for Child Process to Finnish . . .\n");
1 by Colin Watson
Import upstream version 5.5.4
343
#endif
1.1.1 by Colin Watson
Import upstream version 5.6
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);
348
		}
1 by Colin Watson
Import upstream version 5.5.4
349
}
350
351
352
static sig_child (chan)
353
int chan;
354
{
355
#ifdef DEBUG
1.1.1 by Colin Watson
Import upstream version 5.6
356
	fprintf (stderr, "Child Completion AST\n");
1 by Colin Watson
Import upstream version 5.5.4
357
#endif
1.1.1 by Colin Watson
Import upstream version 5.6
358
	if (child_st [0] == 0)
359
		child_st [0] = 1;
1 by Colin Watson
Import upstream version 5.5.4
360
}
361
362
static struct exit_control_block
1.1.1 by Colin Watson
Import upstream version 5.6
363
	{
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 =
370
	{
371
	0,
372
	exit_handler,
373
	1,
374
	&exit_block.exit_status,
375
	0
376
	};
1 by Colin Watson
Import upstream version 5.5.4
377
378
static char *pipe_and_fork (cmd)
379
char *cmd;
380
{
1.1.1 by Colin Watson
Import upstream version 5.6
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
388
		{
389
		short dna_buflen;
390
		short dna_itmcod;
391
		char *dna_buffer;
392
		unsigned short *dna_retlen;
393
		int listend;
394
		} itmlst =
395
		{
396
		sizeof (mbxname),
397
		DVI$_DEVNAM,
398
		mbxname,
399
		&mbxdsc.dsc$w_length,
400
		0
401
		};
402
	int mbxsize;
403
	struct
404
		{
405
		short mbf_buflen;
406
		short mbf_itmcod;
407
		int *mbf_maxbuf;
408
		unsigned short *mbf_retlen;
409
		int listend;
410
		} syiitmlst =
411
		{
412
		sizeof (mbxsize),
413
		SYI$_MAXBUF,
414
		&mbxsize,
415
		0,
416
		0
417
		};
1 by Colin Watson
Import upstream version 5.5.4
418
1.1.1 by Colin Watson
Import upstream version 5.6
419
	cmddsc.dsc$w_length = strlen (cmd);
420
	/*
421
	 * Get the SYSGEN parameter MAXBUF, and the smaller of it and 2048 as
422
	 * the size of the 'pipe' mailbox.
423
	 */
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))
427
		{
428
		errno = EVMSERR;
429
		perror ("Can't get SYSGEN parameter value for MAXBUF");
430
		exit (EXIT_ERR);
431
		}
432
	if (mbxsize > 2048)
433
		mbxsize = 2048;
434
	if (0 == (1& (vaxc$errno = sys$crembx (0, &child_chan, mbxsize, mbxsize, 0, 0, 0))))
435
		{
436
		errno = EVMSERR;
437
		perror ("Can't create pipe mailbox");
438
		exit (EXIT_ERR);
439
		}
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))
444
		{
445
		errno = EVMSERR;
446
		perror ("Can't get pipe mailbox device name");
447
		exit (EXIT_ERR);
448
		}
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))))
456
		{
457
		errno = EVMSERR;
458
		perror ("Can't spawn subprocess");
459
		exit (EXIT_ERR);
460
		}
461
#ifdef DEBUG
462
	fprintf (stderr, "Subprocess's Pid = %08X\n", pid);
463
#endif
464
	sys$dclexh (&exit_block);
465
	return (mbxname);
1 by Colin Watson
Import upstream version 5.5.4
466
}
467
468
background_process (argc, argv)
469
int argc;
470
char **argv;
471
{
472
char command [2048] = "$";
473
$DESCRIPTOR (value, command);
474
$DESCRIPTOR (cmd, "BACKGROUND$COMMAND");
475
$DESCRIPTOR (null, "NLA0:");
476
int pid;
477
1.1.1 by Colin Watson
Import upstream version 5.6
478
	strcat (command, argv [0]);
479
	while (--argc)
480
		{
481
		strcat (command, " \"");
482
		strcat (command, *(++argv));
483
		strcat (command, "\"");
484
		}
485
	value.dsc$w_length = strlen (command);
486
	if (0 == (1& (vaxc$errno = lib$set_symbol (&cmd, &value))))
487
		{
488
		errno = EVMSERR;
489
		perror ("Can't create symbol for subprocess command");
490
		exit (EXIT_ERR);
491
		}
492
	if (0 == (1& (vaxc$errno = lib$spawn (&cmd, &null, 0, &17, 0, &pid))))
493
		{
494
		errno = EVMSERR;
495
		perror ("Can't spawn subprocess");
496
		exit (EXIT_ERR);
497
		}
1 by Colin Watson
Import upstream version 5.5.4
498
#ifdef DEBUG
1.1.1 by Colin Watson
Import upstream version 5.6
499
	fprintf (stderr, "%s\n", command);
1 by Colin Watson
Import upstream version 5.5.4
500
#endif
1.1.1 by Colin Watson
Import upstream version 5.6
501
	fprintf (stderr, "%08X\n", pid);
502
	return (EXIT_OK);
1 by Colin Watson
Import upstream version 5.5.4
503
}
504
1.1.1 by Colin Watson
Import upstream version 5.6
505
/* vi:set tabstop=4 shiftwidth=4: */