file: fileio.c
/**********************************************************************
* filemenu.c
*
* See SelFile() header for interface description.
*
* Copyright 1990, David Nedde
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for any purpose and without fee is granted
* provided that the above copyright notice appears in all copies.
* It is provided "as is" without express or implied warranty.
*
* This source is derived from xdbx source with the following disclaimer:
**********************************************************************/
/*****************************************************************************
*
* xdbx - X Window System interface to the dbx debugger
*
* Copyright 1989 The University of Texas at Austin
* Copyright 1990 Microelectronics and Computer Technology Corporation
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation, and that the name of The University of Texas
* and Microelectronics and Computer Technology Corporation (MCC) not be
* used in advertising or publicity pertaining to distribution of
* the software without specific, written prior permission. The
* University of Texas and MCC makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* THE UNIVERSITY OF TEXAS AND MCC DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF TEXAS OR MCC BE LIABLE FOR
* ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Po Cheung
* Created: March 10, 1989
*
*****************************************************************************/
/* filemenu.c
*
* Construct a file menu (directory browser) which allows a user to go
* up and down the directory tree, to select files.
* The file menu is popped up by the 'file' command button.
* Duane Voth (duanev@mcc.com) contributed to the layout of the file menu,
* plus some code and ideas.
*
* changeDir(): Record the current working directory.
* InList(): Select files to be displayed in the menu.
* ScanDir(): Scan the directory and record selected filenames.
* DisplayMenuFile(): Callback for the file menu.
* CancelFileMenu(): Pop down the file menu.
* SetUpFileMenu(): Create the file menu popupshell.
* UpdateFileMenu(): Update entries in the file menu.
* File(): Command callback for the 'file' command button.
*/
#include <sys/param.h>
#include <sys/stat.h>
#include <ctype.h>
#include <X11/Xos.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Dialog.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/List.h>
#include <X11/Xaw/Paned.h>
#include "XmdvTool.h"
#include "brush.h"
#include "init.h"
#include "util.h"
#include "fileio.h"
static int glob_status;
static char **glob_path;
static Widget parent_w;
char cwd[MAXPATHLEN]; /* current working directory */
static char fileMenuDir[MAXPATHLEN];/* current directory of file menu */
static char **filelist; /* list of file names in fileMenu */
static int nfiles = 0; /* number of files in filelist */
static Widget popupshell, /* parent of popup */
popup, /* vpane widget containing file menu */
fileMenu, /* list widget as file menu */
fileMenuLabel; /* label widget as file menu label */
Arg wargs[10];
int n;
extern Widget appShell;
extern int dims;
/* Change working directory to 'dir'.
* Modify static global variable, cwd, to keep track of
* current working directory.
*/
static void changeDir(char *dir)
{
int i;
if (strcmp(dir, "./") == 0)
return;
if (dir[0] == '/' || dir[0] == '~')
strcpy(cwd, dir);
if (strcmp(dir, "../") == 0) {
for (i=strlen(cwd); cwd[i] != '/' && i > 0; i--);
cwd[i] = '\0';
if (strcmp(cwd, "") == 0)
strcpy(cwd, "/");
}
else {
sprintf(cwd, "%s/%s", cwd, dir);
LASTCH(cwd) = '\0';
}
}
/* Determines if a directory entry should appear in the file menu.
* The files included in the menu are :
* .. (parent directory)
* directories
* text files
* executable files
*/
static int InList(Directory *entry) //OVERLOAD CALL: Directory: fileio.h(?), fileio.h(?)
{
char pathname[LINESIZ];
struct stat statbuf;
if (strcmp(entry->d_name, ".") == 0 || /* ignore current directory */
LASTCH(entry->d_name) == '~' || /* ignore Emacs backup files */
entry->d_name[0] == '#' || /* Ignore emacs backup files */
(LASTCH(entry->d_name) == 'o' && SECLASTCH(entry->d_name) == '.'))
/* ignore object files */
return False;
if (entry->d_name[0] == '.' && entry->d_name[1] != '.')
return False; /* ignore hidden files */
if (strcmp(cwd, "")) /* give full path name */
sprintf(pathname, "%s/%s", cwd, entry->d_name);
else
strcpy(pathname, entry->d_name);
if (stat(pathname, &statbuf) == -1)
return False;
if (statbuf.st_mode & S_IFDIR) { /* is directory */
strcat(entry->d_name, "/");
/* had to put this in since Solaris doesn't have this field defined - Matt */
#ifndef SVR4
++(entry->d_namlen);
#endif
return True;
}
if (statbuf.st_mode & S_IEXEC) { /* is executable */
strcat(entry->d_name, "*");
#ifndef SVR4
++(entry->d_namlen);
#endif
return True;
}
return True;
}
/* Scans the working directory for files selected by InList(), sorted
* alphabetically, and stored in an array of pointers to directory
* entries called namelist.
* The names of the selected files are stored in filelist.
*/
static int ScanDir(char *dir)
{
Directory **namelist; //OVERLOAD CALL: Directory: fileio.h(?), fileio.h(?)
int i, j;
char *format_static();
/* for BSD systems, just use scandir to read in directory */
#ifndef SVR4
extern alphasort();
nfiles = scandir(dir, &namelist, InList, alphasort);
#else
/* for Solaris, use opendir, readdir, malloc, qsort, and closedir instead */
DIR *dirp;
Directory *item; //OVERLOAD CALL: Directory: fileio.h(?), fileio.h(?)
int asort(const void *, const void *);
dirp = opendir(dir);
if(dirp == NULL)
return(-1);
/* count how many entries in directory, and make sufficient space */
i = 0;
while((item = readdir(dirp)) != NULL) i++;
rewinddir(dirp);
namelist = (Directory **)malloc(i * sizeof(Directory *)); //OVERLOAD CALL: Directory: fileio.h(?), fileio.h(?); Directory: fileio.h(?), fileio.h(?)
/* get each directory entry, filter non-data files, and copy info - only
really need d_name - may be able to eliminate others, since they are
not POSIX standard */
i = 0;
while((item = readdir(dirp)) != NULL) {
if(InList(item)) {
namelist[i] = (Directory *)malloc(sizeof(Directory) + //OVERLOAD CALL: Directory: fileio.h(?), fileio.h(?); Directory: fileio.h(?), fileio.h(?)
((strlen(item->d_name) + 4) & ~3));
namelist[i]->d_ino = item->d_ino;
namelist[i]->d_off = item->d_off;
namelist[i]->d_reclen = item->d_reclen;
strcpy(namelist[i]->d_name, item->d_name);
i++;
}
}
/* sort the names alphabetically */
nfiles = i;
qsort(namelist, nfiles, sizeof(Directory *), asort); //OVERLOAD CALL: Directory: fileio.h(?), fileio.h(?)
closedir(dirp);
#endif
if (nfiles <= 0) {
XBell(XtDisplay(popupshell),0);
return(INVALID);
}
if (filelist) {
for (i=0; filelist[i]; i++)
XtFree(filelist[i]);
XtFree((void *)filelist);
}
filelist = (char **) XtMalloc((nfiles+1) * sizeof(char *));
i = 0;
for (j=0; j<nfiles; j++) {
filelist[i++] = XtNewString(namelist[j]->d_name);
XtFree((void *)namelist[j]);
}
filelist[i++] = NULL;
XtFree((void *)namelist);
return(OK);
}
int asort(const void *d1, const void *d2)
{
return(strcmp((*(Directory **)d1)->d_name, (*(Directory **)d2)->d_name)); //OVERLOAD CALL: Directory: fileio.h(?), fileio.h(?); Directory: fileio.h(?), fileio.h(?)
}
/* Delete the current directory prefix from the passed path */
char *remove_current_prefix(char *path)
{
char wd[MAXPATHLEN];
char *temp_str;
getwd(wd);
if (!strncmp(wd,path,strlen(wd)))
{
/* wd matches path prefix */
temp_str = &path[strlen(wd)];
if (temp_str[0] == '/')
/* If first char of prefix is a '/', *
* remove it since we want a relative path */
temp_str++;
return(temp_str);
}
/* Couldn't find the prefix -- return the whole path */
return(path);
}
/* Callback for the fileMenu list widget.
* > if the selected item is a directory, display contents of that directory.
* > if the selected item is a readable file, return the file name
*/
/* ARGSUSED */
static void DisplayMenuFile(Widget w, Widget popupshell,
XawListReturnStruct *call_data)
{
char *filename;
XtPopdown(popupshell);
filename = call_data->string;
if (filename == NULL) return;
if (LASTCH(filename) == '/') {
changeDir(filename);
XtDestroyWidget(popupshell);
if (UpdateFileMenu() == INVALID)
changeDir("../");
/* create new menu */
File(w,(caddr_t)0,(caddr_t)0); /* pop it up */
}
else {
*glob_path = XtMalloc(strlen(filename)+strlen(cwd)+2);
strcpy(*glob_path, remove_current_prefix(cwd));
if (strlen(*glob_path) != 0)
strcat(*glob_path, "/");
strcat(*glob_path, filename);
glob_status = OK;
}
}
/* Callback to popdown the file menu
*/
/* ARGSUSED */
static void CancelFileMenu(Widget w, Widget popupshell, caddr_t call_data)
{
XtPopdown(popupshell);
glob_status = CANCELED;
}
void DisableWindowResize(Widget w)
{
Arg args[MAXARGS];
Cardinal n;
Dimension height;
n = 0;
XtSetArg(args[n], XtNheight, &height); n++;
XtGetValues(w, args, n);
XawPanedSetMinMax(w, height, height);
XawPanedAllowResize(w, False);
}
/* Creates a popup shell with its child being a vpane widget containing
* a file menu label, a file menu containing file names returned from
* ScanDir(), and a cancel command button.
* When an item in the list is selected, DisplayMenuFile is called.
*/
static int SetUpFileMenu(char *dir)
{
Widget cancelButton;
Arg args[MAXARGS];
Cardinal n;
char menulabel[LINESIZ];
int ncolumns;
n = 0;
popupshell = XtCreatePopupShell("File Directory", transientShellWidgetClass, //OVERLOAD CALL: Directory: fileio.h(?), fileio.h(?)
parent_w, args, n);
n = 0;
popup = XtCreateManagedWidget("popup", panedWidgetClass, popupshell,
args, n);
if (ScanDir(dir) == OK)
/* It worked OK */
strcpy(fileMenuDir, dir);
else
return(INVALID);
n = 0;
sprintf(menulabel, " %s ", dir);
XtSetArg(args[n], XtNlabel, (XtArgVal) menulabel); n++;
XtSetArg(args[n], XtNjustify, (XtArgVal) XtJustifyCenter); n++;
fileMenuLabel = XtCreateManagedWidget("fileMenuLabel", labelWidgetClass,
popup, args, n);
n = 0;
ncolumns = nfiles/FILES_PER_COL + 1;
ncolumns = MIN(ncolumns, MAXCOLUMNS);
XtSetArg(args[n], XtNlist, filelist); n++;
XtSetArg(args[n], XtNverticalList, True); n++;
XtSetArg(args[n], XtNdefaultColumns, (XtArgVal) ncolumns); n++;
fileMenu = XtCreateManagedWidget("fileMenu", listWidgetClass,
popup, args, n);
XtAddCallback(fileMenu, XtNcallback, DisplayMenuFile, popupshell);
n = 0;
XtSetArg(args[n], XtNresize, False); n++;
XtSetArg(args[n], XtNlabel, "CANCEL"); n++;
cancelButton = XtCreateManagedWidget("cancelButton", commandWidgetClass,
popup, args, n);
XtAddCallback(cancelButton, XtNcallback, CancelFileMenu, popupshell);
DisableWindowResize(fileMenuLabel);
DisableWindowResize(cancelButton);
return(OK);
}
/* This routine is called when there is a a change in current directory.
* It destroys the existing popup shell and creates a new file menu based
* on the new current directory. A new directory list is created.
*/
static int UpdateFileMenu(void)
{
return(SetUpFileMenu(cwd));
}
/* File command button callback.
*/
/* ARGSUSED */
void File(Widget w, caddr_t client_data, caddr_t call_data)
{
Arg args[MAXARGS];
Cardinal n;
Dimension fileMenu_width, fileMenuLabel_width, border_width;
/* if (strcmp(fileMenuDir, cwd))*/
if (UpdateFileMenu() != OK)
return;
n = 0;
XtSetArg(args[n], XtNwidth, &fileMenu_width); n++;
XtSetArg(args[n], XtNborderWidth, &border_width); n++;
XtGetValues(fileMenu, args, n);
n = 0;
XtSetArg(args[n], XtNwidth, &fileMenuLabel_width); n++;
XtGetValues(fileMenuLabel, args, n);
#if 0
/* In case we want to place the popup window... */
n = 0;
XtSetArg(args[n], XtNwidth, &dialog_width); n++;
XtGetValues(dialogWindow, args, n);
width = MAX(fileMenu_width, fileMenuLabel_width);
x_offset = (Position) (dialog_width - width - border_width);
XtTranslateCoords(dialogWindow, x_offset, 0, &x, &y);
x = MAX(0, x);
y = MAX(0, y);
n = 0;
XtSetArg(args[n], XtNx, x); n++;
XtSetArg(args[n], XtNy, y); n++;
XtSetValues(popupshell, args, n);
#else
PlaceWindow(popupshell,"*viewport,-1,-1",(char *)0);
#endif
XtPopup(popupshell, XtGrabNonexclusive);
/*UpdateMessageWindow("Select a file or directory");*/
}
/**********************************************************************
* SelFile
*
* Pop up a window, letting the user select a file. When the file
* is selected, the string is returned to the caller.
*
* If the init_path is NULL and this is the first call, the current
* directory is used, else the previous call's directory is used.
* If the init_path is an empty string, the current directory is used.
* A passed init path will have the current dir prepended if the path
* doesn't start with a '/'.
* If the popup is canceled, -1 is returned, otherwise 0 is returned.
**********************************************************************/
int SelFile(Widget w, char *init_path, char **path_return)
{
XEvent event;
parent_w = w;
glob_path = path_return;
if (init_path == (char *)0 || init_path[0] == '\0')
{
/* No init_path -- Use the current working directory */
if (cwd[0] == '\0' || init_path[0] == '\0')
getwd(cwd);
}
else
if (strcmp(cwd,init_path))
{
/* They are different -- copy requested starting dir in */
/* Prefix with wd if init_path is a relative path */
if (init_path[0] != '/')
{
getwd(cwd);
strcat(cwd,"/");
}
else
cwd[0] = '\0';
strcat(cwd,init_path);
}
glob_status = INVALID;
File(w, (caddr_t)0, (caddr_t)0);
while (glob_status == INVALID)
{
XtNextEvent(&event);
XtDispatchEvent(&event);
}
return(glob_status);
}
extern int sbt_open;
/**********************************************************************
* LoadFile
*
* Resource file syntax:
* LoadFile()
*
* Popup a load file widget and load the selected file
*
**********************************************************************/
void LoadFile(Widget w, caddr_t call_data)
{
int ret; /* The return value from the selfile popup */
char *path; /* Path returned from selfile */
char *old_path; /* The current path loaded into the sequence */
Widget label_w; /* filename label widget */
char *last_slash; /* Used to extract the directory from a path */
/* Widget shell_w; /* the stack brush tool shell widget */
Widget tw; /* data form widget */
/* Get the current filename's value */
if(!(label_w = (Widget)WcFullNameToWidget(w, "*file_name")))
{
fprintf(stderr, "Error finding *file_name\n");
exit(-1);
}
n = 0;
XtSetArg(wargs[n],XtNlabel,&old_path); n++;
XtGetValues(label_w,wargs,n);
/* Remove the trailing filename leaving only the path */
last_slash = strrchr(old_path,'/');
if (last_slash == NULL)
/* No directories involved -- start from current directory */
old_path[0] = '\0';
else
/* There was a directory -- Start from the currently loaded directory */
*last_slash = '\0';
/* Popup a window letting the user select a file */
ret = SelFile(w,
old_path, /* Init_path */
&path);
if (ret == -1)
return; /* Cancel button pressed */
/*
if (!file_openable(path,"r"))
{
popup_error(form_w,
format_static("Opening file '%s': Not a readable file", path));
XtFree(path);
return;
}
*/
/* Read in the selected file */
get_head(path);
InitBrush();
init_glyphkey();
init_hierkey();
init_DimList();
tw = WcFullNameToWidget(appShell,"*data_form");
/*
if(tw == NULL)
printf("couldn't get data form widget\n");
else {
XawFormDoLayout(tw, True);
n = 0;
XtSetArg(wargs[n],XtNheight,dims*15); n++;
XtSetValues(tw,wargs,n);
}
*/
/* redraw the canvas */
RedrawCanvas(w, NULL, NULL);
XtFree(path);
}
C++ to HTML Conversion by ctoohtml