mark@s.cc.purdue.edu.UUCP (09/17/87)
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# Xshar: Extended Shell Archiver.
# This is part 2 out of 3.
# This archive created: Wed Sep 16 20:51:21 1987
# By: Craig Norborg (Purdue University Computing Center)
# Run the following text with /bin/sh to create:
# BackUp.c
# PathRequest.c
cat << \SHAR_EOF > BackUp.c
/************************* Main *********************/
/* */
/* Hard Disk Backup Usage Backup dhx: */
/* where x is the hard drive number */
/* */
/****************************************************/
#include <exec/memory.h>
#include <exec/types.h>
#include <intuition/intuition.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <stdio.h>
#include <ctype.h>
#include <setjmp.h>
#include <time.h>
#include <functions.h>
#include "gadget.h"
#include "menu.h"
/* Constants */
#define false 0 /* for short parameter requirements */
#define true 1 /* for short parameter requirements */
#define LINES_PER_PAGE 60
#define VOLUME_MAX 32 /* max characters in volume name */
#define PATH_MAX 256 /* max characters in pathname (very arbitrary) */
/* Define error recovery constants. Note that these are all powers
* of 2 to allow creating 'sets' of allowable options during the
* recovery prompt.
*/
#define NERRCODE 5 /* number of error recovery codes */
#define ERR_NONE 0 /* what we want ALL the time :-) */
#define ERR_ABORT 1 /* give up the ship */
#define ERR_RETRY_FILE 2 /* let's try that file one more time */
#define ERR_RESTART_VOLUME 4 /* for media errors on output floppy */
#define ERR_IGNORE 8 /* ignore this error and trudge on */
/* Macros */
/* determine if a menu item is "checked" */
#define GadgetString(g) ((struct StringInfo *) g->SpecialInfo)->Buffer
#define IsChecked(item) (item->Flags & CHECKED == CHECKED)
/* The following structure is used to link file and directory node
* information into a doubly-linked list. This provides a way to
* defer processing of sub-directory nodes until all files in a
* current directory are processed. As nodes are "consumed", they
* are returned to free memory.
*/
typedef struct t_file {
struct t_file *previous,*next;
char *filename;
USHORT blocks;
BOOL is_dir; /* TRUE => it's a directory */
} T_FILE;
/* The following structure links lists of T_FILE nodes. */
typedef struct t_file_list {
T_FILE *first_file;
T_FILE *last_file;
} T_FILE_LIST;
/* External and forward function declarations */
struct Window *GetMyWindow();
extern char *calloc(), *index(), *rindex();
extern long DiskBlocks();
extern int errno;
T_FILE *FindFile();
/* External data */
extern struct Gadget StopGad;
extern struct Menu Titles[];
extern struct MenuItem Items[];
extern struct Window *pathwindow;
/* Global data */
#ifdef DEBUG
struct FileHandle *debugconsole;
char debugmsg[512];
#endif
int back = 0, size = 0;
char backpath[81] = "DF0:"; /* where backups go and restores
come from */
struct FileHandle *console; /* for informative messages */
char conmsg[512];
T_FILE *current_dir = NULL; /* current directory node */
char destdrive[5] = "DF0:";
char destpath[PATH_MAX+1];
char destvol[VOLUME_MAX+1];
USHORT do_compress = 1; /* compression flag */
USHORT do_listing = 1; /* listing flag */
USHORT do_speech = 1; /* speech flag */
char *erropts[NERRCODE] = { /* error recovery options */
"No error",
"Abort processing",
"Retry this file",
"Restart the output volume",
"Ignore this error"
};
char homepath[81] = "DH0:"; /* where files are backed up from and
restored to */
struct IntuitionBase *IntuitionBase;
USHORT level; /* file nesting level */
USHORT linecount; /* number of lines in listing */
FILE *listing;
char listpath[81] = "PRT:"; /* where we send all of that vital
information about backups */
T_FILE_LIST main_list;
struct Window *mywindow;
/* New window structure */
static struct NewWindow nw = {
0,0,640,200,0,1,
/* IDCMP Flags */
MENUPICK | MOUSEBUTTONS | DISKINSERTED |
CLOSEWINDOW | GADGETDOWN | GADGETUP | REQSET,
/* Flags */
WINDOWCLOSE | WINDOWDEPTH | ACTIVATE ,
NULL, /* First gadget */
NULL, /* Checkmark */
(UBYTE *)"MRBackup Version 1.0",/* Window title */
NULL, /* No custom streen */
NULL, /* Not a super bitmap window */
0,0,640,200, /* Not used, but set up anyway */
WBENCHSCREEN
};
struct DateStamp *now, *since; /* for date comparisons */
char srcpath[PATH_MAX];
char srcvol[VOLUME_MAX+1]; /* source volume name */
char temp[256];
/* The following flags suppress repetition of spoken
* messages. After all, let's not over-do it.
*/
UBYTE at_your_service;
^L
/* Main program - N.S.D.T.! */
main(argc,argv)
int argc;
char *argv[];
{
Initialize();
User(); /* it's in the user's hands */
CleanUp(NULL, 0);
}
^L
/* Initialize the program. */
Initialize()
{
if (! (IntuitionBase = (struct IntuitionBase *)
OpenLibrary("intuition.library", 33L ) ) ) {
CleanUp("Can't open Intuition library!", 20);
}
if (!( mywindow = OpenWindow(&nw) ) )
CleanUp("Can't open program window!", 20);
SetMenuStrip(mywindow, Titles);
InitPathRequest();
AddGadget(mywindow, &StopGad, -1L);
OnGadget(&StopGad, mywindow, NULL);
now = (struct DateStamp *)
AllocMem((long) sizeof(struct DateStamp), MEMF_PUBLIC);
since = (struct DateStamp *)
AllocMem( (long) sizeof(struct DateStamp), MEMF_PUBLIC);
#ifdef DEBUG
if (!(debugconsole =
Open("CON:0/100/640/40/Debug Info", MODE_NEWFILE)))
CleanUp("Can't open debug console!", 20);
#endif
if (!(console =
Open("CON:0/140/640/60/Progress Report", MODE_NEWFILE)))
CleanUp("Can't open console!", 20);
SetSpeech();
}
^L
/* Handle program termination.
* Called with:
* msg: termination message or NULL
* code: exit code (0 => normal termination)
*/
CleanUp(msg, code)
char *msg; int code;
{
if (msg)
puts(msg);
#ifdef DEBUG
if (debugconsole) Close(debugconsole);
#endif
if (console) Close(console);
if (listing) fclose(listing);
if (mywindow) {
ClearMenuStrip(mywindow);
CancelPathRequest();
CloseWindow(mywindow);
}
if (IntuitionBase) CloseLibrary(IntuitionBase);
if (now) FreeMem( now, (long) sizeof(struct DateStamp));
if (since) FreeMem( since, (long) sizeof(struct DateStamp));
exit(code);
}
^L
/* Add a file/directory name to the list.
* Called with:
* name: filename string
* FIB: pointer to FileInfoBlock for this file or NULL.
* If NULL, file is starting directory.
* list: address of list header
* Returns:
* 0 => success, failure status otherwise
* Notes:
* The filename string MUST NOT contain the volume component,
* since it is used to build both source and destination
* pathnames. Also note that this routine inserts the name
* into the list in sorted order (case sensitive). Though this
* changes the "natural order" of the files, it makes them
* easier to locate on the backup disks.
*/
int
AddFile(name, FIB, list)
char *name; struct FileInfoBlock *FIB; T_FILE_LIST *list;
{
USHORT blks;
T_FILE *fnode, *tnode;
if (!(fnode = (T_FILE *) calloc(1,sizeof(T_FILE)))) {
nomem:
TypeAndSpeak("AddFile: Out of memory!\n");
return ERROR_NO_FREE_STORE;
}
if (!(fnode->filename = calloc(1, strlen(name)+1)))
goto nomem;
strcpy(fnode->filename, name); /* copy the filename */
if (!FIB) {
blks = 1;
fnode->is_dir = true;
}
else if (fnode->is_dir = (FIB->fib_DirEntryType >= 0) )
blks = 1; /* assume 1 block for directory */
else {
blks = ((FIB->fib_Size/488)+2); /* compute file size in blocks */
blks += (blks/70);
}
fnode->blocks = blks;
if (!list->first_file) { /* file list is empty? */
list->first_file = fnode; /* this is the new head */
}
else {
/* Find the insertion point for this file. */
for (tnode = list->first_file; tnode; tnode = tnode->next) {
if (strcmp(fnode->filename, tnode->filename) <= 0) {
fnode->next = tnode; /* insert it here */
if (tnode->previous)
tnode->previous->next = fnode;
fnode->previous = tnode->previous;
tnode->previous = fnode;
if (list->first_file == tnode)
list->first_file = fnode;
return 0;
}
}
/* append to the end of the list */
fnode->previous = list->last_file;
list->last_file->next = fnode;
}
list->last_file = fnode;
return 0;
}
^L
/* Main backup routine. */
Backup()
{
int compare_flag, status = 0;
Speak("O K, I'm ready. Lets back up your disk!");
DateStamp(now);
main_list.first_file = main_list.last_file = current_dir = NULL;
if (do_listing)
if ( OpenList() ) return;
/* Get the file comparison date. Only files created on or after
* this date are backed up.
*/
do {
*since = *now;
since->ds_Days -= 7; /* default interval is 1 week */
since->ds_Minute = 0;
since->ds_Tick = 0;
Speak("Enter the date since your last backup.");
DateRequest(mywindow, "Backup files since:",since, since);
if ( (compare_flag = CompareDS(since, now) ) >= 0)
DisplayBeep(NULL);
} while (compare_flag >= 0);
BreakPath(homepath, srcvol, srcpath);
BreakPath(backpath, destdrive, destpath);
#ifdef DEBUG
sprintf(debugmsg, "destdrive = %s, destpath = %s\n",destdrive,destpath);
DebugWrite(debugmsg);
sprintf(debugmsg, "srcvol = %s, srcpath = %s\n", srcvol,srcpath);
DebugWrite(debugmsg);
#endif
if (*destpath) {
TypeAndSpeak(
"On a backup, the backup path must only be a device name");
status = ERR_ABORT;
goto done;
}
strcat(destdrive,":");
level = 0;
size = 0;
if (*srcpath) { /* starting path is a directory */
status = AddFile(srcpath, NULL, &main_list);
}
else /* starting path is a device */
status = CollectFiles(srcpath,&main_list);
if (!status) {
while (main_list.first_file) { /* while something in the list */
if (status = BackupFiles(&main_list)) break;
if (status = BackupDirs(&main_list)) break;
}
}
done:
if (status == 0) {
TypeAndSpeak("That was a piece of cake.\n");
}
else {
sprintf(conmsg,"Oops! Backup terminated with error %d\n",status);
TypeAndSpeak(conmsg);
}
}
^L
/* Process the next directory in the file list.
* This routine is recursive.
* Called with:
* list: file list to be processed
* Returns:
* status code (0 => success)
*/
int
BackupDirs(list)
T_FILE_LIST *list;
{
T_FILE *dirnode;
T_FILE *saved_current_dir;
int status = 0;
T_FILE_LIST sublist; /* subdirectory list header */
sublist.first_file = sublist.last_file = NULL;
saved_current_dir = current_dir; /* remember current context */
/* There are a couple of things to note here. The first is that once
* we have reached here, there should be NO simple file nodes in "list".
* That currently is not handled as an error, but probably should be.
* Second, since this scan modifies the list, a removal of a directory
* node starts the scan at the beginning of the list since we shouldn't
* reference the links in the node we're removing. Since we should be
* removing the first node in the list anyway, who cares?
*/
for (dirnode = list->first_file; dirnode; ) {
if (dirnode->is_dir) { /* found one */
current_dir = dirnode; /* set current directory */
RemFile(dirnode, list);
if (status = NewDir(current_dir->filename)) break;
if (status = CollectFiles(current_dir->filename,&sublist))
break;
if (status = BackupFiles(&sublist)) break;
if (status = BackupDirs(&sublist)) break;
dirnode = list->first_file;
}
else /* should never get here !!! */
dirnode = dirnode->next;
}
current_dir = saved_current_dir;
return status;
}
^L
/* Backup all simple files in the current list.
* Called with:
* list: file list header
* Returns:
* status code (0 => success)
*/
int
BackupFiles(list)
T_FILE_LIST *list;
{
T_FILE *primary, *secondary;
int status = 0;
/* The following loop continually scans the file list (from the front),
* looking for more file entries to process. If the primary choice
* fails, an attempt is made to find a file which will fit in the
* space remaining. If that attempt fails, then a new disk is formatted.
*/
while (primary = FindFile(list,false)) {/* find next file to process */
if (primary->blocks >= size) { /* file doesn't fit */
if (!(secondary = FindFile(list,true))) {
/* At this point, we know that there's at least one
* file to back up, but none that fit. Start a new
* disk.
*/
if (status = NewDisk(true)) return status;
continue; /* try that file again */
}
primary = secondary; /* use second choice */
}
if (status = DoFile(primary)) return status;
RemFile(primary,list); /* delete the node */
}
if (current_dir) { /* forget current directory */
FreeFile(current_dir);
current_dir = NULL;
}
return status;
}
/* Break a full file specification into its volume and pathname components.
* Called with:
* fullpath: full pathname string (input)
* volume: volume name component, sans colon (output)
* path: pathname component (output)
* Returns:
* status code: 1 => no volume name specified, 0 otherwise
*/
BreakPath(fullpath,volume,path)
char *fullpath, *volume, *path;
{
char c, *fp, *s;
unsigned has_volume = 1; /* assume it has volume component */
fp = fullpath;
s = volume;
if ( index(fp, ':') ) { /* volume name specified? */
s = volume;
while ((c = *fp++) != ':') *s++ = c;
}
else
has_volume = 0;
*s = '\0'; /* terminate volume */
strcpy(path, fp); /* the rest is pathname stuff */
return has_volume;
}
/* Check the current number of disk blocks (size) available. If
* less than 1, it's time to format a new disk.
* Called with:
* create_dir: true => OK to create continuation directory
* Returns:
* 0 => success
* 1 => failure
*/
int
CheckSize(create_dir)
int create_dir;
{
if (size > 0) return 0;
return NewDisk(create_dir);
}
^L
/* Do a quick poll on the STOP gadget.
* Returns 1 if STOP gadget hit, 0 otherwise.
*/
int
CheckStop()
{
ULONG class;
struct Gadget *gadget;
struct IntuiMessage *msg;
int status = 0;
if (msg = (struct IntuiMessage *) GetMsg(mywindow->UserPort)) {
class = msg->Class;
gadget = (struct Gadget *) msg->IAddress;
ReplyMsg(msg);
if (class == GADGETUP && gadget->GadgetID == STOPGAD) {
TypeAndSpeak("I am stopping, as you requested.\n");
status = ERR_ABORT; /* quit */
}
}
return status;
}
^L
/* Collect file names from a starting path.
* Called with:
* name: starting pathname
* Note that name may be a null string when copying
* the entire home device.
* list: pointer to file list header
* Returns:
* status code (0 => success)
* Notes:
* CollectFiles attempts to collect all file and directory names
* for a given level, starting with "name". If a simple filename
* is given as a starting path, only that name will be collected.
* If a directory name is given, then all pathnames contained
* within that directory (only) will be collected. For each
* directory name collected, CollectFiles will be called again to
* collect files for that particular directory. This iterative
* approach (vs. recursive) saves memory and allows us to maintain
* order at each directory level.
*/
int
CollectFiles(name, list)
char *name; T_FILE_LIST *list;
{
int status = 0;
struct FileInfoBlock *FIB = NULL;
T_FILE *fnode; /* file descriptor node */
struct Lock *lock = NULL;
char path[PATH_MAX+1];
USHORT top_level;
#ifdef DEBUG
sprintf(debugmsg,"Collecting files from %s\n",name);
DebugWrite(debugmsg);
#endif
top_level = (*name == '\0'); /* empty name implies top level */
if (!(FIB =
AllocMem((long)sizeof(struct FileInfoBlock),
MEMF_CHIP|MEMF_CLEAR))) {
TypeAndSpeak("CollectFiles: Can not allocate memory for FIB\n");
return ERROR_NO_FREE_STORE;
}
strcpy(path,srcvol); /* rebuild current home path */
strcat(path,":");
strcat(path, name);
if (!(lock=Lock(path,SHARED_LOCK))) {
status = IoErr();
sprintf(conmsg,"CollectFiles can not lock %s; error %d\n",
path, status);
TypeAndSpeak(conmsg);
goto out2;
}
if ((Examine(lock,FIB))==0){
status = IoErr();
sprintf(conmsg,"CollectFiles can not examine %s; error: %d\n",
name, status);
TypeAndSpeak(conmsg);
goto out2;
}
if (FIB->fib_DirEntryType > 0){ /* "name" is a directory */
while(!status && ExNext(lock,FIB)) {
if (FIB->fib_DirEntryType < 0) {
if (CompareDS(&FIB->fib_Date, since) < 0) {
#ifdef DEBUG
sprintf(debugmsg,"Skipping %s\n",
&FIB->fib_FileName[0]);
DebugWrite(debugmsg);
#endif
continue;
}
}
if (top_level)
*path = '\0';
else {
strcpy(path,name);
strcat(path,"/");
}
strcat(path,&FIB->fib_FileName[0]);
status = AddFile(path, FIB, list);
}
/* !!! Need check here for ERROR_NO_MORE_ENTRIES */
}
else {
if ( CompareDS(&FIB->fib_Date, since ) >= 0 )
status = AddFile(name, FIB, list);
}
out2:
UnLock(lock);
out1:
FreeMem(FIB, (long)sizeof(struct FileInfoBlock) );
/* Don't give up if somebody else is using the file - just
* ignore the error. The user can cancel us if there's a
* problem.
*/
if (status == ERROR_OBJECT_IN_USE)
status = 0;
return status;
}
#ifdef DEBUG
DebugWrite(msg)
char *msg;
{
Write(debugconsole, msg, (long) strlen(msg));
}
#endif
^L
/* Process one file.
* Called with:
* fnode: node describing file
* Returns:
* 0 => success
* 1 => failure
*/
int
DoFile(fnode)
T_FILE *fnode;
{
int status = ERR_NONE;
char destname[PATH_MAX+1];
int oldsize;
char srcname[PATH_MAX+1];
oldsize = size;
size -= fnode->blocks; /* deduct blocks for file */
if (CheckSize(true)) /* check disk space */
return ERR_ABORT;
if (size > oldsize) /* we just formatted */
oldsize = size;
/*#define NOCOPY*/ /* for fast debugging */
do {
if (status = CheckStop()) /* does user want out? */
return status;
sprintf(srcname,"%s:%s",srcvol,fnode->filename);
sprintf(conmsg,"Blocks left: %5d ",oldsize);
WriteConsole(conmsg);
if ( !do_compress || IsCompressed(srcname) || fnode->blocks < 4){
sprintf(destname,"%s%s",destvol,fnode->filename);
sprintf(conmsg,"Copying %s\n",srcname);
WriteConsole(conmsg);
#ifndef NOCOPY
status = CopyFile(srcname,destname);
#endif
}
else {
sprintf(destname,"%s%s.Z",destvol,fnode->filename);
sprintf(conmsg,"Compressing %s\n",srcname);
WriteConsole(conmsg);
#ifndef NOCOPY
if (!(status = compress(srcname,destname)))
status = CopyFileDate(srcname,destname);
#endif
}
if (status) {
status = GetErrOpt("I/O error during copy or compress",
ERR_ABORT | ERR_IGNORE |
ERR_RETRY_FILE | ERR_RESTART_VOLUME);
}
if (status == 0) ListLine(destname);
} while (status == ERR_RETRY_FILE);
if (status == ERR_IGNORE)
status = ERR_NONE;
#ifndef NOCOPY
if (!status){
if ((size = DiskBlocks(destvol)) < 0) /* update blocks left */
++status;
}
#endif
return status;
}
^L
/* Handle a gadget action.
* Called with:
* class: message class (GADGETUP/GADGETDOWN/?)
* addr: pointer to gadget structure
*/
DoGadget(class, addr)
ULONG class; struct Gadget *addr;
{
USHORT id; /* gadget identifier */
if (class == GADGETUP) {
id = addr->GadgetID;
#ifdef DEBUG
sprintf(debugmsg,"GADGETUP: %d\n",id);
DebugWrite(debugmsg);
#endif
switch (id) {
case HOMEPATHGAD:
GetHomePath(addr);
break;
case BACKPATHGAD:
GetBackPath(addr);
break;
case LISTPATHGAD:
GetListPath(addr);
break;
case STOPGAD:
TypeAndSpeak(
"Use the STOP gadget during backup and restore operations.\n");
break;
default:
WriteConsole("Unknown gadget - program error!\n");
break;
}
}
}
^L
/* Attempt to find a file node in the file list. If the check_size
* parameter is true, only look at files which will fit in the space
* remaining on the disk.
* Called with:
* list: pointer to file list to be searched
* check_size: false => find first file in the list
* true => test space available
* Returns:
* file node or NULL (not found)
*/
T_FILE *FindFile(list,check_size)
T_FILE_LIST *list; int check_size;
{
T_FILE *fnode;
for (fnode = list->first_file; fnode; fnode = fnode->next) {
if (!fnode->is_dir) { /* don't consider directory nodes */
if (!check_size) break; /* take this one */
if (fnode->blocks < size) break;
}
}
return fnode;
}
/* Free memory allocated to a file node.
* Called with:
* node: file node
*/
FreeFile(node)
T_FILE *node;
{
free(node->filename);
free(node);
}
^L
/* Get the backup device pathname specification.
* Called with:
* Called with:
* gadget: pointer to relevant string gadget
*
* Side-effects:
* If the pathname specification passes its requirements tests,
* the global string backpath will be set to the pathname.
* Otherwise, homepath is left unchanged and the gadget's string
* is reset to the current contents of homevolume.
*/
GetBackPath(gadget)
struct Gadget *gadget;
{
char volume[VOLUME_MAX+1];
UBYTE *fullpath, path[PATH_MAX+1];
fullpath = (UBYTE *) GadgetString(gadget);
BreakPath(fullpath,volume,path);
if (!IsDir(fullpath)) {
TypeAndSpeak("Backup path must be a device or directory name!\n");
badpath:
strcpy(fullpath, backpath); /* restore previous value */
return;
}
if (strlen(volume) != 3 ||
tolower(volume[0]) != 'd' ||
tolower(volume[1]) != 'f' ||
volume[2] < '0' || volume[2] > '3') {
TypeAndSpeak("Backup device must be DF0 through DF3\n");
goto badpath;
}
strcpy(backpath, fullpath); /* use new value */
}
^L
/* An error has occurred. Find out what the user wants to do about it.
* Called with:
* msg: message string
* options: the "set" of options available
* 0 => sorry - no options, ERR_ABORT returned
* Returns:
* error recovery option
*/
int
GetErrOpt(msg, options)
char *msg; int options;
{
int i, mask, option_count = 0, select;
int option_list[NERRCODE];
sprintf(conmsg,"An error has interrupted processing:\n%s\n\n",msg);
TypeAndSpeak(conmsg);
return ERR_ABORT; /* ...implement recovery... */
}
^L
/* Get the home pathname specification (volume and pathname).
* Called with:
* gadget: pointer to relevant string gadget
*
* Side-effects:
* If the pathname specification passes its requirements tests,
* the global string homepath will be set to the pathname.
* Otherwise, homevolume is left unchanged and the gadget's string
* is reset to the current contents of homevolume.
*/
GetHomePath(gadget)
struct Gadget *gadget;
{
UBYTE *fullpath, path[PATH_MAX+1], volume[VOLUME_MAX+1];
fullpath = (UBYTE *) GadgetString(gadget);
BreakPath(fullpath, volume, path);
if (!IsDir(fullpath)) {
TypeAndSpeak(
"Home path must be a hard disk device with optional directory name!\n");
badpath:
strcpy(fullpath, homepath); /* restore previous value */
}
else if (strlen(volume) != 3 ||
tolower(volume[0]) != 'd' ||
tolower(volume[1]) != 'h' ||
!isdigit(volume[2])) {
#ifdef DEBUG
sprintf(debugmsg,"home device = \"%s\" ? \n",volume);
DebugWrite(debugmsg);
#endif
TypeAndSpeak("Home device must be DH0: through DH9:\n");
goto badpath;
}
strcpy(homepath, fullpath);
}
/* Get the listing pathname.
* Called with:
* gadget: pointer to relevant string gadget
*
* Side-effects:
*/
GetListPath(gadget)
struct Gadget *gadget;
{
UBYTE *path;
if (!do_listing) {
TypeAndSpeak("Listing mode is not enabled. ");
TypeAndSpeak("Your change has been ignored.\n");
badpath:
strcpy(path, listpath);
}
else {
path = (UBYTE *) GadgetString(gadget);
if (!strcmp(path, listpath)) { /* same pathname */
return; /* ignore the request */
}
if (OpenList()) goto badpath;
strcpy(listpath, path);
}
}
^L
/* Output a new header to the listing file. */
Header()
{
if (do_listing) {
fprintf(listing,"\f MRBackup Listing of Volume %s\n\n", destvol);
linecount = 2;
}
}
^L
/* Determine if a file is compressed. This is currently done by looking
* at the file name for a ".Z" or ".z" extension. Since we use the
* "magic header" form of compression, we could also check for that as
* well...maybe later.
*
* Called with:
* filename: file name string
* Returns:
* 1 => file is compressed, 0 => file is not compressed
*/
int IsCompressed(filename)
char *filename;
{
char *s;
s = filename + strlen(filename)-2;
if (!strcmp(s,".z")|| !strcmp(s,".Z"))
return 1;
else
return 0;
}
^L
/* Output a line to the listing file. Start a new line if necessary.
* The output string is assumed to have no form control characters.
* Called with:
* str: string to be output
*/
ListLine(str)
char *str;
{
if (do_listing) {
if (linecount >= LINES_PER_PAGE) Header();
fprintf(listing," %s\n",str);
++linecount;
}
}
^L
/* Create a new directory on the destination disk.
* Called with:
* name: directory pathname
* Returns:
* false => success
* true => failure
* Notes:
* NewDir may be called by NewDisk() or BackupDirs(). You should
* note that a condition of mutual recursion between CheckSize and
* NewDir exists, due to the following:
*
* When NewDir is called from BackupDirs(), it calls CheckSize(),
* which in turn calls NewDisk() if there is no space left.
* The create_dir parameter to CheckSize() (false) prevents a
* secondary call to NewDir() since the job is already being
* performed.
*
* When CheckSize() is called as a result of BackupFiles()
* processing, the create_dir parameter is true so that NewDir()
* will be called if NewDisk() is called, thus creating a
* continuation of the current directory. Confused? Me too :-).
*/
int
NewDir(name)
char *name;
{
char c;
struct Lock *dirlock;
int dirleng;
int errnum;
char dirname[256];
int nameindx = 0, nameleng;
size--; /* takes a block for a directory */
if (CheckSize(false)) /* have room on disk? */
return 1;
strcpy(dirname,destvol); /* start with volume name */
dirleng = strlen(dirname);
nameleng = strlen(name);
/* Parse the pathname, one directory node at a time, creating
* directories as needed.
*/
while (nameindx < nameleng) {
if (nameindx) /* 2nd - nth pass? */
dirname[dirleng++] = '/'; /* directory separator */
while ((c = name[nameindx++]) && c != '/')
dirname[dirleng++] = c;
dirname[dirleng] = '\0'; /* terminate with null */
if (dirlock = Lock(dirname,SHARED_LOCK)) /* subdir exists? */
UnLock(dirlock);
else { /* create subdirectory */
if ((dirlock = CreateDir(dirname))== NULL){
if ((errnum = IoErr())== ERROR_DIRECTORY_NOT_EMPTY){
sprintf(conmsg,
"Directory %s already exists!\n",dirname);
TypeAndSpeak(conmsg);
}
else {
sprintf(conmsg,
"ERROR %d: Unable to create directory %s\n",
errnum,dirname);
TypeAndSpeak(conmsg);
return 1;
}
}
else
UnLock(dirlock);
}
} /* endwhile */
return 0;
}
^L
/* Format a new diskette.
* Called with:
* create_dir: true => create continuation directory, if necessary
* Returns:
* false => success
* true => failure
*/
int
NewDisk(create_dir)
int create_dir;
{
char datestr[20];
int status = 0;
if (back) /* not first disk? */
Delay(TICKS_PER_SECOND * 5L); /* let disk buffers flush */
++back; /* Increment the volume ID */
Speak("Attention! I need a disk for formatting.");
do {
if (!RequestDisk(mywindow, destdrive))
return ERR_ABORT;
/* Don't put the colon in the volume name -
* FormatDisk will happily use it as part of
* the name rather than as a delimiter.
*/
DS2Str(datestr, "%02m-%02d-%02y", now);
sprintf(destvol,"Backup %s.%d", datestr, back);
Inhibit(destdrive,1);
if (status = FormatDisk(destdrive,destvol)) {
TypeAndSpeak("I failed to format the disk. Sorry.\n");
}
} while (status);
strcat(destvol, ":"); /* add colon */
Delay(TICKS_PER_SECOND * 2L); /* let disk validate */
if ((size = DiskBlocks(destvol)) < 0)
status = -size;
else
if (create_dir && (current_dir != NULL) )
status = NewDir(current_dir->filename);
return status;
}
^L
/* Skip 'n' lines in the listing file.
* Called with:
* n: number of lines to skip
*/
NewLine(n)
int n;
{
if (do_listing) {
if (n + linecount >= LINES_PER_PAGE)
Header();
else while (n--) {
fputc('\n', listing);
++linecount;
}
}
}
^L
/* Open the listing file.
* Returns:
* status (0 => success)
*/
int
OpenList()
{
if (listing) fclose(listing); /* prior listing file open? */
if (!(listing = fopen(listpath, "w"))) {
sprintf(conmsg,
"I can't open the listing file %s, error %d\n",
listpath, errno);
TypeAndSpeak(conmsg);
}
else
linecount = LINES_PER_PAGE;
return errno;
}
^L
/* Remove a file node from the list.
* Called with:
* node: file node pointer
* list: file list header
* Returns:
* nothing
*/
RemFile(node,list)
T_FILE *node; T_FILE_LIST *list;
{
if (node->previous)
node->previous->next = node->next;
if (node->next)
node->next->previous = node->previous;
if (node == list->first_file)
list->first_file = node->next;
if (node == list->last_file)
list->last_file = node->previous;
if (!node->is_dir)
FreeFile(node);
}
/* Enable/disable speech capability, based on global 'do_speech'. */
SetSpeech()
{
if (do_speech) {
if (!SpeechOn())
Say("Ahhh, that feels good! Thanks for turning me on!");
}
else
SpeechOff();
}
Speak(msg)
char *msg;
{
if (do_speech) Say(msg);
}
/* Type a message to the console and optionally "speak" it.
* Called with:
* msg: message string
*/
TypeAndSpeak(msg)
char *msg;
{
WriteConsole(msg);
if (do_speech) Say(msg);
}
/* Handle IDCMP messages generated by user actions. */
User()
{
ULONG class; /* message class */
USHORT code; /* message code */
USHORT gadgid; /* gadget ID */
APTR Iadr; /* address field from message */
struct IntuiMessage *msg; /* Intuition message pointer */
USHORT quit = 0;
SHORT x,y; /* mouse x and y position */
ULONG waitbits;
waitbits = (1L << mywindow->UserPort->mp_SigBit) |
(1L << pathwindow->UserPort->mp_SigBit);
#ifdef DEBUG
sprintf(debugmsg,"User: waitbits = %08lx\n", waitbits);
DebugWrite(debugmsg);
#endif
if (++at_your_service == 1)
Speak("At your servis."); /* SIC! SIC! SIC! */
while (!quit) {
Wait(waitbits);
while (!quit) {
if (!(msg = (struct IntuiMessage *)
GetMsg(mywindow->UserPort)))
if (!(msg = (struct IntuiMessage *)
GetMsg(pathwindow->UserPort)))
break;
class = msg->Class;
code = msg->Code;
Iadr = msg->IAddress;
x = msg->MouseX;
y = msg->MouseY;
ReplyMsg(msg); /* acknowledge the message */
#ifdef DEBUG
sprintf(debugmsg,"Message class: 0x%lx, code: 0x%x\n",
class, code);
#endif
switch (class) {
case CLOSEWINDOW:
++quit;
break;
case GADGETUP:
case GADGETDOWN:
DoGadget(class,Iadr);
break;
case MENUPICK:
quit = UserMenu(code);
break;
default:
break; /* ignore the rest */
} /* end switch(class) */
}
}
}
/* Handle a menu selection.
* Called with:
* code: menu selection code
* Returns:
* status code (1 => Quit was selected)
*/
int
UserMenu(code)
USHORT code;
{
struct MenuItem *item;
USHORT itemnum,menunum;
if (code != MENUNULL) {
menunum = MENUNUM(code); /* only 1 in this appl. */
itemnum = ITEMNUM(code);
#ifdef DEBUG
sprintf(debugmsg,"menu = %d, item = %d\n",menunum,itemnum);
DebugWrite(debugmsg);
#endif
item = (struct MenuItem *) ItemAddress(Titles, menunum);
switch (menunum) {
case MENU_PROJECT: /* Project Menu */
switch (itemnum) {
case ITEM_BACKUP: /* Backup */
Backup();
break;
case ITEM_RESTORE: /* Restore */
Restore();
break;
case ITEM_ABOUT: /* About */
About();
break;
case ITEM_QUIT: /* Quit */
return 1;
default:
DisplayBeep(NULL);
break;
}
break;
case MENU_FLAGS: /* Flags Menu */
switch (itemnum) {
case ITEM_COMPRESS: /* Compression */
do_compress = IsChecked(item);
break;
case ITEM_NOCOMPRESS: /* No Compression */
do_compress = !IsChecked(item);
break;
case ITEM_LIST: /* Listing */
do_listing = IsChecked(item);
break;
case ITEM_NOLIST: /* No Listing */
do_listing = !IsChecked(item);
break;
case ITEM_SPEECH: /* Speech */
do_speech = IsChecked(item);
SetSpeech();
break;
case ITEM_NOSPEECH: /* No Speech */
do_speech = !IsChecked(item);
SetSpeech();
break;
default:
DisplayBeep(NULL);
break;
}
}
}
return 0;
}
/* Write a message to the console window.
* Called with:
* msg: message string
*/
WriteConsole(msg)
char *msg;
{
Write(console, msg, (long) strlen(msg));
}
SHAR_EOF
cat << \SHAR_EOF > PathRequest.c
/**********************************************************************
* Gadget Structure Definitions
*
* The following structures were defined using the Gadget Editor created
* by the Programmer's Network.
* The credits for the Gadget Editor are:
*
* John Draper - Initial design, coordination, and integration.
* Ray Larson - Images and Intuitext.
* Brent Southard - Saving and restoring gadgets in binary form.
* Dave Milligan - Gadget Editor Main menu.
*
*
**********************************************************************/
/* The header files needed for gadget definitions */
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <libraries/dosextens.h>
#include <graphics/gfxbase.h>
#include <graphics/gfx.h>
#include <graphics/display.h>
#include <graphics/text.h>
#include <functions.h>
#include <ctype.h>
#include "gadget.h"
/**********************************************************************
* Text attribute structures used in rendering IntuiTexts
**********************************************************************/
char def_font[] ="topaz.font";
struct TextAttr TxtAt_Plain = { (UBYTE *)def_font, 8,
FS_NORMAL, FPF_ROMFONT};
struct TextAttr TxtAt_BIU = {(UBYTE *)def_font, 8,
FSF_BOLD | FSF_ITALIC | FSF_UNDERLINED, FPF_ROMFONT};
struct TextAttr TxtAt_BU = {(UBYTE *)def_font, 8,
FSF_BOLD | FSF_UNDERLINED, FPF_ROMFONT};
struct TextAttr TxtAt_BI = {(UBYTE *)def_font, 8,
FSF_BOLD | FSF_ITALIC, FPF_ROMFONT};
struct TextAttr TxtAt_B ={(UBYTE *)def_font, 8,
FSF_BOLD, FPF_ROMFONT};
struct TextAttr TxtAt_IU ={(UBYTE *)def_font, 8,
FSF_ITALIC | FSF_UNDERLINED, FPF_ROMFONT};
struct TextAttr TxtAt_I ={(UBYTE *)def_font, 8,
FSF_ITALIC, FPF_ROMFONT};
struct TextAttr TxtAt_U ={(UBYTE *)def_font, 8,
FSF_UNDERLINED, FPF_ROMFONT};
/* STOP gadget definition */
/***************************************************************/
/* The following data structure contains the image data */
/***************************************************************/
USHORT StopGadImg_dat[]= {
0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0020, 0x0000, 0x00ff, 0xffff, 0xffe0, 0x0000,
0x0006, 0x0000, 0x03ff, 0xffff, 0xfff8, 0x0000, 0x0006, 0x0000,
0x07ff, 0xffff, 0xfffc, 0x0000, 0x0027, 0x0000, 0x1fff, 0xffff,
0xffff, 0x0000, 0x0021, 0x0000, 0x3fff, 0xffff, 0xffff, 0x8000,
0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xe000, 0x0026, 0x0001,
0xffff, 0xffff, 0xffff, 0xf000, 0x0000, 0x0007, 0xffff, 0xffff,
0xffff, 0xfc00, 0x0020, 0x000f, 0xffff, 0xffff, 0xffff, 0xfe00,
0x0038, 0x000f, 0xffff, 0xffff, 0xffff, 0xfe00, 0x0010, 0x000f,
0xffff, 0xffff, 0xffff, 0xfe00, 0x0000, 0x000f, 0xffff, 0xffff,
0xffff, 0xfe00, 0x0000, 0x000f, 0xffff, 0xffff, 0xffff, 0xfe00,
0x0000, 0x000f, 0xffff, 0xffff, 0xffff, 0xfe00, 0x0000, 0x000f,
0xffff, 0xffff, 0xffff, 0xfe00, 0x0000, 0x000f, 0xffff, 0xffff,
0xffff, 0xfe00, 0x0000, 0x000f, 0xffff, 0xffff, 0xffff, 0xfe00,
0x0036, 0x000f, 0xffff, 0xffff, 0xffff, 0xfe00, 0x0020, 0x000f,
0xffff, 0xffff, 0xffff, 0xfe00, 0x0006, 0x000f, 0xffff, 0xffff,
0xffff, 0xfe00, 0x003c, 0x000f, 0xffff, 0xffff, 0xffff, 0xfe00,
0x0006, 0x0007, 0xffff, 0xffff, 0xffff, 0xfc00, 0x0031, 0x0001,
0xffff, 0xffff, 0xffff, 0xf000, 0x0000, 0x0000, 0xffff, 0xffff,
0xffff, 0xe000, 0x0000, 0x0000, 0x3fff, 0xffff, 0xffff, 0x8000,
0x000f, 0x0000, 0x1fff, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000,
0x07ff, 0xffff, 0xfffc, 0x0000, 0x0000, 0x0000, 0x03ff, 0xffff,
0xfff8, 0x0000, 0x0000, 0x0000, 0x00ff, 0xffff, 0xffe0, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0007, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x00ff, 0xffff,
0xffe0, 0x0000, 0x0000, 0x0000, 0x03ff, 0xffff, 0xfff8, 0x0000,
0x0000, 0x0000, 0x07ff, 0xffff, 0xfffc, 0x0000, 0x0000, 0x0000,
0x1fff, 0xffff, 0xffff, 0x0000, 0x0020, 0x0000, 0x3fff, 0xffff,
0xffff, 0x8000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xe000,
0x003f, 0x0001, 0xffff, 0xffff, 0xffff, 0xf000, 0x0006, 0x0007,
0xffff, 0xffff, 0xffff, 0xfc00, 0x0001, 0x0007, 0xffff, 0xffff,
0xffff, 0xfc00, 0x0026, 0x0007, 0xffff, 0xffff, 0xffff, 0xfc00,
0x0000, 0x0007, 0xffff, 0xffff, 0xffff, 0xfc00, 0x0001, 0x0007,
0xffff, 0xffff, 0xffff, 0xfc00, 0x0006, 0x0007, 0xffff, 0xffff,
0xffff, 0xfc00, 0x0006, 0x0007, 0xffff, 0xffff, 0xffff, 0xfc00,
0x0003, 0x0007, 0xffff, 0xffff, 0xffff, 0xfc00, 0x0001, 0x0007,
0xffff, 0xffff, 0xffff, 0xfc00, 0x0000, 0x0007, 0xffff, 0xffff,
0xffff, 0xfc00, 0x0024, 0x0007, 0xffff, 0xffff, 0xffff, 0xfc00,
0x0000, 0x0007, 0xffff, 0xffff, 0xffff, 0xfc00, 0x0006, 0x0007,
0xffff, 0xffff, 0xffff, 0xfc00, 0x0000, 0x0001, 0xffff, 0xffff,
0xffff, 0xf000, 0x0001, 0x0000, 0xffff, 0xffff, 0xffff, 0xe000,
0x0000, 0x0000, 0x3fff, 0xffff, 0xffff, 0x8000, 0x0001, 0x0000,
0x1fff, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x07ff, 0xffff,
0xfffc, 0x0000, 0x0000, 0x0000, 0x03ff, 0xffff, 0xfff8, 0x0000,
0x0000, 0x0000, 0x00ff, 0xffff, 0xffe0, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x003f, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0007, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0002
};
/***************************************************************/
/* The following data structure defines the image */
/***************************************************************/
struct Image StopGadImg = {
0, 0, /* Left, Top */
90, 38, /* Width, Height */
2, /* Depth */
(USHORT *)&StopGadImg_dat, /* ImageData */
0xff, /* PlanePick */
0x00, /* PlaneOnOff */
NULL /* Next Image */
};
/**********************************************************************
* IntuiTexts for the StopGad gadget.
**********************************************************************/
struct IntuiText StopGad_Text_0 = {
0, 3, /* FrontPen, BackPen */
JAM2, /* DrawMode */
26, 13, /* LeftEdge, TopEdge */
&TxtAt_B, /* ITextFont Pointer - bold */
/* The IText */
(UBYTE *)"STOP",
NULL
};
/**********************************************************************
* Gadget Structure definition for the StopGad gadget.
**********************************************************************/
struct Gadget StopGad = {
NULL, /* NextGadget pointer */
76, 30, /* LeftEdge, TopEdge */
90, 38, /* Width, Height */
/* Gadget Flags */
GADGIMAGE,
/* Activation Flags */
RELVERIFY,
/* GadgetType */
BOOLGADGET,
(APTR)&StopGadImg, /* GadgetRender */
NULL, /* SelectRender */
&StopGad_Text_0, /* GadgetText */
0x0, /* MutualExclude */
NULL, /* SpecialInfo */
STOPGAD, /* GadgetID */
0x4 /* UserData Pointer */
};
^L
#define REQUESTWIDTH 240
#define REQUESTHEIGHT 50
/* New window structure */
static struct NewWindow pathreqnw = {
640 - REQUESTWIDTH - 8, /* LeftEdge */
12, /* TopEdge */
REQUESTWIDTH + 4, /* Width */
REQUESTHEIGHT + 10, /* Height */
0, /* DetailPen */
1, /* BlockPen */
/* IDCMP Flags */
GADGETDOWN | GADGETUP | REQSET,
/* Flags */
WINDOWDEPTH | WINDOWDRAG | ACTIVATE ,
NULL, /* First gadget */
NULL, /* Checkmark */
(UBYTE *)"Pathname Specifications", /* Window title */
NULL, /* No custom streen */
NULL, /* Not a super bitmap window */
REQUESTWIDTH+4, /* MinWidth */
REQUESTHEIGHT + 10, /* MinHeight */
640, /* MaxWidth */
200, /* MaxHeight */
WBENCHSCREEN
};
/**********************************************************************
* Border Definitions for listpath gadget
**********************************************************************/
SHORT listpath_Pairs_1[] = {
0, 0,
240, 0,
240, 30,
0, 30,
0, 0
};
struct Border listpath_bord_1 = {
-1, -1, /* LeftEdge, TopEdge */
1, 3, JAM2, /* FrontPen, BackPen, DrawMode*/
5, /* Count of XY pairs */
(SHORT *)&listpath_Pairs_1, /* XY pairs */
NULL /* Next Border */
};
/**********************************************************************
* IntuiTexts for the listpath gadget.
**********************************************************************/
struct IntuiText listpath_Text_0 = {
3, 0, /* FrontPen, BackPen */
JAM2, /* DrawMode */
-112, 0, /* LeftEdge, TopEdge */
&TxtAt_Plain, /* ITextFont Pointer */
/* The IText */
(UBYTE *)"Listing Path:",
NULL
};
/**********************************************************************
* String information for the listpath string gadget.
**********************************************************************/
UBYTE listpath_sbuf_1[81] = "PRT:";
UBYTE listpath_ubuf_1[81];
struct StringInfo listpath_txstr_1 = {
listpath_sbuf_1, listpath_ubuf_1, /* Buffer, UndoBuffer */
0, 80, 0, /* BufferPos, MaxChars, DispPos */
0, 0, /* UndoPos, NumChars */
0, 0, 0, /* DispCount, CLeft, CTop */
0x0, 0, /* LayerPtr, LongInt */
0x0 /* AltKeyMap */
};
/**********************************************************************
* Gadget Structure definition for the listpath gadget.
**********************************************************************/
struct Gadget listpathgad = {
NULL, /* NextGadget pointer */
120, 36, /* LeftEdge, TopEdge */
100, 9, /* Width, Height */
/* Gadget Flags */
GADGHCOMP,
/* Activation Flags */
GADGIMMEDIATE | RELVERIFY,
/* GadgetType */
REQGADGET | STRGADGET,
/*(APTR)&listpath_bord_1, */ /* GadgetRender */
NULL, /* GadgetRender */
NULL, /* SelectRender */
&listpath_Text_0, /* GadgetText */
0x0, /* MutualExclude */
(APTR)&listpath_txstr_1, /* SpecialInfo */
LISTPATHGAD, /* GadgetID */
NULL /* UserData Pointer */
};
/**********************************************************************
* Border Definitions for backpath gadget
**********************************************************************/
SHORT backpath_Pairs_1[] = {
0, 0,
240, 0,
240, 9,
0, 9,
0, 0
};
struct Border backpath_bord_1 = {
-1, -1, /* LeftEdge, TopEdge */
1, 3, JAM2, /* FrontPen, BackPen, DrawMode*/
5, /* Count of XY pairs */
(SHORT *)&backpath_Pairs_1, /* XY pairs */
NULL /* Next Border */
};
/**********************************************************************
* IntuiTexts for the backpath gadget.
**********************************************************************/
struct IntuiText backpath_Text_0 = {
3, 0, /* FrontPen, BackPen */
JAM2, /* DrawMode */
-104, 0, /* LeftEdge, TopEdge */
&TxtAt_Plain, /* ITextFont Pointer */
/* The IText */
(UBYTE *)"Backup Path:",
NULL
};
/**********************************************************************
* String information for the backpath string gadget.
**********************************************************************/
UBYTE backpath_sbuf_1[81] = "DF0:";
UBYTE backpath_ubuf_1[81];
struct StringInfo backpath_txstr_1 = {
backpath_sbuf_1, backpath_ubuf_1, /* Buffer, UndoBuffer */
0, 80, 0, /* BufferPos, MaxChars, DispPos */
0, 0, /* UndoPos, NumChars */
0, 0, 0, /* DispCount, CLeft, CTop */
0x0, 0, /* LayerPtr, LongInt */
0x0 /* AltKeyMap */
};
/**********************************************************************
* Gadget Structure definition for the backpath gadget.
**********************************************************************/
struct Gadget backpathgad = {
&listpathgad, /* NextGadget pointer */
120, 20, /* LeftEdge, TopEdge */
100, 9, /* Width, Height */
GADGHCOMP, /* Flags */
GADGIMMEDIATE | RELVERIFY, /* Activation */
REQGADGET | STRGADGET, /* GadgetType */
/* (APTR)&backpath_bord_1, */ /* GadgetRender */
NULL, /* GadgetRender */
NULL, /* SelectRender */
&backpath_Text_0, /* GadgetText */
0x0, /* MutualExclude */
(APTR)&backpath_txstr_1, /* SpecialInfo */
BACKPATHGAD, /* GadgetID */
NULL /* UserData Pointer */
};
/**********************************************************************
* Border Definitions for homepath gadget
**********************************************************************/
SHORT homepath_Pairs_1[] = {
0, 0,
240, 0,
240, 9,
0, 9,
0, 0
};
struct Border homepath_bord_1 = {
-1, -1, /* LeftEdge, TopEdge */
1, 3, JAM2, /* FrontPen, BackPen, DrawMode*/
5, /* Count of XY pairs */
(SHORT *)&homepath_Pairs_1, /* XY pairs */
NULL /* Next Border */
};
/**********************************************************************
* IntuiTexts for the homepath gadget.
**********************************************************************/
struct IntuiText homepath_Text_0 = {
3, 0, /* FrontPen, BackPen */
JAM2, /* DrawMode */
-88, 0, /* LeftEdge, TopEdge */
&TxtAt_Plain, /* ITextFont Pointer */
/* The IText */
(UBYTE *)"Home Path:",
NULL
};
/**********************************************************************
* String information for the homepath string gadget.
**********************************************************************/
UBYTE homepath_sbuf_1[81] = "DH0:";
UBYTE homepath_ubuf_1[81];
struct StringInfo homepath_txstr_1 = {
homepath_sbuf_1, homepath_ubuf_1, /* Buffer, UndoBuffer */
0, 80, 0, /* BufferPos, MaxChars, DispPos */
0, 8, /* UndoPos, NumChars */
0, 0, 0, /* DispCount, CLeft, CTop */
0x0, 0, /* LayerPtr, LongInt */
0x0 /* AltKeyMap */
};
/**********************************************************************
* Gadget Structure definition for the homepath gadget.
**********************************************************************/
struct Gadget homepathgad = {
&backpathgad, /* NextGadget pointer */
120, 4, /* LeftEdge, TopEdge */
100, 9, /* Width, Height */
/* Gadget Flags */
GADGHCOMP,
/* Activation Flags */
GADGIMMEDIATE | RELVERIFY,
/* GadgetType */
REQGADGET | STRGADGET,
/*(APTR)&homepath_bord_1, */ /* GadgetRender */
NULL, /* GadgetRender */
NULL, /* SelectRender */
&homepath_Text_0, /* GadgetText */
0x0, /* MutualExclude */
(APTR)&homepath_txstr_1, /* SpecialInfo */
HOMEPATHGAD, /* GadgetID */
NULL /* UserData Pointer */
};
struct Requester *pathrequest;
struct Window *pathwindow;
/* Initialize the pathname requester. */
int
InitPathRequest()
{
int status = 0;
pathrequest = (struct Requester *)
AllocMem((long) sizeof(struct Requester), MEMF_PUBLIC|MEMF_CLEAR);
if (pathrequest) {
InitRequester(pathrequest);
pathrequest->Width = REQUESTWIDTH;
pathrequest->Height = REQUESTHEIGHT;
pathrequest->TopEdge = 12;
pathrequest->LeftEdge = 4;
pathrequest->BackFill = 2;
pathrequest->ReqGadget = &homepathgad;
if (pathwindow = OpenWindow(&pathreqnw))
Request(pathrequest, pathwindow);
else ++status;
}
else ++status;
return status;
}
/* Shut down the path requester mechanisms. */
CancelPathRequest()
{
if (pathrequest) {
if (pathwindow) {
EndRequest(pathrequest, pathwindow);
CloseWindow(pathwindow);
}
FreeMem(pathrequest, (long) sizeof(struct Requester));
}
}
SHAR_EOF