filepick.c 18.5 KB
Newer Older
1 2
#include <ctype.h>

3 4 5 6 7 8
#include "dirwrap.h"
#include "uifc.h"
#include "ciolib.h"

#include "filepick.h"

9 10 11 12
enum {
	 DIR_LIST
	,FILE_LIST
	,MASK_FIELD
deuce's avatar
deuce committed
13
	,CURRENT_PATH
14 15
	,FIELD_LIST_TERM
};
16

17
void drawfpwindow(uifcapi_t *api)
18
{
19
	struct vmem_cell lbuf[512];
20 21 22 23 24
	int i;
	int j;
	int listheight=0;
	int height;
	int width;
25
	struct vmem_cell shade[512];
26 27 28

	width=SCRN_RIGHT-SCRN_LEFT+1;

deuce's avatar
deuce committed
29
	height=api->scrn_len-3;
30 31 32 33
	/* Make sure it's odd */
	if(!(width%2))
		width--;

deuce's avatar
deuce committed
34
	listheight=height-7;
35

36
        i=0;
37 38 39
	set_vmem(&lbuf[i++], '\xc9', api->hclr|(api->bclr<<4), 0);
	for(j=1;j<width-1;j++)
		set_vmem(&lbuf[i++], '\xcd', api->hclr|(api->bclr<<4), 0);
40
	if(api->mode&UIFC_MOUSE && width>6) {
41 42 43 44 45 46
		set_vmem(&lbuf[1], '[', api->hclr|(api->bclr<<4), 0);
		set_vmem(&lbuf[2], '\xfe', api->lclr|(api->bclr<<4), 0);
		set_vmem(&lbuf[3], ']', api->hclr|(api->bclr<<4), 0);
		set_vmem(&lbuf[4], '[', api->hclr|(api->bclr<<4), 0);
		set_vmem(&lbuf[5], '?', api->lclr|(api->bclr<<4), 0);
		set_vmem(&lbuf[6], ']', api->hclr|(api->bclr<<4), 0);
47 48 49 50 51 52
		api->buttony=SCRN_TOP;
		api->exitstart=SCRN_LEFT+1;
		api->exitend=SCRN_LEFT+3;
		api->helpstart=SCRN_LEFT+4;
		api->helpend=SCRN_LEFT+6;
	}
53 54 55 56 57 58 59 60 61
	set_vmem(&lbuf[i++], '\xbb', api->hclr|(api->bclr<<4), 0);
	vmem_puttext(SCRN_LEFT,SCRN_TOP,SCRN_LEFT+width-1,SCRN_TOP,lbuf);
	set_vmem_attr(&lbuf[2], api->hclr|(api->bclr<<4));
	set_vmem_attr(&lbuf[5], api->hclr|(api->bclr<<4));
	for(j=1;j<7;j++)
		lbuf[j].ch='\xcd';
	lbuf[0].ch='\xc8';
	lbuf[(width-1)].ch='\xbc';
	vmem_puttext(SCRN_LEFT,SCRN_TOP+height-1
62
		,SCRN_LEFT+width-1,SCRN_TOP+height-1,lbuf);
63 64 65 66 67 68
	lbuf[0].ch='\xcc';
	lbuf[(width-1)].ch='\xb9';
	lbuf[(width-1)/2].ch='\xcb';
	vmem_puttext(SCRN_LEFT,SCRN_TOP+2,SCRN_LEFT+width-1,SCRN_TOP+2,lbuf);
	lbuf[(width-1)/2].ch='\xca';
	vmem_puttext(SCRN_LEFT,SCRN_TOP+3+listheight
69
		,SCRN_LEFT+width-1,SCRN_TOP+3+listheight,lbuf);
70 71 72 73 74
	lbuf[0].ch='\xba';
	lbuf[(width-1)].ch='\xba';
	for(j=1;j<(width-1);j++)
		lbuf[j].ch=' ';
	vmem_puttext(SCRN_LEFT,SCRN_TOP+1,
75
		SCRN_LEFT+width-1,SCRN_TOP+1,lbuf);
76
	vmem_puttext(SCRN_LEFT,SCRN_TOP+height-2,
77
		SCRN_LEFT+width-1,SCRN_TOP+height-2,lbuf);
78
	vmem_puttext(SCRN_LEFT,SCRN_TOP+height-3,
79
		SCRN_LEFT+width-1,SCRN_TOP+height-3,lbuf);
80
	lbuf[(width-1)/2].ch='\xba';
81
	for(j=0;j<listheight;j++)
82
		vmem_puttext(SCRN_LEFT,SCRN_TOP+3+j
83 84 85
			,SCRN_LEFT+width-1,SCRN_TOP+3+j,lbuf);

	/* Shadow */
86
	if(api->bclr==BLUE) {
87
		vmem_gettext(SCRN_LEFT+width,SCRN_TOP+1,SCRN_LEFT+width+1
88
			,SCRN_TOP+(height-1),shade);
89 90 91
		for(j=0;j<512;j++)
			set_vmem_attr(&shade[j], DARKGRAY);
		vmem_puttext(SCRN_LEFT+width,SCRN_TOP+1,SCRN_LEFT+width+1
92
			,SCRN_TOP+(height-1),shade);
93
		vmem_gettext(SCRN_LEFT+2,SCRN_TOP+height,SCRN_LEFT+width+1
94
			,SCRN_TOP+height,shade);
95 96 97
		for(j=0;j<width;j++)
			set_vmem_attr(&shade[j], DARKGRAY);
		vmem_puttext(SCRN_LEFT+2,SCRN_TOP+height,SCRN_LEFT+width+1
98 99 100 101
			,SCRN_TOP+height,shade);
	}
}

