1 /* Some unix emulation procedures to make XV happy */
2 /* 1-NOV-1990 GJC@MITECH.COM */
3 
4 #include <stdio.h>
5 
6 #ifdef __ALPHA
7 #include <unixio.h>
8 #endif
9 
10 #include <string.h>
11 #include <descrip.h>
12 #include <rmsdef.h>
13 #include <ssdef.h>
14 #include <stat.h>
15 
16 
xv_bcmp(s1,s2,size)17 int xv_bcmp ( s1, s2, size )
18     char *s1, *s2;
19     int size;
20 {
21     int i;
22     for ( i = 0; i < size; i++ ) if ( *s1++ != *s2++ ) {
23 	if ( *(--s1) > *(--s2) ) return 1; else return -1;
24     }
25     return 0;
26 }
27 
bcopy(x,y,n)28 bcopy(x,y,n)
29      char *x,*y;
30      long n;
31 {memmove(y,x,n);}	/* reverse order of arguments */
32 
33 static char *getwd_tmp = NULL;
34 
getwd(p)35 char *getwd(p)
36      char *p;
37 {int c;
38  char *root_dir,*l2;
39  getcwd(p,512,0);	/* get current working directory in unix format*/
40 
41  root_dir = strstr ( p, "/000000" );
42  if ( root_dir != NULL ) {
43     /* trim root directory out of specification */
44     if ( (strlen(root_dir) == 7) &&
45 	 (strpbrk(p+1,"/") == root_dir) ) *root_dir = '\0';
46  }
47  /* special kludge for "/" directory */
48  if ( strcmp ( p, "/XV_Root_Device" ) == 0 ) strcpy  ( p, "/" );
49  return(p);
50 }
51 
unlink(p)52 unlink(p)
53      char *p;
54 {printf("unlink: '%s'\n",p); delete(p);}
55 
rmdir(p)56 rmdir(p)
57      char *p;
58 {printf("rmdir: Sorry, not available on VMS '%s' is unchanged!\n",p);}
59 
rindex(p,c)60 rindex(p,c)
61      char *p;
62      int c;
63 {return(strrchr(p,c));}
64 
lstat(f,st)65 int lstat(f,st)		/* fake a stat operation to return file type */
66    char *f;
67    stat_t *st;
68 {
69     char *dirext, *name;
70     int extlen;
71 
72     st->st_mode = S_IFREG;	/* default to normal file */
73     name = strrchr ( f, '/' );	/* locate rightmost slash */
74     if ( name == NULL ) name = f; else name++;
75 
76     dirext = strstr ( name, ".DIR" );
77     if ( dirext != NULL ) {
78 	/* make it an exact match */
79 	extlen = strcspn(&dirext[1],".;");
80         if ( (extlen == 0) || (extlen == 3) ) {
81 	    st->st_mode = S_IFDIR;
82 	    if ( strncmp ( name, "000000.", 7 ) == 0 ) return 0;
83 	    else return (stat ( f, st ));
84 	}
85     }
86     return 0;
87 }
88 
do_vms_wildcard(pargc,pargv)89 do_vms_wildcard(pargc,pargv)
90      int *pargc;
91      char ***pargv;
92 {int j,vsize;
93  int argc; char **argv;
94  argc = *pargc;
95  argv = *pargv;
96  *pargc = 0;
97  vsize = 3;
98  *pargv = (char **) malloc(sizeof (char *) * vsize);
99  for(j=0;j<argc;++j)
100    vms_wild_putargs(argv[j],pargc,pargv,&vsize);}
101 
vms_wild_putargs(s,pargc,pargv,pvsize)102 vms_wild_putargs(s,pargc,pargv,pvsize)
103      char *s; int *pargc; char ***pargv; int *pvsize;
104 {if ( (!strchr(s,'*')) && (!strchr(s,'%')) )
105    vms_wild_put_one(s,pargc,pargv,pvsize);
106  else
107    vms_wild_put_wild(s,pargc,pargv,pvsize);}
108 
109 
vms_wild_put_one(s,pargc,pargv,pvsize)110 vms_wild_put_one(s,pargc,pargv,pvsize)
111      char *s; int *pargc; char ***pargv; int *pvsize;
112 {int nvsize,i;
113 #ifdef __ALPHA
114 # define SHELL$TRANSLATE_VMS   decc$translate_vms
115 #else
116  char *SHELL$TRANSLATE_VMS();
117 #endif
118  char ** nargv, *uname;
119  if (*pargc == *pvsize)
120    {nvsize = 2 * *pvsize;
121     nargv = (char **) malloc(sizeof (char *) * nvsize);
122     for(i=0;i < *pargc; ++i) nargv[i] = (*pargv)[i];
123     free(*pargv);
124     *pargv = nargv;
125     *pvsize = nvsize;}
126  if ( uname = SHELL$TRANSLATE_VMS ( s ) ) {
127     /* printf("vms: '%s' -> unix: '%s'\n", s, uname ); */
128     if ( strlen(s) >= strlen(uname) ) { strcpy(s,uname); free(uname); }
129     else s = uname;  /* will lose s's old allocation */
130  }
131  (*pargv)[(*pargc)++] = s;}
132 
133 
134 set_dsc(x,buff,len)
135  struct dsc$descriptor *x;
136  char *buff;
137  int len;
138 {(*x).dsc$w_length = len;
139  (*x).dsc$a_pointer = buff;
140  (*x).dsc$b_class = DSC$K_CLASS_S;
141  (*x).dsc$b_dtype = DSC$K_DTYPE_T;
142  return(x);}
143 
144  struct dsc$descriptor *
set_dsc_cst(x,buff)145 set_dsc_cst(x,buff)
146  struct dsc$descriptor *x;
147  char *buff;
148 {return(set_dsc(x,buff,strlen(buff)));}
149 
150 
vms_wild_put_wild(s,pargc,pargv,pvsize)151 vms_wild_put_wild(s,pargc,pargv,pvsize)
152      char *s; int *pargc; char ***pargv; int *pvsize;
153 {struct dsc$descriptor fnamed,foutd,rfnamed;
154  char *ns,*p;
155  int rval;
156  long context;
157  set_dsc_cst(&rfnamed,";");
158  set_dsc_cst(&fnamed,s);
159  set_dsc(&foutd,0,0);
160  foutd.dsc$b_class = DSC$K_CLASS_D;
161  context = 0;
162  while(1)
163   {rval = lib$find_file(&fnamed,&foutd,&context,0,&rfnamed,0,0);
164    if (rval == RMS$_NMF) break;
165    if (rval == RMS$_FNF) break;
166    if (rval != RMS$_NORMAL) exit(rval);
167    ns = (char *) malloc(foutd.dsc$w_length + 1);
168    ns[foutd.dsc$w_length] = 0;
169    memcpy(ns,foutd.dsc$a_pointer,foutd.dsc$w_length);
170    /*if (p = strchr(ns,']')) ns = p+1;*/
171    /* if (p = strchr(ns,';')) *p = 0; */
172    vms_wild_put_one(ns,pargc,pargv,pvsize);}
173  if (foutd.dsc$a_pointer) lib$sfree1_dd(&foutd);
174  if (context)
175    {rval = lib$find_file_end(&context);
176     if (rval != SS$_NORMAL) exit(rval);}}
177 
178 /*
179  * Define substitue qsort for one that dec broke.  Only handle case where
180  * element size is 4 (same as integer).
181  */
182 #ifdef qsort
183 #undefine qsort
184 #endif
xv_qsort(array,size,unit,compare)185 void xv_qsort ( array, size, unit, compare )
186    int array[1000];	/* array to be sorted */
187    int size;		/* size of array to sort, should be at least 100 */
188    int unit;		/* Size of array element */
189    int compare();	/* comaparison function */
190 {
191    int stack[68], *top;	/* work array, depth of stack is bounded */
192    int start, finish, lbound, hbound, pivot, temp, i, j;
193 
194    if ( unit != sizeof(int) ) {	/* punt */
195 	qsort ( array, size, unit, compare );
196 	return;
197     }
198    if ( size <= 1 ) return;
199    /* set up initial partition on top of stack */
200    top = &stack[68];
201    *--top = 0;		/* push lbound */
202    *--top = size-1;	/* push initial hbound */
203 
204    /* loop until stack is emtpy */
205 
206    while ( top < &stack[68] ) {
207 
208       /* pop next range from stack and see if it has at least 3 elements */
209 
210       finish = *top++; start = *top++;
211       pivot = array[start];
212       if ( finish > start + 1 ) {
213          /*
214           *  more than 2 elements, split range into 2 sections according to
215           *  the relation to the pivot value.
216           */
217 	 array[start] = array[(start+finish)/2];	/* avoid sequence */
218 	 array[(start+finish)/2] = pivot; pivot = array[start];
219          lbound = start; hbound = finish;
220          while ( lbound < hbound ) {
221             if ( compare(&pivot, &array[lbound+1]) > 0 ) {
222                lbound++;
223             } else {
224                temp = array[hbound];
225                array[hbound] = array[lbound+1];
226                hbound--;
227                array[lbound+1] = temp;
228             }
229          }
230          /* determine which parition is bigger and push onto stack */
231          if ( lbound + lbound < (start+finish) ) {
232             /* push high partition first. */
233             *--top = lbound + 1;
234             *--top = finish;
235             finish = start;		/* skip add step below */
236              /* either push low partition or sort by inspection */
237             if ( lbound - start > 1 ) {
238                *--top = start;
239                *--top = lbound;
240             } else {
241                /* 2 element parition (start+1=lbound), sort by looking */
242                if ( pivot > array[lbound] ) {
243                   array[start] = array[lbound];
244                   array[lbound] = pivot;
245                }
246             }
247          } else if ( lbound != finish ) {
248             /* either push low partition or sort by inspection */
249             if ( lbound - start > 1 ) {
250                *--top = start;
251                *--top = lbound;
252             } else if ( lbound  > start ) {
253                /* 2 element parition (start+1=lbound), sort by looking */
254                if ( compare(&pivot, &array[lbound]) > 0 ) {
255                   array[start] = array[lbound];
256                   array[lbound] = pivot;
257                }
258             }
259             /* push high partition or sort by inspection */
260             if ( lbound < finish - 2 ) {
261                *--top = lbound + 1;
262                *--top = finish;
263             } else if ( lbound < finish - 1 ) {  /* 2 in partition */
264                if ( compare(&array[lbound+1], &array[finish]) > 0 ) {
265                   temp = array[lbound+1];
266                   array[lbound+1] = array[finish];
267                   array[finish] = temp;
268                }
269             }
270          } else {
271             /*
272              * Special case: high partition is empty, indicating that pivot
273              * value is at maximum.  Move to end and re-push remainder.
274              */
275             array[start] = array[finish];
276             array[finish] = pivot;
277             *--top = start;
278             *--top = finish - 1;
279          }
280 
281       } else {
282          /* only 2 elements in partition, sort inline */
283          if ( compare(&pivot,&array[finish]) > 0 ) {
284             array[start] = array[finish];
285             array[finish] = pivot;
286          }
287       }
288    }
289 }
290 
291 /*****************************************************************************/
292 
293 /*
294 **  VMS readdir() routines.
295 **  Written by Rich $alz, <rsalz@bbn.com> in August, 1990.
296 **  This code has no copyright.
297 */
298 
299 /* 12-NOV-1990 added d_namlen field and special case "." name -GJC@MITECH.COM
300  */
301 
302 #include <stdio.h>
303 #include <ctype.h>
304 #include <errno.h>
305 #include <descrip.h>
306 #include <rmsdef.h>
307 #include "dirent.h"
308 
309     /* Uncomment the next line to get a test routine. */
310 /*#define TEST*/
311 
312     /* Number of elements in vms_versions array */
313 #define VERSIZE(e)	(sizeof e->vms_versions / sizeof e->vms_versions[0])
314 
315     /* Linked in later. */
316 extern char	*strrchr();
317 extern char	*strcpy();
318 /*  Don't need this when all these programs are lumped together.    RLD
319 extern char	*malloc();
320 */
321 
322 
323 /*
324 **  Open a directory, return a handle for later use.
325 */
326 DIR *
opendir(name)327 opendir(name)
328     char	*name;
329 {
330     DIR		*dd;
331 
332     /* Get memory for the handle, and the pattern. */
333     if ((dd = (DIR *)malloc(sizeof *dd)) == NULL) {
334 	errno = ENOMEM;
335 	return NULL;
336     }
337 
338     if (strcmp(".",name) == 0) name = "";
339 
340     dd->pattern = malloc((unsigned int)(strlen(name) + sizeof "*.*" + 1));
341     if (dd->pattern == NULL) {
342 	free((char *)dd);
343 	errno = ENOMEM;
344 	return NULL;
345     }
346 
347     /* Fill in the fields; mainly playing with the descriptor. */
348     (void)sprintf(dd->pattern, "%s*.*", name);
349     dd->context = 0;
350     dd->vms_wantversions = 0;
351     dd->pat.dsc$a_pointer = dd->pattern;
352     dd->pat.dsc$w_length = strlen(dd->pattern);
353     dd->pat.dsc$b_dtype = DSC$K_DTYPE_T;
354     dd->pat.dsc$b_class = DSC$K_CLASS_S;
355 
356     return dd;
357 }
358 
359 
360 /*
361 **  Set the flag to indicate we want versions or not.
362 */
363 void
vmsreaddirversions(dd,flag)364 vmsreaddirversions(dd, flag)
365     DIR		*dd;
366     int		flag;
367 {
368     dd->vms_wantversions = flag;
369 }
370 
371 
372 /*
373 **  Free up an opened directory.
374 */
375 void
closedir(dd)376 closedir(dd)
377     DIR		*dd;
378 {
379     free(dd->pattern);
380     free((char *)dd);
381 }
382 
383 
384 /*
385 **  Collect all the version numbers for the current file.
386 */
387 static void
collectversions(dd)388 collectversions(dd)
389     DIR				*dd;
390 {
391     struct dsc$descriptor_s	pat;
392     struct dsc$descriptor_s	res;
393     struct dirent		*e;
394     char			*p;
395     char			buff[sizeof dd->entry.d_name];
396     int				i;
397     char			*text;
398     long			context;
399 
400     /* Convenient shorthand. */
401     e = &dd->entry;
402 
403     /* Add the version wildcard, ignoring the "*.*" put on before */
404     i = strlen(dd->pattern);
405     text = malloc((unsigned int)(i + strlen(e->d_name)+ 2 + 1));
406     if (text == NULL)
407 	return;
408     (void)strcpy(text, dd->pattern);
409     (void)sprintf(&text[i - 3], "%s;*", e->d_name);
410 
411     /* Set up the pattern descriptor. */
412     pat.dsc$a_pointer = text;
413     pat.dsc$w_length = strlen(text);
414     pat.dsc$b_dtype = DSC$K_DTYPE_T;
415     pat.dsc$b_class = DSC$K_CLASS_S;
416 
417     /* Set up result descriptor. */
418     res.dsc$a_pointer = buff;
419     res.dsc$w_length = sizeof buff - 2;
420     res.dsc$b_dtype = DSC$K_DTYPE_T;
421     res.dsc$b_class = DSC$K_CLASS_S;
422 
423     /* Read files, collecting versions. */
424     for (context = 0; e->vms_verscount < VERSIZE(e); e->vms_verscount++) {
425 	if (lib$find_file(&pat, &res, &context) == RMS$_NMF || context == 0)
426 	    break;
427 	buff[sizeof buff - 1] = '\0';
428 	if (p = strchr(buff, ';'))
429 	    e->vms_versions[e->vms_verscount] = atoi(p + 1);
430 	else
431 	    e->vms_versions[e->vms_verscount] = -1;
432     }
433 
434     free(text);
435 }
436 
437 
438 /*
439 **  Read the next entry from the directory.
440 */
441 struct dirent *
readdir(dd)442 readdir(dd)
443     DIR				*dd;
444 {
445     struct dsc$descriptor_s	res;
446     char			*p;
447     char			buff[sizeof dd->entry.d_name];
448     int				i;
449 
450     /* Set up result descriptor, and get next file. */
451     res.dsc$a_pointer = buff;
452     res.dsc$w_length = sizeof buff - 2;
453     res.dsc$b_dtype = DSC$K_DTYPE_T;
454     res.dsc$b_class = DSC$K_CLASS_S;
455     if (lib$find_file(&dd->pat, &res, &dd->context) == RMS$_NMF
456      || dd->context == 0L)
457 	/* None left... */
458 	return NULL;
459 
460     /* Force the buffer to end with a NUL. */
461     buff[sizeof buff - 1] = '\0';
462     for (p = buff; !isspace(*p); p++)
463 	;
464     *p = '\0';
465 
466     /* Skip any directory component and just copy the name. */
467     if (p = strchr(buff, ']'))
468 	(void)strcpy(dd->entry.d_name, p + 1);
469     else
470 	(void)strcpy(dd->entry.d_name, buff);
471 
472     /* Clobber the version. */
473     if (p = strchr(dd->entry.d_name, ';'))
474 	*p = '\0';
475 
476     dd->entry.d_namlen = strlen(dd->entry.d_name);
477 
478     dd->entry.vms_verscount = 0;
479     if (dd->vms_wantversions)
480 	collectversions(dd);
481     return &dd->entry;
482 }
483 
484 
485 /*
486 **  Return something that can be used in a seekdir later.
487 */
488 long
telldir(dd)489 telldir(dd)
490     DIR		*dd;
491 {
492     return dd->context;
493 }
494 
495 
496 /*
497 **  Return to a spot where we used to be.
498 */
499 void
seekdir(dd,pos)500 seekdir(dd, pos)
501     DIR		*dd;
502     long	pos;
503 {
504     dd->context = pos;
505 }
506 
507 
508 #ifdef	TEST
main()509 main()
510 {
511     char		buff[256];
512     DIR			*dd;
513     struct dirent	*dp;
514     int			i;
515     int			j;
516 
517     for ( ; ; ) {
518 	printf("\n\nEnter dir:  ");
519 	(void)fflush(stdout);
520 	(void)gets(buff);
521 	if (buff[0] == '\0')
522 	    break;
523 	if ((dd = opendir(buff)) == NULL) {
524 	    perror(buff);
525 	    continue;
526 	}
527 
528 	/* Print the directory contents twice, the second time print
529 	 * the versions. */
530 	for (i = 0; i < 2; i++) {
531 	    while (dp = readdir(dd)) {
532 		printf("%s%s", i ? "\t" : "    ", dp->d_name);
533 		for (j = 0; j < dp->vms_verscount; j++)
534 		    printf("  %d", dp->vms_versions[j]);
535 		printf("\n");
536 	    }
537 	    rewinddir(dd);
538 	    vmsreaddirversions(dd, 1);
539 	}
540 	closedir(dd);
541     }
542     exit(0);
543 }
544 #endif	/* TEST */
545 
546 /*****************************************************************************/
547 
548 /*
549 	pseudo_root - Return the Window ID of the Pseudo Root
550 
551 	NOTE: This routine is required for DECwindows
552 	because the true root window is hidden behind
553 	a pseudo-root window created by the window manager.
554 
555 	Calling Sequence:
556 		root_win = pseudo_root(display, screen);
557 	where:
558 		display must already be opened and
559 		screen is usually DefaultScreen(display).
560 
561 */
562 
563 #include <X11/Xlib.h>
564 
565 #ifdef NULL
566 #undef NULL
567 #define	NULL	0L
568 #endif
569 
570 static void chase_root();
571 
572 static int done;
573 static Window last_win;
574 static int root_x, root_y, root_width, root_height;
575 static int root_bw, root_depth;
576 
577 
pseudo_root(dpy,screen)578 Window pseudo_root(dpy, screen)
579 Display *dpy;
580 int screen;
581 {
582     Window root, win;
583 
584     /* Start at the real root */
585     root = RootWindow(dpy, screen);
586 
587     /* Get the geometry of the root */
588     if (XGetGeometry(dpy, root, &win, &root_x, &root_y,
589 			&root_width, &root_height,
590 			&root_bw, &root_depth))
591     {
592 	/* Set up for the tree walk */
593 	done = False;
594 	last_win = root;
595 
596 	/* Run down the tree to find the pseudo root */
597 	chase_root(dpy, root);
598 	return last_win;
599     }
600     else
601 	/* Classic case of "this should never happen" */
602 	return root;
603 
604 } /*** End pseudo_root() ***/
605 
606 
607 /*
608 	chase_root - Internal to this module
609 
610 	This is a recursive routine for descending the window tree.
611 
612 	It looks for the first window which does NOT overlay the root,
613 	then returns with the ID of the last window it saw in the
614 	global variable last_win.
615 
616 	NOTE: The parameters of the root window must be set up before
617 	calling chase_root().
618 */
619 
chase_root(dpy,w)620 static void chase_root (dpy, w)
621 Display *dpy;
622 Window w;
623 {
624     Window root, parent;
625     unsigned int nchildren;
626     Window *children = NULL;
627     Status status;
628     int n;
629     int x, y, rx, ry;
630     unsigned int width, height, bw, depth;
631 
632     /* Insurance */
633     if (done)
634 	return;
635 
636     if (XGetGeometry(dpy, w, &root, &x, &y, &width, &height, &bw, &depth))
637     {
638 	/*
639 	    If this window does not exactly overlay the root
640 	    then we have gone one too far, i.e., we have finished.
641 	*/
642 	if ( (x != root_x) ||
643 	     (y != root_y) ||
644 	     (width  != root_width) ||
645 	     (height != root_height) )
646 	{
647 	    done = True;
648 	    return;
649 	}
650 
651 	/* Otherwise, remember where we got up to and continue */
652 	else
653 	    last_win = w;
654     }
655 
656     else
657 	/* We are in trouble if this happens!!! */
658 	return;
659 
660     if (!XQueryTree (dpy, w, &root, &parent, &children, &nchildren))
661 	/* Likewise, we hope we never get here!!! */
662 	return;
663 
664     for (n = 0; n < nchildren; n++)
665     {
666 	chase_root (dpy, children[n]);
667 	if (done)
668 	    break;
669     }
670 #ifdef VMS
671     if (children) XFree ((char *) children);
672 #else
673     if (children) free ((char *) children);
674 #endif
675     return;
676 
677 } /*** End chase_root() ***/
678 
679 /*****************************************************************************/
680 
681 /*
682  * @(#)argproc.c 1.0 89/02/01		Mark Pizzolato (mark@infopiz.uucp)
683  */
684 
685 #ifndef lint
686 char argproc_version[] = "@(#)argproc.c VMS uucp Version infopiz-1.0";
687 #endif
688 
689 #include "includes.h"		/* System include files, system dependent */
690 
691 
692 /*
693  * getredirection() is intended to aid in porting C programs
694  * to VMS (Vax-11 C) which does not support '>' and '<'
695  * I/O redirection, along with a command line pipe mechanism
696  * using the '|' AND background command execution '&'.
697  * The piping mechanism will probably work with almost any 'filter' type
698  * of program.  With suitable modification, it may useful for other
699  * portability problems as well.
700  *
701  * Author:  Mark Pizzolato	mark@infopiz.UUCP
702  */
703 struct list_item
704     {
705     struct list_item *next;
706     char *value;
707     };
708 
709 int
getredirection(ac,av)710 getredirection(ac, av)
711 int		*ac;
712 char		***av;
713 /*
714  * Process vms redirection arg's.  Exit if any error is seen.
715  * If getredirection() processes an argument, it is erased
716  * from the vector.  getredirection() returns a new argc and argv value.
717  * In the event that a background command is requested (by a trailing "&"),
718  * this routine creates a background subprocess, and simply exits the program.
719  *
720  * Warning: do not try to simplify the code for vms.  The code
721  * presupposes that getredirection() is called before any data is
722  * read from stdin or written to stdout.
723  *
724  * Normal usage is as follows:
725  *
726  *	main(argc, argv)
727  *	int		argc;
728  *    	char		*argv[];
729  *	{
730  *		getredirection(&argc, &argv);
731  *	}
732  */
733 {
734     int			argc = *ac;	/* Argument Count	  */
735     char		**argv = *av;	/* Argument Vector	  */
736     char		*ap;   		/* Argument pointer	  */
737     int	       		j;		/* argv[] index		  */
738     extern int		errno;		/* Last vms i/o error 	  */
739     int			item_count = 0;	/* Count of Items in List */
740     int			new_file;	/* flag, true if '>' used */
741     struct list_item 	*list_head = 0;	/* First Item in List	    */
742     struct list_item	*list_tail;	/* Last Item in List	    */
743     char 		*in = NULL;	/* Input File Name	    */
744     char 		*out = NULL;	/* Output File Name	    */
745     char 		*outmode = "w";	/* Mode to Open Output File */
746     int			cmargc = 0;    	/* Piped Command Arg Count  */
747     char		**cmargv = NULL;/* Piped Command Arg Vector */
748     stat_t		statbuf;	/* fstat buffer		    */
749 
750     /*
751      * First handle the case where the last thing on the line ends with
752      * a '&'.  This indicates the desire for the command to be run in a
753      * subprocess, so we satisfy that desire.
754      */
755     ap = argv[argc-1];
756     if (0 == strcmp("&", ap))
757 	exit(background_process(--argc, argv));
758     if ('&' == ap[strlen(ap)-1])
759 	{
760 	ap[strlen(ap)-1] = '\0';
761 	exit(background_process(argc, argv));
762 	}
763     /*
764      * Now we handle the general redirection cases that involve '>', '>>',
765      * '<', and pipes '|'.
766      */
767     for (new_file = 0, j = 0; j < argc; ++j)
768 	{
769 	if (0 == strcmp("<", argv[j]))
770 	    {
771 	    if (j+1 >= argc)
772 		{
773 		errno = EINVAL;
774 		perror("No input file");
775 		exit(EXIT_ERR);
776 		}
777 	    in = argv[++j];
778 	    continue;
779 	    }
780 	if ('<' == *(ap = argv[j]))
781 	    {
782 	    in = 1 + ap;
783 	    continue;
784 	    }
785 	if (0 == strcmp(">", ap))
786 	    {
787 	    if (j+1 >= argc)
788 		{
789 		errno = EINVAL;
790 		perror("No output file");
791 		exit(EXIT_ERR);
792 		}
793 	    out = argv[++j];
794 	    new_file = 1;
795 	    continue;
796 	    }
797 	if ('>' == *ap)
798 	    {
799 	    if ('>' == ap[1])
800 		{
801 		outmode = "a";
802 		if ('\0' == ap[2])
803 		    out = argv[++j];
804 		else
805 		    out = 2 + ap;
806 		}
807 	    else
808 		{ out = 1 + ap;  new_file = 1; }
809 	    continue;
810 	    }
811 	if (0 == strcmp("|", argv[j]))
812 	    {
813 	    if (j+1 >= argc)
814 		{
815 		errno = EPIPE;
816 		perror("No command to Pipe to");
817 		exit(EXIT_ERR);
818 		}
819 	    cmargc = argc-(j+1);
820 	    cmargv = &argv[j+1];
821 	    argc = j;
822 	    outmode = "wb";	/* pipes are binary mode devices */
823 	    continue;
824 	    }
825 	if ('|' == *(ap = argv[j]))
826 	    {
827 	    ++argv[j];
828 	    cmargc = argc-j;
829 	    cmargv = &argv[j];
830 	    argc = j;
831 	    outmode = "wb";	/* pipes are binary mode devices */
832 	    continue;
833 	    }
834 	expand_wild_cards(ap, &list_head, &list_tail, &item_count);
835 	}
836     /*
837      * Allocate and fill in the new argument vector, Some Unix's terminate
838      * the list with an extra null pointer.
839      */
840     argv = *av = calloc(item_count+1, sizeof(char *));
841     for (j = 0; j < item_count; ++j, list_head = list_head->next)
842 	argv[j] = list_head->value;
843     *ac = item_count;
844     if (cmargv != NULL)
845 	{
846 	char subcmd[1024];
847 	static char *pipe_and_fork();
848 
849 	if (out != NULL)
850 	    {
851 	    errno = EINVAL;
852 	    perror("Invalid '|' and '>' specified");
853 	    exit(EXIT_ERR);
854 	    }
855 	strcpy(subcmd, cmargv[0]);
856 	for (j = 1; j < cmargc; ++j)
857 	    {
858 	    strcat(subcmd, " \"");
859 	    strcat(subcmd, cmargv[j]);
860 	    strcat(subcmd, "\"");
861 	    }
862 	out = pipe_and_fork(subcmd);
863 	outmode = "wb";
864 	}
865 
866     /* Check for input from a pipe (mailbox) */
867 
868     if(fstat(0, &statbuf) == 0){
869 	if(strncmp(statbuf.st_dev, "MB", 2) == 0 ||
870 	    strncmp(statbuf.st_dev, "_MB", 3) == 0){
871 
872 	    /* Input from a pipe, reopen it in binary mode to disable	*/
873 	    /* carriage control processing.				*/
874 
875 	    if (in != NULL){
876 		errno = EINVAL;
877 		perror("Invalid '|' and '<' specified");
878 		exit(EXIT_ERR);
879 		}
880 	    freopen(statbuf.st_dev, "rb", stdin);
881 	    }
882 	}
883     else {
884 	perror("fstat failed");
885 	exit(EXIT_ERR);
886 	}
887 
888 
889 #ifdef __ALPHA
890         /*, "mbc=32", "mbf=2"))) blows up on the ALPHA cbm 11/08/92 */
891     if ((in != NULL) && (NULL == freopen(in, "r", stdin)))
892         {
893 #else
894     if ((in != NULL) && (NULL == freopen(in, "r", stdin, "mbc=32", "mbf=2")))
895 	{
896 #endif
897 	perror(in);    	       	/* Can't find file		*/
898 	exit(EXIT_ERR);		/* Is a fatal error		*/
899 	}
900 #ifdef __ALPHA
901     if ((out != NULL) && (NULL == freopen(out, outmode, stdout)))
902         {
903 #else
904     if ((out != NULL) && (NULL == freopen(out, outmode, stdout, "mbc=32", "mbf=2")))
905 	{
906 #endif
907 	perror(ap);		/* Error, can't write or append	*/
908 	exit(EXIT_ERR);		/* Is a fatal error		*/
909 	}
910 
911      if ( new_file ) {
912 	/*
913 	 * We are making an explicit output file, fstat the file and
914          * declare exit handler to be able change the file to fixed length
915 	 * records if necessary.
916 	 */
917 	char fname[256];
918 	static int outfile_rundown(), check_outfile_filetype();
919 	static stat_t ofile_stat;
920 	static struct exit_control_block {
921     	    struct exit_control_block *flink;
922     	    int	(*exit_routine)();
923 	    int arg_count;
924 	    int *status_address;	/* arg 1 */
925 	    stat_t *stat;		/* arg 2 */
926 	    int exit_status;
927 	    int skew[128];
928 	} exit_block =
929 	    { 0, outfile_rundown, 2, &exit_block.exit_status, &ofile_stat, 0 };
930 
931 	if ( fstat ( fileno(stdout), &ofile_stat ) == 0 )
932 	     sys$dclexh ( &exit_block );
933 	else fprintf(stderr,"Error fstating stdout - %s\n",
934 		strerror(errno,vaxc$errno) );
935 
936 	if ( fgetname ( stdout, fname, 0 ) ) check_outfile_filetype ( fname );
937      }
938 #ifdef DEBUG
939     fprintf(stderr, "Arglist:\n");
940     for (j = 0; j < *ac;  ++j)
941 	fprintf(stderr, "argv[%d] = '%s'\n", j, argv[j]);
942 #endif
943 }
944 
945 static int binary_outfile = 0;
set_outfile_binary()946 void set_outfile_binary() { binary_outfile = 1; return; }
947 
948 /*
949  * Check if output file should be set to binary (fixed 512) on exit based
950  * upon the filetype.
951  */
check_outfile_filetype(name)952 static int check_outfile_filetype ( name )
953     char *name;
954 {
955     char *binary_filetypes, *ext, *p, *t;
956     binary_filetypes = (char *) getenv ( "PBM_BINARY_FILETYPES" );
957     if ( binary_filetypes == NULL ) return 0;
958 
959     ext = strchr ( name, '.' );  if ( ext == NULL ) return 0;
960     ext++;
961     t = strrchr ( name, '.' );   if ( t != NULL ) *t = '\0';
962 
963     for ( p = binary_filetypes; *p != '\0'; p++ ) {
964 	for ( t = p;
965 	      (*p != '\0' ) && (strchr ( ", 	", *p ) == NULL);
966 	     p++ ) *p = toupper(*p);
967 	*p = '\0';
968 
969 	if ( strcmp ( t, ext ) == 0 ) {
970 	    binary_outfile = 1;
971 	    break;
972 	}
973     }
974     return binary_outfile;
975 }
976 
977 
978 /*
979  * Exit handler to set output file to binary on image exit.
980  */
outfile_rundown(reason,statbuf)981 static int outfile_rundown ( reason, statbuf )
982     int *reason;
983     stat_t *statbuf;
984 {
985     int code, channel, status, LIB$GETDVI(), sys$assign(), sys$qiow();
986     long int fib_desc[2], devchar;
987     short int iosb[4];
988     $DESCRIPTOR(device, statbuf->st_dev);
989     struct fibdef fib;		/* File information block (XQP) */
990     struct atrdef atr[2];
991     struct fat {
992       unsigned char rtype, ratattrib;
993       unsigned short int rsize, hiblk[2], efblk[2], ffbyte, maxrec, defext, gbc;
994       unsigned short int reserved[4], versions;
995     } rat;
996 
997     if ( !binary_outfile ) return 1;	/* leave file alone */
998     /*
999      * Assign channel to device listed in stat block and test if it is
1000      * a directory structured device, returning if not.
1001      */
1002     device.dsc$w_length = strlen ( statbuf->st_dev );
1003     status = sys$assign ( &device, &channel, 0, 0 );
1004     if ((status & 1) == 0) { fprintf(stderr,
1005 	"assign error to %s (%d)\n", device.dsc$a_pointer, status);
1006 		return status; }
1007     code = DVI$_DEVCHAR;
1008     status = LIB$GETDVI ( &code, &channel, 0, &devchar );
1009     if ((status & 1) == 0) { fprintf(stderr, "getdvi error: %d\n", status);
1010 		return status; }
1011     if ( (devchar & DEV$M_DIR) == 0 ) return 1;
1012     /*
1013      * Build File Information Block and Atrribute block.
1014      */
1015 #if defined(__ALPHA) || defined(__DECC)
1016     fib.fib$w_fid[0] = statbuf->st_ino[0];
1017     fib.fib$w_fid[1] = statbuf->st_ino[1];
1018     fib.fib$w_fid[2] = statbuf->st_ino[2];
1019 #else
1020     fib.fib$r_fid_overlay.fib$w_fid[0] = statbuf->st_ino[0];
1021     fib.fib$r_fid_overlay.fib$w_fid[1] = statbuf->st_ino[1];
1022     fib.fib$r_fid_overlay.fib$w_fid[2] = statbuf->st_ino[2];
1023 #endif
1024 
1025     atr[0].atr$w_size = sizeof(rat);
1026     atr[0].atr$w_type = ATR$C_RECATTR;
1027     atr[0].atr$l_addr = &rat;
1028     atr[1].atr$w_size = 0; atr[1].atr$w_type = 0;
1029     /*
1030      * Perform access function with read_attributes sub-function.
1031      */
1032     freopen ( "SYS$OUTPUT:", "a", stdout );
1033     fib_desc[0] = 10; fib_desc[1] = (long int) &fib;
1034 #if defined(__ALPHA) || defined(__DECC)
1035     fib.fib$l_acctl = FIB$M_WRITE;
1036 #else
1037     fib.fib$r_acctl_overlay.fib$l_acctl = FIB$M_WRITE;
1038 #endif
1039     status = sys$qiow ( 0, channel, IO$_ACCESS|IO$M_ACCESS,
1040 		 &iosb, 0, 0, &fib_desc, 0, 0, 0, &atr, 0 );
1041     /*
1042      * If status successful, update record byte and perform a MODIFY.
1043      */
1044     if ( (status&1) == 1 ) status = iosb[0];
1045     if ( (status&1) == 1 ) {
1046       rat.rtype = 1;		/* fixed length records */
1047       rat.rsize = 512;  	/* 512 byte block recrods */
1048       rat.ratattrib = 0;        /* Record attributes: none */
1049 
1050      status = sys$qiow
1051 	( 0, channel, IO$_MODIFY, &iosb, 0, 0, &fib_desc, 0, 0, 0, &atr, 0 );
1052        if ( (status&1) == 1 ) status = iosb[0];
1053    }
1054    sys$dassgn ( channel );
1055    if ( (status & 1) == 0 ) fprintf ( stderr,
1056 	"Failed to convert output file to binary format, status: %d\n", status);
1057    return status;
1058 }
1059 
1060 
1061 static add_item(head, tail, value, count)
1062 struct list_item **head;
1063 struct list_item **tail;
1064 char *value;
1065 int *count;
1066 {
1067     if (*head == 0)
1068 	{
1069 	if (NULL == (*head = calloc(1, sizeof(**head))))
1070 	    {
1071 	    errno = ENOMEM;
1072 	    perror("");
1073 	    exit(EXIT_ERR);
1074 	    }
1075 	*tail = *head;
1076 	}
1077     else
1078 	if (NULL == ((*tail)->next = calloc(1, sizeof(**head))))
1079 	    {
1080 	    errno = ENOMEM;
1081 	    perror("");
1082 	    exit(EXIT_ERR);
1083 	    }
1084 	else
1085 	    *tail = (*tail)->next;
1086     (*tail)->value = value;
1087     ++(*count);
1088 }
1089 
expand_wild_cards(item,head,tail,count)1090 static expand_wild_cards(item, head, tail, count)
1091 char *item;
1092 struct ltem_list **head;
1093 struct ltem_list **tail;
1094 int *count;
1095 {
1096 int expcount = 0;
1097 int context = 0;
1098 int status;
1099 int status_value;
1100 int had_version;
1101 $DESCRIPTOR(filespec, item);
1102 $DESCRIPTOR(defaultspec, "SYS$DISK:[]*.*;");
1103 $DESCRIPTOR(resultspec, "");
1104 
1105     if (strcspn(item, "*%") == strlen(item))
1106 	{
1107 	add_item(head, tail, item, count);
1108 	return;
1109 	}
1110     resultspec.dsc$b_dtype = DSC$K_DTYPE_T;
1111     resultspec.dsc$b_class = DSC$K_CLASS_D;
1112     resultspec.dsc$a_pointer = NULL;
1113     filespec.dsc$w_length = strlen(item);
1114     /*
1115      * Only return version specs, if the caller specified a version
1116      */
1117     had_version = strchr(item, ';');
1118     while (1 == (1&lib$find_file(&filespec, &resultspec, &context,
1119     				 &defaultspec, 0, &status_value, &0)))
1120 	{
1121 	char *string;
1122 	char *c;
1123 
1124 	if (NULL == (string = calloc(1, resultspec.dsc$w_length+1)))
1125 	    {
1126 	    errno = ENOMEM;
1127 	    perror("");
1128 	    exit(EXIT_ERR);
1129 	    }
1130 	strncpy(string, resultspec.dsc$a_pointer, resultspec.dsc$w_length);
1131 	string[resultspec.dsc$w_length] = '\0';
1132 	if (NULL == had_version)
1133 	    *((char *)strrchr(string, ';')) = '\0';
1134 	/*
1135 	 * Be consistent with what the C RTL has already done to the rest of
1136 	 * the argv items and lowercase all of these names.
1137 	 */
1138 	for (c = string; *c; ++c)
1139 	    if (isupper(*c))
1140 		*c = tolower(*c);
1141 	add_item(head, tail, string, count);
1142 	++expcount;
1143 	}
1144     if (expcount == 0)
1145 	add_item(head, tail, item, count);
1146     lib$sfree1_dd(&resultspec);
1147     lib$find_file_end(&context);
1148 }
1149 
1150 static int child_st[2];	/* Event Flag set when child process completes	*/
1151 
1152 static short child_chan;/* I/O Channel for Pipe Mailbox			*/
1153 
exit_handler(status)1154 static exit_handler(status)
1155 int *status;
1156 {
1157 short iosb[4];
1158 
1159     if (0 == child_st[0])
1160 	{
1161 #ifdef DEBUG
1162 	fprintf(stderr, "Waiting for Child Process to Finnish . . .\n");
1163 #endif
1164 	fflush(stdout);	    /* Have to flush pipe for binary data to	*/
1165 			    /* terminate properly -- <tp@mccall.com>	*/
1166 #ifdef DEBUG
1167 	fprintf(stderr, "    stdout flushed. . .\n");
1168 #endif
1169 	sys$qio(0, child_chan, IO$_WRITEOF, iosb, 0, 0, 0, 0, 0, 0, 0, 0);
1170 #ifdef DEBUG
1171 	fprintf(stderr, "    Pipe terminated. . .\n");
1172 #endif
1173 	fclose(stdout);
1174 #ifdef DEBUG
1175 	fprintf(stderr, "    stdout closed. . .\n");
1176 #endif
1177 	sys$synch(0, child_st);
1178 	sys$dassgn(child_chan);
1179 	}
1180 #ifdef DEBUG
1181 	fprintf(stderr, "    sync done. . .\n");
1182 #endif
1183 }
1184 
1185 #include <syidef>		/* System Information Definitions	*/
1186 
sig_child(chan)1187 static sig_child(chan)
1188 int chan;
1189 {
1190 #ifdef DEBUG
1191     fprintf(stderr, "Child Completion AST, st: %x\n", child_st[0] );
1192 #endif
1193     if (child_st[0] == 0)
1194 	{ child_st[0] = 1; }
1195     sys$setef ( 0 );
1196 }
1197 
1198 static struct exit_control_block
1199     {
1200     struct exit_control_block *flink;
1201     int	(*exit_routine)();
1202     int arg_count;
1203     int *status_address;
1204     int exit_status;
1205     } exit_block =
1206     {
1207     0,
1208     exit_handler,
1209     1,
1210     &exit_block.exit_status,
1211     0
1212     };
1213 
pipe_and_fork(cmd)1214 static char *pipe_and_fork(cmd)
1215 char *cmd;
1216 {
1217     $DESCRIPTOR(cmddsc, cmd);
1218     static char mbxname[64], ef = 0;
1219     $DESCRIPTOR(mbxdsc, mbxname);
1220     short iosb[4];
1221     int status;
1222     int pid;
1223     struct
1224 	{
1225 	short dna_buflen;
1226 	short dna_itmcod;
1227 	char *dna_buffer;
1228 	short *dna_retlen;
1229 	int listend;
1230 	} itmlst =
1231 	{
1232 	sizeof(mbxname),
1233 	DVI$_DEVNAM,
1234 	mbxname,
1235 	&mbxdsc.dsc$w_length,
1236 	0
1237 	};
1238     int mbxsize;
1239     struct
1240 	{
1241 	short mbf_buflen;
1242 	short mbf_itmcod;
1243 	int *mbf_maxbuf;
1244 	short *mbf_retlen;
1245 	int listend;
1246 	} syiitmlst =
1247 	{
1248 	sizeof(mbxsize),
1249 	SYI$_MAXBUF,
1250 	&mbxsize,
1251 	0,
1252 	0
1253 	};
1254 
1255     cmddsc.dsc$w_length = strlen(cmd);
1256     /*
1257      * Get the SYSGEN parameter MAXBUF, and the smaller of it and 2048 as
1258      * the size of the 'pipe' mailbox.
1259      */
1260     if (1 == (1&(vaxc$errno = sys$getsyiw(0, 0, 0, &syiitmlst, iosb, 0, 0, 0))))
1261 	vaxc$errno = iosb[0];
1262     if (0 == (1&vaxc$errno))
1263 	{
1264  	errno = EVMSERR;
1265 	perror("Can't get SYSGEN parameter value for MAXBUF");
1266 	exit(EXIT_ERR);
1267 	}
1268     if (mbxsize > 2048)
1269 	mbxsize = 2048;
1270     if (0 == (1&(vaxc$errno = sys$crembx(0, &child_chan, mbxsize, mbxsize, 0, 0, 0))))
1271 	{
1272 	errno = EVMSERR;
1273 	perror("Can't create pipe mailbox");
1274 	exit(EXIT_ERR);
1275 	}
1276     if (1 == (1&(vaxc$errno = sys$getdviw(0, child_chan, 0, &itmlst, iosb,
1277     					  0, 0, 0))))
1278 	vaxc$errno = iosb[0];
1279     if (0 == (1&vaxc$errno))
1280 	{
1281  	errno = EVMSERR;
1282 	perror("Can't get pipe mailbox device name");
1283 	exit(EXIT_ERR);
1284 	}
1285     mbxname[mbxdsc.dsc$w_length] = '\0';
1286 #ifdef DEBUG
1287     fprintf(stderr, "Pipe Mailbox Name = '%s'\n", mbxname);
1288 #endif
1289     if (0 == (1&(vaxc$errno = lib$spawn(&cmddsc, &mbxdsc, 0, &1,
1290     					0, &pid, child_st, &ef, sig_child,
1291     					&child_chan))))
1292 	{
1293 	errno = EVMSERR;
1294 	perror("Can't spawn subprocess");
1295 	exit(EXIT_ERR);
1296 	}
1297 #ifdef DEBUG
1298     fprintf(stderr, "Subprocess's Pid = %08X\n", pid);
1299 #endif
1300     sys$dclexh(&exit_block);
1301     return(mbxname);
1302 }
1303 
background_process(argc,argv)1304 background_process(argc, argv)
1305 int argc;
1306 char **argv;
1307 {
1308 char command[2048] = "$";
1309 $DESCRIPTOR(value, command);
1310 $DESCRIPTOR(cmd, "BACKGROUND$COMMAND");
1311 $DESCRIPTOR(null, "NLA0:");
1312 int pid;
1313 
1314     strcat(command, argv[0]);
1315     while (--argc)
1316 	{
1317 	strcat(command, " \"");
1318 	strcat(command, *(++argv));
1319 	strcat(command, "\"");
1320 	}
1321     value.dsc$w_length = strlen(command);
1322     if (0 == (1&(vaxc$errno = lib$set_symbol(&cmd, &value))))
1323 	{
1324 	errno = EVMSERR;
1325 	perror("Can't create symbol for subprocess command");
1326 	exit(EXIT_ERR);
1327 	}
1328     if (0 == (1&(vaxc$errno = lib$spawn(&cmd, &null, 0, &17, 0, &pid))))
1329 	{
1330 	errno = EVMSERR;
1331 	perror("Can't spawn subprocess");
1332 	exit(EXIT_ERR);
1333 	}
1334 #ifdef DEBUG
1335     fprintf(stderr, "%s\n", command);
1336 #endif
1337     fprintf(stderr, "%08X\n", pid);
1338     return(EXIT_OK);
1339 }
1340 
1341 /* got this off net.sources */
1342 
1343 #ifdef	VMS
1344 #define	index	strchr
1345 #endif	/*VMS*/
1346 
1347 /*
1348  * get option letter from argument vector
1349  */
1350 int	opterr = 1,		/* useless, never set or used */
1351 	optind = 1,		/* index into parent argv vector */
1352 	optopt;			/* character checked for validity */
1353 char	*optarg;		/* argument associated with option */
1354 
1355 #define BADCH	(int)'?'
1356 #define EMSG	""
1357 #define tell(s)	fputs(progname,stderr);fputs(s,stderr); \
1358 		fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
1359 
getopt(nargc,nargv,ostr)1360 getopt(nargc,nargv,ostr)
1361 int	nargc;
1362 char	**nargv,
1363 	*ostr;
1364 {
1365 	static char	*place = EMSG;	/* option letter processing */
1366 	register char	*oli;		/* option letter list index */
1367 	char	*index();
1368 	char *progname;
1369 
1370 	if(!*place) {			/* update scanning pointer */
1371 		if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
1372 		if (*place == '-') {	/* found "--" */
1373 			++optind;
1374 			return(EOF);
1375 		}
1376 	}				/* option letter okay? */
1377 	if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
1378 		if(!*place) ++optind;
1379 #ifdef VMS
1380 		progname = strrchr(nargv[0],']');
1381 #else
1382 		progname = rindex(nargv[0],'/');
1383 #endif
1384 		if (!progname) progname = nargv[0]; else progname++;
1385 		tell(": illegal option -- ");
1386 	}
1387 	if (*++oli != ':') {		/* don't need argument */
1388 		optarg = NULL;
1389 		if (!*place) ++optind;
1390 	}
1391 	else {				/* need an argument */
1392 		if (*place) optarg = place;	/* no white space */
1393 		else if (nargc <= ++optind) {	/* no arg */
1394 			place = EMSG;
1395 #ifdef VMS
1396 			progname = strrchr(nargv[0],']');
1397 #else
1398 			progname = rindex(nargv[0],'/');
1399 #endif
1400 			if (!progname) progname = nargv[0]; else progname++;
1401 			tell(": option requires an argument -- ");
1402 		}
1403 	 	else optarg = nargv[optind];	/* white space */
1404 		place = EMSG;
1405 		++optind;
1406 	}
1407 	return(optopt);			/* dump back option letter */
1408 }
1409 
1410 #ifndef __DECC
1411 /*
1412  *  This was stolen from xterm v2.1 for VMS by Rick Dyson
1413 */
1414 
1415 /*
1416  *	gethostname(2) - VMS Version of the UNIX routine
1417  *
1418  *	This routine simply translates the system logical
1419  *	name SYS$NODE and returns the result. This does not
1420  *	exactly match UNIX behaviour. In particular, the
1421  *	double colon at the end of the node name may cause
1422  *	problems in ported code.
1423  */
1424 
1425 #include <ssdef.h>
1426 #include <lnmdef.h>
1427 #include <descrip.h>
1428 #include <errno.h>
1429 
1430 #define	NULL	0L
1431 
1432 
gethostname(name,namelen)1433 int gethostname(name, namelen)		/*--- Get node name ---*/
1434 char name[];
1435 int  namelen;
1436 {
1437     /* Logical name to translate */
1438     char logical[] = "SYS$NODE";
1439     $DESCRIPTOR(logical_dsc, logical);
1440 
1441     /* These descriptors is necessary to select the logical name table */
1442     char sys_log_table[] = "LNM$SYSTEM_TABLE";
1443     $DESCRIPTOR(sys_log_table_dsc, sys_log_table);
1444 
1445     /* Item list as used by SYS$TRNLNM() */
1446     struct ITEM_LIST
1447     {
1448 	unsigned short buflen;
1449 	unsigned short code;
1450 	int buffaddr;
1451 	int retaddr;
1452     };
1453 
1454     struct ITEM_LIST log_list[2];
1455 
1456     unsigned short retlen;		/* Must be a WORD */
1457 
1458     /*
1459 	Buffer for the translation
1460 
1461 	Max return length from SYS$TRNLNM is 255,
1462 	but add a couple to be safe.
1463     */
1464     char string[257];
1465 
1466     int status, i;
1467 
1468 
1469     if (name == NULL)
1470     {
1471 	errno = EFAULT;
1472 	return (-1);
1473     }
1474 
1475     /* Setup the required item list for SYS$TRNLNM */
1476 
1477     log_list[0].buflen = 255;
1478     log_list[0].code   = LNM$_STRING;
1479     log_list[0].buffaddr = &string;
1480     log_list[0].retaddr  = &retlen;
1481     log_list[1].buflen = 0;
1482     log_list[1].code   = 0;
1483 
1484     /* Time to look for a logical name ... */
1485 
1486     status = SYS$TRNLNM(0, &sys_log_table_dsc,
1487 		    &logical_dsc, 0, &log_list);
1488 
1489     if (status == SS$_NORMAL)
1490     {
1491 	/* Got a translation */
1492 	/* Copy the name back to the calling program */
1493 	for (i=0; i<retlen && i<namelen; i++)
1494 	{
1495 	    name[i] = string[i];
1496 	}
1497 	if (i < namelen)
1498 	    name[i] = 0;		/* Append a null */
1499 
1500 	return (0);
1501 
1502     }
1503     else
1504     {
1505 	errno = EFAULT;
1506 	vaxc$errno = status;
1507 	return (-1);
1508     }
1509 }
1510 #endif /* __DECC */
1511