From: cpg@cs.utexas.edu (Carlos M. Puchol)
Newsgroups: alt.toolkits.xview
Subject: Re: HELP! Find all files of a directory in Xview
Date: 31 Dec 1992 11:29:44 -0600
Organization: Department of Computer Sciences, UT Austin
NNTP-Posting-Host: thor.cs.utexas.edu

In article <hue.725789508@coney> hue@island.COM (Pond Scum) writes:
>rickg@eng.sun.com (The Tankster) writes:
>>according to the SunSoft toolkit strategy annoncement that
>>appeared awhile back, the XView toolkit itself will eventually
>>contain such an object.  i guess it depends on when you need it...
>
>Here in the Graphic Arts Division of Island Graphics we have at least
>four different file requesters (fortunately they are in four separate
>applications, not all in the same one).  I needed one and didn't find one

...

>So a month ago I decided to write the "ultimate file requester" which would
>hopefully make everyone here happy.  The main goal was to make it easy
>to use, and not force anyone into buying into my particular style of
>programming or force them to carry a lot of baggage around, so I did
>it as an XView extension.  Also, I wanted to emulate the behavior of

Well, sounds pretty nice to me. Judging from the name of the uuencoded file,
it is a snapshot of your "ultimate file requester". Are you going to contribute
your code to the net :-)

BTW, the code I posted had a minor error. I have fixed it and I had intorduced
sorting for the file & direcotry names (There wasn't at the beginning!).
Now it also remembers the CWD from invocation to invocation.

Help yourself.

-- Carlos

/*
 *      XGed : Graph Editor for the X Window System
 *
 *      Carlos Puchol (cpg@cs.utexas.edu)
 *
 *	This file is public domain. Do with it what you please.
 *	I am not to be held responsible for any damage caused by the use of this
 *	code. I would appreciate if you quote the authors, if you use this code.
 *
 *      %W%     %G%
 */

/*************************************************************************\
 *                                                                       *
 * FILE: dir_list.c                                                      *
 *                                                                       *
 * EXPORTED ROUTINES:                                                    *
 *                                                                       *
 * - get_filename_popup(char *label, void (*action)())                   *
 *                                                                       *
 *     This procedure creates two scrolling lists, one with directories  *
 *     and one with files.  It allows the user to search through         *
 *     directories for files and then select a file. The label is        *
 *     attached to the frame and the actual button "ok" button.          *
 *                                                                       *
 *     The procedure "action" will be called when the button is pressed  *
 *     or <cr> is pressed in the "file" line. It will be called with     *
 *     the absolute file name of the selected file.                      *
 *                                                                       *
 *     The popup window will remember the "current" directory from       *
 *     invocation to invocation.                                         *
 *                                                                       *
 * - destroy_filename_frame()                                            *
 *                                                                       *
 *     You can guess what it does!                                       *
 *                                                                       *
\*************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <xview/xview.h>
#include <xview/panel.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/param.h>
#include <xvged_objects.h>

#define DESELECT 0
#define SELECT 1
#define ENTRY_KEY 5877
#define NULL_STR ""

static Frame frame;
static Panel panel;
static Panel_item pi_dir, pi_file, ti_file, mi_dir, bi_open;
static DIR *dirp;
static struct dirent *entry;
static char *current;

static int num_files, num_dirs;
static void (*action_to_call)();

static int Action ();
static int Cancel ();
static void setup_list ();
static void dir_proc ();
static void file_proc ();
static int check_read ();
static void create_frame();

void  destroy_filename_frame()
{
	xv_destroy_safe (frame);
}

void get_filename_popup(label, action)
char	*label;
void	(*action)();
{
	static char initial[MAXPATHLEN]={'\0'};

	if (initial[0]=='\0') {
		getwd(initial);
		current = (char *) malloc (strlen (initial) + 1);
		memset (current, '\0', strlen (initial) + 1);
		strcat (current, initial);
		create_frame();
	}
	xv_set(bi_open, PANEL_LABEL_STRING, label, NULL);
	xv_set(frame, FRAME_LABEL, label, NULL);

/*	xv_set(frame, FRAME_LABEL, label, NULL); */

	action_to_call=action;

	if (check_read (current, NULL_STR))
		setup_list ();

	xv_set(frame, XV_SHOW, TRUE, NULL);

}