102
void free_opt_list(char ***opts)
103 104 105
{
	char **p;

106 107 108 109 110
	if(*opts==NULL)
		return;
	for(p=*opts; *p && (*p)[0]; p++) {
		if(*p)
			FREE_AND_NULL((*p));
111
	}
112
	FREE_AND_NULL(*opts);
113 114
}

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
char *insensitive_mask(char *mask)
{
#ifdef __unix__
	char *in;
	char *out;
	static char nmask[MAX_PATH*4+1];

	out=nmask;
	for(in=mask; *in; in++) {
		if(isalpha(*in)) {
			*(out++)='[';
			*(out++)=tolower(*in);
			*(out++)=toupper(*in);
			*(out++)=']';
		}
		else
			*(out++)=*in;
	}
	*out=0;
	return(nmask);
#else
	return(mask);
#endif
}

140 141 142 143 144 145 146 147 148
char **get_file_opt_list(char **fns, int files, int dirsonly, int root)
{
	char **opts;
	int  i;
	int  j=0;

	opts=(char **)malloc((files+2)*sizeof(char *));
	if(opts==NULL)
		return(NULL);
149
	memset(opts, 0, (files+2)*sizeof(char *));
150 151 152 153 154 155 156
	if(dirsonly) {
		if(!root)
			opts[j++]=strdup("..");
	}
	for(i=0;i<files;i++) {
		if(isdir(fns[i])) {
			if(dirsonly)
157
				opts[j++]=strdup(getdirname(fns[i]));
158 159 160 161 162 163 164 165 166 167
		}
		else {
			if(!dirsonly)
				opts[j++]=strdup(getfname(fns[i]));
		}
	}
	opts[j]="";
	return(opts);
}

168 169 170
void display_current_path(uifcapi_t *api, char *path)
{
	char	dpath[MAX_PATH+2];
deuce's avatar
deuce committed
171
	size_t	width;
172
	int height;
deuce's avatar
deuce committed
173
#ifdef _WIN32
deuce's avatar
deuce committed
174
	char	*p;
deuce's avatar
deuce committed
175
#endif
176

deuce's avatar
deuce committed
177
	height=api->scrn_len-3;
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
	width=SCRN_RIGHT-SCRN_LEFT-3;
	SAFECOPY(dpath, path);
	while(strlen(dpath) > width) {
		/* Just remove paths from the start. */
		dpath[0]='.';
		dpath[1]='.';
		dpath[2]='.';
		memmove(dpath+3, dpath+(strlen(dpath)-width+4), width-1);
	}
	/* For Win32, convert all "confusing" / to \\ */
#ifdef _WIN32
	for(p=dpath; *p; p++) {
		if(*p=='/')
			*p='\\';
	}
193 194
	if (strncmp(dpath, "\\\\?\\", 4)==0)
		memmove(dpath, dpath+4, strlen(dpath+3));
195 196
#endif

deuce's avatar
deuce committed
197
	api->printf(SCRN_LEFT+2, SCRN_TOP+height-2, api->lclr|(api->bclr<<4), "%-*s", width, dpath);
198 199
}

