1 /********************************************************************
2 * $Author: jgoerzen $
3 * $Revision: 1.2 $
4 * $Date: 2000/12/20 01:19:20 $
5 * $Source: /home/jgoerzen/tmp/gopher-umn/gopher/head/object/fileio.c,v $
6 * $State: Exp $
7 *
8 * Paul Lindner, University of Minnesota CIS.
9 *
10 * Copyright 1991, 92, 93, 94 by the Regents of the University of Minnesota
11 * see the file "Copyright" in the distribution for conditions of use.
12 *********************************************************************
13 * MODULE: fileio.c
14 * Socket/file input output routines.
15 *********************************************************************
16 * Revision History:
17 * $Log: fileio.c,v $
18 * Revision 1.2 2000/12/20 01:19:20 jgoerzen
19 * Added patches from David Allen <s2mdalle@titan.vcu.edu>
20 *
21 * Revision 1.1.1.1 2000/08/19 00:28:56 jgoerzen
22 * Import from UMN Gopher 2.3.1 after GPLization
23 *
24 * Revision 3.41 1996/01/04 18:25:12 lindner
25 * Updates for autoconf
26 *
27 * Revision 3.40 1995/11/03 18:01:28 lindner
28 * Fix for waitpid stuff
29 *
30 * Revision 3.39 1995/09/25 22:07:23 lindner
31 * Ansification
32 *
33 * Revision 3.38 1995/06/12 15:32:41 lindner
34 * Close correct file descriptor
35 *
36 * Revision 3.37 1995/06/08 05:17:54 lindner
37 * From Fote: Deal with UCX's funny EPIPE return value on EOF
38 * immediately after each socket_read().
39 *
40 * Ensure that file is closed on fstat() error in FIOopenUFS()
41 *
42 * Revision 3.36 1995/04/15 06:53:39 lindner
43 * Different way of returning errors
44 *
45 * Revision 3.35 1995/03/09 05:28:19 lindner
46 * Insure files get closed in FIO routines
47 *
48 * Revision 3.34 1995/02/27 17:45:52 lindner
49 * Fix for sco
50 *
51 * Revision 3.33 1995/01/02 21:09:46 lindner
52 * Fix for UCX menu ordering
53 *
54 * Revision 3.32 1994/12/20 17:09:46 lindner
55 * Fix for binary file retrievals
56 *
57 * Revision 3.31 1994/12/03 02:14:13 lindner
58 * Correct fix for waitpid() code
59 *
60 * Revision 3.30 1994/12/02 00:37:05 lindner
61 * Fix for mail and misc process execution
62 *
63 * Revision 3.29 1994/12/01 00:30:13 lindner
64 * Remove EINTR wait for FIOwaitpid.. sigh..
65 *
66 * Revision 3.28 1994/11/29 06:30:04 lindner
67 * Make waitpid keep going after an interrupted system call
68 *
69 * Revision 3.27 1994/11/29 04:59:38 lindner
70 * Fix for broken shell scripts with Shell Index type
71 *
72 * Revision 3.26 1994/10/21 02:42:47 lindner
73 * fix for 0 length files
74 *
75 * Revision 3.25 1994/10/19 03:33:57 lindner
76 * Fix nasty bug, combine more code...
77 *
78 * Revision 3.24 1994/10/13 05:26:16 lindner
79 * Compiler complaint fixes
80 *
81 * Revision 3.23 1994/09/29 19:54:57 lindner
82 * Routines to use memory mapped I/O
83 *
84 * Revision 3.22 1994/07/21 22:19:37 lindner
85 * Add filename new and change debug msg
86 *
87 * Revision 3.21 1994/06/29 06:43:04 lindner
88 * Remove VMS message about reversed values, initialize filename
89 *
90 * Revision 3.20 1994/05/25 20:57:20 lindner
91 * Fix for piped play commands
92 *
93 * Revision 3.19 1994/04/25 03:44:42 lindner
94 * Don't block empty FIOsystem() command on VMS. That's what's used for
95 * the '!' or '$' commands, and they've already be checked for permission
96 * in Gopher.c.
97 *
98 * Reversed DCLsystem() return values in CURCurses.c, and eliminated the
99 * reversing kludge in FIOsystem().
100 *
101 * Fixed break of open() for Alpha. (all From F.Macrides)
102 *
103 * Revision 3.18 1994/04/25 03:37:00 lindner
104 * Modifications for Debug() and mismatched NULL arguments, added Debugmsg
105 *
106 * Revision 3.17 1994/04/25 02:18:46 lindner
107 * Fix for gcc-Wall
108 *
109 * Revision 3.16 1994/04/14 18:14:49 lindner
110 * Fix for closing null files
111 *
112 * Revision 3.15 1994/04/14 15:44:55 lindner
113 * Remove duplicate variable
114 *
115 * Revision 3.14 1994/04/08 21:07:34 lindner
116 * Put back a variable
117 *
118 * Revision 3.13 1994/04/08 20:05:57 lindner
119 * gcc -Wall fixes
120 *
121 * Revision 3.12 1994/04/08 19:15:47 lindner
122 * Fix for old union wait stuff
123 *
124 * Revision 3.11 1994/04/07 22:51:24 lindner
125 * Fix for typecast
126 *
127 * Revision 3.10 1994/04/01 04:43:31 lindner
128 * Fixes for memory leak in argv, and exit status
129 *
130 * Revision 3.9 1994/03/30 21:37:48 lindner
131 * Fix for AIX that doesn't #define unix..
132 *
133 * Revision 3.8 1994/03/11 00:10:52 lindner
134 * Fix for FIOopenUFS()
135 *
136 * Revision 3.7 1994/03/09 16:57:56 lindner
137 * Fix for other vms system() call
138 *
139 * Revision 3.6 1994/03/09 02:11:49 lindner
140 * Use DCLsystem for VMS
141 *
142 * Revision 3.5 1994/03/08 17:23:17 lindner
143 * Fix for return vals
144 *
145 * Revision 3.4 1994/03/08 06:17:15 lindner
146 * Nuke compiler warnings
147 *
148 * Revision 3.3 1994/03/08 03:22:39 lindner
149 * Additions for process management
150 *
151 * Revision 3.2 1994/03/04 17:43:36 lindner
152 * Fix for weird error
153 *
154 * Revision 3.1 1994/02/20 16:20:48 lindner
155 * New object based versions of buffered io routines
156 *
157 *
158 *********************************************************************/
159
160 #include "fileio.h"
161 #include "Malloc.h"
162
163 #include <errno.h>
164 #include "Debug.h"
165 #include "Wait.h"
166 #include "String.h"
167 #include "Stdlib.h"
168 #include "compatible.h"
169
170 #ifdef VMS
171 # include <stat.h>
172 #else
173 # include <sys/stat.h>
174 #endif
175
176 #ifdef MMAP_IO
177 # include <sys/mman.h>
178 # ifndef MAP_FILE
179 # define MAP_FILE 0
180 # endif
181 #endif
182
183 static char ** FIOgetargv(char *cmd);
184
185
186 /*
187 * Cache of used fios
188 */
189
190 static FileIO* FIOusedfios[FIOMAXOFILES];
191 static int FIOnumusedfios = -1;
192
193 /*
194 * Pop a recently used item.
195 */
196
FIOpopUsedfio()197 static FileIO *FIOpopUsedfio()
198 {
199 if (FIOnumusedfios > 0) {
200 return(FIOusedfios[--FIOnumusedfios]);
201 } else
202 return(NULL);
203 }
204
205 /*
206 * Push an item on our recently used stack.
207 */
208
FIOpushUsedfio(FileIO * oldfio)209 static boolean FIOpushUsedfio(FileIO *oldfio)
210 {
211 if (FIOnumusedfios < FIOMAXOFILES) {
212 FIOusedfios[FIOnumusedfios++] = oldfio;
213 return(0);
214 } else
215 return(-1);
216 }
217
218 static FileIO *
FIOnew()219 FIOnew()
220 {
221 FileIO *temp;
222
223 if (FIOnumusedfios == -1) {
224 int i;
225 /* Initialize the usedfios struct the first time through */
226 for (i=0; i < FIOMAXOFILES; i++) {
227 FIOusedfios[i] = NULL;
228 }
229 FIOnumusedfios=0;
230 }
231
232 temp = FIOpopUsedfio();
233 if (temp == NULL) {
234 temp = (FileIO *) malloc(sizeof(FileIO));
235 temp->filename = STRnew();
236 } else {
237 STRinit(temp->filename);
238 }
239
240
241 temp->issocket = -1;
242 temp->pid = -1;
243 temp->fd = (pid_t) -1;
244 temp->buf = NULL;
245
246 temp->bufindex = -1;
247 temp->bufdatasize = -1;
248 temp->filename = STRnew();
249
250
251 return(temp);
252 }
253
254
255 /*
256 * Should only be called by FIOclose* functions really..
257 */
258
259 void
FIOdestroy(FileIO * fio)260 FIOdestroy(FileIO *fio)
261 {
262 if (FIOpushUsedfio(fio)) {
263 /** No space in cache. **/
264 free(fio);
265 }
266 }
267
268 /*
269 * Open a file, initialize data structures.
270 */
271
272 FileIO *
FIOopenUFS(char * fname,int flags,int mode)273 FIOopenUFS(char *fname, int flags, int mode)
274 {
275 int fd;
276 FileIO *fio;
277 struct stat buf;
278
279 if (fname == NULL)
280 return(NULL);
281
282 /* Okay, try and open up the file */
283 fd = open(fname, flags, mode );
284
285 if (fd < 0)
286 return(NULL); /* Couldn't open file */
287
288 if (fstat(fd, &buf)) {
289 close(fd);
290 return(NULL); /* Couldn't open anything */
291 }
292
293 fio = FIOnew();
294
295 FIOsetSocket(fio, FALSE);
296 FIOsetFilename(fio, fname);
297 FIOsetfd(fio,fd);
298
299 return(fio);
300 }
301
302
303 /*
304 * Start FIO routines on an already open file descriptor
305 */
306
307 FileIO*
FIOopenfd(int fd,boolean issocket)308 FIOopenfd(int fd, boolean issocket)
309 {
310 FileIO *fio;
311
312 fio = FIOnew();
313
314 FIOsetfd(fio, fd);
315 FIOsetSocket(fio, issocket);
316 return(fio);
317 }
318
319 FileIO*
FIOopenProcess(char * prog,char ** args,char * rw)320 FIOopenProcess(char *prog, char **args, char *rw)
321 {
322 int pfd[2];
323 int pid;
324 FileIO *fio;
325
326 if (prog == NULL)
327 return(NULL);
328
329 fio = FIOnew();
330
331 dup(0); /*** Arghh!! pipe doesn't work right when all fds are closed! */
332
333 if (pipe(pfd) < 0)
334 return(NULL);
335
336
337 switch (pid = vfork()) {
338 case -1: /* Error */
339 (void) close(pfd[0]);
340 (void) close(pfd[1]);
341 break;
342 case 0: /* Child */
343 if (rw == NULL || *rw == '\0') {
344 /** mimic system(), don't do anything **/
345 (void) close(pfd[0]);
346 (void) close(pfd[1]);
347 }
348 else if (*rw == 'r') {
349 if (pfd[1] != 1) {
350 dup2(pfd[1], 1);
351 (void) close(pfd[1]);
352 }
353
354 (void) close(pfd[0]);
355 } else {
356 if (pfd[0] != 0) {
357 dup2(pfd[0], 0);
358 (void) close(pfd[0]);
359 }
360 (void) close(pfd[1]);
361 }
362 #ifdef VMS
363 execv(prog, args);
364 #else
365 /** Unix **/
366
367 if (*prog == '/')
368 execv(prog, args);
369 else
370 execvp(prog, args); /* search the path for the command */
371 #endif
372
373 _exit(1);
374 }
375
376 /* parent.. */
377 if (rw == NULL || *rw == '\0') {
378 /** Don't do anything, mimic system() **/
379 FIOsetfd(fio, -1);
380 (void) close(pfd[0]);
381 (void) close(pfd[1]);
382 } else if (*rw == 'r') {
383 FIOsetfd(fio, pfd[0]);
384 (void) close(pfd[1]);
385 } else {
386 FIOsetfd(fio, pfd[1]);
387 (void) close(pfd[0]);
388 }
389 FIOsetPid(fio, pid);
390 FIOsetSocket(fio, FALSE);
391 return(fio);
392 }
393
394
395 /*
396 * Close a file/socket/process
397 */
398
399 int
FIOclose(FileIO * fio)400 FIOclose(FileIO *fio)
401 {
402 int result;
403
404 if (fio == NULL)
405 return(0);
406
407 if (FIOgetPid(fio) >= 0) {
408
409 close(FIOgetfd(fio));
410 result = FIOwaitpid(fio);
411 FIOdestroy(fio);
412
413 return(result);
414 }
415
416
417 #ifdef MMAP_IO
418 /** Unmap memory mapped I/O stuff here.. **/
419 if (FIOgetFilename(fio) != NULL && fio->buf != NULL)
420 munmap(fio->buf, FIOgetBufDsize(fio));
421
422 #endif
423
424 result = FIOisSocket(fio) ? socket_close(FIOgetfd(fio)) :
425 close(FIOgetfd(fio));
426
427 FIOdestroy(fio);
428
429 return(result);
430 }
431
432 /*
433 * A portable waitpid fcn that returns the exit value of the child process
434 *
435 * Should be better about stopped and signaled processes....
436 */
437
438 int
FIOwaitpid(FileIO * fio)439 FIOwaitpid(FileIO *fio)
440 {
441 Portawait status;
442 pid_t result;
443
444
445 do {
446 errno = 0;
447 result = waitpid(FIOgetPid(fio), &status, 0);
448 } while (result != FIOgetPid(fio) && (errno == ECHILD));
449
450 return(Gwaitstatus(status) & 0xf);
451 }
452
453 /*
454 * write n bytes to an fd..
455 *
456 * returns -1 on error.
457 */
458
459 int
FIOwriten(FileIO * fio,char * ptr,int nbytes)460 FIOwriten(FileIO *fio, char *ptr, int nbytes)
461 {
462 int nleft, nwritten;
463 int fd = FIOgetfd(fio);
464
465 nleft = nbytes;
466 while(nleft > 0) {
467 nwritten = FIOisSocket(fio) ? socket_write(fd, ptr, nleft) :
468 write(fd, ptr, nleft);
469
470 if (nwritten <= 0)
471 return(nwritten); /* error */
472
473 nleft -= nwritten;
474 ptr += nwritten;
475 }
476 return(nbytes - nleft);
477 }
478
479 /*
480 * write a string to a FileDescriptor, eventually buffer outgoing input
481 *
482 * If write fails a -1 is returned. Otherwise zero is returned.
483 */
484
485 int
FIOwritestring(FileIO * fio,char * str)486 FIOwritestring(FileIO *fio, char *str)
487 {
488 int length;
489
490 Debug("writing: %s\n",str);
491
492 if (str == NULL)
493 return(0);
494
495 length = strlen(str);
496 if (FIOwriten(fio, str, length) != length) {
497 Debugmsg("writestring: writen failed\n");
498 return(-1);
499 }
500 else
501 return(0);
502 }
503
504 #ifdef MMAP_IO
505 static int
FIOreadbuf_mmap(FileIO * fio,char * newbuf,int newbuflen)506 FIOreadbuf_mmap(FileIO *fio, char *newbuf, int newbuflen)
507 {
508 struct stat buf;
509 char *bytes;
510
511 if (FIOgetFilename(fio) != NULL) {
512 /** Do MMAP IO if we can... **/
513
514 if (fio->buf == NULL) {
515 if (fstat(FIOgetfd(fio), &buf)) {
516 close(FIOgetfd(fio));
517 return(-1);
518 }
519
520 if (buf.st_size == 0)
521 return(0);
522
523 FIOsetBufDsize(fio, buf.st_size);
524 FIOsetBufIndex(fio, 0);
525
526 bytes = mmap(0, buf.st_size, PROT_READ,
527 MAP_SHARED | MAP_FILE,
528 FIOgetfd(fio), 0);
529 #ifdef HAVE_MADVISE
530 madvise(bytes, buf.st_size, MADV_SEQUENTIAL);
531 #endif
532
533 if (bytes == (caddr_t) -1)
534 return(-1);
535 fio->buf = bytes;
536 }
537
538 if (FIOgetBufIndex(fio) == -1)
539 return(0);
540
541 /** Okay, lets return some data... **/
542 if (FIOgetBufIndex(fio) >= FIOgetBufDsize(fio))
543 return(0);
544
545 if ((FIOgetBufIndex(fio) + newbuflen) > FIOgetBufDsize(fio)) {
546 newbuflen = FIOgetBufDsize(fio) - FIOgetBufIndex(fio);
547 }
548 memcpy(newbuf, fio->buf+FIOgetBufIndex(fio), newbuflen);
549 FIOsetBufIndex(fio, FIOgetBufIndex(fio) + newbuflen);
550
551 return(newbuflen);
552 }
553 /** This is an error condition **/
554 return(-1);
555
556 }
557 #endif
558
559 /*
560 * Read through a buffer, more efficient for character at a time
561 * processing. Not so good for block binary transfers
562 */
563
564 int
FIOreadbuf(FileIO * fio,char * newbuf,int newbuflen)565 FIOreadbuf(FileIO *fio, char *newbuf, int newbuflen)
566 {
567 int len;
568 int fd = FIOgetfd(fio);
569 char *recvbuf;
570 int bytesread = 0;
571
572 #ifdef MMAP_IO
573 if (FIOisMMAPable(fio)) {
574 return(FIOreadbuf_mmap(fio,newbuf, newbuflen));
575 }
576 #endif
577
578 if (FIOgetBufIndex(fio) == -1) {
579
580 if (fio->buf == NULL)
581 fio->buf = (char *) malloc(sizeof(char) * FIOBUFSIZE);
582
583 len = FIOisSocket(fio) ? socket_read(fd, fio->buf, FIOBUFSIZE) :
584 read(fd, fio->buf, FIOBUFSIZE);
585
586 #if defined(FIO_NOMULTIEOF)
587 if (len < 0 && errno == EPIPE) { /** EOF **/
588 FIOsetBufIndex(fio,-1);
589 return(0);
590 }
591 #endif
592
593 FIOsetBufDsize(fio, len);
594 FIOsetBufIndex(fio, 0);
595
596 if (len == 0) {
597 FIOsetBufIndex(fio,-1);
598 return(bytesread); /** EOF **/
599 }
600
601 }
602 recvbuf = fio->buf;
603
604 while (newbuflen--) {
605 *newbuf++ = recvbuf[FIOgetBufIndex(fio)++];
606 bytesread++;
607
608 if (FIOgetBufIndex(fio) == FIOgetBufDsize(fio) && newbuflen != 0) {
609 /** Read another buffer **/
610 len = FIOisSocket(fio) ? socket_read(fd, fio->buf, FIOBUFSIZE) :
611 read(fd, fio->buf, FIOBUFSIZE);
612 #if defined(FIO_NOMULTIEOF)
613 if (len < 0 && errno == EPIPE) { /** EOF **/
614 len = 0;
615 errno = 0;
616 }
617 #endif
618
619 if (len == 0) {
620 FIOsetBufIndex(fio,-1);
621 return(bytesread); /** EOF **/
622 }
623 if (len < 0)
624 return(len); /** Error **/
625
626 FIOsetBufDsize(fio, len);
627 FIOsetBufIndex(fio, 0);
628 } else if (FIOgetBufIndex(fio) >= FIOgetBufDsize(fio))
629 /* Read a new buffer next time through */
630 FIOsetBufIndex(fio, -1);
631 }
632 return(bytesread);
633
634 }
635
636
637 /* Read 'n' bytes from a descriptor, non buffered direct into the storage. */
638 int
FIOreadn(FileIO * fio,char * ptr,int nbytes)639 FIOreadn(FileIO *fio, char *ptr, int nbytes)
640 {
641 int nleft, nread;
642 int fd = FIOgetfd(fio);
643
644 nleft = nbytes;
645 while (nleft > 0) {
646 nread = FIOisSocket(fio) ? socket_read(fd, ptr, nleft) :
647 read(fd, ptr, nleft);
648 #if defined(FIO_NOMULTIEOF)
649 if (nread < 0 && errno == EPIPE) { /** EOF **/
650 nread = 0;
651 errno = 0;
652 }
653 #endif
654
655 if (nread < 0)
656 return(nread); /* error, return < 0 */
657 else if (nread == 0) /* EOF */
658 break;
659
660 nleft -= nread;
661 ptr += nread;
662 }
663 return(nbytes - nleft);
664
665 }
666
667
668 /*
669 * Read a line from the file/socket, Read the line one byte at a time,
670 * looking for the newline. We store the newline in the buffer,
671 * then follow it with a null (the same as fgets(3)).
672 * We return the number of characters up to, but not including,
673 * the null (the same as strlen(3))
674 */
675
676 int
FIOreadline(FileIO * fio,char * ptr,int maxlen)677 FIOreadline(FileIO *fio, char *ptr, int maxlen)
678 {
679 int bytesread;
680 int rc;
681 char c;
682
683 for (bytesread=1; bytesread < maxlen; bytesread++) {
684 if ( (rc = FIOreadbuf(fio, &c, 1)) == 1) {
685 *ptr++ = c;
686 if (c == '\n')
687 break;
688 }
689 else if (rc == 0) {
690 if (bytesread == 1)
691 return(0); /* EOF, no data read */
692 else
693 break; /* EOF, some data was read */
694 }
695 else
696 return(rc); /* error */
697 }
698
699 *ptr = 0; /* Tack a NULL on the end */
700 Debug("FIOreadline: %s\n", (ptr-bytesread));
701
702 return(bytesread);
703 }
704
705
706 /*
707 * This does the same as readline, except that all newlines and
708 * carriage returns are automatically zapped.
709 *
710 * More efficient than doing a readline and a ZapCRLF
711 */
712
713 int
FIOreadlinezap(FileIO * fio,char * ptr,int maxlen)714 FIOreadlinezap(FileIO *fio, char *ptr, int maxlen)
715 {
716 int len;
717
718 len = FIOreadtoken(fio, ptr, maxlen, '\n');
719 ptr += len;
720 ptr --;
721
722 if (len && *ptr == '\r') {
723 ptr[len] = '\0';
724 len--;
725 }
726 return(len);
727 }
728
729
730 /*
731 * Read a line from the file/socket, Read the line one byte at a time,
732 * looking for the token. We nuke the token from the returned string.
733 * We return the number of characters up to, but not including,
734 * the null (the same as strlen(3))
735 */
736
737 int
FIOreadtoken(FileIO * fio,char * ptr,int maxlen,char zechar)738 FIOreadtoken(FileIO *fio, char *ptr, int maxlen, char zechar)
739 {
740 int bytesread;
741 int rc;
742 char c;
743
744 for (bytesread=1; bytesread < maxlen; bytesread++) {
745 rc = FIOreadbuf(fio, &c, 1);
746 if (rc == 1) {
747 *ptr++ = c;
748 if (c == zechar) {
749 *(ptr - 1) = '\0';
750 break;
751 }
752 }
753 else if (rc == 0) {
754 if (bytesread == 1)
755 return(0); /* EOF, no data read */
756 else
757 break; /* EOF, some data was read */
758 }
759 else
760 return(rc); /* error */
761 }
762
763 *ptr = 0; /* Tack a NULL on the end */
764 Debug("readtoken: %s\n", (ptr-bytesread));
765 return(bytesread);
766 }
767
768 static int
FIOexecv(char * prog,char ** args)769 FIOexecv(char *prog, char **args)
770 {
771 FileIO *fio;
772 int result;
773
774 #ifdef VMS
775 int i = 0;
776 char buffer[1024];
777
778 /* DCL hog heaven */
779 strcpy(buffer, prog);
780 strcat(buffer, " ");
781
782 while (i++) {
783 if (args[i] == NULL)
784 break;
785
786 strcat(buffer, args[i]);
787 strcat(buffer, " ");
788 }
789 result = DCLsystem(buffer);
790
791 #else
792 fio = FIOopenProcess(prog, args, NULL);
793 result = FIOclose(fio);
794 #endif /* VMS */
795
796 return(result);
797 }
798
799
800 /*
801 * Do the minimal shell/dcl processing
802 */
803
804 static char **
FIOgetargv(char * cmd)805 FIOgetargv(char *cmd)
806 {
807 int inquote = 0;
808 int insquote = 0;
809 int i;
810 static char *argv[128]; /* Sufficient for now.. */
811 int argc = 0;
812 char buf[256];
813 char *cp = buf;
814
815 if (cmd == NULL)
816 return(NULL);
817
818 for (i=0; cmd[i] != '\0'; i++) {
819
820 switch (cmd[i]) {
821
822 case ' ': case '\t':
823 /* Separators */
824 if (insquote || inquote) {
825 *cp = cmd[i]; cp++;
826 break;
827 } else {
828 *cp = '\0';
829 argv[argc++] = strdup(buf);
830 cp = buf;
831
832 /** Get rid of any other whitespace **/
833 while (cmd[i+1] == ' ' || cmd[i+1] == '\t')
834 i++;
835 }
836 break;
837
838 case '"':
839 if (!insquote)
840 inquote = 1-inquote;
841 break;
842
843 case '\'':
844 if (!inquote)
845 insquote = 1-insquote;
846 break;
847
848 case '\\':
849 /* Quote next character if not in quotes */
850 if (insquote || inquote) {
851 *cp = cmd[i]; cp++;
852 } else {
853 *cp = cmd[i+1]; cp++; i++;
854 }
855
856 break;
857
858 default:
859 *cp = cmd[i]; cp++;
860 break;
861 }
862 }
863 if (buf != cp) {
864 *cp = '\0';
865 argv[argc++] = strdup(buf);
866 }
867 argv[argc] = NULL;
868
869 return(argv);
870 }
871
872
873 /*
874 * An emulation of the system() call without the shell
875 * returns the exit status of the child
876 */
877
878 int
FIOsystem(char * cmd)879 FIOsystem(char *cmd)
880 {
881 char **argv;
882 int result, i;
883
884 #ifdef VMS
885 return(DCLsystem(cmd));
886 #else
887
888 if (cmd == NULL || *cmd == '\0')
889 return(-1);
890
891 argv = FIOgetargv(cmd);
892
893 result = FIOexecv(argv[0], argv);
894
895 for (i=0; argv[i] != NULL; i++)
896 free(argv[i]);
897
898 return(result);
899 #endif
900 }
901
902
903
904 /*
905 * Similar to popen...
906 */
907
908 FileIO
FIOopenCmdline(char * cmd,char * rw)909 *FIOopenCmdline(char *cmd, char *rw)
910 {
911 char **argv;
912 FileIO *fio;
913
914 if (cmd == NULL)
915 return(NULL);
916
917 if (*cmd == '|')
918 cmd++;
919
920 argv = FIOgetargv(cmd);
921
922 fio = FIOopenProcess(argv[0], argv, rw);
923
924 return(fio);
925 }
926
927