static void create_frame()
{

	frame = (Frame) xv_create (NULL, FRAME,
				   FRAME_LABEL, "File Open",
				   NULL);

	panel = (Panel) xv_create (frame, PANEL, NULL);

	mi_dir = (Panel_item) xv_create (panel, PANEL_MESSAGE,
					 PANEL_LABEL_STRING, current,
					 PANEL_LABEL_BOLD, TRUE,
					 XV_X, 20,
					 XV_Y, 20,
					 NULL);

	ti_file = (Panel_item) xv_create (panel, PANEL_TEXT,
					  PANEL_LABEL_STRING, "File:",
					  PANEL_VALUE_DISPLAY_LENGTH, 50,
					  PANEL_VALUE_STORED_LENGTH, 256,
					  PANEL_NEXT_ROW, -1,
					  PANEL_VALUE, NULL_STR,
					  PANEL_NOTIFY_PROC, Action,
					  NULL);

	pi_dir = (Panel_item) xv_create (panel, PANEL_LIST,
					 PANEL_LABEL_STRING, "Directories:",
					 PANEL_LIST_DISPLAY_ROWS, 10,
					 PANEL_CHOOSE_ONE, TRUE,
					 PANEL_CHOOSE_NONE, TRUE,
					 PANEL_READ_ONLY, TRUE,
					 PANEL_NOTIFY_PROC, dir_proc,
					 PANEL_NEXT_ROW, -1,
					 PANEL_LIST_WIDTH, 150,
					 PANEL_LAYOUT, PANEL_VERTICAL,
					 NULL);

	pi_file = (Panel_item) xv_create (panel, PANEL_LIST,
					  PANEL_LABEL_STRING, "Files:",
					  PANEL_LIST_DISPLAY_ROWS, 10,
					  PANEL_CHOOSE_ONE, TRUE,
					  PANEL_CHOOSE_NONE, TRUE,
					  PANEL_READ_ONLY, TRUE,
					  PANEL_NOTIFY_PROC, file_proc,
					  PANEL_LIST_WIDTH, 150,
					  PANEL_LAYOUT, PANEL_VERTICAL,
					  NULL);

	bi_open = (Panel_item) xv_create (panel, PANEL_BUTTON,
					  PANEL_LABEL_STRING, "Open",
					  PANEL_NOTIFY_PROC, Action,
					  XV_X, 370,
					  XV_Y, 73,
					  NULL);

	(void) xv_create (panel, PANEL_BUTTON,
			  PANEL_LABEL_STRING, "Cancel",
			  PANEL_NOTIFY_PROC, Cancel,
			  XV_X, 367,
			  XV_Y, 103,
			  NULL);

	window_fit (panel);
	window_fit (frame);

}


/*
 * Re-read the directory entries for the scrolling lists
 */

static void setup_list ()
{
	char *tmpname;
	int i;

	xv_set (ti_file,
		PANEL_VALUE, NULL_STR,
		NULL);

	xv_set (bi_open,
		XV_SHOW, FALSE,
		NULL);

	xv_set (mi_dir,
		PANEL_LABEL_STRING, current,
		NULL);

/*
 * Hide the scroll lists while re-computing the lists.  Saves on re-draw
 * time.
 */

	xv_set (pi_dir,
		XV_SHOW, FALSE,
		NULL);

	xv_set (pi_file,
		XV_SHOW, FALSE,
		NULL);

/*
 * First delete the old entries
 */

	for (i = num_dirs - 1; i >= 0; i--)
		xv_set (pi_dir, PANEL_LIST_DELETE, i, NULL);

	for (i = num_files - 1; i >= 0; i--)
		xv_set (pi_file, PANEL_LIST_DELETE, i, NULL);

	num_files = 0;
	num_dirs = 0;
/*
 * Now read the new entries
 */
	dirp = opendir (current);

	while ((entry = readdir (dirp)) != NULL) {
		tmpname = (char *) malloc (strlen (current) + entry->d_namlen + 2);
		memset (tmpname, '\0', strlen (current) + entry->d_namlen + 2);
		strcat (tmpname, current);
		strcat (tmpname, "/");
		strcat (tmpname, entry->d_name);
		if (dir_test (tmpname)) {
/*
 * A directory
 */
			if (strcmp (entry->d_name, ".")) {
				for (i=0; i < num_dirs; i++) {
					if (0 > strcmp (entry->d_name,
						xv_get (pi_dir, PANEL_LIST_STRING,
							i, NULL, NULL)))
					break;
				}
				xv_set (pi_dir,
					PANEL_LIST_INSERT, i,
					PANEL_LIST_STRING, i, entry->d_name,
					NULL);
				num_dirs++;
			}
		}
		else {
/*
 * A file
 */
			if (strncmp (entry->d_name, ".", 1)) {
				for (i=0; i < num_files; i++) {
					if (0 > strcmp (entry->d_name,
						xv_get (pi_file, PANEL_LIST_STRING,
							i, NULL, NULL)))
					break;
				}
				xv_set (pi_file,
					PANEL_LIST_INSERT, i,
					PANEL_LIST_STRING, i, entry->d_name,
					NULL);
				num_files++;
			}
		}
		free (tmpname);
	}

/*
 * Done, show the new scroll panels
 */

	xv_set (pi_dir,
		XV_SHOW, TRUE,
		NULL);
	xv_set (pi_file,
		XV_SHOW, TRUE,
		NULL);

	closedir (dirp);
}