deuce's avatar
deuce committed
200
int mousetofield(int currfield, int opts, int height, int width, int listheight, int listwidth, int *dcur, int *dbar, int *fcur, int *fbar)
deuce's avatar
deuce committed
201 202
{
	int newfield;
deuce's avatar
deuce committed
203
	int bardif;
deuce's avatar
deuce committed
204 205 206 207 208 209 210 211 212
	struct mouse_event mevnt;

	newfield=currfield;
	if(getmouse(&mevnt)==0) {
		if(mevnt.endx >= SCRN_LEFT + 1
				&& mevnt.endx <= SCRN_LEFT + listwidth
				&& mevnt.endy >= SCRN_TOP + 3
				&& mevnt.endy <= SCRN_TOP + 2 + listheight) {
			newfield = DIR_LIST;
deuce's avatar
deuce committed
213 214 215 216 217 218 219
			if(mevnt.endx == SCRN_LEFT + 1)
				ungetmouse(&mevnt);
			else {
				bardif = (mevnt.starty - SCRN_TOP - 3) - *dbar;
				*dbar += bardif;
				*dcur += bardif;
			}
deuce's avatar
deuce committed
220 221 222 223 224 225
		}
		if(mevnt.endx >= SCRN_LEFT + 1 + listwidth + 1
				&& mevnt.endx <= SCRN_LEFT + 1 + listwidth * 2
				&& mevnt.endy >= SCRN_TOP + 3
				&& mevnt.endy <= SCRN_TOP + 2 + listheight) {
			newfield = FILE_LIST;
deuce's avatar
deuce committed
226 227 228 229 230 231 232
			if(mevnt.endx == SCRN_LEFT + 1 + listwidth + 1)
				ungetmouse(&mevnt);
			else {
				bardif = (mevnt.starty - SCRN_TOP - 3) - *fbar;
				*fbar += bardif;
				*fcur += bardif;
			}
deuce's avatar
deuce committed
233 234 235 236 237 238
		}
		if(!(opts & UIFC_FP_MSKNOCHG)
				&& (mevnt.endx >= SCRN_LEFT + 1
					&& mevnt.endx <= SCRN_LEFT + width - 2
					&& mevnt.endy == SCRN_TOP + height - 3)) {
			newfield = MASK_FIELD;
deuce's avatar
deuce committed
239
			ungetmouse(&mevnt);
deuce's avatar
deuce committed
240 241 242 243 244 245 246
		}
		if(opts & UIFC_FP_ALLOWENTRY
				&& mevnt.endx >= SCRN_LEFT + 1
				&& mevnt.endx <= SCRN_LEFT + width - 2
				&& mevnt.endy == SCRN_TOP + height - 2) {
			newfield = CURRENT_PATH;
			ungetmouse(&mevnt);
deuce's avatar
deuce committed
247
		}
deuce's avatar
deuce committed
248 249 250 251
	}
	return(newfield);
}

