use PhysicsFS in file.c, involves modifying the listbox so it can use an array of...
[btb/d2x.git] / ui / file.c
1 /* $Id: file.c,v 1.11 2005-03-05 09:30:26 chris Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 #ifdef RCS
16 static char rcsid[] = "$Id: file.c,v 1.11 2005-03-05 09:30:26 chris Exp $";
17 #endif
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <physfs.h>
22
23 #include "fix.h"
24 #include "pstypes.h"
25 #include "gr.h"
26 #include "key.h"
27 #include "strutil.h"
28
29 #include "ui.h"
30 #include "mono.h"
31
32 #include "u_mem.h"
33
34 int file_sort_func(char **e0, char **e1)
35 {
36         return stricmp(*e0, *e1);
37 }
38
39
40 char **file_getdirlist(int *NumDirs, char *dir)
41 {
42         char    path[PATH_MAX];
43         char    **list = PHYSFS_enumerateFiles(dir);
44         char    **i, **j = list;
45         char    *test_filename;
46         int             test_max;
47
48         if (!list)
49                 return NULL;
50
51         strcpy(path, dir);
52         if (*path)
53                 strncat(path, "/", PATH_MAX - strlen(dir));
54
55         test_filename = path + strlen(path);
56         test_max = PATH_MAX - (test_filename - path);
57
58         for (i = list; *i; i++)
59         {
60                 if (strlen(*i) >= test_max)
61                         continue;
62
63                 strcpy(test_filename, *i);
64                 if (PHYSFS_isDirectory(path))
65                         *j++ = *i;
66                 else
67                         free(*i);
68         }
69         *j = NULL;
70
71         *NumDirs = j - list;
72         qsort(list, *NumDirs, sizeof(char *), (int (*)( const void *, const void * ))file_sort_func);
73
74         if (*dir)
75         {
76                 // Put the 'go to parent directory' sequence '..' first
77                 (*NumDirs)++;
78                 list = realloc(list, sizeof(char *)*(*NumDirs + 1));
79                 list[*NumDirs] = NULL;  // terminate
80                 for (i = list + *NumDirs - 1; i != list; i--)
81                         *i = i[-1];
82                 list[0] = strdup("..");
83         }
84
85         return list;
86 }
87
88 char **file_getfilelist(int *NumFiles, char *filespec, char *dir)
89 {
90         char **list = PHYSFS_enumerateFiles(dir);
91         char **i, **j = list, *ext;
92
93         if (!list)
94                 return NULL;
95
96         if (*filespec == '*')
97                 filespec++;
98
99         for (i = list; *i; i++)
100         {
101                 ext = strrchr(*i, '.');
102                 if (ext && (!stricmp(ext, filespec)))
103                         *j++ = *i;
104                 else
105                         free(*i);
106         }
107         *j = NULL;
108
109
110         *NumFiles = j - list;
111         qsort(list, *NumFiles, sizeof(char *), (int (*)( const void *, const void * ))file_sort_func);
112
113         return list;
114 }
115
116 int ui_get_filename( char * filename, char * Filespec, char * message  )
117 {
118         char            ViewDir[PATH_MAX];
119         char            InputText[PATH_MAX];
120         char            *p;
121         PHYSFS_file     *TempFile;
122         int                     NumFiles, NumDirs,i;
123         char            **filename_list;
124         char            **directory_list;
125         char            Spaces[35];
126         UI_WINDOW                       *wnd;
127         UI_GADGET_BUTTON        *Button1, *Button2, *HelpButton;
128         UI_GADGET_LISTBOX       *ListBox1;
129         UI_GADGET_LISTBOX       *ListBox2;
130         UI_GADGET_INPUTBOX      *UserFile;
131         int                             new_listboxes;
132
133         if ((p = strrchr(filename, '/')))
134         {
135                 *p++ = 0;
136                 strcpy(ViewDir, filename);
137                 strcpy(InputText, p);
138         }
139         else
140         {
141                 strcpy(ViewDir, "");
142                 strcpy(InputText, filename);
143         }
144
145         filename_list = file_getfilelist(&NumFiles, Filespec, ViewDir);
146         directory_list = file_getdirlist(&NumDirs, ViewDir);
147
148         // Running out of memory may become likely in the future
149         if (!filename_list && !directory_list)
150                 return 0;
151
152         if (!filename_list)
153         {
154                 PHYSFS_freeList(directory_list);
155                 return 0;
156         }
157
158         if (!directory_list)
159         {
160                 PHYSFS_freeList(filename_list);
161                 return 0;
162         }
163
164         //MessageBox( -2,-2, 1,"DEBUG:0", "Ok" );
165         for (i=0; i<35; i++)
166                 Spaces[i] = ' ';
167         Spaces[34] = 0;
168
169         wnd = ui_open_window( 200, 100, 400, 370, WIN_DIALOG );
170
171         ui_wprintf_at( wnd, 10, 5, message );
172
173         ui_wprintf_at( wnd, 20, 32,"N&ame" );
174         UserFile  = ui_add_gadget_inputbox( wnd, 60, 30, PATH_MAX, 40, InputText );
175
176         ui_wprintf_at( wnd, 20, 86,"&Files" );
177         ui_wprintf_at( wnd, 210, 86,"&Dirs" );
178
179         ListBox1 = ui_add_gadget_listbox(wnd,  20, 110, 125, 200, NumFiles, filename_list);
180         ListBox2 = ui_add_gadget_listbox(wnd, 210, 110, 100, 200, NumDirs, directory_list);
181
182         Button1 = ui_add_gadget_button( wnd,     20, 330, 60, 25, "Ok", NULL );
183         Button2 = ui_add_gadget_button( wnd,    100, 330, 60, 25, "Cancel", NULL );
184         HelpButton = ui_add_gadget_button( wnd, 180, 330, 60, 25, "Help", NULL );
185
186         wnd->keyboard_focus_gadget = (UI_GADGET *)UserFile;
187
188         Button1->hotkey = KEY_CTRLED + KEY_ENTER;
189         Button2->hotkey = KEY_ESC;
190         HelpButton->hotkey = KEY_F1;
191         ListBox1->hotkey = KEY_ALTED + KEY_F;
192         ListBox2->hotkey = KEY_ALTED + KEY_D;
193         UserFile->hotkey = KEY_ALTED + KEY_A;
194
195         ui_gadget_calc_keys(wnd);
196
197         ui_wprintf_at( wnd, 20, 60, "%s", Spaces );
198         ui_wprintf_at( wnd, 20, 60, "%s", ViewDir );
199
200         new_listboxes = 0;
201
202         while( 1 )
203         {
204                 ui_mega_process();
205                 ui_window_do_gadgets(wnd);
206
207                 if ( Button2->pressed )
208                 {
209                         PHYSFS_freeList(filename_list);
210                         PHYSFS_freeList(directory_list);
211                         ui_close_window(wnd);
212                         return 0;
213                 }
214
215                 if ( HelpButton->pressed )
216                         MessageBox( -1, -1, 1, "Sorry, no help is available!", "Ok" );
217
218                 if (ListBox1->moved || new_listboxes)
219                 {
220                         if (ListBox1->current_item >= 0 )
221                         {
222                                 strcpy(UserFile->text, filename_list[ListBox1->current_item] );
223                                 UserFile->position = strlen(UserFile->text);
224                                 UserFile->oldposition = UserFile->position;
225                                 UserFile->status=1;
226                                 UserFile->first_time = 1;
227                         }
228                 }
229
230                 if (ListBox2->moved || new_listboxes)
231                 {
232                         if (ListBox2->current_item >= 0 )
233                         {
234                                 strcpy(UserFile->text, directory_list[ListBox2->current_item]);
235                                 UserFile->position = strlen(UserFile->text);
236                                 UserFile->oldposition = UserFile->position;
237                                 UserFile->status=1;
238                                 UserFile->first_time = 1;
239                         }
240                 }
241                 new_listboxes = 0;
242
243                 if (Button1->pressed || UserFile->pressed || (ListBox1->selected_item > -1 ) || (ListBox2->selected_item > -1 ))
244                 {
245                         ui_mouse_hide();
246
247                         if (ListBox2->selected_item > -1 )
248                                 strcpy(UserFile->text, directory_list[ListBox2->selected_item]);
249
250                         strncpy(filename, ViewDir, PATH_MAX);
251
252                         p = UserFile->text;
253                         while (!strncmp(p, "..", 2))    // shorten the path manually
254                         {
255                                 char *sep = strrchr(filename, '/');
256                                 if (sep)
257                                         *sep = 0;
258                                 else
259                                         *filename = 0;  // look directly in search paths
260
261                                 p += 2;
262                                 if (*p == '/')
263                                         p++;
264                         }
265
266                         if (*filename && *p)
267                                 strncat(filename, "/", PATH_MAX - strlen(filename));
268                         strncat(filename, p, PATH_MAX - strlen(filename));
269
270                         if (!PHYSFS_isDirectory(filename))
271                         {
272                                 TempFile = PHYSFS_openRead(filename);
273                                 if (TempFile)
274                                 {
275                                         // Looks like a valid filename that already exists!
276                                         PHYSFS_close(TempFile);
277                                         break;
278                                 }
279         
280                                 // File doesn't exist, but can we create it?
281                                 TempFile = PHYSFS_openWrite(filename);
282                                 if (TempFile)
283                                 {
284                                         // Looks like a valid filename!
285                                         PHYSFS_close(TempFile);
286                                         PHYSFS_delete(filename);
287                                         break;
288                                 }
289                         }
290                         else
291                         {
292                                 if (filename[strlen(filename) - 1] == '/')      // user typed a separator on the end
293                                         filename[strlen(filename) - 1] = 0;
294         
295                                 strcpy(ViewDir, filename);
296         
297                                 //mprintf( 0, "----------------------------\n" );
298                                 //mprintf( 0, "Full dir: '%s'\n", ViewDir );
299         
300                                 PHYSFS_freeList(filename_list);
301                                 filename_list = file_getfilelist(&NumFiles, Filespec, ViewDir);
302                                 if (!filename_list)
303                                 {
304                                         PHYSFS_freeList(directory_list);
305                                         return 0;
306                                 }
307
308                                 strcpy(UserFile->text, Filespec);
309                                 UserFile->position = strlen(UserFile->text);
310                                 UserFile->oldposition = UserFile->position;
311                                 UserFile->status=1;
312                                 UserFile->first_time = 1;
313
314                                 PHYSFS_freeList(directory_list);
315                                 directory_list = file_getdirlist(&NumDirs, ViewDir);
316                                 if (!directory_list)
317                                 {
318                                         PHYSFS_freeList(filename_list);
319                                         return 0;
320                                 }
321
322                                 ui_listbox_change(wnd, ListBox1, NumFiles, filename_list);
323                                 ui_listbox_change(wnd, ListBox2, NumDirs, directory_list);
324                                 new_listboxes = 0;
325
326                                 ui_wprintf_at( wnd, 20, 60, "%s", Spaces );
327                                 ui_wprintf_at( wnd, 20, 60, "%s", ViewDir );
328
329                                 //i = TICKER;
330                                 //while ( TICKER < i+2 );
331
332                         }
333
334                         ui_mouse_show();
335
336                 }
337
338                 gr_update();
339         }
340
341         //key_flush();
342
343         ui_close_window(wnd);
344         if (filename_list)
345                 PHYSFS_freeList(filename_list);
346         if (directory_list)
347                 PHYSFS_freeList(directory_list);
348
349         return 1;
350 }
351
352
353
354 int ui_get_file( char * filename, char * Filespec  )
355 {
356         int x, NumFiles;
357         char **list = file_getfilelist(&NumFiles, Filespec, "");
358
359         if (!list) return 0;
360
361         x = MenuX(-1, -1, NumFiles, list);
362
363         if (x > 0)
364                 strcpy(filename, list[x - 1]);
365
366         PHYSFS_freeList(list);
367
368         return (x > 0);
369 }
370