home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume9 / browse_pds / browse.c next >
C/C++ Source or Header  |  1989-12-14  |  36KB  |  2,154 lines

  1. /*             -- Just what the hell am I ??? ---                            */
  2.  
  3. #include <stdio.h>
  4. #ifdef M_XENIX
  5. #define USG
  6. #define rindex strrchr
  7. #define GETCWD
  8. #else
  9. #ifdef L_ctermid
  10. #define USG
  11. #define rindex strrchr
  12. #define minor(i) ((i)&0xFF)
  13. #define major(i) minor((i)>>8)
  14. #else
  15. #include <whoami.h>
  16. #endif
  17. #endif
  18.  
  19. /*         -- Miscellaneous include files --                     */
  20.  
  21. #include <sys/param.h>            /* NCARGS, and others */
  22. #ifndef M_XENIX
  23. #include <sys/types.h>                       /* data types for various files */
  24. #endif
  25. #include <sys/stat.h>         /* stat data structure for getdir(), statout() */
  26. #include <sys/dir.h>                      /* dir data structure for getdir() */
  27. #include <pwd.h>                       /* passwd data structure for u_name() */
  28. #include <grp.h>                        /* group data structure for g_name() */
  29. #ifdef BSD
  30. #include <sys/time.h>                  /* time data structure for printime() */
  31. #else
  32. #include <time.h>                       /* time data structure for printime() */
  33. #endif
  34. #ifdef USG
  35. #ifdef M_XENIX
  36. #include <sys/ioctl.h>
  37. #endif
  38. #include <termio.h>
  39. #else
  40. #include <sgtty.h>                     /* terminal modes for tinit(), tend() */
  41. #endif
  42. #include <signal.h>
  43.  
  44. /*        -- make information --
  45. BUILD
  46. browse: browse.c
  47.     cc browse.c -O -o browse -ltermlib
  48. END
  49. */
  50.  
  51. /*        -- Miscellaneous defines --                     */
  52. #define FALSE 0
  53. #define TRUE 1
  54.  
  55. #define MAXENTS 320
  56. #define MAXID 16
  57. #define MAXLINE 81
  58. #define NCOL 64
  59. #define MAXNAME 14
  60. #define FILENAME 256
  61. #define MAXARGC (NCARGS/16)    /* Estimate max ARGC */
  62. #define CHARSET 256        /* Number of macros == size of byte */
  63. #define NOMAC (0)        /* Null macro (last) */
  64. #define TERMBUF 1024        /* Size of term buf for termcap */
  65. #define SMALLBUF 256
  66.  
  67. /*        -- Extended directory entry format --                 */
  68. struct entry {
  69.     char *e_name;
  70.     int e_flags;
  71. #define FTAGGED (1<<0)
  72. #define FPERMANENT (1<<1)
  73.     struct stat e_stat;                             /* file status field */
  74.     char e_uname[9];                                        /* user name */
  75.     char e_gname[9];                                /* user's group name */
  76. *xentries[MAXENTS], **entries=xentries;
  77. int nentries;
  78.  
  79. /*        -- Look-up cache for user names --                 */
  80. struct idtab {
  81.     int  id_id;                                    /* user (or group) id */
  82.     char id_name[9];                                 /* name[8] + filler */
  83. u_list[MAXID],                                       /* Matched user id's. */
  84. g_list[MAXID];                                              /* ditto group */
  85. int u_ptr=0, g_ptr=0;                                     /* current entries */
  86.  
  87. /*        -- Global variables --                         */
  88. FILE *efp;                                               /* Environment file */
  89. char efname[MAXLINE];                                              /* " name */
  90. char *tent;                                               /* Pointer to tbuf */
  91. char PC;                                                    /* Pad character */
  92. char *UP, *BC;                                /* Upline, backsapce character */
  93. short ospeed;                                       /* Terminal output speed */
  94. char termbuf[TERMBUF];                   /* Place to put term info */
  95.  
  96. char *macbuf[CHARSET], ungetbuf[SMALLBUF];         /* Buffers for pushback and macros */
  97. char c_macro=NOMAC;                                           /* current macro */
  98. char *macptr = "";                   /* Pointer to currently executing macro */
  99. char *ungetptr = ungetbuf;              /* Pointer to pushed-back characters */
  100.  
  101. char *errname;                                /* Name of file error found in */
  102. extern int errno;                                     /* system error number */
  103. int xerrno;                                         /* extended error number */
  104. int ccol=NCOL;                /* Width of used display, current column */
  105. int quickmode;              /* short display mode (files only) */
  106.  
  107. #ifdef USG
  108. struct termio rawbuf;
  109. struct termio cookedbuf;
  110. #else
  111. struct sgttyb sgbuf;                        /* buffer for terminal mode info */
  112. int rawflags, cookflags;          /* flags for raw & cooked tty mode */
  113. #endif
  114.  
  115. char *cm,                                                   /* Cursor motion */
  116.      *cs,                                         /* Change scrolling region */
  117.      *sf,                                         /*  - scroll forward       */
  118.      *sr,                                         /*  - scroll backwards     */
  119.      *ce,                                            /* Clear to end of line */
  120.      *cl,                                                    /* Clear screen */
  121.      *al,                                                     /* Insert line */
  122.      *dl,                                                    /* delete ditto */
  123.      *so,                                                        /* standout */
  124.      *se,                                                    /* standout end */
  125.      *us,                                                       /* underline */
  126.      *ue,                                                   /* underline end */
  127.      *ti,                            /* Init terminal */
  128.      *te;                           /* Reset terminal */
  129. int  li,                                                  /* lines on screen */
  130.      co;                                                    /* columns ditto */
  131. char xn;        /* Magic cookie kludge */
  132.  
  133. /*        -- Global error messages --                     */
  134. char *emesg[4]={
  135.     "??",
  136. #define TOO_MANY 1
  137.     "Too many directory entries",
  138. #define NOMATCH 2
  139.     "No match",
  140.     0
  141. };
  142.  
  143. int    top, curr;               /* Positions of screen in directory */
  144. #define bottom ((top+nlines>nentries)?nentries:(top+nlines))
  145. char    *dot;                                   /* name of current directory */
  146. int    nlines;                         /* number of lines displayed on page */
  147. char    display_up;                               /* Does the display exist? */
  148. int    todump=1;                 /* Do we want to dump data? */
  149. int    ended;                                    /* Have we quite finished? */
  150. int    intrup;                    /* Have we been interrupted? */
  151. char    *HOME;                      /* Where did I start from? */
  152. char    *SHELL;                       /* How do I run programs? */
  153.  
  154. /*        -- types of functions !!!                     */
  155. char *getenv(), *tgetstr();
  156. char *malloc();
  157.  
  158. #define NEW(t) (t *)malloc(sizeof (t))
  159. #define NIL(t) ((t) 0)
  160.  
  161. /*        -- Code starts here: dummy main --                    */
  162. main(ac, av, ep)
  163. int ac;
  164. char **av;
  165. char **ep;
  166. {
  167.     if(ac>1) chdir(av[1]);
  168.  
  169.     sprintf(efname, "/tmp/br.env.%d", getpid());
  170.     HOME=getenv("HOME");
  171.     SHELL=getenv("SHELL");
  172.     dumpenv(ep);
  173.  
  174.     intrup=0;
  175.     tinit(getenv("TERM"));
  176.     clear_all();
  177.     browse();
  178.     tend();
  179.     unlink(efname);
  180. }
  181.  
  182. clear_all()
  183. {
  184.     int i;
  185.  
  186.     for(i = 0; i < MAXENTS; i++)
  187.         entries[i] = 0;
  188. }
  189.  
  190. char *clone(name)
  191. char *name;
  192. {
  193.     char *hold;
  194.     
  195.     hold = (char *)malloc(strlen(name)+1);
  196.  
  197.     if(hold==0)
  198.         return 0;
  199.     strcpy(hold, name);
  200.     return hold;
  201. }
  202.  
  203. newname(e, name)
  204. struct entry *e;
  205. char *name;
  206. {
  207.     if(e->e_name)
  208.         free(e->e_name);
  209.     e->e_name = clone(name);
  210. }
  211.  
  212. #if BSD
  213. readent(dp, db)
  214. DIR *dp;
  215. struct direct *db;
  216. {
  217.     struct direct *ptr;
  218.  
  219.     ptr = readdir(dp);
  220.     if(!ptr) return 0;
  221.  
  222.     *db = *ptr;    /* V7 'C' and above... safe, since UCB=V7+ */
  223.     free(ptr);
  224.     return 1;
  225. }
  226. #else
  227. #define opendir(n) fopen(n, "r")
  228. #define DIR FILE
  229. readent(dp, db)
  230. DIR *dp;
  231. struct direct *db;
  232. {
  233.     if(fread(db, sizeof(struct direct), 1, dp))
  234.         return 1;
  235.     /* else */
  236.         return 0;
  237. }
  238. #define closedir fclose
  239. #endif
  240.  
  241. getdir()
  242. {
  243.     char *u_name(), *g_name();
  244.     DIR *dp;
  245.     int  valid;
  246.     struct direct *hold = NEW(struct direct);
  247.     int i, p;
  248.  
  249.     if(!(dp = opendir("."))) {
  250.         errname=".";
  251.         return FALSE;
  252.     }
  253.  
  254.     p = 0;
  255.     for(i = 0; i < nentries; i++) {
  256.         if(entries[i]->e_flags & FPERMANENT) {
  257.             if(p != i) {
  258.                 struct entry *hold;
  259.                 hold = entries[p];
  260.                 entries[p] = entries[i];
  261.                 entries[i] = hold;
  262.             }
  263.             p++;
  264.         }
  265.     }
  266.  
  267.     for(nentries = p; !intrup && nentries < MAXENTS; nentries += valid) {
  268.  
  269.         if(!entries[nentries]) {
  270.             entries[nentries] = NEW(struct entry);
  271.             if(!entries[nentries])
  272.                 break;
  273.             entries[nentries]->e_name = NIL(char *);
  274.         }
  275.  
  276.         if(!readent(dp, hold))
  277.             break;
  278.  
  279.         valid = (hold->d_ino != 0);
  280.         if(valid) {
  281.             if(stat(hold->d_name, &entries[nentries]->e_stat)==-1) {
  282.                 closedir(dp);
  283.                 errname=hold->d_name;
  284.                 free(hold);
  285.                 return FALSE;
  286.             }
  287.  
  288.             newname(entries[nentries], hold->d_name);
  289.  
  290. #ifndef BSD /* truncate name to 14 characters in non-BSD systems */
  291.             if(strlen(entries[nentries]->e_name)>14)
  292.                 entries[nentries]->e_name[14] = 0;
  293. #endif
  294.  
  295.             entries[nentries]->e_flags = 0;
  296.  
  297.             strcpy(entries[nentries]->e_uname,
  298.                 u_name(entries[nentries]->e_stat.st_uid));
  299.  
  300.             strcpy(entries[nentries]->e_gname,
  301.                 g_name(entries[nentries]->e_stat.st_gid));
  302.         }
  303.     }
  304.  
  305.     closedir(dp);
  306.  
  307.     free(hold);
  308.  
  309.     if(intrup)
  310.         return FALSE;
  311.  
  312.     if(nentries>=MAXENTS || entries[nentries]==NIL(struct entry *)) {
  313.         errno=0;
  314.         xerrno=TOO_MANY;
  315.         errname=".";
  316.         return FALSE;
  317.     }
  318.  
  319.     sortdir();
  320.  
  321.     if(intrup)
  322.         return FALSE;
  323.     return TRUE;
  324. }
  325.  
  326. at_current()
  327. {
  328.     at_file(curr);
  329. }
  330.  
  331. at_file(file)
  332. int file;
  333. {
  334.     if(display_up) {
  335.         if(file < top || file >= top+nlines)
  336.             return 0;
  337.         at(0, curr-top+2);
  338.     } else {
  339.         if(file != curr)
  340.             return 0;
  341.         cmdline();
  342.     }
  343.     return 1;
  344. }
  345.  
  346. display_flags(flags)
  347. {
  348.     outc((flags&FTAGGED)?'+':((flags&FPERMANENT)?'!':' '));
  349. }
  350.  
  351. repaint_flags()
  352. {
  353.     if(!display_up) return;
  354.     at(NCOL-1, curr-top+2);
  355.     display_flags(entries[curr]->e_flags);
  356. }
  357.  
  358. repaint_current()
  359. {
  360.     if(!display_up) return;
  361.     at_current();
  362.     dump(curr, curr+1);
  363. }
  364.  
  365. tag()
  366. {
  367.     entries[curr]->e_flags ^= FTAGGED;
  368.     repaint_flags();
  369. }
  370.  
  371. tag_all(flag)
  372. int flag;
  373. {
  374.     int i;
  375.  
  376.     for(i = 0; i < nentries; i++)
  377.         if(flag)
  378.             entries[i]->e_flags |= FTAGGED;
  379.         else
  380.             entries[i]->e_flags &= ~FTAGGED;
  381.     if(display_up)
  382.         todump = TRUE;
  383. }
  384.  
  385. delete_from_display(file)
  386. int file;
  387. {
  388.     if(!display_up) return;
  389.  
  390.     if(file>=top+nlines) return;
  391.  
  392.     if(file < top) file = top;
  393.  
  394.     scroll(2+file-top, 2+nlines, 1);
  395.     at(0, 2+nlines-1);
  396.     if(top+nlines >= nentries)
  397.         outc('~');
  398.     else
  399.         dump(bottom, bottom+1);
  400. }
  401.         
  402. delete_file_entry(file)
  403. int file;
  404. {
  405.     struct entry *hold;
  406.     int    i;
  407.  
  408.     delete_from_display(file);
  409.  
  410.     hold = entries[file];
  411.     for(i=file; i<nentries-1; i++)
  412.         entries[i]=entries[i+1];
  413.     entries[nentries-1]=hold;
  414.     nentries--;
  415.  
  416.     if(file < curr || curr >= nentries) {
  417.         curr--;
  418.         if(top >= nentries) {
  419.             top--;
  420.             display_up = 0;
  421.             todump = 1;
  422.         }
  423.     }
  424.  
  425. remove_one(file, doit)
  426. int file;
  427. int doit;
  428. {
  429.     if(!doit) {
  430.         cmdline();
  431.         outs("Delete ");
  432.         ctlouts(entries[file]->e_name);
  433.         outs(" [n]?");
  434.         doit = getchar() == 'y';
  435.         outs(doit?"Yes.":"No.");
  436.     }
  437.     if(doit) {
  438.         if(unlink(entries[file]->e_name) == 0) {
  439.             cmdline();
  440.             outs("Deleted ");
  441.             ctlouts(entries[file]->e_name);
  442.             outs(".");
  443.             delete_file_entry(file);
  444.             return 1;
  445.         } else {
  446.             wperror(entries[file]->e_name);
  447.             return 0;
  448.         }
  449.     }
  450.     return 0;
  451.  
  452. remove(doit)
  453. int doit;
  454. {
  455.     int i;
  456.     int found_tags;
  457.  
  458.     found_tags = 0;
  459.     i = 0;
  460.     while(i < nentries) {
  461.         if(entries[i]->e_flags & FTAGGED) {
  462.             found_tags = 1;
  463.             if(!remove_one(i, doit)) /* decrements nentries */
  464.                 break;
  465.         } else
  466.             i++;
  467.     }
  468.     if(!found_tags)
  469.         remove_one(curr, doit);
  470. }
  471.  
  472. insert_entry_at(ent, i)
  473. struct entry *ent;
  474. int i;
  475. {
  476.     struct entry *hold;
  477.     int j;
  478.  
  479.     /* Allocate slot at end */
  480.     if(!entries[nentries]) {
  481.         entries[nentries] = NEW(struct entry);
  482.         if(!entries[nentries])
  483.             return 0;
  484.         entries[nentries]->e_name = NIL(char *);
  485.     } else if(entries[nentries]->e_name) {
  486.         free(entries[nentries]->e_name);
  487.         entries[nentries]->e_name = NIL(char *);
  488.     }
  489.  
  490.     /* Copy data into slot */
  491.     *entries[nentries] = *ent;
  492.     entries[nentries]->e_name = clone(ent->e_name);
  493.     if(!entries[nentries]->e_name)
  494.         return 0;
  495.  
  496.     if(i != nentries) {
  497.         /* Rotate slot to middle */
  498.         hold = entries[nentries];
  499.         for(j = nentries; j > i; j--)
  500.             entries[j] = entries[j-1];
  501.         entries[i] = hold;
  502.     }
  503.     nentries++;
  504.  
  505.     if(display_up) {
  506.         if(i < top)
  507.             i = top;
  508.         if(i >= bottom)
  509.             return;
  510.         scroll(2+i-top, 2+nlines, -1);
  511.         at(0, 2+i-top);
  512.         dump(i, i+1);
  513.     }
  514. }
  515.  
  516. insert_entry(ent)
  517. struct entry *ent;
  518. {
  519.     int i;
  520.  
  521.     if(nentries >= MAXENTS)
  522.         return 0;
  523.  
  524.     for(i = 0; i < nentries; i++)
  525.         if(entcmp(&ent, &entries[i]) < 0)
  526.             break;
  527.  
  528.     return insert_entry_at(ent, i);
  529. }
  530.  
  531. move()
  532. {
  533.     char scratch[FILENAME];
  534.     struct entry hold;
  535.     char inps();
  536.  
  537.     hold = *entries[curr];
  538.  
  539.     cmdline();
  540.     outs("Rename ");
  541.     ctlouts(entries[curr]->e_name);
  542.     outc(' ');
  543.     if(inps(scratch, entries[curr]->e_name, 0)=='\033') {
  544.         killcmd();
  545.         return;
  546.     }
  547.     if(link(entries[curr]->e_name, scratch)!=0) {
  548.         char tmbuf[42];
  549.         sprintf(tmbuf, "(rename %s %s)", entries[curr]->e_name, scratch);
  550.         wperror(tmbuf);
  551.         return;
  552.     }
  553.     if(unlink(entries[curr]->e_name)!=0) {
  554.         wperror(entries[curr]->e_name);
  555.         return;
  556.     }
  557.  
  558.     hold.e_name = scratch;
  559.     hold.e_flags &= ~FTAGGED;
  560.  
  561.     delete_file_entry(curr);
  562.     insert_entry(&hold);
  563. }
  564.  
  565. pname(name, mode)
  566. char *name;
  567. int mode;
  568. {
  569.     int i;
  570.     char *slash, *rindex();
  571.     int max=quickmode?MAXLINE:(MAXNAME+1);
  572.  
  573.     if((mode&S_IFMT)==S_IFDIR)
  574.         max--;
  575.     else if((mode&S_IFMT)==S_IFREG && (mode&0111))
  576.         max--;
  577.     else if((mode&S_IFMT)!=S_IFREG)
  578.         max--;
  579.  
  580.     if(!quickmode && (slash=rindex(name, '/'))) {
  581.         name=slash;
  582.         outc('<');
  583.         max--;
  584.     }
  585.     for(i=0; i<max && *name; name++)
  586.         i += ctlout(*name);
  587.     standend();
  588.     if(i==max && *name)
  589.         outs("\b>");
  590.     if((mode&S_IFMT)==S_IFDIR) {
  591.         outc('/');
  592.     }
  593.     else if((mode&S_IFMT)==S_IFREG && (mode&0111)) {
  594.         outc('*');
  595.     }
  596.     else if((mode&S_IFMT)!=S_IFREG) {
  597.         outc('?');
  598.     }
  599. }
  600.  
  601. sortdir()
  602. {
  603.     int   entcmp();
  604.     qsort(entries, nentries, sizeof(struct entry *), entcmp);
  605. }
  606.  
  607. addname(flag)
  608. char flag;
  609. {
  610.     char buf[FILENAME], *ptr, *tmp;
  611.     char scratch[FILENAME];
  612.     struct entry hold;
  613.     char inps();
  614.  
  615.     cmdline();
  616.     outs("Add ");
  617.     if(inps(scratch, entries[curr]->e_name, 0)=='\033') {
  618.         killcmd();
  619.         return;
  620.     }
  621.     
  622.     if(stat(scratch, &hold.e_stat)==-1) {
  623.         wperror(scratch);
  624.         return;
  625.     }
  626.     if(flag!='+' && *scratch != '/') {
  627.         strcpy(buf, dot);
  628.         ptr = scratch;
  629.         for(;;) {    /* eat '../' and './' */
  630.             if(ptr[0]=='.' && ptr[1]=='.' &&
  631.                (ptr[2]=='/' || !ptr[2])) {
  632.                 tmp = rindex(buf, '/');
  633.                 if(!tmp) break;
  634.                 *tmp=0;
  635.                 ptr += 2+(ptr[2]=='/');
  636.                 continue;
  637.             }
  638.             if(ptr[0]=='.' && 
  639.                (ptr[1]=='/' || !ptr[1])) {
  640.                 ptr += 1+(ptr[1]=='/');
  641.                 continue;
  642.             }
  643.             break;
  644.         }
  645.         if(*ptr) {
  646.             strcat(buf, "/");
  647.             strcat(buf, ptr);
  648.         }
  649.         hold.e_name = buf;
  650.     } else
  651.         hold.e_name = scratch;
  652.     strcpy(hold.e_uname,
  653.         u_name(hold.e_stat.st_uid));
  654.     strcpy(hold.e_gname,
  655.         g_name(hold.e_stat.st_gid));
  656.     hold.e_flags = 0;
  657.     if(flag!='+')
  658.         hold.e_flags |= FPERMANENT;
  659.     insert_entry(&hold);
  660. }
  661.  
  662. addperm()
  663. {
  664.     char buf[FILENAME], *ptr, *tmp;
  665.     struct entry hold;
  666.     int   entcmp(), i;
  667.  
  668.     if(entries[curr]->e_flags & FPERMANENT)
  669.         return;
  670.  
  671.     if(entries[curr]->e_name[0]!='/') {
  672.         strcpy(buf, dot);
  673.         ptr = entries[curr]->e_name;
  674.         for(;;) {    /* eat '../' and './' */
  675.             if(ptr[0]=='.' && ptr[1]=='.' &&
  676.                (ptr[2]=='/' || !ptr[2])) {
  677.                 tmp = rindex(buf, '/');
  678.                 if(!tmp) break;
  679.                 *tmp=0;
  680.                 ptr += 2+(ptr[2]=='/');
  681.                 continue;
  682.             }
  683.             if(ptr[0]=='.' && 
  684.                (ptr[1]=='/' || !ptr[1])) {
  685.                 ptr += 1+(ptr[1]=='/');
  686.                 continue;
  687.             }
  688.             break;
  689.         }
  690.         if(*ptr) {
  691.             strcat(buf, "/");
  692.             strcat(buf, ptr);
  693.         }
  694.         hold = *entries[curr];
  695.  
  696.         hold.e_name = buf;
  697.         hold.e_flags &= ~FTAGGED;
  698.         hold.e_flags |= FPERMANENT;
  699.         insert_entry(&hold);
  700.     } else {
  701.         entries[curr]->e_flags |= FPERMANENT;
  702.         entries[curr]->e_flags &= ~FTAGGED;
  703.         repaint_flags();
  704.     }
  705. }
  706.  
  707. delperm()
  708. {
  709.     entries[curr]->e_flags &= ~(FPERMANENT|FTAGGED);
  710.     repaint_flags();
  711. }
  712.  
  713. entcmp(e1, e2)
  714. struct entry **e1, **e2;
  715. {
  716.     if((*e1)->e_name[0] == '/') {
  717.         if((*e2)->e_name[0] != '/')
  718.             return 1;
  719.     } else if((*e2)->e_name[0] == '/')
  720.         return -1;
  721.  
  722.     return strcmp((*e1)->e_name, (*e2)->e_name);
  723. }
  724.  
  725. dump(start, end)
  726. int start;
  727. int end;
  728. {
  729.     int  i;
  730.     int  lo = (start<nentries)?start:nentries;
  731.     int  hi = (end<nentries)?end:nentries;
  732.  
  733.     for(i=lo; i<hi; i++) {
  734.         statout(entries[i]->e_name,
  735.         &entries[i]->e_stat,
  736.         entries[i]->e_uname,
  737.         entries[i]->e_gname,
  738.         entries[i]->e_flags);
  739.         nl();
  740.     }
  741.     return TRUE;
  742. }
  743.  
  744. statout(name, sbuf, user, group, flags)
  745. char *name;
  746. struct stat *sbuf;
  747. char *user, *group;
  748. int flags;
  749. {
  750.     int mode = sbuf->st_mode;
  751.  
  752.     if(!quickmode) {
  753.         printf("%5u ", sbuf->st_ino);
  754.  
  755.         if((mode&S_IFMT)==S_IFCHR) outc('c');
  756.         else if((mode&S_IFMT)==S_IFBLK) outc('b');
  757.         else if((mode&S_IFMT)==S_IFDIR) outc('d');
  758.         else if((mode&S_IFMT)==S_IFREG) outc('-');
  759.         else outc('?');
  760.         triad((mode>>6)&7, mode&S_ISUID, 's');
  761.         triad((mode>>3)&7, mode&S_ISGID, 's');
  762.         triad(mode&7, mode&S_ISVTX, 't');
  763.         outc(' ');
  764.  
  765.         printf("%3u ", sbuf->st_nlink);
  766.         printf("%-8s ", user);
  767.         printf("%-8s ", group);
  768.  
  769.         if((mode&S_IFMT)==S_IFREG || (mode&S_IFMT)==S_IFDIR)
  770.             printf("%7ld ", sbuf->st_size);
  771.         else
  772.             printf("%3d,%3d ",
  773.             major(sbuf->st_rdev),
  774.             minor(sbuf->st_rdev));
  775.  
  776.         outc(' ');
  777.         printime(&sbuf->st_mtime);
  778.     }
  779.  
  780.     display_flags(flags);
  781.     pname(name, sbuf->st_mode);
  782. }
  783.  
  784. char *
  785. u_name(uid)
  786. int uid;
  787. {
  788.     int  i;
  789.     struct passwd *pwptr, *getpwuid();
  790.  
  791.     for(i=0; i<u_ptr; i++)
  792.         if(u_list[i].id_id==uid)
  793.             return u_list[i].id_name;
  794.  
  795.     if(u_ptr>=MAXID)                                       /* cache full */
  796.         u_ptr = 0;        /* simplistic algorithm, wrap to beginning */
  797.     /* with MAXID >> # common id's it's good enough */
  798.  
  799.     u_list[u_ptr].id_id=uid;
  800.  
  801.     if(pwptr=getpwuid(uid)) { /* Copy name */
  802.         for(i=0; pwptr->pw_name[i]>' '; i++)
  803.             u_list[u_ptr].id_name[i]=pwptr->pw_name[i];
  804.         u_list[u_ptr].id_name[i]=0;
  805.     } 
  806.     else /* Default to UID */
  807.         sprintf(u_list[u_ptr].id_name, "%d", uid);
  808.  
  809.     return u_list[u_ptr++].id_name;
  810. }
  811.  
  812. char *
  813. g_name(gid)
  814. int gid;
  815. {
  816.     int  i;
  817.     struct group *grptr, *getgrgid();
  818.  
  819.     for(i=0; i<g_ptr; i++)
  820.         if(g_list[i].id_id==gid)
  821.             return g_list[i].id_name;
  822.  
  823.     if(g_ptr>=MAXID)                                       /* cache full */
  824.         g_ptr = 0;        /* simplistic algorithm, wrap to beginning */
  825.     /* with MAXID >> # common id's it's good enough */
  826.  
  827.     g_list[g_ptr].id_id=gid;
  828.  
  829.     if(grptr=getgrgid(gid)) { /* Copy name */
  830.         for(i=0; grptr->gr_name[i]>' '; i++)
  831.             g_list[g_ptr].id_name[i]=grptr->gr_name[i];
  832.         g_list[g_ptr].id_name[i]=0;
  833.     } 
  834.     else /* Default to UID */
  835.         sprintf(g_list[g_ptr].id_name, "%d", gid);
  836.  
  837.     return g_list[g_ptr++].id_name;
  838. }
  839.  
  840. printime(clock)
  841. long *clock;
  842. {
  843.     struct tm *tmbuf, *localtime();
  844.     static char *months[12]= {
  845.         "Jan","Feb","Mar","Apr","May","Jun",
  846.         "Jul","Aug","Sep","Oct","Nov","Dec"
  847.     };
  848.  
  849.     tmbuf=localtime(clock);
  850.     printf("%2d %3s %02d %2d:%02d",
  851.     tmbuf->tm_mday,
  852.     months[tmbuf->tm_mon],
  853.     tmbuf->tm_year,
  854.     tmbuf->tm_hour,
  855.     tmbuf->tm_min);
  856. }
  857.  
  858. header()
  859. {
  860.     int    i;
  861.     if(quickmode)
  862.         printf(" File Name");
  863.     else
  864.         printf(
  865. "Inode Long mode  LNX User     Group   Size/Dev  Modify Time     File name"
  866.             );
  867.     nl();
  868. }
  869.  
  870. triad(bits, special, code)
  871. int bits, special;
  872. char code;
  873. {
  874.     if(bits&4) outc('r');
  875.     else outc('-');
  876.  
  877.     if(bits&2) outc('w');
  878.     else outc('-');
  879.  
  880.     if(special) outc(code);
  881.     else if(bits&1) outc('x');
  882.     else outc('-');
  883. }
  884.  
  885. outs(s)
  886. char *s;
  887. {
  888.     int  outc();
  889.  
  890.     if(s)
  891.         tputs(s, 0, outc);
  892. }
  893.  
  894. outc(c)
  895. char c;
  896. {
  897.     putchar(c);
  898. }
  899.  
  900. /* Screen manipulation primitives: dumb set for smart terminals */
  901. at(x, y)
  902. int x, y;
  903. {
  904.     outs(tgoto(cm, x, y));
  905. }
  906.  
  907. nl()
  908. {
  909.     outs(ce);
  910.     outc('\n');
  911. }
  912.  
  913.  
  914. /* Scroll lines in window (from:to) n lines */
  915. scroll(from, to, n)
  916. int from, to, n;
  917. {
  918.     if(cs && sf && sr) {
  919.         outs(tgoto(cs, from, to-1));
  920.         if(n<0)
  921.             while(n++)
  922.                 outs(sr);
  923.         else
  924.             while(n--)
  925.                 outs(sf);
  926.         outs(tgoto(cs, 0, li-1));
  927.     } 
  928.     else if(al && dl) {
  929.         if(n<0) {
  930.             int i=n;
  931.             outs(tgoto(cm, 0, to+n));
  932.             while(i++)
  933.                 outs(dl);
  934.             outs(tgoto(cm, 0, from));
  935.             while(n++)
  936.                 outs(al);
  937.         } 
  938.         else {
  939.             int i=n;
  940.             outs(tgoto(cm, 0, from));
  941.             while(i--)
  942.                 outs(dl);
  943.             outs(tgoto(cm, 0, to-n));
  944.             while(n--)
  945.                 outs(al);
  946.         }
  947.     }
  948. }
  949.  
  950. wperror(file)
  951. char *file;
  952. {
  953.     extern int errno;
  954.     extern char *sys_errlist[];
  955.  
  956.     cmdline();
  957.     ctlouts(file);
  958.     ctlouts(": ");
  959.     ctlouts(errno?sys_errlist[errno]:emesg[xerrno]);
  960.     if(!display_up)
  961.         nl();
  962. }
  963.  
  964. fperror(prog, file)
  965. char *prog, *file;
  966. {
  967.     extern int errno;
  968.  
  969.     fprintf(stderr, "%s -- ", prog);
  970.     if(errno)
  971.         perror(file);
  972.     else
  973.         fprintf(stderr, "%s: %s\n", file, emesg[xerrno]);
  974. }
  975.  
  976. tinit(name)
  977. char *name;
  978. {
  979.     char *termptr;
  980.     char tbuf[TERMBUF], *tmp;
  981.     int  intr();
  982. #ifdef BSD
  983.     int  stop();
  984. #endif
  985.  
  986.     termptr = termbuf;
  987.  
  988.     tgetent(tbuf, name);
  989.  
  990.     tmp = tgetstr("pc", &termptr);
  991.     if(tmp) PC = *tmp;
  992.     UP = tgetstr("up", &termptr);
  993.     BC = tgetstr("bc", &termptr);
  994.     cm = tgetstr("cm", &termptr);
  995.     cs = tgetstr("cs", &termptr);
  996.     sf = tgetstr("sf", &termptr);
  997.     sr = tgetstr("sr", &termptr);
  998.     ce = tgetstr("ce", &termptr);
  999.     cl = tgetstr("cl", &termptr);
  1000.     al = tgetstr("al", &termptr);
  1001.     dl = tgetstr("dl", &termptr);
  1002.     us = tgetstr("us", &termptr);
  1003.     ue = tgetstr("ue", &termptr);
  1004.     so = tgetstr("so", &termptr);
  1005.     se = tgetstr("se", &termptr);
  1006.     ti = tgetstr("ti", &termptr);
  1007.     te = tgetstr("te", &termptr);
  1008.     li = tgetnum("li");
  1009.     co = tgetnum("co");
  1010.     xn = tgetflag("xn");
  1011.  
  1012.     nlines=li-3;
  1013.  
  1014. #ifdef USG
  1015.     ioctl(1, TCGETA, &rawbuf);
  1016.     cookedbuf = rawbuf;
  1017.     rawbuf.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
  1018.     rawbuf.c_cc[VMIN] = 1;
  1019.     rawbuf.c_cc[VTIME] = 0;
  1020. #else
  1021.     gtty(1, &sgbuf);
  1022.     ospeed=sgbuf.sg_ospeed;
  1023.     quickmode=ospeed<10;
  1024.     cookflags=sgbuf.sg_flags;
  1025.     sgbuf.sg_flags = (sgbuf.sg_flags&~ECHO)|CBREAK;
  1026.     rawflags=sgbuf.sg_flags;
  1027. #endif
  1028.     signal(SIGINT, intr);
  1029. #ifdef BSD
  1030.     signal(SIGTSTP, stop);
  1031. #endif
  1032.     rawtty();
  1033. }
  1034.  
  1035. int tmode=0;
  1036.  
  1037. entty()
  1038. {
  1039.     if(!tmode)
  1040.         outs(ti);
  1041.     tmode=1;
  1042. }
  1043.  
  1044. extty()
  1045. {
  1046.     if(tmode)
  1047.         outs(te);
  1048.     tmode=0;
  1049. }
  1050.  
  1051. rawtty()
  1052. {
  1053. #ifdef USG
  1054.     ioctl(1, TCSETA, &rawbuf);
  1055. #else
  1056.     sgbuf.sg_flags=rawflags;
  1057.     stty(1, &sgbuf);
  1058. #endif
  1059.     entty();
  1060. }
  1061.  
  1062. cooktty()
  1063. {
  1064. #ifdef USG
  1065.     ioctl(1, TCSETA, &cookedbuf);
  1066. #else
  1067.     sgbuf.sg_flags=cookflags;
  1068.     stty(1, &sgbuf);
  1069. #endif
  1070.     extty();
  1071. }
  1072.  
  1073. intr()
  1074. {
  1075.     int intr();
  1076.     signal(SIGINT, intr);
  1077.     intrup=1;
  1078.     bell();
  1079. }
  1080.  
  1081. #ifdef BSD
  1082. stop()
  1083. {
  1084.     int stop();
  1085.     signal(SIGTSTP, stop);
  1086.     intrup=1;
  1087.     tend();
  1088.     kill(getpid(), SIGSTOP);
  1089.     rawtty();
  1090.     display_up=0;
  1091. }
  1092. #endif
  1093.  
  1094. tend()
  1095. {
  1096.     cmdline();
  1097.     cooktty();
  1098.     fflush(stdout);
  1099. }
  1100.  
  1101. char *
  1102. pwd()
  1103. #ifdef GETCWD
  1104. {
  1105.     static char mydir[FILENAME+1] = "";
  1106.     char *getcwd();
  1107.  
  1108.     return getcwd(mydir, FILENAME);
  1109. }
  1110. #else
  1111. {
  1112.     static char mydir[FILENAME] = "";
  1113.     int  status;
  1114.     int  pip[2];
  1115.     int  n;
  1116.     int  (*sigs[2])();
  1117.  
  1118.     sigs[0] = signal(2, 1);
  1119.     sigs[1] = signal(3, 1);
  1120.  
  1121.     if(pipe(pip)<0)
  1122.         return 0;
  1123.  
  1124.     if(!fork()) {
  1125.         close(1); 
  1126.         dup(pip[1]);
  1127.         close(pip[0]);
  1128.         execl("/bin/pwd", "pwd", 0);
  1129.         exit(-1);
  1130.     }
  1131.     close(pip[1]);
  1132.     wait(&status);
  1133.     signal(2, sigs[0]);
  1134.     signal(3, sigs[1]);
  1135.  
  1136.     if(status) {
  1137.         close(pip[0]);
  1138.         return "/";
  1139.     }
  1140.     n = read(pip[0], mydir, FILENAME);
  1141.     close(pip[0]);
  1142.     if(n<=0)
  1143.         return "/";
  1144.     mydir[n-1] = 0;
  1145.     return mydir;
  1146. }
  1147. #endif
  1148.  
  1149. browse()
  1150. {
  1151.     int  c;
  1152.     char *env;
  1153.  
  1154.     if(env=getenv("BROWSE"))
  1155.         macptr = env;
  1156.  
  1157.     defmacs();
  1158.     newdir();
  1159.     redraw();
  1160.     ended=0;
  1161.  
  1162.     do {
  1163.         if(intrup) {
  1164.             intrup=0;    /* clear interrupt */
  1165.             cmdline();    /* go to the command line */
  1166.             outs("Interrupt");    /* let us know about it */
  1167.             endmac();    /* clear macros */
  1168.             clearin();    /* and input buffer */
  1169.         }
  1170.         here_i_am();
  1171.         fflush(stdout);
  1172.         c = getch();
  1173.         cmd(c);
  1174.     } 
  1175.     while(!ended);
  1176. }
  1177.  
  1178. clearin()
  1179. {
  1180.     fseek(stdin, 0L, 1); /* stay here messily */
  1181. }
  1182.  
  1183. cmd(c)
  1184. char c;
  1185. {
  1186.     int    i;
  1187.  
  1188.     if(intrup)
  1189.         return;
  1190.  
  1191.     switch(c) {
  1192.     case ' ':
  1193.         if(isdir(entries[curr])) {
  1194.             if(!cd(entries[curr]->e_name))
  1195.                 wperror(entries[curr]->e_name);
  1196.         } else
  1197.             if(!macro(c))
  1198.                 bell();
  1199.             else
  1200.                 cmd(getch());
  1201.         break;
  1202.     case '&': 
  1203.         syscom(0); 
  1204.         break;
  1205.     case '!': 
  1206.         syscom(1); 
  1207.         break;
  1208.     case '=':
  1209.         todir();
  1210.         break;
  1211.     case '?': 
  1212.         sample(entries[curr]->e_name); 
  1213.         break;
  1214.     case '[':
  1215.         define();
  1216.         break;
  1217.     case 'B'-'@':
  1218.         prev(nlines);
  1219.         break;
  1220.     case 'D'-'@':
  1221.         next(nlines/2);
  1222.         break;
  1223.     case 'F'-'@':
  1224.         next(nlines);
  1225.         break;
  1226.     case 'H': 
  1227.         curr=top; 
  1228.         break;
  1229.     case 'J': 
  1230.         tail(); 
  1231.         break;
  1232.     case 'K': 
  1233.         home(); 
  1234.         break;
  1235.     case 'L'-'@': 
  1236.         redraw(); 
  1237.         break;
  1238.     case 'L': 
  1239.         curr=bottom-1; 
  1240.         break;
  1241.     case 'M':
  1242.         definitions();
  1243.         break;
  1244.     case 'N': 
  1245.         next(nlines);
  1246.         break;
  1247.     case 'P': 
  1248.         prev(nlines);
  1249.         break;
  1250.     case 'R': 
  1251.         move(); 
  1252.         break;
  1253.     case 'S':
  1254.         savedefs();
  1255.         break;
  1256.     case 'U'-'@':
  1257.         prev(nlines/2);
  1258.         break;
  1259.     case 'D':
  1260.     case 'd': 
  1261.         if(getch()==c && !intrup)
  1262.             remove(c=='D'); 
  1263.         else
  1264.             bell(); 
  1265.         break;
  1266.     case 'h': 
  1267.         ccol=0; 
  1268.         break;
  1269.     case 'l': 
  1270.         ccol=NCOL; 
  1271.         break;
  1272.     case '<':
  1273.         quickmode=1;
  1274.         if(display_up) {
  1275.             todump=1;
  1276.             at(0, 1);
  1277.             header();
  1278.         }
  1279.         break;
  1280.     case '+': case '^':
  1281.         addname(c);
  1282.         break;
  1283.     case '(':
  1284.         addperm();
  1285.         break;
  1286.     case ')':
  1287.         delperm();
  1288.         break;
  1289.     case '>':
  1290.         quickmode=0;
  1291.         if(display_up) {
  1292.             todump=1;
  1293.             at(0, 1);
  1294.             header();
  1295.         }
  1296.         break;
  1297.     case 'J'-'@': 
  1298.     case 'j': 
  1299.         newline(); 
  1300.         break;
  1301.     case 'K'-'@': 
  1302.     case 'k': 
  1303.         upline(); 
  1304.         break;
  1305.     case 'n': 
  1306.         next(nlines/2);
  1307.         break;
  1308.     case 'p': 
  1309.         prev(nlines/2);
  1310.         break;
  1311.     case 'q':  case 'Z': case 'Q':
  1312.         if(getchar()==c && !intrup)
  1313.             ended=1;
  1314.         else
  1315.             bell();
  1316.         break;
  1317.     case 'r': 
  1318.         reload(); 
  1319.         break;
  1320.     case 't':
  1321.         tag();
  1322.         break;
  1323.     case 'T': case 'U':
  1324.         tag_all(c=='T');
  1325.         break;
  1326.     default:
  1327.         if(!macro(c))
  1328.             bell();
  1329.         else
  1330.             cmd(getch()); /* make sure it does something */
  1331.     }                                 /* and thus avoid unneeded redraws */
  1332. }
  1333.  
  1334. cmdline()
  1335. {
  1336.     at(0, li-1);
  1337.     outs(ce);
  1338. }
  1339.  
  1340. newdir()
  1341. {
  1342.     if(display_up)
  1343.         at(0,0);
  1344.     fflush(stdout);
  1345.     dot=pwd();
  1346.  
  1347.     if(!getdir())
  1348.         wperror(dot);
  1349.  
  1350.     curr=0;
  1351.     top=0;
  1352.     topline();
  1353.     if(display_up)
  1354.         todump=TRUE;
  1355. }
  1356.  
  1357. reload()
  1358. {
  1359.     getdir();
  1360.     curr=(curr>=bottom)?bottom-1:curr;
  1361.     if(display_up) {
  1362.         topline();
  1363.         todump=TRUE;
  1364.     }
  1365. }
  1366.  
  1367. topline()
  1368. {
  1369.     if(display_up)
  1370.         at(0,0);
  1371.     printf("%s: %d files", dot, nentries);
  1372.     nl();
  1373. }
  1374.  
  1375. redraw()
  1376. {
  1377.     outs(cl);
  1378.     display_up=0;
  1379.     topline();
  1380.     at(0,1);
  1381.     header();
  1382.     todump=1;
  1383.     display_up=1;
  1384. }
  1385.  
  1386. dumpdata()
  1387. {
  1388.     at(0,2);
  1389.     dump(top,bottom);
  1390.     if(top+nlines>nentries) {
  1391.         int i;
  1392.         at(0, bottom-top+2);
  1393.         for(i=bottom-top; i<nlines; i++) {
  1394.             outc('~');
  1395.             nl();
  1396.         }
  1397.     }
  1398. }
  1399.  
  1400. upline()
  1401. {
  1402.      if(curr>0)
  1403.          curr--;
  1404.      else bell();
  1405. }
  1406.  
  1407. home()
  1408. {
  1409.     curr=0;
  1410. }
  1411.  
  1412. next(l)
  1413. {
  1414.      curr += l;
  1415.      if(curr>=nentries) curr=nentries-1;
  1416. }
  1417.  
  1418. prev(l)
  1419. {
  1420.      curr -= l;
  1421.      if(curr<0) curr=0;
  1422. }
  1423.  
  1424. tail()
  1425. {
  1426.     curr=nentries-1;
  1427. }
  1428.  
  1429. newline()
  1430. {
  1431.      if(curr<nentries-1)
  1432.          curr++;
  1433.      else
  1434.         bell();
  1435. }
  1436.  
  1437. here_i_am()
  1438. {
  1439.     int c;
  1440.     if(*macptr)
  1441.         return;
  1442.     if(todump)
  1443.         display_up = 1;
  1444.     if(!display_up) {
  1445.         cmdline();
  1446.         statout(entries[curr]->e_name,
  1447.             &entries[curr]->e_stat,
  1448.             entries[curr]->e_uname,
  1449.             entries[curr]->e_gname,
  1450.             entries[curr]->e_flags);
  1451.         at(quickmode?1:ccol, li-1);
  1452.         fflush(stdout);
  1453.         if((c=getch())=='\n') {
  1454.             redraw();
  1455.             here_i_am();
  1456.         } 
  1457.         else
  1458.             ungetch(c);
  1459.      } else if(todump) {
  1460.          if(!(curr-top > 0 && curr-top < nlines)) {
  1461.              top = curr-nlines/2;
  1462.              if(top<0) top=0;
  1463.          }
  1464.          dumpdata();
  1465.          at(quickmode?1:ccol, curr-top+2);
  1466.          todump=0;
  1467.      } else {
  1468.          int lines_to_scroll = curr-top;
  1469.          if(lines_to_scroll > 0)
  1470.              if((lines_to_scroll -= nlines-1) < 0)
  1471.                  lines_to_scroll = 0;
  1472.          if(lines_to_scroll < 1-nlines) {
  1473.              top=curr;
  1474.              at(0,2);
  1475.              dump(top, bottom);
  1476.          } else if(lines_to_scroll > nlines-1) {
  1477.              top=curr-nlines+1;
  1478.              at(0,2);
  1479.              dump(top, bottom);
  1480.          } else if(lines_to_scroll) {
  1481.              scroll(2, nlines+2, lines_to_scroll);
  1482.              top += lines_to_scroll;
  1483.              if(lines_to_scroll < 0) {
  1484.                  at(0, 2);
  1485.                  dump(top, top-lines_to_scroll);
  1486.              } else {
  1487.                  at(0, 2+nlines-lines_to_scroll);
  1488.                  dump(bottom-lines_to_scroll, bottom);
  1489.              }
  1490.          }
  1491.          at(quickmode?1:ccol, curr-top+2);
  1492.      }
  1493. }
  1494.  
  1495. bell()
  1496. {
  1497.     outc(7);
  1498. }
  1499.  
  1500. perform(command)
  1501. char *command;
  1502. {
  1503.     char cmdbuf[MAXLINE];
  1504.  
  1505.     cmdline();
  1506.     extty();
  1507.     outc('!');
  1508.     printf(command, entries[curr]->e_name);
  1509.     sprintf(cmdbuf, command, entries[curr]->e_name);
  1510.  
  1511.     system(cmdbuf, 1);
  1512.     entty();
  1513. }
  1514.  
  1515. system(command, rdflag)
  1516. char *command;
  1517. int rdflag; /* Should I redraw? */
  1518. {
  1519.     char scratch[32];
  1520.     int status;
  1521.     int (*sigint)(), (*sigquit)();
  1522.     char c;
  1523.  
  1524.     sigint=signal(2, 1);
  1525.     sigquit=signal(3, 1);
  1526.     cooktty();
  1527.     fflush(stdout);
  1528.     strcpy(scratch, entries[curr]->e_name);
  1529.     if(!fork()) {
  1530.         int i;
  1531.         static char *envp[MAXARGC];
  1532.         static char env[NCARGS];
  1533.         char *hold;
  1534.         char line[MAXLINE];
  1535.         char *tmp;
  1536.  
  1537.         signal(2,0);
  1538.         signal(3,0);
  1539.  
  1540.         if(!(efp=fopen(efname, "r"))) {
  1541.             fputc('\n', stderr);
  1542.             perror(efname);
  1543.             execl(SHELL, SHELL, "-c", command, 0);
  1544.             execl("/bin/sh", "sh", "-c", command, 0);
  1545.             perror("/bin/sh");
  1546.             exit(-77);
  1547.         }
  1548.  
  1549.         i=0;
  1550.         tmp=hold=env;
  1551.  
  1552.         while(!feof(efp)) {
  1553.             fgets(line, MAXLINE, efp);
  1554.             if(strlen(line)+(tmp-env)>NCARGS)
  1555.                 break;
  1556.             if(line[0]=='$')
  1557.                 if(tmp>hold) {
  1558.                     envp[i] = hold;
  1559.                     i++;
  1560.                     if(i > MAXARGC-2) break;
  1561.                     tmp[-1]=0;   /* eat line-feed at end */
  1562.                     hold = tmp;
  1563.                 }
  1564.             strcpy(tmp, line+(line[0]=='$'));
  1565.             tmp += strlen(tmp);
  1566.         }
  1567.         if(tmp>hold) {
  1568.             envp[i] = hold;
  1569.             i++;
  1570.             tmp[-1]=0;               /* and eat this one as well */
  1571.         }
  1572.         sprintf(tmp, "FILE=%s", scratch);
  1573.         envp[i++]=tmp;
  1574.         envp[i]=0;
  1575.  
  1576.         if(rdflag)
  1577.             putchar('\n');
  1578.         else
  1579.             putchar('\r');
  1580.         fflush(stdout);
  1581.         execle(SHELL, SHELL, "-c", command, 0, envp);
  1582.         execle("/bin/sh", "sh", "-c", command, 0, envp);
  1583.         perror("/bin/sh");
  1584.         exit(-77);
  1585.     }
  1586.     wait(&status);
  1587.     signal(2, sigint);
  1588.     signal(3, sigquit);
  1589.     rawtty();
  1590.  
  1591.     if(rdflag || status!=0)
  1592.         display_up=0;
  1593. }
  1594.  
  1595. char
  1596. inps(buf, text, termin)
  1597. char *buf;
  1598. char *text;
  1599. char termin;
  1600. {
  1601.     int i = 0;
  1602.     char c, *ptr, *txp;
  1603.  
  1604.     txp=text?text:"!";
  1605.  
  1606.     while(!intrup &&
  1607.         (fflush(stdout), c=getch()) != '\033' &&
  1608.         c != '\n' &&
  1609.         c != termin)
  1610.         switch(c) {
  1611.         case '\b': 
  1612.         case '\177':
  1613.             if(i>0) {
  1614.                 printf("\b \b");
  1615.                 i--;
  1616.             } 
  1617.             else
  1618.                 bell();
  1619.             break;
  1620.         case 'U'-'@':
  1621.             txp=text?text:"!";
  1622.         case 'X'-'@':
  1623.             if(i>0)
  1624.                 while(i>0) {
  1625.                     printf("\b \b");
  1626.                     i--;
  1627.                 }
  1628.             else
  1629.                 bell();
  1630.             break;
  1631.         case 'K'-'@':
  1632.             if(*txp)
  1633.                 ctloutc(buf[i++] = *txp++);
  1634.             break;
  1635.         case '%':
  1636.             for(ptr=entries[curr]->e_name; *ptr; ptr++)
  1637.                 ctlout(buf[i++] = *ptr);
  1638.             standend();
  1639.             break;
  1640.         case '#':
  1641.             for(ptr=dot; *ptr; ptr++)
  1642.                 ctlout(buf[i++] = *ptr);
  1643.             standend();
  1644.             break;
  1645.         case '~':
  1646.             for(ptr=HOME; *ptr; ptr++)
  1647.                 ctlout(buf[i++] = *ptr);
  1648.             standend();
  1649.             break;
  1650.         case '@':
  1651.             outc(c);
  1652.             fflush(stdout);
  1653.             c = getch();
  1654.             if(!macro(c)) {
  1655.                 ungetch(c);
  1656.                 buf[i++]='@';
  1657.             } 
  1658.             else
  1659.                 outs("\b \b");
  1660.             break;
  1661.         case '$':
  1662.             outc(c);
  1663.             fflush(stdout);
  1664.             c = getch();
  1665.             if(c=='$') {
  1666.                 char tmp[10];
  1667.                 sprintf(tmp, "%d", getpid());
  1668.                 outs("\b \b");
  1669.                 for(ptr=tmp; *ptr; ptr++)
  1670.                     ctlout(buf[i++] = *ptr);
  1671.                 standend();
  1672.             } 
  1673.             else if(!macbuf[c]) {
  1674.                 ungetch(c);
  1675.                 buf[i++]='$';
  1676.             } 
  1677.             else {
  1678.                 outs("\b \b");
  1679.                 for(ptr=macbuf[c]; *ptr; ptr++)
  1680.                     ctlout(buf[i++] = *ptr);
  1681.                 standend();
  1682.             }
  1683.             break;
  1684.         case '!':
  1685.             while(*txp)
  1686.                 ctlout(buf[i++] = *txp++);
  1687.             standend();
  1688.             break;
  1689.         case '\\':
  1690.             outc(c);
  1691.             fflush(stdout);
  1692.             c=getch();
  1693.             if(c=='~' || c=='%' || c=='#' ||
  1694.                 c=='\\' || c=='!' ||
  1695.                 c=='K'-'@' || c=='U'-'@' || c=='X'-'@' ||
  1696.                 c=='\b' || c=='\177' ||
  1697.                 c==termin || c=='\033' || c=='\n' ||
  1698.                 c=='@' || c=='$') {
  1699.                 outc('\b');
  1700.                 ctloutc(buf[i++]=c);
  1701.                 break;
  1702.             } 
  1703.             else if(c>='0' && c<='7') {
  1704.                 int n, val=0;
  1705.                 for(n=0; n<3 && c>='0' && c<='7'; n++) {
  1706.                     val = val*8 + c-'0';
  1707.                     outc('\b');
  1708.                     ctloutc(val);
  1709.                     c=getch();
  1710.                 }
  1711.                 ungetch(c);
  1712.                 c=buf[i++]=val;
  1713.                 break;
  1714.             } 
  1715.             else if(c=='^') {
  1716.                 outc('\b');
  1717.                 outc('^');
  1718.                 fflush(stdout);
  1719.                 c=getch();
  1720.                 if(c>='?'&&c<='_') {
  1721.                     outc('\b');
  1722.                     ctloutc(buf[i++]=(c-'@')&'\177');
  1723.                     break;
  1724.                 } 
  1725.                 else if(c>='`'&&c<='~') {
  1726.                     outc('\b');
  1727.                     ctloutc(buf[i++]=c-'`');
  1728.                     break;
  1729.                 } /* otherwise default */
  1730.                 else buf[i++]='^'; /* after adding caret */
  1731.  
  1732.             } /* otherwise fall through to default */
  1733.             else buf[i++]='\\'; /* after adding backslash */
  1734.         default:
  1735.             ctloutc(buf[i++] = c);
  1736.             break;
  1737.         }
  1738.  
  1739.     buf[i] = 0;
  1740.     return intrup?'\033':c;
  1741. }
  1742.  
  1743. ctlouts(s)
  1744. char *s;
  1745. {
  1746.     int cnt = 0;
  1747.  
  1748.     while(*s)
  1749.         cnt += ctlout(*s++);
  1750.     cnt += standend();
  1751.  
  1752.     return cnt;
  1753. }
  1754.  
  1755. ctloutc(c)
  1756. char c;
  1757. {
  1758.     int cnt;
  1759.  
  1760.     cnt = ctlout(c);
  1761.     cnt += standend();
  1762.  
  1763.     return cnt;
  1764. }
  1765.  
  1766. int somode = 0;
  1767. int ulmode = 0;
  1768.  
  1769. standout()
  1770. {
  1771.     if(!somode) {
  1772.         outs(so);
  1773.         somode = 1;
  1774.         if(xn) return 1;
  1775.     }
  1776.     return 0;
  1777. }
  1778.  
  1779. underline()
  1780. {
  1781.     if(!ulmode) {
  1782.         outs(us);
  1783.         ulmode = 1;
  1784.         if(xn) return 1;
  1785.     }
  1786.     return 0;
  1787. }
  1788.  
  1789. standend()
  1790. {
  1791.     int cnt = 0;
  1792.  
  1793.     if(somode) {
  1794.         outs(se);
  1795.         somode = 0;
  1796.         if(xn) cnt++;
  1797.     }
  1798.     if(ulmode) {
  1799.         outs(ue);
  1800.         ulmode = 0;
  1801.         if(xn) cnt++;
  1802.     }
  1803.     return cnt;
  1804. }
  1805.  
  1806. ctlout(c)
  1807. char c;
  1808. {
  1809.     int cnt = 0;
  1810.     if(c&'\200') {
  1811.         cnt += underline();
  1812.         cnt += ctlout(c&'\177');
  1813.         return cnt;
  1814.     } 
  1815.     else if(c<' ' || c=='\177') {
  1816.         cnt += standout();
  1817.         outc((c+'@')&'\177');
  1818.         cnt++;
  1819.         return cnt;
  1820.     } 
  1821.     else {
  1822.         cnt += standend();
  1823.         outc(c);
  1824.         cnt++;
  1825.         return cnt;
  1826.     }
  1827. }
  1828.  
  1829. todir()
  1830. {
  1831.     char cmdbuf[MAXLINE];
  1832.     static char lastdir[MAXLINE] = ".";
  1833.     char *slash, *rindex();
  1834.  
  1835.     cmdline();
  1836.     printf("goto ");
  1837.     if(inps(cmdbuf, lastdir, 0)!='\033' && cmdbuf[0]) {
  1838.         strcpy(lastdir, cmdbuf);
  1839.         if(!cd(cmdbuf, 0)) {
  1840.             if(!fgoto(cmdbuf))
  1841.                 if(slash=rindex(cmdbuf, '/')) {
  1842.                     *slash++=0;
  1843.                     if(cd(cmdbuf, 1)) {
  1844.                         if(!fgoto(slash)) {
  1845.                             errno=0;
  1846.                             xerrno=NOMATCH;
  1847.                             wperror(slash);
  1848.                         }
  1849.                     } else
  1850.                         wperror(cmdbuf);
  1851.                 } else
  1852.                     wperror(cmdbuf);
  1853.         }
  1854.     } 
  1855.     else
  1856.         killcmd();
  1857. }
  1858.  
  1859. fgoto(file)
  1860. char *file;
  1861. {
  1862.     int i;
  1863.  
  1864.     for(i = 0; i<nentries; i++)
  1865.         if(match(entries[i]->e_name, file)) {
  1866.             curr=i;
  1867.             return 1;
  1868.         }
  1869.  
  1870.     return 0;
  1871. }
  1872.  
  1873. match(target, sample)
  1874. char *target, *sample;
  1875. {
  1876.     while(*sample && *target==*sample) {
  1877.         target++;
  1878.         sample++;
  1879.     }
  1880.     return !*sample;
  1881. }
  1882.  
  1883. killcmd()
  1884. {
  1885.     if(!intrup) {
  1886.         cmdline();
  1887.         printf("Command killed");
  1888.         if(!display_up)
  1889.             nl();
  1890.     }
  1891. }
  1892.  
  1893. cd(dir, flag)
  1894. char *dir;
  1895. int flag;
  1896. {
  1897.     if(flag) {
  1898.         cmdline();
  1899.         printf("cd %s\r", dir);
  1900.     } 
  1901.     else
  1902.         outc('\r');
  1903.     fflush(stdout);
  1904.     if(access(dir, 5)==0 && chdir(dir)==0) {
  1905.         newdir();
  1906.         return 1;
  1907.     } 
  1908.     return 0;
  1909. }
  1910.  
  1911. syscom(rd)
  1912. int rd; /* should I redraw? */
  1913. {
  1914.     char buf[MAXLINE];
  1915.     static char lastcmd[MAXLINE] = "";
  1916.     char inps();
  1917.  
  1918.     cmdline();
  1919.     extty();
  1920.     putchar(rd?'!':'&');
  1921.     if(inps(buf, lastcmd, 0)=='\033') {
  1922.         entty();
  1923.         killcmd();
  1924.         return;
  1925.     } 
  1926.     else
  1927.         strcpy(lastcmd, buf);
  1928.     system(buf, rd);
  1929.     entty();
  1930. }
  1931.  
  1932. isdir(entry)
  1933. struct entry *entry;
  1934. {
  1935.     return((entry->e_stat.st_mode&S_IFMT)==S_IFDIR);
  1936. }
  1937.  
  1938. sample(name)
  1939. char *name;
  1940. {
  1941.     int col;
  1942.     int c, i;
  1943.     FILE *tfp;
  1944.  
  1945.     if(!(tfp = fopen(name, "r"))) {
  1946.         wperror(name);
  1947.         return;
  1948.     }
  1949.  
  1950.     i=0;
  1951.     do {
  1952.         cmdline();
  1953.         col = 0;
  1954.         for(c=fgetc(tfp); col<72 && !feof(tfp); c=fgetc(tfp))
  1955.             col+=ctlout(c);
  1956.         standend();
  1957.         if(display_up)
  1958.             outc('\r');
  1959.         else
  1960.             outc('\n');
  1961.     } 
  1962.     while(!feof(tfp) && (i=getch())=='?');
  1963.  
  1964.     fclose(tfp);
  1965.  
  1966.     if(i && i!=' ' && i!='q' && i!='?')
  1967.         ungetch(i);
  1968. }
  1969.  
  1970. macro(c)
  1971. char c;
  1972. {
  1973.     if(c==NOMAC)
  1974.         return 0;
  1975.     else if(!macbuf[c])
  1976.         return 0;
  1977.     else if(c==c_macro) {
  1978.         cmdline();
  1979.         printf("Recursive macro.");
  1980.         endmac();
  1981.         return 0;
  1982.     } 
  1983.     else {
  1984.         c_macro = c;
  1985.         macptr = macbuf[c];
  1986.         return 1;
  1987.     }
  1988. }
  1989.  
  1990. getch()
  1991. {
  1992.     char c;
  1993.  
  1994.     if(ungetptr>ungetbuf)
  1995.         return *--ungetptr;
  1996.     if(*macptr)
  1997.         if(*macptr=='\007') {
  1998.             macptr++;
  1999.             if(*macptr!='\007')
  2000.                 return getchar();
  2001.             else {
  2002.                 if((c=getchar()) != '\n')
  2003.                     macptr--;
  2004.                 else
  2005.                     macptr++;
  2006.                 return (c=='\n')?getch():c;
  2007.             }
  2008.         } 
  2009.         else if(*macptr=='\\') {
  2010.             if(macptr[1]=='\007')
  2011.                 macptr++;
  2012.             return *macptr++;
  2013.         } 
  2014.         else
  2015.             return *macptr++;
  2016.     else {
  2017.         endmac();
  2018.         return getchar();
  2019.     }
  2020. }
  2021.  
  2022. endmac() {
  2023.     c_macro=NOMAC;
  2024.     macptr="";
  2025. }
  2026.  
  2027. ungetch(c)
  2028. char c;
  2029. {
  2030.     if(ungetptr-ungetbuf>SMALLBUF)
  2031.         return;
  2032.     *ungetptr++=c;
  2033. }
  2034.  
  2035. define()
  2036. {
  2037.     int c;
  2038.     char buf[SMALLBUF];
  2039.  
  2040.     cmdline();
  2041.  
  2042.     printf("define ");
  2043.     c = getch();
  2044.  
  2045.     if(intrup)
  2046.         return;
  2047.  
  2048.     ctloutc(c);
  2049.     printf(" as [");
  2050.     if(inps(buf, macbuf[c], ']')=='\033') {
  2051.         killcmd();
  2052.         return;
  2053.     }
  2054.     printf("]");
  2055.  
  2056.     defent(c, buf);
  2057. }
  2058.  
  2059. defent(c, buf)
  2060. char c;
  2061. char *buf;
  2062. {
  2063.     if(macbuf[c])
  2064.         free(macbuf[c]);
  2065.  
  2066.     if(!buf[0]) {
  2067.         macbuf[c]=0;
  2068.         return;
  2069.     }
  2070.  
  2071.     macbuf[c] = (char *)malloc(strlen(buf)+1);
  2072.  
  2073.     if(!macbuf[c]) {
  2074.         cmdline();
  2075.         printf("No room");
  2076.         return;
  2077.     }
  2078.  
  2079.     strcpy(macbuf[c], buf);
  2080. }
  2081.  
  2082. defmacs()
  2083. {
  2084.     defent(' ', "!more %\n");
  2085.     defent('%', "!%\n");
  2086.     defent('.', "=.");
  2087.     defent('/', "=/");
  2088.     defent('~', "=~");
  2089.     defent('v', "!vi %\n");
  2090.     defent('$', "!vi /tmp/br.env.$$\n");
  2091. }
  2092.  
  2093. definitions()
  2094. {
  2095.     char *ptr;
  2096.     int    i;
  2097.  
  2098.     cmdline();
  2099.     for(i=0; i<CHARSET; i++)
  2100.         if(macbuf[i]) {
  2101.             printf("define ");
  2102.             ctloutc(i);
  2103.             printf(" as [");
  2104.             ctlouts(macbuf[i]);
  2105.             printf("]\n");
  2106.         }
  2107.     display_up=0;
  2108. }
  2109.  
  2110. savedefs()
  2111. {
  2112.     int i;
  2113.     char filename[MAXLINE];
  2114.     static char lastfile[MAXLINE] = "/usr/tmp/macros";
  2115.     FILE *fp;
  2116.  
  2117.     cmdline();
  2118.     outs("Save macros as ");
  2119.  
  2120.     if(inps(filename, lastfile, '\033')=='\033') {
  2121.         killcmd();
  2122.         return;
  2123.     }
  2124.  
  2125.     strcpy(lastfile, filename);
  2126.  
  2127.     if(!(fp = fopen(filename, "w"))) {
  2128.         wperror(filename);
  2129.         return;
  2130.     }
  2131.  
  2132.     for(i=1; i<CHARSET; i++)
  2133.         if(macbuf[i])
  2134.             fprintf(fp, "[%c%s]\n", i, macbuf[i]);
  2135.  
  2136.     fclose(fp);
  2137. }
  2138.  
  2139. dumpenv(envp)
  2140. char **envp;
  2141. {
  2142.     if(!(efp=fopen(efname, "w"))) {
  2143.         fperror(efname);
  2144.         exit(-1);
  2145.     }
  2146.     while(*envp)
  2147.         fprintf(efp, "$%s\n", *envp++);
  2148.     fflush(efp);
  2149. }
  2150.