home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_sys5 / unixkit.tgz / unixkit.tar / unixkit / lwp / bsdunix.c next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  19.5 KB  |  879 lines

  1. /*            NOS porting kit for UNIX with LWP
  2.  *                    900410
  3.  *
  4.  * Files are: bsdunix.c, asy.h, bsd_io.c, bsd_nit.c, bsd_tun.c, kernel.c,
  5.  * proc.h, global.h, Makefile
  6.  *
  7.  * This runs on a Sun-4, Sun-3, and Sun386i with the LWP library.
  8.  * The NIT and TUN drivers are activated by defining PACKET in config.h but
  9.  * you need to run NOS as root to use them. TUN is the more efficient, so
  10.  * I recommend its usage over NIT.
  11.  *
  12.  * You need release 900312 or later of KA9Q NOS to use these files.
  13.  *
  14.  * You will probably have to increase the definition of MSPTICK in
  15.  * timer.h. Try setting it to 100 (100 milliseconds/tick).
  16.  * Delete any lines that cause troubles in hardware.h.
  17.  * (The definition of "setbit", "clrbit", and "Intstk" are usually
  18.  * the only problems)
  19.  *
  20.  * You need to add the following line to the assignment of Daemons[]
  21.  * in the file config.c:
  22.  *      "interval timer", 1024, ctick,
  23.  *
  24.  * There will be other compiler errors too, since NOS was written for
  25.  * Turbo-C. But you are expected to fix those yourself.
  26.  *
  27.  * 
  28.  * Written by Anders Klemets, SM0RGV, klemets@sics.se
  29.  * (a few functions at the end were written by Mikel Matthews, N9DVG
  30.  *  Jere Sandidge, K4FUM, and some others.)
  31.  * I would appreciate to see any improvements you make.
  32.  *
  33.  */
  34.  
  35.  /*
  36.   * Overhaul by KA9WSB, November, 1991 for later versions of NOS.
  37.   * See the "README" file for more details!  KA9WSB
  38.   */
  39.  
  40.  /*   KA9WSB
  41.   * Seems that the original stuff used unbuffered output... Seems a
  42.   * shame to make the system hang up waiting to send some characters
  43.   * to a display.  By inserting a line like:
  44.   *    #define BUFFERED_OUTPUT
  45.   * we will turn on buffered output.  The side effect is that
  46.   * we have to call fflush every few clock ticks...  You can do
  47.   *    #define TICKS_PER_FLUSH 10
  48.   * to call fflush once every 10 ticks (default is once every 5 ticks).
  49.   * Shoot for between a quarter and a half of a second...
  50.   * Note that this makes debugging a bit more difficult, as the progam
  51.   * may crash without printing the final bit of output...
  52.   */
  53.  /*   KA9WSB
  54.   * Seems that LWP crashes if you use buffered output... Don't know
  55.   * why, but until we find and fix it, best not use it.
  56.   */
  57. #undef BUFFERED_OUTPUT
  58.  
  59. #include <stdio.h>
  60. #include <sys/types.h>
  61. #include <lwp/lwp.h>
  62. #include <lwp/lwperror.h>
  63. #include <signal.h>
  64. #include <fcntl.h>
  65. #include <sys/ioctl.h>
  66. #include <sys/time.h>
  67. #include <sys/resource.h>
  68. #include <sys/stat.h>
  69. #include <sys/param.h>
  70. #include <dirent.h>
  71. #include <ctype.h>
  72.  
  73.  /*   KA9WSB
  74.   * free handling...
  75.   * This is grungy 'cause free() in most unix machines pukes if handed
  76.   * a null pointer.  So we have to check.  The "easy" way is to define
  77.   * a variable named "xxfree" which is an indirect pointer to the real
  78.   * system free().  Then, in "global.h", we define free to be a macro:
  79.   *      ((char *)p != NULLCHAR ? (*xxfree)(p) : 0)
  80.   * Neat huh??
  81.   * Only one problem -- code like this:
  82.   *      free(*argv++);
  83.   * fails!  Why?  Well, it translates to:
  84.   *      ((char *)*argv++ != NULLCHAR ? (*xxfree)(*argv++) : 0)
  85.   * which increments argv twice; the first time by one byte,
  86.   * the second time by whatever argv is declared to be! (this
  87.   * little gem was gleaned from kernel.c; it ended up incrementing
  88.   * argv by 5 bytes instead of 4)  To solve this problem, you are
  89.   * offered two choices:  search for all every occurence of "free"
  90.   * in all the c sources (grep works nicely), and verify that none
  91.   * will break if expanded into the above macro.  Or, add the
  92.   * following flag to the CCFLAGS line in the makefile:
  93.   * -DBULLET_PROOF_FREE
  94.   *
  95.   */
  96. int free();         /* This must be before we include global.h */
  97. #ifndef BULLET_PROOF_FREE
  98. int (*xxfree)() = free; /* if we are not using alloc.c */
  99. #else
  100. int xyfree(q) char *q;{if(q)return free(q);else return 0;}
  101. #endif
  102.  
  103. #include "global.h"
  104. #include "config.h"
  105. #include "iface.h"
  106. #include "proc.h"
  107. #include "timer.h"
  108. #include "session.h"
  109. #include "asy.h"
  110. #include "hardware.h"
  111.  
  112. void inpint(),iostop();
  113. int32 Clock, StartSec, StartUsec;
  114. int Tick, console;
  115. FILE *Rawterm = stdout;
  116. struct sgttyb mysavetty, savecon;
  117. int console_saved = 0;
  118. int Intstk[1024]; /* The signal stack */
  119. struct proc *ctickp = NULLPROC;
  120. static struct proc *inpintp = NULLPROC;
  121. static mon_t mid;
  122.  
  123. /* Interface list header */
  124. struct iface *Ifaces;
  125.  
  126. /* Keyboard input buffer */
  127. struct fifo Keyboard;
  128.  
  129. extern struct proc *Display;
  130.  
  131. int shell=0,intoff=0;
  132.  
  133.  /*  KA9WSB
  134.   *  define MALLOCDEBUG in the makefile to use the malloc debugging stuff.
  135.   *  Note that if you do this, you will have to load /usr/lib/debug/malloc.o
  136.   *  before libc in the makefile...
  137.   */
  138. #ifdef MALLOCDEBUG
  139. int malloc_debug();    /* in the /usr/lib/debug/malloc.o library */
  140. int malloc_verify();    /* in the /usr/lib/debug/malloc.o library */
  141. #endif
  142.  
  143.  /* KA9WSB
  144.   * Debugging trick... #define QUERY_INPUT and NOS will check the NOS_TTY
  145.   * environment variable for the device to use for input... thus making
  146.   * it possible to debug NOS under dbxtool.  Fire up another shelltool,
  147.   * use the tty command to find out the tty name (something like 
  148.   * /dev/ttyp2), and then type "sleep 30000" to make the shell in that
  149.   * window go away.  Now in another shelltool type "setenv NOS_TTY
  150.   * /dev/ttyp2", fire up dbxtool with nos in it, type "ignore IO" 
  151.   * (so dbxtool will let nos handle the SIGIO envents, and type "run".
  152.   * NOS will now be happily taking input from the sleeping window.
  153.   */
  154. #define QUERY_INPUT
  155.  
  156. /* Called at startup time to set up console I/O, memory heap */
  157. void
  158. ioinit()
  159. {
  160.     struct sgttyb ttybuf;
  161.         struct sigstack ss;
  162.     struct sigvec sv;
  163.     struct timeval tp;
  164.     char *ttydev;
  165.  
  166. #ifdef MALLOCDEBUG
  167. #ifndef MALLOCDEBUG_LEVEL
  168. #define MALLOCDEBUG_LEVEL 1
  169. #endif
  170.     (void)malloc_debug(MALLOCDEBUG_LEVEL);
  171. #endif
  172.  
  173.     /* begin by recording the start time as NOW */
  174.     gettimeofday(&tp,NULL);
  175.     StartSec = tp.tv_sec;
  176.     StartUsec = tp.tv_usec;
  177.     Clock = 0;
  178.  
  179.     /* We want unbuffered output */
  180.     if(isatty(1)) {
  181. #ifndef BUFFERED_OUTPUT
  182.         freopen(ttyname(1),"w",stdout);
  183.         setbuf(stdout,NULLCHAR);
  184. #endif
  185.  
  186. #ifdef QUERY_INPUT
  187.         ttydev = getenv("NOS_TTY");
  188.         if(ttydev==NULL) ttydev = "/dev/tty";
  189. #else
  190.         ttydev = "/dev/tty";
  191. #endif
  192.         if ((console = open(ttydev,O_RDONLY|O_NDELAY)) < 0) {
  193.         perror(ttydev);
  194.         exit(1);
  195.         }
  196.         ioctl(console,TIOCGETP,&ttybuf);
  197.         savecon = ttybuf;
  198.         ttybuf.sg_flags &= ~ECHO;
  199.         ttybuf.sg_flags |= CBREAK;
  200.         ioctl(console,TIOCSETP,&ttybuf);
  201.         console_saved = 1;
  202.     }
  203.     else console = 0;
  204.  
  205.     (void) signal(SIGHUP, iostop);
  206.     (void) signal(SIGINT, iostop);
  207.     (void) signal(SIGQUIT, iostop);
  208.     (void) signal(SIGTERM, iostop);
  209.  
  210.     /* Initialize keyboard queue */
  211.     Keyboard.bufsize = 256;
  212.     Keyboard.buf = malloc (256);
  213.     Keyboard.rp = Keyboard.wp = Keyboard.buf;
  214.  
  215.     mon_create(&mid);
  216. }
  217.  
  218. void
  219. ctick(p, v1, v2)
  220. int p;
  221. void *v1, *v2;
  222. {
  223.      char i_state;
  224.      struct timeval timout;
  225.      newproc("interrupt handler",1024,inpint,0,NULL,NULL);
  226.  
  227.      /* We will awaken the timer process at every MSPTICK milliseconds.
  228.     You may try to tweak its definition in timer.h */
  229.  
  230.      ctickp = Curproc;
  231.  
  232. #undef LWP_USE_PRIO      /* Doesn't work yet KA9WSB */
  233. #ifdef LWP_USE_PRIO
  234.      if(lwp_setpri(SELF, MINPRIO+2) < 0){
  235.         lwp_perror("ctick: lwp_setpri");
  236.         abort();
  237.      }
  238. #endif
  239.  
  240.      while(1) {
  241.       timout.tv_sec = 0;
  242.       timout.tv_usec = MSPTICK * 1000;
  243.       if(lwp_sleep(&timout) < 0){
  244.         lwp_perror("ctick: lwp_sleep");
  245.         abort();
  246.       }
  247.       Curproc = ctickp;
  248.       i_state = dirps();
  249.       ++Tick;
  250.       psignal(&Tick,1);
  251.       restore(i_state);
  252.      }
  253. }
  254.  
  255. /* Called just before exiting to restore console state */
  256. void
  257. iostop()
  258. {
  259.     struct iface *ifp, *ifptmp;
  260.     void (**fp)();
  261.  
  262.     for(ifp = Ifaces; ifp != NULLIF; ifp = ifptmp){
  263.         ifptmp = ifp->next;
  264.         if_detach(ifp);
  265.     }
  266.  
  267.     for(fp = Shutdown; *fp != NULLVFP; fp++){
  268.         (**fp)();
  269.     }
  270.  
  271.     if(console_saved)
  272.         ioctl(console,TIOCSETP,&savecon);
  273.  
  274.     pod_exit(0);
  275. }
  276.  
  277.  
  278. /* Disable all "interrupts", don't mask any signals however */
  279. int dirps()
  280. {
  281.     if (intoff)
  282.      return 0;
  283.     mon_enter(mid);
  284.     intoff = 1;
  285.     return 1;
  286. }
  287.  
  288. /* Restore the "interrupts" */
  289. void restore (mask)
  290.     char mask;
  291. {
  292.      if (mask) {
  293.     intoff = 0;
  294.     mon_exit(mid);
  295.      }
  296. }
  297.  
  298. /* Return the interrupt state */
  299. int istate()
  300. {
  301.      return !intoff;
  302. }
  303.  
  304. /* Input interrupt handler.
  305.    This function is called whenever there is input from stdin, the
  306.    asynchronus interfaces or the NIT driver. But unfortunately only if their
  307.    respective input queues were empty.
  308.    Speeding up this function would probably enhance the general performance
  309.    of the program.
  310. */
  311. void
  312. inpint(p, v1, v2)
  313. int p;
  314. void *v1, *v2;
  315. {
  316.     int i,ok,r,cnt;
  317.     struct timeval timeout;
  318.     fd_set readfds;
  319.     thread_t agt;
  320.     eventinfo_t argbuf;
  321.     char evbuf[100], *dummy, i_state;
  322.     
  323.     inpintp = Curproc;
  324.  
  325. #ifdef LWP_USE_PRIO
  326.      if(lwp_setpri(SELF, MINPRIO+1) < 0){
  327.         lwp_perror("inpintp: lwp_setpri");
  328.         abort();
  329.      }
  330. #endif
  331.  
  332.     /* Create an agent for the SIGIO signal */
  333.     agt_create(&agt, SIGIO, evbuf);
  334.          
  335.     /* This will send a SIGIO signal whenever a key is pressed and
  336.        the stdin queue is empty. It would be better if the signal would
  337.        always be sent, regardless of the status of the queue. */
  338.     if(isatty(console)) {
  339.         fcntl(console,F_SETFL, fcntl(console,F_GETFL,0) | FASYNC);
  340.         fcntl(console,F_SETOWN,getpid());
  341.     }
  342.     
  343.     /* This loop should never exit... it should be running as the
  344.        "interrupt handler"... */
  345.  
  346.     while (1) {
  347.         i = 0;
  348.         r = 0;
  349.         dummy = NULL;
  350.         msg_recv(&agt,(caddr_t)&argbuf,&i,(caddr_t)&dummy,&r,INFINITY);
  351.         Curproc = inpintp;
  352.         FD_ZERO (&readfds);
  353.         for (i=0; i<Nasy; ++i)
  354.         FD_SET(Asy[i].IORser,&readfds);
  355. #ifdef PACKET
  356. /* This is only for the NIT and Tun drivers */
  357.         for (i=0; i<Nnit; ++i)
  358.         FD_SET(Nitdrvr[i].IOser,&readfds);
  359.         for (i=0; i<Ntun; ++i)
  360.         FD_SET(Tundrvr[i].IOser,&readfds);
  361. #endif
  362.         if(isatty(console))
  363.         FD_SET(console,&readfds);
  364.         msg_reply(agt); /* Reply before we read anything */
  365.         timeout.tv_sec = 0;
  366.         timeout.tv_usec = 35;
  367.         ok = select(NOFILE,&readfds,(fd_set *)0,(fd_set *)0,&timeout);
  368.         i_state = dirps();
  369.         cnt = 0;
  370.         if (ok > 0) {
  371. #ifdef PACKET
  372.         for (i=0; i<Nnit; ++i)
  373.             if (FD_ISSET(Nitdrvr[i].IOser,&readfds))
  374.             psignal(&Nitdrvr[i],1);
  375.         for (i=0; i<Ntun; ++i)
  376.             if (FD_ISSET(Tundrvr[i].IOser,&readfds))
  377.             psignal(&Tundrvr[i],1);
  378. #endif
  379.         /* Now scan the asynchronus interfaces. Remember, this is
  380.            supposed to be efficient. */
  381.         for (i=0; i<Nasy; ++i)
  382.             if (FD_ISSET(Asy[i].IORser,&readfds)) {
  383.             if (Asy[i].fifo.cnt == Asy[i].fifo.bufsize)
  384.                 continue; /* No room */
  385.             /* Try to read as much as we are allowed to */
  386.             r = read(Asy[i].IORser, Asy[i].fifo.wp,
  387.                  Asy[i].fifo.rp > Asy[i].fifo.wp ?
  388.                  Asy[i].fifo.rp - Asy[i].fifo.wp :
  389.                  &Asy[i].fifo.buf[Asy[i].fifo.bufsize] - Asy[i].fifo.wp);
  390.             if (r <= 0)
  391.                 continue;
  392.             cnt += r;
  393.             Asy[i].rxchar += r;
  394.             Asy[i].fifo.wp += r;
  395.             Asy[i].fifo.cnt += r;
  396.             if(Asy[i].fifo.wp >= &Asy[i].fifo.buf[Asy[i].fifo.bufsize])
  397.                 /* Wrap around */
  398.                 Asy[i].fifo.wp = Asy[i].fifo.buf;
  399.             /* Signal "asy_rx" that we have got new data. */
  400.             psignal(&Asy[i].fifo,1);
  401.             }
  402.         }
  403.         /* This function would be a monster if I didn't split it up
  404.            into a special part for keyboard input. */
  405.         if (ok > 0 && FD_ISSET(console,&readfds))
  406.         kbraw();
  407.        /* Now do it all over again since we might have received more input */
  408.     restore(i_state);
  409.     }
  410. }
  411.  
  412. /* Read characters from stdin. Called from the generic interrupt handler. */
  413. int
  414. kbraw()
  415. {
  416.     int cnt;
  417.  
  418.     if (shell)
  419.      /* We are executing a shell right now */
  420.     return 0;
  421.  
  422.     if (Keyboard.cnt == Keyboard.bufsize)
  423.     return 0;
  424.     /* Try to read as much as we are allowed to */
  425.     cnt = read(console, Keyboard.wp,
  426.          Keyboard.rp > Keyboard.wp ? Keyboard.rp - Keyboard.wp :
  427.          Keyboard.buf + Keyboard.bufsize - Keyboard.wp);
  428.     if (cnt <= 0)
  429.     return 0;
  430.     Keyboard.cnt += cnt;
  431.     Keyboard.wp += cnt;
  432.     if(Keyboard.wp >= Keyboard.buf + Keyboard.bufsize)
  433.     Keyboard.wp = Keyboard.buf;
  434.     psignal(&Keyboard,1);
  435.     return cnt;
  436. }
  437. /* Blocking read from the keyboard */
  438. int
  439. kbread()
  440. {
  441.     int i_state;
  442.     char c;
  443.  
  444.     i_state = dirps();
  445.     while(Keyboard.cnt == 0)
  446.         pwait (&Keyboard);
  447.     c = *Keyboard.rp++;
  448.     if(Keyboard.rp == &Keyboard.buf[Keyboard.bufsize])
  449.         Keyboard.rp = Keyboard.buf;
  450.     Keyboard.cnt--;
  451.     restore(i_state);
  452.     
  453.     if (c == 0x7f) /* DEL key */
  454.         c = '\b';
  455.     if (c == '\n') /* Emulate MS/DOS. SysV would reset the ICRNL flag */
  456.         c = '\r';
  457.     return c;
  458. }
  459. void
  460. systick()
  461. {
  462. }
  463.  
  464. void
  465. sysreset()
  466. {
  467. }
  468.  
  469. /* This function is only needed if you DO use alloc.c */
  470. unsigned long coreleft()
  471. {
  472.     struct rlimit rlp;
  473.     extern end;
  474.     getrlimit(RLIMIT_CORE,&rlp);
  475.     return ((unsigned long) (rlp.rlim_cur - end));
  476. }
  477. /* Sleep gracefully until the next interrupt. */
  478. void
  479. giveup()
  480. {
  481.     restore(1); /* Interrupts must be enabled */
  482.     sigpause(0);
  483.     dirps();
  484. }
  485. /* To be removed if alloc.c is to be used */
  486. memstat()
  487. {
  488.     return 0;
  489. }
  490.  
  491. /* Note: make sure that there is no previous definition of tolower() */
  492. char tolower (c)
  493.     char c;
  494. {
  495.     return ((c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c);
  496. }
  497.  
  498. FILE *
  499. tmpfile()
  500. {
  501.     FILE *tmp;
  502.     char *mktemp();
  503.     char *ptr = "SMTPXXXXXX";
  504.     char *name;
  505.     name = mktemp(ptr);
  506.     if ( ( tmp = fopen(name, "w+") ) == NULL)
  507.     {
  508.         tprintf("tmpfile: counld not create temp file.\n");
  509.         return(NULL);
  510.     }
  511.     (void) unlink(name);
  512.     return ( tmp );
  513. }
  514.  
  515. /* wildcard filename lookup */
  516. filedir(name, times, ret_str)
  517. char    *name;
  518. int    times;
  519. char    *ret_str;
  520. {
  521.     static char    dname[128], fname[128];
  522.     static DIR *dirp = NULL;
  523.     struct dirent *dp;
  524.     struct stat sbuf;
  525.     char    *cp, temp[128];
  526.  
  527.     /*
  528.      * Make sure that the NULL is there in case we don't find anything
  529.      */
  530.     ret_str[0] = '\0';
  531.  
  532.     if (times == 0) {
  533.         /* default a null name to *.* */
  534.         if (name == NULL || *name == '\0')
  535.             name = "*.*";
  536.         /* split path into directory and filename */
  537.         if ((cp = strrchr(name, '/')) == NULL) {
  538.             strcpy(dname, ".");
  539.             strcpy(fname, name);
  540.         } else {
  541.             strcpy(dname, name);
  542.             dname[cp - name] = '\0';
  543.             strcpy(fname, cp + 1);
  544.             /* root directory */
  545.             if (dname[0] == '\0')
  546.                 strcpy(dname, "/");
  547.             /* trailing '/' */
  548.             if (fname[0] == '\0')
  549.                 strcpy(fname, "*.*");
  550.         }
  551.         /* close directory left over from another call */
  552.         if (dirp != NULL)
  553.             closedir(dirp);
  554.         /* open directory */
  555.         if ((dirp = opendir(dname)) == NULL) {
  556.             tprintf("Could not open DIR (%s)\n", dname);
  557.             return;
  558.         }
  559.     } else {
  560.         /* for people who don't check return values */
  561.         if (dirp == NULL)
  562.             return;
  563.     }
  564.  
  565.     /* scan directory */
  566.     while ((dp = readdir(dirp)) != NULL) {
  567.         /* test for name match */
  568. /*        if (wildmat(dp->d_name, fname)) {*/
  569.         if (!strcmp(dp->d_name, fname) || (fname[0] == '*' &&
  570.             !strcmp(&dp->d_name[strlen(dp->d_name) - strlen(fname)+1],
  571.             &fname[1]))) { /* ...when we do not use wildmat */
  572.             /* test for regular file */
  573.             sprintf(temp, "%s/%s", dname, dp->d_name);
  574.             if (stat(temp, &sbuf) < 0)
  575.                 continue;
  576.             if ((sbuf.st_mode & S_IFREG) == 0)
  577.                 continue;
  578.             strcpy(ret_str, dp->d_name);
  579.             break;
  580.         }
  581.     }
  582.  
  583.     /* close directory if we hit the end */
  584.     if (dp == NULL) {
  585.         closedir(dirp);
  586.         dirp = NULL;
  587.     }
  588. }
  589. doshell(argc, argv)
  590. char **argv;
  591. {
  592.     register int pid, pid1, i;
  593.     void (*savi)();
  594.     int rc;
  595.     char str[256], *cp;
  596.     struct sgttyb ttybuf;
  597.     extern struct sgttyb savecon;
  598.     shell = 1;
  599.  
  600.     ioctl(console, TIOCGETP, &ttybuf);
  601.     ioctl(console, TIOCSETP, &savecon);
  602.  
  603.     str[0] = '\0';
  604.     for (i = 1; i < argc; i++) {
  605.         strcat(str, argv[i]);
  606.         strcat(str, " ");
  607.     }
  608.     if ((cp = getenv("SHELL")) == NULLCHAR)
  609.         cp = "/bin/sh";
  610.     if ((pid = fork()) == 0) {
  611.         seteuid(getuid()); /* Restore original user ID */
  612.         if (argc > 1)
  613.             (void)execl(cp, cp, "-c", str, 0);
  614.         else
  615.             (void)execl(cp, cp, (char *)0,(char *)0,0);
  616.         tprintf("Can't execl() (%d)\n", errno);
  617.         exit(1);
  618.     } else if (pid == -1) {
  619.         tprintf("Can't fork() (%d)\n", errno);
  620.         rc = -1;
  621.     } else {
  622.         savi = signal(SIGINT, SIG_IGN);
  623.         while ((pid1 = wait(&rc)) != pid && pid1 != -1)
  624.             ;    
  625.         signal(SIGINT, savi);
  626.     }
  627.     ioctl(console, TIOCSETP, &ttybuf);
  628.     shell = 0;
  629.     return (rc);
  630. }
  631.  
  632. dodir(argc, argv)
  633. char **argv;
  634. {
  635.     register int i;
  636.     char str[256];
  637.  
  638.     strcpy(str, "ls -lL ");
  639.     for (i = 1; i < argc; i++) {
  640.         strcat(str, argv[i]);
  641.         strcat(str, " ");
  642.     }
  643.  
  644.     return system(str);
  645. }
  646.     
  647. /* Terminal printf that counts newlines. At end of the page,
  648.  * prints "--More--" and waits for a keystroke before continuing.
  649.  */
  650. void
  651. display(i,v1,v2)
  652. int i;
  653. void *v1;
  654. void *v2;
  655. {
  656.     int c;
  657.     struct session *sp;
  658.  
  659.     /* This is very tricky code. Because the value of "Current" can
  660.      * change any time we do a pwait, we have to be careful to detect
  661.      * any change and go back and start again.
  662.      */
  663.     for(;;){
  664.         sp = Current;
  665.  
  666.         if(sp->morewait){
  667.             pwait(&sp->row);
  668.             if(sp != Current || sp->row <= 0){
  669.                 /* Current changed value, or the user
  670.                  * hasn't really hit a key
  671.                  */
  672.                 continue;
  673.             }
  674.             /* Erase the prompt */
  675.             printf("\r        \r");
  676.         }
  677.         sp->morewait = 0;
  678.         if((c = recvchar(sp->output)) == -1){
  679.             /* the alert() in swapscreen will cause this to
  680.              * return -1 when current changes
  681.              */
  682.             pwait(NULL);    /* Prevent a nasty loop */
  683.             continue;
  684.         }
  685.         putchar(c);
  686.         if(sp->record != NULLFILE)
  687.             fputc(c,sp->record);
  688.         if(sp->flowmode && c == '\n' && --sp->row <= 0){
  689.             printf("--More--");
  690.             sp->morewait = 1;
  691.         }
  692.     }
  693. }
  694. void swapscreen(old, new)
  695. struct session *old;
  696. struct session *new;
  697. {
  698.     if(old == new)
  699.         return;    /* Nothing to do */
  700.  
  701.     fflush(stdout);
  702.     if(old != NULLSESSION){
  703.         /* Save old screen */
  704.     }
  705.     if(new != NULLSESSION){
  706.         /* Load new screen */
  707.     }
  708.     alert(Display,1);    /* Wake him up */
  709. }
  710. void
  711. newscreen(sp)
  712. struct session *sp;
  713. {
  714.     if(sp != NULLSESSION)
  715.         sp->screen = (struct screen *)callocw(1,sizeof(struct screen));
  716. }
  717. void
  718. freescreen(sp)
  719. struct session *sp;
  720. {
  721.     if(sp == NULLSESSION || sp->screen == NULLSCREEN)
  722.         return;
  723.     if(sp->screen->save != NULLCHAR)
  724.         free(sp->screen->save);
  725.     free((char *)sp->screen);
  726. }
  727.  
  728. /* Case-insensitive string comparison  (Needed on some machines) */
  729. int
  730. stricmp(a,b)
  731. register char *a,*b;
  732. {
  733.     char a1,b1;
  734.  
  735.     while((a1 = *a++) != '\0' && (b1 = *b++) != '\0'){
  736.         if(a1 == b1)
  737.             continue;    /* No need to convert */
  738.         if(isupper(a1))
  739.             a1 = tolower(a1);
  740.         if(isupper(b1))
  741.             b1 = tolower(b1);
  742.         if(a1 == b1)
  743.             continue;    /* NOW they match! */
  744.         if(a1 > b1)
  745.             return 1;
  746.         if(a1 < b1)
  747.             return -1;
  748.     }
  749.     return 0;
  750. }
  751.  
  752. /* Create directory */
  753. int
  754. domkd(argc,argv,p)
  755. int argc;
  756. char *argv[];
  757. void *p;
  758. {
  759.     if(mkdir(argv[1]) == -1)
  760.         tprintf("Can't make %s: %s\n",argv[1],sys_errlist[errno]);
  761.     return 0;
  762. }
  763. /* Remove directory */
  764. int
  765. dormd(argc,argv,p)
  766. int argc;
  767. char *argv[];
  768. void *p;
  769. {
  770.     if(rmdir(argv[1]) == -1)
  771.         tprintf("Can't remove %s: %s\n",argv[1],sys_errlist[errno]);
  772.     return 0;
  773. }
  774.  
  775. /* Routines we don't do... but don't want to constantly hack config.c */
  776. int
  777. dofkey(argc,argv,p)
  778. int argc;
  779. char *argv[];
  780. void *p;
  781. {
  782.     tprintf("This command is not supported under UNIX yet...\n");
  783.     return 0;
  784. }
  785.  
  786. int
  787. dobmail(argc,argv,p)
  788. int argc;
  789. char *argv[];
  790. void *p;
  791. {
  792.     tprintf("This command is not supported under UNIX yet...\n");
  793.     return 0;
  794. }
  795.  
  796. void rflush()
  797. {
  798.     fflush(Rawterm);
  799. }
  800.  
  801. char Hashtab[256];
  802.  
  803. int16
  804. hash_ip(ipaddr)
  805. int32 ipaddr;
  806. {
  807.     return 0;    /* A nicer technique later on :-) KA9WSB */
  808. }
  809.  
  810. void
  811. kbint()
  812. {
  813. }
  814.  
  815. void
  816. uchtimer()
  817. {
  818. }
  819.  
  820. int32
  821. secclock()
  822. {
  823.     struct timeval tp;
  824.     int32 t, u;
  825.  
  826.     gettimeofday(&tp,NULL);
  827.     t = tp.tv_sec - StartSec;
  828.     u = tp.tv_usec - StartUsec;
  829.     if(u>499999)t++;
  830.     return t;
  831. }
  832.  
  833. int32
  834. msclock()
  835. {
  836.     struct timeval tp;
  837.     int32 t, u;
  838.  
  839.  
  840.     gettimeofday(&tp,NULL);
  841.     t = tp.tv_sec - StartSec;
  842.     u = tp.tv_usec - StartUsec;
  843.     return ((t * 1000) + (u / 1000));
  844. }
  845.  
  846. #ifdef BUFFERED_OUTPUT
  847. int FlushTock = 0;
  848. #ifndef TICKS_PER_FLUSH
  849. #define TICKS_PER_FLUSH 5
  850. #endif
  851. #endif
  852.  
  853. #ifdef MALLOCDEBUG
  854. int MallocTock = 0;
  855. #endif
  856.  
  857. void
  858. pctick()
  859. {
  860.     Clock++;
  861.  
  862. #ifdef BUFFERED_OUTPUT
  863.     FlushTock++;
  864.     if(FlushTock>=TICKS_PER_FLUSH){
  865.         fflush(stdout);
  866.         FlushTock = 0;
  867.     }
  868. #endif
  869.  
  870. #ifdef MALLOCDEBUG
  871.     MallocTock++;
  872.     if(MallocTock>=10){
  873.         if( malloc_verify() == 0 )
  874.             printf("Warning: malloc_verify: Corrupted heap!\n");
  875.         MallocTock = 0;
  876.     }
  877. #endif
  878. }
  879.