home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / misc / volume06 / pserv < prev    next >
Encoding:
Internet Message Format  |  1991-08-27  |  19.0 KB

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