/*
 * Handle the selection of a directory entry in the scroll list
 */

static void dir_proc (item, string, client_data, op, event)
     Panel_item item;
     char *string;
     caddr_t client_data;
     Panel_list_op op;
     Event *event;

{
	char *oldcurrent;
	int i;

/*
 * Make sure the user selected and didn't drag.  Dragging may cause unwanted
 * changes
 */

/*
 * Make sure we can read the directory before making any changes
 */

	if (op == SELECT && event_id (event) != LOC_DRAG &&
	    check_read (current, string)) {

		oldcurrent = (char *) malloc (strlen (current) + 1);
		memset (oldcurrent, '\0', strlen (current) + 1);
		strcat (oldcurrent, current);
		free (current);

		if (strcmp (string, "..")) {

/*
 * Add the new directory to the "current" directory string
 */

			current = (char *) malloc (strlen (oldcurrent) + strlen (string) + 2);
			memset (current, '\0', strlen (oldcurrent) + strlen (string) + 2);
			strcat (current, oldcurrent);
			if (strlen (oldcurrent) > 1)
				strcat (current, "/");
			strcat (current, string);
		}
		else {

/*
 * Go back one directory
 */

			i = strlen (oldcurrent);

			while (oldcurrent[i] != '/') {
				oldcurrent[i] = '\0';
				i--;
			}

/*
 * Tried to go back from the root directory?
 */

			if (i < 1) {
				oldcurrent[0] = '/';
				oldcurrent[1] = '\0';
				i = 1;
			}
			else
				oldcurrent[i] = '\0';

			current = (char *) malloc (i);
			memset (current, '\0', i);
			strcat (current, oldcurrent);
		}

		free (oldcurrent);

		setup_list ();
	}
}


/*
 * Handle a selection on the file list
 */

static void file_proc (item, string, client_data, op, event)
     Panel_item item;
     char *string;
     caddr_t client_data;
     Panel_list_op op;
     Event *event;

{
	if (op == SELECT) {
		xv_set (ti_file,
			PANEL_VALUE, string,
			NULL);
		xv_set (bi_open,
			XV_SHOW, TRUE,
			NULL);
	}
	else if (op == DESELECT) {
		xv_set (ti_file,
			PANEL_VALUE, NULL_STR,
			NULL);
		xv_set (bi_open,
			XV_SHOW, FALSE,
			NULL);
	}
}


/*
 * Acknowledge an Action button press
 */

static int Action (item, event)
     Panel_item item;
     Event *event;

{
	if (strcmp (NULL_STR, (char *) xv_get (ti_file, PANEL_VALUE))) {
		xv_set (frame, XV_SHOW, FALSE, NULL);
		xv_set (XGedObjects.BaseFrame, FRAME_BUSY, TRUE, NULL);
		(*action_to_call)(xv_get (ti_file, PANEL_VALUE));
		xv_set (XGedObjects.BaseFrame, FRAME_BUSY, FALSE, NULL);
	}
}

static int Cancel (item, event)
     Panel_item item;
     Event *event;

{
	xv_set (frame, XV_SHOW, FALSE, NULL);
}


/*
 * This routine tests to see if a file name is a directory entry
 */

static dir_test (filename)
     char *filename;

{
	struct stat statbuf;

	stat (filename, &statbuf);
	return (S_ISDIR (statbuf.st_mode));
}


/*
 * Check to see if the directory is readable
 */

static int check_read (oldpath, newdir)
     char *oldpath, *newdir;

{
	char *both;
	DIR *test_open;

	both = (char *) malloc (strlen (oldpath) + strlen (newdir) + 2);
	memset (both, '\0', strlen (oldpath) + strlen (newdir) + 2);
	strcat (both, oldpath);
	strcat (both, "/");
	strcat (both, newdir);

	if (!(test_open = opendir (both))) {
		free (both);
		return 0;
	}
	else {
		free (both);
		closedir (test_open);
		return 1;
	}
}