UTIL 22-SEP-1995 18:31:19 VAX C V3.2-044 Page 1 V1.0 19-SEP-1995 13:16:05 [GOPHER.G2.VMS2_13.OBJECT]UTIL.C;2 (1) 1 /******************************************************************** 2 * lindner 3 * 3.20 4 * 1995/02/02 17:14:47 5 * /home/arcwelder/GopherSrc/CVS/gopher+/object/util.c,v 6 * Exp 7 * 8 * Paul Lindner, University of Minnesota CIS. 9 * 10 * Copyright 1991, 1992 by the Regents of the University of Minnesota 11 * see the file "Copyright" in the distribution for conditions of use. 12 ********************************************************************* 13 * MODULE: util.c 14 * Various useful utilities for gopher clients and servers 15 ********************************************************************* 16 * Revision History: 17 * util.c,v 18 * Revision 3.20 1995/02/02 17:14:47 lindner 19 * Fix for memory leaks and accesses 20 * 21 * Revision 3.19 1994/10/19 03:34:39 lindner 22 * Dynamically allocate acceptable array 23 * 24 * Revision 3.18 1994/08/19 16:12:11 lindner 25 * Sanity check for Tohexstr 26 * 27 * Revision 3.17 1994/07/21 22:07:52 lindner 28 * none 29 * 30 * Revision 3.16 1994/04/25 03:37:01 lindner 31 * Modifications for Debug() and mismatched NULL arguments, added Debugmsg 32 * 33 * Revision 3.15 1994/03/31 21:04:36 lindner 34 * Mitra's 2.011 debug patch 35 * 36 * Revision 3.14 1994/03/08 15:56:22 lindner 37 * gcc -Wall fixes 38 * 39 * Revision 3.13 1994/02/20 16:25:58 lindner 40 * Optimize readline and friends to use fileio routines 41 * 42 * Revision 3.12 1993/12/27 16:14:54 lindner 43 * prettify debug output 44 * 45 * Revision 3.11 1993/09/21 01:52:54 lindner 46 * Fixes for NETLIB 47 * 48 * Revision 3.10 1993/08/16 19:41:23 lindner 49 * Fix for DECC/Alpha 50 * 51 * Revision 3.9 1993/08/09 20:17:13 lindner 52 * Fixes for CMULIB and NETLIB for VMS 53 * 54 * Revision 3.8 1993/08/05 03:23:40 lindner 55 * Changes for CMUIP and NETLIB UTIL 22-SEP-1995 18:31:19 VAX C V3.2-044 Page 2 V1.0 19-SEP-1995 13:16:05 [GOPHER.G2.VMS2_13.OBJECT]UTIL.C;2 (1) 56 * 57 * Revision 3.7 1993/07/27 05:30:30 lindner 58 * Mondo Debug overhaul from Mitra 59 * 60 * Revision 3.6 1993/07/23 04:49:24 lindner 61 * none 62 * 63 * Revision 3.5 1993/06/22 05:49:39 lindner 64 * *** empty log message *** 65 * 66 * Revision 3.4 1993/04/23 20:11:56 lindner 67 * Fixed misdeclaration of DEBUG 68 * 69 * Revision 3.3 1993/04/15 17:53:12 lindner 70 * Debug stuff from Mitra 71 * 72 * Revision 3.2 1993/03/18 22:28:27 lindner 73 * changed hex routines around for admit1 74 * 75 * Revision 3.1.1.1 1993/02/11 18:03:05 lindner 76 * Gopher+1.2beta release 77 * 78 * Revision 2.5 1993/01/31 00:31:12 lindner 79 * New functions, readword() and readtotoken() 80 * 81 * Revision 2.4 1993/01/12 21:12:23 lindner 82 * Reverted to old readfield behavior() \n is now ignored again. 83 * 84 * Revision 2.3 1993/01/08 23:29:21 lindner 85 * More mods from jqj. 86 * 87 * Revision 2.2 1992/12/31 04:58:41 lindner 88 * merged 1.1.1.1 and 2.1 89 * 90 * Revision 2.1 1992/12/21 19:41:14 lindner 91 * Added check for null in writestring 92 * Added function skip_whitespace 93 * 94 * Revision 1.1.1.1 1992/12/31 04:52:01 lindner 95 * Changes for VMS 96 * 97 * Revision 1.1 1992/12/10 23:27:52 lindner 98 * gopher 1.1 release 99 * 100 * 101 *********************************************************************/ 102 103 #include "String.h" 985 #include 1048 #include "boolean.h" 1093 #include "util.h" 1151 #include 1400 #include "Debug.h" 1715 #include "fileio.h" 3270 3271 3272 #if defined(VMS) && (defined(UCX) || defined(CMUIP) || defined(NETLIB)) UTIL 22-SEP-1995 18:31:19 VAX C V3.2-044 Page 3 V1.0 19-SEP-1995 13:16:05 [GOPHER.G2.VMS2_13.OBJECT]UTIL.C;2 (1) 3273 X #include 3274 #endif 3275 3276 3277 static FileIO *Gfio = NULL; 3278 static int Oldsockfd = -1; 3279 3280 3281 3282 #if defined(VMS) && (defined(WOLLONGONG) || defined(MULTINET) ||defined(CMUIP)||defined(NETLIB)) 3283 /* Multinet and Wollongong,etc. (non UCX-emulation) use channel numbers */ 3284 /* for sockets, which are small multiples of 16. The first 5 */ 3285 /* channels can be assumed to be already used, so we assume that */ 3286 /* sockets start at 64, and that only 64 VAXC fds are simultaneously */ 3287 /* open in the program. Actually, the first socket is likely to be */ 3288 /* more like 176! */ 3289 3290 #define IS_SOCKET(s) ((s)>=64) 3291 3292 /* Close a socket. 3293 * Note that in old Wollongong and Multinet implementations close() 3294 * works only on fds, not sockets. 3295 * For UCX and Unix, closenet() is #defined to be close() 3296 */ 3297 int closenet(s) 3298 int s; 3299 { 3300 1 #ifdef DEBUGGING 3301 1 #ifndef VMS 3302 X if (s == stderr) { 3303 X fprintf(stderr, "YUK - closing stderr"); 3304 X } 3305 1 #else 3306 1 if (s == (int)stderr) { 3307 2 fprintf(stderr, "YUK - closing stderr"); 3308 2 } 3309 1 #endif 3310 1 #endif 3311 1 3312 1 if (IS_SOCKET(s)) { 3313 2 #ifdef MULTINET 3314 2 return (socket_close(s)); 3315 2 #else /* WOLLONGONG, CMUIP, NETLIB */ 3316 X return (netclose(s)); 3317 2 #endif 3318 2 } 3319 1 else 3320 1 close(s); /* shouldn't be calling this routine */ 3321 1 } 3322 #else /* WOLLANGONG or MULTINET */ 3323 X #define IS_SOCKET(a) 1 3324 #endif 3325 3326 static void CheckGfio(fd) 3327 int fd; 3328 { 3329 1 UTIL 22-SEP-1995 18:31:19 VAX C V3.2-044 Page 4 V1.0 19-SEP-1995 13:16:05 [GOPHER.G2.VMS2_13.OBJECT]UTIL.C;2 (1) 3330 1 if (Gfio == NULL || Oldsockfd != fd) { 3331 2 Oldsockfd = fd; 3332 2 if (Gfio != NULL) 3333 2 FIOdestroy(Gfio); 3334 2 Gfio = FIOopenfd(fd, IS_SOCKET(fd)); 3335 2 } 3336 1 } 3337 3338 3339 3340 3341 /* Read "n" bytes from a descriptor. 3342 * Use in place of read() when fd is a stream socket 3343 * 3344 * Returns the number of total bytes read. 3345 */ 3346 3347 int readn(fd, ptr, nbytes) 3348 int fd; 3349 char *ptr; 3350 int nbytes; 3351 { 3352 1 int nleft, nread; 3353 1 3354 1 nleft = nbytes; 3355 1 while (nleft > 0) { 3356 2 #if defined(VMS) && (defined(WOLLONGONG) || defined(CMUIP) || defined(NETLIB)) 3357 X nread = IS_SOCKET(fd) ? netread(fd, ptr, nleft) : read(fd, ptr, nleft); 3358 2 #else 3359 2 #if defined(VMS) && defined(MULTINET) 3360 2 nread = IS_SOCKET(fd) ? socket_read(fd, ptr, nleft) : read(fd, ptr, nleft); 3361 2 #else 3362 X nread = read(fd, ptr, nleft); 3363 2 #endif 3364 2 #endif 3365 2 #if defined(VMS) && (defined(UCX) || defined(CMUIP) || defined(NETLIB)) 3366 X if (nread < 0 && errno == EPIPE) 3367 X break; 3368 2 #endif 3369 2 if (nread < 0) 3370 2 return(nread); /* error, return <0 */ 3371 2 else if (nread == 0) /* EOF */ 3372 2 break; 3373 2 3374 2 nleft -= nread; 3375 2 ptr += nread; 3376 2 } 3377 1 return(nbytes - nleft); /* return >= 0) */ 3378 1 } 3379 3380 3381 3382 /* 3383 * Write "n" bytes to a descriptor. 3384 * Use in place of write() when fd is a stream socket 3385 * 3386 * We return the number of bytes written UTIL 22-SEP-1995 18:31:19 VAX C V3.2-044 Page 5 V1.0 19-SEP-1995 13:16:05 [GOPHER.G2.VMS2_13.OBJECT]UTIL.C;2 (1) 3387 */ 3388 3389 int 3390 writen(fd, ptr, nbytes) 3391 int fd; 3392 char *ptr; 3393 int nbytes; 3394 { 3395 1 int nleft, nwritten; 3396 1 3397 1 nleft = nbytes; 3398 1 while(nleft > 0) { 3399 2 #if defined(VMS) && (defined(WOLLONGONG) || defined(CMUIP) || defined(NETLIB)) 3400 X nwritten = IS_SOCKET(fd) ? netwrite(fd, ptr, nleft) : write(fd, ptr, nleft); 3401 2 #else 3402 2 #if defined(VMS) && defined(MULTINET) 3403 2 nwritten = IS_SOCKET(fd) ? socket_write(fd, ptr, nleft) : write(fd, ptr, nleft); 3404 2 #else 3405 X nwritten = write(fd, ptr, nleft); 3406 2 #endif 3407 2 #endif 3408 2 if (nwritten <= 0) 3409 2 return(nwritten); /* error */ 3410 2 3411 2 nleft -= nwritten; 3412 2 ptr += nwritten; 3413 2 } 3414 1 return(nbytes - nleft); 3415 1 } 3416 3417 3418 /* 3419 * Writestring uses the writen and strlen calls to write a 3420 * string to the file descriptor fd. If the write fails 3421 * a -1 is returned. Otherwise zero is returned. 3422 */ 3423 3424 int writestring(fd, stringptr) 3425 int fd; 3426 char *stringptr; 3427 { 3428 1 int length; 3429 1 3430 1 Debug("writing: %s\n",stringptr); 3431 1 3432 1 if (stringptr == NULL) 3433 1 return(0); 3434 1 3435 1 length = strlen(stringptr); 3436 1 if (writen(fd, stringptr, length) != length) { 3437 2 Debugmsg("writestring: writen failed\n"); 3438 2 return(-1); 3439 2 } 3440 1 else 3441 1 return(0); 3442 1 } 3443 UTIL 22-SEP-1995 18:31:19 VAX C V3.2-044 Page 6 V1.0 19-SEP-1995 13:16:05 [GOPHER.G2.VMS2_13.OBJECT]UTIL.C;2 (1) 3444 /* 3445 * Read from the socket into a buffer. Mucho more efficent in terms of 3446 * system calls.. 3447 * 3448 * returns bytes read, or <0 for an error 3449 */ 3450 3451 int readrecvbuf(sockfd, buf, len) 3452 int sockfd; 3453 char *buf; 3454 int len; 3455 { 3456 1 int bytesread; 3457 1 3458 1 CheckGfio(sockfd); 3459 1 if (Gfio == NULL) 3460 1 return(-1); 3461 1 3462 1 bytesread = FIOreadbuf(Gfio, buf, len); 3463 1 3464 1 return(bytesread); 3465 1 } 3466 3467 3468 /* 3469 * Read a line from a descriptor. Read the line one byte at a time, 3470 * looking for the newline. We store the newline in the buffer, 3471 * then follow it with a null (the same as fgets(3)). 3472 * We return the number of characters up to, but not including, 3473 * the null (the same as strlen(3)) 3474 */ 3475 3476 int 3477 readline(fd, ptr, maxlen) 3478 int fd; 3479 char *ptr; 3480 int maxlen; 3481 { 3482 1 int n; 3483 1 3484 1 CheckGfio(fd); 3485 1 3486 1 if (Gfio == NULL) 3487 1 return(-1); 3488 1 3489 1 n = FIOreadline(Gfio, ptr, maxlen); 3490 1 Debug("readline: %s\n", ptr); 3491 1 3492 1 return(n); 3493 1 } 3494 3495 3496 /* 3497 * Read a line from the file/socket, Read the line one byte at a time, 3498 * looking for the token. We nuke the token from the returned string. 3499 * We return the number of characters up to, but not including, 3500 * the null (the same as strlen(3)) UTIL 22-SEP-1995 18:31:19 VAX C V3.2-044 Page 7 V1.0 19-SEP-1995 13:16:05 [GOPHER.G2.VMS2_13.OBJECT]UTIL.C;2 (1) 3501 */ 3502 3503 int 3504 readtoken(fd, ptr, maxlen, zechar) 3505 int fd; 3506 char *ptr; 3507 int maxlen; 3508 char zechar; 3509 { 3510 1 int bytesread; 3511 1 3512 1 CheckGfio(fd); 3513 1 if (Gfio == NULL) 3514 1 return(-1); 3515 1 3516 1 bytesread = FIOreadtoken(Gfio, ptr, maxlen, zechar); 3517 1 3518 1 Debug("readtoken: %s\n", (ptr-bytesread)); 3519 1 return(bytesread); 3520 1 } 3521 3522 3523 int 3524 sreadword(input, output, maxlen) 3525 char *input; 3526 char *output; 3527 int maxlen; 3528 { 3529 1 int n; 3530 1 char c; 3531 1 3532 1 for (n=0; n < maxlen; n++) { 3533 2 c = *input++; 3534 2 *output++ = c; 3535 2 if (isspace(c)) { 3536 3 *(output - 1) = '\0'; 3537 3 break; 3538 3 } 3539 2 3540 2 if (c == '\0') { 3541 3 break; 3542 3 } 3543 2 } 3544 1 3545 1 *output = '\0'; /* Tack a NULL on the end */ 3546 1 return(n); 3547 1 } 3548 3549 3550 /* 3551 * ZapCRLF removes all carriage returns and linefeeds from the end of 3552 * a C-string. 3553 */ 3554 3555 void 3556 ZapCRLF(inputline) 3557 char *inputline; UTIL 22-SEP-1995 18:31:19 VAX C V3.2-044 Page 8 V1.0 19-SEP-1995 13:16:05 [GOPHER.G2.VMS2_13.OBJECT]UTIL.C;2 (1) 3558 { 3559 1 int len; 3560 1 3561 1 len = strlen(inputline); 3562 1 3563 1 if (len == 0) 3564 1 return; 3565 1 inputline += len; 3566 1 inputline--; 3567 1 3568 1 if (*inputline == '\n' || *inputline == '\r') { 3569 2 *inputline = '\0'; 3570 2 if (len > 1) { 3571 3 inputline--; 3572 3 if (*inputline == '\n' || *inputline == '\r') 3573 3 *inputline = '\0'; 3574 3 } 3575 2 } 3576 1 } 3577 3578 /* 3579 * Utilities for dealing with HTML junk 3580 */ 3581 3582 static boolean *acceptable; 3583 static boolean acceptable_inited = FALSE; 3584 3585 void init_acceptable() 3586 { 3587 1 unsigned int i; 3588 1 char * good = 3589 1 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_$"; 3590 1 3591 1 acceptable = (boolean*) malloc(sizeof(boolean) * 256); 3592 1 3593 1 for(i=0; i<256; i++) 3594 1 acceptable[i] = FALSE; 3595 1 for(;*good; good++) 3596 1 acceptable[(unsigned int)*good] = TRUE; 3597 1 3598 1 acceptable_inited = TRUE; 3599 1 } 3600 3601 static char hex[17] = "0123456789abcdef"; 3602 3603 char from_hex(c) 3604 char c; 3605 { 3606 1 return (c>='0')&&(c<='9') ? c-'0' 3607 1 : (c>='A')&&(c<='F') ? c-'A'+10 3608 1 : (c>='a')&&(c<='f') ? c-'a'+10 3609 1 : 0; 3610 1 } 3611 3612 3613 /* 3614 * return a hex encoding of the char, UTIL 22-SEP-1995 18:31:19 VAX C V3.2-044 Page 9 V1.0 19-SEP-1995 13:16:05 [GOPHER.G2.VMS2_13.OBJECT]UTIL.C;2 (1) 3615 */ 3616 3617 char *to_hex(c) 3618 char c; 3619 { 3620 1 static char out[4]; 3621 1 3622 1 out[0] = '\0'; 3623 1 3624 1 out[0]='%'; 3625 1 out[1]=hex[c >> 4]; 3626 1 out[2]=hex[c & 15]; 3627 1 out[3]='\0'; 3628 1 3629 1 return(out); 3630 1 } 3631 3632 /* 3633 * Replace hex escape sequences with the proper codes... 3634 * 3635 * input and output can be the same if you want 3636 */ 3637 3638 void 3639 Fromhexstr(input, output) 3640 char *input, *output; 3641 { 3642 1 char c; 3643 1 unsigned int b; 3644 1 3645 1 while (*input) { 3646 2 if (*input == '%') { 3647 3 input++; 3648 3 c = *input++; 3649 3 b = from_hex(c); 3650 3 c = *input++; 3651 3 if (!c) break; 3652 3 *output++ = (b<<4) + from_hex(c); 3653 3 } 3654 2 else 3655 2 *output++ = *input++; 3656 2 } 3657 1 *output = '\0'; 3658 1 } 3659 3660 void 3661 Tohexstr(input, output) 3662 char *input, *output; 3663 { 3664 1 if ( (input == NULL) || (output == NULL) ) 3665 1 return; 3666 1 3667 1 if (acceptable_inited == FALSE) 3668 1 init_acceptable(); 3669 1 3670 1 while (*input) { 3671 2 UTIL 22-SEP-1995 18:31:19 VAX C V3.2-044 Page 10 V1.0 19-SEP-1995 13:16:05 [GOPHER.G2.VMS2_13.OBJECT]UTIL.C;2 (1) 3672 2 if (acceptable[(int)*input] == TRUE) { 3673 3 *output++ = *input++; 3674 3 } 3675 2 else { 3676 3 *output++ = '%'; 3677 3 *output++ = hex[*input >> 4]; 3678 3 *output++ = hex[*input & 15]; 3679 3 input++; 3680 3 } 3681 2 } 3682 1 3683 1 *output = '\0'; 3684 1 } 3685 3686 /* 3687 * This fcn hexifies everything 3688 */ 3689 3690 void 3691 Hexall(input, output) 3692 char *input, *output; 3693 { 3694 1 while (*input) { 3695 2 3696 2 *output++ = hex[*input >> 4]; 3697 2 *output++ = hex[*input & 15]; 3698 2 input++; 3699 2 } 3700 1 3701 1 *output = '\0'; 3702 1 } 3703 3704 3705 /* 3706 * String insensitive strstr 3707 */ 3708 3709 char * 3710 strcasestr(inputline, match) 3711 char *inputline; 3712 char *match; 3713 { 3714 1 int matchlen=0; 3715 1 int i, inlen; 3716 1 3717 1 matchlen = strlen(match); 3718 1 inlen = strlen(inputline); 3719 1 3720 1 for(i=0; i 1500) length = 1500; 3787 X buffer_desc.len = length; 3788 X buffer_desc.adr = buffer; 3789 X SYS$CLREF (0); 3790 X status = TCP_RECEIVE (&channel, &buffer_desc, &netlib_iosb, netlib_ast, 0); 3791 X if ((status & 1) == 0) 3792 X return (-1); 3793 X SYS$WAITFR (0); 3794 X if ((netlib_iosb.status & 1) == 0) { 3795 X if ((netlib_iosb.status == SS$_ABORT && 3796 X netlib_iosb.xxx == 0x086380da) /* CMUIP Connection Closing */ || 3797 X netlib_iosb.status == SS$_LINKDISCON) /* UCX link disconnecting */ 3798 X errno = EPIPE; 3799 X return (-1); 3800 X } 3801 X return (netlib_iosb.size); 3802 X } 3803 X 3804 X int netwrite (channel, buffer, length) 3805 X int channel; 3806 X char *buffer; 3807 X int length; 3808 X { 3809 X struct { 3810 X long len; 3811 X char *adr; 3812 X } buffer_desc; 3813 X int status; 3814 X 3815 X buffer_desc.len = length; 3816 X buffer_desc.adr = buffer; 3817 X SYS$CLREF (0); 3818 X status = TCP_SEND (&channel, &buffer_desc, 6, &netlib_iosb, netlib_ast, 0); 3819 X if ((status & 1) == 0) 3820 X return (-1); 3821 X SYS$WAITFR (0); 3822 X if ((netlib_iosb.status & 1) == 0) { 3823 X return (-1); 3824 X } 3825 X return (netlib_iosb.size); 3826 X } 3827 X 3828 #endif /* NETLIB */ 3829 3830 #if defined(VMS) && defined(CMUIP) 3831 X 3832 X /* 3833 X * netclose, netread, and netwrite for CMUIP 3834 X */ 3835 X 3836 X #include iodef 3837 X #include ssdef 3838 X 3839 X static struct { 3840 X short status; 3841 X short size; 3842 X long xxx; UTIL 22-SEP-1995 18:31:19 VAX C V3.2-044 Page 13 V1.0 19-SEP-1995 13:16:05 [GOPHER.G2.VMS2_13.OBJECT]UTIL.C;2 (1) 3843 X } cmu_iosb; 3844 X globalvalue NET$_CC; /* Connection Closing */ 3845 X 3846 X int netclose (channel) 3847 X int channel; 3848 X { 3849 X int status; 3850 X 3851 X status = SYS$QIOW (0, channel, IO$_DELETE, &cmu_iosb, 0, 0, 3852 X 0, 0, 0, 0, 0, 0); 3853 X status = SYS$DASSGN (channel); 3854 X 3855 X return (0); 3856 X } 3857 X 3858 X int netread (channel, buffer, length) 3859 X int channel; 3860 X char *buffer; 3861 X int length; 3862 X { 3863 X int status; 3864 X 3865 X if (length > 1500) length = 1500; 3866 X status = SYS$QIOW (0, channel, IO$_READVBLK, &cmu_iosb, 0, 0, 3867 X buffer, length, 0, 0, 0, 0); 3868 X if ((status & 1) == 0) 3869 X return (-1); 3870 X if ((cmu_iosb.status & 1) == 0) { 3871 X if (cmu_iosb.status == SS$_ABORT && cmu_iosb.xxx == NET$_CC) 3872 X errno = EPIPE; 3873 X return (-1); 3874 X } 3875 X return (cmu_iosb.size); 3876 X } 3877 X 3878 X int netwrite (channel, buffer, length) 3879 X int channel; 3880 X char *buffer; 3881 X int length; 3882 X { 3883 X int status; 3884 X 3885 X status = SYS$QIOW (0, channel, IO$_WRITEVBLK, &cmu_iosb, 0, 0, 3886 X buffer, length, 0, 1, 0, 0); 3887 X if ((status & 1) == 0) 3888 X return (-1); 3889 X if ((cmu_iosb.status & 1) == 0) 3890 X return (-1); 3891 X return (cmu_iosb.size); 3892 X } 3893 X 3894 #endif /* CMUIP */ 3895 3896 3897 3898 /* 3899 * Checks to see if Remote server is up.. UTIL 22-SEP-1995 18:31:19 VAX C V3.2-044 Page 14 V1.0 19-SEP-1995 13:16:05 [GOPHER.G2.VMS2_13.OBJECT]UTIL.C;2 (1) 3900 */ 3901 3902 boolean 3903 RemoteIsUp(host, port) 3904 char *host; 3905 int port; 3906 { 3907 1 ; 3908 1 return(TRUE); 3909 1 } 3910 3911 3912 Command Line ------------ CC/INCL=([-],[-.OBJECT])/DEFINE=(MULTINET=1,DEBUGGING,__VMS)/DEBUG/NOOPT/OBJ=[.VAX.DBG]/LIS=[.VAX.LIS] UTIL.C .