home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d581 / prism.lha / Prism / Source / source.lzh / stdfile.c < prev   
C/C++ Source or Header  |  1991-11-17  |  23KB  |  979 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-20
  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. struct IntuiText STD_OK =
  209.     { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"  OK  ", Z };
  210. struct IntuiText STD_CANCEL =
  211.     { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"CANCEL", Z };
  212. struct IntuiText STD_VOLUME =
  213.     { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"VOLUME", Z };
  214. 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. struct Border ButBorder[BUTTONS] = {
  263.     {0, 0, 3, BP, JAM1, BUTVEC, butvecs[0], NULL},
  264.     {0, 0, 3, BP, JAM1, BUTVEC, butvecs[1], NULL},
  265.     {0, 0, 3, BP, JAM1, BUTVEC, butvecs[2], NULL},
  266.     {0, 0, 3, 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 Requester",
  299.     NULL, NULL, 0, 0, 0, 0, CUSTOMSCREEN
  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. int max_color;
  315.  
  316. struct Border STD_FileBox = {
  317.     0, 0, FP, BP, JAM1, NVEC, Vectors, NULL
  318. };
  319.  
  320. static struct IntuiText STD_Text[3] = {
  321.     { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"Directory:", NULL },
  322.     { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"File Name:", NULL },
  323.     { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"Pattern:", NULL }
  324. };
  325.  
  326. static OpenFileWindow()
  327. {
  328.     extern struct IntuitionBase *IntuitionBase;
  329.     extern int windowleftedge,windowtopedge;
  330.     int i;
  331.  
  332.     /* Rebuild gadget list */
  333.     STD_NewWindow.FirstGadget = &STD_Gadget[0];
  334.     for(i = 0; i < GADGETS; i++) {
  335.         STD_Gadget[i].NextGadget = (i==GADGETS-1)?(0):(&STD_Gadget[i+1]);
  336.     }
  337.     for(i = 0; i < STRINGS; i++) {
  338.         STD_String[i].BufferPos = strlen(SBuffer[i]);
  339.         STD_String[i].DispPos = 0;
  340.     }
  341.     STD_Prop.VertBody = 0xFFFF;
  342.     STD_Prop.VertPot = 0;
  343.  
  344.     STD_NewWindow.TopEdge=WINTP+windowtopedge;
  345.     STD_NewWindow.LeftEdge=WININ+windowleftedge;
  346.     if(!(STD_Window = OpenWindow(&STD_NewWindow))) {
  347.         return 0;
  348.     }
  349.  
  350.     /* This optional line will activate a string gadget    */
  351.     if ( IntuitionBase->lib_Version > 32 )
  352.     {
  353.     if (dir_only)
  354.         ActivateGadget(G(0),STD_Window,0L);
  355.     else
  356.         ActivateGadget(G(1),STD_Window,0L);
  357.     }
  358.  
  359.     CalcPropGadget();
  360.     PaintFileWindow();
  361.     return 1;
  362. }
  363.  
  364. static CloseFileWindow()
  365. {
  366.     STD_NewWindow.LeftEdge = STD_Window->LeftEdge;
  367.     STD_NewWindow.TopEdge = STD_Window->TopEdge;
  368.     if(STD_Window)
  369.         CloseWindow(STD_Window);
  370. }
  371.  
  372. static int State;
  373.  
  374. #define INITIAL 0
  375. #define DIRECTORY 1
  376.  
  377. static PaintFileWindow()
  378. {
  379.     DrawBorder(STD_Window->RPort, &STD_FileBox, 0, 0);
  380.     PrintIText(STD_Window->RPort, &STD_Text[0], LEFTMAR, TP1);
  381.     PrintIText(STD_Window->RPort, &STD_Text[1], LEFTMAR, TP2);
  382.     PrintIText(STD_Window->RPort, &STD_Text[2], LEFTMAR, TP3);
  383.     if(State == DIRECTORY) PrintFileNames();
  384. }
  385.  
  386. static int FirstFile;
  387. static int Selected;
  388. static int NumFiles;
  389. static struct dirent {
  390.     struct dirent *nextfile;
  391.     SHORT filetype;
  392.     char *filename;
  393. } *NameList, **NameTable;
  394.  
  395. #define FILETYPE 0
  396. #define DIRTYPE 1
  397. #define VOLTYPE 2
  398.  
  399. static PrintFileNames()
  400. {
  401.     int i;
  402.  
  403.     for(i = 0; i < MAXFILES; i++) {
  404.         SetBPen(STD_Window->RPort, BP);
  405.         SetAPen(STD_Window->RPort, BP);
  406.         RectFill(STD_Window->RPort,
  407.             HOMEX, HOMEY+i*CHSIZ,
  408.             LASTX, HOMEY+(i+1)*CHSIZ);
  409.         if(i+FirstFile < NumFiles)
  410.             PrintName(i+FirstFile, i+FirstFile==Selected);
  411.     }
  412. }
  413.  
  414. static PrintName(file, hilite)
  415. int file;
  416. int hilite;
  417. {
  418.     int i;
  419.  
  420.     i = file - FirstFile;
  421.  
  422.     Move(STD_Window->RPort, HOMEX, HOMEY+i*CHSIZ+BASELINE);
  423.     if(hilite == 0) {
  424.         SetBPen(STD_Window->RPort, BP);
  425.         if(NameTable[file]->filetype == FILETYPE)
  426.             SetAPen(STD_Window->RPort, max_color-1);
  427.         else
  428.             SetAPen(STD_Window->RPort, max_color-2);
  429.     } else {
  430.         SetAPen(STD_Window->RPort, BP);
  431.         if(NameTable[file]->filetype == FILETYPE)
  432.             SetBPen(STD_Window->RPort, max_color-1);
  433.         else
  434.             SetBPen(STD_Window->RPort, max_color-2);
  435.     }
  436.     Text(STD_Window->RPort,
  437.         NameTable[file]->filename,
  438.         strlen(NameTable[file]->filename));
  439. }
  440.  
  441. static CalcPropGadget()
  442. {
  443.     int VertPot, VertBody;
  444.  
  445.     if(State == INITIAL) return;
  446.  
  447.     if(NumFiles<=MAXFILES) {
  448.         VertBody = 0xFFFF;
  449.         VertPot = 0;
  450.         FirstFile = 0;
  451.     } else {
  452.         VertBody = ((MAXFILES<<16)-1) / NumFiles;
  453.         VertPot = 0;
  454.         FirstFile = 0;
  455.     }
  456.  
  457.     ModifyProp(&STD_Gadget[BARID], STD_Window, NULL,
  458.         STD_Prop.Flags, 0, VertPot, 0, VertBody);
  459. }
  460.  
  461. static CalcFilePosition()
  462. {
  463.     int old_pos;
  464.  
  465.     if(State == INITIAL) return;
  466.  
  467.     old_pos = FirstFile;
  468.     if(NumFiles<=MAXFILES)
  469.         FirstFile = 0;
  470.     else {
  471.         int VertPot = STD_Prop.VertPot;
  472.  
  473.         FirstFile = ((VertPot+1)*(NumFiles-MAXFILES))>>16;
  474.     }
  475.     if(old_pos != FirstFile)
  476.         PrintFileNames();
  477. }
  478.  
  479. FreeList(list)
  480. struct dirent *list;
  481. {
  482.     struct dirent *ptr;
  483.  
  484.     while(list) {
  485.         ptr = list->nextfile;
  486.         if(list->filename) free(list->filename);
  487.         free(list);
  488.         list = ptr;
  489.     }
  490. }
  491.  
  492. static ReadNewDir()
  493. {
  494.     struct dirent *NewList, **NewTable, *ptr;
  495.     int NewCount;
  496.     struct FileInfoBlock *FIB;
  497.     BPTR dirlock;
  498.  
  499.     SetPointer(STD_Window,&BusyPointer,22,16,0,0);
  500.  
  501.     if(State != DIRECTORY) {
  502.         NameTable = 0;
  503.         NameList = 0;
  504.     }
  505.     if(DirName[0])
  506.         dirlock = Lock(DirName, ACCESS_READ);
  507.     else {
  508.         BPTR ram;
  509.         ram = Lock("RAM:", ACCESS_READ);
  510.         dirlock = CurrentDir(ram);
  511.         CurrentDir(dirlock);
  512.         UnLock(ram);
  513.     }
  514.     if(dirlock==0) {
  515.         ClearPointer(STD_Window);
  516.         return 0;
  517.         }
  518.  
  519.     /* FIB must be long word aligned, and aztec doesn't guarantee this, so: */
  520.     if((FIB = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC)) == 0) {
  521.         UnLock(dirlock);
  522.         ClearPointer(STD_Window);
  523.         return 0;
  524.     }
  525.     if(!Examine(dirlock, FIB)) {
  526.         UnLock(dirlock);
  527.         FreeMem(FIB, sizeof(struct FileInfoBlock));
  528.         ClearPointer(STD_Window);
  529.         return 0;
  530.     }
  531.     if(FIB->fib_DirEntryType < 0) {
  532.         UnLock(dirlock);
  533.         FreeMem(FIB, sizeof(struct FileInfoBlock));
  534.         ClearPointer(STD_Window);
  535.         return 0;
  536.     }
  537.     NewList = 0;
  538.     NewCount = 0;
  539.     while(ExNext(dirlock, FIB)) {
  540.         NewCount += 1;
  541.         ptr = (struct dirent *)malloc(sizeof(struct dirent));
  542.         if(ptr==0) {
  543.             FreeList(NewList);
  544.             UnLock(dirlock);
  545.             FreeMem(FIB, sizeof(struct FileInfoBlock));
  546.             ClearPointer(STD_Window);
  547.             return 0;
  548.         }
  549.         ptr->nextfile = NewList;
  550.         ptr->filetype = (FIB->fib_DirEntryType<0)?FILETYPE:DIRTYPE;
  551.         ptr->filename = malloc(strlen(FIB->fib_FileName)+1);
  552.         if(ptr->filename == 0) {
  553.             FreeList(ptr);
  554.             UnLock(dirlock);
  555.             FreeMem(FIB, sizeof(struct FileInfoBlock));
  556.             ClearPointer(STD_Window);
  557.             return 0;
  558.         }
  559.         strcpy(ptr->filename, FIB->fib_FileName);
  560.         NewList = ptr;
  561.     }
  562.     FreeMem(FIB, sizeof(struct FileInfoBlock));
  563.     if(DirName[0]) {
  564.         UnLock(dirlock);
  565.     }
  566.     NewTable = malloc(sizeof(struct dirent *)*NewCount);
  567.     if(NewTable==0) {
  568.         FreeList(NewList);
  569.         ClearPointer(STD_Window);
  570.         return 0;
  571.     }
  572.     FreeList(NameList);
  573.     NameList = NewList;
  574.     if(NameTable) free(NameTable);
  575.     NameTable = NewTable;
  576.  
  577.     if(PatName[0]==0)
  578.         SetPatName("#?");
  579.  
  580.     State = DIRECTORY;
  581.     Selected = -1;
  582.  
  583.     ReCalcPattern();
  584.     ClearPointer(STD_Window);
  585. }
  586.  
  587. static ReadVol()
  588. {
  589.     struct dirent *NewList, **NewTable, *ptr;
  590.     int NewCount;
  591.     char name[MAXNAME];
  592.  
  593.     if(State != DIRECTORY) {
  594.         NameTable = 0;
  595.         NameList = 0;
  596.     }
  597.     OpenVolList();
  598.     NewList = 0;
  599.     NewCount = 0;
  600.     while(ReadVolList(name)) {
  601.         NewCount += 1;
  602.         ptr = (struct dirent *)malloc(sizeof(struct dirent));
  603.         if(ptr==0) {
  604.             FreeList(NewList);
  605.             return 0;
  606.         }
  607.         ptr->nextfile = NewList;
  608.         ptr->filetype = VOLTYPE;
  609.         ptr->filename = malloc(strlen(name)+1);
  610.         if(ptr->filename == 0) {
  611.             FreeList(ptr);
  612.             return 0;
  613.         }
  614.         strcpy(ptr->filename, name);
  615.         if(!(strcmp(ptr->filename,"RAM Disk:")))
  616.             strcpy(ptr->filename,"RAM:");
  617.         NewList = ptr;
  618.     }
  619.     CloseVolList();
  620.     NewTable = malloc(sizeof(struct dirent *)*NewCount);
  621.     if(NewTable==0) {
  622.         FreeList(NewList);
  623.         return 0;
  624.     }
  625.     FreeList(NameList);
  626.     NameList = NewList;
  627.     if(NameTable) free(NameTable);
  628.     NameTable = NewTable;
  629.  
  630.     if(PatName[0]==0)
  631.         SetPatName("#?");
  632.  
  633.     State = DIRECTORY;
  634.     Selected = -1;
  635.  
  636.     ReCalcPattern();
  637. }
  638.  
  639. static WORD PatCode[128];
  640.  
  641. static patcomp()
  642. {
  643.     /* This is a judgement call: that no pattern should be equivalent
  644.        to "#?". Perhaps it should do this invisibly, by adding a
  645.        pointer to the real pattern name and making it PatName or "#?"
  646.        as appropriate. */
  647.  
  648.     if(!PatName[0])
  649.         SetPatName("#?");
  650.     return CmplPat(PatName, PatCode);
  651. }
  652.  
  653. static patmatch(name)
  654. {
  655.     return Match(PatName, PatCode, name);
  656. }
  657.  
  658. /* this routine does a true dictionary search:
  659.  *
  660.  *        Devs < devs but Devs > devices
  661.  */
  662. static table_compare(p1, p2)
  663. struct dirent **p1, **p2;
  664. {
  665.     char *s1, *s2;
  666.     char c1, c2;
  667.     char firstdiff;
  668.  
  669.     s1 = (*p1)->filename;
  670.     s2 = (*p2)->filename;
  671.     firstdiff = 0;
  672.  
  673.     while(*s1 && *s2) {
  674.         c1 = *s1++;
  675.         c2 = *s2++;
  676.         if(firstdiff==0)
  677.             firstdiff = c1 - c2;
  678.         if(c1>='A' && c1<='Z') c1 = c1+'@';
  679.         if(c2>='A' && c2<='Z') c2 = c2+'@';
  680.         if(c1 != c2)
  681.             return c1 - c2;
  682.     }
  683.     return firstdiff;
  684. }
  685.  
  686. static sort_table()
  687. {
  688.     qsort(NameTable, NumFiles, sizeof(struct dirent *), table_compare);
  689.     return 1;
  690. }
  691.  
  692. static ReCalcPattern()
  693. {
  694.     if(State != DIRECTORY)
  695.         ReadNewDir();
  696.     else {
  697.         struct dirent *ptr;
  698.         patcomp();
  699.  
  700.         NumFiles = 0;
  701.         for(ptr = NameList; ptr; ptr=ptr->nextfile) {
  702.             /* Directories always match. Is this good? */
  703.             if(ptr->filetype == DIRTYPE ||
  704.                ptr->filetype == VOLTYPE ||
  705.                patmatch(ptr->filename)) {
  706.                 NameTable[NumFiles] = ptr;
  707.                 NumFiles++;
  708.             }
  709.         }
  710.         sort_table();
  711.         CalcPropGadget();
  712.         Selected = -1;
  713.         PrintFileNames();
  714.     }
  715. }
  716.  
  717. static SetGadgetText(id, text)
  718. int id;
  719. char *text;
  720. {
  721.     int position;
  722.  
  723.     position = RemoveGadget(STD_Window, G(id));
  724.     if(position != -1) {
  725.         strcpy(SBuffer[id], text);
  726.         STD_String[id].BufferPos = strlen(text);
  727.         position = AddGadget(STD_Window, G(id), -1);
  728.         if(position != -1)
  729.             RefreshGadgets(G(id), STD_Window, NULL);
  730.     }
  731. }
  732.  
  733. static SetDirName(name)
  734. char *name;
  735. {
  736.     char buffer[MAXFULL+1], *ptr;
  737.     int index;
  738.     char lastchar;
  739.  
  740.     /* Can't enter a file name too long. */
  741.     if(strlen(DirName) + strlen(name) + 1 > MAXFULL) {
  742.         DisplayBeep();
  743.         return 0;
  744.     }
  745.     index = 0;
  746.     lastchar = 0;
  747.     for(ptr = DirName; *ptr; ptr++)
  748.         buffer[index++] = lastchar = *ptr;
  749.     if(lastchar!='/' && lastchar!=':' && lastchar!=0)
  750.         buffer[index++] = '/';
  751.     strcpy(&buffer[index], name);
  752.     SetGadgetText(DIRID, buffer);
  753.     SetGadgetText(FILID, "");
  754.     return 1;
  755. }
  756.  
  757. static ReadParDir()
  758. {
  759.     int i;
  760.     int ptr;
  761.  
  762.     ptr = -1;
  763.     for(i = 0; DirName[i]; i++)
  764.         if(DirName[i]==':' || DirName[i]=='/')
  765.             ptr = i;
  766.     if(ptr>=0) {
  767.         SetGadgetText(FILID, &DirName[ptr+1]);
  768.         if(ptr==0 || DirName[ptr]==':')
  769.             ptr++;
  770.         DirName[ptr] = 0;
  771.         SetGadgetText(DIRID, DirName);
  772.     } else {
  773.         SetGadgetText(FILID, DirName);
  774.         if(i)
  775.             SetGadgetText(DIRID, "");
  776.         else
  777.             SetGadgetText(DIRID, "/");
  778.     }
  779.     ReadNewDir();
  780.     return 1;
  781. }
  782.  
  783. static SetFileName(name)
  784. char *name;
  785. {
  786.     /* Can't enter a file name too long. */
  787.     if(strlen(DirName) + strlen(name) + 1 > MAXFULL) {
  788.         DisplayBeep();
  789.         return 0;
  790.     }
  791.     SetGadgetText(FILID, name);
  792.     return 1;
  793. }
  794.  
  795. static SetPatName(name)
  796. char *name;
  797. {
  798.     SetGadgetText(PATID, name);
  799. }
  800.  
  801. static ProcessGadget(id)
  802. int id;
  803. {
  804.     switch(id) {
  805.         case DIRID: ReadNewDir(); break;
  806.         case FILID: if (dir_only) 
  807.                 ActivateGadget(&STD_Gadget[0],STD_Window,0L);
  808.                 else
  809.                 DoneFlag = 1; break;
  810.         case PATID: ReCalcPattern(); break;
  811.         case BARID: CalcFilePosition(); break;
  812.         case YESID: DoneFlag = 1; break;
  813.         case CANID: DoneFlag = -1; break;
  814.         case VOLID: ReadVol(); break;
  815.         case PARID: ReadParDir(); break;
  816.     }
  817. }
  818.  
  819. static ProcessMouse(x, y, code, seconds, micros)
  820. int x, y, code;
  821. {
  822.     int NewSelected;
  823.     static int oseconds = 0, omicros = 0;
  824.  
  825.     if(x<HOMEX || y<HOMEY || x>=LASTX || y>=LASTY)
  826.         return;
  827.     if((code&SELECTUP) == SELECTUP)
  828.         return;
  829.     if(State != DIRECTORY) {
  830.         ReadNewDir();
  831.         return;
  832.     }
  833.     NewSelected = (y-HOMEY)/CHSIZ + FirstFile;
  834.     if(NewSelected == Selected) {
  835.         if(Selected != -1) {
  836.             if(DoubleClick(oseconds, omicros, seconds, micros)) {
  837.                 if(NameTable[Selected]->filetype == DIRTYPE) {
  838.                     if(SetDirName(NameTable[Selected]->filename))
  839.                         ReadNewDir();
  840.                 } else if(NameTable[Selected]->filetype == VOLTYPE) {
  841.                     SetGadgetText(DIRID, NameTable[Selected]->filename);
  842.                     SetGadgetText(FILID, "");
  843.                     ReadNewDir();
  844.                 } else {
  845.                     if(!SetFileName(NameTable[Selected]->filename))
  846.                         Selected = -1;
  847.                     DoneFlag = 1;
  848.                 }
  849.             }
  850.         }
  851.     } else {
  852.         if(Selected != -1 &&
  853.            Selected>=FirstFile && Selected<FirstFile+MAXFILES)
  854.             PrintName(Selected, 0);
  855.         Selected = NewSelected;
  856.         if(Selected>=NumFiles)
  857.             Selected = -1;
  858.         else {
  859.             if(SetFileName(NameTable[Selected]->filename))
  860.                 PrintName(Selected, 1);
  861.             else
  862.                 Selected = -1;
  863.         }
  864.     }
  865.     oseconds = seconds;
  866.     omicros = micros;
  867. }
  868.  
  869. stdfile(title, deffile, defpat, name, screen)
  870. char *title, *deffile, *defpat, *name;
  871. struct Screen *screen;
  872. {
  873. int i;
  874.  
  875. STD_NewWindow.Screen=screen;
  876. max_color=(1 << screen->RastPort.BitMap->Depth)-1;
  877. STD_OK.FrontPen=max_color;
  878. STD_CANCEL.FrontPen=max_color;
  879. STD_PARENT.FrontPen=max_color;
  880. STD_VOLUME.FrontPen=max_color;
  881. STD_FileBox.FrontPen=max_color;
  882. for (i=0; i<3; i++)
  883.     STD_Text[i].FrontPen=max_color;
  884.  
  885.     if(title)
  886.         STD_NewWindow.Title = (UBYTE *)title;
  887.     else
  888.         STD_NewWindow.Title = (UBYTE *)"Enter File Name";
  889.     if(deffile) {
  890.         int i;
  891.         for(i = strlen(deffile)-1; i>=0; i--) {
  892.             if(deffile[i]==':' || deffile[i]=='/') {
  893.                 int hold;
  894.                 strcpy(FileName, &deffile[i+1]);
  895.                 if(deffile[i]==':')
  896.                     i++;
  897.                 hold = deffile[i];
  898.                 deffile[i] = 0;
  899.                 strcpy(DirName, deffile);
  900.                 deffile[i] = hold;
  901.                 break;
  902.             }
  903.         }
  904.         if(i<0) {
  905.             strcpy(FileName, deffile);
  906.             DirName[0] = 0;
  907.         }
  908.     } else {
  909.         DirName[0] = 0;
  910.         FileName[0] = 0;
  911.     }
  912.     if(defpat)
  913.         strcpy(PatName, defpat);
  914.     else
  915.         PatName[0] = 0;
  916.  
  917.     State = INITIAL;
  918.     NameTable = 0;
  919.     NameList = 0;
  920.  
  921.     if(OpenFileWindow()) {
  922.         struct IntuiMessage *msg;
  923.         DoneFlag = 0;
  924.         if (read_dir)
  925.             ReadNewDir();
  926.         while(!DoneFlag) {
  927.             Wait(1<<STD_Window->UserPort->mp_SigBit);
  928.             while(msg = GetMsg(STD_Window->UserPort)) {
  929.                 switch(msg->Class) {
  930.                     case CLOSEWINDOW:
  931.                         DoneFlag = -1;
  932.                         break;
  933.                     case MOUSEBUTTONS:
  934.                         ProcessMouse(msg->MouseX, msg->MouseY,
  935.                             msg->Code,
  936.                             msg->Seconds, msg->Micros);
  937.                         break;
  938.                     case GADGETUP:
  939.                         ProcessGadget(
  940.                             ((struct Gadget *)msg->IAddress)->GadgetID
  941.                         );
  942.                         break;
  943.                     case REFRESHWINDOW:
  944.                         BeginRefresh(STD_Window);
  945.                         PaintFileWindow();
  946.                         EndRefresh(STD_Window, 1);
  947.                         break;
  948.                 }
  949.                 ReplyMsg(msg);
  950.             }
  951.         }
  952.  
  953.         CloseFileWindow();
  954.     }
  955.     else return 0;
  956.  
  957.     FreeList(NameList);
  958.     if(NameTable) free(NameTable);
  959.  
  960.     if(DoneFlag==1) {
  961.         int len;
  962.  
  963.         strcpy(name, DirName);
  964.         if(FileName[0]) {
  965.             if(len = strlen(name))
  966.                 if(name[len-1]!=':')
  967.                     strcat(name, "/");
  968.             strcat(name, FileName);
  969.             return 1;
  970.         }
  971.  
  972.         /* Here the user has accepted the name without providing a file
  973.            name. I return true, but false may be more appropriate. What
  974.            do you think? */
  975.         return 1;
  976.     }
  977.     return 0;
  978. }
  979.