252 253
int filepick(uifcapi_t *api, char *title, struct file_pick *fp, char *dir, char *msk, int opts)
{
254 255
	char	cfile[MAX_PATH*8+1];		/* Current full path to file */
	char	cpath[(MAX_PATH<<2)+1];			/* Current path */
256 257 258 259 260 261
	char	drive[3];
	char	tdir[MAX_PATH+1];
	char	fname[MAX_PATH+1];
	char	ext[MAX_PATH+1];
	char	cmsk[MAX_PATH*4+1];			/* Current file mask */
	char	cglob[MAX_PATH*4+1];		/* File glob patter */
262
	char	dglob[MAX_PATH*4+2];		/* Directory glob pattern */
263 264 265
	char	*p;
	glob_t	fgl;						/* Files */
	glob_t	dgl;						/* Directories */
266 267 268 269
	int		dircur=0;
	int		dirbar=0;
	int		filecur=0;
	int		filebar=0;
270
	int		listwidth;
271 272
	char	**dir_list=NULL;
	char	**file_list=NULL;
273 274
	int		currfield;
	int		lastfield;
275
	int		i;
276 277 278
	int		root=0;						/* Is this the root of the file system? */
										/* On *nix, this just means no .. on Win32,
										 * Something should be done about drive letters. */
279 280
	int		reread=FALSE;
	int		lbclr;
281
	char	*lastpath=NULL;
282 283
	char	*tmplastpath=NULL;
	char	*tmppath=NULL;
284 285
	int		width;
	int		height;
286 287
	char	*YesNo[]={"Yes", "No", ""};
	int		finished=FALSE;
288
	int		retval=0;
deuce's avatar
deuce committed
289
	int		fieldmove;
deuce's avatar
deuce committed
290
	int		oldhu=hold_update;
deuce's avatar
deuce committed
291 292
	int		oldx=wherex();
	int		oldy=wherey();
293

deuce's avatar
deuce committed
294
	height=api->scrn_len-3;
295
	width=SCRN_RIGHT-SCRN_LEFT-3;
296 297

	lbclr=api->lbclr;
298 299 300 301 302 303

	/* No struct passed */
	if(fp==NULL)
		return(-1);

	/* Illegal options */
deuce's avatar
deuce committed
304
	if((opts & UIFC_FP_MULTI)==UIFC_FP_MULTI && (opts & (UIFC_FP_ALLOWENTRY|UIFC_FP_OVERPROMPT|UIFC_FP_CREATPROMPT)))
305 306
		return(-1);

307 308 309 310 311
	if (opts & UIFC_FP_DIRSEL)
		currfield = lastfield = DIR_LIST;
	else
		currfield = lastfield = FILE_LIST;

312 313 314
	fp->files=0;
	fp->selected=NULL;

315 316 317 318 319
	/* No initial path specified */
	if(dir==NULL || !dir[0])
		SAFECOPY(cpath,".");

	FULLPATH(cpath,((dir==NULL||dir[0]==0)?".":dir),sizeof(cpath));
deuce's avatar
deuce committed
320
	backslash(cpath);
321 322 323 324 325 326 327

	if(msk==NULL || msk[0]==0) {
		SAFECOPY(cmsk,"*");
	}
	else {
		SAFECOPY(cmsk,msk);
	}
328
	sprintf(cfile,"%s%s",cpath,cmsk);
329 330
	listwidth=SCRN_RIGHT-SCRN_LEFT+1;
	listwidth-=listwidth%2;
331
	listwidth-=3;
332 333
	listwidth/=2;
	/* Draw the file picker itself... */
334
	hold_update = TRUE;
335
	drawfpwindow(api);
336 337 338 339 340
	/* Display the title centered */
	i=strlen(title);
	if(i>width-4)
		i=width-4;
	api->printf(SCRN_LEFT+2, SCRN_TOP+1, api->hclr|(api->bclr<<4), "%*s%-*s", (width-i)/2-2, "", i, title);
deuce's avatar
deuce committed
341
	api->printf(SCRN_LEFT+2, SCRN_TOP+height-3, api->hclr|(api->bclr<<4), "Mask: ");
342
	while(!finished) {
343
		hold_update = TRUE;
deuce's avatar
deuce committed
344
		api->printf(SCRN_LEFT+8, SCRN_TOP+height-3, api->lclr|(api->bclr<<4), "%-*s", width-7, cmsk);
345
		tmppath=strdup(cpath);
346 347 348 349 350 351 352 353 354 355 356 357
		if(tmppath != NULL) {
#ifdef _WIN32
			if (tmppath[0] == 0 || (tmppath[5]==0 && tmppath[3]=='.' && tmppath[4]=='.' && tmppath[1]==':' && IS_PATH_DELIM(tmppath[2])))
				strcpy(cpath, "\\\\?\\");
			else if(strncmp(tmppath, "\\\\?\\", 4)==0 && tmppath[4])
				strcpy(cpath, tmppath+4);
			else
#endif
			{
				FULLPATH(cpath,tmppath,sizeof(cpath));
			}
		}
358 359
		FREE_AND_NULL(tmppath);

deuce's avatar
deuce committed
360 361 362 363 364 365
#ifdef __unix__
		if(cpath[0]==0) {
			cpath[0]='/';
			cpath[1]=0;
		}
#endif
deuce's avatar
deuce committed
366
		backslash(cpath);
367 368
		sprintf(cglob,"%s%s",cpath,(opts&UIFC_FP_MSKCASE)?cmsk:insensitive_mask(cmsk));
		sprintf(dglob,"%s*",cpath);
deuce's avatar
deuce committed
369 370 371
		switch(currfield) {
			case DIR_LIST:
				if(lastfield==DIR_LIST)
372
					sprintf(cfile,"%s%s",cpath,cmsk);
deuce's avatar
deuce committed
373 374 375
				break;
		}

376
#ifdef __unix__
deuce's avatar
deuce committed
377 378 379 380
		if(cpath[0]==0) {
			cpath[0]='/';
			cpath[1]=0;
		}
381
		if(cpath[1]==0)
382
			root=TRUE;
383 384
		else
			root=FALSE;
385
#endif
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421

#ifdef _WIN32
		if (strcmp(cpath, "\\\\?\\")==0)
			root = TRUE;
		else
			root = FALSE;
#endif

#ifdef _WIN32
		// Hack together some hawtness
		if (root) {
			unsigned long drives = _getdrives();
			int j;
			char path[4];

			memset(&dgl, 0, sizeof(dgl));
			strcpy(path, "A:\\");
			dgl.gl_pathv=malloc(sizeof(char *)*('Z'-'A'+2));
			for (j=0; j<='Z'-'A'; j++) {
				if(drives & (1<<j)) {
					path[0]='A'+j;
					dgl.gl_pathv[dgl.gl_pathc++]=strdup(path);
				}
			}
		}
		else 
#endif
		{
			if(glob(dglob, GLOB_MARK, NULL, &dgl)!=0 && !isdir(cpath)) {
				if(lastpath==NULL) {
					fp->files=0;
					retval=-1;
					goto cleanup;
				}
				hold_update=FALSE;
				api->msg("Cannot read directory!");
deuce's avatar
deuce committed
422 423 424 425
				if (api->exit_flags & UIFC_XF_QUIT) {
					retval=fp->files=0;
					goto cleanup;
				}
426 427 428 429
				SAFECOPY(cpath, lastpath);
				FREE_AND_NULL(lastpath);
				currfield=lastfield;
				continue;
430
			}
431
		}
deuce's avatar
deuce committed
432 433
		if(glob(cglob, 0, NULL, &fgl)!=0)
			fgl.gl_pathc=0;
deuce's avatar
deuce committed
434
		api->list_height=api->scrn_len-3-7;
deuce's avatar
deuce committed
435
		dir_list=get_file_opt_list(dgl.gl_pathv, dgl.gl_pathc, TRUE, root);
436
		file_list=get_file_opt_list(fgl.gl_pathv, fgl.gl_pathc, FALSE, root);
deuce's avatar
deuce committed
437 438
		globfree(&dgl);
		globfree(&fgl);
439
		reread=FALSE;
440
		dircur=dirbar=filecur=filebar=0;
441
		while(!reread) {
442
			hold_update=TRUE;
deuce's avatar
deuce committed
443
			display_current_path(api, cfile);
444 445 446 447
			api->lbclr=api->lclr|(api->bclr<<4);
			api->list(WIN_NOBRDR|WIN_FIXEDHEIGHT|WIN_IMM|WIN_REDRAW,1,3,listwidth,&dircur,&dirbar,NULL,dir_list);
			api->list(WIN_NOBRDR|WIN_FIXEDHEIGHT|WIN_IMM|WIN_REDRAW,1+listwidth+1,3,listwidth,&filecur,&filebar,NULL,file_list);
			api->lbclr=lbclr;
448
			lastfield=currfield;
deuce's avatar
deuce committed
449
			fieldmove=0;
450
			hold_update = FALSE;
451 452
			switch(currfield) {
				case DIR_LIST:
453
					i=api->list(WIN_DYN|WIN_NOBRDR|WIN_FIXEDHEIGHT|WIN_EXTKEYS|WIN_UNGETMOUSE|WIN_REDRAW,1,3,listwidth,&dircur,&dirbar,NULL,dir_list);
deuce's avatar
deuce committed
454
					if(i==-1) {		/* ESC */
455
						retval=fp->files=0;
456 457
						goto cleanup;
					}
458
					if(i==-2-'\t' || i==-2-CIO_KEY_RIGHT)	/* TAB */
deuce's avatar
deuce committed
459 460 461
						fieldmove=1;
					if(i==-3842)	/* Backtab */
						fieldmove=-1;
deuce's avatar
deuce committed
462
					if(i==-2-CIO_KEY_MOUSE)
deuce's avatar
deuce committed
463
						currfield=mousetofield(currfield, opts, height, width, api->list_height, listwidth, &dircur, &dirbar, &filecur, &filebar);
464
					if(i>=0) {
465 466
						FREE_AND_NULL(lastpath);
						lastpath=strdup(cpath);
467 468
						strcat(cpath,dir_list[i]);
						reread=TRUE;
469
						sprintf(cfile,"%s%s",cpath,cmsk);
470 471 472
					}
					break;
				case FILE_LIST:
473
					i=api->list(WIN_DYN|WIN_NOBRDR|WIN_FIXEDHEIGHT|WIN_EXTKEYS|WIN_UNGETMOUSE|WIN_REDRAW,1+listwidth+1,3,listwidth,&filecur,&filebar,NULL,file_list);
474
					if(i==-1) {
475
						retval=fp->files=0;
476 477
						goto cleanup;
					}
478
					if(i>=0) {
deuce's avatar
deuce committed
479
						sprintf(cfile,"%s%s",cpath,file_list[i]);
480 481 482 483 484
						if((opts & UIFC_FP_MULTI)!=UIFC_FP_MULTI) {
							retval=fp->files=1;
							fp->selected=(char **)malloc(sizeof(char *));
							if(fp->selected==NULL) {
								fp->files=0;
485
								retval=-1;
486 487 488 489
								goto cleanup;
							}
							fp->selected[0]=strdup(cfile);
							if(fp->selected[0]==NULL) {
490
								FREE_AND_NULL(fp->selected);
491
								fp->files=0;
492
								retval=-1;
493 494
								goto cleanup;
							}
deuce's avatar
deuce committed
495
							api->list(WIN_NOBRDR|WIN_FIXEDHEIGHT|WIN_IMM|WIN_REDRAW,1+listwidth+1,3,listwidth,&filecur,&filebar,NULL,file_list);
496
							finished=reread=TRUE;
497
						}
498
					}
deuce's avatar
deuce committed
499 500
					if(i==-2-'\t')
						fieldmove=1;
501
					if(i==-3842 || i==-2-CIO_KEY_LEFT)	/* Backtab */
deuce's avatar
deuce committed
502
						fieldmove=-1;
deuce's avatar
deuce committed
503
					if(i==-2-CIO_KEY_MOUSE)
deuce's avatar
deuce committed
504
						currfield=mousetofield(currfield, opts, height, width, api->list_height, listwidth, &dircur, &dirbar, &filecur, &filebar);
505 506 507 508
					break;
				case CURRENT_PATH:
					FREE_AND_NULL(tmplastpath);
					tmplastpath=strdup(cpath);
509 510 511 512 513 514
#ifdef _WIN32
					if (strncmp(tmplastpath, "\\\\?\\", 4)==0)
						memmove(tmplastpath, tmplastpath+4, strlen(tmplastpath+3));
					if (strncmp(cfile, "\\\\?\\", 4)==0)
						memmove(cfile, cfile+4, strlen(cfile+3));
#endif
deuce's avatar
deuce committed
515
					api->getstrxy(SCRN_LEFT+2, SCRN_TOP+height-2, width-1, cfile, sizeof(cfile)-1, K_EDIT|K_TABEXIT|K_MOUSEEXIT, &i);
516
					if(i==ESC) {
517
						retval=fp->files=0;
518 519
						goto cleanup;
					}
deuce's avatar
deuce committed
520
					if((opts & (UIFC_FP_FILEEXIST|UIFC_FP_PATHEXIST)) && !fexist(cfile)) {
521 522 523 524 525 526
#ifdef _WIN32
						if (cfile[0])	// Allow zero-length path to mean "Drive list"
#endif
						{
							FREE_AND_NULL(tmplastpath);
							api->msg("No such path/file!");
deuce's avatar
deuce committed
527 528 529 530
							if (api->exit_flags & UIFC_XF_QUIT) {
								retval=fp->files=0;
								goto cleanup;
							}
531 532
							continue;
						}
deuce's avatar
deuce committed
533
					}
534
					if(isdir(cfile) && cfile[0])
deuce's avatar
deuce committed
535
						backslash(cfile);
536 537
					_splitpath(cfile, drive, tdir, fname, ext);
					sprintf(cpath,"%s%s",drive,tdir);
538
					if(!isdir(cpath)) {
539 540 541 542 543 544
#ifdef _WIN32
						if (cfile[0] && strcmp(cfile, cmsk))	// Allow zero-length path to mean "Drive list"
#endif
						{
							FREE_AND_NULL(tmplastpath);
							api->msg("No such path!");
deuce's avatar
deuce committed
545 546 547 548
							if (api->exit_flags & UIFC_XF_QUIT) {
								retval=fp->files=0;
								goto cleanup;
							}
549 550
							continue;
						}
551
					}
deuce's avatar
deuce committed
552
					if(i==CIO_KEY_MOUSE)
deuce's avatar
deuce committed
553
						currfield=mousetofield(currfield, opts, height, width, api->list_height, listwidth, &dircur, &dirbar, &filecur, &filebar);
deuce's avatar
deuce committed
554 555 556 557 558 559
					if(i==3840)
						fieldmove=-1;
					else {
						if(currfield == CURRENT_PATH)
							fieldmove=1;
					}
560
					sprintf(cfile,"%s%s%s%s",drive,tdir,fname,ext);
deuce's avatar
deuce committed
561
					if(strchr(fname,'*') !=NULL || strchr(fname,'?') !=NULL
562
						|| strchr(ext,'*') !=NULL || strchr(ext,'?') !=NULL
563
						|| ((isdir(cfile) || cfile[0]==0) && !(opts & UIFC_FP_DIRSEL) && (i=='\r' || i=='\n'))
564
						|| (!isdir(cfile) && i!='\r' && i!='\n')) {
deuce's avatar
deuce committed
565 566 567 568
						if(opts & UIFC_FP_MSKNOCHG) {
							sprintf(cfile,"%s%s%s",drive,tdir,cmsk);
							FREE_AND_NULL(tmplastpath);
							api->msg("File mask cannot be changed");
deuce's avatar
deuce committed
569 570 571 572
							if (api->exit_flags & UIFC_XF_QUIT) {
								retval=fp->files=0;
								goto cleanup;
							}
deuce's avatar
deuce committed
573 574 575
							continue;
						}
						else {
576
							if((!isdir(cfile)) && cpath[0] != 0)
deuce's avatar
deuce committed
577
								sprintf(cmsk, "%s%s", fname, ext);
deuce's avatar
deuce committed
578 579 580 581
							reread=TRUE;
						}
						break;
					}
582 583 584 585
					else {
						if((opts & UIFC_FP_MULTI)!=UIFC_FP_MULTI && (i=='\r' || i!='\n'))
						fieldmove=0;
					}
deuce's avatar
deuce committed
586 587
					if((currfield != CURRENT_PATH) || fieldmove)
						break;
deuce's avatar
deuce committed
588
					if(isdir(cfile)) {
deuce's avatar
deuce committed
589
						if((opts & UIFC_FP_MULTI)!=UIFC_FP_MULTI && i!='\t' && i != 3840) {
590
							if(opts & UIFC_FP_DIRSEL) {
591
								finished=reread=TRUE;
592 593 594 595
								retval=fp->files=1;
								fp->selected=(char **)malloc(sizeof(char *));
								if(fp->selected==NULL) {
									fp->files=0;
596
									retval=-1;
597 598 599 600 601 602
									goto cleanup;
								}
								fp->selected[0]=strdup(cfile);
								if(fp->selected[0]==NULL) {
									free(fp->selected);
									fp->files=0;
603
									retval=-1;
604 605 606
									goto cleanup;
								}
							}
607
						}
deuce's avatar
deuce committed
608 609 610 611
						SAFECOPY(cpath, cfile);
						backslash(cfile);
						strcat(cfile,cmsk);
					}
612 613 614 615 616 617 618 619 620
					if(tmplastpath != NULL) {
						if(strcmp(tmplastpath, cpath)) {
							reread=TRUE;
							FREE_AND_NULL(lastpath);
							lastpath=tmplastpath;
							tmplastpath=NULL;
						}
					}
					FREE_AND_NULL(tmplastpath);
621
					if((opts & UIFC_FP_MULTI)!=UIFC_FP_MULTI && i!='\t' && i!=3840 && cpath[0]) {
622 623 624 625
						retval=fp->files=1;
						fp->selected=(char **)malloc(sizeof(char *));
						if(fp->selected==NULL) {
							fp->files=0;
626
							retval=-1;
627 628 629 630
							goto cleanup;
						}
						fp->selected[0]=strdup(cfile);
						if(fp->selected[0]==NULL) {
631
							FREE_AND_NULL(fp->selected);
632
							fp->files=0;
633
							retval=-1;
634 635
							goto cleanup;
						}
636 637
						finished=reread=TRUE;
					}
638
					break;
deuce's avatar
deuce committed
639
				case MASK_FIELD:
640
					p=strdup(cmsk);
deuce's avatar
deuce committed
641 642
					api->getstrxy(SCRN_LEFT+8, SCRN_TOP+height-3, width-7, cmsk, sizeof(cmsk)-1, K_EDIT|K_TABEXIT|K_MOUSEEXIT, &i);
					if(i==CIO_KEY_MOUSE)
deuce's avatar
deuce committed
643
						currfield=mousetofield(currfield, opts, height, width, api->list_height, listwidth, &dircur, &dirbar, &filecur, &filebar);
deuce's avatar
deuce committed
644
					if(i==ESC || i==CIO_KEY_QUIT || (api->exit_flags & UIFC_XF_QUIT)) {
645
						FREE_AND_NULL(p);
646
						retval=fp->files=0;
647 648 649
						goto cleanup;
					}
					if(strcmp(cmsk, p)) {
deuce's avatar
deuce committed
650 651 652
						sprintf(cfile,"%s%s",cpath,cmsk);
						reread=TRUE;
					}
653
					FREE_AND_NULL(p);
deuce's avatar
deuce committed
654 655 656 657
					if(i==3840)
						fieldmove=-1;
					else
						fieldmove=1;
deuce's avatar
deuce committed
658
					break;
659
			}
deuce's avatar
deuce committed
660 661 662 663 664 665 666 667 668 669 670 671 672 673
			currfield+=fieldmove;
			if(currfield<0)
				currfield=FIELD_LIST_TERM-1;
			while(1) {
				if(currfield==MASK_FIELD && (opts & UIFC_FP_MSKNOCHG)) {
					currfield+=fieldmove;
					continue;
				}
				if(currfield==CURRENT_PATH && !(opts & UIFC_FP_ALLOWENTRY)) {
					currfield+=fieldmove;
					continue;
				}
				break;
			}
deuce's avatar
deuce committed
674
			if(currfield==FIELD_LIST_TERM)
675
				currfield=DIR_LIST;
676
		}
677 678
		free_opt_list(&file_list);
		free_opt_list(&dir_list);
679 680
		if(finished) {
			if((opts & UIFC_FP_OVERPROMPT) && fexist(cfile)) {
deuce's avatar
deuce committed
681 682 683 684 685
				if(api->list(WIN_MID|WIN_SAV, 0,0,0, &i, NULL, "File exists, overwrite?", YesNo)!=0) {
					if (api->exit_flags & UIFC_XF_QUIT) {
						retval=fp->files=0;
						goto cleanup;
					}
686
					finished=FALSE;
deuce's avatar
deuce committed
687
				}
688 689
			}
			if((opts & UIFC_FP_CREATPROMPT) && !fexist(cfile)) {
deuce's avatar
deuce committed
690 691 692 693 694
				if(api->list(WIN_MID|WIN_SAV, 0,0,0, &i, NULL, "File does not exist, create?", YesNo)!=0) {
					if (api->exit_flags & UIFC_XF_QUIT) {
						retval=fp->files=0;
						goto cleanup;
					}
695
					finished=FALSE;
deuce's avatar
deuce committed
696
				}
697 698
			}
		}
699 700
	}

701
cleanup:		/* Cleans up allocated variables returns from function */
deuce's avatar
deuce committed
702
	hold_update=oldhu;
deuce's avatar
deuce committed
703
	gotoxy(oldx,oldy);
704
	FREE_AND_NULL(lastpath);
705 706 707 708 709
	FREE_AND_NULL(tmppath);
	FREE_AND_NULL(tmplastpath);
	free_opt_list(&file_list);
	free_opt_list(&dir_list);
	return(retval);
710 711 712 713
}

int filepick_free(struct file_pick *fp)
{
714 715 716 717 718 719
	int i;

	for(i=0; i<fp->files; i++) {
		FREE_AND_NULL(fp->selected[i]);
	}
	FREE_AND_NULL(fp->selected);
720 721
	return(0);
}