home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume25 / ils / ils.c < prev    next >
C/C++ Source or Header  |  1992-02-28  |  26KB  |  882 lines

  1. /**************************************************************************
  2.  * ils - interactive "ls" library for ascii terminals.
  3.  *
  4.  * Subroutine ils expects variable "rows", and "cols" to be set prior to
  5.  * calling.  rows should contain the verticle size of the window to
  6.  * be used, and cols should contain horizontal size (in characters).
  7.  *
  8.  *
  9.  * Author: Jack Alexander
  10.  *       jack@marley
  11.  *
  12.  */
  13. #include    "ils.h"
  14.  
  15. #include <curses.h>
  16. #include <stdio.h>
  17. #include <sys/dir.h>
  18. #include <fcntl.h>
  19. #include <errno.h>
  20.  
  21. #include    "get.h"           /* need key definitions from getstring routine */
  22.  
  23. extern    char    *pnam;        /* program name */
  24.  
  25. int    a_num, a_ind;            /* work variables for argument processing */
  26. int    syms=0;                /* number of symbols in table */
  27. struct    symbol    *symtab[MAX_SYMBOLS]; /* symbol table */
  28. char    *args[ILS_MAX_ARGS];        /* argument list */
  29. int    modes;                /* hold behavioral data */
  30.  
  31. char    cur_path[MAXPATH];        /* current path */
  32.  
  33.  
  34. /* interactive directory browser -- main routine 
  35. **
  36. ** variable pattern in a two dimensional array containing all of the patterns
  37. ** to use for pattern matching.  If pattern[0] == NULL, then no
  38. ** patterns are used, and all files are shown.
  39. **
  40. ** variable path is a string containing the path of the directory from which
  41. ** browsing will begin (typically, same as pwd(1)).
  42. **
  43. ** ulx, uly, lrx, and lry are the coordinates (in screen coordinates where
  44. ** units are characters.
  45. **
  46. ** m is an integer which may contain any behavioral charactaristics.
  47. ** various bits, as described in ils.h can be ored into this variable to
  48. ** change the behavior of ils.
  49. **
  50. ** title is a string which is displayed on the top line of the window.  If
  51. ** title is NULL, then no title is shown, and you get an extra line for
  52. ** editing.
  53. **/
  54. ils(pattern,path,ulx,uly,lrx,lry,m,title)
  55. char    *pattern[],*path,*title;
  56. int    ulx, uly, lrx, lry, m;
  57. {
  58.     struct    d_entry    *top;    /* the very top of the known directory tree */
  59.  
  60.     modes = m;        /* makes user defined modes global */
  61.     top = (struct d_entry *) NULL;    /* haven't read any directories yet */
  62.     clear();
  63.     read_ils_defines();    /* read this user's definitions */
  64.     read_directory(pattern,path,&top); /* read in current directory */
  65.     edit_directory(pattern,path,&top,ulx,uly,lrx,lry,title); /* do it */
  66. }
  67.  
  68. /* read_ils_defines() looks and the ".ils" file for the user.  This file
  69.    contains all user-specific key sequences and correspoding actions for
  70.    the key sequences. */
  71. read_ils_defines()
  72. {
  73.     char    *getenv(), *a, dummy[MAXPATH];
  74.     FILE    *fopen(), *fp;
  75.     int    lnum=0;
  76.  
  77.     a=getenv("HOME");        /* get path to user's home directory */
  78.     sprintf(dummy,"%s/.ils",a);    /* set up path to the .ils file */
  79.     if((fp=fopen(dummy,"r"))==NULL)
  80.         return;            /* no ".ils" file in home directory */
  81.     while(fgets(dummy,MAXPATH,fp)!=NULL) {
  82.         lnum++;            /* line number counter */
  83.         if(dummy[0]=='#')
  84.             continue;    /* a comment line */
  85.         parse_line(dummy,lnum); /* enter into symbol table */
  86.     }
  87.     fclose(fp);
  88. }
  89.  
  90. #ifdef BSD
  91. /******
  92.  * Berkeley UNIX version. read directory reads all files in the current
  93.  * directory.
  94.  */
  95. read_directory(pattern,path,dptr)
  96. char    *pattern[],path[];
  97. struct    d_entry    **dptr;
  98. {
  99.     DIR    *dp, *opendir();
  100.     struct    direct    *dirptr, *readdir();
  101.  
  102.     if(chdir(path)<0)
  103.         return;        /* can't change to desired directory */
  104.     if((dp=opendir("."))==NULL)
  105.         return;        /* can't open the directory file itself */
  106.     while((dirptr=readdir(dp))!=NULL)    /* end of directory */
  107.         add_entry(pattern,dirptr->d_fileno,dirptr->d_name,dptr);
  108.     closedir(dp);
  109. }
  110. #endif BSD
  111.  
  112. #ifdef SYSTEMV
  113. /* SYSTEM V Unix version of the read_directory routine.    */
  114. read_directory(pattern,path,dptr)
  115. char    *pattern[],path[];
  116. struct    d_entry    **dptr;
  117. {
  118.     struct    direct    d;
  119.     int    fd;
  120.  
  121.     if(chdir(path)<0)    /* can't change to the desired directory */
  122.         return;
  123.     if((fd=open(".",O_RDONLY))<0)    /* can't open the directory file */
  124.         return;
  125.     while(read(fd,&d,sizeof(struct direct)) == sizeof(struct direct))
  126.         add_entry(pattern,d.d_ino,d.d_name,dptr); /* add file */
  127.     close(fd);
  128. }
  129. #endif SYSTEMV
  130.  
  131. /* showpath displays the string in "path" on the top line of the window.
  132.    The top line is defined in ulx, ily.  Only as much of the path as
  133.    can be seen is displayed, the rest is cust out. */
  134. showpath(path,ulx, uly, lrx, lry)
  135. char    path[];
  136. int    ulx, uly, lrx, lry;
  137. {
  138.     int    l;
  139.     char    dummy[80];
  140.  
  141.     standout();    /* invert the line */
  142.     move(uly,ulx);    /* move to top line of the window */
  143.     if((l=strlen(path))>(lrx-uly-1)) {    /* is string too long? */
  144.         /* if string is too long, truncate it.  preceed all truncated
  145.            paths with "..." to show user that the path was indeed
  146.            truncated. */
  147.         sprintf(dummy,"...%c%d.%ds",'%',(lrx-ulx-3),(lrx-ulx-3));
  148.         printw(dummy,path+(l-(lrx-ulx-3)));    /* print path */
  149.     }
  150.     else    /* string is not too long, just print it */
  151.         printw(path);
  152.     standend();   /* end inverted mode */
  153.     clrtoeol();   /* get rid of standend char on some types of terminals */
  154. }
  155.  
  156. /* display an error message on the top line of the window, wait for RETURN
  157.    key to be pressed so that user can acknowledge the error */
  158. ils_error(msg,ulx,uly,lrx,lry)
  159. char    msg[];
  160. int    ulx, uly, lrx, lry;
  161. {
  162.     int    l;
  163.     char    dummy[80];
  164.  
  165.     standout();        /* all errors in inverse mode */
  166.     move(uly,ulx);        /* go to top line */
  167.     sprintf(dummy,">> %s <<  Press RETURN...",msg);
  168.     if((l=strlen(dummy))>(lrx-uly-1)) {  /* does message need truncation? */
  169.         if(strlen(msg) > (lrx-uly-1)) {
  170.             /* truncate the message. Preceed truncated with "..." */
  171.             sprintf(dummy,"...%c%d.%ds",'%',(lrx-ulx-3),(lrx-ulx-3));
  172.             printw(dummy,msg+(l-(lrx-ulx-3)));
  173.             
  174.         }
  175.         else
  176.             strcpy(dummy,msg);    /* no truncation needed */
  177.     }
  178.     printw(dummy);
  179.     standend();    /* end inverse mode */
  180.     refresh();
  181.     ils_wait_key(ILS_ENTER);    /* wait for RETURN key to be pressed */
  182. }
  183.  
  184. /* wait for key (passed in variable 'c') to be pressed.  Keep asking
  185.    for more keys until the one waited for is pressed. */
  186. ils_wait_key(c)
  187. int    c;
  188. {
  189.     while((getch()&0x7f)!=c);
  190. }
  191.  
  192. /* edit a directory, using a rectangle in the screen with (ulx, uly) as
  193.    the coordinates of the upper-left corner of the rectangle, and
  194.    (lrx, lry) as the lower-right corner of the rectangle.  title is
  195.    a character string that will be printed in the top line of the rectangle,
  196.    unless a NULL is passed, in which case nothing is printed, and you
  197.    have another line to use as part of the directory. */
  198.  
  199. edit_directory(pattern,path,dptr,ulx,uly,lrx,lry,title)
  200. char    *pattern[],path[];
  201. struct    d_entry    **dptr;
  202. int    ulx, uly, lrx, lry;
  203. char    *title;
  204. {
  205.     static    int    level=0;
  206.     char    newpath[80], trailer, *p, line[MAXPATH], this_dir[MAXPATH],
  207.         last_active[MAXPATH];
  208.     struct    d_entry *cur, *t, *active_list[ILS_MAX_ENTRIES];
  209.     int    height, width, widest, entries, i, j, horiz_fit, vert_fit,
  210.         x, y, more_line, first_visible, orig_uly,
  211.         column_height, cur_entry, state, next_state, c,
  212.         last_x, last_y, z, up_x, up_y, down_x, down_y,
  213.         done, new_entries, low, high, middle;
  214.  
  215.     clear();
  216.     raw();        /* need characters AS THEY ARE PRESSED */
  217.     noecho();    /* don't show user's input */
  218.  
  219.     orig_uly = uly;
  220.     if(title != (char *)NULL)     /* is there a title? */
  221.         uly++;    /* account for title line */
  222.     uly++;        /* account for "current directory" line */
  223.     
  224.     height = lry - uly;    /* height of window */
  225.     width = lrx - ulx;    /* width of window */
  226.  
  227.     strcpy(cur_path,path);    /* make path globally known */
  228.  
  229.     level++;        /* count the levels down */
  230.  
  231.     state = ILS_INITIAL;
  232.     next_state = ILS_INITIAL2;
  233.     cur_entry = 0;
  234.  
  235.     while(1) {    /* loop will end with an exit() call */
  236.       switch(state) {
  237.         case ILS_INITIAL:
  238.         cur = *dptr; /* get all entries in directory into a sorted list */
  239.         widest = 6;  /* default longest string length */
  240.         entries = first_visible = 0;
  241.         /* loop through and find the longest filename in the list */
  242.         while(cur != (struct d_entry *)NULL) {
  243.             if((i=strlen(cur->name)) > widest)
  244.                 widest = i;    /* found a longer string */
  245.             active_list[entries++] = cur;
  246.             cur = cur->next;    /* get next in list */
  247.         }
  248.         /* get number of strings that can fit => how many columns */
  249.         horiz_fit = width / (widest+2);
  250.         column_height = entries / horiz_fit + ((entries%horiz_fit)==0? 0:1);
  251.         vert_fit = lry-uly; /* how many can fit verticall into window */
  252.         if(vert_fit > column_height)
  253.             vert_fit = column_height;    /* safeguard */
  254.  
  255.         state = next_state;
  256.         break;
  257.  
  258.         case ILS_INITIAL2:
  259.         if(!entries) {    /* is this an empty directory? */
  260.             showpath(path,ulx,orig_uly+(title==NULL? 0:1),lrx,lry);
  261.             ils_error("EMPTY DIRECTORY",ulx,orig_uly,lrx,lry);
  262.             level--;
  263.             return;    /* empty: allow no editing */
  264.         }
  265.         state = ILS_TOTAL_DRAW;    /* redraw screen */
  266.         break;
  267.  
  268.         case ILS_FIND_CURSOR:    /* locate best place for cursor */
  269.         done = 0;
  270.         low = 0;        /* base value for binary search */
  271.         high = entries;        /* high value for binary search */
  272.         /* binary search to position where the cursor should be */
  273.         while(!done) {    /* binary search to the place to put cursor */
  274.             middle = (low+high)/2;
  275.             i = strcmp(last_active,active_list[middle]->name);
  276.             if(i==0)
  277.                 done = 1;    /* found entry! */
  278.             if(i<0) {
  279.                 if(middle==high) /* found where to put cursor */
  280.                     done=1;
  281.                 else
  282.                     high = middle; /* try lower half */
  283.             }
  284.             else {
  285.                 if(middle==low) /* found where to put cursor */
  286.                     done=1;
  287.                 else
  288.                     low = middle; /* try upper half */
  289.             }
  290.         }
  291.         /* middle is now equal to entry number where cursor should be */
  292.         cur_entry = middle;
  293.         first_visible = 0;    /* for now, top line shown is line 0 */
  294.         i = middle % column_height;  /* get offset from top of column */
  295.         if(i>=vert_fit)        /* is the active entry off the screen? */
  296.             first_visible = i-vert_fit+1;/* YES make it visible */
  297.         if(first_visible<0 || first_visible>=entries || first_visible>=vert_fit)
  298.             first_visible = i;    /* safeguard */
  299.         if(first_visible >= entries)    /* another safeguard */
  300.             first_visible;
  301.         state = ILS_INITIAL2;
  302.         break;
  303.  
  304.         case ILS_TOTAL_DRAW:    /* redraw the whole window */
  305.         clear();
  306.         if(title != NULL) {    /* is there a title to display? */
  307.             move(orig_uly,ulx);
  308.             clrtoeol();
  309.             printw("%s",title);    /* display the title */
  310.         }
  311.         /* display the path either just below the title, or on top */
  312.         showpath(path,ulx,orig_uly+(title==NULL? 0:1),lrx,lry);
  313.         case ILS_DRAW:        /* show files in directory */
  314.         up_x=up_y=down_x=down_y= -1;
  315.         for(i=0,z=first_visible;i<horiz_fit;i++) {
  316.             for(j=0;j<vert_fit && z<entries;j++,z++) {
  317.                 y=uly+j;
  318.                 x=1+ulx+(width/horiz_fit)*i;
  319.                 move(y,x);
  320.                 if(!i)
  321.                     clrtoeol();
  322.                 if(!i && !j && first_visible) {
  323.                     standout();
  324.                     printw("< more",first_visible*horiz_fit+1);
  325.                     standend();
  326.                     up_x = x;
  327.                     up_y = y;
  328.                 }
  329.                 else {
  330.                     trailer=' ';
  331.                     if(modes & ILS_F_TYPE) {
  332.                         if(active_list[z]->stat.st_mode & 040000)
  333.                             trailer='/';
  334.                         else if(active_list[z]->stat.st_mode & 0100)
  335.                             trailer='*';
  336.                     }
  337.                     printw("%s%c",active_list[z]->name,trailer);
  338.  
  339.                 }
  340.             }
  341.             z+=column_height-vert_fit;
  342.         }
  343.         if((first_visible+vert_fit) < column_height) {
  344.             y=uly+vert_fit-1;
  345.             x=1+ulx+(width/horiz_fit)*(horiz_fit-1);
  346.             move(y,x);
  347.             standout();
  348.             printw("more >");
  349.             standend();
  350.             clrtoeol();
  351.             down_x = x;
  352.             down_y = y;
  353.         }
  354.  
  355.         refresh();
  356.         state = ILS_SHOW_CURSOR;
  357.         next_state = ILS_KEYBOARD;
  358.         break;
  359.       case ILS_SHOW_PATH:
  360.         showpath(path,ulx,orig_uly+(title==NULL? 0:1),lrx,lry);
  361.       case ILS_MOVE_CURSOR:
  362.         move(last_y,last_x);
  363.         addch(' ');
  364.       case ILS_SHOW_CURSOR:
  365.         last_y=y=uly + cur_entry%column_height-first_visible;
  366.         last_x=x=ulx + (width/horiz_fit) * (cur_entry / column_height);
  367.         if((x+1)==up_x && y==up_y) {
  368.             first_visible--;
  369.             state = ILS_DRAW;
  370.             break;
  371.         }
  372.         if((x+1)==down_x && y==down_y) {
  373.             first_visible++;
  374.             state = ILS_DRAW;
  375.             break;
  376.         }
  377.         move(y,x);
  378.         addch('>');
  379.         move(y,x);
  380.         refresh();
  381.         state = next_state;
  382.         break;
  383.       case ILS_KEYBOARD:
  384.         switch((c=(getch()&0x7f))) {
  385.             case ILS_ESCAPE:    /*  go back up or QUIT! */
  386.                 if(level==1)
  387.                     state=ILS_ASCEND;
  388.                 else
  389.                     state = ILS_EXIT;
  390.                 break;
  391.             case ILS_EXIT_KEY:        /* QUIT NOW! */
  392.                 ils_exit(1);
  393.                 break;
  394.             case ILS_ENTER:
  395.             case ILS_RETURN:    /* descend into a directory */
  396.                 if(active_list[cur_entry]->stat.st_mode & 040000) {
  397.                     if(strcmp(active_list[cur_entry]->name,".")==0) {
  398.                         flash(); /* change to current directory */
  399.                         break;
  400.                     }
  401.                     if(strcmp(active_list[cur_entry]->name,"..")==0) {
  402.                         if(level==1)
  403.                             state = ILS_ASCEND;
  404.                         else
  405.                             state = ILS_EXIT;
  406.                         break;
  407.                     }
  408.                     if(path[1]=='\0')
  409.                         sprintf(newpath,"/%s",active_list[cur_entry]->name);
  410.                     else
  411.                         sprintf(newpath,"%s/%s",path,active_list[cur_entry]->name);
  412.                     strcpy(last_active,active_list[cur_entry]->name);
  413.                     if(active_list[cur_entry]->contents == (struct d_entry *)NULL) {
  414.                         read_directory(pattern,newpath,&(active_list[cur_entry]->contents));
  415.                     }
  416.                     else {
  417.                         chdir(newpath);
  418.                         strcpy(cur_path,newpath);
  419.                         re_read_dir(pattern,&(active_list[cur_entry]->contents));
  420.                     }
  421.                     refresh();
  422.                     edit_directory(pattern,newpath,&(active_list[cur_entry]->contents),ulx,orig_uly,lrx,lry,title);
  423.                     chdir(path);    /* back up */
  424.                     strcpy(cur_path,path);
  425.                     state = ILS_INITIAL;
  426.                     if((new_entries=re_read_dir(pattern,dptr))!=entries) 
  427.                         next_state = ILS_FIND_CURSOR;
  428.                     else
  429.                         next_state = ILS_INITIAL2;
  430.                 }
  431.                 break;
  432.             case ILS_UP:        /* move cursor up */
  433.                 if(cur_entry==0 || (cur_entry%column_height)==0)
  434.                     break; /* can't move up one */
  435.                 cur_entry--;
  436.                 y=uly+cur_entry%column_height-first_visible;
  437.                  if(y<uly) {
  438.                     state = ILS_DRAW;
  439.                     first_visible--;
  440.                 }
  441.                 else {
  442.                     state = ILS_MOVE_CURSOR;
  443.                     next_state = ILS_KEYBOARD;
  444.                 }
  445.                 break;
  446.             case ILS_DOWN:        /* move cursor down */
  447.                 if(cur_entry==(entries-1) || (cur_entry%column_height)==column_height-1)
  448.                     break;    /* can't move down one */
  449.                 cur_entry++;
  450.                 y=uly+cur_entry%column_height-first_visible;
  451.                 if(y>=lry) {
  452.                     state = ILS_DRAW;
  453.                     first_visible++;
  454.                 }
  455.                 else {
  456.                     state = ILS_MOVE_CURSOR;
  457.                     next_state = ILS_KEYBOARD;
  458.                 }
  459.                 break;
  460.             case ILS_RIGHT:        /* move cursor right */
  461.                 if(cur_entry+column_height >= entries)
  462.                     break;    /* can't move right */
  463.                 else {
  464.                     cur_entry+=column_height;
  465.                     state = ILS_MOVE_CURSOR;
  466.                     next_state = ILS_KEYBOARD;
  467.                 }
  468.                 break;
  469.             case ILS_LEFT:        /* move cursor left */
  470.                 if(cur_entry-column_height < 0)
  471.                     break;    /* can't move left */
  472.                 else {
  473.                     cur_entry-=column_height;
  474.                     state = ILS_MOVE_CURSOR;
  475.                     next_state = ILS_KEYBOARD;
  476.                 }
  477.                 break;
  478.             case ILS_REDRAW:    /* redraw the screen */
  479.             case ILS_REDRAW_ALT:    /* alternate character */
  480.                 state = ILS_TOTAL_DRAW;
  481.                 break;
  482.                 case ILS_ENV:        /* display symbol table */
  483.                 display_symtab();
  484.                 state = ILS_TOTAL_DRAW;
  485.                 break;
  486.             case ILS_FORCE_KEYBOARD: /* force us into keyboard mode */
  487.             default:
  488.                 if(keybd(c,ulx,orig_uly+(title==NULL? 0:1),lrx,lry,line)) {
  489.                     strcpy(last_active,active_list[cur_entry]->name);
  490.                     process_input(c,active_list,cur_entry,entries,line,ulx,orig_uly+(title==NULL? 0:1),lrx);
  491.                     state = ILS_INITIAL;
  492.                     if((new_entries=re_read_dir(pattern,dptr))!=entries)
  493.                         next_state = ILS_FIND_CURSOR;
  494.                     else
  495.                         next_state = ILS_INITIAL2;
  496.                     showpath(path,ulx,orig_uly+(title==NULL? 0:1),lrx,lry);
  497.                 }
  498.                 else
  499.                     state = ILS_SHOW_PATH;
  500.                 break;
  501.         }
  502.         break;
  503.         case ILS_ASCEND:            /* up into a new directory */
  504.         if(path[1]=='\0') {        /* at root (/) ? */
  505.             flash();        /* can't go up any higher! */ 
  506.             state = ILS_KEYBOARD;    /* back to input mode */
  507.             break;
  508.         }
  509.         strcpy(newpath,path);
  510.         /* find the first '/' character from the right, then chop the
  511.            path from that point on.  This is to make a path like:
  512.                 /usr/local/bin
  513.            into
  514.                 /usr/local
  515.          */
  516.         for(i=strlen(path)-1;i && newpath[i]!='/';i--);
  517.         if(i==0) {    /* i==0 if we are one level down from root */
  518.             strcpy(newpath,"/");    /* make root the new path */
  519.             strcpy(this_dir,&(path[1]));
  520.         }
  521.         else {
  522.             newpath[i]='\0';    /* up one level in the path */
  523.             strcpy(this_dir,&(newpath[i+1]));
  524.         }
  525.         if(this_dir[0]=='\0')    /* make sure not a  null string */
  526.             break;    /* a little safeguard */
  527.         cur = (struct d_entry *) NULL;    /* ready to read a new dir */
  528.         read_directory(pattern,newpath,&cur); /* read it */
  529.         t = cur;    /* find the entry in the new directory that
  530.                    corresponds to this directory's name. */
  531.         strcpy(last_active,this_dir);    /* for finding cursor pos */
  532.         for(cur = (*dptr);cur!=(struct d_entry *)NULL;) {
  533.             if(strcmp(cur->name,this_dir)==0) {
  534.                 /* found it.  assign contents to this entry */
  535.                 cur->contents = (*dptr);
  536.                 cur = (struct d_entry *) NULL;
  537.             }
  538.             else    /* try next one */
  539.                 cur = cur->next;
  540.         }
  541.         (*dptr) = t;    /* make this the new "top of tree" pointer */
  542.         strcpy(cur_path,newpath);    /* let globals know */
  543.         strcpy(path,newpath);
  544.         cur_entry = first_visible = 0;
  545.         state = ILS_INITIAL;        /* make this the active one */
  546.         next_state = ILS_FIND_CURSOR;
  547.         break;
  548.         case ILS_EXIT:            /* QUIT! */
  549.         move(last_y,last_x);
  550.         addch(' ');            /* erase cursor */
  551.         level--;            /* back up one level */
  552.         if(level==0) {
  553.             noraw();
  554.             echo();
  555.         }
  556.         return(1);
  557.         break;
  558.           }
  559.     }
  560. }
  561.  
  562. /* add an entry to a directory list.
  563. ** pattern is the array of search patterns as passed to ils()
  564. ** i is the inode number of this entry
  565. ** p is the name of this entry
  566. ** place the the pointer to the directory list (of d_entry's)
  567. */
  568. add_entry(pattern,i,p,place)
  569. long    i;
  570. char    *pattern[],*p;
  571. struct    d_entry **place;
  572. {
  573.     struct    d_entry    *t, *cur, *last;
  574.     int    l, match;
  575.     struct    stat    st;
  576.     char    *ps, *pd;
  577.  
  578.     if(i==0)        /* if inode is 0, file was removed */
  579.         return;
  580.     if(stat(p,&st)<0)    /* can't stat file, don't add it */
  581.         return;
  582.     if(p[0]=='.' && (modes&ILS_ALL)==0) /* is this a "." file? */
  583.         return;        /* starts with '.', not in list all mode */
  584.     if(pattern[0]!=(char *)NULL) {    /* if patterns are used, see if match */
  585.         for(l=match=0;pattern[l]!=(char *)NULL && match==0;l++) {
  586.             if(wildmat(p,pattern[l]))
  587.                 match++;    /* matches a pattern */
  588.         }
  589.         if(!match)
  590.             return;        /* doesn't match any patterns */
  591.     }
  592.     
  593.     new_entry(&t,p,&st);        /* get memory and assign values */
  594.  
  595.     if(*place == (struct d_entry *)NULL)     /* empty list */
  596.         *place=t;
  597.     else {
  598.         /* loop through and decide where to place the new entry.
  599.            the list is a sorted doubly-linked list. */
  600.         cur = last = *place;
  601.         while(cur != (struct d_entry *)NULL) {
  602.             if(strcmp(p,cur->name) < 0) {    /* insert before */
  603.                 if(cur == *place) {    /* at top of list */
  604.                     t->next = *place;
  605.                     cur->prev = t;
  606.                     *place = t;
  607.                     return;
  608.                 }
  609.                 else {            /* in middle */
  610.                     cur->prev->next = t;
  611.                     t->prev = cur->prev;
  612.                     cur->prev = t;
  613.                     t->next = cur;
  614.                     return;
  615.                 }
  616.             }
  617.             else {        /* check next name */
  618.                 last = cur;
  619.                 cur = cur->next;
  620.             }
  621.         }
  622.         if( cur == (struct d_entry *)NULL) { /* insert at end of list */
  623.             last->next = t;
  624.             t->prev = last;
  625.         }
  626.     }
  627. }
  628.  
  629. /* get a string from the keyboard, and process it based on defined keysequences.
  630. ** c is the first character (as entered in the mailine ils code above.
  631. **    if c is not a FORCE_KEYBOARD character, thenn it is inserted into
  632. **    the string passed to the string editing routine, as the first character
  633. **    of the user's string.
  634. ** leftx,upy,rightx,downy are screen coordinates of the window size,
  635. **    regarding the location of the upper-left and lower-right corners.
  636. ** line    is a pointer to a string.  This is where the keyboard input will
  637. **    be placed and thus passed back to the calling routine.
  638. */ 
  639. keybd(c,leftx,upy,rightx,downy,line)
  640. int    leftx, upy, rightx, downy;
  641. char    c, line[];
  642. {
  643.     int    l;
  644.  
  645.     if(c==ILS_FORCE_KEYBOARD)    /* is this a FORCED KEY SEQUENCE? */
  646.         line[0]='\0';
  647.     else {            /* if legal character, insert into line[] */
  648.         if(c<' ' || c >0x7f)    /* out of range */
  649.             return;
  650.         line[0]=c;
  651.         line[1]='\0';
  652.     }
  653.  
  654.     if(rightx-leftx-7 < 2)        /* see if we can fit the prompt */
  655.         return(0);        /* no space on screen for input */
  656.     move(upy,leftx);
  657.     printw("Input: ");        /* print the prompt */
  658.     l=getst(rightx-leftx-8,leftx+7,upy,line,rightx-leftx-7,&l,ALL_ALPHA,NULL);
  659.     if(l==GET_RETURN || l==GET_DOWN)
  660.         return(1);
  661.     return(0);    /* probably ESCAPED out */
  662. }
  663.  
  664. /* free_contents() de-allocates the contents of the directory pointed at 
  665. ** by p.
  666. */
  667. free_contents(p)
  668. struct    d_entry    *p;
  669. {
  670.     if(p->next != (struct d_entry *)NULL)    /* depth-first deallaocation */
  671.         free_contents(p->next);
  672.     if(p->contents != (struct d_entry *)NULL) /* get rid of contents */
  673.         free_contents(p->contents);
  674.     free(p);                /* get rid of top node */
  675. }
  676.  
  677. /* re_read_dir() takes another look at the contents of a directory for
  678. ** changes in the contents or mode bits of the directory members.
  679. ** This is used when a directory is re-entered into, and we need to see
  680. ** if files were remove, added, or changed in any way.
  681. ** 
  682. ** pattern is the array of search patterns as passed to ils() initially.
  683. **
  684. ** dptr is the pointer to the contents of the directory last time it was
  685. ** examined.
  686. */
  687. re_read_dir(pattern,dptr)
  688. char    *pattern[];
  689. struct    d_entry    **dptr;
  690. {
  691.     char    name[MAXPATH], *pd, *ps;
  692.     struct    d_entry    *tdptr,*t;
  693.     int    i,inode,r,done,mxloop;
  694.     struct    stat    st;
  695.     long    touch, time();
  696. #ifdef BSD        /* berkeley directories are different */
  697.     DIR    *dp, *opendir();
  698.     struct    direct    *dirptr, *readdir();
  699.  
  700.     if(chdir(cur_path)<0)
  701.         return;
  702.     if((dp=opendir("."))==NULL)
  703.         return;
  704.     tdptr = *dptr;
  705.     touch = time((long *)0);
  706.     while((dirptr=readdir(dp))!=NULL) {
  707.         strcpy(name,dirptr->d_name);
  708.         inode = dirptr->d_fileno;
  709. #endif BSD
  710.  
  711. #ifdef SYSTEMV
  712.     struct    direct    d;
  713.     int    fd;
  714.  
  715.     if(chdir(cur_path)<0)
  716.         return;
  717.     if((fd=open(".",O_RDONLY))<0)
  718.         return;
  719.     tdptr = *dptr;
  720.     touch = time((long *)0);
  721.     while(read(fd,&d,sizeof(struct direct)) == sizeof(struct direct)) {
  722.         strncpy(name,d.d_name,DIRSIZ);
  723.         name[DIRSIZ]='\0';
  724.         inode = d.d_ino;
  725. #endif SYSTEMV
  726.         /* common entry-handling code */
  727.  
  728.         if(inode)    /* if this file wasn't removed, stat it */
  729.             if(stat(name,&st)<0)
  730.             continue;    /* can't stat? forget this one! */
  731.         if(name[0]=='.' && (modes&ILS_ALL)==0)
  732.             continue;    /* skip this, not in 'list all' mode */
  733.         done=0;
  734.         mxloop=0;/* mxloop is a safeguard.  It was used for
  735.                 initial debugging, and can probably be removed */
  736.         while(!done && mxloop++ < 10000) {
  737.             if((r=strcmp(name,tdptr->name))==0) {
  738.                 if(inode) {    /* copy over new stat struct */
  739.                     for(i=0, ps=(char *)&st,pd=(char *)&(tdptr->stat);i<sizeof(struct stat);i++)
  740.                         *pd++ = *ps++;
  741.                     /* flag this file as "touched" */
  742.                     tdptr->touched = touch;
  743.                 }
  744.                 done=1;    /* file found, move on to next */
  745.             }
  746.             else if(r<0 && inode) {    /* name < tdptr->name insert before? */
  747.                 if((tdptr->prev) == (struct d_entry *)NULL) {
  748.                     /* insert at top of list */
  749.                     new_entry(&t,name,&st);
  750.                     t->touched = touch;
  751.                     t->next = tdptr;
  752.                     tdptr->prev = t;
  753.                     *dptr = t;
  754.                     done=1;
  755.                 }
  756.                 else if(strcmp(name,tdptr->prev->name)>0) {
  757.                     /* insert above tdptr */
  758.                     new_entry(&t,name,&st);
  759.                     t->touched = touch;
  760.                     tdptr->prev->next = t;
  761.                     t->next = tdptr;
  762.                     t->prev = tdptr->prev;
  763.                     tdptr->prev = t;
  764.                     done=1;
  765.                 }
  766.                 else
  767.                     tdptr = tdptr->prev;
  768.             }
  769.             else if(inode) { /* name > tdptr->name  insert after? */
  770.                 if((tdptr->next) == (struct d_entry *)NULL) {
  771.                     /* insert at end of list */
  772.                     new_entry(&t,name,&st);
  773.                     t->touched = touch;
  774.                     tdptr->next = t;
  775.                     t->prev = tdptr;
  776.                     done=1;
  777.                 }
  778.                 else if(strcmp(name,tdptr->next->name)<0) {
  779.                     /* insert just below tdptr */
  780.                     new_entry(&t,name,&st);
  781.                     t->touched = touch;
  782.                     t->next = tdptr->next;
  783.                     tdptr->next = t;
  784.                     t->prev = tdptr;
  785.                     t->next->prev = t;
  786.                     done=1;
  787.                 }
  788.                 else
  789.                     tdptr = tdptr->next;
  790.             }
  791.             else
  792.                 done=1;
  793.         }
  794.     }
  795.  
  796.     /* loop through and remove all entries that have a different touch
  797.        if the touch value doesn't match, then file was removed and the
  798.        entry in the directory was used by a new filename. */
  799.     tdptr = *dptr;    /* start at top of directory */
  800.     while(tdptr != (struct d_entry *) NULL) {
  801.         if((tdptr->touched) != touch) {
  802.             /* need to remove this entry, see where it's at */
  803.             if(tdptr == (*dptr)) {
  804.                 /* at the top */
  805.                 *dptr = (*dptr)->next;
  806.                 (*dptr)->prev = (struct d_entry *)NULL;
  807.                 tdptr->next = (struct d_entry *)NULL;
  808.                 free_contents(tdptr);
  809.                 tdptr = *dptr;
  810.             }
  811.             else if(tdptr->next == (struct d_entry *)NULL) {
  812.                 /* at the bottom */
  813.                 tdptr->prev->next = (struct d_entry *)NULL;
  814.                 free_contents(tdptr);
  815.                 tdptr = (struct d_entry *) NULL;  /* end */
  816.             }
  817.             else {
  818.                 /* in the middle somewhere */
  819.                 t = tdptr->next;
  820.                 tdptr->prev->next = tdptr->next;
  821.                 tdptr->next->prev = tdptr->prev;
  822.                 tdptr->next = (struct d_entry *) NULL;
  823.                 free_contents(tdptr);
  824.                 tdptr = t;
  825.             }
  826.         }
  827.         else    /* try next entry */
  828.             tdptr = tdptr->next;
  829.     }
  830.  
  831. #ifdef BSD
  832.     closedir(dp);
  833. #endif BSD
  834. #ifdef SYSTEMV
  835.     close(fd);
  836. #endif SYSTEMV
  837. }
  838.  
  839. /* new_entry allocates memory for a new addition to a directory, then
  840. ** copies in the name and stat structure into the newly allocated structure.
  841. ** It copies nulls into all of the structure's pointers.
  842. **
  843. ** tex is to be assigned to the address of the new memory.
  844. ** name is the string to copy into the name field.
  845. ** st is a pointer to the stat structure to copy over.
  846. */
  847. new_entry(tex,name,st)
  848. struct    d_entry    **tex;
  849. char    *name;
  850. struct    stat    *st;
  851. {
  852.     struct    d_entry    *t;
  853.     register int    i;
  854.     char    *pd, *ps;
  855.  
  856.     if((*tex=t= (struct d_entry *) malloc(sizeof(struct d_entry)))==NULL) {
  857.         clear();
  858.         printw("OUT OF MEMORY!\n");
  859.         refresh();
  860.         ils_exit(1);
  861.     }
  862.     t->name = (char *)malloc(strlen(name)+1); /* alloc space for name */
  863.     strcpy(t->name,name);    /* copy name over */
  864.  
  865.     for(i=0, ps=(char *)st,pd=(char *)&(t->stat);i<sizeof(struct stat);i++)
  866.         *pd++ = *ps++;    /* copy stat over on byte at a time */
  867.  
  868.     t->next = (struct d_entry *) NULL;    /* null out all pointers */
  869.     t->prev = (struct d_entry *) NULL;
  870.     t->contents = (struct d_entry *) NULL;
  871. }
  872.  
  873. /* exit ils gracefully with 'code' as the exit code */
  874. ils_exit(code)
  875. int    code;
  876. {
  877.     noraw();    /* out of raw mode */
  878.     echo();        /* echo back on */
  879.     endwin();    /* exit curses */
  880.     exit(code);
  881. }
  882.