home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume6 / pserv < prev    next >
Text File  |  1989-03-06  |  19KB  |  840 lines

  1. Newsgroups: comp.sources.misc
  2. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  3. Message-Id: <8808112056.AA16787@ACC-SB-UNIX.ARPA>
  4. Subject: v06i054: PSERV sample programs
  5. Reply-To: lars@ACC-SB-UNIX.ARPA (Lars J Poulsen)
  6.  
  7. Posting-number: Volume 6, Issue 54
  8. Submitted-by: lars@ACC-SB-UNIX.ARPA (Lars J Poulsen)
  9. Archive-name: pserv
  10.  
  11. PSERV - a sample piece of functional TCP/IP Berkeley socket programming.
  12.  
  13. Every so often, programmers new to socket programming ask for working
  14. examples. I will give you this small example to play with.
  15.  
  16. This program is a minimal remote spooling package, intended to solve
  17. a personal problem: I use every day two VMS systems and a Unix system.
  18. In my work area we have a LaserWriter connected to the Unix system,
  19. but I have to ride a sloooow elevator two floors to get to a VMS printer.
  20.  
  21. I really wanted to write a small "lpd" client, but found that this
  22. would require the cooperation of system managers on both machines, since
  23. (1) LPD will only accept commands from known hosts
  24. (2) LPD will only accept connections from privileged ports (<1024)
  25.     and the Wollongong VMS package enforces this also; you need
  26.     system privileges to get a low-numbered port on WIN/TCP.
  27.  
  28. So I decided to write my own mini protocol. This program illustrates
  29. the basic mechanism used by any server/client pair, and is small enough
  30. to dink around with fairly safely. [After all, if the system lets an
  31. unprivileged user do it, it must be safe :-) ?]
  32.  
  33. The client runs un 4.3BSD or VMS/WIN/TCP; the server runs on 4.3BSD.
  34.  
  35. Enjoy.
  36.  
  37.     / Lars Poulsen
  38.       ACC Customer Service
  39. --------------------------------- Cut Here --------------------------------
  40. # This is a shell archive.  Remove anything before this line
  41. # then unpack it by saving it in a file and typing "sh file"
  42. # (Files unpacked will be owned by you and have default permissions).
  43. # This archive contains the following files:
  44. #    ./copytoheap.c
  45. #    ./filename.c
  46. #    ./listen.c
  47. #    ./rmtprint.c
  48. #    ./strpak.c
  49. #    ./Makefile
  50. #
  51. if `test ! -s ./copytoheap.c`
  52. then
  53. echo "writing ./copytoheap.c"
  54. cat > ./copytoheap.c << '\Rogue\Monster\'
  55. static char rcsid[] = "$Header: copytoheap.c,v 3.5 87/05/26 14:16:25 lars Production $";
  56.  
  57. #include <stdio.h>
  58.  
  59. extern char *malloc();
  60. extern int   strlen();
  61.  
  62. char *
  63. copytoheap(string)
  64.     char *string;
  65. {
  66.     char *temp;
  67.     int   size;
  68.     if (string == NULL) return NULL;
  69.     size = strlen(string)+1;
  70.     if (size > 64*1024)
  71.     {
  72.     fprintf(stderr,"copytoheap: object too large (%d bytes)\n",size);
  73.     exit(-1);
  74.     }
  75.     temp = malloc(size);
  76.     strcpy(temp,string);
  77.     return temp;
  78. }
  79. \Rogue\Monster\
  80. else
  81.   echo "will not over write ./copytoheap.c"
  82. fi
  83. if `test ! -s ./filename.c`
  84. then
  85. echo "writing ./filename.c"
  86. cat > ./filename.c << '\Rogue\Monster\'
  87. static char rcsid[] = "$Header: filename.c,v 3.3 88/08/07 19:00:37 lars Exp $";
  88.  
  89. /* filename.c - extract the FILENAME part from a pathname string
  90.  *              written by Lars Poulsen <lars@acc.arpa>
  91.  *              for the ACC PSR system
  92.  *
  93.  * $Header: filename.c,v 3.3 88/08/07 19:00:37 lars Exp $
  94.  *
  95.  * $Log:    filename.c,v $
  96.  * Revision 3.3  88/08/07  19:00:37  lars
  97.  * handle vms-filenames also:
  98.  * if name contains a slash, it's a unix name.
  99.  * else, if it has "]" or ":", cut off what's before those.
  100.  * 
  101.  * Revision 3.2  87/05/18  13:36:19  lars
  102.  * First stable version of PSR after pf_get/pf_write went in
  103.  * 
  104.  * Revision 3.1  87/05/16  21:16:55  lars
  105.  * At end of splitting up (First stable version)
  106.  * 
  107.  */
  108. extern char *rindex();
  109.  
  110. char   *
  111. filename(path)
  112.     char   *path;
  113. {
  114.     char   *ptr;
  115.  
  116. /* first deal with unix filenames */
  117.     ptr = rindex(path, '/');
  118.     if (ptr)
  119.     return ++ptr;
  120.     /* now deal with vmsisms */
  121.  
  122.     ptr = rindex(path, ']');
  123.     if (ptr)
  124.     return ++ptr;
  125.     ptr = rindex(path, ':');
  126.     if (ptr)
  127.     return ++ptr;
  128.     return path;
  129. }
  130. \Rogue\Monster\
  131. else
  132.   echo "will not over write ./filename.c"
  133. fi
  134. if `test ! -s ./listen.c`
  135. then
  136. echo "writing ./listen.c"
  137. cat > ./listen.c << '\Rogue\Monster\'
  138. /* listen.c - a server daemon to match "rmtprint"
  139.  *
  140.  * Written by Lars Poulsen <lars@acc-sb-unix.arpa>
  141.  *    August 1988
  142.  *
  143.  *    This is a simple example of a TCP based network server.
  144.  */
  145. #include <ctype.h>
  146. #include <stdio.h>
  147. #include <sys/types.h>
  148. #include <errno.h>
  149. #include <signal.h>
  150. #include <sys/socket.h>
  151. #include <netinet/in.h>
  152. #include <netdb.h>
  153. #include <pwd.h>
  154.  
  155. #define MY_PORT 12345
  156. #define ANY_PORT 0
  157. #define DEFPRT "mac7"
  158. #define FORKING    1
  159.  
  160. extern int errno;
  161.  
  162. extern char *asctime();
  163. extern struct tm *localtime();
  164. extern char *mktemp();
  165. extern long time();
  166.  
  167. extern char *copytoheap();
  168. extern char *filename();
  169.  
  170. char   *what_alarm = NULL;
  171. char    temp_name[40];
  172. int     forking = 0;
  173. extern char *home_directory();
  174. extern exit_server();
  175. extern  timeout();
  176. extern  wait_child();
  177.  
  178. char   *
  179. tstamp()
  180. {
  181.     long    time_now;
  182.     char   *temp;
  183.  
  184.     time_now = time(0);
  185.     temp = asctime(localtime(&time_now)) + 4;
  186.     temp[12] = 0;
  187.     return temp;
  188. }
  189.  
  190. main(argc, argv)
  191.     int     argc;
  192.     char   *argv[];
  193.  
  194. {
  195.     int     s,
  196.             cs;
  197.     struct sockaddr_in my_name;
  198.     struct sockaddr_in any_name;
  199.     struct sockaddr_in his_name;
  200.     int     idsw;
  201.     int     his_addr_len;
  202.  
  203.     forking = FORKING;        /* done this way in case it is an expression */
  204.  
  205.     signal(SIGALRM, timeout);
  206.     signal(SIGCHLD, wait_child);
  207.     signal(SIGTERM, exit_server);
  208.     printf("%s Print server starting - defprt = %s\n", tstamp(), DEFPRT);
  209.     fflush(stdout);
  210.  
  211.     s = socket(AF_INET, SOCK_STREAM, 0);    /* protocol #0 is IP */
  212.     if (0)
  213.     printf("tcp: got socket fd=%d (Hex: %x)\n", s, s);
  214.  
  215.     bzero((char *) &my_name, sizeof(my_name));
  216.     my_name.sin_family = AF_INET;
  217.     my_name.sin_port = htons(MY_PORT);
  218.     my_name.sin_addr.s_addr = INADDR_ANY;
  219.  
  220.     idsw = bind(s, &my_name, sizeof(my_name));
  221.     if (idsw != 0)
  222.     printf("tcp: bind returned %d - errno = %d\n", idsw, errno);
  223.  
  224.     bzero((char *) &any_name, sizeof(any_name));
  225.     any_name.sin_family = AF_INET;
  226.     any_name.sin_port = htons(ANY_PORT);
  227.     any_name.sin_addr.s_addr = INADDR_ANY;
  228.     idsw = listen(s, 0);
  229.     if (idsw != 0)
  230.     printf("listen: listen returned %d - errno = %d\n", idsw, errno);
  231. next_in_file:
  232.     alarm(0);
  233.     bzero((char *) &his_name, sizeof(his_name));
  234.     his_addr_len = sizeof(his_name);
  235.     cs = accept(s, &his_name, &his_addr_len);
  236.     if (cs < 0)
  237.     {
  238.     printf("listen: accept failed,  errno = %d his_addr_len = %d\n",
  239.            errno, his_addr_len);
  240.     fflush(stdout);
  241.     exit(errno);
  242.     }
  243.     process_a_file(cs);
  244.     goto next_in_file;
  245. }
  246.  
  247. process_a_file(cs)
  248. {
  249.     int     bcnt;
  250.     char    buffer[512];
  251.     int     ofd;
  252.     char    printer[20],
  253.             rmtuser[40],
  254.             rmtfile[80];
  255.     int     file_size = 0;
  256.     int     idsw;
  257.  
  258.     if (forking)
  259.     {
  260.     idsw = fork();
  261.     if (idsw < 0)
  262.     {
  263.         printf("%s listen: Fatal error - fork() failed with error = %d\n",
  264.            tstamp(), -idsw);
  265.         exit(-idsw);
  266.     }
  267.     if (idsw != 0)        /* parent listens for next connection */
  268.     {
  269.         close(cs);
  270.         return;
  271.     }
  272.     }
  273.     what_alarm = "Reading Command Line";
  274.     alarm(30);
  275.  
  276.     if (get_command(cs, printer, rmtuser, rmtfile) != 0)
  277.     {
  278.     printf("%s Bad incoming commnd %s %s %s\n",
  279.            tstamp(), printer, rmtuser, rmtfile);
  280.     fflush(stdout);
  281.     close(cs);
  282.     return;
  283.     }
  284.     printf("%s Received connection %s %s %s\n",
  285.        tstamp(), printer, rmtuser, rmtfile);
  286.     fflush(stdout);
  287.  
  288.     ofd = open_out_file(printer, rmtuser, rmtfile);
  289.  
  290.     what_alarm = "Receiving File";
  291.     alarm(30);
  292.     while (bcnt = recv(cs, buffer, sizeof(buffer), 0))
  293.     {
  294.     write(ofd, buffer, bcnt);
  295.     alarm(30);
  296.     file_size += bcnt;
  297.     if (buffer[bcnt - 1] == 0)
  298.         break;
  299.     }
  300.     close(cs);
  301.     printf("%s Received %d bytes for %s %s %s\r\n",
  302.        tstamp(), file_size, printer, rmtuser, rmtfile);
  303.     fflush(stdout);
  304.  
  305.     what_alarm = "Printing File";
  306.     alarm(5);
  307.     if (strcmp(printer, "save") != 0)
  308.     {
  309.     check_printer(printer, DEFPRT);
  310.     sprintf(buffer, "lpr -P %s -r -s %s", printer, temp_name);
  311.     idsw = system(buffer);
  312.     if (idsw)
  313.     {
  314.         printf("listen: lpr command returned %d\n", idsw);
  315.         fflush(stdout);
  316.     }
  317.     }
  318.     if (forking)
  319.     exit(0);
  320.     else
  321.         return;
  322. }
  323.  
  324. get_command(nfd, printer, rmtuser, rmtfile)
  325.     int     nfd;
  326.     char   *printer,
  327.            *rmtuser,
  328.            *rmtfile;
  329. {
  330.     char    c,
  331.            *p;
  332.     extern char readch();
  333.  
  334.     p = printer;
  335.     while (isalnum(c = readch(nfd)))
  336.     *(p++) = c;
  337.     *p = 0;
  338.     if (c != ' ')
  339.     goto cmd_error;
  340.  
  341.     p = rmtuser;
  342.     while (isalnum(c = readch(nfd)))
  343.     *(p++) = c;
  344.     *p = 0;
  345.     if (c != ' ')
  346.     goto cmd_error;
  347.  
  348.     p = rmtfile;
  349.     while ((c = readch(nfd)) && (c > ' '))
  350.     *(p++) = c;
  351.     if (!isspace(c))
  352.     goto cmd_error;        /* space or \n */
  353.     *p = 0;
  354.     return 0;
  355. cmd_error:
  356.     printf("syntax error in print command *p = %d\n", *p);
  357.     printf("printer = %s user = %s filename = %s\n",
  358.        printer, rmtuser, rmtfile);
  359.     return -1;
  360. }
  361. char
  362. readch(fd)
  363. {
  364.     char    buf;
  365.  
  366. begin:
  367.     if (recv(fd, &buf, 1, 0) != 1)
  368.     {
  369.     printf("readch(%d) got error %d\n", fd, errno);
  370.     return 0;
  371.     }
  372.     if (buf == 0)
  373.     goto begin;
  374.     return buf;
  375. }
  376.  
  377. check_printer(printer, defprt)
  378.     char   *printer,
  379.            *defprt;
  380. {
  381.     char    fname[80];
  382.     int     fd;
  383.     int     err;
  384.  
  385. /* The following check is bad: If the device exists and is busy,
  386.     we will wait forever for the daemon to exit... */
  387.     if (0)
  388.     {
  389.     sprintf(fname, "/dev/%s", printer);
  390.     errno = 0;
  391.     fd = open(fname, 0, 0);
  392.     err = errno;
  393.     close(fd);
  394.     if (errno == ENOENT)
  395.         goto failed;
  396.     }
  397.     sprintf(fname, "/usr/spool/%s", printer);
  398.     errno = 0;
  399.     fd = open(fname, 0, 0);
  400.     err = errno;
  401.     close(fd);
  402.     if (errno)
  403.     goto failed;
  404.  
  405.     return;
  406. failed:
  407.     printf("%s Failed to open %s - errno = %d\n",
  408.        tstamp, fname, err);
  409.     printf("%s %s is not a valid printer, %s substituted\n",
  410.        tstamp, printer, defprt);
  411.     fflush(stdout);
  412.     strcpy(printer, defprt);
  413.     return;
  414. }
  415.  
  416. /* alarm clock is used to debug hang's */
  417. timeout()
  418. {
  419.     printf("%s Fatal Timeout While %s\n", tstamp(), what_alarm);
  420.     exit(2);
  421. }
  422.  
  423. /* dummy child handler - just get rid of <defunct> child */
  424. wait_child()
  425. {
  426.     wait(0);
  427. }
  428.  
  429. /* clean exit on a simple "kill" */
  430. exit_server()
  431. {
  432.     printf("%s Received SIGTERM - exiting\n", tstamp());
  433.     exit(0);
  434. }
  435.  
  436. open_out_file(printer, rmtuser, rmtfile)
  437.     char   *printer,
  438.            *rmtuser,
  439.            *rmtfile;
  440. {
  441.     int     ofd;
  442.     char   *directory;
  443.  
  444.     rmtfile = filename(rmtfile);
  445.     if ((directory = home_directory(rmtuser)) == NULL)
  446.     directory = "/tmp";
  447.     sprintf(temp_name, "%s/%s", directory, rmtfile);
  448.     if ((ofd = open(temp_name, 0) < 0) && errno == ENOENT)
  449.     /* no such file exists */
  450.     ofd = creat(temp_name, 0644);
  451.     if (ofd >= 0)
  452.     return ofd;
  453.  
  454.     close(ofd);
  455.  
  456.     strcpy(temp_name, "/tmp/spoolXXXXXX");
  457.     (void) mktemp(temp_name);
  458.     ofd = creat(temp_name, 0644);
  459.     return ofd;
  460. }
  461. char   *
  462. home_directory(name)
  463.     char   *name;
  464. {
  465.     struct passwd *pw;
  466.     char   *hd;
  467.  
  468.     setpwent();
  469.     for (pw = getpwent(); pw; pw = getpwent())
  470.     {
  471.     if (strcmp_nocase(pw->pw_name, name) == 0)
  472.         break;
  473.     }
  474.     if (pw)
  475.     hd = copytoheap(pw->pw_dir);
  476.     else
  477.     hd = NULL;
  478.     if (forking && !geteuid())
  479.     setuid(pw->pw_uid);    /* try to set this child to the right userid */
  480.     endpwent();
  481.     return hd;
  482. }
  483. \Rogue\Monster\
  484. else
  485.   echo "will not over write ./listen.c"
  486. fi
  487. if `test ! -s ./rmtprint.c`
  488. then
  489. echo "writing ./rmtprint.c"
  490. cat > ./rmtprint.c << '\Rogue\Monster\'
  491. #include <stdio.h>
  492. #include <signal.h>
  493. #ifdef VAXC
  494. #include "twg$tcp:[netdist.include.sys]types.h"
  495. #include "twg$tcp:[netdist.include]errno.h"
  496. #include "twg$tcp:[netdist.include.sys]socket.h"
  497. #include "twg$tcp:[netdist.include.netinet]in.h"
  498. #include "twg$tcp:[netdist.include]netdb.h"
  499. #else
  500. #include <sys/types.h>
  501. #include <errno.h>
  502. #include <sys/socket.h>
  503. #include <netinet/in.h>
  504. #include <netdb.h>
  505. #define uerrno errno
  506. #endif
  507.  
  508. #define MY_PORT 0
  509. #define HIS_PORT 12345
  510.  
  511. extern int uerrno;
  512. extern timeout();
  513. char *what_alarm = "Name Service";
  514.  
  515. main(argc, argv)
  516.     int     argc;
  517.     char   *argv[];
  518.  
  519. {
  520.     int     s;
  521.     struct sockaddr_in my_name;
  522.     struct sockaddr_in his_name;
  523.     int     idsw;
  524.     int     namelen;
  525.     struct hostent *gethostbyname(),
  526.            *salt_ent;
  527.     u_long *found_addr;
  528.     struct servent *sp;
  529.     char    buffer[512];
  530.     int     bcnt;
  531.     int     ifd;
  532.     char    cmdbuf[80];
  533.     int null = 0;
  534.  
  535.     if (argc != 4)
  536.     {
  537.     printf("usage: rmtprint host printer file\n");
  538.     exit(1);
  539.     }
  540.     s = socket(AF_INET, SOCK_STREAM, 0);    /* protocol #0 is IP */
  541.     if (0)
  542.     printf("tcp: got socket fd=%d (Hex: %x)\n", s, s);
  543.  
  544.     bzero((char *) &my_name, sizeof(my_name));
  545.     my_name.sin_family = AF_INET;
  546.     my_name.sin_port = MY_PORT;
  547.     my_name.sin_addr.s_addr = INADDR_ANY;
  548.  
  549.     idsw = bind(s, &my_name, sizeof(my_name));
  550.     if (idsw != 0)
  551.     printf("tcp: bind returned %d - uerrno = %d\n", idsw, uerrno);
  552.  
  553.     signal(SIGALRM, timeout);
  554.     alarm(30);
  555.     salt_ent = gethostbyname(argv[1]);
  556.     if (salt_ent) found_addr = (u_long *)salt_ent->h_addr_list[0];
  557.     if ((salt_ent == NULL) || (found_addr == 0))
  558.     {
  559.     printf("rmtprint: %s is not a known host\n", argv[1]);
  560.     exit(2);
  561.     }
  562.     bzero((char *) &his_name, sizeof(his_name));
  563.     his_name.sin_family = AF_INET;
  564.     sp = getservbyname("rmtprint", "tcp");
  565.     if (sp)
  566.     his_name.sin_port = sp->s_port;
  567.     else
  568.     his_name.sin_port = htons(HIS_PORT);
  569.     bcopy(salt_ent->h_addr_list[0], &his_name.sin_addr, salt_ent->h_length);
  570.  
  571.     what_alarm = "Connection Request";
  572.     alarm(30);
  573.     idsw = connect(s, &his_name, sizeof(my_name));
  574.     if (idsw != 0)
  575.     {
  576.     idsw = uerrno;
  577.     printf("rmtprint: Connect to %s port %d returned Unix error %d\n",
  578.            argv[1], ntohs(his_name.sin_port), idsw);
  579.     if (idsw == 61)
  580.         printf("rmtprint: Connection refused by %s - server not running ?\n",
  581.            argv[1]);
  582.     exit(2);
  583.     }
  584.     what_alarm = "Sending Command Line";
  585.     alarm(30);
  586.     sprintf(cmdbuf, "%s %s %s\n", argv[2], getenv("USER"), argv[3]);
  587.     send(s, cmdbuf, strlen(cmdbuf), 0);
  588.     what_alarm = "Sending File";
  589.     ifd = open(argv[3], 0, 0);
  590.     if (ifd < 0)
  591.     {idsw = errno;
  592.     printf("rmtprint: Failed to open %s errno = %d\n", argv[3], idsw);
  593.     exit(idsw);
  594.     }
  595.     bcnt = read(ifd, buffer, sizeof(buffer));
  596.     while (bcnt > 0)
  597.     {
  598.         alarm(30);
  599.     send(s, buffer, bcnt, 0);
  600.     bcnt = read(ifd, buffer, sizeof(buffer));
  601.     }
  602.     if (errno) printf("rmtprint: read ended with errno = %d\n",errno);
  603.     close(ifd);
  604.     sleep(1);
  605.     send(s, &null, 1, 0);
  606.     recv(s, buffer, sizeof(buffer), 0);
  607.     close(s);
  608.     exit(1);
  609. }
  610. timeout()
  611. {
  612.     printf("rmtprint: Fatal timeout during %s\n", what_alarm);
  613.     exit(4);
  614. }
  615. \Rogue\Monster\
  616. else
  617.   echo "will not over write ./rmtprint.c"
  618. fi
  619. if `test ! -s ./strpak.c`
  620. then
  621. echo "writing ./strpak.c"
  622. cat > ./strpak.c << '\Rogue\Monster\'
  623. static char rcsid[] = "$Header: strpak.c,v 1.10 88/08/07 20:18:49 lars Exp $";
  624. #include <stdio.h>
  625. #include <ctype.h>
  626. extern char *index();
  627. extern char *malloc();
  628.  
  629. char *
  630. str_firstline(multi_field)
  631.     char *multi_field;
  632. {
  633.     char *end_of_line;
  634.     static int i = 0;
  635.     static char buf[4][80];
  636.     i = (i+1)&3;
  637.     strncpy(buf[i], multi_field, 80);
  638.     if (end_of_line = index(buf[i],'\n')) *end_of_line = 0;
  639.     return buf[i];
  640. }
  641.  
  642. char *
  643. str_firstword(multi_field)
  644.     char *multi_field;
  645. {
  646.     char *end_of_line;
  647.     static int i = 0;
  648.     static char buf[4][80];
  649.     i = (i+1)&3;
  650.     strncpy(buf[i], multi_field, 80);
  651.     for (end_of_line = buf[i]; isalpha(*end_of_line); end_of_line++);
  652.     *end_of_line = 0;
  653.     return buf[i];
  654. }
  655.  
  656. char *str_join3(a,b,c)
  657.     char *a, *b, *c;
  658. {
  659.     int size = strlen(a) + strlen(b) + strlen(c) +1;
  660.     char *new;
  661.     char *pp;
  662.  
  663.     pp = new = malloc(size);
  664.     if (new == NULL) return NULL;
  665.     if (a != NULL) while (*a) *(pp++) = *(a++);
  666.     if (b != NULL) while (*b) *(pp++) = *(b++);
  667.     if (c != NULL) while (*c) *(pp++) = *(c++);
  668.     *pp = 0;
  669.     return new;
  670. }
  671.  
  672. int str_lines(string)
  673.     char *string;
  674. {
  675.     char *pp = string;
  676.     char c;
  677.     int count = 1;
  678.  
  679.     if (string == NULL) return 0;
  680.     if (strlen(string) == 0) return 0;
  681.  
  682.     while(c = *pp++)
  683.     if (c == '\n')
  684.         count ++;
  685.     return count;
  686. }
  687.  
  688. int str_longest(string)
  689.     char *string;
  690. {
  691.     int lines, longest = 0, total;
  692.     int thislen;
  693.     char *thisline, *nextline;
  694.  
  695.     if (string == NULL) return 0;
  696.     if ((total = strlen(string)) == 0) return 0;
  697.     lines = str_lines(string);
  698.     thisline = string;
  699.     while (--lines)
  700.     {
  701.       nextline = index(thisline,'\n') + 1;
  702.       if (nextline == NULL)
  703.       {
  704.       fprintf(stderr,"str_longest: Program bug !!\n");
  705.           exit(-1);
  706.       }
  707.       thislen = nextline - thisline - 1;
  708.       if (thislen > longest) longest = thislen;
  709.       thisline = nextline;
  710.     }
  711.     thislen = strlen(thisline);
  712.     if (thislen > longest) longest = thislen;
  713.     return longest;
  714. }
  715.  
  716. char *
  717. str_trim(string)
  718.     char *string;
  719. {
  720.     char *pp;
  721.     int length;
  722.     static int i = 0;
  723.     static char buf[4][80];
  724.  
  725.     if (string == NULL) return NULL;
  726.     i = (i+1)&3;
  727.  
  728.     pp = string + strlen(string) - 1;
  729.     while ((*pp == 0) || (*pp == ' ') || (*pp == '\n')
  730.     || (*pp == '\t') || (*pp == '_'))
  731.     pp--;
  732.     length = pp - string + 1;
  733.     if (length <= 0) return NULL;
  734.     strncpy(buf[i],string, length);
  735.     buf[i][length] = 0;
  736.     return buf[i];
  737. }
  738.  
  739. #define MAXINIT 3
  740. char   *
  741. str_initials(name)
  742.     char   *name;
  743. {
  744.     static char init[4][MAXINIT + 1];
  745.     static int i = 0;
  746.     int     j;
  747.     char   *p;
  748.     char    c;
  749.  
  750.     if (name == NULL)
  751.     return "";
  752.     if (strlen(name) == 0)
  753.     return "";
  754.  
  755.     i = (++i) & 3;
  756.     j = 0;
  757.     p = name;
  758.  
  759.     while ((c = *(p++)) && (j < MAXINIT))
  760.     if (isupper(c))
  761.         init[i][j++] = c;
  762.     init[i][j] = 0;
  763.     return init[i];
  764. }
  765.  
  766. /*
  767.  * Compare strings (at most n bytes):  s1>s2: >0  s1==s2: 0  s1<s2: <0
  768.  */
  769.  
  770. strncmp_nocase(s1, s2, n)
  771. register char *s1, *s2;
  772. register n;
  773. {
  774.     register char c1, c2;
  775.  
  776.     while (--n >= 0)
  777.     {
  778.        c1 = *s1++;
  779.        if (c1 == 0) return 0;
  780.        if (isupper(c1)) c1 = tolower(c1);
  781.  
  782.        c2 = *s2++;
  783.        if (c2 == 0) return 0;
  784.        if (isupper(c2)) c2 = tolower(c2);
  785.  
  786.        if (c1 != c2) break;
  787.     }
  788.     return(n<0 ? 0 : c1 - c2);
  789. }
  790. strcmp_nocase(s1, s2)
  791. register char *s1, *s2;
  792. {
  793.     register char c1, c2;
  794.  
  795.     while (1)
  796.     {
  797.        c1 = *s1++;
  798.        if (isupper(c1)) c1 = tolower(c1);
  799.        c2 = *s2++;
  800.        if (isupper(c2)) c2 = tolower(c2);
  801.  
  802.        if (c1 == 0) break;
  803.        if (c2 == 0) break;
  804.        if (c1 != c2) break;
  805.     }
  806.     return(c1 - c2);
  807. }
  808. \Rogue\Monster\
  809. else
  810.   echo "will not over write ./strpak.c"
  811. fi
  812. if `test ! -s ./Makefile`
  813. then
  814. echo "writing ./Makefile"
  815. cat > ./Makefile << '\Rogue\Monster\'
  816. all: listen rmtprint
  817.  
  818. listen: listen.o copytoheap.o filename.o strpak.o
  819.     cc -o listen -g listen.o copytoheap.o filename.o strpak.o
  820.  
  821. rmtprint: rmtprint.o
  822.     cc -o rmtprint -g rmtprint.o
  823.  
  824. listen.o: listen.c
  825.  
  826. rmtprint.o: rmtprint.c
  827.  
  828. copytoheap.o: copytoheap.c
  829.  
  830. filename.o: filename.c
  831.  
  832. strpak.o: strpak.c
  833. \Rogue\Monster\
  834. else
  835.   echo "will not over write ./Makefile"
  836. fi
  837. echo "Finished archive 1 of 1"
  838. # if you want to concatenate archives, remove anything after this line
  839. exit
  840.