home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 0 / 0979 / browse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  20.0 KB  |  1,184 lines

  1. /*             -- Just what the hell am I ??? ---                            */
  2. /* (If this is made from MAKEFILE, BSD or USG should be set.) */
  3.  
  4. #include <stdio.h>
  5.  
  6. #include "system.h"
  7.  
  8. /*         -- Miscellaneous include files --                     */
  9.  
  10. #include <sys/param.h>            /* NCARGS, and others */
  11. #ifndef M_XENIX
  12. # include <sys/types.h>                       /* data types for various files */
  13. #endif
  14. #include <sys/stat.h>         /* stat data structure for getdir(), statout() */
  15. #include <sys/dir.h>                      /* dir data structure for getdir() */
  16. #include <pwd.h>                       /* passwd data structure for u_name() */
  17. #include <grp.h>                        /* group data structure for g_name() */
  18. #ifdef BSD
  19. # include <sys/time.h>                  /* time data structure for printime() */
  20. #else
  21. # include <time.h>                       /* time data structure for printime() */
  22. #endif
  23. #include <signal.h>
  24.  
  25. #ifndef MAXNAMLEN
  26. # ifdef BSD
  27. #  define MAXNAMLEN 256
  28. # else
  29. #  define MAXNAMLEN DIRSIZ
  30. # endif
  31. #endif
  32.  
  33. /*        -- make information --
  34. BUILD
  35. browse: browse.c
  36.     cc browse.c -O -o browse -ltermlib
  37. END
  38. */
  39.  
  40. /*        -- Miscellaneous defines --                     */
  41. #define FALSE 0
  42. #define TRUE 1
  43.  
  44. #define MAXENTS 1024
  45. #define MAXID 16
  46. #define MAXLINE 81
  47. #define NCOL 64
  48. #define MAXNAME 14
  49. #define FILENAME 256
  50.  
  51. /*        -- Extended directory entry format --                 */
  52. struct entry {
  53.     char *e_name;
  54.     int e_flags;
  55. #define FTAGGED (1<<0)
  56. #define FPERMANENT (1<<1)
  57.     struct stat e_stat;                             /* file status field */
  58.     char e_uname[9];                                        /* user name */
  59.     char e_gname[9];                                /* user's group name */
  60. *xentries[MAXENTS], **entries=xentries;
  61. int nentries;
  62.  
  63. /*        -- Look-up cache for user names --                 */
  64. struct idtab {
  65.     int  id_id;                                    /* user (or group) id */
  66.     char id_name[9];                                 /* name[8] + filler */
  67. u_list[MAXID],                                       /* Matched user id's. */
  68. g_list[MAXID];                                              /* ditto group */
  69. int u_ptr=0, g_ptr=0;                                     /* current entries */
  70.  
  71. /*        -- Global variables --                         */
  72. int ccol=NCOL;                /* Width of used display, current column */
  73. int quickmode;              /* short display mode (files only) */
  74.  
  75. int    top, curr;               /* Positions of screen in directory */
  76. #define bottom ((top+nlines>nentries)?nentries:(top+nlines))
  77. char    *dot;                                   /* name of current directory */
  78. int    nlines;                         /* number of lines displayed on page */
  79. char    display_up;                               /* Does the display exist? */
  80. int    todump=1;                 /* Do we want to dump data? */
  81. int    ended;                                    /* Have we quite finished? */
  82. int    intrup;                    /* Have we been interrupted? */
  83. char    *HOME;                      /* Where did I start from? */
  84. char    *SHELL;                       /* How do I run programs? */
  85.  
  86. /*        -- types of functions !!!                     */
  87. char *getenv();
  88. char *malloc();
  89.  
  90. #define NEW(t) (t *)malloc(sizeof (t))
  91. #define NIL(t) ((t) 0)
  92.  
  93. /*        -- Code starts here: dummy main --                    */
  94. main(ac, av)
  95. int ac;
  96. char **av;
  97. {
  98.     if(ac>1) chdir(av[1]);
  99.  
  100.     HOME=getenv("HOME");
  101.     SHELL=getenv("SHELL");
  102.  
  103.     intrup=0;
  104.     if(tcl_init()) {
  105.         tinit(getenv("TERM"));
  106.         clear_all();
  107.         browse();
  108.         tend();
  109.         tcl_end();
  110.     }
  111.     exit(0);
  112. }
  113.  
  114. clear_all()
  115. {
  116.     int i;
  117.  
  118.     for(i = 0; i < MAXENTS; i++)
  119.         entries[i] = 0;
  120. }
  121.  
  122. char *clone(name)
  123. char *name;
  124. {
  125.     char *hold;
  126.     
  127.     hold = (char *)malloc(strlen(name)+1);
  128.  
  129.     if(hold==0)
  130.         return 0;
  131.     strcpy(hold, name);
  132.     return hold;
  133. }
  134.  
  135. newname(e, name)
  136. struct entry *e;
  137. char *name;
  138. {
  139.     if(e->e_name)
  140.         free(e->e_name);
  141.     e->e_name = clone(name);
  142. }
  143.  
  144. #if BSD
  145. readent(dp, buffer)
  146. DIR *dp;
  147. char *buffer;
  148. {
  149.     struct direct *ptr;
  150.  
  151.     do {
  152.         ptr = readdir(dp);
  153.         if(!ptr) return 0;
  154.     } while(ptr->d_ino == 0);
  155.  
  156.     strcpy(buffer, ptr->d_name);
  157.     return 1;
  158. }
  159. #else
  160. #define opendir(n) fopen(n, "r")
  161. #define DIR FILE
  162. readent(dp, buffer)
  163. DIR *dp;
  164. char *buffer;
  165. {
  166.     struct direct db;
  167.     while(fread(&db, sizeof(struct direct), 1, dp)) {
  168.         if(db.d_ino) {
  169.             strncpy(buffer, db.d_name, MAXNAMLEN);
  170.             buffer[MAXNAMLEN] = 0;
  171.             return 1;
  172.         }
  173.     }
  174.     return 0;
  175. }
  176. #define closedir fclose
  177. #endif
  178.  
  179. getdir()
  180. {
  181.     char *u_name(), *g_name();
  182.     DIR *dp;
  183.     static char buffer[MAXNAMLEN+1];
  184.     int i, p;
  185.  
  186.     if(!(dp = opendir("."))) {
  187.         save_errno(".");
  188.         return FALSE;
  189.     }
  190.  
  191.     p = 0;
  192.     for(i = 0; i < nentries; i++) {
  193.         if(entries[i]->e_flags & FPERMANENT) {
  194.             if(p != i) {
  195.                 struct entry *hold;
  196.                 hold = entries[p];
  197.                 entries[p] = entries[i];
  198.                 entries[i] = hold;
  199.             }
  200.             p++;
  201.         }
  202.     }
  203.  
  204.     for(nentries = p; !intrup && nentries < MAXENTS; nentries++) {
  205.         if(!entries[nentries]) {
  206.             entries[nentries] = NEW(struct entry);
  207.             if(!entries[nentries])
  208.                 break;
  209.             entries[nentries]->e_name = NIL(char *);
  210.         }
  211.  
  212.         if(!readent(dp, buffer))
  213.             break;
  214.  
  215.         if(stat(buffer, &entries[nentries]->e_stat)==-1) {
  216.             closedir(dp);
  217.             save_errno(buffer);
  218.             return FALSE;
  219.         }
  220.  
  221.         newname(entries[nentries], buffer);
  222.  
  223.         entries[nentries]->e_flags = 0;
  224.  
  225.         strcpy(entries[nentries]->e_uname,
  226.             u_name(entries[nentries]->e_stat.st_uid));
  227.  
  228.         strcpy(entries[nentries]->e_gname,
  229.             g_name(entries[nentries]->e_stat.st_gid));
  230.     }
  231.  
  232.     closedir(dp);
  233.  
  234.     if(intrup)
  235.         return FALSE;
  236.  
  237.     if(nentries>=MAXENTS || entries[nentries]==NIL(struct entry *)) {
  238.         save_errmsg(".: Directory too large");
  239.         return FALSE;
  240.     }
  241.  
  242.     sortdir();
  243.  
  244.     if(intrup) {
  245.         save_errmsg("Interrupted");
  246.         return FALSE;
  247.     }
  248.     return TRUE;
  249. }
  250.  
  251. at_current()
  252. {
  253.     at_file(curr);
  254. }
  255.  
  256. at_file(file)
  257. int file;
  258. {
  259.     if(display_up) {
  260.         if(file < top || file >= top+nlines)
  261.             return 0;
  262.         at(0, curr-top+2);
  263.     } else {
  264.         if(file != curr)
  265.             return 0;
  266.         cmdline();
  267.     }
  268.     return 1;
  269. }
  270.  
  271. disp_flags(flags)
  272. {
  273.     outc((flags&FTAGGED)?'+':((flags&FPERMANENT)?'!':' '));
  274. }
  275.  
  276. show_flags(ent)
  277. {
  278.     if(!display_up) return;
  279.     if(ent < top || ent >= top+nlines) return;
  280.     at(quickmode?0:(ccol-1), ent-top+2);
  281.     disp_flags(entries[ent]->e_flags);
  282. }
  283.  
  284. tag(ent, mode, bit)
  285. {
  286.     switch(bit) {
  287.         case 'P': bit = FPERMANENT; break;
  288.         case 'T': bit = FTAGGED; break;
  289.     }
  290.     switch(mode) {
  291.         case -1: entries[ent]->e_flags &= ~bit; break;
  292.         case 0: entries[ent]->e_flags ^= bit; break;
  293.         case 1: entries[ent]->e_flags |= bit; break;
  294.     }
  295.     show_flags(ent);
  296. }
  297.  
  298. tagged(ent)
  299. {
  300.     return (entries[ent]->e_flags & FTAGGED) ? 1 : 0;
  301. }
  302.  
  303. delete_from_display(file)
  304. int file;
  305. {
  306.     if(!display_up) return;
  307.  
  308.     if(file>=top+nlines) return;
  309.  
  310.     if(file < top) file = top;
  311.  
  312.     scroll(2+file-top, 2+nlines, 1);
  313.     at(0, 2+nlines-1);
  314.     if(top+nlines >= nentries)
  315.         outc('~');
  316.     else
  317.         dump(bottom, bottom+1);
  318. }
  319.         
  320. delete_entry(file)
  321. int file;
  322. {
  323.     struct entry *hold;
  324.     int    i;
  325.  
  326.     delete_from_display(file);
  327.  
  328.     hold = entries[file];
  329.     for(i=file; i<nentries-1; i++)
  330.         entries[i]=entries[i+1];
  331.     entries[nentries-1]=hold;
  332.     nentries--;
  333.  
  334.     if(file < curr || curr >= nentries) {
  335.         curr--;
  336.         if(top >= nentries) {
  337.             top--;
  338.             display_up = 0;
  339.             todump = 1;
  340.         }
  341.     }
  342.  
  343. ins_at(ent, i)
  344. struct entry *ent;
  345. int i;
  346. {
  347.     struct entry *hold;
  348.     int j;
  349.  
  350.     /* Allocate slot at end */
  351.     if(!entries[nentries]) {
  352.         entries[nentries] = NEW(struct entry);
  353.         if(!entries[nentries]) {
  354.             save_errno(ent->e_name);
  355.             return 0;
  356.         }
  357.         entries[nentries]->e_name = NIL(char *);
  358.     } else if(entries[nentries]->e_name) {
  359.         free(entries[nentries]->e_name);
  360.         entries[nentries]->e_name = NIL(char *);
  361.     }
  362.  
  363.     /* Copy data into slot */
  364.     *entries[nentries] = *ent;
  365.     entries[nentries]->e_name = clone(ent->e_name);
  366.     if(!entries[nentries]->e_name) {
  367.         save_errno(ent->e_name);
  368.         return 0;
  369.     }
  370.  
  371.     if(i != nentries) {
  372.         /* Rotate slot to middle */
  373.         hold = entries[nentries];
  374.         for(j = nentries; j > i; j--)
  375.             entries[j] = entries[j-1];
  376.         entries[i] = hold;
  377.     }
  378.     nentries++;
  379.  
  380.     if(display_up) {
  381.         if(i < top)
  382.             i = top;
  383.         if(i >= bottom)
  384.             return 1;
  385.         scroll(2+i-top, 2+nlines, -1);
  386.         at(0, 2+i-top);
  387.         dump(i, i+1);
  388.     }
  389.     return 1;
  390. }
  391.  
  392. ins_entry(ent)
  393. struct entry *ent;
  394. {
  395.     int i;
  396.  
  397.     if(nentries >= MAXENTS) {
  398.         save_errmsg("Too many files");
  399.         return 0;
  400.     }
  401.  
  402.     for(i = 0; i < nentries; i++)
  403.         if(entcmp(&ent, &entries[i]) < 0)
  404.             break;
  405.  
  406.     return ins_at(ent, i);
  407. }
  408.  
  409. domove(ent, new_name)
  410. int ent;
  411. char *new_name;
  412. {
  413.     struct entry hold;
  414.     hold = *entries[ent];
  415.  
  416.     if(link(entries[ent]->e_name, new_name)!=0) {
  417.         save_errno(entries[ent]->e_name);
  418.         return 0;
  419.     }
  420.     if(unlink(entries[ent]->e_name)!=0) {
  421.         save_errno(entries[ent]->e_name);
  422.         return 0;
  423.     }
  424.  
  425.     hold.e_name = new_name;
  426.     hold.e_flags &= ~FTAGGED;
  427.  
  428.     delete_entry(ent);
  429.     return ins_entry(&hold);
  430. }
  431.  
  432. addfile(name)
  433. char *name;
  434. {
  435.     struct entry hold;
  436.  
  437.     if(stat(name, &hold.e_stat)==-1) {
  438.         save_errno(name);
  439.         return FALSE;
  440.     }
  441.  
  442.     hold.e_name = name;
  443.  
  444.     hold.e_flags = 0;
  445.  
  446.     strcpy(hold.e_uname, u_name(hold.e_stat.st_uid));
  447.  
  448.     strcpy(hold.e_gname, g_name(hold.e_stat.st_gid));
  449.  
  450.     return ins_entry(&hold);
  451. }
  452.  
  453. pname(name, mode)
  454. char *name;
  455. int mode;
  456. {
  457.     int i;
  458.     char *slash, *rindex();
  459.     int max=quickmode?MAXLINE:(MAXNAME+1);
  460.  
  461.     if((mode&S_IFMT)==S_IFDIR)
  462.         max--;
  463.     else if((mode&S_IFMT)==S_IFREG && (mode&0111))
  464.         max--;
  465.     else if((mode&S_IFMT)!=S_IFREG)
  466.         max--;
  467.  
  468.     if(!quickmode && (slash=rindex(name, '/'))) {
  469.         name=slash;
  470.         outc('<');
  471.         max--;
  472.     }
  473.     for(i=0; i<max && *name; name++)
  474.         i += ctlout(*name);
  475.     standend();
  476.     if(i==max && *name) {
  477.         outc('\b');
  478.         outc('>');
  479.     }
  480.     if((mode&S_IFMT)==S_IFDIR) {
  481.         outc('/');
  482.     }
  483.     else if((mode&S_IFMT)==S_IFREG && (mode&0111)) {
  484.         outc('*');
  485.     }
  486.     else if((mode&S_IFMT)!=S_IFREG) {
  487.         outc('?');
  488.     }
  489. }
  490.  
  491. sortdir()
  492. {
  493.     int   entcmp();
  494.     qsort(entries, nentries, sizeof(struct entry *), entcmp);
  495. }
  496.  
  497. entcmp(e1, e2)
  498. struct entry **e1, **e2;
  499. {
  500.     if((*e1)->e_name[0] == '/') {
  501.         if((*e2)->e_name[0] != '/')
  502.             return 1;
  503.     } else if((*e2)->e_name[0] == '/')
  504.         return -1;
  505.  
  506.     return strcmp((*e1)->e_name, (*e2)->e_name);
  507. }
  508.  
  509. dump(start, end)
  510. int start;
  511. int end;
  512. {
  513.     int  i;
  514.     int  lo = (start<nentries)?start:nentries;
  515.     int  hi = (end<nentries)?end:nentries;
  516.  
  517.     for(i=lo; i<hi; i++) {
  518.         statout(entries[i]->e_name,
  519.         &entries[i]->e_stat,
  520.         entries[i]->e_uname,
  521.         entries[i]->e_gname,
  522.         entries[i]->e_flags);
  523.         nl();
  524.     }
  525.     return TRUE;
  526. }
  527.  
  528. statout(name, sbuf, user, group, flags)
  529. char *name;
  530. struct stat *sbuf;
  531. char *user, *group;
  532. int flags;
  533. {
  534.     int mode = sbuf->st_mode;
  535.  
  536.     if(!quickmode) {
  537.         printf("%5u ", sbuf->st_ino);
  538.  
  539.         if((mode&S_IFMT)==S_IFCHR) outc('c');
  540.         else if((mode&S_IFMT)==S_IFBLK) outc('b');
  541.         else if((mode&S_IFMT)==S_IFDIR) outc('d');
  542.         else if((mode&S_IFMT)==S_IFREG) outc('-');
  543.         else outc('?');
  544.         triad((mode>>6)&7, mode&S_ISUID, 's');
  545.         triad((mode>>3)&7, mode&S_ISGID, 's');
  546.         triad(mode&7, mode&S_ISVTX, 't');
  547.         outc(' ');
  548.  
  549.         printf("%3u ", sbuf->st_nlink);
  550.         printf("%-8s ", user);
  551.         printf("%-8s ", group);
  552.  
  553.         if((mode&S_IFMT)==S_IFREG || (mode&S_IFMT)==S_IFDIR)
  554.             printf("%7ld ", sbuf->st_size);
  555.         else
  556.             printf("%3d,%3d ",
  557.             major(sbuf->st_rdev),
  558.             minor(sbuf->st_rdev));
  559.  
  560.         outc(' ');
  561.         printime(&sbuf->st_mtime);
  562.     }
  563.  
  564.     disp_flags(flags);
  565.     pname(name, sbuf->st_mode);
  566. }
  567.  
  568. char *
  569. u_name(uid)
  570. int uid;
  571. {
  572.     int  i;
  573.     struct passwd *pwptr, *getpwuid();
  574.  
  575.     for(i=0; i<u_ptr; i++)
  576.         if(u_list[i].id_id==uid)
  577.             return u_list[i].id_name;
  578.  
  579.     if(u_ptr>=MAXID)                                       /* cache full */
  580.         u_ptr = 0;        /* simplistic algorithm, wrap to beginning */
  581.     /* with MAXID >> # common id's it's good enough */
  582.  
  583.     u_list[u_ptr].id_id=uid;
  584.  
  585.     if(pwptr=getpwuid(uid)) { /* Copy name */
  586.         for(i=0; pwptr->pw_name[i]>' '; i++)
  587.             u_list[u_ptr].id_name[i]=pwptr->pw_name[i];
  588.         u_list[u_ptr].id_name[i]=0;
  589.     } 
  590.     else /* Default to UID */
  591.         sprintf(u_list[u_ptr].id_name, "%d", uid);
  592.  
  593.     return u_list[u_ptr++].id_name;
  594. }
  595.  
  596. char *
  597. g_name(gid)
  598. int gid;
  599. {
  600.     int  i;
  601.     struct group *grptr, *getgrgid();
  602.  
  603.     for(i=0; i<g_ptr; i++)
  604.         if(g_list[i].id_id==gid)
  605.             return g_list[i].id_name;
  606.  
  607.     if(g_ptr>=MAXID)                                       /* cache full */
  608.         g_ptr = 0;        /* simplistic algorithm, wrap to beginning */
  609.     /* with MAXID >> # common id's it's good enough */
  610.  
  611.     g_list[g_ptr].id_id=gid;
  612.  
  613.     if(grptr=getgrgid(gid)) { /* Copy name */
  614.         for(i=0; grptr->gr_name[i]>' '; i++)
  615.             g_list[g_ptr].id_name[i]=grptr->gr_name[i];
  616.         g_list[g_ptr].id_name[i]=0;
  617.     } 
  618.     else /* Default to UID */
  619.         sprintf(g_list[g_ptr].id_name, "%d", gid);
  620.  
  621.     return g_list[g_ptr++].id_name;
  622. }
  623.  
  624. printime(clock)
  625. long *clock;
  626. {
  627.     struct tm *tmbuf, *localtime();
  628.     static char *months[12]= {
  629.         "Jan","Feb","Mar","Apr","May","Jun",
  630.         "Jul","Aug","Sep","Oct","Nov","Dec"
  631.     };
  632.  
  633.     tmbuf=localtime(clock);
  634.     printf("%2d %3s %02d %2d:%02d",
  635.     tmbuf->tm_mday,
  636.     months[tmbuf->tm_mon],
  637.     tmbuf->tm_year,
  638.     tmbuf->tm_hour,
  639.     tmbuf->tm_min);
  640. }
  641.  
  642. header()
  643. {
  644.     if(quickmode)
  645.         printf(" File Name");
  646.     else
  647.         printf(
  648. "Inode Long mode  LNX User     Group   Size/Dev  Modify Time     File name"
  649.             );
  650.     nl();
  651. }
  652.  
  653. triad(bits, special, code)
  654. int bits, special;
  655. char code;
  656. {
  657.     if(bits&4) outc('r');
  658.     else outc('-');
  659.  
  660.     if(bits&2) outc('w');
  661.     else outc('-');
  662.  
  663.     if(special) outc(code);
  664.     else if(bits&1) outc('x');
  665.     else outc('-');
  666. }
  667.  
  668. char *
  669. pwd()
  670. #ifdef GETCWD
  671. {
  672.     static char mydir[FILENAME+1] = "";
  673.     char *getcwd();
  674.  
  675.     return getcwd(mydir, FILENAME);
  676. }
  677. #else
  678. {
  679.     static char buffer[FILENAME+1];
  680.  
  681.     strcpy(buffer, "exec pwd");
  682.     if(tcl_call(buffer, sizeof buffer)) {
  683.         int len = strlen(buffer);
  684.         while(len > 0 && buffer[len-1] <= ' ')
  685.             len--;
  686.         buffer[len] = 0;
  687.         return buffer;
  688.     }
  689.     save_errmsg(buffer);
  690.     return 0;
  691. }
  692. #endif
  693.  
  694. browse()
  695. {
  696.     int  c;
  697.  
  698.     newdir();
  699.     redraw();
  700.     ended=0;
  701.  
  702.     do {
  703.         intrup=0;    /* clear interrupt */
  704.         here_i_am();
  705.         fflush(stdout);
  706.         c = getch();
  707.         cmd(c);
  708.     } 
  709.     while(!ended);
  710. }
  711.  
  712. clearin()
  713. {
  714.     fseek(stdin, 0L, 1); /* stay here messily */
  715. }
  716.  
  717. char *name_of(c)
  718. int c;
  719. {
  720.     static char *p, b[80];
  721.     int ctrl = 0;
  722.  
  723.     p = b;
  724.     if(c & 0x80) {
  725.         c &= 0x7F;
  726.         strcpy(b, "meta_");
  727.         p += 5;
  728.     }
  729.  
  730.     switch(c) {
  731.         case '\033':
  732.             strcpy(p, "escape");
  733.             return b;
  734.         case '\034':
  735.             strcpy(p, "ctrl_backslash");
  736.             return b;
  737.         case '\035':
  738.             strcpy(p, "ctrl_close_bracket");
  739.             return b;
  740.     }
  741.  
  742.     if(c < ' ') {
  743.         c += '@';
  744.         ctrl = 1;
  745.     }
  746.  
  747.     switch(c) {
  748.         case ' ': strcpy(p, "space"); break;
  749.         case '$': strcpy(p, "dollar_sign"); break;
  750.         case '\'': strcpy(p, "quote"); break;
  751.         case '"': strcpy(p, "double_quote"); break;
  752.         case ';': strcpy(p, "semicolon"); break;
  753.         case '{': strcpy(p, "open_brace"); break;
  754.         case '}': strcpy(p, "close_brace"); break;
  755.         case '\177': strcpy(p, "delete"); break;
  756.         case '\\': strcpy(p, "backslash"); break;
  757.         case '[': strcpy(p, "open_bracket"); break;
  758.         case ']': strcpy(p, "close_bracket"); break;
  759.         default: 
  760.             if(ctrl)
  761.                 sprintf(p, "'^%c'", c);
  762.             else
  763.                 sprintf(p, "'%c'", c);
  764.             break;
  765.     }
  766.     return b;
  767. }
  768.  
  769. cmd(c)
  770. int c;
  771. {
  772.     char buffer[80];
  773.  
  774.     if(intrup) {
  775.         cmdline();
  776.         outs("Interrupt");
  777.         return;
  778.     }
  779.  
  780.     sprintf(buffer, "key_%s\n", name_of(c));
  781.     if(!tcl_call(buffer, 80)) {
  782.         cmdline();
  783.         ctlouts(buffer);
  784.         if(!display_up) outc('\n');
  785.         bell();
  786.     }
  787. }
  788.  
  789. char *macro(c)
  790. int c;
  791. {
  792.     static char buffer[80];
  793.  
  794.     sprintf(buffer, "macro_%s\n", name_of(c));
  795.     if(tcl_call(buffer, 80))
  796.         return buffer;
  797.     else
  798.         return 0;
  799. }
  800.  
  801. newdir()
  802. {
  803.     int result = 1;
  804.  
  805.     if(display_up)
  806.         at(0,0);
  807.     fflush(stdout);
  808.     dot=pwd();
  809.  
  810.     if(!getdir())
  811.         result = 0;
  812.  
  813.     curr=0;
  814.     top=0;
  815.     topline();
  816.     if(display_up)
  817.         todump=TRUE;
  818.  
  819.     return result;
  820. }
  821.  
  822. reload()
  823. {
  824.     if(getdir()) {
  825.         curr=(curr>=bottom)?bottom-1:curr;
  826.         if(display_up) {
  827.             topline();
  828.             todump=TRUE;
  829.         }
  830.         return 1;
  831.     }
  832.     return 0;
  833. }
  834.  
  835. topline()
  836. {
  837.     if(display_up)
  838.         at(0,0);
  839.     printf("%s: %d files", dot, nentries);
  840.     nl();
  841. }
  842.  
  843. set_quickmode(mode)
  844. int mode;
  845. {
  846.     if(quickmode != mode) {
  847.         quickmode = mode;
  848.         if(display_up) {
  849.             at(0,1);
  850.             header();
  851.             todump = 1;
  852.         }
  853.     }
  854. }
  855.  
  856. redraw()
  857. {
  858.     clear_screen();
  859.     display_up=0;
  860.     topline();
  861.     at(0,1);
  862.     header();
  863.     todump=1;
  864.     display_up=1;
  865. }
  866.  
  867. dumpdata()
  868. {
  869.     at(0,2);
  870.     dump(top,bottom);
  871.     if(top+nlines>nentries) {
  872.         int i;
  873.         at(0, bottom-top+2);
  874.         for(i=bottom-top; i<nlines; i++) {
  875.             outc('~');
  876.             nl();
  877.         }
  878.     }
  879. }
  880.  
  881. here_i_am()
  882. {
  883.     if(todump)
  884.         display_up = 1;
  885.     if(!display_up) {
  886.         cmdline();
  887.         statout(entries[curr]->e_name,
  888.             &entries[curr]->e_stat,
  889.             entries[curr]->e_uname,
  890.             entries[curr]->e_gname,
  891.             entries[curr]->e_flags);
  892.         at(quickmode?1:ccol, nlines+2);
  893.         fflush(stdout);
  894.      } else if(todump) {
  895.          if(!(curr-top > 0 && curr-top < nlines)) {
  896.              top = curr-nlines/2;
  897.              if(top<0) top=0;
  898.          }
  899.          dumpdata();
  900.          at(quickmode?1:ccol, curr-top+2);
  901.          todump=0;
  902.      } else {
  903.          int lines_to_scroll = curr-top;
  904.          if(lines_to_scroll > 0)
  905.              if((lines_to_scroll -= nlines-1) < 0)
  906.                  lines_to_scroll = 0;
  907.          if(lines_to_scroll < 1-nlines) {
  908.              top=curr;
  909.              at(0,2);
  910.              dump(top, bottom);
  911.          } else if(lines_to_scroll > nlines-1) {
  912.              top=curr-nlines+1;
  913.              at(0,2);
  914.              dump(top, bottom);
  915.          } else if(lines_to_scroll) {
  916.              scroll(2, nlines+2, lines_to_scroll);
  917.              top += lines_to_scroll;
  918.              if(lines_to_scroll < 0) {
  919.                  at(0, 2);
  920.                  dump(top, top-lines_to_scroll);
  921.              } else {
  922.                  at(0, 2+nlines-lines_to_scroll);
  923.                  dump(bottom-lines_to_scroll, bottom);
  924.              }
  925.          }
  926.          at(quickmode?1:ccol, curr-top+2);
  927.      }
  928. }
  929.  
  930. bell()
  931. {
  932.     outc(7);
  933. }
  934.  
  935. system(command)
  936. char *command;
  937. {
  938.     int status;
  939.     int pid;
  940.     SIGNAL (*sigint)(), (*sigquit)();
  941. #ifdef BSD
  942.     SIGNAL  (*sigtstp)();
  943. #endif
  944.  
  945.     sigint=signal(SIGINT, SIG_IGN);
  946.     sigquit=signal(SIGQUIT, SIG_IGN);
  947. #ifdef BSD
  948.     sigtstp = signal(SIGTSTP, SIG_IGN);
  949. #endif
  950.     end_screenmode();
  951.     cooktty();
  952.     fflush(stdout);
  953.     pid = fork();
  954.     if(pid == 0) {
  955.         signal(SIGINT, SIG_DFL);
  956.         signal(SIGQUIT, SIG_DFL);
  957. #ifdef BSD
  958.         signal(SIGTSTP, SIG_DFL);
  959. #endif
  960.         fflush(stdout);
  961.         execl(SHELL, SHELL, "-c", command, (char *)0);
  962.         execl("/bin/sh", "sh", "-c", command, (char *)0);
  963.         perror("/bin/sh");
  964.         exit(-77);
  965.     }
  966.     if(pid==-1) {
  967.         save_errno("browse");
  968.         status = -1;
  969.     } else
  970.         wait(&status);
  971.     signal(SIGINT, sigint);
  972.     signal(SIGQUIT, sigquit);
  973. #ifdef BSD
  974.     signal(SIGTSTP, sigtstp);
  975. #endif
  976.     rawtty();
  977.  
  978.     if(status & 0xFF)
  979.         return -(status&0xFF);
  980.     else
  981.         return (status&0xFF00)>>8;
  982. }
  983.  
  984. addstring(ptr, buf, ip)
  985. char *ptr, *buf;
  986. int *ip;
  987. {
  988.     while(*ptr)
  989.         ctlout(buf[(*ip)++] = *ptr++);
  990.     standend();
  991. }
  992.  
  993. char
  994. inps(buf, text, termin)
  995. char *buf;
  996. char *text;
  997. char termin;
  998. {
  999.     int i = 0;
  1000.     char c, *txp;
  1001.     char *s;
  1002.  
  1003.     txp=text?text:"!";
  1004.  
  1005.     while(!intrup &&
  1006.         (fflush(stdout), c=getch()) != '\033' &&
  1007.         c != '\n' &&
  1008.         c != termin)
  1009.         switch(c) {
  1010.         case '\b': 
  1011.         case '\177':
  1012.             if(i>0) {
  1013.                 printf("\b \b");
  1014.                 i--;
  1015.             } 
  1016.             else
  1017.                 bell();
  1018.             break;
  1019.         case 'U'-'@':
  1020.             txp=text?text:"!";
  1021.         case 'X'-'@':
  1022.             if(i>0)
  1023.                 while(i>0) {
  1024.                     printf("\b \b");
  1025.                     i--;
  1026.                 }
  1027.             else
  1028.                 bell();
  1029.             break;
  1030.         case 'K'-'@':
  1031.             if(*txp)
  1032.                 ctloutc(buf[i++] = *txp++);
  1033.             break;
  1034.         case '\\':
  1035.             outc(c);
  1036.             fflush(stdout);
  1037.             c=getch();
  1038.             if( c=='\\' || c=='\b' || c=='\177' ||
  1039.                 c=='K'-'@' || c=='U'-'@' || c=='X'-'@' ||
  1040.                 c==termin || c=='\033' || c=='\n') {
  1041.                 outc('\b');
  1042.                 ctloutc(buf[i++]=c);
  1043.                 break;
  1044.             } 
  1045.             else if(c>='0' && c<='7') {
  1046.                 int n, val=0;
  1047.                 for(n=0; n<3 && c>='0' && c<='7'; n++) {
  1048.                     val = val*8 + c-'0';
  1049.                     outc('\b');
  1050.                     ctloutc(val);
  1051.                     c=getch();
  1052.                 }
  1053.                 ungetch(c);
  1054.                 c=buf[i++]=val;
  1055.                 break;
  1056.             } 
  1057.             else if(c=='^') {
  1058.                 outc('\b');
  1059.                 outc('^');
  1060.                 fflush(stdout);
  1061.                 c=getch();
  1062.                 if(c>='?'&&c<='_') {
  1063.                     outc('\b');
  1064.                     ctloutc(buf[i++]=(c-'@')&'\177');
  1065.                     break;
  1066.                 } 
  1067.                 else if(c>='`'&&c<='~') {
  1068.                     outc('\b');
  1069.                     ctloutc(buf[i++]=c-'`');
  1070.                     break;
  1071.                 } /* otherwise default */
  1072.                 else buf[i++]='^'; /* after adding caret */
  1073.             }
  1074.             else buf[i++]='\\';
  1075.         default:
  1076.             if(c=='V'-'@')
  1077.                 ctloutc(buf[i++] = getch());
  1078.             if(s = macro(c))
  1079.                 addstring(s, buf, &i);
  1080.             else
  1081.                 ctloutc(buf[i++] = c);
  1082.             break;
  1083.         }
  1084.  
  1085.     buf[i] = 0;
  1086.     return intrup?'\033':c;
  1087. }
  1088.  
  1089. ctlouts(s)
  1090. char *s;
  1091. {
  1092.     int cnt = 0;
  1093.  
  1094.     while(*s)
  1095.         cnt += ctlout(*s++);
  1096.     cnt += standend();
  1097.  
  1098.     return cnt;
  1099. }
  1100.  
  1101. ctloutc(c)
  1102. char c;
  1103. {
  1104.     int cnt;
  1105.  
  1106.     cnt = ctlout(c);
  1107.     cnt += standend();
  1108.  
  1109.     return cnt;
  1110. }
  1111.  
  1112. ctlout(c)
  1113. char c;
  1114. {
  1115.     int cnt = 0;
  1116.     if(c&'\200') {
  1117.         cnt += underline();
  1118.         cnt += ctlout(c&'\177');
  1119.         return cnt;
  1120.     } 
  1121.     else if(c<' ' || c=='\177') {
  1122.         cnt += standout();
  1123.         outc((c+'@')&'\177');
  1124.         cnt++;
  1125.         return cnt;
  1126.     } 
  1127.     else {
  1128.         cnt += standend();
  1129.         outc(c);
  1130.         cnt++;
  1131.         return cnt;
  1132.     }
  1133. }
  1134.  
  1135. get_index(file)
  1136. char *file;
  1137. {
  1138.     int i;
  1139.  
  1140.     for(i = 0; i<nentries; i++)
  1141.         if(strcmp(entries[i]->e_name, file) == 0)
  1142.             return i;
  1143.     return -1;
  1144. }
  1145.  
  1146. char *file_name(i)
  1147. int i;
  1148. {
  1149.     if(i < 0 || i >= nentries)
  1150.         return 0;
  1151.     else
  1152.         return entries[i]->e_name;
  1153. }
  1154.  
  1155. enter(dir)
  1156. char *dir;
  1157. {
  1158.     if(access(dir, 5)==0 && chdir(dir)==0)
  1159.         return newdir();
  1160.     save_errno(dir);
  1161.     return 0;
  1162. }
  1163.  
  1164. isdir(entry)
  1165. struct entry *entry;
  1166. {
  1167.     return((entry->e_stat.st_mode&S_IFMT)==S_IFDIR);
  1168. }
  1169.  
  1170. getch()
  1171. {
  1172.     return getchar();
  1173. }
  1174.  
  1175. ungetch(c)
  1176. char c;
  1177. {
  1178.     ungetc(c, stdin);
  1179. }
  1180.  
  1181.