diff options
Diffstat (limited to 'funtools/util/gio.c')
-rw-r--r-- | funtools/util/gio.c | 2314 |
1 files changed, 2314 insertions, 0 deletions
diff --git a/funtools/util/gio.c b/funtools/util/gio.c new file mode 100644 index 0000000..b3dd109 --- /dev/null +++ b/funtools/util/gio.c @@ -0,0 +1,2314 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * + * GIO -- generalized I/O to disk files, streams, and memory + * + */ + +#include <gio.h> +#include <find.h> +#include <word.h> +#include <zlib.h> + +/* + * + * Private Routines + * + */ + +#define GBUFSZ 32768 +static char _gtbuf[GBUFSZ]; + +static char _gerrors[GBUFSZ]; +static int _gerror = -1; + +static char _gwarnings[GBUFSZ]; +static int _gwarning = -1; + +static int _gcrnl = 1; + +/* + * + * gext -- return extension from a file (without bracket extension) + * + */ +#ifdef ANSI_FUNC +static char * +gext(char *fname) +#else +static char *gext(fname) + char *fname; +#endif +{ + char *s, *t=NULL; + char *file; + + if( !fname || !*fname ) + return(NULL); + /* make a working copy */ + file = xstrdup(fname); + /* remove the bracket extension */ + if( (s=strchr(file, '[')) ){ + *s = '\0'; + } + /* look for a file extension */ + if( (s = strrchr(file, '.')) ){ + strncpy(_gtbuf, s, GBUFSZ-2); + _gtbuf[GBUFSZ-1] = '\0'; + t = _gtbuf; + } + /* free working copy */ + if( file ) xfree(file); + /* return extension */ + return(t); +} + + +/* + * + * gnew -- create a new GIO structure + * + */ +#ifdef ANSI_FUNC +static GIO +gnew (void) +#else +static GIO gnew() +#endif +{ + GIO gio; + gio = (GIO)xcalloc(1, sizeof(GFile)); + gio->ifd = -1; + gio->ofd = -1; + return(gio); +} + +/* + * + * gfree -- destroy a GIO structure + * + */ +#ifdef ANSI_FUNC +static void +gfree (GIO gio) +#else +static void gfree(gio) + GIO gio; +#endif +{ + if( gio == NULL ) + return; + if( gio->name ) + xfree(gio->name); + if( gio->mode ) + xfree(gio->mode); + if( gio->crbuf ) + xfree(gio->crbuf); + xfree((void *)gio); +} + + +/* + * + * gmemseek -- memory "seek" of data + * + */ +#ifdef ANSI_FUNC +static off_t +gmemseek (GIO gio, off_t offset, int whence) +#else +static off_t gmemseek(gio, offset, whence) + GIO gio; + off_t offset; + int whence; +#endif +{ + int offset2; + + switch(whence){ + case 0: + offset2 = offset; + break; + case 1: + offset2 = gio->cur + offset; + break; + case 2: + offset2 = gio->len + offset; + break; + default: + return(-1); + } + if( offset2 >= gio->len ){ + if( gio->extend ){ + gio->len = offset2 + 1; + gio->buf = (char *)xrealloc(gio->buf, gio->len); + gio->cur = offset2; + return(0); + } + else{ + return(-1); + } + } else { + gio->cur = offset2; + return(0); + } +} + +/* + * + * gmemread -- memory "read" of data + * + */ +#ifdef ANSI_FUNC +static void * +gmemread (GIO gio, void *buf, size_t size, size_t n, size_t *got) +#else +static void *gmemread(gio, buf, size, n, got) + GIO gio; + void *buf; + size_t size; + size_t n; + size_t *got; +#endif +{ + char *obuf; + + /* sanity checks */ + if( (gio==NULL) || (gio->buf == NULL) ) + return((void *)NULL); + if( !strchr(gio->mode, 'r') && !strstr(gio->mode, "w+") ){ + gerror(stderr, + "illegal read operation on write-only data (%s)\n", gio->name); + return((void *)NULL); + } + /* see how much we can grab to "EOF" */ + if( size <= 0 ) size = 1; + *got = MIN(size*n, ((gio->len - gio->cur)/size)*size); + /* copy bytes, if a buffer was supplied */ + if( buf ){ + obuf = buf; + memmove(obuf, &(gio->buf[gio->cur]), *got); + } + else{ + obuf = &(gio->buf[gio->cur]); + } + /* bump position pointer */ + gio->cur += *got; + /* convert got to elements */ + *got /= size; + /* return buffer */ + return(obuf); +} + +/* + * + * gmemwrite -- memory "write" of data + * + */ +#ifdef ANSI_FUNC +static int +gmemwrite (GIO gio, char *buf, size_t size, size_t n) +#else +static int gmemwrite(gio, buf, size, n) + GIO gio; + char *buf; + size_t size; + size_t n; +#endif +{ + size_t n2; + int len; + + /* sanity checks */ + if( (gio==NULL) || (gio->buf == NULL) ) + return(0); + if( !strchr(gio->mode, 'w') && !strstr(gio->mode, "r+") ){ + gerror(stderr, + "illegal write operation on read-only data (%s)\n", gio->name); + return(0); + } + len = size*n; + /* make sure we have enough space */ + if( gio->cur + len >= gio->len ){ + if( gio->extend ){ + gio->len += MAX(len, GIO_BUFINC); + if( (gio->buf = (char *)xrealloc(gio->buf, gio->len)) != NULL ) + n2 = len; + /* could not grab space -- try just a bit to recover */ + else{ + gerror(stderr, "could not realloc space for memory write\n"); + n2 = 0; + } + } + else{ + n2 = gio->len - gio->cur; + } + } + else + n2 = len; + /* copy bytes */ + memmove(&(gio->buf[gio->cur]), buf, n2); + /* bump pointer */ + gio->cur += n2; + return(n/size); +} + +#if HAVE_MINGW32==0 +/* + * + * gexec -- open a connected subprocess with bidirectional + * IPC channels, implemented with pipes for this version + * + */ +#ifdef ANSI_FUNC +static int +gexec(GIO gio, char *cmd, char *mode) +#else +static int gexec(gio, cmd, mode) + GIO gio; + char *cmd; + char *mode; +#endif +{ + int pin[2], pout[2]; + int maxforks = 3; + char *argv[4096]; + + /* start out pessimisticaly */ + gio->ifd = -1; + gio->ofd = -1; + + /* open pipes */ + pipe(pin); + if( pipe(pout) != 0){ + return(-1); + } + + /* Create child process. The child inherits the open stdio files. + * The fork can fail if swap space is full or if we have too many processes. + */ + while ((gio->pid = fork()) == -1) { + if (--maxforks == 0) { + close(pin[0]); close(pin[1]); + close(pout[0]); close(pout[1]); + return(-1); + } + sleep (2); + } + if(gio->pid == 0) { + /* New child process. Make child think the pipe is its stdin/out. + */ + close(pin[0]); + close(pout[1]); + close(0); dup (pout[0]); close(pout[0]); + close(1); dup (pin[1]); close(pin[1]); + + /* run through shell so that we expand shell meta characters */ + argv[0] = "sh"; + argv[1] = "-c"; + argv[2] = cmd; + argv[3] = NULL; + + /* Exec the new process. Will not return if successful. */ + execvp(argv[0], (void *)argv); + + /* If we get here the new process could not be executed for some + * reason. Shutdown, calling _exit to avoid flushing parent's + * io buffers. + */ + _exit(1); + } else { + /* Existing, parent process. */ + close(pin[1]); + close(pout[0]); + if( strchr(mode, 'r') ) + gio->ifd = pin[0]; + else{ + close(pin[0]); + } + if( strchr(mode, 'w') ) + gio->ofd = pout[1]; + else{ + close(pout[1]); + } + } + /* clean up and return */ + return(0); +} + +/* + * + * gopenpipe -- open a command pipe + * + */ +#ifdef ANSI_FUNC +static GIO +gopenpipe (char *name, char *mode) +#else +static GIO gopenpipe(name, mode) + char *name; + char *mode; +#endif +{ + GIO gio; + char *s; + + /* allocate the new struct */ + if( (gio = gnew()) == NULL ) + return(NULL); + + /* skip past prefix */ + s = name; + if( !strncasecmp(s, "pipe:", 5) ) s += 5; + while( isspace((int)*s) ) s++; + + /* start the piped process */ + if( gexec(gio, s, mode) != 0 ){ + gclose(gio); + return(NULL); + } + + /* fill in the record */ + gio->name = xstrdup(s); + gio->mode = xstrdup(mode); + gio->type = GIO_PIPE; + gio->extend = 0; + return(gio); +} +#endif + +/* + * + * giohostip -- convert ascii host into ip number + * + */ +#ifdef ANSI_FUNC +static unsigned int +giohostip (char *xhost) +#else +static unsigned int giohostip(xhost) + char *xhost; +#endif +{ + struct hostent *hostent; + unsigned int ip; + char temp[SZ_LINE]; + + /* null input means current host */ + if( (xhost == NULL) || (*xhost == '\0') || !strncmp(xhost, "$host", 5) ){ + gethostname(temp, SZ_LINE); + } else { + strcpy(temp, xhost); + } + + /* special check */ + if( !strcmp(temp, "$localhost") ){ + return(0x7F000001); + } + + /* + * Try looking by address (i.e., host is something like "128.84.253.1"). + * Do this first because it's much faster (no trip to the DNS) + */ + if( (int)(ip = inet_addr(temp)) != -1 ){ + return(ntohl(ip)); + } + + /* + * Try looking it up by name. If successful, the IP address is in + * hostent->h_addr_list[0] + */ + if( (hostent = gethostbyname(temp)) != NULL ){ + memcpy(&ip, hostent->h_addr_list[0], (size_t)hostent->h_length); + return(ntohl(ip)); + } + + /* could not convert */ + return(0); +} + +/* + * + * gioparseipport -- parse ascii string into a host and port + * + */ +#ifdef ANSI_FUNC +static int +gioparseipport (char *host, unsigned int *ip, unsigned short *port) +#else +static int gioparseipport(host, ip, port) + char *host; + unsigned int *ip; + unsigned short *port; +#endif +{ + char *s1, *p1, *p2; + int got; + + /* start out pessimistically */ + *ip = 0; + *port = 0; + + /* make sure we have something to work with */ + if( !host || !*host ) + return(0); + + /* we null out ':' (so that what comes before is the host name) and + bump past it to point to the port */ + s1 = xstrdup(host); + if( !(p1 = (char *)strchr(s1, ':')) ){ + got = 0; + goto done; + } + *p1 = '\0'; + p1++; + + /* get port */ + p2 = NULL; + *port = (unsigned short)strtol(p1, &p2, 0); + /* check for bad port number -- we lose */ + if( *port <=0 || (p1 == p2) ){ + *port = 0; + got = 0; + goto done; + } + + /* convert ip string (might be null) to an ip address */ + if( (*ip = giohostip(s1)) == 0 ){ + *port = 0; + got = 0; + } + else{ + got = 1; + } + +done: + xfree(s1); + return(got); +} + +/* + * + * gopensocket -- open a socket for reading and/or writing + * + */ +#ifdef ANSI_FUNC +static GIO +gopensocket (char *name, char *mode) +#else +static GIO gopensocket(name, mode) + char *name; + char *mode; +#endif +{ + char *s; + char tbuf[SZ_LINE]; + int fd=-1; + int fd2=-1; + int status; + int tries; + int reuse_addr=1; + int doaccept=-1; + unsigned int ip; + unsigned short port; + socklen_t slen; + struct sockaddr_in sock_in; + struct timeval tv; + fd_set readfds; + GIO gio; + + /* allocate a new struct */ + if( (gio = gnew()) == NULL ) + return(NULL); + + /* skip past prefix */ + s = name; + if( !strncasecmp(s, "socket:", 7) ) s += 7; + while( isspace((int)*s) ) s++; + + /* if $host is the socket, we might also be specifying whether we + connect ($host_c[onnect]) or accept ($host_a[ccept]). This allows + either end to initiate the connection */ + if( !strncasecmp(s, "$host_a", 7) ){ + doaccept = 1; + s = strchr(s,':'); + } + else if( !strncasecmp(s, "$host_c", 7) ){ + doaccept = 0; + s = strchr(s,':'); + } + while( isspace((int)*s) ) s++; + + /* get host and port number */ + if( !gioparseipport(s, &ip, &port) ) + goto error; + + if( doaccept < 0 ){ + /* see whether we accept or connect */ + if( ip != giohostip(NULL) ){ + doaccept = 0; + } + else{ + if( strchr(mode, 'w') ){ + doaccept = 0; + } + else{ + doaccept = 1; + } + } + } + + /* open socket for reading, i.e., reading 'stdin' from another host */ + if( doaccept ){ + /* set up listening socket, which will accept connection */ + if( (fd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) + goto error; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (char *)&reuse_addr, sizeof(reuse_addr)); + memset((char *)&sock_in, 0, sizeof(sock_in)); + sock_in.sin_family = AF_INET; + sock_in.sin_addr.s_addr = htonl(INADDR_ANY); + sock_in.sin_port = htons(port); + /* bind to a port */ + if( bind(fd, (struct sockaddr *)&sock_in, sizeof(sock_in)) < 0 ) + goto error; + /* listen for connections */ + if( listen(fd, 5) < 0 ) + goto error; + /* use select() to wait for a connect, so that we can timeout */ + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + tv.tv_sec = GIO_TIMEOUT; + tv.tv_usec = 0; + if( select(fd+1, &readfds, NULL, NULL, &tv) <=0) + goto error; + /* accept connection -- the goal of our striving */ + slen = sizeof(struct sockaddr_in); + if((fd2=accept(fd, (struct sockaddr *)&sock_in, &slen)) <0) + goto error; + /* done with the listening socket */ + close(fd); + /* make sure we close on exec */ + xfcntl(fd2, F_SETFD, FD_CLOEXEC); + setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR, + (char *)&reuse_addr, sizeof(reuse_addr)); + /* make sure the right fd is set properly */ + if( strchr(mode, 'r') ) gio->ifd = fd2; + if( strchr(mode, 'w') ) gio->ofd = fd2; + } + /* open socket for writing, i.e., writing to 'stdout' on another host */ + else{ + tries = GIO_RETRIES; + /* if we opened a socket for reading, use the next port for writing */ + if( gio->ifd >=0 ) + port++; +again: + if( (fd2 = socket(AF_INET, SOCK_STREAM, 0)) < 0 ){ + gerror(stderr, "can't open socket (%s)\n", name); + gfree(gio); + return(NULL); + } + memset((char *)&sock_in, 0, sizeof(sock_in)); + sock_in.sin_family = AF_INET; + sock_in.sin_addr.s_addr = htonl(ip); + sock_in.sin_port = htons(port); + /* try connecting to the specified socket */ + status=connect(fd2, (struct sockaddr *)&sock_in, sizeof(sock_in)); + /* handle error */ + if( status != 0 ){ + close(fd2); + /* if the other process is not ready, we can wait a bit */ + if( (errno == ECONNREFUSED) && (--tries >0) ){ + gsleep(10); + goto again; + } + else{ + goto error; + } + } + /* make sure we close on exec */ + xfcntl(fd2, F_SETFD, FD_CLOEXEC); + setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR, + (char *)&reuse_addr, sizeof(reuse_addr)); + /* make sure the right fd is set properly */ + if( strchr(mode, 'r') ) gio->ifd = fd2; + if( strchr(mode, 'w') ) gio->ofd = fd2; + } + + /* fill in the record */ + gio->name = xstrdup(s); + gio->mode = xstrdup(mode); + gio->type = GIO_SOCKET; + gio->extend = 0; + /* return the good news */ + return(gio); + +error: + snprintf(tbuf, SZ_LINE-1, "in %s: %s\n", name, strerror(errno)); + gerror(stderr, tbuf); + if( fd >=0 ) close(fd); + return(NULL); +} + +/* + * + * gopenstdio -- open stdin or stdout + * + */ +#ifdef ANSI_FUNC +static GIO +gopenstdio (char *name, char *mode) +#else +static GIO gopenstdio(name, mode) + char *name; + char *mode; +#endif +{ + GIO gio; + + /* allocate a new struct */ + if( (gio = gnew()) == NULL ) + return(NULL); + + if( !strncasecmp(name, "stdout", 6) || + (!strncmp(name, "-", 1) && strchr(mode, 'w')) ){ + if( strchr(mode, 'r') ){ + gerror(stderr, "can't open STDOUT for reading\n"); + gfree(gio); + return(NULL); + } + else{ + /* fill in the record */ + gio->name = xstrdup("stdout"); + gio->mode = xstrdup(mode); + gio->type = GIO_STREAM; + gio->extend = 0; + gio->fp = stdout; + } + } + /* look for stdin */ + else if( !strncasecmp(name, "stdin", 5) || + (!strncmp(name, "-", 1) && strchr(mode, 'r')) ){ + if( strchr(mode, 'w') ){ + gerror(stderr, "can't open STDIN for writing\n"); + gfree(gio); + return(NULL); + } + else{ + /* fill in the record */ + gio->name = xstrdup("stdin"); + gio->mode = xstrdup(mode); + gio->type = GIO_STREAM; + gio->extend = 0; + gio->fp = stdin; + } + } + else{ + gerror(stderr, "invalid stdout specification (%s)\n", name); + gfree(gio); + return(NULL); + } + /* return the good news */ + return(gio); +} + +#ifdef HAVE_SYS_SHM_H +/* + * + * gopenshm -- open shared memory for reading or writing + * + */ +#ifdef ANSI_FUNC +static GIO +gopenshm (char *name, char *mode) +#else +static GIO gopenshm(name, mode) + char *name; + char *mode; +#endif +{ + GIO gio; + int shmid=-1; + int shmkey=-1; + int shmflg=0; + int shmlen=0; + int smode=0; + char *shmaddr=NULL; + char *shmbuf; + char *s, *t; + struct shmid_ds buf; + + /* allocate a new struct */ + if( (gio = gnew()) == NULL ) + return(NULL); + + /* skip past prefix */ + s = name; + if( !strncasecmp(s, "shm:", 4) ) s += 4; + while( isspace((int)*s) ) s++; + + /* fill in the record */ + gio->name = xstrdup(s); + gio->mode = xstrdup(mode); + gio->type = GIO_SHM; + gio->extend = 0; + + /* parse the shared memory specification */ + if( !s || !*s ){ + gerror(stderr, "missing shared memory specification\n"); + goto error; + } + /* @ => shmkey, otherwise shmid */ + if( *s == '@' ){ + s++; + if( !strncasecmp(s, "IPC_PRIVATE", 11) ){ + shmkey = IPC_PRIVATE; + s += 11; + } + else{ + shmkey = strtol(s, &t, 0); + s = t; + } + } + else{ + shmid = strtol(s, &t, 0); + s = t; + } + + /* get length parameter, if necessary */ + if( *s == ':' ){ + s++; + shmlen = strtol(s, &t, 0); + s = t; + } + + /* convert key to id, if necessary */ + if( shmid == -1 ){ + if( shmkey != -1 ){ + /* create if segment des not exist */ + if( strstr(mode, "w+") ){ + smode = 0664|IPC_CREAT; + } + /* open for reading and/or writing */ + else{ + if( strchr(mode, 'w') ) + smode |= 0600; + if( strchr(mode, 'r') ) + smode |= 0400; + } + /* get shared memory area identifier */ + shmid = shmget(shmkey, shmlen, smode); + } + else{ + gerror(stderr, "invalid shared memory key (%s)\n", name); + goto error; + } + /* at this point, we better have one */ + if( shmid == -1 ){ + gerror(stderr, "invalid shared memory id (%s)\n", name); + goto error; + } + } + + /* get (optional) max len we are allowed to access (def: whole segment) */ + if( shmctl(shmid, IPC_STAT, &buf) == 0 ){ + if( (shmlen <= 0) || ((size_t)shmlen > buf.shm_segsz) ){ + shmlen = buf.shm_segsz; + } + } + else{ + gerror(stderr, "can't determine memory mapping length (%s)\n", name); + goto error; + } + + /* finally ... map shared memory containing data */ + shmbuf = (char *)shmat(shmid, shmaddr, shmflg); + if( shmbuf == (char *)-1){ + gerror(stderr, "can't map shared memory image (%s)\n", name); + goto error; + } + + /* set the access parameters */ + gio->buf = shmbuf; + gio->len = shmlen; + gio->cur = 0; + gio->shmid = shmid; + /* return the good news */ + return(gio); + +error: + gfree(gio); + return(NULL); +} +#endif + +#ifdef HAVE_SYS_MMAN_H +/* + * + * gopenmmap -- open memory mapped file for reading or writing + * + */ +#ifdef ANSI_FUNC +static GIO +gopenmmap (char *name, char *mode) +#else +static GIO gopenmmap(name, mode) + char *name; + char *mode; +#endif +{ + GIO gio; + int prot; + int flags; + int len; + char *buf; + char *s; + struct stat statbuf; + + /* allocate a new struct */ + if( (gio = gnew()) == NULL ) + return(NULL); + + /* skip past prefix */ + s = name; + if( !strncasecmp(s, "mmap:", 5) ) s += 5; + while( isspace((int)*s) ) s++; + + /* fill in the record */ + gio->name = xstrdup(s); + gio->mode = xstrdup(mode); + gio->type = GIO_MMAP; + + /* open the file */ + gio->fp = fopen(s, gio->mode); + if( gio->fp == NULL ){ + gerror(stderr, "can't open data file (%s)\n", s); + goto error; + } + fstat(fileno(gio->fp), &statbuf); + len = statbuf.st_size; + prot = 0; + if( strchr(mode, 'r') ) prot |= PROT_READ; + if( strchr(mode, 'w') ) prot |= PROT_WRITE; + flags = MAP_PRIVATE; + buf = mmap(NULL, len, prot, flags, fileno(gio->fp), 0); + fclose(gio->fp); + if( buf == NULL ){ + gerror(stderr, "can't mmap data file (%s)\n", s); + goto error; + } + gio->buf = (void *)buf; + gio->len = len; + gio->cur = 0; + if( strchr(mode, 'w') ) + gio->extend = 1; + else + gio->extend = 0; + /* return the good news */ + return(gio); + +error: + gfree(gio); + return(NULL); +} +#endif + +/* + * + * gopengzip -- open gzip'ed for reading or writing + * + */ +#ifdef ANSI_FUNC +static GIO +gopengzip (char *name, char *mode) +#else +static GIO gopengzip(name, mode) + char *name; + char *mode; +#endif +{ + GIO gio; + char *s; + + /* allocate a new struct */ + if( (gio = gnew()) == NULL ) + return(NULL); + + /* skip past prefix */ + s = name; + if( !strncasecmp(s, "gzip:", 5) ) s += 5; + while( isspace((int)*s) ) s++; + + /* fill in the record */ + gio->name = xstrdup(s); + gio->mode = xstrdup(mode); + gio->type = GIO_GZIP; + gio->extend = 1; + + /* open stdin specially */ + if( !strncasecmp(name, "stdin", 5) || + (!strncmp(name, "-", 1) && strchr(mode, 'r')) ){ + gio->gz = (void *)gzdopen(dup(fileno(stdin)), gio->mode); + } + /* open stdout specially */ + else if( !strncasecmp(name, "stdout", 6) || + (!strncmp(name, "-", 1) && strchr(mode, 'w')) ){ + gio->gz = (void *)gzdopen(dup(fileno(stdout)), gio->mode); + } + /* open the file */ + else{ + gio->gz = (void *)gzopen(s, gio->mode); + } + if( gio->gz == NULL ){ + gerror(stderr, "can't open gzip'ed data file (%s)\n", s); + goto error; + } + else{ + return(gio); + } + +error: + gfree(gio); + return(NULL); +} + + +#ifdef ANSI_FUNC +static void * +_ggets (GIO gio, char *obuf, int len) +#else +static void *_ggets(gio, obuf, len) + GIO gio; + char *obuf; + int len; +#endif +{ + int i, j, l; + char *s=NULL; + char *t=NULL; + + /* existence of crbuf => we already determined that the data uses cr + instead of newline for end of line */ + if( gio->crbuf ){ + /* make sure we have a large enough buffer */ + if( len > gio->crlen ){ + gio->crbuf = xrealloc(gio->crbuf, len); + gio->crlen = len; + } + /* grab from existing buffer, reading from file when necessary */ + for(i=0, j=0; i<(len-1);){ + /* did we reach the end of the cr buffer? */ + if( gio->crbuf[j] == '\0' ){ + /* yes, try to get more */ + if( !(s=fgets(gio->crbuf, gio->crlen, gio->fp)) ) break; + /* reset cr buffer pointer to beginning */ + j = 0; + /* continue processing at beginning of buffer */ + continue; + } + /* transfer character from cr buffer to output */ + obuf[i] = gio->crbuf[j]; + /* look for CR as end of line */ + if( obuf[i] == '\r' ){ + /* change it to a new-line */ + obuf[i++] = '\n'; + /* shift rest of start of cr buffer */ + memmove(gio->crbuf, &(gio->crbuf[j+1]), strlen(&(gio->crbuf[j+1]))+1); + /* bump cr bbuf pointer */ + j++; + break; + } + else{ + /* bump pointers to both buffers */ + i++; j++; + } + } + obuf[i] = '\0'; + return((void *)obuf); + } + /* hopefully we have a nice, new-line delimited file */ + else{ + /* get next line, the usual way */ + s = fgets(obuf, len, gio->fp); + /* return if we don't want t check, have no data, or already checked */ + if( !_gcrnl || !s || gio->crlen ) return s; + /* if we did not get a new-line at the end, we either have a very long + line, or we have a cr-delimited file */ + l = strlen(s); + /* look for standard new-line */ + if( s[l-1] == '\n' ){ + /* found one -- flag that we have checked this file and return */ + gio->crlen=len; + return s; + } + /* look for cr */ + if( !(t=strchr(s, '\r')) ){ + /* no new-line and no cr -- we'll have to check the next line as well */ + return s; + } + /* its cr-delimited */ + gio->crbuf = xmalloc(len); + gio->crlen=len; + /* copy everything after the cr to a save buffer */ + memmove(gio->crbuf, t+1, (s+l)-t); + /* change cr to new-line */ + *t = '\n'; + /* null terminate */ + *(t+1) = '\0'; + return (void *)obuf; + } +} + +/* + * + * gopenfile -- open ordinary file for reading or writing + * + */ +#ifdef ANSI_FUNC +static GIO +gopenfile (char *name, char *mode) +#else +static GIO gopenfile(name, mode) + char *name; + char *mode; +#endif +{ + char *s; + GIO gio; + +#if HAVE_MINGW32 + /* binary mode for mingw */ + _fmode = _O_BINARY; +#endif + + /* allocate a new struct */ + if( (gio = gnew()) == NULL ) + return(NULL); + + /* skip past prefix */ + s = name; + if( !strncasecmp(s, "file:", 5) ) s += 5; + if( !strncasecmp(s, "unfile:", 7) ){ + gio->unbuffered = 1; + s += 7; + } + while( isspace((int)*s) ) s++; + + /* fill in the record */ + gio->name = xstrdup(s); + gio->type = GIO_DISK; + gio->extend = 1; + gio->mode = xstrdup(mode); + + /* open the file */ + gio->fp = fopen(s, gio->mode); + if( gio->fp == NULL ){ + gerror(stderr, "can't open data file (%s)\n", s); + goto error; + } + else{ + return(gio); + } + +error: + gfree(gio); + return(NULL); +} + +/* + * + * Public Routines + * + */ + +/* + * + * gopen -- open a file or a stream + * + */ +#ifdef ANSI_FUNC +GIO +gopen (char *fname, char *mode) +#else +GIO gopen(fname, mode) + char *fname; + char *mode; +#endif +{ + GIO gio; + unsigned int ip; + unsigned short port; + off_t len=0; + char name[SZ_LINE]; + char *buf=NULL; + char *tname=NULL; + char *s, *t; + + /* make sure we have a valid fname */ + if( (fname==NULL) || (*fname=='\0') ) + return(NULL); + + /* escape clause so that we can NOT convert cr to nl in ggets */ + if( (s=getenv("GCRNL")) ){ + if( istrue(s) ) + _gcrnl = 1; + else if( isfalse(s) ) + _gcrnl = 0; + } + + /* make a temp file name */ + tname = xstrdup(fname); + /* remove the bracket extension for everything except pipes */ + if( strncasecmp(tname, "pipe:", 5) ){ + if( (s=strchr(tname, '[')) ) *s = '\0'; + } + + /* expand environment variables to get working filename */ + ExpandEnv (tname, name, SZ_LINE-1); + + /* look for an explicit file */ + if( !strncasecmp(name, "file:", 5) || + !strncasecmp(name, "unfile:", 7) || strchr(mode, 'u') ) + gio = gopenfile(name, mode); + /* look for stdio */ + else if( (!strncasecmp(name, "stdin", 5) || + !strncasecmp(name, "stdout", 6)) && + !(gext(name) && !strcmp(gext(name),".gz")) ) + gio = gopenstdio(name, mode); + else if( (*name == '-') && ((*(name+1) == '\0') || (*(name+1) == '[')) ) + gio = gopenstdio(name, mode); +#if HAVE_MINGW32==0 + /* look for command pipe */ + else if( !strncasecmp(name, "pipe:", 5) || strchr(mode, 'p') ) + gio = gopenpipe(name, mode); +#endif +#ifdef HAVE_SYS_MMAN_H + /* look for a mapped file */ + else if( !strncasecmp(name, "mmap:", 5) || strchr(mode, 'm') ) + gio = gopenmmap(name, mode); +#endif +#ifdef HAVE_SYS_SHM_H + /* look for shared memory segment */ + else if( !strncasecmp(name, "shm:", 4) || strchr(mode, 's') ) + gio = gopenshm(name, mode); +#endif + /* look for data in memory (ordinary buffer) */ + else if( !strncasecmp(name, "mem:", 4) || + !strncasecmp(name, "buf:", 4) || strchr(mode, 'b') ){ + s = name; + if( !strncasecmp(name, "mem:", 4) || !strncasecmp(name, "buf:", 4) ) + s += 4; + buf = (char *)strtoul(s, &t, 0); + if( *t != ':' ){ + gerror(stderr, "illegal memory buffer specification (%s)\n", name); + gio = NULL; + } + else{ + len = (off_t)strtoul(++t, NULL, 0); + gio = gmemopen(buf, len, mode); + } + } + /* look for a socket, in the form machine:port */ + else if( gioparseipport(name, &ip, &port) ) + gio = gopensocket(name, mode); + /* look for gzip'ed file */ + else if( !strncasecmp(name, "gzip:", 5) || + (gext(name) && !strcmp(gext(name),".gz")) ) + gio = gopengzip(name, mode); + /* if all else fails, its an ordinary file */ + else + gio = gopenfile(name, mode); + + /* free working space */ + if( tname ) xfree(tname); + + /* return results */ + return(gio); +} + +/* + * + * gmemopen -- open memory for reading or writing + * + */ +#ifdef ANSI_FUNC +GIO +gmemopen (char *buf, off_t len, char *mode) +#else +GIO gmemopen(buf, len, mode) + char *buf; + off_t len; + char *mode; +#endif +{ + GIO gio; + + /* allocate a new struct */ + if( (gio = gnew()) == NULL ) + return(NULL); + + /* fill in the record */ + gio->name = xstrdup("MEMORY"); + gio->mode = xstrdup(mode); + gio->type = GIO_MEMORY; + + /* process open type */ + if( strchr(mode, 'w') ){ + if( (buf!=NULL) && (len>0) ){ + gio->buf = (void *)buf; + gio->len = len; + } + else{ + gio->buf = (char *)xmalloc(GIO_BUFINC); + gio->len = GIO_BUFINC; + } + gio->cur = 0; + gio->extend = 1; + } else { + gio->buf = (void *)buf; + gio->len = len; + gio->cur = 0; + gio->extend = 0; + } + + /* return the news */ + return(gio); +} + +/* + * + * _gread -- read bytes from a data I/O structure + * + */ +#ifdef ANSI_FUNC +void * +_gread (GIO gio, char *buf, size_t size, size_t n, size_t *got) +#else +void *_gread(gio, buf, size, n, got) + GIO gio; + char *buf; + size_t size; + size_t n; + size_t *got; +#endif +{ + char *obuf; + char *tptr; + int get; + int tgot; + + /* got nothing yet */ + *got = 0; + + /* sanity checks */ + if( gio==NULL ) + return(NULL); + if( !strchr(gio->mode, 'r') && !strstr(gio->mode, "w+") ){ + gerror(stderr, + "illegal read operation on write-only data (%s)\n", gio->name); + return(NULL); + } + + /* try to read */ + switch(gio->type){ + case GIO_DISK: + if( buf ) + obuf = buf; + else + obuf = (char *)xmalloc(size*n); + if( gio->unbuffered ){ + for(tptr=obuf, get=size*n; get>0; get -= tgot){ + tgot = read(fileno(gio->fp), tptr, get); + if( tgot <0 ) { + *got = tgot; + break; + } + if( tgot == 0 ){ + break; + } + else{ + *got += tgot; + tptr += tgot; + } + } + if( *got >0 ) + *got /= size; + } + else{ + *got = fread(obuf, size, n, gio->fp); + } + if( *got <= 0 ){ + if( !buf ) + xfree(obuf); + obuf = NULL; + } + return(obuf); + case GIO_STREAM: + if( buf ) + obuf = buf; + else + obuf = (char *)xmalloc(size*n); + *got = fread(obuf, size, n, gio->fp); + if( *got <= 0 ){ + if( !buf ) + xfree(obuf); + obuf = NULL; + } + return(obuf); + case GIO_MEMORY: + return(gmemread(gio, buf, size, n, got)); +#ifdef HAVE_SYS_MMAN_H + case GIO_MMAP: + return(gmemread(gio, buf, size, n, got)); +#endif +#ifdef HAVE_SYS_SHM_H + case GIO_SHM: + return(gmemread(gio, buf, size, n, got)); +#endif + case GIO_PIPE: + if( buf ) + obuf = buf; + else + obuf = (char *)xmalloc(size*n); + if( gio->ifd >=0 ){ + for(tptr=obuf, get=size*n; get>0; get -= tgot){ + tgot = read(gio->ifd, tptr, get); + if( tgot <0 ) { + *got = tgot; + break; + } + else if( tgot ==0 ) { + break; + } + else{ + *got += tgot; + tptr += tgot; + } + } + if( *got > 0 ) + *got /= size; + } + if( *got <= 0 ){ + if( !buf ) + xfree(obuf); + obuf = NULL; + } + else{ + gio->cur += *got; + } + return(obuf); + case GIO_SOCKET: + if( buf ) + obuf = buf; + else + obuf = (char *)xmalloc(size*n); + if( gio->ifd >=0 ){ + for(tptr=obuf, get=size*n; get>0; get -= tgot){ + tgot = recv(gio->ifd, tptr, get, 0); + if( tgot <0 ) { + *got = tgot; + break; + } + else if( tgot == 0 ) { + break; + } + else{ + *got += tgot; + tptr += tgot; + } + } + if( *got > 0 ) + *got /= size; + } + if( *got <= 0 ){ + if( !buf ) + xfree(obuf); + obuf = NULL; + } + else{ + gio->cur += *got; + } + return(obuf); + case GIO_GZIP: + if( buf ) + obuf = buf; + else + obuf = (char *)xmalloc(size*n); + *got = gzread(gio->gz, obuf, size * n); + if( *got <= 0 ){ + if( !buf ) + xfree(obuf); + obuf = NULL; + } + if( *got >0 ) + *got /= size; + return(obuf); + default: + return(NULL); + } +} + +/* + * + * gread -- read bytes from a data I/O structure + * + */ +#ifdef ANSI_FUNC +size_t +gread (GIO gio, char *buf, size_t size, size_t n) +#else +size_t gread(gio, buf, size, n) + GIO gio; + char *buf; + size_t size; + size_t n; +#endif +{ + size_t got; + if( buf == NULL ) + return(0); + _gread(gio, buf, size, n, &got); + return (got); +} + +/* + * + * gwrite -- write bytes to a structure + * + */ +#ifdef ANSI_FUNC +size_t +gwrite (GIO gio, char *buf, size_t size, size_t n) +#else +size_t gwrite(gio, buf, size, n) + GIO gio; + char *buf; + size_t size; + size_t n; +#endif +{ + int got=0; + + /* sanity checks */ + if( gio==NULL ) + return(0); + if( !strchr(gio->mode, 'w') && !strchr(gio->mode, 'a') && + !strstr(gio->mode, "r+") ){ + gerror(stderr, + "illegal write operation on read-only data (%s)\n", gio->name); + return(0); + } + + switch(gio->type){ + case GIO_DISK: + if( gio->unbuffered ){ + got = write(fileno(gio->fp), buf, size*n); + if( got > 0 ) got /= size; + } + else{ + got = fwrite(buf, size, n, gio->fp); + } + break; + case GIO_STREAM: + got = fwrite(buf, size, n, gio->fp); + break; + case GIO_MEMORY: + got = gmemwrite(gio, buf, size, n); + break; +#ifdef HAVE_SYS_MMAN_H + case GIO_MMAP: + got = gmemwrite(gio, buf, size, n); + break; +#endif +#ifdef HAVE_SYS_SHM_H + case GIO_SHM: + got = gmemwrite(gio, buf, size, n); + break; +#endif + case GIO_PIPE: + if( gio->ofd >= 0 ){ + got = write(gio->ofd, buf, size * n); + if( got > 0 ){ + gio->cur += got; + got /= size; + } + } + break; + case GIO_SOCKET: + if( gio->ofd >= 0 ){ + got = send(gio->ofd, buf, size * n, 0); + if( got > 0 ){ + gio->cur += got; + got /= size; + } + } + break; + case GIO_GZIP: + got = gzwrite(gio->gz, buf, size*n); + if( got >=0 ) got /= size; + break; + default: + break; + } + return(got); +} + +#ifdef ANSI_FUNC +void * +ggets (GIO gio, char *buf, int len) +#else +void *ggets(gio, buf, len) + GIO gio; + char *buf; + int len; +#endif +{ + int i=0; + int got; + char *obuf=NULL; + + /* sanity checks */ + if( !gio ) + return NULL; + if( !strchr(gio->mode, 'r') && !strstr(gio->mode, "w+") ){ + gerror(stderr, + "illegal read operation on write-only data (%s)\n", gio->name); + return NULL; + } + + /* allocate buffer, if necessary */ + if( buf ) + obuf = buf; + else + obuf = (char *)xmalloc(len); + + /* start out clean */ + *obuf = '\0'; + + switch(gio->type){ + case GIO_STREAM: + _ggets(gio, obuf, len); + if( !obuf || !*obuf ){ + if( !buf ) xfree(obuf); + obuf = NULL; + } + return obuf; + case GIO_DISK: + if( !gio->unbuffered ){ + _ggets(gio, obuf, len); + if( !obuf || !*obuf ){ + if( !buf ) xfree(obuf); + obuf = NULL; + } + return obuf; + } + default: + /* grab characters up to a new-line or max len */ + while( i < (len-1) ){ + got = gread(gio, &(obuf[i]), sizeof(char), 1); + if( got < 0 ){ + i = 0; + break; + } + else if( got == 0 ) + break; + else if( obuf[i] == '\n' ){ + i++; + break; + } + else if( (obuf[i] == '\r') && _gcrnl ){ + obuf[i] = '\n'; + i++; + break; + } + else{ + i++; + } + } + obuf[i] = '\0'; + if( i == 0 ){ + if( !buf ) xfree(obuf); + obuf = NULL; + } + return((void *)obuf); + } +} + +#ifdef __STDC__ +int +gprintf(GIO gio, char *format, ...) +{ + int got; + va_list args; + va_start(args, format); +#else +int gprintf(va_alist) va_dcl +{ + GIO gio + char *format; + int got; + va_list args; + + va_start(args); + gio = va_arg(args, GIO); + format = va_arg(args, char *); +#endif + got = vsnprintf(_gtbuf, GBUFSZ, format, args); + if( got > GBUFSZ ){ + gerror(stderr, "gprintf string too long (%d > %d)\n", got, GBUFSZ); + return -1; + } + else{ + return gwrite(gio, _gtbuf, sizeof(char), strlen(_gtbuf)); + } +} + +/* + * + * gflush -- flush I/O + * + */ +#ifdef ANSI_FUNC +int +gflush (GIO gio) +#else +int gflush(gio) + GIO gio; +#endif +{ + /* sanity checks */ + if( gio==NULL ) + return(-1); + + switch(gio->type){ + case GIO_DISK: + if( gio->unbuffered ) + return(0); + else + return(fflush(gio->fp)); + case GIO_STREAM: + return(fflush(gio->fp)); + case GIO_MEMORY: + return(0); +#ifdef HAVE_SYS_MMAN_H + case GIO_MMAP: + return(0); +#endif +#ifdef HAVE_SYS_SHM_H + case GIO_SHM: + return(0); +#endif + case GIO_PIPE: + return(0); + case GIO_SOCKET: + return(0); + case GIO_GZIP: + return(0); + default: + return(-1); + } +} + +/* + * + * gseek -- set current pointer position in a "file" + * + */ +#ifdef ANSI_FUNC +off_t +gseek (GIO gio, off_t offset, int whence) +#else +off_t gseek(gio, offset, whence) + GIO gio; + off_t offset; + int whence; +#endif +{ + off_t opos; + /* sanity checks */ + if( gio==NULL ) + return(-1); + + switch(gio->type){ + case GIO_DISK: + if( gio->unbuffered ) + return(lseek(fileno(gio->fp), offset, whence)); + else{ +#if USE_FSEEKO + opos = ftello(gio->fp); + if( fseeko(gio->fp, offset, whence) == 0 ){ + return(opos); + } + else{ + return(-1); + } +#else + opos = ftell(gio->fp); + if( fseek(gio->fp, (long)offset, whence) == 0 ){ + return(opos); + } + else{ + return(-1); + } +#endif + } + case GIO_STREAM: + if( whence == SEEK_CUR ) + return( gskip(gio, offset) ); + else{ +#if USE_FSEEKO + opos = ftello(gio->fp); + if( fseeko(gio->fp, offset, whence) == 0 ){ + return(opos); + } + else{ + return(-1); + } +#else + opos = ftell(gio->fp); + if( fseek(gio->fp, (long)offset, whence) == 0 ){ + return(opos); + } + else{ + return(-1); + } +#endif + } + case GIO_MEMORY: + return(gmemseek(gio, offset, whence)); +#ifdef HAVE_SYS_MMAN_H + case GIO_MMAP: + return(gmemseek(gio, offset, whence)); +#endif +#ifdef HAVE_SYS_SHM_H + case GIO_SHM: + return(gmemseek(gio, offset, whence)); +#endif + case GIO_PIPE: + if( whence == SEEK_CUR ) + return( gskip(gio, offset) ); + else + return(-1); + case GIO_SOCKET: + if( whence == SEEK_CUR ) + return( gskip(gio, offset) ); + else + return(-1); + case GIO_GZIP: + return(gzseek(gio->gz, offset, whence)); + default: + return(-1); + } +} + +/* + * + * gtell -- return current pointer position in a "file" + * + */ +#ifdef ANSI_FUNC +off_t +gtell (GIO gio) +#else +off_t gtell(gio) + GIO gio; +#endif +{ +#if USE_FTELLO + off_t lval; +#else + long lval; +#endif + /* sanity checks */ + if( gio==NULL ) + return((off_t)-1); + + switch(gio->type){ + case GIO_DISK: + if( gio->unbuffered ) + return(lseek(fileno(gio->fp), 0, SEEK_CUR)); + else +#if USE_FTELLO + return(ftello(gio->fp)); +#else + return(ftell(gio->fp)); +#endif + case GIO_STREAM: +#if USE_FTELLO + lval = ftello(gio->fp); +#else + lval = ftell(gio->fp); +#endif + if( lval >=0 ) + return lval; + else + return gio->cur; + case GIO_MEMORY: + return(gio->cur); +#ifdef HAVE_SYS_MMAN_H + case GIO_MMAP: + return(gio->cur); +#endif +#ifdef HAVE_SYS_SHM_H + case GIO_SHM: + return(gio->cur); +#endif + case GIO_PIPE: + return(gio->cur); + case GIO_SOCKET: + return(gio->cur); + case GIO_GZIP: + return(gztell(gio->gz)); + default: + return((off_t)-1); + } +} + +/* + * + * gskip - skip reading bytes to a file position + * + */ +#ifdef ANSI_FUNC +int +gskip (GIO gio, off_t n) +#else +int gskip(gio, n) + GIO gio; + off_t n; +#endif +{ + char buf[1]; + + /* sanity checks */ + if( !gio ) + return(-1); + + /* nothing to do */ + if( !n ) + return 0; + + switch(gio->type){ + case GIO_DISK: + if( gio->unbuffered ) + return(lseek(fileno(gio->fp), n, SEEK_CUR)); + else +#if USE_FSEEKO + return(fseeko(gio->fp, n, SEEK_CUR)); +#else + return(fseek(gio->fp, (long)n, SEEK_CUR)); +#endif + case GIO_STREAM: + /* for stdin, read the bytes */ + if( gio->fp == stdin ){ + if( n < 0 ) + return(-1); + while( n-- ){ + if( fread(buf, sizeof(char), 1, gio->fp) != 1 ) + return(0); + } + return(0); + } + /* who knows what will happen here */ + else{ +#if USE_FSEEKO + return(fseeko(gio->fp, n, SEEK_CUR)); +#else + return(fseek(gio->fp, (long)n, SEEK_CUR)); +#endif + } + case GIO_MEMORY: + if( (gio->cur + n >= gio->len) || (gio->cur + n <0) ){ + return(-1); + } + else{ + gio->cur += n; + return(0); + } +#ifdef HAVE_SYS_MMAN_H + case GIO_MMAP: + if( (gio->cur + n >= gio->len) || (gio->cur + n <0) ){ + return(-1); + } + else{ + gio->cur += n; + return(0); + } +#endif +#ifdef HAVE_SYS_SHM_H + case GIO_SHM: + if( (gio->cur + n >= gio->len) || (gio->cur + n <0) ){ + return(-1); + } + else{ + gio->cur += n; + return(0); + } +#endif + case GIO_PIPE: + if( n < 0 ) + return(-1); + if( gio->ifd >= 0 ){ + while( n-- ){ + if( read(gio->ifd, buf, 1) != 1 ) + return(0); + gio->cur++; + } + return(0); + } + else{ + return(-1); + } + case GIO_SOCKET: + if( n < 0 ) + return(-1); + if( gio->ifd >= 0 ){ + while( n-- ){ + if( recv(gio->ifd, buf, 1, 0) != 1 ) + return(0); + gio->cur++; + } + return(0); + } + else{ + return(-1); + } + case GIO_GZIP: + return(gzseek(gio->gz, (z_off_t)n, SEEK_CUR)); + default: + return(-1); + } +} + +/* + * + * ginfo -- return information about a "file" + * + */ +#ifdef ANSI_FUNC +int +ginfo (GIO gio, char **name, int *type, off_t *cur, char **buf, int *len) +#else +int ginfo(gio, name, type, cur, buf, len) + GIO gio; + char **name; + int *type; + off_t *cur; + char **buf; + int *len; +#endif +{ + if( gio==NULL ) + return(-1); + if( name ) + *name = gio->name; + if( type ) + *type = gio->type; + if( cur ) + *cur = gtell(gio); + if( buf ) + *buf = gio->buf; + if( len ) + *len = gio->len; + return(0); +} + +/* + * + * gfreebuf -- free allocated data buffers + * + */ +#ifdef ANSI_FUNC +void +gfreebuf (GIO gio, void *buf) +#else +void gfreebuf(gio, buf) + GIO gio; + void *buf; +#endif +{ + if( gio==NULL ) + return; + + switch(gio->type){ + case GIO_DISK: + if( buf ) + xfree(buf); + break; + case GIO_STREAM: + if( buf ) + xfree(buf); + break; + case GIO_MEMORY: + break; +#ifdef HAVE_SYS_MMAN_H + case GIO_MMAP: + break; +#endif +#ifdef HAVE_SYS_SHM_H + case GIO_SHM: + break; +#endif + case GIO_PIPE: + if( buf ) + xfree(buf); + break; + case GIO_SOCKET: + if( buf ) + xfree(buf); + break; + case GIO_GZIP: + if( buf ) + xfree(buf); + break; + default: + break; + } +} + +/* + * + * gclose -- close an I/O structure + * + */ +#ifdef ANSI_FUNC +void +gclose (GIO gio) +#else +void gclose(gio) + GIO gio; +#endif +{ + int status; + + /* sanity checks */ + if( gio==NULL ) + return; + + switch(gio->type){ + case GIO_DISK: + if( gio->unbuffered ){ + fclose(gio->fp); + } + else{ + fflush(gio->fp); + fclose(gio->fp); + } + break; + case GIO_STREAM: + fflush(gio->fp); + /* close stream, but don't close a stdio stream */ + if( (gio->fp != stdin) && (gio->fp != stdout) && (gio->fp != stderr) ) + fclose(gio->fp); + break; +#ifdef HAVE_SYS_MMAN_H + case GIO_MMAP: + munmap(gio->buf, gio->len); + break; +#endif + case GIO_MEMORY: + break; +#ifdef HAVE_SYS_SHM_H + case GIO_SHM: + /* unmap shared memory segment */ + shmdt(gio->buf); + /* in write+ mode, we try to destroy the shared memory as well */ + if( strstr(gio->mode, "w+") ) shmctl(gio->shmid, IPC_RMID, NULL); + break; +#endif + case GIO_PIPE: + if( gio->ifd >=0 ) + close(gio->ifd); + if( gio->ofd >=0 ) + close(gio->ofd); +#if HAVE_MINGW32==0 + if( gio->pid ) + waitpid(gio->pid, &status, 0); +#endif + break; + case GIO_SOCKET: + if( gio->ifd >=0 ) + close(gio->ifd); + else if( gio->ofd >=0 ) + close(gio->ofd); + break; + case GIO_GZIP: + gzclose(gio->gz); + break; + default: + break; + } + gfree(gio); +} + +/* + * + * gerrorstring -- return last exception string + * + */ +#ifdef ANSI_FUNC +char * +gerrorstring(void) +#else +char *gerrorstring() +#endif +{ + return(_gerrors); +} + +/* + * + * setgerror -- set the error flag + * + */ +#ifdef ANSI_FUNC +int +setgerror(int flag) +#else +int setgerror(flag) + int flag; +#endif +{ + int oflag; + oflag = _gerror; + _gerror = flag; + return oflag; +} + +/* + * + * gerror - error message handler + * actions based on value of error flag: + * + * flag action + * ---- ------ + * 0 store error message in _gerrors string + * 1 store, print error message and continue + * 2 print error message and exit + * + */ +#ifdef __STDC__ +void gerror(FILE *fd, char *format, ...) +{ + char tbuf[SZ_LINE]; + va_list args; + va_start(args, format); +#else +void gerror(va_alist) va_dcl +{ + FILE *fd; + char *format; + char tbuf[SZ_LINE]; + va_list args; + + va_start(args); + fd = va_arg(args, FILE *); + format = va_arg(args, char *); +#endif + /* initialize level, if not already done */ + if( _gerror == -1 ){ + char *s; + if( (s=getenv("GERROR")) ) + _gerror = atoi(s); + else + _gerror = 2; + } + snprintf(tbuf, SZ_LINE-1, "ERROR: %s", format); + vsnprintf(_gerrors, SZ_LINE-1, tbuf, args); + /* if the error flag is positive, we output immediately */ + if( (fd != NULL) && _gerror ){ + fputs(_gerrors, fd); + fflush(fd); + } + /* if the error flag is set high, we exit */ + if( _gerror >= 2 ) + exit(_gerror); +} + +/* + * + * gwarningstring -- return last exception string + * + */ +#ifdef ANSI_FUNC +char * +gwarningstring(void) +#else +char *gwarningstring() +#endif +{ + return(_gwarnings); +} + +/* + * + * setgwarning -- set the warning flag + * + */ +#ifdef ANSI_FUNC +int +setgwarning(int flag) +#else +int setgwarning(flag) + int flag; +#endif +{ + int oflag; + oflag = _gwarning; + _gwarning = flag; + return oflag; +} + +#ifdef __STDC__ +void gwarning(FILE *fd, char *format, ...) +{ + char tbuf[SZ_LINE]; + va_list args; + va_start(args, format); +#else +void gwarning(va_alist) va_dcl +{ + FILE *fd; + char *format; + char tbuf[SZ_LINE]; + va_list args; + + va_start(args); + fd = va_arg(args, FILE *); + format = va_arg(args, char *); +#endif + /* initialize level, if not already done */ + if( _gwarning == -1 ){ + char *s; + if( (s=getenv("GWARNING")) ) + _gwarning = atoi(s); + else + _gwarning = 1; + } + snprintf(tbuf, SZ_LINE-1, "WARNING: %s", format); + vsnprintf(_gwarnings, SZ_LINE-1, tbuf, args); + /* if the warning flag is positive, we output immediately */ + if( (fd != NULL) && _gwarning ){ + fputs(_gwarnings, fd); + fflush(fd); + } +} + +#ifdef ANSI_FUNC +void +gsleep (int msec) +#else +void gsleep(msec) + int msec; +#endif +{ + struct timeval tv; + if( msec > 0 ){ + tv.tv_sec = msec / 1000; + tv.tv_usec = (msec % 1000) * 1000; + select(1, NULL, NULL, NULL, &tv); + } +} |