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