home *** CD-ROM | disk | FTP | other *** search
/ ftp.uv.es / 2014.11.ftp.uv.es.tar / ftp.uv.es / pub / unix / pine4.10.tar.gz / pine4.10.tar / pine4.10 / pico / browse.c < prev    next >
C/C++ Source or Header  |  1998-09-15  |  52KB  |  2,274 lines

  1. #if    !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: browse.c,v 4.82 1998/09/16 00:18:45 hubert Exp $";
  3. #endif
  4. /*
  5.  * Program:    Routines to support file browser in pico and Pine composer
  6.  *
  7.  *
  8.  * Michael Seibel
  9.  * Networks and Distributed Computing
  10.  * Computing and Communications
  11.  * University of Washington
  12.  * Administration Builiding, AG-44
  13.  * Seattle, Washington, 98195, USA
  14.  * Internet: mikes@cac.washington.edu
  15.  *
  16.  * Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  17.  *
  18.  *
  19.  * Pine and Pico are registered trademarks of the University of Washington.
  20.  * No commercial use of these trademarks may be made without prior written
  21.  * permission of the University of Washington.
  22.  * 
  23.  * Pine, Pico, and Pilot software and its included text are Copyright
  24.  * 1989-1998 by the University of Washington.
  25.  * 
  26.  * The full text of our legal notices is contained in the file called
  27.  * CPYRIGHT, included with this distribution.
  28.  *
  29.  *
  30.  * NOTES:
  31.  *
  32.  *   Misc. thoughts (mss, 5 Apr 92)
  33.  * 
  34.  *      This is supposed to be just a general purpose browser, equally
  35.  *    callable from either pico or the pine composer.  Someday, it could
  36.  *     even be used to "wrap" the unix file business for really novice 
  37.  *      users.  The stubs are here for renaming, copying, creating directories,
  38.  *      deleting, undeleting (thought is delete just moves files to 
  39.  *      ~/.pico.deleted directory or something and undelete offers the 
  40.  *      files in there for undeletion: kind of like the mac trashcan).
  41.  *
  42.  *   Nice side effects
  43.  *
  44.  *      Since the full path name is always maintained and referencing ".." 
  45.  *      stats the path stripped of its trailing name, the unpleasantness of 
  46.  *      symbolic links is hidden.  
  47.  *
  48.  *   Fleshed out the file managements stuff (mss, 24 June 92)
  49.  *
  50.  *
  51.  */
  52. #include "headers.h"
  53.  
  54. #ifndef    _WINDOWS
  55.  
  56. #if    defined(bsd) || defined(lnx)
  57. extern int errno;
  58. #endif
  59.  
  60.  
  61. /*
  62.  * directory cell structure
  63.  */
  64. struct fcell {
  65.     char *fname;                /* file name            */
  66.     unsigned mode;                /* file's mode           */
  67.     char size[16];                /* file's size in s    */
  68.     struct fcell *next;
  69.     struct fcell *prev;
  70. };
  71.  
  72.  
  73. /*
  74.  * master browser structure
  75.  */
  76. static struct bmaster {
  77.     struct fcell *head;                /* first cell in list  */
  78.     struct fcell *top;                /* cell in top left    */
  79.     struct fcell *current;            /* currently selected  */
  80.     int    longest;                /* longest file name   */
  81.     int       fpl;                    /* file names per line */
  82.     int    cpf;                    /* chars / file / line */
  83.     char   dname[NLINE];            /* this dir's name     */
  84.     char   *names;                /* malloc'd name array */
  85. } *gmp;                        /* global master ptr   */
  86.  
  87.  
  88. /*
  89.  * title for exported browser display
  90.  */
  91. static    char    *browser_title = NULL;
  92.  
  93.  
  94. #ifdef    ANSI
  95.     struct bmaster *getfcells(char *);
  96.     int    PaintCell(int, int, int, struct fcell *, int);
  97.     int    PaintBrowser(struct bmaster *, int, int *, int *);
  98.     int    BrowserKeys(void);
  99.     int    layoutcells(struct bmaster *);
  100.     int    percdircells(struct bmaster *);
  101.     int    PlaceCell(struct bmaster *, struct fcell *, int *, int *);
  102.     int    zotfcells(struct fcell *);
  103.     int    zotmaster(struct bmaster **);
  104.     struct fcell *FindCell(struct bmaster *, char *);
  105.     int    sisin(char *, char *);
  106.     int    BrowserAnchor(char *);
  107.     void   ClearBrowserScreen(void);
  108.     void   BrowserRunChild(char *, char *);
  109.     int    LikelyASCII(char *);
  110. #else
  111.     struct bmaster *getfcells();
  112.     int    PaintCell();
  113.     int    PaintBrowser();
  114.     int    BrowserKeys();
  115.     int    percdircells();
  116.     int    PlaceCell();
  117.     int    zotfcells();
  118.     int    zotmaster();
  119.     struct fcell *FindCell();
  120.     int    sisin();
  121.     int    BrowserAnchor();
  122.     void   ClearBrowserScreen();
  123.     void   BrowserRunChild();
  124.     int    LikelyASCII();
  125. #endif
  126.  
  127.  
  128. static    KEYMENU menu_browse[] = {
  129.     {"?", "Get Help", KS_SCREENHELP},    {NULL, NULL, KS_NONE},
  130.     {NULL, NULL, KS_NONE},        {"-", "Prev Pg", KS_PREVPAGE},
  131.     {"D", "Delete", KS_NONE},        {"C","Copy", KS_NONE},
  132.     {NULL, NULL, KS_NONE},        {NULL, NULL, KS_NONE},
  133.     {"W", "Where is", KS_NONE},        {"Spc", "Next Pg", KS_NEXTPAGE},
  134.     {"R", "Rename", KS_NONE},        {NULL, NULL, KS_NONE}
  135. };
  136. #define    QUIT_KEY    1
  137. #define    EXEC_KEY    2
  138. #define    GOTO_KEY    6
  139. #define    SELECT_KEY    7
  140. #define    PICO_KEY    11
  141.  
  142.  
  143. /*
  144.  * Default pager used by the stand-alone file browser.
  145.  */
  146. #define    BROWSER_PAGER    ((gmode & MDFKEY) ? "pine -k -F" : "pine -F")
  147.  
  148.  
  149. /*
  150.  * function key mappings for callable browser
  151.  */
  152. static int  bfmappings[2][12][2] = { { { F1,  '?'},    /* stand alone */
  153.                        { F2,  NODATA },    /* browser function */
  154.                        { F3,  'q'},    /* key mappings... */
  155.                        { F4,  'v'},
  156.                        { F5,  'l'},
  157.                        { F6,  'w'},
  158.                        { F7,  '-'},
  159.                        { F8,  ' '},
  160.                        { F9,  'd'},
  161.                        { F10, 'r'},
  162.                        { F11, 'c'},
  163.                        { F12, 'e'} },
  164.                      { { F1,  '?'},    /* callable browser */
  165.                        { F2,  NODATA },    /* function key */
  166.                        { F3,  'e'},    /* mappings... */
  167.                        { F4,  's'},
  168.                        { F5,  NODATA },
  169.                        { F6,  'w'},
  170.                        { F7,  '-'},
  171.                        { F8,  ' '},
  172.                        { F9,  'd'},
  173.                        { F10, 'r'},
  174.                        { F11, 'c'},
  175.                        { F12, 'a'} } };
  176.  
  177.  
  178. /*
  179.  * Browser help for pico (pine composer help handed to us by pine)
  180.  */
  181. static char *BrowseHelpText[] = {
  182. "Help for Browse Command",
  183. "  ",
  184. "\tPico's file browser is used to select a file from the",
  185. "\tfile system for inclusion in the edited text.",
  186. "  ",
  187. "~\tBoth directories and files are displayed.  Press ~S",
  188. "~\tor ~R~e~t~u~r~n to select a file or directory.  When a file",
  189. "\tis selected during the \"Read File\" command, it is",
  190. "\tinserted into edited text.  Answering \"yes\" to the",
  191. "\tverification question after a directory is selected causes",
  192. "\tthe contents of that directory to be displayed for selection.",
  193. "  ",
  194. "\tThe file named \"..\" is special, and means the \"parent\"",
  195. "\tof the directory being displayed.  Select this directory",
  196. "\tto move upward in the directory tree.",
  197. "  ",
  198. "End of Browser Help.",
  199. "  ",
  200. NULL
  201. };
  202.  
  203. /*
  204.  * Help for standalone browser (pilot)
  205.  */
  206. static char *sa_BrowseHelpText[] = {
  207. "Help for Pilot (PIne's Looker-upper Of Things",
  208. " ",
  209. "\tPilot is a simple, display-oriented file system browser based on the",
  210. "~\tPine message system composer.  As with Pine, commands are displayed at",
  211. "~\tthe bottom of the screen, and context-sensitive help is provided.",
  212. " ",
  213. "~\tPilot displays the current working directory at the top of the screen.",
  214. "~\tThe directory's contents are displayed in columns of file name, file",
  215. "~\tsize pairs.  Names that are directories are indicated by the name",
  216. "~\t~(~d~i~r~) in place of the file size.  The parent of the current working",
  217. "~\tdirectory is indicated by the file name ~.~. and size of ~(~p~a~r~e~n~t~ ~d~i~r~).",
  218. "~\tFile names that are symbolic links to other files are displayed with a",
  219. "~\tfile size of ~-~-.",
  220. " ",
  221. "\tThe following function keys are available in Pilot:",
  222. " ",
  223. "~\t~?\tDisplay this help text.",
  224. "~\t~Q\tQuit Pilot.",
  225. " ",
  226. "~\t~V\tView the currently selected file or open the selected directory.",
  227. "~\t\tNote: Pilot invokes ~p~i~n~e ~-~F, or the program defined by the ~P~A~G~E~R",
  228. "~\t\t      environment variable, to view the file.",
  229. "~\t~L\tLaunch an external application program.",
  230. " ",
  231. "~\t~W\tSearch for a file by name.",
  232. "~\t~-\tScroll up one page.",
  233. "~\t~S~p~a~c~e\tScroll down one page.",
  234. "~\t~N,~^~F\tMove forward (right) one column.",
  235. "~\t~P,~^~B\tMove back (left) one column.",
  236. "~\t~^~N\tMove down one row.",
  237. "~\t~^~P\tMove up one row.",
  238. " ",
  239. "~\t~D\tDelete the selected file.",
  240. "~\t~R\tRename the selected file or directory.",
  241. "~\t~C\tCopy the selected file.",
  242. "~\t~E\tEdit the selected file.",
  243. "~\t\tNote: Pilot invokes ~p~i~c~o, or the program defined by the ~E~D~I~T~O~R",
  244. "~\t\t      environment variable, to edit the file.",
  245. " ",
  246. " ",
  247. "\tPine and Pico are trademarks of the University of Washington.",
  248. "\tNo commercial use of these trademarks may be made without prior",
  249. "\twritten permission of the University of Washington.",
  250. " ",
  251. "End of Pilot Help.",
  252. NULL
  253. };
  254.  
  255.  
  256.  
  257. /*
  258.  * pico_file_browse - Exported version of FileBrowse below.
  259.  */
  260. pico_file_browse(pdata, dir, dirlen, fn, fnlen, sz, flags)
  261.     PICO *pdata;
  262.     char *dir, *fn, *sz;
  263.     int   dirlen, fnlen, flags;
  264. {
  265.     int  rv;
  266.     char title_buf[64];
  267.  
  268.     Pmaster = pdata;
  269.     gmode = pdata->pine_flags | MDEXTFB;
  270.     km_popped = 0;
  271.  
  272.     /* only init screen bufs for display and winch handler */
  273.     if(!vtinit())
  274.       return(-1);
  275.  
  276.     if(Pmaster){
  277.     term.t_mrow = Pmaster->menu_rows;
  278.     if(Pmaster->oper_dir)
  279.       strncpy(opertree, Pmaster->oper_dir, NLINE);
  280.     
  281.     if(*opertree)
  282.       fixpath(opertree, NLINE);
  283.     }
  284.  
  285.     /* install any necessary winch signal handler */
  286.     ttresize();
  287.  
  288.     sprintf(title_buf, "%s FILE", pdata->pine_anchor);
  289.     set_browser_title(title_buf);
  290.     rv = FileBrowse(dir, dirlen, fn, fnlen, sz, flags);
  291.     set_browser_title(NULL);
  292.     vttidy();            /* clean up tty handling */
  293.     zotdisplay();        /* and display structures */
  294.     Pmaster = NULL;        /* and global config structure */
  295.     return(rv);
  296. }
  297.  
  298.  
  299.  
  300. /*
  301.  * FileBrowse - display contents of given directory dir
  302.  *
  303.  *        intput:  
  304.  *             dir points to initial dir to browse.
  305.  *                   dirlen- buffer size of dir
  306.  *             fn  initial file name.
  307.  *                   fnlen- buffer size of fn 
  308.  *
  309.  *         returns:
  310.  *                   dir points to currently selected directory (without
  311.  *            trailing file system delimiter)
  312.  *                   fn  points to currently selected file
  313.  *                   sz  points to size of file if ptr passed was non-NULL
  314.  *             flags
  315.  *
  316.  *                   1 if a file's been selected
  317.  *                   0 if no files seleted
  318.  *                  -1 if there where problems
  319.  */
  320. FileBrowse(dir, dirlen, fn, fnlen, sz, flags)
  321. char *dir, *fn, *sz;            /* dir, name and optional size */
  322. int   dirlen, fnlen, flags;
  323. {
  324.     int status, i, j, c, new_c;
  325.     int row, col, crow, ccol;
  326.     char *p, *envp, child[NLINE], tmp[NLINE];
  327.     struct bmaster *mp;
  328.     struct fcell *tp;
  329. #ifdef MOUSE
  330.     MOUSEPRESS mousep;
  331. #endif
  332.  
  333.     child[0] = '\0';
  334.  
  335.     if((gmode&MDTREE) && !in_oper_tree(dir)){
  336.     emlwrite("\007Can't read outside of %s in restricted mode", opertree);
  337.     sleep(2);
  338.     return(0);
  339.     }
  340.  
  341.     if(gmode&MDGOTO){
  342.     /* fix up function key mapping table */
  343.     /* fix up key menu labels */
  344.     }
  345.  
  346.     /* build contents of cell structures */
  347.     if((gmp = getfcells(dir)) == NULL)
  348.       return(-1);
  349.     
  350.     tp = NULL;
  351.     if(fn && *fn){
  352.     if((tp = FindCell(gmp, fn)) != NULL){
  353.         gmp->current = tp;
  354.         PlaceCell(gmp, gmp->current, &row, &col);
  355.     }
  356.     }
  357.  
  358.     /* paint screen */
  359.     PaintBrowser(gmp, 0, &crow, &ccol);
  360.  
  361.     while(1){                        /* the big loop */
  362.     if(!(gmode&MDSHOCUR)){
  363.         crow = term.t_nrow-term.t_mrow;
  364.         ccol = 0;
  365.     }
  366.  
  367.     movecursor(crow, ccol);
  368.  
  369.     if(km_popped){
  370.         km_popped--;
  371.         if(km_popped == 0)
  372.           /* cause bottom three lines to repaint */
  373.           PaintBrowser(gmp, 0, &crow, &ccol);
  374.     }
  375.  
  376.     if(km_popped){  /* temporarily change to cause menu to paint */
  377.         term.t_mrow = 2;
  378.         movecursor(term.t_nrow-2, 0);  /* clear status line */
  379.         peeol();
  380.         BrowserKeys();
  381.         term.t_mrow = 0;
  382.     }
  383.  
  384.     (*term.t_flush)();
  385.  
  386. #ifdef MOUSE
  387.     mouse_in_content(KEY_MOUSE, -1, -1, 0, 0);
  388.     register_mfunc(mouse_in_content,2,0,term.t_nrow-(term.t_mrow+1),
  389.         term.t_ncol);
  390. #endif
  391.     c = GetKey();
  392. #ifdef    MOUSE
  393.     clear_mfunc(mouse_in_content);
  394. #endif
  395.  
  396.     if(Pmaster){
  397.         if(Pmaster->newmail && (c == NODATA || time_to_check())){
  398.         if((*Pmaster->newmail)(c == NODATA ? 0 : 2, 1) >= 0){
  399.             int rv;
  400.             
  401.             if(km_popped){        /* restore display */
  402.             km_popped = 0;
  403.             PaintBrowser(gmp, 0, &crow, &ccol);
  404.             }
  405.  
  406.             clearcursor();
  407.             mlerase();
  408.             rv = (*Pmaster->showmsg)(c);
  409.             ttresize();
  410.             picosigs();
  411.             if(rv)    /* Did showmsg corrupt the display? */
  412.               PaintBrowser(gmp, 0, &crow, &ccol); /* Yes, repaint */
  413.  
  414.             mpresf = 1;
  415.         }
  416.  
  417.         clearcursor();
  418.         movecursor(crow, ccol);
  419.         }
  420.     }
  421.     else{
  422.         if(timeo && (c == NODATA || time_to_check()))
  423.           if(pico_new_mail())
  424.         emlwrite("You may possibly have new mail.", NULL);
  425.     }
  426.  
  427.     if(km_popped)
  428.       switch(c){
  429.         case NODATA:
  430.         case (CTRL|'L'):
  431.           km_popped++;
  432.           break;
  433.         
  434.         default:
  435.           /* clear bottom three lines */
  436.           movecursor(term.t_nrow-2, 0);
  437.           peeol();
  438.           movecursor(term.t_nrow-1, 0);
  439.           peeol();
  440.           movecursor(term.t_nrow, 0);
  441.           peeol();
  442.           break;
  443.       }
  444.  
  445.     if(c == NODATA)                /* GetKey timed out */
  446.       continue;
  447.     else if(Pmaster)
  448.       (*Pmaster->keybinput)();
  449.       
  450.  
  451.     if(mpresf){                /* blast old messages */
  452.         if(mpresf++ > MESSDELAY){        /* every few keystrokes */
  453.         mlerase();
  454.         }
  455.         }
  456.  
  457.                         /* process commands */
  458.     switch(new_c = normalize_cmd(c,bfmappings[(gmode&MDBRONLY)?0:1],2)){
  459.  
  460.       case KEY_RIGHT:            /* move right */
  461.       case (CTRL|'@'):
  462.       case (CTRL|'F'):            /* forward  */
  463.       case 'n' :
  464.       case 'N' :
  465.         if(gmp->current->next == NULL){
  466.         (*term.t_beep)();
  467.         break;
  468.         }
  469.  
  470.         PlaceCell(gmp, gmp->current, &row, &col);
  471.         PaintCell(row, col, gmp->cpf, gmp->current, 0);
  472.         gmp->current = gmp->current->next;
  473.         if(PlaceCell(gmp, gmp->current, &row, &col)){
  474.         PaintBrowser(gmp, 1, &crow, &ccol);
  475.         }
  476.         else{
  477.         PaintCell(row, col, gmp->cpf, gmp->current, 1);
  478.         crow = row;
  479.         ccol = col;
  480.         }
  481.         break;
  482.  
  483.       case KEY_LEFT:                /* move left */
  484.       case (CTRL|'B'):                /* back */
  485.       case 'p' :
  486.       case 'P' :
  487.         if(gmp->current->prev == NULL){
  488.         (*term.t_beep)();
  489.         break;
  490.         }
  491.  
  492.         PlaceCell(gmp, gmp->current, &row, &col);
  493.         PaintCell(row, col, gmp->cpf, gmp->current, 0);
  494.         gmp->current = gmp->current->prev;
  495.         if(PlaceCell(gmp, gmp->current, &row, &col)){
  496.         PaintBrowser(gmp, 1, &crow, &ccol);
  497.         }
  498.         else{
  499.         PaintCell(row, col, gmp->cpf, gmp->current, 1);
  500.         crow = row;
  501.         ccol = col;
  502.         }
  503.         break;
  504.  
  505.       case (CTRL|'A'):                /* beginning of line */
  506.         tp = gmp->current;
  507.         i = col;
  508.         while(i > 0){
  509.         i -= gmp->cpf;
  510.         if(tp->prev != NULL)
  511.           tp = tp->prev;
  512.         }
  513.         PlaceCell(gmp, gmp->current, &row, &col);
  514.         PaintCell(row, col, gmp->cpf, gmp->current, 0);
  515.         gmp->current = tp;
  516.         if(PlaceCell(gmp, tp, &row, &col)){
  517.         PaintBrowser(gmp, 1, &crow, &ccol);
  518.         }
  519.         else{
  520.         PaintCell(row, col, gmp->cpf, gmp->current, 1);
  521.         crow = row;
  522.         ccol = col;
  523.         }
  524.         break;
  525.  
  526.       case (CTRL|'E'):                /* end of line */
  527.         tp = gmp->current;
  528.         i = col + gmp->cpf;
  529.         while(i+gmp->cpf <= gmp->cpf * gmp->fpl){
  530.         i += gmp->cpf;
  531.         if(tp->next != NULL)
  532.           tp = tp->next;
  533.         }
  534.  
  535.         PlaceCell(gmp, gmp->current, &row, &col);
  536.         PaintCell(row, col, gmp->cpf, gmp->current, 0);
  537.         gmp->current = tp;
  538.         if(PlaceCell(gmp, tp, &row, &col)){
  539.         PaintBrowser(gmp, 1, &crow, &ccol);
  540.         }
  541.         else{
  542.         PaintCell(row, col, gmp->cpf, gmp->current, 1);
  543.         crow = row;
  544.         ccol = col;
  545.         }
  546.         break;
  547.  
  548.       case (CTRL|'V'):                /* page forward */
  549.       case ' ':
  550.       case KEY_PGDN :
  551.       case KEY_END :
  552.         tp = gmp->top;
  553.         i = term.t_nrow - term.t_mrow - 2;
  554.  
  555.         while(i-- && tp->next != NULL){
  556.         j = 0;
  557.         while(++j <= gmp->fpl  && tp->next != NULL)
  558.           tp = tp->next;
  559.         }
  560.  
  561.         if(tp == NULL)
  562.           continue;
  563.  
  564.         PlaceCell(gmp, gmp->current, &row, &col);
  565.         PaintCell(row, col, gmp->cpf, gmp->current, 0);
  566.         gmp->current = tp;
  567.         if(PlaceCell(gmp, tp, &row, &col)){
  568.         PaintBrowser(gmp, 1, &crow, &ccol);
  569.         }
  570.         else{
  571.         PaintCell(row, col, gmp->cpf, gmp->current, 1);
  572.         crow = row;
  573.         ccol = col;
  574.         }
  575.         break;
  576.  
  577.       case '-' :
  578.       case (CTRL|'Y'):                /* page backward */
  579.       case KEY_PGUP :
  580.       case KEY_HOME :
  581.         tp = gmp->top;
  582.         i = term.t_nrow - term.t_mrow - 4;
  583.         while(i-- && tp != NULL){
  584.         j = gmp->fpl;
  585.         while(j-- && tp != NULL)
  586.           tp = tp->prev;
  587.         }
  588.  
  589.         if(tp || (gmp->current != gmp->top)){    /* clear old hilite */
  590.         PlaceCell(gmp, gmp->current, &row, &col);
  591.         PaintCell(row, col, gmp->cpf, gmp->current, 0);
  592.         }
  593.  
  594.         if(tp)                    /* new page ! */
  595.         gmp->current = tp;
  596.         else if(gmp->current != gmp->top)        /* goto top of page */
  597.         gmp->current = gmp->top;
  598.         else                    /* do nothing */
  599.           continue;
  600.  
  601.         if(PlaceCell(gmp, gmp->current, &row, &col)){
  602.         PaintBrowser(gmp, 1, &crow, &ccol);
  603.         }
  604.         else{
  605.         PaintCell(row, col, gmp->cpf, gmp->current, 1);
  606.         crow = row;
  607.         ccol = col;
  608.         }
  609.  
  610.         break;
  611.  
  612.       case KEY_DOWN :
  613.       case (CTRL|'N'):                /* next */
  614.         tp = gmp->current;
  615.         i = gmp->fpl;
  616.         while(i--){
  617.         if(tp->next == NULL){
  618.             (*term.t_beep)();
  619.             break;
  620.         }
  621.         else
  622.           tp = tp->next;
  623.         }
  624.         if(i != -1)                    /* can't go down */
  625.           break;
  626.  
  627.         PlaceCell(gmp, gmp->current, &row, &col);
  628.         PaintCell(row, col, gmp->cpf, gmp->current, 0);
  629.         gmp->current = tp;
  630.         if(PlaceCell(gmp, tp, &row, &col)){
  631.         PaintBrowser(gmp, 1, &crow, &ccol);
  632.         }
  633.         else{
  634.         PaintCell(row, col, gmp->cpf, gmp->current, 1);
  635.         crow = row;
  636.         ccol = col;
  637.         }
  638.         break;
  639.  
  640.       case KEY_UP :
  641.       case (CTRL|'P'):                /* previous */
  642.         tp = gmp->current;
  643.         i = gmp->fpl;
  644.         while(i-- && tp)
  645.           tp = tp->prev;
  646.  
  647.         if(tp == NULL)
  648.           break;
  649.  
  650.         PlaceCell(gmp, gmp->current, &row, &col);
  651.         PaintCell(row, col, gmp->cpf, gmp->current, 0);
  652.         gmp->current = tp;
  653.         if(PlaceCell(gmp, tp, &row, &col)){
  654.         PaintBrowser(gmp, 1, &crow, &ccol);
  655.         }
  656.         else{
  657.         PaintCell(row, col, gmp->cpf, gmp->current, 1);
  658.         crow = row;
  659.         ccol = col;
  660.         }
  661.         break;
  662.  
  663. #ifdef MOUSE        
  664.       case KEY_MOUSE:
  665.         mouse_get_last (NULL, &mousep);
  666.         if (mousep.doubleclick) {
  667.         goto Selected;
  668.         }
  669.         else {
  670.         row = mousep.row -= 2;        /* Adjust for header*/
  671.         col = mousep.col;
  672.         i = row * gmp->fpl + (col / gmp->cpf);    /* Count from top */
  673.         tp = gmp->top;                /* start at top. */
  674.         for (; i > 0 && tp != NULL; --i)    /* Count cells. */
  675.           tp = tp->next;
  676.         if (tp != NULL) {            /* Valid cell? */
  677.             PlaceCell(gmp, gmp->current, &row, &col);
  678.             PaintCell(row, col, gmp->cpf, gmp->current, 0);
  679.             gmp->current = tp;
  680.             if(PlaceCell(gmp, tp, &row, &col)){
  681.             PaintBrowser(gmp, 1, &crow, &ccol);
  682.             }
  683.             else{
  684.             PaintCell(row, col, gmp->cpf, gmp->current, 1);
  685.             crow = row;
  686.             ccol = col;
  687.             }
  688.         }
  689.             }
  690.         break;
  691. #endif
  692.  
  693.       case 'e':                    /* exit or edit */
  694.       case 'E':
  695.         if(gmode&MDBRONLY){                /* run "pico" */
  696.         sprintf(child, "%s%c%s", gmp->dname, C_FILESEP,
  697.             gmp->current->fname);
  698.         /* make sure selected isn't a directory or executable */
  699.         if(!LikelyASCII(child)){
  700.             emlwrite("Can't edit non-text file.  Try Launch.", NULL);
  701.             break;
  702.         }
  703.  
  704.         if(envp = (char *) getenv("EDITOR"))
  705.           sprintf(tmp, "%s \'%s\'", envp, child);
  706.         else
  707.           sprintf(tmp, "pico%s%s%s \'%s\'",
  708.               (gmode & MDFKEY) ? " -f" : "",
  709.               (gmode & MDSHOCUR) ? " -g" : "",
  710.               (gmode & MDMOUSE) ? " -m" : "",
  711.               child);
  712.  
  713.         BrowserRunChild(tmp, gmp->dname);    /* spawn pico */
  714.         PaintBrowser(gmp, 0, &crow, &ccol);    /* redraw browser */
  715.         }
  716.         else{
  717.         zotmaster(&gmp);
  718.         return(0);
  719.         }
  720.  
  721.         break;
  722.  
  723.       case 'q':                        /* user exits wrong */
  724.       case 'Q':
  725.         if(gmode&MDBRONLY){
  726.         zotmaster(&gmp);
  727.         return(0);
  728.         }
  729.  
  730.         emlwrite("\007Unknown command '%c'", (void *)c);
  731.         break;
  732.  
  733.       case 'l':                        /* run Command */
  734.       case 'L':
  735.         if(!(gmode&MDBRONLY)){
  736.         emlwrite("\007Unknown command '%c'", (void *)c);
  737.         break;
  738.         }
  739.  
  740. /* add subcommands to invoke pico and insert selected filename */
  741. /* perhaps: add subcmd to scroll command history */
  742.  
  743.         tmp[0] = '\0';
  744.         i = 0;
  745.         sprintf(child, "%s%c%s", gmp->dname, C_FILESEP,
  746.             gmp->current->fname);
  747.         while(!i){
  748.         static EXTRAKEYS opts[] = {
  749.             {"^X", "Add Name", CTRL|'X', KS_NONE},
  750.             {NULL, NULL, 0, KS_NONE},
  751.         };
  752.  
  753.         status = mlreply("Command to execute: ",
  754.                  tmp, NLINE, QNORML, opts);
  755.         switch(status){
  756.           case HELPCH:
  757.             emlwrite("\007No help yet!", NULL);
  758. /* remove break and sleep after help text is installed */
  759.             sleep(3);
  760.             break;
  761.           case (CTRL|'X'):
  762.             strcat(tmp, child);
  763.             break;
  764.           case (CTRL|'L'):
  765.             PaintBrowser(gmp, 0, &crow, &ccol);
  766.             break;
  767.           case ABORT:
  768.             emlwrite("Command cancelled", NULL);
  769.             i++;
  770.             break;
  771.           case FALSE:
  772.           case TRUE:
  773.             i++;
  774.  
  775.             if(tmp[0] == '\0'){
  776.             emlwrite("No command specified", NULL);
  777.             break;
  778.             }
  779.  
  780.             BrowserRunChild(tmp, gmp->dname);
  781.             PaintBrowser(gmp, 0, &crow, &ccol);
  782.             break;
  783.           default:
  784.             break;
  785.         }
  786.         }
  787.  
  788.         BrowserKeys();
  789.         break;
  790.  
  791.       case 'd':                    /* delete */
  792.       case 'D':
  793.         if(gmp->current->mode == FIODIR){
  794. /* BUG: if dir is empty it should be deleted */
  795.         emlwrite("\007Can't delete a directory", NULL);
  796.         break;
  797.         }
  798.  
  799.         if(gmode&MDSCUR){                /* not allowed! */
  800.         emlwrite("Delete not allowed in restricted mode",NULL);
  801.         break;
  802.         }
  803.  
  804.         sprintf(child, "%s%c%s", gmp->dname, C_FILESEP, 
  805.             gmp->current->fname);
  806.  
  807.         i = 0;
  808.         while(i++ < 2){        /* verify twice!! */
  809.         if(i == 1){
  810.             if(fexist(child, "w", (off_t *)NULL) != FIOSUC)
  811.               strcpy(tmp, "File is write protected! OVERRIDE");
  812.             else
  813.               sprintf(tmp, "Delete file \"%.*s\"", NLINE - 20, child);
  814.         }
  815.         else
  816.           strcpy(tmp, "File CANNOT be UNdeleted!  Really delete");
  817.  
  818.         if((status = mlyesno(tmp, FALSE)) != TRUE){
  819.             emlwrite((status ==  ABORT)
  820.                    ? "Delete Cancelled"
  821.                    : "File Not Deleted",
  822.                  NULL);
  823.             break;
  824.         }
  825.         }
  826.  
  827.         if(status == TRUE){
  828.         if(unlink(child) < 0){
  829.             emlwrite("Delete Failed: %s", errstr(errno));
  830.         }
  831.         else{            /* fix up pointers and redraw */
  832.             tp = gmp->current;
  833.             if(tp->next){
  834.             gmp->current = tp->next;
  835.             if(tp->next->prev = tp->prev)
  836.               tp->prev->next = tp->next;
  837.             }
  838.             else if(tp->prev) {
  839.             gmp->current = tp->prev;
  840.             if(tp->prev->next = tp->next)
  841.               tp->next->prev = tp->prev;
  842.             }
  843.  
  844.             if(tp == gmp->head)
  845.               gmp->head = tp->next;
  846.  
  847.             tp->fname = NULL;
  848.             tp->next = tp->prev = NULL;
  849.             if(tp != gmp->current)
  850.               free((char *) tp);
  851.  
  852.             if((tp = FindCell(gmp, gmp->current->fname)) != NULL){
  853.             gmp->current = tp;
  854.             PlaceCell(gmp, gmp->current, &row, &col);
  855.             }
  856.                 
  857.             PaintBrowser(gmp, 1, &crow, &ccol);
  858.             mlerase();
  859.         }
  860.         }
  861.  
  862.         BrowserKeys();
  863.         break;
  864.  
  865.       case '?':                    /* HELP! */
  866.       case (CTRL|'G'):
  867.         if(term.t_mrow == 0){
  868.         if(km_popped == 0){
  869.             km_popped = 2;
  870.             break;
  871.         }
  872.         }
  873.  
  874.         if(Pmaster){
  875.         VARS_TO_SAVE *saved_state;
  876.  
  877.         saved_state = save_pico_state();
  878.         (*Pmaster->helper)(Pmaster->browse_help,
  879.                    "Help for Browsing", 1);
  880.         if(saved_state){
  881.             restore_pico_state(saved_state);
  882.             free_pico_state(saved_state);
  883.         }
  884.         }
  885.         else if(gmode&MDBRONLY)
  886.           pico_help(sa_BrowseHelpText, "Browser Help", 1);
  887.         else
  888.           pico_help(BrowseHelpText, "Help for Browsing", 1);
  889.         /* fall thru to repaint everything */
  890.  
  891.       case (CTRL|'L'):
  892.         PaintBrowser(gmp, 0, &crow, &ccol);
  893.         break;
  894.  
  895.       case 'g':                             /* jump to a directory */
  896.       case 'G':
  897.  
  898.         if(!(gmode&MDGOTO))
  899.           goto Default;
  900.  
  901.         i = 0;
  902.         child[0] = '\0';
  903.  
  904.         while(!i){
  905.  
  906.         status = mlreply("Directory to go to: ", child, NLINE, QNORML,
  907.                  NULL);
  908.  
  909.         switch(status){
  910.           case HELPCH:
  911.             emlwrite("\007No help yet!", NULL);
  912.             /* remove break and sleep after help text is installed */
  913.             sleep(3);
  914.             break;
  915.           case (CTRL|'L'):
  916.             PaintBrowser(gmp, 0, &crow, &ccol);
  917.           break;
  918.           case ABORT:
  919.             emlwrite("Goto cancelled", NULL);
  920.             i++;
  921.             break;
  922.           case FALSE:
  923.           case TRUE:
  924.             i++;
  925.  
  926.             if(*child == '\0')
  927.               strcpy(child, gethomedir(NULL));
  928.  
  929.             if(!compresspath(gmp->dname, child, NLINE)){
  930.             emlwrite("Invalid Directory: %s", child);
  931.             break;
  932.             }
  933.  
  934.             if((gmode&MDSCUR) && homeless(child)){
  935.             emlwrite("Restricted mode browsing limited to home directory",NULL);
  936.             break;
  937.             }
  938.  
  939.             if((gmode&MDTREE) && !in_oper_tree(child)){
  940.               emlwrite("\007 Can't go outside of %s in restricted mode",
  941.                    opertree);
  942.             break;
  943.             }
  944.  
  945.             if(isdir(child, (long *) NULL, NULL)){
  946.             if((mp = getfcells(child)) == NULL){
  947.                 /* getfcells should explain what happened */
  948.                 i++;
  949.                 break;
  950.             }
  951.  
  952.             zotmaster(&gmp);
  953.             gmp = mp;
  954.             PaintBrowser(gmp, 0, &crow, &ccol);
  955.             }
  956.             else
  957.               emlwrite("\007Not a directory: \"%s\"", child);
  958.  
  959.             break;
  960.           default:
  961.             break;
  962.         }
  963.         }
  964.         BrowserKeys();
  965.         break;
  966.  
  967.       case 'a':                    /* Add */
  968.       case 'A':
  969.         if(gmode&MDSCUR){                /* not allowed! */
  970.         emlwrite("Add not allowed in restricted mode",NULL);
  971.         break;
  972.         }
  973.  
  974.         i = 0;
  975.         child[0] = '\0';
  976.  
  977.         while(!i){
  978.  
  979.         switch(status=mlreply("Name of file to add: ", child, NLINE,
  980.                       QFFILE, NULL)){
  981.           case HELPCH:
  982.             emlwrite("\007No help yet!", NULL);
  983. /* remove break and sleep after help text is installed */
  984.             sleep(3);
  985.             break;
  986.           case (CTRL|'L'):
  987.             PaintBrowser(gmp, 0, &crow, &ccol);
  988.             break;
  989.           case ABORT:
  990.             emlwrite("Add File Cancelled", NULL);
  991.             i++;
  992.             break;
  993.           case FALSE:
  994.             i++;
  995.             mlerase();
  996.             break;
  997.           case TRUE:
  998.             i++;
  999.  
  1000.             if(child[0] == '\0'){
  1001.             emlwrite("No file named.  Add Cancelled.", NULL);
  1002.             break;
  1003.             }
  1004.  
  1005.             if(!compresspath(gmp->dname, child, NLINE)){
  1006.             emlwrite("Too many ..'s in name", NULL);
  1007.             break;
  1008.             }
  1009.  
  1010.             if((gmode&MDTREE) && !in_oper_tree(child)){
  1011.                emlwrite("\007Restricted mode allows Add in %s only",
  1012.                 opertree);
  1013.             break;
  1014.             }
  1015.  
  1016.             if((status = fexist(child, "w", (off_t *)NULL)) == FIOSUC){
  1017.             sprintf(tmp,"File \"%.*s\" already exists!",
  1018.                 NLINE - 20, child);
  1019.             emlwrite(tmp, NULL);
  1020.             break;
  1021.             }
  1022.             else if(status != FIOFNF){
  1023.             fioperr(status, child);
  1024.             break;
  1025.             }
  1026.  
  1027.             if(ffwopen(child, FALSE) != FIOSUC){
  1028.             /* ffwopen should've complained */
  1029.             break;
  1030.             }
  1031.             else{            /* highlight new file */
  1032.             ffclose();
  1033.             emlwrite("Added File \"%s\"", child);
  1034.  
  1035.             if((p = strrchr(child, C_FILESEP)) == NULL){
  1036.                 emlwrite("Problems refiguring browser", NULL);
  1037.                 break;
  1038.             }
  1039.  
  1040.             *p = '\0';
  1041.             if(p != child){
  1042.                 strcpy(tmp, child);
  1043.                 j = 0;
  1044.                 while(child[j++] = *++p)
  1045.                   ;
  1046.             }
  1047.             else
  1048.               strcpy(tmp, S_FILESEP);
  1049.  
  1050.             /*
  1051.              * new file in same dir? if so, refigure files
  1052.              * and redraw...
  1053.              */
  1054.             if(!strcmp(tmp, gmp->dname)){ 
  1055.                 if((mp = getfcells(gmp->dname)) == NULL)
  1056.                   /* getfcells should explain what happened */
  1057.                   break;
  1058.  
  1059.                 zotmaster(&gmp);
  1060.                 gmp = mp;
  1061.                 if((tp = FindCell(gmp, child)) != NULL){
  1062.                 gmp->current = tp;
  1063.                 PlaceCell(gmp, gmp->current, &row, &col);
  1064.                 }
  1065.  
  1066.                 PaintBrowser(gmp, 1, &crow, &ccol);
  1067.             }
  1068.             }
  1069.             break;
  1070.           default:
  1071.             break;
  1072.         }
  1073.         }
  1074.  
  1075.         BrowserKeys();
  1076.         break;
  1077.  
  1078.       case 'c':                    /* copy */
  1079.       case 'C':
  1080.         if(gmp->current->mode == FIODIR){
  1081.         emlwrite("\007Can't copy a directory", NULL);
  1082.         break;
  1083.         }
  1084.  
  1085.         if(gmode&MDSCUR){                /* not allowed! */
  1086.         emlwrite("Copy not allowed in restricted mode",NULL);
  1087.         break;
  1088.         }
  1089.  
  1090.         i = 0;
  1091.         child[0] = '\0';
  1092.  
  1093.         while(!i){
  1094.  
  1095.         switch(status=mlreply("Name of new copy: ", child, NLINE,
  1096.                       QFFILE, NULL)){
  1097.           case HELPCH:
  1098.             emlwrite("\007No help yet!", NULL);
  1099. /* remove break and sleep after help text is installed */
  1100.             sleep(3);
  1101.             break;
  1102.           case (CTRL|'L'):
  1103.             PaintBrowser(gmp, 0, &crow, &ccol);
  1104.             break;
  1105.           case ABORT:
  1106.             emlwrite("Make Copy Cancelled", NULL);
  1107.             i++;
  1108.             break;
  1109.           case FALSE:
  1110.             i++;
  1111.             mlerase();
  1112.             break;
  1113.           case TRUE:
  1114.             i++;
  1115.  
  1116.             if(child[0] == '\0'){
  1117.             emlwrite("No destination, file not copied", NULL);
  1118.             break;
  1119.             }
  1120.  
  1121.             if(!strcmp(gmp->current->fname, child)){
  1122.             emlwrite("\007Can't copy file on to itself!", NULL);
  1123.             break;
  1124.             }
  1125.  
  1126.             if(!compresspath(gmp->dname, child, NLINE)){
  1127.             emlwrite("Too many ..'s in name", NULL);
  1128.             break;
  1129.             }
  1130.  
  1131.             if((gmode&MDTREE) && !in_oper_tree(child)){
  1132.                emlwrite("\007Restricted mode allows Copy in %s only",
  1133.                 opertree);
  1134.             break;
  1135.             }
  1136.  
  1137.             if((status = fexist(child, "w", (off_t *)NULL)) == FIOSUC){
  1138.             sprintf(tmp,"File \"%.*s\" exists! OVERWRITE",
  1139.                 NLINE - 20, child);
  1140.             if((status = mlyesno(tmp, 0)) != TRUE){
  1141.                 emlwrite((status == ABORT)
  1142.                       ? "Make copy cancelled" 
  1143.                       : "File Not Renamed",
  1144.                      NULL);
  1145.                 break;
  1146.             }
  1147.             }
  1148.             else if(status != FIOFNF){
  1149.             fioperr(status, child);
  1150.             break;
  1151.             }
  1152.  
  1153.             sprintf(tmp, "%s%c%s", gmp->dname, C_FILESEP, 
  1154.                 gmp->current->fname);
  1155.  
  1156.             if(copy(tmp, child) < 0){
  1157.             /* copy()  will report any error messages */
  1158.             break;
  1159.             }
  1160.             else{            /* highlight new file */
  1161.             emlwrite("File copied to %s", child);
  1162.  
  1163.             if((p = strrchr(child, C_FILESEP)) == NULL){
  1164.                 emlwrite("Problems refiguring browser", NULL);
  1165.                 break;
  1166.             }
  1167.  
  1168.             *p = '\0';
  1169.             strcpy(tmp, (p == child) ? S_FILESEP: child);
  1170.  
  1171.             /*
  1172.              * new file in same dir? if so, refigure files
  1173.              * and redraw...
  1174.              */
  1175.             if(!strcmp(tmp, gmp->dname)){ 
  1176.                 strcpy(child, gmp->current->fname);
  1177.                 if((mp = getfcells(gmp->dname)) == NULL)
  1178.                   /* getfcells should explain what happened */
  1179.                   break;
  1180.  
  1181.                 zotmaster(&gmp);
  1182.                 gmp = mp;
  1183.                 if((tp = FindCell(gmp, child)) != NULL){
  1184.                 gmp->current = tp;
  1185.                 PlaceCell(gmp, gmp->current, &row, &col);
  1186.                 }
  1187.  
  1188.                 PaintBrowser(gmp, 1, &crow, &ccol);
  1189.             }
  1190.             }
  1191.             break;
  1192.           default:
  1193.             break;
  1194.         }
  1195.         }
  1196.         BrowserKeys();
  1197.         break;
  1198.  
  1199.       case 'r':                    /* rename */
  1200.       case 'R':
  1201.         i = 0;
  1202.  
  1203.         if(!strcmp(gmp->current->fname, "..")){
  1204.         emlwrite("\007Can't rename \"..\"", NULL);
  1205.         break;
  1206.         }
  1207.  
  1208.         if(gmode&MDSCUR){                /* not allowed! */
  1209.         emlwrite("Rename not allowed in restricted mode",NULL);
  1210.         break;
  1211.         }
  1212.  
  1213.         strcpy(child, gmp->current->fname);
  1214.  
  1215.         while(!i){
  1216.  
  1217.         switch(status=mlreply("Rename file to: ", child, NLINE, QFFILE,
  1218.                       NULL)){
  1219.           case HELPCH:
  1220.             emlwrite("\007No help yet!", NULL);
  1221. /* remove break and sleep after help text is installed */
  1222.             sleep(3);
  1223.             break;
  1224.           case (CTRL|'L'):
  1225.             PaintBrowser(gmp, 0, &crow, &ccol);
  1226.             break;
  1227.           case ABORT:
  1228.             emlwrite("Rename cancelled", NULL);
  1229.             i++;
  1230.             break;
  1231.           case FALSE:
  1232.           case TRUE:
  1233.             i++;
  1234.  
  1235.             if(child[0] == '\0' || status == FALSE){
  1236.             mlerase();
  1237.             break;
  1238.             }
  1239.  
  1240.             if(!compresspath(gmp->dname, child, NLINE)){
  1241.             emlwrite("Too many ..'s in name", NULL);
  1242.             break;
  1243.             }
  1244.  
  1245.             if((gmode&MDTREE) && !in_oper_tree(child)){
  1246.                emlwrite("\007Restricted mode allows Rename in %s only",
  1247.                 opertree);
  1248.             break;
  1249.             }
  1250.  
  1251.             status = fexist(child, "w", (off_t *)NULL);
  1252.             if(status == FIOSUC || status == FIOFNF){
  1253.             if(status == FIOSUC){
  1254.                 sprintf(tmp,"File \"%.*s\" exists! OVERWRITE",
  1255.                     NLINE - 20, child);
  1256.  
  1257.                 if((status = mlyesno(tmp, FALSE)) != TRUE){
  1258.                 emlwrite((status ==  ABORT)
  1259.                       ? "Rename cancelled"
  1260.                       : "Not Renamed",
  1261.                      NULL);
  1262.                 break;
  1263.                 }
  1264.             }
  1265.  
  1266.             sprintf(tmp, "%s%c%s", gmp->dname, C_FILESEP, 
  1267.                 gmp->current->fname);
  1268.  
  1269.             if(rename(tmp, child) < 0){
  1270.                 emlwrite("Rename Failed: %s", errstr(errno));
  1271.             }
  1272.             else{
  1273.                 if((p = strrchr(child, C_FILESEP)) == NULL){
  1274.                 emlwrite("Problems refiguring browser", NULL);
  1275.                 break;
  1276.                 }
  1277.                 
  1278.                 *p = '\0';
  1279.                 strcpy(tmp, (p == child) ? S_FILESEP: child);
  1280.  
  1281.                 if((mp = getfcells(tmp)) == NULL)
  1282.                   /* getfcells should explain what happened */
  1283.                   break;
  1284.  
  1285.                 zotmaster(&gmp);
  1286.                 gmp = mp;
  1287.  
  1288.                 if((tp = FindCell(gmp, ++p)) != NULL){
  1289.                 gmp->current = tp;
  1290.                 PlaceCell(gmp, gmp->current, &row, &col);
  1291.                 }
  1292.  
  1293.                 PaintBrowser(gmp, 1, &crow, &ccol);
  1294.                 mlerase();
  1295.             }
  1296.             }
  1297.             else{
  1298.             fioperr(status, child);
  1299.             }
  1300.             break;
  1301.           default:
  1302.             break;
  1303.         }
  1304.         }
  1305.         BrowserKeys();
  1306.         break;
  1307.  
  1308.       case 'v':                    /* stand-alone */
  1309.       case 'V':                    /* browser "view" */
  1310.       case 's':                    /* user "select" */
  1311.       case 'S':
  1312.       case (CTRL|'M'):
  1313.       Selected:
  1314.  
  1315.         if((toupper(new_c) == 'S' && (gmode&MDBRONLY))
  1316.            || (toupper(new_c) == 'V' && !(gmode&MDBRONLY)))
  1317.           goto Default;
  1318.  
  1319.         if(gmp->current->mode == FIODIR){
  1320.         *child = '\0';
  1321.         strcpy(tmp, gmp->dname);
  1322.         p = gmp->current->fname;
  1323.         if(p[0] == '.' && p[1] == '.' && p[2] == '\0'){
  1324.             if((p=strrchr(tmp, C_FILESEP)) != NULL){
  1325.             *p = '\0';
  1326.  
  1327.             if((gmode&MDTREE) && !in_oper_tree(tmp)){
  1328.                 emlwrite(
  1329.                    "\007Can't visit parent in restricted mode",
  1330.                    NULL);
  1331.                 break;
  1332.             }
  1333.  
  1334.             strcpy(child, &p[1]);
  1335.             if
  1336. #if defined(DOS) || defined(OS2)
  1337.               (p == tmp || (tmp[1] == ':' && tmp[2] == '\0'))
  1338. #else
  1339.               (p == tmp)
  1340. #endif
  1341.               {    /* is it root? */
  1342. #if defined(DOS) || defined(OS2)
  1343.                   if(*child)
  1344.                 strcat(tmp, S_FILESEP);
  1345. #else
  1346.                   if(*child)
  1347.                     strcpy(tmp, S_FILESEP);
  1348. #endif
  1349.                   else{
  1350.                   emlwrite("\007Can't move up a directory",
  1351.                        NULL);
  1352.                   break;
  1353.                   }
  1354.               }
  1355.             }
  1356.         }
  1357.         else{
  1358.             if(tmp[1] != '\0')        /* were in root? */
  1359.               strcat(tmp, S_FILESEP);
  1360.             strcat(tmp, gmp->current->fname);
  1361.         }
  1362.  
  1363.         if((mp = getfcells(tmp)) == NULL)
  1364.           /* getfcells should explain what happened */
  1365.           break;
  1366.  
  1367.         zotmaster(&gmp);
  1368.         gmp = mp;
  1369.         tp  = NULL;
  1370.  
  1371.         if(*child){
  1372.             if((tp = FindCell(gmp, child)) != NULL){
  1373.             gmp->current = tp;
  1374.             PlaceCell(gmp, gmp->current, &row, &col);
  1375.             }
  1376.             else
  1377.               emlwrite("\007Problem finding dir \"%s\"",child);
  1378.         }
  1379.  
  1380.         PaintBrowser(gmp, 0, &crow, &ccol);
  1381.         if(!*child)
  1382.           emlwrite("Select/View \".. parent dir\" to return to previous directory.",
  1383.                NULL);
  1384.  
  1385.         break;
  1386.         }
  1387.         else if(gmode&MDBRONLY){
  1388.         sprintf(child, "%s%c%s", gmp->dname, C_FILESEP, 
  1389.             gmp->current->fname);
  1390.  
  1391.         if(LikelyASCII(child)){
  1392.             sprintf(tmp, "%s \'%s\'",
  1393.                 (envp = (char *) getenv("PAGER"))
  1394.                   ? envp : BROWSER_PAGER, child);
  1395.             BrowserRunChild(tmp, gmp->dname);
  1396.             PaintBrowser(gmp, 0, &crow, &ccol);
  1397.         }
  1398.  
  1399.         break;
  1400.         }
  1401.         else{                /* just return */
  1402.           if ((strlen(gmp->dname) < dirlen) && 
  1403.           (strlen(gmp->current->fname) < fnlen)){
  1404.           strcpy(dir, gmp->dname);
  1405.           strcpy(fn, gmp->current->fname);
  1406.           }
  1407.           else {
  1408.         zotmaster(&gmp);
  1409.         return(-1);
  1410.           }
  1411.           if(sz != NULL)            /* size uninteresting */
  1412.         strcpy(sz, gmp->current->size);
  1413.           
  1414.           zotmaster (&gmp);
  1415.           return (1);
  1416.         }
  1417.         break;
  1418.  
  1419.       case 'w':                /* Where is */
  1420.       case 'W':
  1421.       case (CTRL|'W'):
  1422.         i = 0;
  1423.  
  1424.         while(!i){
  1425.  
  1426.         switch(readpattern("File name to find")){
  1427.           case HELPCH:
  1428.             emlwrite("\007No help yet!", NULL);
  1429. /* remove break and sleep after help text is installed */
  1430.             sleep(3);
  1431.             break;
  1432.           case (CTRL|'L'):
  1433.             PaintBrowser(gmp, 0, &crow, &ccol);
  1434.             break;
  1435.           case (CTRL|'Y'):        /* first first cell */
  1436.             for(tp = gmp->top; tp->prev; tp = tp->prev)
  1437.               ;
  1438.  
  1439.             i++;
  1440.             /* fall thru to repaint */
  1441.           case (CTRL|'V'):
  1442.             if(!i){
  1443.             do{
  1444.                 tp = gmp->top;
  1445.                 if((i = term.t_nrow - term.t_mrow - 2) <= 0)
  1446.                   break;
  1447.  
  1448.                 while(i-- && tp->next){
  1449.                 j = 0;
  1450.                 while(++j <= gmp->fpl  && tp->next)
  1451.                   tp = tp->next;
  1452.                 }
  1453.  
  1454.                 if(i < 0)
  1455.                   gmp->top = tp;
  1456.             }
  1457.             while(tp->next);
  1458.  
  1459.             emlwrite("Searched to end of directory", NULL);
  1460.             }
  1461.             else
  1462.               emlwrite("Searched to start of directory", NULL);
  1463.  
  1464.             if(tp){
  1465.             PlaceCell(gmp, gmp->current, &row, &col);
  1466.             PaintCell(row, col, gmp->cpf, gmp->current, 0);
  1467.             gmp->current = tp;
  1468.             if(PlaceCell(gmp, gmp->current, &row, &col)){
  1469.                 PaintBrowser(gmp, 1, &crow, &ccol);
  1470.             }
  1471.             else{
  1472.                 PaintCell(row, col, gmp->cpf, gmp->current, 1);
  1473.                 crow = row;
  1474.                 ccol = col;
  1475.             }
  1476.             }
  1477.  
  1478.             i++;            /* make sure we jump out */
  1479.             break;
  1480.           case ABORT:
  1481.             emlwrite("Whereis cancelled", NULL);
  1482.             i++;
  1483.             break;
  1484.           case FALSE:
  1485.             mlerase();
  1486.             i++;
  1487.             break;
  1488.           case TRUE:
  1489.             if((tp = FindCell(gmp, pat)) != NULL){
  1490.             PlaceCell(gmp, gmp->current, &row, &col);
  1491.             PaintCell(row, col, gmp->cpf, gmp->current, 0);
  1492.             gmp->current = tp;
  1493.  
  1494.             if(PlaceCell(gmp, tp, &row, &col)){ /* top changed */
  1495.                 PaintBrowser(gmp, 1, &crow, &ccol);
  1496.             }
  1497.             else{
  1498.                 PaintCell(row, col, gmp->cpf, gmp->current, 1);
  1499.                 crow = row;
  1500.                 ccol = col;
  1501.             }
  1502.             mlerase();
  1503.             }
  1504.             else
  1505.               emlwrite("\"%s\" not found", pat);
  1506.  
  1507.             i++;
  1508.             break;
  1509.           default:
  1510.             break;
  1511.         }
  1512.         }
  1513.  
  1514.         BrowserKeys();
  1515.         break;
  1516.  
  1517.       case (CTRL|'Z'):
  1518.         if(gmode&MDSSPD){
  1519.         bktoshell();
  1520.         PaintBrowser(gmp, 0, &crow, &ccol);
  1521.         break;
  1522.         }                    /* fall thru with error! */
  1523.  
  1524.       default:                /* what? */
  1525.       Default:
  1526.         if(c < 0xff)
  1527.           emlwrite("\007Unknown command: '%c'", (void *) c);
  1528.         else if(c & CTRL)
  1529.           emlwrite("\007Unknown command: ^%c", (void *)(c&0xff));
  1530.         else
  1531.           emlwrite("\007Unknown command", NULL);
  1532.       case NODATA:                /* no op */
  1533.         break;
  1534.     }
  1535.     }
  1536. }
  1537.  
  1538.  
  1539.  
  1540. /*
  1541.  * getfcells - make a master browser struct and fill it in
  1542.  *             return NULL if there's a problem.
  1543.  */
  1544. struct bmaster *
  1545. getfcells(dname)
  1546.     char *dname;
  1547. {
  1548.     int  i,                     /* various return codes */
  1549.          flength,
  1550.          nentries = 0;                /* number of dir ents */
  1551.     off_t attsz;
  1552.     char *np,                    /* names of files in dir */
  1553.          *dcp,                                  /* to add file to path */
  1554.          *tmpstr,
  1555.          **filtnames,                /* array filtered names */
  1556.      errbuf[NLINE];
  1557.     struct fcell *ncp,                /* new cell pointer */
  1558.                  *tcp;                /* trailing cell ptr */
  1559.     struct bmaster *mp;
  1560.  
  1561.     errbuf[0] = '\0';
  1562.     if((mp=(struct bmaster *)malloc(sizeof(struct bmaster))) == NULL){
  1563.     emlwrite("\007Can't malloc space for master filename cell", NULL);
  1564.     return(NULL);
  1565.     }
  1566.  
  1567.     if(dname[0] == '.' && dname[1] == '\0'){        /* remember this dir */
  1568.     if(!getcwd(mp->dname, 256))
  1569.       mp->dname[0] = '\0';
  1570.     }
  1571.     else if(dname[0] == '.' && dname[1] == '.' && dname[2] == '\0'){
  1572.     if(!getcwd(mp->dname, 256))
  1573.       mp->dname[0] = '\0';
  1574.     else{
  1575.         if((np = (char *)strrchr(mp->dname, C_FILESEP)) != NULL)
  1576.           if(np != mp->dname)
  1577.         *np = '\0';
  1578.     }
  1579.     }
  1580.     else
  1581.       strcpy(mp->dname, dname);
  1582.  
  1583.     mp->head = mp->top = NULL;
  1584.     mp->cpf = mp->fpl = 0;
  1585.     mp->longest = 5;                /* .. must be labeled! */
  1586.  
  1587.     emlwrite("Building file list of %s...", mp->dname);
  1588.  
  1589.     if((mp->names = getfnames(mp->dname, NULL, &nentries, errbuf)) == NULL){
  1590.     free((char *) mp);
  1591.     if(*errbuf)
  1592.       emlwrite(errbuf, NULL);
  1593.  
  1594.     return(NULL);
  1595.     }
  1596.  
  1597.     /*
  1598.      * this is the fun part.  build an array of pointers to the fnames we're
  1599.      * interested in (i.e., do any filtering), then pass that off to be
  1600.      * sorted before building list of cells...
  1601.      *
  1602.      * right now default filtering on ".*" except "..", but this could
  1603.      * easily be made a user option later on...
  1604.      */
  1605.     if((filtnames=(char **)malloc((nentries+1) * sizeof(char *))) == NULL){
  1606.     emlwrite("\007Can't malloc space for name array", NULL);
  1607.     zotmaster(&mp);
  1608.     return(NULL);
  1609.     }
  1610.  
  1611.     i = 0;                    /* index of filt'd array */
  1612.     np = mp->names;
  1613.     while(nentries--){
  1614.     int ii;
  1615.  
  1616.     /*
  1617.      * Filter dot files?  Always filter ".", never filter "..",
  1618.      * and sometimes fitler ".*"...
  1619.      */
  1620.     if(*np == '.' && !(*(np+1) == '.' && *(np+2) == '\0')
  1621.        && (*(np+1) == '\0' || !(gmode & MDDOTSOK))){
  1622.         np += strlen(np) + 1;
  1623.         continue;
  1624.     }
  1625.  
  1626.     filtnames[i++] = np;
  1627.  
  1628.     if((ii = (int)strlen(np)) > mp->longest)
  1629.       mp->longest = ii;            /* remember longest */
  1630.     np += ii + 1;                /* advance name pointer */
  1631.  
  1632.     }
  1633.     nentries = i;                /* new # of entries */
  1634.  
  1635.     /* 
  1636.      * sort files case independently
  1637.      */
  1638.     qsort((QSType *)filtnames, (size_t)nentries, sizeof(char *), sstrcasecmp);
  1639.  
  1640.     /* 
  1641.      * this is so we use absolute path names for stats.
  1642.      * remember: be careful using dname as directory name, and fix mp->dname
  1643.      * when we're done
  1644.      */
  1645.     dcp = (char *)strchr(mp->dname, '\0');
  1646.     if(dcp == mp->dname || dcp[-1] != C_FILESEP){
  1647.     dcp[0] = C_FILESEP;
  1648.     dcp[1] = '\0';
  1649.     }
  1650.     else
  1651.       dcp--;
  1652.  
  1653.     i = 0;
  1654.     while(nentries--){                /* stat filtered files */
  1655.     /* get a new cell */
  1656.     if((ncp=(struct fcell *)malloc(sizeof(struct fcell))) == NULL){
  1657.         emlwrite("\007Can't malloc cells for browser!", NULL);
  1658.         zotfcells(mp->head);        /* clean up cells */
  1659.         free((char *) filtnames);
  1660.         free((char *) mp);
  1661.         return(NULL);            /* bummer. */
  1662.     }
  1663.     ncp->next = ncp->prev = NULL;
  1664.  
  1665.     if(mp->head == NULL){            /* tie it onto the list */
  1666.         mp->head = mp->top = mp->current = ncp;
  1667.     }
  1668.     else{
  1669.         tcp->next = ncp;
  1670.         ncp->prev = tcp;
  1671.     }
  1672.     tcp = ncp;
  1673.  
  1674.     /* fill in the new cell */
  1675.     ncp->fname = filtnames[i++];
  1676.  
  1677.     /* fill in file's mode */
  1678.     if ((flength = strlen(ncp->fname) + 1 + strlen(dname)) < NLINE){
  1679.       strcpy(&dcp[1], ncp->fname);     /* use absolute path! */
  1680.       tmpstr = mp->dname;
  1681.     }
  1682.     else{
  1683.       if((tmpstr = (char *)malloc((flength+1)*sizeof(char))) == NULL){
  1684.         emlwrite("\007Can't malloc cells for temp buffer!", NULL);
  1685.             zotfcells(mp->head);                /* clean up cells */
  1686.             free((char *) filtnames);
  1687.             free((char *) mp);
  1688.             return(NULL);                       /* bummer. */
  1689.       }
  1690.       strcpy(tmpstr, dname);
  1691.       tmpstr = strcat(tmpstr, S_FILESEP);
  1692.       tmpstr = strcat(tmpstr, ncp->fname);
  1693.     }
  1694.     switch(fexist(tmpstr, "t", &attsz)){
  1695.       case FIODIR :
  1696.         ncp->mode = FIODIR;
  1697.         sprintf(ncp->size, "(%sdir)",
  1698.             (ncp->fname[0] == '.' && ncp->fname[1] == '.'
  1699.              && ncp->fname[2] == '\0') ? "parent " : "");
  1700.         break;
  1701.       case FIOSYM :
  1702.         ncp->mode = FIOSYM;
  1703.         strcpy(ncp->size, "--");
  1704.         break;
  1705.       default :
  1706.         ncp->mode = FIOSUC;            /* regular file */
  1707.         strcpy(ncp->size,  prettysz(attsz));
  1708.         break;
  1709.     }
  1710.     if (flength >= NLINE)
  1711.       free((char *) tmpstr);
  1712.     }
  1713.  
  1714.     dcp[(dcp == mp->dname) ? 1 : 0] = '\0';    /* remember to cap dname */
  1715.     free((char *) filtnames);            /* 'n blast filt'd array*/
  1716.  
  1717.     percdircells(mp);
  1718.     layoutcells(mp);
  1719.     return(mp);
  1720. }
  1721.  
  1722.  
  1723.  
  1724. /*
  1725.  * PaintCell - print the given cell at the given location on the display
  1726.  *             the format of a printed cell is:
  1727.  *
  1728.  *                       "<fname>       <size>  "
  1729.  */
  1730. PaintCell(x, y, l, cell, inverted)
  1731. struct fcell *cell;
  1732. int    x, y, l, inverted;
  1733. {
  1734.     char *p;                    /* temp str pointer */
  1735.     int   i = 0,                /* current display count */
  1736.           j, sl, fl;                /* lengths */
  1737.  
  1738.     if(cell == NULL)
  1739.     return(-1);
  1740.  
  1741.     fl = strlen(cell->fname);
  1742.     sl = strlen(cell->size);
  1743.  
  1744.     movecursor(x, y);
  1745.     if(inverted)
  1746.       (*term.t_rev)(1);
  1747.     
  1748.     /* room for fname? */
  1749.     p = (fl+2 > l) ? &cell->fname[fl-(l-2)] : cell->fname;
  1750.     while(*p != '\0'){                /* write file name */
  1751.     pputc(*p++, 0);
  1752.     i++;
  1753.     }
  1754.  
  1755.     if(sl+3 <= l-i){                /* room for size? */
  1756.     j = (l-i)-(sl+2);            /* put space between */
  1757.     i += j;
  1758.     while(j--)                /* file name and size */
  1759.       pputc(' ', 0);
  1760.  
  1761.     p = cell->size;
  1762.     while(*p != '\0'){            /* write file size */
  1763.         pputc(*p++, 0);
  1764.         i++;
  1765.     }
  1766.     }
  1767.  
  1768.     if(inverted)
  1769.       (*term.t_rev)(0);
  1770.  
  1771.     while(i++ < l)                /* pad ending */
  1772.       pputc(' ', 0);
  1773.  
  1774.     return(1);
  1775. }
  1776.  
  1777.  
  1778.  
  1779. /*
  1780.  * PaintBrowse - with the current data, display the browser.  if level == 0 
  1781.  *               paint the whole thing, if level == 1 just paint the cells
  1782.  *               themselves
  1783.  */
  1784. PaintBrowser(mp, level, row, col)
  1785. struct bmaster *mp;
  1786. int level;
  1787. int *row, *col;
  1788. {
  1789.     int i, cl;
  1790.     struct fcell *tp;
  1791.  
  1792.     if(!level){
  1793.     ClearBrowserScreen();
  1794.     BrowserAnchor(mp->dname);
  1795.     }
  1796.  
  1797.     i = 0;
  1798.     tp = mp->top;
  1799.     cl = COMPOSER_TOP_LINE;            /* current display line */
  1800.     while(tp){
  1801.  
  1802.     PaintCell(cl, mp->cpf * i, mp->cpf, tp, tp == mp->current);
  1803.  
  1804.     if(tp == mp->current){
  1805.         if(row)
  1806.           *row = cl;
  1807.  
  1808.         if(col)
  1809.           *col = mp->cpf * i;
  1810.     }
  1811.  
  1812.     if(++i >= mp->fpl){
  1813.         i = 0;
  1814.         if(++cl > term.t_nrow-(term.t_mrow+1))
  1815.           break;
  1816.     }
  1817.  
  1818.     tp = tp->next;
  1819.     }
  1820.  
  1821.     if(level){
  1822.     while(cl <= term.t_nrow - (term.t_mrow+1)){
  1823.         if(!i)
  1824.           movecursor(cl, 0);
  1825.         peeol();
  1826.         movecursor(++cl, 0);
  1827.     }
  1828.     }
  1829.     else{
  1830.     BrowserKeys();
  1831.     }
  1832.  
  1833.     return(1);
  1834. }
  1835.  
  1836.  
  1837. /*
  1838.  * BrowserKeys - just paints the keyhelp at the bottom of the display
  1839.  */
  1840. BrowserKeys()
  1841. {
  1842.     menu_browse[QUIT_KEY].name  = (gmode&MDBRONLY) ? "Q" : "E";
  1843.     menu_browse[QUIT_KEY].label = (gmode&MDBRONLY) ? "Quit" : "Exit Brwsr";
  1844.     menu_browse[GOTO_KEY].name  = (gmode&MDGOTO) ? "G" : NULL;
  1845.     menu_browse[GOTO_KEY].label = (gmode&MDGOTO) ? "Goto" : NULL;
  1846.     if(gmode & MDBRONLY){
  1847.     menu_browse[EXEC_KEY].name  = "L";
  1848.     menu_browse[EXEC_KEY].label = "Launch";
  1849.     menu_browse[SELECT_KEY].name  = "V";
  1850.     menu_browse[SELECT_KEY].label = "[View]";
  1851.     menu_browse[PICO_KEY].name  = "E";
  1852.     menu_browse[PICO_KEY].label = "Edit";
  1853.     }
  1854.     else{
  1855.     menu_browse[SELECT_KEY].name  = "S";
  1856.     menu_browse[SELECT_KEY].label = "[Select]";
  1857.     menu_browse[PICO_KEY].name  = "A";
  1858.     menu_browse[PICO_KEY].label = "Add";
  1859.     }
  1860.  
  1861.     wkeyhelp(menu_browse);
  1862. }
  1863.  
  1864.  
  1865. /*
  1866.  * layoutcells - figure out max length of cell and how many cells can 
  1867.  *               go on a line of the display
  1868.  */
  1869. layoutcells(mp)
  1870. struct bmaster *mp;
  1871. {
  1872.     mp->cpf = mp->longest + 12;            /* max chars / file */
  1873.     if(gmode & MDONECOL){
  1874.     mp->fpl = 1;
  1875.     }
  1876.     else{
  1877.     int i = 1;
  1878.  
  1879.     while(i*mp->cpf < term.t_ncol)        /* no force... */
  1880.       i++;                    /* like brute force! */
  1881.  
  1882.     mp->fpl = i - 1;            /* files per line */
  1883.     }
  1884.  
  1885.     if(mp->fpl == 0)
  1886.       mp->fpl = 1;
  1887. }
  1888.  
  1889.  
  1890. /*
  1891.  * percdircells - bubble all the directory cells to the top of the
  1892.  *                list.
  1893.  */
  1894. percdircells(mp)
  1895. struct bmaster *mp;
  1896. {
  1897.     struct fcell *dirlp,            /* dir cell list pointer */
  1898.                  *lp, *nlp;            /* cell list ptr and next */
  1899.  
  1900.     dirlp = NULL;
  1901.     for(lp = mp->head; lp; lp = nlp){
  1902.     nlp = lp->next;
  1903.     if(lp->mode == FIODIR){
  1904.         if(lp->prev)            /* clip from list */
  1905.           lp->prev->next = lp->next;
  1906.  
  1907.         if(lp->next)
  1908.           lp->next->prev = lp->prev;
  1909.  
  1910.         if(lp->prev = dirlp){        /* tie it into dir portion */
  1911.         if(lp->next = dirlp->next)
  1912.           lp->next->prev = lp;
  1913.  
  1914.         dirlp->next = lp;
  1915.         dirlp = lp;
  1916.         }
  1917.         else{
  1918.         if((dirlp = lp) != mp->head)
  1919.           dirlp->next = mp->head;
  1920.  
  1921.         if(dirlp->next)
  1922.           dirlp->next->prev = dirlp;
  1923.  
  1924.         mp->head = mp->top = mp->current = dirlp;
  1925.         }
  1926.     }
  1927.     }
  1928. }
  1929.  
  1930.  
  1931. /*
  1932.  * PlaceCell - given a browser master, return row and col of the display that
  1933.  *             it should go.  
  1934.  *
  1935.  *             return 1 if mp->top has changed, x,y relative to new page
  1936.  *             return 0 if otherwise (same page)
  1937.  *             return -1 on error
  1938.  */
  1939. PlaceCell(mp, cp, x, y)
  1940. struct bmaster *mp;
  1941. struct fcell *cp;
  1942. int    *x, *y;
  1943. {
  1944.     int cl = COMPOSER_TOP_LINE;            /* current line */
  1945.     int ci = 0;                    /* current index on line */
  1946.     int rv = 0;
  1947.     int secondtry = 0;
  1948.     struct fcell *tp;
  1949.  
  1950.     /* will cp fit on screen? */
  1951.     tp = mp->top;
  1952.     while(1){
  1953.     if(tp == cp){                /* bingo! */
  1954.         *x = cl;
  1955.         *y = ci * mp->cpf;
  1956.         break;
  1957.     }
  1958.  
  1959.     if((tp = tp->next) == NULL){        /* above top? */
  1960.         if(secondtry++){
  1961.         emlwrite("\007Internal error: can't find fname cell", NULL);
  1962.         return(-1);
  1963.         }
  1964.         else{
  1965.         tp = mp->top = mp->head;    /* try from the top! */
  1966.         cl = COMPOSER_TOP_LINE;
  1967.         ci = 0;
  1968.         rv = 1;
  1969.         continue;            /* start over! */
  1970.         }
  1971.     }
  1972.  
  1973.     if(++ci >= mp->fpl){            /* next line? */
  1974.         ci = 0;
  1975.         if(++cl > term.t_nrow-(term.t_mrow+1)){ /* next page? */
  1976.         ci = mp->fpl;            /* tp is at bottom right */
  1977.         while(ci--)            /* find new top */
  1978.           tp = tp->prev;
  1979.         mp->top = tp;
  1980.         ci = 0;
  1981.         cl = COMPOSER_TOP_LINE;        /* keep checking */
  1982.         rv = 1;
  1983.         }
  1984.     }
  1985.  
  1986.     }
  1987.  
  1988.     /* not on display! */
  1989.     return(rv);
  1990.     
  1991. }
  1992.  
  1993.  
  1994. /*
  1995.  * zotfcells - clean up malloc'd cells of file names
  1996.  */
  1997. zotfcells(hp)
  1998. struct fcell *hp;
  1999. {
  2000.     struct fcell *tp;
  2001.  
  2002.     while(hp){
  2003.     tp = hp;
  2004.     hp = hp->next;
  2005.     tp->next = NULL;
  2006.     free((char *) tp);
  2007.     }
  2008. }
  2009.  
  2010.  
  2011. /*
  2012.  * zotmaster - blast the browser master struct
  2013.  */
  2014. zotmaster(mp)
  2015. struct bmaster **mp;
  2016. {
  2017.     zotfcells((*mp)->head);            /* free cells       */
  2018.     free((char *)(*mp)->names);            /* free file names  */
  2019.     free((char *)*mp);                /* free master      */
  2020.     *mp = NULL;                    /* make double sure */
  2021. }
  2022.  
  2023.  
  2024. /*
  2025.  * FindCell - starting from the current cell find the first occurance of 
  2026.  *            the given string wrapping around if necessary
  2027.  */
  2028. struct fcell *FindCell(mp, string)
  2029. struct bmaster *mp;
  2030. char   *string;
  2031. {
  2032.     struct fcell *tp, *fp;
  2033.  
  2034.     if(*string == '\0')
  2035.       return(NULL);
  2036.  
  2037.     fp = NULL;
  2038.     tp = mp->current->next;
  2039.     
  2040.     while(tp && !fp){
  2041.     if(sisin(tp->fname, string))
  2042.       fp = tp;
  2043.     else
  2044.       tp = tp->next;
  2045.     }
  2046.  
  2047.     tp = mp->head;
  2048.     while(tp != mp->current && !fp){
  2049.     if(sisin(tp->fname, string))
  2050.       fp = tp;
  2051.     else
  2052.       tp = tp->next;
  2053.     }
  2054.  
  2055.     return(fp);
  2056. }
  2057.  
  2058.  
  2059. /*
  2060.  * sisin - case insensitive substring matching function
  2061.  */
  2062. sisin(s1, s2)
  2063. char *s1, *s2;
  2064. {
  2065.     register int j;
  2066.  
  2067.     while(*s1){
  2068.     j = 0;
  2069.     while(toupper((unsigned char)s1[j]) == toupper((unsigned char)s2[j]))
  2070.       if(s2[++j] == '\0')            /* bingo! */
  2071.         return(1);
  2072.  
  2073.     s1++;
  2074.     }
  2075.     return(0);
  2076. }
  2077.  
  2078.  
  2079. /*
  2080.  * set_browser_title - 
  2081.  */
  2082. set_browser_title(s)
  2083. char *s;
  2084. {
  2085.     browser_title = s;
  2086. }
  2087.  
  2088.  
  2089. /*
  2090.  * BrowserAnchor - draw the browser's anchor line.
  2091.  */
  2092. BrowserAnchor(dir)
  2093. char *dir;
  2094. {
  2095.     register char *p;
  2096.     register int  i, j, l;
  2097.     char          buf[NLINE];
  2098.  
  2099.     movecursor(0, 0);
  2100.     (*term.t_rev)(1);
  2101.  
  2102.     i = 0;
  2103.     l = strlen(dir);
  2104.     j = (term.t_ncol-(l+16))/2;
  2105.  
  2106.     if(browser_title)
  2107.       sprintf(buf, "   %s", browser_title);
  2108.     else if(Pmaster)
  2109.       sprintf(buf, "   PINE %s", Pmaster->pine_version);
  2110.     else
  2111.       sprintf(buf,"   UW PICO(tm) %s", (gmode&MDBRONLY) ? "BROWSER" : version);
  2112.  
  2113.     p = buf;
  2114.     while(*p){
  2115.     pputc(*p++, 0);
  2116.     i++;
  2117.     }
  2118.  
  2119.     if(l > term.t_ncol - i - 21){        /* fit dir name on line */
  2120.     p = dir;
  2121.     while((p = strchr(p, C_FILESEP)) && (l-(p-dir)) > term.t_ncol-i-21)
  2122.       p++;
  2123.  
  2124.     if(!p)                    /* no suitable length! */
  2125.       p = &dir[l-(term.t_ncol-i-19)];
  2126.  
  2127.     sprintf(buf, "%s Dir ...%s", (gmode&MDBRONLY) ? "" : " BROWSER  ", p);
  2128.     }
  2129.     else 
  2130.       sprintf(buf,"%s  Dir: %s", (gmode&MDBRONLY) ? "" : " BROWSER  ", dir);
  2131.  
  2132.     if(i < j)                    /* keep it centered */
  2133.       j = j - i;                /* as long as we can */
  2134.     else
  2135.       j = ((term.t_ncol-i)-((int)strlen(p)+15))/2;
  2136.  
  2137.     while(j-- && i++)
  2138.       pputc(' ', 0);
  2139.  
  2140.     p = buf;
  2141.     while(i++ < term.t_ncol && *p)        /* show directory */
  2142.       pputc(*p++, 0);
  2143.  
  2144.     while(i++ < term.t_ncol)
  2145.       pputc(' ', 0);
  2146.  
  2147.     (*term.t_rev)(0);
  2148. }
  2149.  
  2150.  
  2151. /*
  2152.  * ResizeBrowser - handle a resize event
  2153.  */
  2154. ResizeBrowser()
  2155. {
  2156.     if(gmp){
  2157.     layoutcells(gmp);
  2158.     PaintBrowser(gmp, 0, NULL, NULL);
  2159.     return(1);
  2160.     }
  2161.     else
  2162.       return(0);
  2163. }
  2164.  
  2165.  
  2166. void
  2167. ClearBrowserScreen()
  2168. {
  2169.     int i;
  2170.  
  2171.     for(i = 0; i <= term.t_nrow; i++){        /* clear screen */
  2172.     movecursor(i, 0);
  2173.     peeol();
  2174.     }
  2175. }
  2176.  
  2177.  
  2178. void
  2179. BrowserRunChild(child, dir)
  2180.     char *child;
  2181.     char *dir;
  2182. {
  2183.     int    status;
  2184.     char   tmp[NLINE];
  2185.     time_t t_in, t_out;
  2186.  
  2187.     ClearBrowserScreen();
  2188.     movecursor(0, 0);
  2189.     (*term.t_close)();
  2190.     if(!isdir(dir, NULL, &t_in))
  2191.       t_in = 0;
  2192.  
  2193.     fflush(stdout);
  2194.     status = system(child);
  2195.     (*term.t_open)();
  2196.     if(t_in && isdir(dir, NULL, &t_out) && t_in < t_out){
  2197.     struct bmaster *mp;
  2198.  
  2199.     if(mp = getfcells(dir)){
  2200.         zotmaster(&gmp);
  2201.         gmp = mp;
  2202.     }
  2203.     /* else getfcells should explain what happened */
  2204.     }
  2205.  
  2206.     /* complain about non-zero exit status */
  2207.     if((status >> 8) & 0xff){
  2208.  
  2209.     movecursor(term.t_nrow - 1, 0);
  2210.     sprintf(tmp, "[ \"%.30s\" exit with error value: %d ]",
  2211.         child, (status >> 8) & 0xff);
  2212.     pputs(tmp, 1);
  2213.     movecursor(term.t_nrow, 0);
  2214.     pputs("[ Hit RETURN to continue ]", 1);
  2215.     fflush(stdout);
  2216.  
  2217.     while(GetKey() != (CTRL|'M')){
  2218.         (*term.t_beep)();
  2219.         fflush(stdout);
  2220.     }
  2221.     }
  2222. }
  2223. #endif    /* _WINDOWS */
  2224.  
  2225.  
  2226. /*
  2227.  * LikelyASCII - make a rough guess as to the displayability of the
  2228.  *         given file.
  2229.  */
  2230. int
  2231. LikelyASCII(file)
  2232.     char *file;
  2233. {
  2234. #define    LA_TEST_BUF    1024
  2235. #define    LA_LINE_LIMIT    300
  2236. #if defined(DOS) || defined(OS2)
  2237. #define    MODE    "rb"
  2238. #else
  2239. #define    MODE    "r"
  2240. #endif
  2241.     int           n, i, line, rv = FALSE;
  2242.     unsigned char  buf[LA_TEST_BUF];
  2243.     FILE      *fp;
  2244.  
  2245.     if(fp = fopen(file, "rb")){
  2246.     clearerr(fp);
  2247.     if((n = fread(buf, sizeof(char), LA_TEST_BUF * sizeof(char), fp)) > 0
  2248.        || !ferror(fp)){
  2249.         /*
  2250.          * If we don't hit any newlines in a reasonable number,
  2251.          * LA_LINE_LIMIT, of characters or the file contains NULLs,
  2252.          * bag out...
  2253.          */
  2254.         rv = TRUE;
  2255.         for(i = line = 0; i < n; i++)
  2256.           if((line = (buf[i] == '\n') ? 0 : line + 1) >= LA_LINE_LIMIT
  2257.          || !buf[i]){
  2258.           rv = FALSE;
  2259.           emlwrite("Can't display non-text file.  Try \"Launch\".",
  2260.                NULL);
  2261.           break;
  2262.           }
  2263.     }
  2264.     else
  2265.       emlwrite("Can't read file: %s", file);
  2266.  
  2267.     fclose(fp);
  2268.     }
  2269.     else
  2270.       emlwrite("Can't open file: %s", file);
  2271.  
  2272.     return(rv);
  2273. }
  2274.