home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 1 / crawlyvol1.bin / utility / disk / undelete / fsel.c next >
C/C++ Source or Header  |  1993-02-14  |  44KB  |  916 lines

  1. /****************************************************************
  2. *
  3. * a new FSEL placed in public domain by D N Korte 26 Dec 86.
  4. * Do with it whatever you want...
  5. *
  6. * modified for undelete program & GNU c by T Blight, Dec 1992
  7. *
  8. *****************************************************************/
  9.  
  10. #include <aesbind.h>
  11. #include <gemfast.h>
  12. #include <osbind.h>
  13. #include <string.h>
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include <ctype.h>
  17. #include <errno.h>
  18. #include "undel.h"
  19.  
  20. #define QUIT     0
  21. #define CONTINUE 1
  22.  
  23. #define MAXFILES 144      /* abs max 327 (overflow FS_calc_curfirst) */
  24. #define WINDSIZE   9      /* size of file window */
  25. #define DIAMOND_THINGY 7
  26.  
  27. /*** indexes into rs_object ***/
  28. #define CANCBUT 2
  29. #define OKBUT   3
  30. #define NEWNAME 4
  31. #define WINDOW  5
  32. #define DRVA    6
  33. #define DRVB    7
  34. #define DRVC    8
  35. #define DRVD    9
  36. #define DRVE   10
  37. #define DRVF   11
  38. #define SLEXTN0 12
  39. #define SLEXTN1 13
  40. #define SLEXTN2 14
  41. #define SLEXTN3 15
  42. #define SLEXTN4 16
  43. #define EXTN3   17
  44. #define EXTN4   18
  45. #define FNAM1   19
  46. #define FNAM2   20
  47. #define FNAM3   21
  48. #define FNAM4   22
  49. #define FNAM5   23
  50. #define FNAM6   24
  51. #define FNAM7   25
  52. #define FNAM8   26
  53. #define FNAM9   27
  54. #define FILEBOX 28
  55. #define TOPBAR  29
  56. #define UARROW  30
  57. #define SLIDBOX 31
  58. #define MVSLIDE 32
  59. #define DARROW  33
  60. #define TOPTEXT 34
  61.  
  62. struct finfo {
  63.     char name[9];    /* name of file */
  64.     char extn[4];    /* extension of it */
  65.     BOOL  dirflag;    /* FALSE if not a directory, TRUE if is directory */
  66. };
  67.  
  68. PRIVATE void FS_dir_dis( struct finfo[], int[], int, int);
  69. PRIVATE void FS_dir_select_good( int, const char *, const char *, const char *,
  70.                                  char *, char *, struct finfo[], int, int[],
  71.                                  int *, int *);
  72. PRIVATE int FS_dir_read(char *drivs, char *path, struct finfo files[],
  73.                         int *numfiles, char *dispath);
  74. PRIVATE void FS_shift_curfirst(int, int, int *);
  75. PRIVATE void FS_calc_curfirst(int, int, int *);
  76. PRIVATE void FS_calc_slid_box(int, int, BOOL);
  77. PRIVATE void FS_setname( int, char *);
  78. PRIVATE void FS_path_lengthen( char *, int, struct finfo[], char *);
  79. PRIVATE void FS_path_shorten( char *, char *);
  80. PRIVATE void FS_pathtrunc( char *, const char *);
  81. PRIVATE BOOL FS_wildmatch( const char *, const char *);
  82. PRIVATE void FS_exchinfo( struct finfo *, struct finfo *);
  83. PRIVATE int FS_find_last_delim(char, char *);
  84. PRIVATE void FS_strxcpy(char *, const char*);
  85.  
  86.  
  87.  
  88. PRIVATE char file_ids[WINDSIZE][17]; /* spot for (10) 16-char formatted filenames in menu */
  89.  
  90. PRIVATE TEDINFO rs_tedinfo[] = {
  91.     NULL,"________.___","FFFFFFFFFFF",3,0,0,0x1180,0, 0,0,13, /* 0 for newname */
  92.     NULL,".___",        "",           3,0,2,0x1180,0,-2,0,5,  /* 1 for extn0   */
  93.     NULL,".___",        "",           3,0,2,0x1180,0,-2,0,5,  /* 2 for extn1   */
  94.     NULL,".___",        "",           3,0,2,0x1180,0,-2,0,5,  /* 3 for extn2   */
  95.     NULL,".___",        "FFF",        3,0,2,0x1180,0,-2,0,5,  /* 4 for extn3   */
  96.     NULL,".___",        "FFF",        3,0,2,0x1180,0,-2,0,5,  /* 5 for extn4   */
  97.     NULL,"",            "",           3,0,2,0x1180,0, 0,0,0   /* 6 for pathname in TOPBAR */
  98. };
  99. /*  ^        ^              ^         ^ ^ ^   ^    ^  ^ ^ ^
  100.     |        |              |         | | |   |    |  | | +-- te_tmplen length of template (+1 for null)
  101.     |        |              |         | | |   |    |  | ----- te_txtlen length of text     (+1 for null)
  102.     |        |              |         | | |   |    |  +------ te_thickness  border thickness (-) outside
  103.     |        |              |         | | |   |    +--------- te_junk2
  104.     |        |              |         | | |   +-------------- te_color packed color information
  105.     |        |              |         | | +------------------ te_just 0=left 1=right 2=centered
  106.     |        |              |         | +-------------------- te_junk1
  107.     |        |              |         +---------------------- te_font 3=system 5=small
  108.     |        |              +------------------------------- *te_pvalid ptr to validation chars
  109.     |        +---------------------------------------------- *te_ptmplt ptr to template
  110.     +------------------------------------------------------- *te_ptext  ptr to text
  111. */
  112.  
  113. PRIVATE OBJECT rs_object[] = {
  114.     -1,1,34,G_BOX,      NONE,                        OUTLINED,    0x21100L, 0, 0,38,15, /* 0 dialog box */
  115.     2,-1,-1,G_STRING,   NONE,                        NORMAL,            0L, 2, 1,34,1,  /* 1 TITLE */
  116.     3,-1,-1,G_BUTTON,   SELECTABLE|EXIT,             NORMAL,(unsigned long)"CANCEL",22, 3, 6,1,  /* 2 CANCBUT */
  117.     4,-1,-1,G_BUTTON,   SELECTABLE|EXIT|DEFAULT,     NORMAL,(unsigned long)"OK",30, 3, 6,1,  /* 3 OKBUT */
  118.     5,-1,-1,G_FTEXT,    EDITABLE,                    NORMAL,(unsigned long)&rs_tedinfo[0],22, 5,12,1,  /* 4 NEWNAME */
  119.     6,-1,-1,G_IBOX,     NONE,                        NORMAL,     0xFF1100L, 2, 3,18,11, /* 5 WINDOW (outline of pretend window) */
  120.     7,-1,-1,G_BUTTON,   SELECTABLE|EXIT|RBUTTON,     NORMAL,(unsigned long)"A:",22, 7, 4,1,  /* 6 DRVA */
  121.     8,-1,-1,G_BUTTON,   SELECTABLE|EXIT|RBUTTON,     NORMAL,(unsigned long)"B:",27, 7, 4,1,  /* 7 DRVB */
  122.     9,-1,-1,G_BUTTON,   SELECTABLE|EXIT|RBUTTON,     NORMAL,(unsigned long)"C:",32, 7, 4,1,  /* 8 DRVC */
  123.     10,-1,-1,G_BUTTON,  SELECTABLE|EXIT|RBUTTON,     NORMAL,(unsigned long)"D:",22, 9, 4,1,  /* 9 DRVD */
  124.     11,-1,-1,G_BUTTON,  SELECTABLE|EXIT|RBUTTON,     NORMAL,(unsigned long)"E:",27, 9, 4,1,  /* 10 DRVE */
  125.     12,-1,-1,G_BUTTON,  SELECTABLE|EXIT|RBUTTON,     NORMAL,(unsigned long)"F:",32, 9, 4,1,  /* 11 DRVF */
  126.     13,-1,-1,G_FBOXTEXT,SELECTABLE|TOUCHEXIT,        NORMAL,(unsigned long)&rs_tedinfo[1],22,11, 4,1,  /* 12 SLEXTN0 */
  127.     14,-1,-1,G_FBOXTEXT,SELECTABLE|TOUCHEXIT,        NORMAL,(unsigned long)&rs_tedinfo[2],27,11, 4,1,  /* 13 SLEXTN1 */
  128.     15,-1,-1,G_FBOXTEXT,SELECTABLE|TOUCHEXIT,        NORMAL,(unsigned long)&rs_tedinfo[3],32,11, 4,1,  /* 14 SLEXTN2 */
  129.     16,-1,-1,G_BOX,     SELECTABLE|TOUCHEXIT,        NORMAL,     0xFE1100L,22,13, 2,1,  /* 15 SLEXTN3 */
  130.     17,-1,-1,G_BOX,     SELECTABLE|TOUCHEXIT,        NORMAL,     0xFE1100L,30,13, 2,1,  /* 16 SLEXTN4 */
  131.     18,-1,-1,G_FBOXTEXT,EDITABLE,                    NORMAL,(unsigned long)&rs_tedinfo[4],24,13, 4,1,  /* 17 EXTN3 */
  132.     28,-1,-1,G_FBOXTEXT,EDITABLE,                    NORMAL,(unsigned long)&rs_tedinfo[5],32,13, 4,1,  /* 18 EXTN4 */
  133.     20,-1,-1,G_STRING,  SELECTABLE|TOUCHEXIT|RBUTTON,NORMAL,(unsigned long)&file_ids[0][0], 0, 0,15,1,  /* 19 FNAM1 (note that for doubleclick */
  134.     21,-1,-1,G_STRING,  SELECTABLE|TOUCHEXIT|RBUTTON,NORMAL,(unsigned long)&file_ids[1][0], 0, 1,15,1,  /* 20 FNAM2 (to work, these objects must */
  135.     22,-1,-1,G_STRING,  SELECTABLE|TOUCHEXIT|RBUTTON,NORMAL,(unsigned long)&file_ids[2][0], 0, 2,15,1,  /* 21 FNAM3 (be G_STRING and must have */
  136.     23,-1,-1,G_STRING,  SELECTABLE|TOUCHEXIT|RBUTTON,NORMAL,(unsigned long)&file_ids[3][0], 0, 3,15,1,  /* 22 FNAM4 (ob_flags exactly as shown. */
  137.     24,-1,-1,G_STRING,  SELECTABLE|TOUCHEXIT|RBUTTON,NORMAL,(unsigned long)&file_ids[4][0], 0, 4,15,1,  /* 23 FNAM5 (When selected, bit 15 of */
  138.     25,-1,-1,G_STRING,  SELECTABLE|TOUCHEXIT|RBUTTON,NORMAL,(unsigned long)&file_ids[5][0], 0, 5,15,1,  /* 24 FNAM6 (form_do return will be */
  139.     26,-1,-1,G_STRING,  SELECTABLE|TOUCHEXIT|RBUTTON,NORMAL,(unsigned long)&file_ids[6][0], 0, 6,15,1,  /* 25 FNAM7 (set if gotten by a */
  140.     27,-1,-1,G_STRING,  SELECTABLE|TOUCHEXIT|RBUTTON,NORMAL,(unsigned long)&file_ids[7][0], 0, 7,15,1,  /* 26 FNAM8 (doubleclick. */
  141.     28,-1,-1,G_STRING,  SELECTABLE|TOUCHEXIT|RBUTTON,NORMAL,(unsigned long)&file_ids[8][0], 0, 8,15,1,  /* 27 FNAM9 */
  142.     29,19,27,G_BOX,     NONE,                        NORMAL,      0x011100L, 2, 4,15,10, /* 28 FILEBOX (box is parent for FNAMs) */
  143.     30,-1,-1,G_BOX,     NONE,                        NORMAL,      0xFF1121L, 2, 3,18,1,  /* 29 TOPBAR */
  144.     31,-1,-1,G_BOXCHAR, TOUCHEXIT,                   NORMAL,    0x01011180L,17, 4, 3,1,  /* 30 UARROW (adjust y later) */
  145.     33,32,32,G_BOX,     TOUCHEXIT,                   NORMAL,      0x011111L,17, 5, 3,7,  /* 31 SLIDBOX (adjust y later) */
  146.     31,-1,-1,G_BOX,     TOUCHEXIT,                   NORMAL,      0x011100L, 0, 0, 3,1,  /* 32 MVSLIDE */
  147.     34,-1,-1,G_BOXCHAR, TOUCHEXIT,                   NORMAL,    0x02011100L,17,12, 3,1,  /* 33 DARROW (adjust y and h later) */
  148.      0,-1,-1,G_TEXT,    LASTOB,                      NORMAL, (unsigned long)&rs_tedinfo[6], 3, 3,16,1   /* 34 TOPTEXT */
  149. };
  150. /*   ^  ^ ^    ^           ^                            ^        ^           ^  ^  ^ ^
  151.      |  | |    |           |                            |        |           |  |  | +-- ob_height height of obj (now chars, but
  152.      |  | |    |           |                            |        |           |  |  +---- ob_width  width  of obj (must cnvt to pixels
  153.      |  | |    |           |                            |        |           |  +------- ob_y      y coord relative to parent
  154.      |  | |    |           |                            |        |           +---------- ob_x      x coord relative to parent
  155.      |  | |    |           |                            |        +---------------------  ob_spec   obj determines meaning (p11-55,60)
  156.      |  | |    |           |                            +------------------------------  ob_state  current state of obj (p.11-61 MM)
  157.      |  | |    |           +-----------------------------------------------------------  ob_flags  attributes for obj (p.11-60 MM)
  158.      |  | |    +-----------------------------------------------------------------------  ob_type   object type (p. 11-59 MM)
  159.      |  | +----------------------------------------------------------------------------  ob_tail   ptr to last child of obj or -1
  160.      |  +------------------------------------------------------------------------------  ob_head   ptr to first child of obj or -1
  161.      +---------------------------------------------------------------------------------  ob_next   ptr to next sibling or -1
  162.  
  163. */
  164.  
  165. PRIVATE int xdial,ydial,wdial,hdial;         /* co-ord for dialog box */
  166.  
  167. PRIVATE int firstcall = TRUE;                /* for first-run initialization */
  168.  
  169. /*************************************************************************
  170.  *
  171.  * Function fsel ()
  172.  * This is what we're here for !!!
  173.  * Can't say much more 'cuz MM editor is almost full of characters.
  174.  *
  175.  *   The parameters are as follows:
  176.  *
  177.  *      stat        an integer returned by routine; 0=canc 1=ok
  178.  *      title       a string of up to 34 characters which will
  179.  *                  be displayed as the title or instructions line
  180.  *      path        a string representing the current path.
  181.  *                  This must both start and end with a '\' and
  182.  *                  may include any number of subdirectories
  183.  *                  within it.  The selector will return the
  184.  *                  user's path selection in this variable too
  185.  *                  so it should be a real variable of reasonable
  186.  *                  length (don't make it up as text in the
  187.  *                  parameter list itself!).
  188.  *      driv        An integer indicating which drive to use.
  189.  *                  code is as follows;
  190.  *                      -1 use current default drive
  191.  *                       0 A:
  192.  *                       1 B:
  193.  *                       ...
  194.  *                       5 F:
  195.  *                  The selector will return the user's drive
  196.  *                  selection in this variable too, so you should
  197.  *                  pass the address instead of the value.
  198.  *      sextn       An integer which indicates which of the five
  199.  *                  extension boxes should be used when matching
  200.  *                  filenames.  This is bit-mapped such that:
  201.  *                     0x0001 selects extn0
  202.  *                     0x0002 selects extn1
  203.  *                     0x0004 selects extn2
  204.  *                     0x0008 selects extn3
  205.  *                     0x0010 selects extn4
  206.  *                  More than one may be selected.  As above, the
  207.  *                  selector returns the user's suggestions, so
  208.  *                  this should be passed as an address too.
  209.  *      extn0 ...
  210.  *      extn4       There are 5 extension text variables.  These
  211.  *                  should all be 3 characters long (plus the
  212.  *                  terminator of course) and should not include
  213.  *                  the '.' (dot) which normally preceeds an
  214.  *                  extension.  The first three will not be
  215.  *                  changed by the selector and so may be defined
  216.  *                  as constants in the calling line if desired.
  217.  *                  The last two will be modified by the selector
  218.  *                  and thus must be defined as real variables.
  219.  *                  In all cases, the string must have all 3
  220.  *                  characters defined (use trailing blanks or
  221.  *                  underscores for short extensions).  A '*'
  222.  *                  will match anything; a '?' in any position
  223.  *                  will match any character in that position.
  224.  *      fullname    This is where the selector returns the user's
  225.  *                  selected name and path.  The string should be
  226.  *                  long enough to hold the largest anticipated
  227.  *                  string.  The returned string will include
  228.  *                  the drive specifier (i.e. A:), the full path
  229.  *                  specified, and the file name itself.
  230.  */
  231. int
  232. fsel(const char *title,    /* I  display title for box */
  233.      char *path,     /* IO initial path spec \ ... \ no drive; returns selected path */
  234.      int  *driv,     /* IO selects drive -1=default 0=A: .. 5=F: */
  235.      int  *sextn,    /* IO bitmap selected extn boxes :
  236.                       *    0x0001 = extn0    0x0002 = extn1    0x0004 = extn2
  237.                       *    0x0008 = extn3    0x0010 = extn4
  238.                       */
  239.      char *extn0,
  240.      char *extn1,    /* I  extension text not including "." for each of 1st 3 extn boxes  */
  241.      char *extn2,    /*    NOTE for all 5 boxes this should be 3 chars long, even if spaces   */
  242.      char *extn3,
  243.      char *extn4,    /* IO extension text for last 2 extn boxes (editable) */
  244.      char *fullname) /* O  returns complete path and file */
  245.  
  246. {
  247.  
  248. struct finfo files[MAXFILES];           /* holds name, extn, dir for all files */
  249.  
  250. char newname[12],                       /* holds user-typed name */
  251.      fnam[13],                           /* will build return filename here */
  252.      c,
  253.      drivs[3],                           /* current dir as string i.e. "B:" */
  254.      dispath[17];                       /* displayable pathname (trunc to 16 chars max) */
  255.  
  256. int  i,fp,ret,x,y,w,h;
  257. int  action,                           /* flag */
  258.      button,                           /* button code from dialog box */
  259.      slidpsn,                          /* slider position 0-1000 */
  260.      goodfiles[MAXFILES],               /* has indices into 'files[]' of files matching extn specifications */
  261.      numfiles,                         /* total number of files in 'files[]' */
  262.      numgood,                           /* number of files noted in 'goodfiles[]' */
  263.      curfirst,                           /* index into 'goodfiles[]' of first displayable file */
  264.      hchar,                               /* height of character in pixels */
  265.      my,                               /* mouse position y coordinate */
  266.      doubleclick,                       /* TRUE if double-clicked on item, else FALSE */
  267.      editfield;                           /* index of field to edit */
  268. int  t;                    /* holds drivemap */
  269.  
  270.     /*
  271.      * On the very first call to this subroutine we must do some
  272.      * setup stuff...  Primarily adjustments to the resource table
  273.      * to adjust for screen resolution, and to adjust element locations
  274.      * which do not live on even character boundaries.
  275.      */
  276.     if (firstcall) {
  277.         firstcall = FALSE;
  278.  
  279.         for(i=0; i<=HIGH(rs_object); i++)
  280.             rsrc_obfix(rs_object,i);        /* chg coord from char to pixel */
  281.  
  282.         /*
  283.          * also adjust size of SLIDBOX and xxARROWs into half-char sizes
  284.          * because 1 char tall is too short to allow boxchar to display the arrows,
  285.          * but 2 chars tall looks silly.
  286.          */
  287.         i=graf_handle(&ret,&hchar,&ret,&ret);
  288.         rs_object[UARROW].ob_height += hchar/2;
  289.         rs_object[DARROW].ob_y      += hchar/2;
  290.         rs_object[DARROW].ob_height += hchar/2;
  291.         rs_object[SLIDBOX].ob_y     += hchar/2;
  292.  
  293.         /*
  294.          * and similarly, adjust position of filenames in menu box
  295.          * so that 9 fit nicely into a box that tightly fits 10
  296.          */
  297.          for (i=0; i<WINDSIZE; i++) {
  298.              rs_object[FNAM1+i].ob_y += hchar/2;
  299.          } /* for */
  300.     } /* if (firstcall) ... */
  301.  
  302.     strcpy(newname,"___________");
  303.     rs_tedinfo[0].te_ptext = newname;
  304.     rs_tedinfo[1].te_ptext = extn0 ;
  305.     rs_tedinfo[2].te_ptext = extn1 ;
  306.     rs_tedinfo[3].te_ptext = extn2 ;
  307.     rs_tedinfo[4].te_ptext = extn3 ;
  308.     rs_tedinfo[5].te_ptext = extn4 ;
  309.     rs_tedinfo[6].te_ptext = dispath  ;
  310.  
  311.  
  312.     for (i=0; i<=HIGH(rs_tedinfo); i++) {
  313.         rs_tedinfo[i].te_txtlen = strlen(rs_tedinfo[i].te_ptext) + 1 ;
  314.     }
  315.  
  316.     rs_object[1].ob_spec  = (unsigned long)title;
  317.     FS_pathtrunc(dispath,path);
  318.     for (i=0; i<WINDSIZE; i++) strcpy(&file_ids[i][0],"                ");
  319.     editfield = NEWNAME;
  320.  
  321.     /*
  322.      * If user passed blanks for editable extensions, this is good
  323.      * but it will look funny -- put in initial underscores instead,
  324.      * also if he just passed unitialized (empty) string do it too.
  325.      * We must assume that string will be long enough...
  326.      */
  327.     if((extn3[0] == ' ') OR (strlen(extn3) == 0)) strcpy(extn3,"___");
  328.     if((extn4[0] == ' ') OR (strlen(extn4) == 0)) strcpy(extn4,"___");
  329.  
  330.     if (*sextn & 0x0001) rs_object[SLEXTN0].ob_state |= SELECTED;
  331.     if (*sextn & 0x0002) rs_object[SLEXTN1].ob_state |= SELECTED;
  332.     if (*sextn & 0x0004) rs_object[SLEXTN2].ob_state |= SELECTED;
  333.     if (*sextn & 0x0008) rs_object[SLEXTN3].ob_state |= SELECTED;
  334.     if (*sextn & 0x0010) rs_object[SLEXTN4].ob_state |= SELECTED;
  335.  
  336.     if (*driv  == -1)     *driv = Dgetdrv();            /* get cur logged drive if needed */
  337.     rs_object[(*driv)+DRVA].ob_state |= SELECTED;
  338.     drivs[0] = (*driv) +'A' ;    drivs[1] = ':' ;   drivs[2] = '\0' ;
  339.  
  340.     t = Drvmap();
  341.     if ((t & 0x01) == 0) rs_object[DRVA].ob_state = DISABLED;
  342.     if ((t & 0x02) == 0) rs_object[DRVB].ob_state = DISABLED;
  343.     if ((t & 0x04) == 0) rs_object[DRVC].ob_state = DISABLED;
  344.     if ((t & 0x08) == 0) rs_object[DRVD].ob_state = DISABLED;
  345.     if ((t & 0x10) == 0) rs_object[DRVE].ob_state = DISABLED;
  346.     if ((t & 0x20) == 0) rs_object[DRVF].ob_state = DISABLED;
  347.     
  348.     form_center (&rs_object,&xdial,&ydial,&wdial,&hdial);
  349.     x=y=w=h=0;
  350.     form_dial (0,x,y,w,h,xdial,ydial,wdial,hdial);      /* reserve room */
  351.     form_dial (1,x,y,w,h,xdial,ydial,wdial,hdial);      /* grow box */
  352.     objc_draw (&rs_object,0,2,xdial,ydial,wdial,hdial); /* draw the dialog box */
  353.  
  354.  
  355.  
  356.  
  357.     FS_dir_read(drivs, path, files, &numfiles, dispath);
  358.     FS_dir_select_good(*sextn,extn0,extn1,extn2,extn3,extn4,
  359.                     files, numfiles, goodfiles, &numgood, &curfirst);
  360.     FS_calc_slid_box(numgood,curfirst,FALSE);             /* calculate initial slider position */
  361.  
  362.     FS_dir_dis(files,goodfiles,numgood,curfirst);
  363.  
  364.     action = CONTINUE;                                       /* look for new button press */
  365.     while (action == CONTINUE) {                           /* loop while operator plays */
  366.  
  367.         if (rs_object[SLEXTN3].ob_state & SELECTED)     /* setup status of (SL)EXTN3 click-ability */
  368.             rs_object[EXTN3].ob_flags = TOUCHEXIT;
  369.         else
  370.             rs_object[EXTN3].ob_flags = EDITABLE;
  371.  
  372.         if (rs_object[SLEXTN4].ob_state & SELECTED)     /* setup status of (SL)EXTN4 click-ability */
  373.             rs_object[EXTN4].ob_flags = TOUCHEXIT;
  374.         else
  375.             rs_object[EXTN4].ob_flags = EDITABLE;
  376.  
  377.         button = form_do(&rs_object,editfield);            /* manage user's actions until a button press */
  378.         if (button & 0x8000) {                            /* if double-click ... */
  379.             doubleclick  = TRUE;
  380.             button      &= ~0x8000;                        /* (remove double-click bit from botton code) */
  381.         }
  382.         else
  383.             doubleclick  = FALSE;
  384.  
  385.         switch (button) {                                /* now prepare to act upon user's request */
  386.             case CANCBUT: action = QUIT; rs_object[CANCBUT].ob_state &= ~SELECTED; break;
  387.             case OKBUT:   action = QUIT; rs_object[OKBUT].ob_state   &= ~SELECTED; break;
  388.  
  389.             case DRVA:
  390.             case DRVB:
  391.             case DRVC:
  392.             case DRVD:
  393.             case DRVE:
  394.             case DRVF:    *driv = button - DRVA;
  395.                           drivs[0] = (*driv) + 'A'; drivs[1] = ':';  drivs[2] = '\0';
  396.                           strcpy(path,"\\");
  397.                           FS_pathtrunc(dispath,path);
  398.                           FS_dir_read(drivs,path,files,&numfiles,dispath);
  399.                           FS_dir_select_good(*sextn,extn0,extn1,extn2,extn3,extn4,
  400.                                 files,numfiles,goodfiles,&numgood,&curfirst);
  401.                           FS_dir_dis(files,goodfiles,numgood,curfirst);
  402.                           FS_setname(-1,newname);
  403.                           break;
  404.  
  405.             case SLEXTN0:
  406.             case SLEXTN1:
  407.             case SLEXTN2:
  408.             case SLEXTN3:
  409.             case SLEXTN4: i = 0x01 << (button - SLEXTN0);
  410.                           *sextn ^= i ;
  411.                           FS_dir_select_good(*sextn,extn0,extn1,extn2,extn3,extn4,
  412.                                 files,numfiles,goodfiles,&numgood,&curfirst);
  413.                           FS_dir_dis(files,goodfiles,numgood,curfirst);
  414.                           FS_setname(-1,newname);
  415.                           break;
  416.  
  417.             case FNAM1:
  418.             case FNAM2:
  419.             case FNAM3:
  420.             case FNAM4:
  421.             case FNAM5:
  422.             case FNAM6:
  423.             case FNAM7:
  424.             case FNAM8:
  425.             case FNAM9: i = button - FNAM1;
  426.                         fp= goodfiles[curfirst+i] ;                            /* (fp points into files[]) */
  427.                         if (files[fp].dirflag) {                            /* if a directory of any flavor */
  428.                             if (strcmp(files[fp].name,".") == 0)             /* current directory */
  429.                                   /* do nothing special */ ;
  430.                               else if (strcmp(files[fp].name,"..") == 0) {    /* parent directory */
  431.                                   FS_path_shorten(path,dispath);
  432.                                   FS_dir_read(drivs,path,files,&numfiles,dispath);
  433.                                   FS_dir_select_good(*sextn,extn0,extn1,extn2,extn3,extn4,
  434.                                     files,numfiles,goodfiles,&numgood,&curfirst);
  435.                             }
  436.                             else {                                            /* another directory */
  437.                                 FS_path_lengthen(path,fp,files,dispath);
  438.                                 FS_dir_read(drivs,path,files,&numfiles,dispath);
  439.                                   FS_dir_select_good(*sextn,extn0,extn1,extn2,extn3,extn4,
  440.                                     files,numfiles,goodfiles,&numgood,&curfirst);
  441.                               }
  442.                               FS_dir_dis(files,goodfiles,numgood,curfirst);    /* then always display the selected directory */
  443.                               FS_setname(-1,newname);
  444.                           }                                                    /* end of 'if a directory' stuff */
  445.                           else {                                            /* here it must be just a file */
  446.                              FS_setname(i,newname);
  447.                              if (doubleclick) {                                /* a doubleclick causes default OKBUT too */
  448.                                  action   = QUIT;
  449.                                  button   = OKBUT;
  450.                              }
  451.                           }
  452.                           break;
  453.             case MVSLIDE: if (rs_object[SLIDBOX].ob_height==rs_object[MVSLIDE].ob_height) break;     /* do nothing if full size */
  454.                           slidpsn = graf_slidebox(&rs_object,SLIDBOX,MVSLIDE,1);
  455.                           FS_calc_curfirst(slidpsn,numgood,&curfirst);
  456.                           FS_calc_slid_box(numgood,curfirst,TRUE);
  457.                           FS_dir_dis(files,goodfiles,numgood,curfirst);
  458.                           FS_setname(-1,newname);
  459.                           break;
  460.             case SLIDBOX: graf_mkstate(&ret,&my,&ret,&ret);
  461.                           if (my > (ydial+rs_object[SLIDBOX].ob_y+rs_object[MVSLIDE].ob_y))
  462.                              FS_shift_curfirst(WINDSIZE,numgood,&curfirst);
  463.                           else
  464.                                FS_shift_curfirst(-WINDSIZE,numgood,&curfirst);
  465.                           FS_calc_slid_box(numgood,curfirst,TRUE);
  466.                           FS_dir_dis(files,goodfiles,numgood,curfirst);
  467.                           FS_setname(-1,newname);
  468.                           break;
  469.             case UARROW:  FS_shift_curfirst(-1,numgood,&curfirst);
  470.                           FS_calc_slid_box(numgood,curfirst,TRUE);
  471.                           FS_dir_dis(files,goodfiles,numgood,curfirst);
  472.                           FS_setname(-1,newname);
  473.                           break;
  474.             case DARROW:  FS_shift_curfirst(1,numgood,&curfirst);
  475.                           FS_calc_slid_box(numgood,curfirst,TRUE);
  476.                           FS_dir_dis(files,goodfiles,numgood,curfirst);
  477.                           FS_setname(-1,newname);
  478.                           break;
  479.  
  480.                           /*
  481.                            * to get to EXTN3 then EXTN3 must have been TOUCHEXIT
  482.                            * which means that SLEXTN3 must have been SELECTED.
  483.                            * When we touched on the EXTN3 field we signify that we
  484.                            * want to edit it -- therefore we unSELECT the box so
  485.                            * that we can force a directory read when it next gets selected.
  486.                            */
  487.             case EXTN3:      rs_object[EXTN3].ob_flags = EDITABLE;
  488.                           objc_change(&rs_object,SLEXTN3,0,xdial,ydial,wdial,hdial,NORMAL,1);
  489.                           *sextn &= ~0x0008;
  490.                           editfield = EXTN3;
  491.                           break;
  492.  
  493.                           /* similar logic here... */
  494.             case EXTN4:      rs_object[EXTN4].ob_flags = EDITABLE;
  495.                           objc_change(&rs_object,SLEXTN4,0,xdial,ydial,wdial,hdial,NORMAL,1);
  496.                           *sextn &= ~0x0010;
  497.                           editfield = EXTN4;
  498.                           break;
  499.         }    /* end of switch(button)    */
  500.     }        /* end of while(action) */
  501.  
  502.     form_dial (2,x,y,w,h,xdial,ydial,wdial,hdial);  /* shrink dialog box */
  503.     form_dial (3,x,y,w,h,xdial,ydial,wdial,hdial);  /* release its room */
  504.  
  505.     for (i=0; i<8; i++) {                            /* build formatted filename from newname */
  506.         if ((c=newname[i]) == ' ') break ;            /* (scan name part until ends at space */
  507.         if ( c == '_' ) break;                        /* (also stops at _ in case no name was ever selected! */
  508.         fnam[i]   = c;
  509.         fnam[i+1] = '\0';
  510.     }
  511.     if((newname[8] != ' ') AND (newname[8] != '_')) {    /* (if there is an extension) */
  512.         fnam[i++] = '.';
  513.         fnam[i]   = '\0';
  514.         strcat(&fnam[i],&newname[8]);
  515.     }
  516.  
  517.     strcpy(fullname,drivs);                            /* finally, build a returnable name with full path info too */
  518.     strcat(fullname,path);
  519.     strcat(fullname,fnam);
  520.  
  521.     if (button == CANCBUT) return (0);                /* then return */
  522.     return(1);
  523. } /* fsel() */
  524.  
  525.  
  526. /************************************************************
  527.  * function FS_shift_curfirst() is called when the slider
  528.  * is moved by an arrow key or a pageup/pagedn request.
  529.  * it returns a new value for curfirst (index into goodfiles)
  530.  */
  531. PRIVATE void
  532. FS_shift_curfirst(int  inc,      /* typically -1,1 (arrow), -9,+9 pagedn,pageup */
  533.                   int  numgood,  /* total number of good files */
  534.                   int *curfirst) /* returns new value for curfirst */
  535. {
  536.     *curfirst += inc;        /* change it as requested */
  537.  
  538.     /* then fix it if necessary */
  539.     if (*curfirst > (numgood-WINDSIZE)) *curfirst = numgood-WINDSIZE;
  540.     if (*curfirst < 0) *curfirst = 0;
  541. } /* FS_shift_curfirst() */
  542.  
  543.  
  544. /*********************************************************
  545.  * function FS_calc_curfirst() is called after
  546.  * a boxslide operation to find new value for curfirst.
  547.  */
  548. PRIVATE void
  549. FS_calc_curfirst(int  slidpsn,        /* slider psn as returned from graf_slidbox 0-1000 */
  550.                  int  numgood,        /* total number of good files */
  551.                  int *curfirst)       /* returned index into goodfiles */
  552. {
  553.     *curfirst = (numgood * (slidpsn/10)) / 100 ;   /* funny scaling to avoid arith overflow */
  554.     if (*curfirst > (numgood - WINDSIZE)) *curfirst = numgood - WINDSIZE;
  555. } /* FS_calc_curfirst() */
  556.  
  557.  
  558. /*****************************************************
  559.  * function FS_calc_slid_box() is called to calculate
  560.  * new dimensions for the moving box, and draw it if necessary.
  561.  */
  562. PRIVATE void
  563. FS_calc_slid_box(int numgood,            /* number of good files */
  564.                  int curfirst,           /* index into goodfiles[] */
  565.                  BOOL    drawit)         /* FALSE = don't draw, TRUE = please draw */
  566. {
  567.     if (numgood <= WINDSIZE) {               /* then sliding box is full size */
  568.         rs_object[MVSLIDE].ob_y      = 0;    /* position at top (rel to parent) */
  569.         rs_object[MVSLIDE].ob_height = rs_object[SLIDBOX].ob_height;
  570.     }
  571.     else {
  572.         rs_object[MVSLIDE].ob_height = (rs_object[SLIDBOX].ob_height * WINDSIZE) / numgood ;
  573.         rs_object[MVSLIDE].ob_y      = (rs_object[SLIDBOX].ob_height * curfirst) / numgood ;
  574.     }
  575.  
  576.     if (drawit) objc_draw(&rs_object,SLIDBOX,2,xdial,ydial,wdial,hdial);
  577. } /* FS_calc_slid_box() */
  578.  
  579.  
  580. /***************************************************************
  581.  * function FS_setname() sets a filename or blanks into the NEWNAME field
  582.  * if i== -1 then blanks are set, otherwise file_ids[i] is set
  583.  */
  584. PRIVATE void FS_setname( int i, char *newname)
  585. {
  586.     if (i == -1)
  587.         strcpy(newname,"___________");
  588.     else {
  589.         strncpy(newname,&file_ids[i][2],8);
  590.         strncpy(&newname[8],&file_ids[i][11],3);
  591.     }
  592.     objc_draw(&rs_object,NEWNAME,1,xdial,ydial,wdial,hdial);
  593. } /* FS_setname() */
  594.  
  595.  
  596. /***************************************
  597.  * function FS_dir_read() reads specified directory
  598.  * and stores names in 'files' array.  Also adjusts numfiles.
  599.  * function returns 0 on error 1 on success
  600.  */
  601. PRIVATE int FS_dir_read(char *drivs, char *path, struct finfo files[],
  602.                         int *numfiles, char *dispath)
  603. {
  604. char fullname[14];                            /* full name of file from dta */
  605. int   dotat,error,i,numdirs,exch;
  606. char  fullpath[80];                            /* full path spec with driv, pathlist, and *.*  */
  607. struct _dta *dtap;
  608.  
  609.     *numfiles = 0;                            /* no files found yet */
  610.     dtap = (struct _dta *)Fgetdta();
  611.  
  612.     do {
  613.         strcpy(fullpath, drivs);
  614.         strcat(fullpath, path);
  615.         strcat(fullpath, "*.*");
  616.         error = d_First(drivs, path, FA_DIR);
  617.         if (error == -33) {
  618.             i = form_alert(2,"[1][You have specified either|an empty disk or a nonexistant path...][CONTINUE|RETRY|BACKUP PATH]");
  619.             switch(i) {
  620.                 case 1: return(1);            /* quit indicating success (?) */
  621.                 case 2: break;                /* just do it again */
  622.                 case 3: FS_path_shorten(path,dispath);
  623.             }
  624.         }
  625.         else if (error != 0) {
  626.             char  emsg[80];
  627.             sprintf( emsg, "[1][%s|%s][QUIT]", sys_errlist[-error], fullpath);
  628.             form_alert(1,emsg);
  629.             exit(1);              /* quit  */
  630.         } /* if */
  631.     } while (error == -33);
  632.  
  633.     while (error == 0) {
  634.         strcpy(fullname,dtap->dta_name);
  635.         if(fullname[0] == '.') {               /* then a directory . or .. */
  636.             strcpy(files[*numfiles].name,fullname);
  637.             strcpy(files[*numfiles].extn,"");
  638.         }
  639.         else {                                  /* a real file */
  640.  
  641.             dotat = FS_find_last_delim('.',fullname);
  642.             if (dotat == -1) {
  643.                 strcpy(files[*numfiles].extn,"");
  644.                 strcpy(files[*numfiles].name,fullname);
  645.             }
  646.             else {
  647.                 strcpy(files[*numfiles].extn,&fullname[dotat+1]);
  648.                 strncpy(files[*numfiles].name,fullname,dotat);
  649.                 files[*numfiles].name[dotat] = '\0';
  650.             }
  651.         }
  652.         files[*numfiles].dirflag = (dtap->dta_attribute & FA_DIR) != 0;
  653.         (*numfiles)++;                                /* count the discovered file */
  654.         if (*numfiles > MAXFILES-1) {                /* is this possible??? */
  655.             *numfiles = MAXFILES-1;                    /* if so, just ignore later files */
  656.             return(1);                                /* kinda sloppy huh ??? */
  657.         }
  658.         error = d_Next();                            /* then look for another */
  659. } /* while */
  660.  
  661.     /* now find all directories and put at beginning of list */
  662.     numdirs = 0;
  663.     for (i=0; i< *numfiles; i++) {
  664.         if(files[i].dirflag) {
  665.             FS_exchinfo(&files[numdirs],&files[i]); /* if dir, swap to beginning of list */
  666.             numdirs++;                                /* and count it */
  667.         }
  668.     }
  669.  
  670.     /* now sort the directories */
  671.     if ((numdirs) > 1) {
  672.         do {
  673.             exch = FALSE;
  674.             for(i=0; i<numdirs-1; i++) {            /* for all directories */
  675.                 if(strcmp(files[i].name,files[i+1].name) > 0) {
  676.                     FS_exchinfo(&files[i],&files[i+1]);
  677.                 }
  678.             }
  679.         } while (exch == TRUE);
  680.     }
  681.  
  682.     /* and now sort real files */
  683.     if ((*numfiles-numdirs) > 1) {
  684.         do {
  685.             exch = FALSE;
  686.             for(i=numdirs; i< *numfiles-1; i++) {    /* for all files */
  687.                 if(strcmp(files[i].name,files[i+1].name) > 0) {
  688.                     FS_exchinfo(&files[i],&files[i+1]);
  689.                     exch = TRUE;
  690.                 }
  691.             }
  692.         } while (exch == TRUE);
  693.     }
  694.  
  695.     /* all done so return status */
  696.     if (error == -ENMFILES) return (1) ;                /* success if error = "no more files" */
  697.      return(0);                                         /* else a problem */
  698. } /* FS_dir_read() */
  699.  
  700.  
  701. /**************************************************
  702.  * function FS_dir_select_good() scans files[] for files matching at least one of
  703.  * specified extensions.  Counts matches in numgood, stores index (into files[])
  704.  * in goodfiles[]. Also sets curfirst = 0 so later display will start at beginning.
  705.  */
  706. PRIVATE void
  707. FS_dir_select_good( int sextn,       /* the mask specifying checkable extensions */
  708.                     const char *extn0,     /* the extensions to try matching */
  709.                     const char *extn1,
  710.                     const char *extn2,
  711.                     char *extn3,
  712.                     char *extn4,
  713.                     struct finfo files[],
  714.                     int numfiles,
  715.                     int goodfiles[],
  716.                     int *numgood,
  717.                     int *curfirst)
  718. {
  719. int i;
  720.  
  721.     *curfirst = 0;
  722.     *numgood  = 0;
  723.  
  724.     for (i=0; i<numfiles; i++) {                    /* always match directories */
  725.         if(files[i].dirflag) {
  726.             goodfiles[(*numgood)++] = i;
  727.             continue;
  728.         }
  729.         if((sextn & 0x01) AND FS_wildmatch(extn0,files[i].extn)) {
  730.             goodfiles[(*numgood)++] = i;
  731.             continue;
  732.         }
  733.         if((sextn & 0x02) AND FS_wildmatch(extn1,files[i].extn)) {
  734.             goodfiles[(*numgood)++] = i;
  735.             continue;
  736.         }
  737.         if((sextn & 0x04) AND FS_wildmatch(extn2,files[i].extn)) {
  738.             goodfiles[(*numgood)++] = i;
  739.             continue;
  740.         }
  741.         if((sextn & 0x08) AND FS_wildmatch(extn3,files[i].extn)) {
  742.             goodfiles[(*numgood)++] = i;
  743.             continue;
  744.         }
  745.         if((sextn & 0x10) AND FS_wildmatch(extn4,files[i].extn)) {
  746.             goodfiles[(*numgood)++] = i;
  747.             continue;
  748.         }
  749.     }
  750. }
  751.  
  752. /*
  753.  * function FS_dir_dis() displays current directory in window.  It displays
  754.  * at max WINDSIZE names, starting at 'curfirst' in files[].
  755.  */
  756. PRIVATE void
  757. FS_dir_dis( struct finfo files[],
  758.             int          goodfiles[],
  759.             int          numgood,
  760.             int          curfirst)
  761. {
  762. int i,j;
  763.  
  764.     /* first, clear out display strings */
  765.     for (i=0; i<WINDSIZE; i++) {
  766.         for(j=0; j<16; j++)
  767.             file_ids[i][j] = ' ';
  768.         file_ids[i][16]    = '\0';
  769.     }
  770.  
  771.     /* now build  at most WINDSIZE filenames */
  772.     for (i=0,j=curfirst; i<WINDSIZE; i++,j++) {
  773.         if (j >= numgood) break;                                /* in case not enough good files to fill window */
  774.         FS_strxcpy(&file_ids[i][2],files[goodfiles[j]].name);    /* put in basic filename */
  775.         if (strlen(files[goodfiles[j]].extn) > 0) {                /* if there is an extension... */
  776.             file_ids[i][10] = '.';
  777.             FS_strxcpy(&file_ids[i][11],files[goodfiles[j]].extn);
  778.         }
  779.         if (files[goodfiles[j]].dirflag)
  780.             file_ids[i][0]  = DIAMOND_THINGY;                    /* put in funny box if its a directory */
  781.     }
  782.  
  783.     /* and finally 'print' all to screen */
  784.     for (i=0; i< WINDSIZE; i++)
  785.         rs_object[FNAM1+i].ob_state = NORMAL;                    /* unselect all filenames */
  786.     objc_draw(&rs_object,FILEBOX,2,xdial,ydial,wdial,hdial);    /* blank the FILEBOX then write in all filenames */
  787.     FS_calc_slid_box(numgood,curfirst,1);                        /* redraw sliding box too */
  788.     objc_draw(&rs_object,TOPBAR, 0,xdial,ydial,wdial,hdial);    /* redraw TOPBAR to erase old path name */
  789.     objc_draw(&rs_object,TOPTEXT,0,xdial,ydial,wdial,hdial);    /* then redraw TOPTEXT  so that new path is shown */
  790. }
  791.  
  792.  
  793. /*******************************************************
  794.  * function FS_path_lengthen() is called to add a newly
  795.  * selected name to the current pathlist.  It is assumed that
  796.  * the newly selected name is a directory...
  797.  */
  798. PRIVATE void
  799. FS_path_lengthen( char *path,    /* the current path name (ends with '\') */
  800.                   int   index,   /* index into FS_files[] of name to add  */
  801.                   struct finfo files[],
  802.                   char * dispath)       /* the truncated displayable version of same */
  803. {
  804.     strcat(path,files[index].name);                /* add the name itself */
  805.     if (strlen(files[index].extn) > 0) {          /* (if there is an extension */
  806.         strcat(path,".");                        /* then append it */
  807.         strcat(path,files[index].extn);
  808.     }
  809.     strcat(path,"\\");                            /* and put on trailing backslash */
  810.     FS_pathtrunc(dispath,path);                    /* make displayable version */
  811. } /* FS_path_lengthen() */
  812.  
  813. /* 
  814.  * function FS_path_shorten() shortens the current path. 
  815.  * It is called after click on ".."
  816.  * Note that the path must always start and end with a '\' 
  817.  * character (will always have a length of at least 1).
  818.  */
  819. PRIVATE void FS_path_shorten( char *path, char *dispath)
  820. {
  821. int len,i;
  822.     
  823.     len=strlen(path);
  824.     if (len == 1) return;                /* already minimum path */
  825.     i=len-2;                            /* points at char before trailing slash */
  826.     while(path[i] != '\\') i-- ;        /* keep looking for a slash */
  827.     path[i+1] = '\0' ;                    /* and put a terminator after it */
  828.     FS_pathtrunc(dispath,path);            /* make displayable version */
  829. }
  830.  
  831. /* 
  832.  * function pathtrunc() truncates real pathname into shorter displayable version
  833.  */
  834. PRIVATE void FS_pathtrunc( char *dpath,    /* the output (destination) string */
  835.                            const char *spath)    /* the (maybe too long) source str */
  836. {
  837. int slen,i,is,id;
  838.  
  839.     if((slen=strlen(spath)) <= 16) strcpy(dpath,spath);    /* the trivial case */
  840.     else {
  841.         is = slen - 1 ;                    /* index of last char in string */
  842.         id = 15 ;                         /* last position in destination string */
  843.         for(i=0; i<14; i++)                /* copy 14 chars into 16 char field */
  844.             dpath[id--] = spath[is--];
  845.         dpath[0] = '<';                    /* and put little flags at beginning */
  846.         dpath[1] = '<';
  847.     }
  848. }
  849.  
  850. /* 
  851.  * function FS_wildmatch() checks a specified extension
  852.  * against a mask value for match, and returns TRUE if matched, else FALSE.
  853.  * Cases causing match are as follows:
  854.  *     exact match
  855.  *     mask value is "*"
  856.  *     match on all existing characters, with any '?' in mask matching anything
  857.  * Note that the mask value may have trailing spaces (" ") or underbars ("_") as
  858.  * a result of the object template process.  These are considered junk and are
  859.  * removed from the comparison process.
  860.  */
  861. PRIVATE BOOL FS_wildmatch( const char *mask, const char *candidate)
  862. {
  863. int masklen,i;
  864.  
  865.    if(mask[0]=='*') return(TRUE);         /*  a '*' in mask matches anything */
  866.  
  867.    masklen = strlen(mask);                /* will elim trailing spaces and underbars */
  868.    for(i=masklen-1; i>0; i--)                             /* check all but first char to see if it is ignorable */
  869.       if((mask[i]==' ') OR (mask[i]=='_')) masklen=i;    /* adjust length word to effect ignorance */
  870.    if(strlen(candidate) > masklen) return(FALSE);      /* candidate .OLD should not match mask .O */
  871.         
  872.    for(i=0; i<masklen; i++) {             /* now look at all valid chars to check for match */
  873.       if(mask[i] == '?') continue;        /* a '?' in mask matches anything in that position */
  874.       if(toupper(mask[i]) != toupper(candidate[i])) return(FALSE);    /* oops -- no match */
  875.    }
  876.     
  877.    return(TRUE);                                        /* must have matched ! */
  878. }
  879.     
  880.     
  881.  
  882. /*
  883.  * function FS_exchinfo() exchanges contents of two 'finfo' style structures 
  884.  */        
  885. PRIVATE void FS_exchinfo( struct finfo *x, struct finfo *y)
  886. {
  887. struct finfo t;
  888.  
  889.      t = *x;    /* caution -- */
  890.     *x = *y;    /* this all-in-one assignment is an extension that works in MM C */
  891.     *y =  t;    /* other C's take care ... */
  892. }
  893.     
  894.  
  895. PRIVATE int FS_find_last_delim(char delim, char *string)
  896. {
  897. int i,spot;
  898.  
  899.     spot = -1;
  900.     for (i=0; i<strlen(string); i++) 
  901.         if (string[i] == delim) spot = i;
  902.     return(spot);
  903. }
  904.  
  905. /*
  906.  * function FS_strxcpy() is just like strcpy except it does not copy 
  907.  * the terminating \0
  908.  */
  909. PRIVATE void FS_strxcpy(char *dest, const char *sour)
  910. {
  911. char c;
  912.     while ((c=*sour++) != '\0') *dest++ = c ;
  913. }
  914.  
  915. /************************* end of fsel.c ************************/
  916.