FILEIO 22-SEP-1995 18:31:48 VAX C V3.2-044 Page 1 V1.0 21-SEP-1995 14:58:44 [GOPHER.G2.VMS2_13.OBJECT]FILEIO.C;3 (1) 1 /***************************************************************************** 2 * JLWilkinson 21-Sep-1995 Use DCLsystem() for client, VMS$system() for server. 3 * F.Macrides 12-May-1995 Deal with UCX's funny EPIPE return value on EOF 4 * immediately after each socket_read(). 5 * F.Macrides 03-Mar-1995 Ensure that file is closed on fstat() error in 6 * FIOopenUFS(). 7 */ 8 /******************************************************************** 9 * lindner 10 * 3.33 11 * 1995/01/02 21:09:46 12 * /home/arcwelder/GopherSrc/CVS/gopher+/object/fileio.c,v 13 * Exp 14 * 15 * Paul Lindner, University of Minnesota CIS. 16 * 17 * Copyright 1991, 92, 93, 94 by the Regents of the University of Minnesota 18 * see the file "Copyright" in the distribution for conditions of use. 19 ********************************************************************* 20 * MODULE: fileio.c 21 * Socket/file input output routines. 22 ********************************************************************* 23 * Revision History: 24 * fileio.c,v 25 * Revision 3.33 1995/01/02 21:09:46 lindner 26 * Fix for UCX menu ordering 27 * 28 * Revision 3.32 1994/12/20 17:09:46 lindner 29 * Fix for binary file retrievals 30 * 31 * Revision 3.31 1994/12/03 02:14:13 lindner 32 * Correct fix for waitpid() code 33 * 34 * Revision 3.30 1994/12/02 00:37:05 lindner 35 * Fix for mail and misc process execution 36 * 37 * Revision 3.29 1994/12/01 00:30:13 lindner 38 * Remove EINTR wait for FIOwaitpid.. sigh.. 39 * 40 * Revision 3.28 1994/11/29 06:30:04 lindner 41 * Make waitpid keep going after an interrupted system call 42 * 43 * Revision 3.27 1994/11/29 04:59:38 lindner 44 * Fix for broken shell scripts with Shell Index type 45 * 46 * Revision 3.26 1994/10/21 02:42:47 lindner 47 * fix for 0 length files 48 * 49 * Revision 3.25 1994/10/19 03:33:57 lindner 50 * Fix nasty bug, combine more code... 51 * 52 * Revision 3.24 1994/10/13 05:26:16 lindner 53 * Compiler complaint fixes 54 * 55 * Revision 3.23 1994/09/29 19:54:57 lindner FILEIO 22-SEP-1995 18:31:48 VAX C V3.2-044 Page 2 V1.0 21-SEP-1995 14:58:44 [GOPHER.G2.VMS2_13.OBJECT]FILEIO.C;3 (1) 56 * Routines to use memory mapped I/O 57 * 58 * Revision 3.22 1994/07/21 22:19:37 lindner 59 * Add filename new and change debug msg 60 * 61 * Revision 3.21 1994/06/29 06:43:04 lindner 62 * Remove VMS message about reversed values, initialize filename 63 * 64 * Revision 3.20 1994/05/25 20:57:20 lindner 65 * Fix for piped play commands 66 * 67 * Revision 3.19 1994/04/25 03:44:42 lindner 68 * Don't block empty FIOsystem() command on VMS. That's what's used for 69 * the '!' or '$' commands, and they've already be checked for permission 70 * in Gopher.c. 71 * 72 * Reversed DCLsystem() return values in CURCurses.c, and eliminated the 73 * reversing kludge in FIOsystem(). 74 * 75 * Fixed break of open() for Alpha. (all From F.Macrides) 76 * 77 * Revision 3.18 1994/04/25 03:37:00 lindner 78 * Modifications for Debug() and mismatched NULL arguments, added Debugmsg 79 * 80 * Revision 3.17 1994/04/25 02:18:46 lindner 81 * Fix for gcc-Wall 82 * 83 * Revision 3.16 1994/04/14 18:14:49 lindner 84 * Fix for closing null files 85 * 86 * Revision 3.15 1994/04/14 15:44:55 lindner 87 * Remove duplicate variable 88 * 89 * Revision 3.14 1994/04/08 21:07:34 lindner 90 * Put back a variable 91 * 92 * Revision 3.13 1994/04/08 20:05:57 lindner 93 * gcc -Wall fixes 94 * 95 * Revision 3.12 1994/04/08 19:15:47 lindner 96 * Fix for old union wait stuff 97 * 98 * Revision 3.11 1994/04/07 22:51:24 lindner 99 * Fix for typecast 100 * 101 * Revision 3.10 1994/04/01 04:43:31 lindner 102 * Fixes for memory leak in argv, and exit status 103 * 104 * Revision 3.9 1994/03/30 21:37:48 lindner 105 * Fix for AIX that doesn't #define unix.. 106 * 107 * Revision 3.8 1994/03/11 00:10:52 lindner 108 * Fix for FIOopenUFS() 109 * 110 * Revision 3.7 1994/03/09 16:57:56 lindner 111 * Fix for other vms system() call 112 * FILEIO 22-SEP-1995 18:31:48 VAX C V3.2-044 Page 3 V1.0 21-SEP-1995 14:58:44 [GOPHER.G2.VMS2_13.OBJECT]FILEIO.C;3 (1) 113 * Revision 3.6 1994/03/09 02:11:49 lindner 114 * Use DCLsystem for VMS 115 * 116 * Revision 3.5 1994/03/08 17:23:17 lindner 117 * Fix for return vals 118 * 119 * Revision 3.4 1994/03/08 06:17:15 lindner 120 * Nuke compiler warnings 121 * 122 * Revision 3.3 1994/03/08 03:22:39 lindner 123 * Additions for process management 124 * 125 * Revision 3.2 1994/03/04 17:43:36 lindner 126 * Fix for weird error 127 * 128 * Revision 3.1 1994/02/20 16:20:48 lindner 129 * New object based versions of buffered io routines 130 * 131 * 132 *********************************************************************/ 133 134 #include "fileio.h" 2054 #include "Malloc.h" 2267 2268 #include 2367 #include "Debug.h" 2682 #include "Wait.h" 2855 #include "String.h" 3372 #include "Stdlib.h" 3436 3437 #ifdef VMS 3438 # include 3505 #else 3506 X # include 3507 #endif 3508 3509 #ifdef MMAP_IO 3510 X # include 3511 X # ifndef MAP_FILE 3512 X # define MAP_FILE 0 3513 X # endif 3514 #endif 3515 3516 /* 3517 * Cache of used fios 3518 */ 3519 3520 static FileIO* FIOusedfios[FIOMAXOFILES]; 3521 static int FIOnumusedfios = -1; 3522 3523 /* 3524 * Pop a recently used item. 3525 */ 3526 3527 static FileIO *FIOpopUsedfio() 3528 { 3529 1 if (FIOnumusedfios > 0) { FILEIO 22-SEP-1995 18:31:48 VAX C V3.2-044 Page 4 V1.0 21-SEP-1995 14:58:44 [GOPHER.G2.VMS2_13.OBJECT]FILEIO.C;3 (1) 3530 2 return(FIOusedfios[--FIOnumusedfios]); 3531 2 } else 3532 1 return(NULL); 3533 1 } 3534 3535 /* 3536 * Push an item on our recently used stack. 3537 */ 3538 3539 static boolean FIOpushUsedfio(oldfio) 3540 FileIO *oldfio; 3541 { 3542 1 if (FIOnumusedfios < FIOMAXOFILES) { 3543 2 FIOusedfios[FIOnumusedfios++] = oldfio; 3544 2 return(0); 3545 2 } else 3546 1 return(-1); 3547 1 } 3548 3549 static FileIO * 3550 FIOnew() 3551 { 3552 1 FileIO *temp; 3553 1 3554 1 if (FIOnumusedfios == -1) { 3555 2 int i; 3556 2 /* Initialize the usedfios struct the first time through */ 3557 2 for (i=0; i < FIOMAXOFILES; i++) { 3558 3 FIOusedfios[i] = NULL; 3559 3 } 3560 2 FIOnumusedfios=0; 3561 2 } 3562 1 3563 1 temp = FIOpopUsedfio(); 3564 1 if (temp == NULL) { 3565 2 temp = (FileIO *) malloc(sizeof(FileIO)); 3566 2 temp->filename = STRnew(); 3567 2 } else { 3568 2 STRinit(temp->filename); 3569 2 } 3570 1 3571 1 3572 1 temp->issocket = -1; 3573 1 temp->pid = -1; 3574 1 temp->fd = (pid_t) -1; 3575 1 temp->buf = NULL; 3576 1 3577 1 temp->bufindex = -1; 3578 1 temp->bufdatasize = -1; 3579 1 temp->filename = STRnew(); 3580 1 3581 1 3582 1 return(temp); 3583 1 } 3584 3585 3586 /* FILEIO 22-SEP-1995 18:31:48 VAX C V3.2-044 Page 5 V1.0 21-SEP-1995 14:58:44 [GOPHER.G2.VMS2_13.OBJECT]FILEIO.C;3 (1) 3587 * Should only be called by FIOclose* functions really.. 3588 */ 3589 3590 void 3591 FIOdestroy(fio) 3592 FileIO *fio; 3593 { 3594 1 if (FIOpushUsedfio(fio)) { 3595 2 /** No space in cache. **/ 3596 2 free(fio); 3597 2 } 3598 1 } 3599 3600 /* 3601 * Open a file, initialize data structures. 3602 */ 3603 3604 FileIO * 3605 FIOopenUFS(fname, flags, mode) 3606 char *fname; 3607 int flags; 3608 int mode; 3609 { 3610 1 int fd; 3611 1 FileIO *fio; 3612 1 struct stat buf; 3613 1 3614 1 if (fname == NULL) 3615 1 return(NULL); 3616 1 3617 1 /* Okay, try and open up the file */ 3618 1 fd = open(fname, flags, mode ); 3619 1 3620 1 if (fd < 0) 3621 1 return(NULL); /* Couldn't open file */ 3622 1 3623 1 if (fstat(fd, &buf)) { 3624 2 close(fd); 3625 2 return(NULL); /* Couldn't open anything */ 3626 2 } 3627 1 3628 1 fio = FIOnew(); 3629 1 3630 1 FIOsetSocket(fio, FALSE); 3631 1 FIOsetFilename(fio, fname); 3632 1 FIOsetfd(fio,fd); 3633 1 3634 1 return(fio); 3635 1 } 3636 3637 3638 /* 3639 * Start FIO routines on an already open file descriptor 3640 */ 3641 3642 FileIO* 3643 FIOopenfd(fd, issocket) FILEIO 22-SEP-1995 18:31:48 VAX C V3.2-044 Page 6 V1.0 21-SEP-1995 14:58:44 [GOPHER.G2.VMS2_13.OBJECT]FILEIO.C;3 (1) 3644 int fd; 3645 boolean issocket; 3646 { 3647 1 FileIO *fio; 3648 1 3649 1 fio = FIOnew(); 3650 1 3651 1 FIOsetfd(fio, fd); 3652 1 FIOsetSocket(fio, issocket); 3653 1 return(fio); 3654 1 } 3655 3656 FileIO* 3657 FIOopenProcess(prog, args, rw) 3658 char *prog; 3659 char **args; 3660 char *rw; 3661 { 3662 1 int pfd[2]; 3663 1 int pid; 3664 1 FileIO *fio; 3665 1 3666 1 if (prog == NULL) 3667 1 return(NULL); 3668 1 3669 1 fio = FIOnew(); 3670 1 3671 1 dup(0); /*** Arghh!! pipe doesn't work right when all fds are closed! */ 3672 1 3673 1 if (pipe(pfd) < 0) 3674 1 return(NULL); 3675 1 3676 1 3677 1 switch (pid = vfork()) { 3678 2 case -1: /* Error */ 3679 2 (void) close(pfd[0]); 3680 2 (void) close(pfd[1]); 3681 2 break; 3682 2 case 0: /* Child */ 3683 2 if (rw == NULL || *rw == '\0') { 3684 3 /** mimic system(), don't do anything **/ 3685 3 (void) close(pfd[0]); 3686 3 (void) close(pfd[1]); 3687 3 } 3688 2 else if (*rw == 'r') { 3689 3 if (pfd[1] != 1) { 3690 4 dup2(pfd[1], 1); 3691 4 (void) close(pfd[1]); 3692 4 } 3693 3 3694 3 (void) close(pfd[0]); 3695 3 } else { 3696 3 if (pfd[0] != 0) { 3697 4 dup2(pfd[0], 0); 3698 4 (void) close(pfd[0]); 3699 4 } 3700 3 (void) close(pfd[1]); FILEIO 22-SEP-1995 18:31:48 VAX C V3.2-044 Page 7 V1.0 21-SEP-1995 14:58:44 [GOPHER.G2.VMS2_13.OBJECT]FILEIO.C;3 (1) 3701 3 } 3702 2 #ifdef VMS 3703 2 execv(prog, args); 3704 2 #else 3705 X /** Unix **/ 3706 X 3707 X if (*prog == '/') 3708 X execv(prog, args); 3709 X else 3710 X execvp(prog, args); /* search the path for the command */ 3711 2 #endif 3712 2 3713 2 _exit(1); 3714 2 } 3715 1 3716 1 /* parent.. */ 3717 1 if (rw == NULL || *rw == '\0') { 3718 2 /** Don't do anything, mimic system() **/ 3719 2 FIOsetfd(fio, -1); 3720 2 (void) close(pfd[0]); 3721 2 (void) close(pfd[1]); 3722 2 } else if (*rw == 'r') { 3723 2 FIOsetfd(fio, pfd[0]); 3724 2 (void) close(pfd[1]); 3725 2 } else { 3726 2 FIOsetfd(fio, pfd[1]); 3727 2 (void) close(pfd[0]); 3728 2 } 3729 1 FIOsetPid(fio, pid); 3730 1 FIOsetSocket(fio, FALSE); 3731 1 return(fio); 3732 1 } 3733 3734 3735 /* 3736 * Close a file/socket/process 3737 */ 3738 3739 int 3740 FIOclose(fio) 3741 FileIO *fio; 3742 { 3743 1 int result; 3744 1 3745 1 if (fio == NULL) 3746 1 return(0); 3747 1 3748 1 if (FIOgetPid(fio) >= 0) { 3749 2 3750 2 close(FIOgetfd(fio)); 3751 2 result = FIOwaitpid(fio); 3752 2 FIOdestroy(fio); 3753 2 3754 2 return(result); 3755 2 } 3756 1 3757 1 FILEIO 22-SEP-1995 18:31:48 VAX C V3.2-044 Page 8 V1.0 21-SEP-1995 14:58:44 [GOPHER.G2.VMS2_13.OBJECT]FILEIO.C;3 (1) 3758 1 #ifdef MMAP_IO 3759 X /** Unmap memory mapped I/O stuff here.. **/ 3760 X if (FIOgetFilename(fio) != NULL && fio->buf != NULL) 3761 X munmap(fio->buf, FIOgetBufDsize(fio)); 3762 X 3763 1 #endif 3764 1 3765 1 result = FIOisSocket(fio) ? socket_close(FIOgetfd(fio)) : 3766 1 close(FIOgetfd(fio)); 3767 1 3768 1 FIOdestroy(fio); 3769 1 3770 1 return(result); 3771 1 } 3772 3773 /* 3774 * A portable waitpid fcn that returns the exit value of the child process 3775 * 3776 * Should be better about stopped and signaled processes.... 3777 */ 3778 3779 int 3780 FIOwaitpid(fio) 3781 FileIO *fio; 3782 { 3783 1 Portawait status; 3784 1 pid_t result; 3785 1 3786 1 3787 1 do { 3788 2 result = waitpid(FIOgetPid(fio), &status, 0); 3789 2 } while (result != FIOgetPid(fio) && (errno == EINTR)); 3790 1 3791 1 return(Gwaitstatus(status) & 0xf); 3792 1 } 3793 3794 /* 3795 * write n bytes to an fd.. 3796 * 3797 * returns -1 on error. 3798 */ 3799 3800 int 3801 FIOwriten(fio, ptr, nbytes) 3802 FileIO *fio; 3803 char *ptr; 3804 int nbytes; 3805 { 3806 1 int nleft, nwritten; 3807 1 int fd = FIOgetfd(fio); 3808 1 3809 1 nleft = nbytes; 3810 1 while(nleft > 0) { 3811 2 nwritten = FIOisSocket(fio) ? socket_write(fd, ptr, nleft) : 3812 2 write(fd, ptr, nleft); 3813 2 3814 2 if (nwritten <= 0) FILEIO 22-SEP-1995 18:31:48 VAX C V3.2-044 Page 9 V1.0 21-SEP-1995 14:58:44 [GOPHER.G2.VMS2_13.OBJECT]FILEIO.C;3 (1) 3815 2 return(nwritten); /* error */ 3816 2 3817 2 nleft -= nwritten; 3818 2 ptr += nwritten; 3819 2 } 3820 1 return(nbytes - nleft); 3821 1 } 3822 3823 /* 3824 * write a string to a FileDescriptor, eventually buffer outgoing input 3825 * 3826 * If write fails a -1 is returned. Otherwise zero is returned. 3827 */ 3828 3829 int 3830 FIOwritestring(fio, str) 3831 FileIO *fio; 3832 char *str; 3833 { 3834 1 int length; 3835 1 3836 1 Debug("writing: %s\n",str); 3837 1 3838 1 if (str == NULL) 3839 1 return(0); 3840 1 3841 1 length = strlen(str); 3842 1 if (FIOwriten(fio, str, length) != length) { 3843 2 Debugmsg("writestring: writen failed\n"); 3844 2 return(-1); 3845 2 } 3846 1 else 3847 1 return(0); 3848 1 } 3849 3850 #ifdef MMAP_IO 3851 X int 3852 X FIOreadbuf_mmap(fio, newbuf, newbuflen) 3853 X FileIO *fio; 3854 X char *newbuf; 3855 X int newbuflen; 3856 X { 3857 X struct stat buf; 3858 X char *bytes; 3859 X 3860 X if (FIOgetFilename(fio) != NULL) { 3861 X /** Do MMAP IO if we can... **/ 3862 X 3863 X if (fio->buf == NULL) { 3864 X if (fstat(FIOgetfd(fio), &buf)) 3865 X return(-1); 3866 X 3867 X if (buf.st_size == 0) 3868 X return(0); 3869 X 3870 X FIOsetBufDsize(fio, buf.st_size); 3871 X FIOsetBufIndex(fio, 0); FILEIO 22-SEP-1995 18:31:48 VAX C V3.2-044 Page 10 V1.0 21-SEP-1995 14:58:44 [GOPHER.G2.VMS2_13.OBJECT]FILEIO.C;3 (1) 3872 X 3873 X bytes = mmap(0, buf.st_size, PROT_READ, 3874 X MAP_SHARED | MAP_FILE, 3875 X FIOgetfd(fio), 0); 3876 X madvise(bytes, buf.st_size, MADV_SEQUENTIAL); 3877 X 3878 X if (bytes == (caddr_t) -1) 3879 X return(-1); 3880 X fio->buf = bytes; 3881 X } 3882 X 3883 X if (FIOgetBufIndex(fio) == -1) 3884 X return(0); 3885 X 3886 X /** Okay, lets return some data... **/ 3887 X if (FIOgetBufIndex(fio) >= FIOgetBufDsize(fio)) 3888 X return(0); 3889 X 3890 X if ((FIOgetBufIndex(fio) + newbuflen) > FIOgetBufDsize(fio)) { 3891 X newbuflen = FIOgetBufDsize(fio) - FIOgetBufIndex(fio); 3892 X } 3893 X memcpy(newbuf, fio->buf+FIOgetBufIndex(fio), newbuflen); 3894 X FIOsetBufIndex(fio, FIOgetBufIndex(fio) + newbuflen); 3895 X 3896 X return(newbuflen); 3897 X } 3898 X /** This is an error condition **/ 3899 X return(-1); 3900 X 3901 X } 3902 #endif 3903 3904 /* 3905 * Read through a buffer, more efficient for character at a time 3906 * processing. Not so good for block binary transfers 3907 */ 3908 3909 int 3910 FIOreadbuf(fio, newbuf, newbuflen) 3911 FileIO *fio; 3912 char *newbuf; 3913 int newbuflen; 3914 { 3915 1 int len; 3916 1 int fd = FIOgetfd(fio); 3917 1 char *recvbuf; 3918 1 int bytesread = 0; 3919 1 3920 1 #ifdef MMAP_IO 3921 X if (FIOisMMAPable(fio)) { 3922 X return(FIOreadbuf_mmap(fio,newbuf, newbuflen)); 3923 X } 3924 1 #endif 3925 1 3926 1 if (FIOgetBufIndex(fio) == -1) { 3927 2 3928 2 if (fio->buf == NULL) FILEIO 22-SEP-1995 18:31:48 VAX C V3.2-044 Page 11 V1.0 21-SEP-1995 14:58:44 [GOPHER.G2.VMS2_13.OBJECT]FILEIO.C;3 (1) 3929 2 fio->buf = (char *) malloc(sizeof(char) * FIOBUFSIZE); 3930 2 3931 2 len = FIOisSocket(fio) ? socket_read(fd, fio->buf, FIOBUFSIZE) : 3932 2 read(fd, fio->buf, FIOBUFSIZE); 3933 2 #if defined(FIO_NOMULTIEOF) 3934 X if (len < 0 && errno == EPIPE) { /** EOF **/ 3935 X len = 0; 3936 X errno = 0; 3937 X } 3938 2 #endif 3939 2 FIOsetBufDsize(fio, len); 3940 2 FIOsetBufIndex(fio, 0); 3941 2 3942 2 if (len == 0) { 3943 3 FIOsetBufIndex(fio,-1); 3944 3 return(bytesread); /** EOF **/ 3945 3 } 3946 2 3947 2 } 3948 1 recvbuf = fio->buf; 3949 1 3950 1 while (newbuflen--) { 3951 2 *newbuf++ = recvbuf[FIOgetBufIndex(fio)++]; 3952 2 bytesread++; 3953 2 3954 2 if (FIOgetBufIndex(fio) == FIOgetBufDsize(fio) && newbuflen != 0) { 3955 3 /** Read another buffer **/ 3956 3 len = FIOisSocket(fio) ? socket_read(fd, fio->buf, FIOBUFSIZE) : 3957 3 read(fd, fio->buf, FIOBUFSIZE); 3958 3 #if defined(FIO_NOMULTIEOF) 3959 X if (len < 0 && errno == EPIPE) { /** EOF **/ 3960 X len = 0; 3961 X errno = 0; 3962 X } 3963 3 #endif 3964 3 3965 3 if (len == 0) { 3966 4 FIOsetBufIndex(fio,-1); 3967 4 return(bytesread); /** EOF **/ 3968 4 } 3969 3 if (len < 0) 3970 3 return(len); /** Error **/ 3971 3 3972 3 FIOsetBufDsize(fio, len); 3973 3 FIOsetBufIndex(fio, 0); 3974 3 } else if (FIOgetBufIndex(fio) >= FIOgetBufDsize(fio)) 3975 2 /* Read a new buffer next time through */ 3976 2 FIOsetBufIndex(fio, -1); 3977 2 } 3978 1 return(bytesread); 3979 1 3980 1 } 3981 3982 3983 /* Read 'n' bytes from a descriptor, non buffered direct into the storage. */ 3984 int 3985 FIOreadn(fio, ptr, nbytes) FILEIO 22-SEP-1995 18:31:48 VAX C V3.2-044 Page 12 V1.0 21-SEP-1995 14:58:44 [GOPHER.G2.VMS2_13.OBJECT]FILEIO.C;3 (1) 3986 FileIO *fio; 3987 char *ptr; 3988 int nbytes; 3989 { 3990 1 int nleft, nread; 3991 1 int fd = FIOgetfd(fio); 3992 1 3993 1 nleft = nbytes; 3994 1 while (nleft > 0) { 3995 2 nread = FIOisSocket(fio) ? socket_read(fd, ptr, nleft) : 3996 2 read(fd, ptr, nleft); 3997 2 #if defined(FIO_NOMULTIEOF) 3998 X if (nread < 0 && errno == EPIPE) { /* EOF */ 3999 X nread = 0; 4000 X errno = 0; 4001 X } 4002 2 #endif 4003 2 4004 2 if (nread < 0) 4005 2 return(nread); /* error, return < 0 */ 4006 2 else if (nread == 0) /* EOF */ 4007 2 break; 4008 2 4009 2 nleft -= nread; 4010 2 ptr += nread; 4011 2 } 4012 1 return(nbytes - nleft); 4013 1 4014 1 } 4015 4016 4017 /* 4018 * Read a line from the file/socket, Read the line one byte at a time, 4019 * looking for the newline. We store the newline in the buffer, 4020 * then follow it with a null (the same as fgets(3)). 4021 * We return the number of characters up to, but not including, 4022 * the null (the same as strlen(3)) 4023 */ 4024 4025 int 4026 FIOreadline(fio, ptr, maxlen) 4027 FileIO *fio; 4028 char *ptr; 4029 int maxlen; 4030 { 4031 1 int bytesread; 4032 1 int rc; 4033 1 char c; 4034 1 4035 1 for (bytesread=1; bytesread < maxlen; bytesread++) { 4036 2 if ( (rc = FIOreadbuf(fio, &c, 1)) == 1) { 4037 3 *ptr++ = c; 4038 3 if (c == '\n') 4039 3 break; 4040 3 } 4041 2 else if (rc == 0) { 4042 3 if (bytesread == 1) FILEIO 22-SEP-1995 18:31:48 VAX C V3.2-044 Page 13 V1.0 21-SEP-1995 14:58:44 [GOPHER.G2.VMS2_13.OBJECT]FILEIO.C;3 (1) 4043 3 return(0); /* EOF, no data read */ 4044 3 else 4045 3 break; /* EOF, some data was read */ 4046 3 } 4047 2 else 4048 2 return(-1); /* error */ 4049 2 } 4050 1 4051 1 *ptr = 0; /* Tack a NULL on the end */ 4052 1 Debug("FIOreadline: %s\n", (ptr-bytesread)); 4053 1 4054 1 return(bytesread); 4055 1 } 4056 4057 4058 /* 4059 * This does the same as readline, except that all newlines and 4060 * carriage returns are automatically zapped. 4061 * 4062 * More efficient than doing a readline and a ZapCRLF 4063 */ 4064 4065 int 4066 FIOreadlinezap(fio, ptr, maxlen) 4067 FileIO *fio; 4068 char *ptr; 4069 int maxlen; 4070 { 4071 1 int len; 4072 1 4073 1 len = FIOreadtoken(fio, ptr, maxlen, '\n'); 4074 1 ptr += len; 4075 1 ptr --; 4076 1 4077 1 if (*ptr == '\r') { 4078 2 ptr[len] = '\0'; 4079 2 len--; 4080 2 } 4081 1 return(len); 4082 1 } 4083 4084 4085 /* 4086 * Read a line from the file/socket, Read the line one byte at a time, 4087 * looking for the token. We nuke the token from the returned string. 4088 * We return the number of characters up to, but not including, 4089 * the null (the same as strlen(3)) 4090 */ 4091 4092 int 4093 FIOreadtoken(fio, ptr, maxlen, zechar) 4094 FileIO *fio; 4095 char *ptr; 4096 int maxlen; 4097 char zechar; 4098 { 4099 1 int bytesread; FILEIO 22-SEP-1995 18:31:48 VAX C V3.2-044 Page 14 V1.0 21-SEP-1995 14:58:44 [GOPHER.G2.VMS2_13.OBJECT]FILEIO.C;3 (1) 4100 1 int rc; 4101 1 char c; 4102 1 4103 1 for (bytesread=1; bytesread < maxlen; bytesread++) { 4104 2 rc = FIOreadbuf(fio, &c, 1); 4105 2 if (rc == 1) { 4106 3 *ptr++ = c; 4107 3 if (c == zechar) { 4108 4 *(ptr - 1) = '\0'; 4109 4 break; 4110 4 } 4111 3 } 4112 2 else if (rc == 0) { 4113 3 if (bytesread == 1) 4114 3 return(0); /* EOF, no data read */ 4115 3 else 4116 3 break; /* EOF, some data was read */ 4117 3 } 4118 2 else 4119 2 return(-1); /* error */ 4120 2 } 4121 1 4122 1 *ptr = 0; /* Tack a NULL on the end */ 4123 1 Debug("readtoken: %s\n", (ptr-bytesread)); 4124 1 return(bytesread); 4125 1 } 4126 4127 int 4128 FIOexecv(prog, args) 4129 char *prog; 4130 char **args; 4131 { 4132 1 FileIO *fio; 4133 1 int result; 4134 1 4135 1 #ifdef VMS 4136 1 int i = 0; 4137 1 char buffer[1024]; 4138 1 4139 1 /* DCL hog heaven */ 4140 1 strcpy(buffer, prog); 4141 1 strcat(buffer, " "); 4142 1 4143 1 while (i++) { 4144 2 if (args[i] == NULL) 4145 2 break; 4146 2 4147 2 strcat(buffer, args[i]); 4148 2 strcat(buffer, " "); 4149 2 } 4150 1 result = system(buffer); 4151 1 4152 1 #else 4153 X fio = FIOopenProcess(prog, args, NULL); 4154 X result = FIOclose(fio); 4155 1 #endif /* VMS */ 4156 1 FILEIO 22-SEP-1995 18:31:48 VAX C V3.2-044 Page 15 V1.0 21-SEP-1995 14:58:44 [GOPHER.G2.VMS2_13.OBJECT]FILEIO.C;3 (1) 4157 1 return(result); 4158 1 } 4159 4160 4161 /* 4162 * Do the minimal shell/dcl processing 4163 */ 4164 4165 char ** 4166 FIOgetargv(cmd) 4167 char *cmd; 4168 { 4169 1 int inquote = 0; 4170 1 int insquote = 0; 4171 1 int i; 4172 1 static char *argv[128]; /* Sufficient for now.. */ 4173 1 int argc = 0; 4174 1 char buf[256]; 4175 1 char *cp = buf; 4176 1 4177 1 if (cmd == NULL) 4178 1 return(NULL); 4179 1 4180 1 for (i=0; cmd[i] != '\0'; i++) { 4181 2 4182 2 switch (cmd[i]) { 4183 3 4184 3 case ' ': case '\t': 4185 3 /* Separators */ 4186 3 if (insquote || inquote) { 4187 4 *cp = cmd[i]; cp++; 4188 4 break; 4189 4 } else { 4190 4 *cp = '\0'; 4191 4 argv[argc++] = strdup(buf); 4192 4 cp = buf; 4193 4 4194 4 /** Get rid of any other whitespace **/ 4195 4 while (cmd[i+1] == ' ' || cmd[i+1] == '\t') 4196 4 i++; 4197 4 } 4198 3 break; 4199 3 4200 3 case '"': 4201 3 if (!insquote) 4202 3 inquote = 1-inquote; 4203 3 break; 4204 3 4205 3 case '\'': 4206 3 if (!inquote) 4207 3 insquote = 1-insquote; 4208 3 break; 4209 3 4210 3 case '\\': 4211 3 /* Quote next character if not in quotes */ 4212 3 if (insquote || inquote) { 4213 4 *cp = cmd[i]; cp++; FILEIO 22-SEP-1995 18:31:48 VAX C V3.2-044 Page 16 V1.0 21-SEP-1995 14:58:44 [GOPHER.G2.VMS2_13.OBJECT]FILEIO.C;3 (1) 4214 4 } else { 4215 4 *cp = cmd[i+1]; cp++; i++; 4216 4 } 4217 3 4218 3 break; 4219 3 4220 3 default: 4221 3 *cp = cmd[i]; cp++; 4222 3 break; 4223 3 } 4224 2 } 4225 1 if (buf != cp) { 4226 2 *cp = '\0'; 4227 2 argv[argc++] = strdup(buf); 4228 2 } 4229 1 argv[argc] = NULL; 4230 1 4231 1 return(argv); 4232 1 } 4233 4234 4235 /* 4236 * An emulation of the system() call without the shell 4237 * returns the exit status of the child 4238 */ 4239 4240 int 4241 FIOsystem(cmd) 4242 char *cmd; 4243 { 4244 1 char **argv, i; 4245 1 int result; 4246 1 4247 1 #ifdef VMS 4248 1 return(system(cmd)); 4249 1 #else 4250 X 4251 X if (cmd == NULL || *cmd == '\0') 4252 X return(-1); 4253 X 4254 X argv = FIOgetargv(cmd); 4255 X 4256 X result = FIOexecv(argv[0], argv); 4257 X 4258 X for (i=0; argv[i] != NULL; i++) 4259 X free(argv[i]); 4260 X 4261 X return(result); 4262 1 #endif 4263 1 } 4264 4265 4266 4267 /* 4268 * Similar to popen... 4269 */ 4270 FILEIO 22-SEP-1995 18:31:48 VAX C V3.2-044 Page 17 V1.0 21-SEP-1995 14:58:44 [GOPHER.G2.VMS2_13.OBJECT]FILEIO.C;3 (1) 4271 FileIO 4272 *FIOopenCmdline(cmd, rw) 4273 char *cmd; 4274 char *rw; 4275 { 4276 1 char **argv; 4277 1 FileIO *fio; 4278 1 4279 1 if (cmd == NULL) 4280 1 return(NULL); 4281 1 4282 1 if (*cmd == '|') 4283 1 cmd++; 4284 1 4285 1 argv = FIOgetargv(cmd); 4286 1 4287 1 fio = FIOopenProcess(argv[0], argv, rw); 4288 1 4289 1 return(fio); 4290 1 } 4291 Command Line ------------ CC/INCL=([-],[-.OBJECT])/DEFINE=(MULTINET=1,DEBUGGING,__VMS)/DEBUG/NOOPT/OBJ=[.VAX.DBG]/LIS=[.VAX.LIS] FILEIO.C .