home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 602b.lha / StripANSI_v1.0 / Source / source.lzh / stdfile.c < prev    next >
C/C++ Source or Header  |  1991-08-02  |  22KB  |  964 lines

  1. /* STDFILE -- Standard File Requestor. Version 2.0a 15 June 1987
  2.  *
  3.  * AUTHOR -- Peter da Silva      US (713) 497-4372
  4.  *
  5.  * Copyright (c) 1987 Peter da Silva, all rights reserved.
  6.  *
  7.  *    This module may be freely used in any product, commercial or
  8.  *    otherwise, provided credit is given for this module and
  9.  *    and provided this notice remains intact in the source. The
  10.  *    intent of this module is to provide a standard file requestor
  11.  *    such as is available on the Macintosh, in GEM on the IBM-PC
  12.  *    and Atari ST, and in the Microsoft Windows software on the
  13.  *    IBM-PC. The advantage this module has over other requestors
  14.  *    is that it minimises disk accesses: an important consideration
  15.  *    given the structure of AmigaDos directories. If you need to
  16.  *    modify it for your needs, by all means go ahead... but please
  17.  *    conform to the intent of this program as stated above. If you
  18.  *    have suggestions for improvements, by all means call me at
  19.  *    the number listed above.
  20.  *
  21.  * Enhancements in the current version:
  22.  *
  23.  *    Gadgets now boxed. Display generally cleaned up.
  24.  *
  25.  *    True "dictionary order" for searches.
  26.  *
  27.  *    Default pattern can now be specified. Default file name now
  28.  *    specified in a single argument.
  29.  *
  30.  *    Directories always match.
  31.  *
  32.  *    Null pattern converted to "#?" universal wildcard.
  33.  *
  34.  *    If you attempt to build a file name longer than 128 characters the
  35.  *    screen will flash and the operation will be aborted.
  36.  *
  37.  *    "Volumes" gadget, using the device list code in "mounted". This
  38.  *    gadget brings up a list of all currently mounted volumes for
  39.  *    selection. Volumes leaves the directory specification intact, so
  40.  *    you can quickly return to where you left off.
  41.  *
  42.  *    "Parent" gadget, displays parent directory.
  43.  *
  44.  *    With these enhancements it is now possible to select any file on
  45.  *    any device without touching the keyboard. This is now release 2.0,
  46.  *    as it is significantly better than 1.0.
  47.  *
  48.  * Acknowledgements:
  49.  *
  50.  *    Thanks to Jeff Lydiatt for the pattern matching code in PatMatch.c
  51.  *    Thanks to Jay Miner, =RJ= and the whole Amiga team for the Amiga
  52.  *    itself.
  53.  *
  54.  * Environment:
  55.  *
  56.  *    IntuitionBase and GfxBase must be open. dos.library must be open
  57.  *    under the name "DOSBase". Link with PatMatch.o and VolList.o.
  58.  *
  59.  * Usage:
  60.  *
  61.  *    #define MAXFILENAME 128
  62.  *
  63.  *    int stdfile(title, default_file, default_pat, name);
  64.  *    char *title;
  65.  *    char *default_file;
  66.  *    char *default_pattern;
  67.  *    char name[MAXFILENAME];
  68.  *
  69.  *    struct Screen *stdscreen;
  70.  *
  71.  *    STDFILE puts up a file requestor (actually, it's a plain window)
  72.  *    in stdscreen. If stdscreen is NULL, the workbench screen is used.
  73.  *    The requestor looks like this (allowing for the limitations of
  74.  *    text):
  75.  *
  76.  *    +-----------------------------------+
  77.  *    |o| Title ------------------- |  |  | title parameter, or "File Name"
  78.  *    |-----------------------------------|
  79.  *    | Directory: [                    ] | Directory parameter, or current.
  80.  *    | File name: [                    ] | Default parameter, or empty.
  81.  *    | Pattern:   [                    ] | Initially empty, if the user
  82.  *    | +-------------------------------+ | enters anything here it will
  83.  *    | | [Filename]                 |  | | be used to select files. The
  84.  *    | | [Filename]                 |  | | file display will also be empty
  85.  *    | | [Filename]                 |@@| | to start with to avoid excess
  86.  *    | | [Filename]                 |@@| | disk I/O. If the user selects
  87.  *    | |                            |@@| | here the directory will be
  88.  *    | |                            |@@| | scanned looking for files
  89.  *    | |                            |  | | matching the specified pattern,
  90.  *    | |                            |  | | or "#?" if no pattern is given.
  91.  *    | |                            |  | |
  92.  *    | +-------------------------------+ | ACCEPT returns 1. CANCEL
  93.  *    | [ACCEPT]    [VOLUMES]    [CANCEL] | or the close gadget return 0.
  94.  *    +-----------------------------------+ VOLUMES displays volume names.
  95.  *
  96.  *    The number of filenames displayed is specified at compile time in the
  97.  *    constant MAXFILES. The maximum size of a filename is specified in the
  98.  *    constant MAXNAME. The parameter "Default file" will be broken into
  99.  *    directory and file parts.
  100.  */
  101. char *Copyright =
  102. "stdfile V2.0a. Copyright (c) 1987 Peter da Silva. All rights reserved.";
  103. #include <intuition/intuitionbase.h>
  104. #include <intuition/intuition.h>
  105. #include <libraries/dos.h>
  106. #include <exec/memory.h>
  107.  
  108. extern USHORT BusyPointer;
  109. extern int read_dir,dir_only;
  110. char *malloc();
  111.  
  112. #define MAXFILES 8
  113. #define MAXNAME 32
  114. #define MAXFULL (MAXNAME*4)
  115.  
  116. /* SIZING PARAMS */
  117. #define Z NULL
  118. #define INDENT 6
  119. #define LEFTMAR (INDENT-1)
  120. #define BORDER 3
  121. #define CHSIZ 8
  122. #define HT CHSIZ
  123. #define BASELINE 6
  124. #define BUTWID (6*CHSIZ+INDENT*2)
  125.  
  126. /* GADGET BORDERS */
  127. #define IN1 LEFTMAR+10*CHSIZ
  128. #define IN3 LEFTMAR+3
  129. #define IN4 -(INDENT+6*CHSIZ+1)
  130. #define IN5 -(INDENT+CHSIZ*2)
  131. #define IN6 ((WINWD-BUTWID)/3+INDENT)
  132. #define IN7 (((WINWD-BUTWID)*2)/3+INDENT)
  133. #define WD1 -(INDENT+IN1)
  134. #define WD3 (6*CHSIZ)
  135. #define WD4 (6*CHSIZ)
  136. #define WD5 (CHSIZ*2+2)
  137. #define WD6 (6*CHSIZ)
  138. #define WD7 (6*CHSIZ)
  139. #define TP1 (CHSIZ+BORDER)
  140. #define TP2 (TP1+HT+1)
  141. #define TP3 (TP2+HT+1)
  142. #define TP4 -(BORDER+HT4-1)
  143. #define TP5 (TP3+HT+BORDER)
  144. #define HT4 (HT+1)
  145. #define HT5 CHSIZ*MAXFILES+INDENT
  146.  
  147. #define WINHT (TP5 + HT5 + (-TP4) + BORDER)
  148. #define WINWD (INDENT*4 + (MAXNAME+2)*CHSIZ)
  149. #define WININ (640-WINWD)/2
  150. #define WINTP (200-WINHT)/2
  151.  
  152. #define HOMEX (INDENT+LEFTMAR)
  153. #define HOMEY (TP5+BORDER)
  154. #define LASTX (HOMEX+MAXNAME*CHSIZ)
  155. #define LASTY (HOMEY+MAXFILES*CHSIZ)
  156.  
  157. #define BTP TP5
  158. #define BIN LEFTMAR
  159. #define BWD (WINWD-INDENT-BIN)
  160. #define BHT (WINHT-BTP-(-TP4+BORDER+1))
  161.  
  162. #define SF GADGHCOMP|GRELWIDTH
  163. #define SEL SELECTED
  164. #define BF1 GADGHCOMP|GRELBOTTOM
  165. #define BF2 GADGHCOMP|GRELBOTTOM|GRELRIGHT
  166. #define PF GRELRIGHT
  167.  
  168. #define SA RELVERIFY
  169. #define CEN STRINGCENTER
  170. #define BA RELVERIFY
  171. #define PA RELVERIFY
  172.  
  173. #define SI(n) (APTR)&STD_String[n]
  174. #define G(n) &STD_Gadget[n]
  175. #define IMAG (APTR)&STD_Image
  176. #define PROP (APTR)&STD_Prop
  177.  
  178. #define SG STRGADGET
  179. #define BG BOOLGADGET
  180. #define PG PROPGADGET
  181.  
  182. #define FP AUTOBACKPEN
  183. #define BP AUTOFRONTPEN
  184.  
  185. #define OKTEXT &STD_OK
  186. #define NOTEXT &STD_CANCEL
  187. #define VLTEXT &STD_VOLUME
  188. #define PRTEXT &STD_PARENT
  189.  
  190. static int DoneFlag;
  191.  
  192. #define DirName SBuffer[0]
  193. #define FileName SBuffer[1]
  194. #define PatName SBuffer[2]
  195. #define STRINGS 3
  196.  
  197. static UBYTE SBuffer[STRINGS][MAXFULL];
  198. static UBYTE Undo[MAXFULL];
  199.  
  200. static struct StringInfo STD_String[STRINGS] = {
  201.     {SBuffer[0],Undo,0,MAXFULL,0},
  202.     {SBuffer[1],Undo,0,MAXFULL,0},
  203.     {SBuffer[2],Undo,0,MAXFULL,0}
  204. };
  205.  
  206. static struct PropInfo STD_Prop = { AUTOKNOB|FREEVERT, 0, 0, 0, 0 };
  207.  
  208. static struct IntuiText STD_OK =
  209.     { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"  OK  ", Z };
  210. static struct IntuiText STD_CANCEL =
  211.     { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"CANCEL", Z };
  212. static struct IntuiText STD_VOLUME =
  213.     { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"VOLUME", Z };
  214. static struct IntuiText STD_PARENT =
  215.     { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"PARENT", Z };
  216.  
  217. #define BUTTONS 4
  218. #define BUTVEC 8
  219.  
  220. static SHORT butvecs[BUTTONS][BUTVEC*2] = {
  221.     {
  222.         -2, HT4,
  223.         -2, -1,
  224.         WD3+1,-1,
  225.         WD3+1,HT4,
  226.         -3, HT4,
  227.         -3,-1,
  228.         WD3+2,-1,
  229.         WD3+2, HT4
  230.     },
  231.     {
  232.         -2, HT4,
  233.         -2, -1,
  234.         WD4+1,-1,
  235.         WD4+1,HT4,
  236.         -3, HT4,
  237.         -3,-1,
  238.         WD4+2,-1,
  239.         WD4+2, HT4
  240.     },
  241.     {
  242.         -2, HT4,
  243.         -2, -1,
  244.         WD6+1,-1,
  245.         WD6+1,HT4,
  246.         -3, HT4,
  247.         -3,-1,
  248.         WD6+2,-1,
  249.         WD6+2, HT4
  250.     },
  251.     {
  252.         -2, HT4,
  253.         -2, -1,
  254.         WD7+1,-1,
  255.         WD7+1,HT4,
  256.         -3, HT4,
  257.         -3,-1,
  258.         WD7+2,-1,
  259.         WD7+2, HT4
  260.     }
  261. };
  262. static struct Border ButBorder[BUTTONS] = {
  263.     {0, 0, FP, BP, JAM1, BUTVEC, butvecs[0], NULL},
  264.     {0, 0, FP, BP, JAM1, BUTVEC, butvecs[1], NULL},
  265.     {0, 0, FP, BP, JAM1, BUTVEC, butvecs[2], NULL},
  266.     {0, 0, FP, BP, JAM1, BUTVEC, butvecs[3], NULL}
  267. };
  268. #define BB(n) &ButBorder[n]
  269.  
  270. static struct Image STD_Image;
  271.  
  272. #define DIRID 0
  273. #define FILID 1
  274. #define PATID 2
  275. #define YESID 3
  276. #define CANID 4
  277. #define VOLID 5
  278. #define PARID 6
  279. #define BARID 7
  280. #define GADGETS 8
  281.  
  282. static struct Gadget STD_Gadget[GADGETS] = {
  283. /*NEXT, LFT, TP,WDTH, H, FLAG,  ACT, TYP, REND, Z, TXT, Z, SPEC, ID, Z */
  284. { G(1), IN1,TP1, WD1,HT, SF,     SA,  SG,    Z, Z,   Z, Z, SI(0), 0, 0 },
  285. { G(2), IN1,TP2, WD1,HT, SF, SA,  SG,    Z, Z,   Z, Z, SI(1), 1, 0 },
  286. { G(3), IN1,TP3, WD1,HT, SF,     SA,  SG,    Z, Z,   Z, Z, SI(2), 2, 0 },
  287. { G(4), IN3,TP4, WD3,HT4,BF1,    BA,  BG,BB(0), Z, OKTEXT, Z,  Z, 3, 0 },
  288. { G(5), IN4,TP4, WD4,HT4,BF2,    BA,  BG,BB(1), Z, NOTEXT, Z,  Z, 4, 0 },
  289. { G(6), IN6,TP4, WD6,HT4,BF1,    BA,  BG,BB(2), Z, VLTEXT, Z,  Z, 5, 0 },
  290. { G(7), IN7,TP4, WD7,HT4,BF1,    BA,  BG,BB(3), Z, PRTEXT, Z,  Z, 6, 0 },
  291. { NULL, IN5,TP5, WD5,HT5,PF,     PA,  PG, IMAG, Z,   Z, Z,  PROP, 7, 0 }
  292. };
  293.  
  294. static struct NewWindow STD_NewWindow = {
  295.     WININ, WINTP, WINWD, WINHT, -1, -1,
  296.     REFRESHWINDOW|MOUSEBUTTONS|GADGETUP|CLOSEWINDOW,
  297.     WINDOWDRAG|WINDOWCLOSE|SIMPLE_REFRESH|ACTIVATE,
  298.     G(0), NULL, "File Name Requestor",
  299.     NULL, NULL, 0, 0, 0, 0, WBENCHSCREEN
  300. };
  301. static struct Window *STD_Window;
  302.  
  303. #define NVEC 6
  304.  
  305. static SHORT Vectors[NVEC*2] = {
  306.     BIN+1, BTP,
  307.     BIN+1, BTP+BHT,
  308.     BIN+BWD, BTP+BHT,
  309.     BIN+BWD, BTP,
  310.     BIN, BTP,
  311.     BIN, BTP+BHT
  312. };
  313.  
  314. static struct Border STD_FileBox = {
  315.     0, 0, FP, BP, JAM1, NVEC, Vectors, NULL
  316. };
  317.  
  318. static struct IntuiText STD_Text[3] = {
  319.     { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"Directory:", NULL },
  320.     { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"File Name:", NULL },
  321.     { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"Pattern:", NULL }
  322. };
  323.  
  324. static OpenFileWindow()
  325. {
  326.     extern struct IntuitionBase *IntuitionBase;
  327.     extern int windowleftedge,windowtopedge;
  328.     int i;
  329.  
  330.     /* Rebuild gadget list */
  331.     STD_NewWindow.FirstGadget = &STD_Gadget[0];
  332.     for(i = 0; i < GADGETS; i++) {
  333.         STD_Gadget[i].NextGadget = (i==GADGETS-1)?(0):(&STD_Gadget[i+1]);
  334.     }
  335.     for(i = 0; i < STRINGS; i++) {
  336.         STD_String[i].BufferPos = strlen(SBuffer[i]);
  337.         STD_String[i].DispPos = 0;
  338.     }
  339.     STD_Prop.VertBody = 0xFFFF;
  340.     STD_Prop.VertPot = 0;
  341.  
  342.     STD_NewWindow.TopEdge=WINTP+windowtopedge;
  343.     STD_NewWindow.LeftEdge=WININ+windowleftedge;
  344.     if(!(STD_Window = OpenWindow(&STD_NewWindow))) {
  345.         return 0;
  346.     }
  347.  
  348.     /* This optional line will activate a string gadget    */
  349.     if ( IntuitionBase->lib_Version > 32 )
  350.     {
  351.     if (dir_only)
  352.         ActivateGadget(G(0),STD_Window,0L);
  353.     else
  354.         ActivateGadget(G(1),STD_Window,0L);
  355.     }
  356.  
  357.     CalcPropGadget();
  358.     PaintFileWindow();
  359.     return 1;
  360. }
  361.  
  362. static CloseFileWindow()
  363. {
  364.     STD_NewWindow.LeftEdge = STD_Window->LeftEdge;
  365.     STD_NewWindow.TopEdge = STD_Window->TopEdge;
  366.     if(STD_Window)
  367.         CloseWindow(STD_Window);
  368. }
  369.  
  370. static int State;
  371.  
  372. #define INITIAL 0
  373. #define DIRECTORY 1
  374.  
  375. static PaintFileWindow()
  376. {
  377.     DrawBorder(STD_Window->RPort, &STD_FileBox, 0, 0);
  378.     PrintIText(STD_Window->RPort, &STD_Text[0], LEFTMAR, TP1);
  379.     PrintIText(STD_Window->RPort, &STD_Text[1], LEFTMAR, TP2);
  380.     PrintIText(STD_Window->RPort, &STD_Text[2], LEFTMAR, TP3);
  381.     if(State == DIRECTORY) PrintFileNames();
  382. }
  383.  
  384. static int FirstFile;
  385. static int Selected;
  386. static int NumFiles;
  387. static struct dirent {
  388.     struct dirent *nextfile;
  389.     SHORT filetype;
  390.     char *filename;
  391. } *NameList, **NameTable;
  392.  
  393. #define FILETYPE 0
  394. #define DIRTYPE 1
  395. #define VOLTYPE 2
  396.  
  397. static PrintFileNames()
  398. {
  399.     int i;
  400.  
  401.     for(i = 0; i < MAXFILES; i++) {
  402.         SetBPen(STD_Window->RPort, BP);
  403.         SetAPen(STD_Window->RPort, BP);
  404.         RectFill(STD_Window->RPort,
  405.             HOMEX, HOMEY+i*CHSIZ,
  406.             LASTX, HOMEY+(i+1)*CHSIZ);
  407.         if(i+FirstFile < NumFiles)
  408.             PrintName(i+FirstFile, i+FirstFile==Selected);
  409.     }
  410. }
  411.  
  412. static PrintName(file, hilite)
  413. int file;
  414. int hilite;
  415. {
  416.     int i;
  417.  
  418.     i = file - FirstFile;
  419.  
  420.     Move(STD_Window->RPort, HOMEX, HOMEY+i*CHSIZ+BASELINE);
  421.     if(hilite == 0) {
  422.         SetBPen(STD_Window->RPort, BP);
  423.         if(NameTable[file]->filetype == FILETYPE)
  424.             SetAPen(STD_Window->RPort, FP);
  425.         else
  426.             SetAPen(STD_Window->RPort, 3);
  427.     } else {
  428.         SetAPen(STD_Window->RPort, BP);
  429.         if(NameTable[file]->filetype == FILETYPE)
  430.             SetBPen(STD_Window->RPort, FP);
  431.         else
  432.             SetBPen(STD_Window->RPort, 3);
  433.     }
  434.     Text(STD_Window->RPort,
  435.         NameTable[file]->filename,
  436.         strlen(NameTable[file]->filename));
  437. }
  438.  
  439. static CalcPropGadget()
  440. {
  441.     int VertPot, VertBody;
  442.  
  443.     if(State == INITIAL) return;
  444.  
  445.     if(NumFiles<=MAXFILES) {
  446.         VertBody = 0xFFFF;
  447.         VertPot = 0;
  448.         FirstFile = 0;
  449.     } else {
  450.         VertBody = ((MAXFILES<<16)-1) / NumFiles;
  451.         VertPot = 0;
  452.         FirstFile = 0;
  453.     }
  454.  
  455.     ModifyProp(&STD_Gadget[BARID], STD_Window, NULL,
  456.         STD_Prop.Flags, 0, VertPot, 0, VertBody);
  457. }
  458.  
  459. static CalcFilePosition()
  460. {
  461.     int old_pos;
  462.  
  463.     if(State == INITIAL) return;
  464.  
  465.     old_pos = FirstFile;
  466.     if(NumFiles<=MAXFILES)
  467.         FirstFile = 0;
  468.     else {
  469.         int VertPot = STD_Prop.VertPot;
  470.  
  471.         FirstFile = ((VertPot+1)*(NumFiles-MAXFILES))>>16;
  472.     }
  473.     if(old_pos != FirstFile)
  474.         PrintFileNames();
  475. }
  476.  
  477. FreeList(list)
  478. struct dirent *list;
  479. {
  480.     struct dirent *ptr;
  481.  
  482.     while(list) {
  483.         ptr = list->nextfile;
  484.         if(list->filename) free(list->filename);
  485.         free(list);
  486.         list = ptr;
  487.     }
  488. }
  489.  
  490. static ReadNewDir()
  491. {
  492.     struct dirent *NewList, **NewTable, *ptr;
  493.     int NewCount;
  494.     struct FileInfoBlock *FIB;
  495.     BPTR dirlock;
  496.  
  497.     SetPointer(STD_Window,&BusyPointer,22,16,0,0);
  498.  
  499.     if(State != DIRECTORY) {
  500.         NameTable = 0;
  501.         NameList = 0;
  502.     }
  503.     if(DirName[0])
  504.         dirlock = Lock(DirName, ACCESS_READ);
  505.     else {
  506.         BPTR ram;
  507.         ram = Lock("RAM:", ACCESS_READ);
  508.         dirlock = CurrentDir(ram);
  509.         CurrentDir(dirlock);
  510.         UnLock(ram);
  511.     }
  512.     if(dirlock==0) {
  513.         ClearPointer(STD_Window);
  514.         return 0;
  515.         }
  516.  
  517.     /* FIB must be long word aligned, and aztec doesn't guarantee this, so: */
  518.     if((FIB = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC)) == 0) {
  519.         UnLock(dirlock);
  520.         ClearPointer(STD_Window);
  521.         return 0;
  522.     }
  523.     if(!Examine(dirlock, FIB)) {
  524.         UnLock(dirlock);
  525.         FreeMem(FIB, sizeof(struct FileInfoBlock));
  526.         ClearPointer(STD_Window);
  527.         return 0;
  528.     }
  529.     if(FIB->fib_DirEntryType < 0) {
  530.         UnLock(dirlock);
  531.         FreeMem(FIB, sizeof(struct FileInfoBlock));
  532.         ClearPointer(STD_Window);
  533.         return 0;
  534.     }
  535.     NewList = 0;
  536.     NewCount = 0;
  537.     while(ExNext(dirlock, FIB)) {
  538.         NewCount += 1;
  539.         ptr = (struct dirent *)malloc(sizeof(struct dirent));
  540.         if(ptr==0) {
  541.             FreeList(NewList);
  542.             UnLock(dirlock);
  543.             FreeMem(FIB, sizeof(struct FileInfoBlock));
  544.             ClearPointer(STD_Window);
  545.             return 0;
  546.         }
  547.         ptr->nextfile = NewList;
  548.         ptr->filetype = (FIB->fib_DirEntryType<0)?FILETYPE:DIRTYPE;
  549.         ptr->filename = malloc(strlen(FIB->fib_FileName)+1);
  550.         if(ptr->filename == 0) {
  551.             FreeList(ptr);
  552.             UnLock(dirlock);
  553.             FreeMem(FIB, sizeof(struct FileInfoBlock));
  554.             ClearPointer(STD_Window);
  555.             return 0;
  556.         }
  557.         strcpy(ptr->filename, FIB->fib_FileName);
  558.         NewList = ptr;
  559.     }
  560.     FreeMem(FIB, sizeof(struct FileInfoBlock));
  561.     if(DirName[0]) {
  562.         UnLock(dirlock);
  563.     }
  564.     NewTable = malloc(sizeof(struct dirent *)*NewCount);
  565.     if(NewTable==0) {
  566.         FreeList(NewList);
  567.         ClearPointer(STD_Window);
  568.         return 0;
  569.     }
  570.     FreeList(NameList);
  571.     NameList = NewList;
  572.     if(NameTable) free(NameTable);
  573.     NameTable = NewTable;
  574.  
  575.     if(PatName[0]==0)
  576.         SetPatName("#?");
  577.  
  578.     State = DIRECTORY;
  579.     Selected = -1;
  580.  
  581.     ReCalcPattern();
  582.     ClearPointer(STD_Window);
  583. }
  584.  
  585. static ReadVol()
  586. {
  587.     struct dirent *NewList, **NewTable, *ptr;
  588.     int NewCount;
  589.     char name[MAXNAME];
  590.  
  591.     if(State != DIRECTORY) {
  592.         NameTable = 0;
  593.         NameList = 0;
  594.     }
  595.     OpenVolList();
  596.     NewList = 0;
  597.     NewCount = 0;
  598.     while(ReadVolList(name)) {
  599.         NewCount += 1;
  600.         ptr = (struct dirent *)malloc(sizeof(struct dirent));
  601.         if(ptr==0) {
  602.             FreeList(NewList);
  603.             return 0;
  604.         }
  605.         ptr->nextfile = NewList;
  606.         ptr->filetype = VOLTYPE;
  607.         ptr->filename = malloc(strlen(name)+1);
  608.         if(ptr->filename == 0) {
  609.             FreeList(ptr);
  610.             return 0;
  611.         }
  612.         strcpy(ptr->filename, name);
  613.         if(!(strcmp(ptr->filename,"RAM Disk:")))
  614.             strcpy(ptr->filename,"RAM:");
  615.         NewList = ptr;
  616.     }
  617.     CloseVolList();
  618.     NewTable = malloc(sizeof(struct dirent *)*NewCount);
  619.     if(NewTable==0) {
  620.         FreeList(NewList);
  621.         return 0;
  622.     }
  623.     FreeList(NameList);
  624.     NameList = NewList;
  625.     if(NameTable) free(NameTable);
  626.     NameTable = NewTable;
  627.  
  628.     if(PatName[0]==0)
  629.         SetPatName("#?");
  630.  
  631.     State = DIRECTORY;
  632.     Selected = -1;
  633.  
  634.     ReCalcPattern();
  635. }
  636.  
  637. static WORD PatCode[128];
  638.  
  639. static patcomp()
  640. {
  641.     /* This is a judgement call: that no pattern should be equivalent
  642.        to "#?". Perhaps it should do this invisibly, by adding a
  643.        pointer to the real pattern name and making it PatName or "#?"
  644.        as appropriate. */
  645.  
  646.     if(!PatName[0])
  647.         SetPatName("#?");
  648.     return CmplPat(PatName, PatCode);
  649. }
  650.  
  651. static patmatch(name)
  652. {
  653.     return Match(PatName, PatCode, name);
  654. }
  655.  
  656. /* this routine does a true dictionary search:
  657.  *
  658.  *        Devs < devs but Devs > devices
  659.  */
  660. static table_compare(p1, p2)
  661. struct dirent **p1, **p2;
  662. {
  663.     char *s1, *s2;
  664.     char c1, c2;
  665.     char firstdiff;
  666.  
  667.     s1 = (*p1)->filename;
  668.     s2 = (*p2)->filename;
  669.     firstdiff = 0;
  670.  
  671.     while(*s1 && *s2) {
  672.         c1 = *s1++;
  673.         c2 = *s2++;
  674.         if(firstdiff==0)
  675.             firstdiff = c1 - c2;
  676.         if(c1>='A' && c1<='Z') c1 = c1+'@';
  677.         if(c2>='A' && c2<='Z') c2 = c2+'@';
  678.         if(c1 != c2)
  679.             return c1 - c2;
  680.     }
  681.     return firstdiff;
  682. }
  683.  
  684. static sort_table()
  685. {
  686.     qsort(NameTable, NumFiles, sizeof(struct dirent *), table_compare);
  687.     return 1;
  688. }
  689.  
  690. static ReCalcPattern()
  691. {
  692.     if(State != DIRECTORY)
  693.         ReadNewDir();
  694.     else {
  695.         struct dirent *ptr;
  696.         patcomp();
  697.  
  698.         NumFiles = 0;
  699.         for(ptr = NameList; ptr; ptr=ptr->nextfile) {
  700.             /* Directories always match. Is this good? */
  701.             if(ptr->filetype == DIRTYPE ||
  702.                ptr->filetype == VOLTYPE ||
  703.                patmatch(ptr->filename)) {
  704.                 NameTable[NumFiles] = ptr;
  705.                 NumFiles++;
  706.             }
  707.         }
  708.         sort_table();
  709.         CalcPropGadget();
  710.         Selected = -1;
  711.         PrintFileNames();
  712.     }
  713. }
  714.  
  715. static SetGadgetText(id, text)
  716. int id;
  717. char *text;
  718. {
  719.     int position;
  720.  
  721.     position = RemoveGadget(STD_Window, G(id));
  722.     if(position != -1) {
  723.         strcpy(SBuffer[id], text);
  724.         STD_String[id].BufferPos = strlen(text);
  725.         position = AddGadget(STD_Window, G(id), -1);
  726.         if(position != -1)
  727.             RefreshGadgets(G(id), STD_Window, NULL);
  728.     }
  729. }
  730.  
  731. static SetDirName(name)
  732. char *name;
  733. {
  734.     char buffer[MAXFULL+1], *ptr;
  735.     int index;
  736.     char lastchar;
  737.  
  738.     /* Can't enter a file name too long. */
  739.     if(strlen(DirName) + strlen(name) + 1 > MAXFULL) {
  740.         DisplayBeep();
  741.         return 0;
  742.     }
  743.     index = 0;
  744.     lastchar = 0;
  745.     for(ptr = DirName; *ptr; ptr++)
  746.         buffer[index++] = lastchar = *ptr;
  747.     if(lastchar!='/' && lastchar!=':' && lastchar!=0)
  748.         buffer[index++] = '/';
  749.     strcpy(&buffer[index], name);
  750.     SetGadgetText(DIRID, buffer);
  751.     SetGadgetText(FILID, "");
  752.     return 1;
  753. }
  754.  
  755. static ReadParDir()
  756. {
  757.     int i;
  758.     int ptr;
  759.  
  760.     ptr = -1;
  761.     for(i = 0; DirName[i]; i++)
  762.         if(DirName[i]==':' || DirName[i]=='/')
  763.             ptr = i;
  764.     if(ptr>=0) {
  765.         SetGadgetText(FILID, &DirName[ptr+1]);
  766.         if(ptr==0 || DirName[ptr]==':')
  767.             ptr++;
  768.         DirName[ptr] = 0;
  769.         SetGadgetText(DIRID, DirName);
  770.     } else {
  771.         SetGadgetText(FILID, DirName);
  772.         if(i)
  773.             SetGadgetText(DIRID, "");
  774.         else
  775.             SetGadgetText(DIRID, "/");
  776.     }
  777.     ReadNewDir();
  778.     return 1;
  779. }
  780.  
  781. static SetFileName(name)
  782. char *name;
  783. {
  784.     /* Can't enter a file name too long. */
  785.     if(strlen(DirName) + strlen(name) + 1 > MAXFULL) {
  786.         DisplayBeep();
  787.         return 0;
  788.     }
  789.     SetGadgetText(FILID, name);
  790.     return 1;
  791. }
  792.  
  793. static SetPatName(name)
  794. char *name;
  795. {
  796.     SetGadgetText(PATID, name);
  797. }
  798.  
  799. static ProcessGadget(id)
  800. int id;
  801. {
  802.     switch(id) {
  803.         case DIRID: ReadNewDir(); break;
  804.         case FILID: if (dir_only) 
  805.                 ActivateGadget(&STD_Gadget[0],STD_Window,0L);
  806.                 else
  807.                 DoneFlag = 1; break;
  808.         case PATID: ReCalcPattern(); break;
  809.         case BARID: CalcFilePosition(); break;
  810.         case YESID: DoneFlag = 1; break;
  811.         case CANID: DoneFlag = -1; break;
  812.         case VOLID: ReadVol(); break;
  813.         case PARID: ReadParDir(); break;
  814.     }
  815. }
  816.  
  817. static ProcessMouse(x, y, code, seconds, micros)
  818. int x, y, code;
  819. {
  820.     int NewSelected;
  821.     static int oseconds = 0, omicros = 0;
  822.  
  823.     if(x<HOMEX || y<HOMEY || x>=LASTX || y>=LASTY)
  824.         return;
  825.     if((code&SELECTUP) == SELECTUP)
  826.         return;
  827.     if(State != DIRECTORY) {
  828.         ReadNewDir();
  829.         return;
  830.     }
  831.     NewSelected = (y-HOMEY)/CHSIZ + FirstFile;
  832.     if(NewSelected == Selected) {
  833.         if(Selected != -1) {
  834.             if(DoubleClick(oseconds, omicros, seconds, micros)) {
  835.                 if(NameTable[Selected]->filetype == DIRTYPE) {
  836.                     if(SetDirName(NameTable[Selected]->filename))
  837.                         ReadNewDir();
  838.                 } else if(NameTable[Selected]->filetype == VOLTYPE) {
  839.                     SetGadgetText(DIRID, NameTable[Selected]->filename);
  840.                     SetGadgetText(FILID, "");
  841.                     ReadNewDir();
  842.                 } else {
  843.                     if(!SetFileName(NameTable[Selected]->filename))
  844.                         Selected = -1;
  845.                     DoneFlag = 1;
  846.                 }
  847.             }
  848.         }
  849.     } else {
  850.         if(Selected != -1 &&
  851.            Selected>=FirstFile && Selected<FirstFile+MAXFILES)
  852.             PrintName(Selected, 0);
  853.         Selected = NewSelected;
  854.         if(Selected>=NumFiles)
  855.             Selected = -1;
  856.         else {
  857.             if(SetFileName(NameTable[Selected]->filename))
  858.                 PrintName(Selected, 1);
  859.             else
  860.                 Selected = -1;
  861.         }
  862.     }
  863.     oseconds = seconds;
  864.     omicros = micros;
  865. }
  866.  
  867. stdfile(title, deffile, defpat, name)
  868. char *title, *deffile, *defpat, *name;
  869. {
  870.     if(title)
  871.         STD_NewWindow.Title = (UBYTE *)title;
  872.     else
  873.         STD_NewWindow.Title = (UBYTE *)"Enter File Name";
  874.     if(deffile) {
  875.         int i;
  876.         for(i = strlen(deffile)-1; i>=0; i--) {
  877.             if(deffile[i]==':' || deffile[i]=='/') {
  878.                 int hold;
  879.                 strcpy(FileName, &deffile[i+1]);
  880.                 if(deffile[i]==':')
  881.                     i++;
  882.                 hold = deffile[i];
  883.                 deffile[i] = 0;
  884.                 strcpy(DirName, deffile);
  885.                 deffile[i] = hold;
  886.                 break;
  887.             }
  888.         }
  889.         if(i<0) {
  890.             strcpy(FileName, deffile);
  891.             DirName[0] = 0;
  892.         }
  893.     } else {
  894.         DirName[0] = 0;
  895.         FileName[0] = 0;
  896.     }
  897.     if(defpat)
  898.         strcpy(PatName, defpat);
  899.     else
  900.         PatName[0] = 0;
  901.  
  902.     State = INITIAL;
  903.     NameTable = 0;
  904.     NameList = 0;
  905.  
  906.     if(OpenFileWindow()) {
  907.         struct IntuiMessage *msg;
  908.         DoneFlag = 0;
  909.         if (read_dir)
  910.             ReadNewDir();
  911.         while(!DoneFlag) {
  912.             Wait(1<<STD_Window->UserPort->mp_SigBit);
  913.             while(msg = GetMsg(STD_Window->UserPort)) {
  914.                 switch(msg->Class) {
  915.                     case CLOSEWINDOW:
  916.                         DoneFlag = -1;
  917.                         break;
  918.                     case MOUSEBUTTONS:
  919.                         ProcessMouse(msg->MouseX, msg->MouseY,
  920.                             msg->Code,
  921.                             msg->Seconds, msg->Micros);
  922.                         break;
  923.                     case GADGETUP:
  924.                         ProcessGadget(
  925.                             ((struct Gadget *)msg->IAddress)->GadgetID
  926.                         );
  927.                         break;
  928.                     case REFRESHWINDOW:
  929.                         BeginRefresh(STD_Window);
  930.                         PaintFileWindow();
  931.                         EndRefresh(STD_Window, 1);
  932.                         break;
  933.                 }
  934.                 ReplyMsg(msg);
  935.             }
  936.         }
  937.  
  938.         CloseFileWindow();
  939.     }
  940.     else return 0;
  941.  
  942.     FreeList(NameList);
  943.     if(NameTable) free(NameTable);
  944.  
  945.     if(DoneFlag==1) {
  946.         int len;
  947.  
  948.         strcpy(name, DirName);
  949.         if(FileName[0]) {
  950.             if(len = strlen(name))
  951.                 if(name[len-1]!=':')
  952.                     strcat(name, "/");
  953.             strcat(name, FileName);
  954.             return 1;
  955.         }
  956.  
  957.         /* Here the user has accepted the name without providing a file
  958.            name. I return true, but false may be more appropriate. What
  959.            do you think? */
  960.         return 1;
  961.     }
  962.     return 0;
  963. }
  964.