mrr@softie.UUCP (09/26/87)
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file"
# Created Fri Sep 25 07:25:56 1987
#
# This archive contains:
# CopyFile.c
# Gadget.h
# InitBuffer.c
# MRBackup.h
# Main.c
echo "Creating CopyFile.c"
cat > CopyFile.c <<"***EOF CopyFile.c***"
/* MRBackup: File Copy Routine.
* Date: 09/04/87
* Notes:
* To enhance the performance of MRBackup, this package was copied
* from my Misc library and modified to couple it more tightly with
* MRBackup. It now uses a global buffer area allocated during
* initialization.
*
* History: (most recent change first)
*
* 09/04/87 -MRR- CopyFile, upon failure, now returns the error status
* code from IoErr().
*/
#include "MRBackup.h"
/*
* Copy file, preserving date.
* Depends upon file date routines in FileMisc.c
* Original author: Jeff Lydiatt, Vancouver, Canada
*/
#include <stdio.h>
#include <exec/types.h>
#include <libraries/dos.h>
#include <exec/memory.h>
#include <functions.h>
#define MAXSTR 127
extern long Chk_Abort();
extern BOOL GetFileDate(), SetFileDate();
extern long IoErr();
/* Copy the last modified date from one file to another.
* Called with:
* from: name of source file
* to: name of destination file
* Returns:
* 0 => success, 1 => failure
* Note:
* Dynamic memory allocation of the DateStamp struction is
* necessary to insure longword alignment.
*/
BOOL
CopyFileDate(from,to)
char *from, *to;
{
struct DateStamp *date;
int status = 1; /* default is fail code */
if (date = (struct DateStamp *)
AllocMem((long) sizeof(struct DateStamp), MEMF_PUBLIC)) {
if (GetFileDate(from,date))
if (SetFileDate(to,date))
status = 0;
FreeMem(date, (long) sizeof(struct DateStamp));
}
return status;
}
int
CopyFile(from,to)
char *from,*to;
{
long status, count;
struct FileHandle *fin,*fout;
#ifdef DEBUG
char errmsg[256];
static char *errfmt = "I/O error %ld, file %s";
#endif
if ((fin = Open(from, MODE_OLDFILE ))== NULL ){
badcopy:
status = IoErr();
#ifdef DEBUG
sprintf(errmsg, errfmt, status, from);
print_err:
puts(errmsg);
#endif
if (fin) Close(fin);
if (fout) {
Close(fout);
unlink(to); /* delete the bad copy */
}
return (int) status;
}
if ( !(fout = Open(to, MODE_NEWFILE)) ) goto badcopy;
status = 0;
while ( !status && (count = Read( fin, buffer, bufsize )) == bufsize )
if ( Write(fout, buffer, count) != count)
status = IoErr();
if (!status && count > 0 ) {
if (Write(fout, buffer, count) != count)
status = IoErr();
}
if (status) goto badcopy;
Close(fin);
Close(fout);
return CopyFileDate(from, to);
}
***EOF CopyFile.c***
echo "Creating Gadget.h"
cat > Gadget.h <<"***EOF Gadget.h***"
/* Definitions for Gadget ID numbers */
#define HOMEPATHGAD 0
#define BACKPATHGAD 1
#define LISTPATHGAD 2
#define XCLDPATHGAD 3
#define STOPGAD 4
***EOF Gadget.h***
echo "Creating InitBuffer.c"
cat > InitBuffer.c <<"***EOF InitBuffer.c***"
for (bufsize = BUFMAX; bufsize > 2048; bufsize -= 2048 )
if ((buffer = malloc((unsigned int)bufsize))!= NULL )
break;
***EOF InitBuffer.c***
echo "Creating MRBackup.h"
cat > MRBackup.h <<"***EOF MRBackup.h***"
/* MRBackup - include file for global data and definitions.
* Filename: MRBackup.h
* Date: 08/22/87
*
* History: (most recent change first)
*
* 09/03/87 -MRR- V1.3: Changed window version and date.
*/
/* Main.c defines MAIN. It should not defined elsewhere. */
#ifdef MAIN
#define EXTERN
#else
#define EXTERN extern
#endif
#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 BUFMAX (32L * 1024L) /* max size for copy/compress buffer */
#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)
typedef struct t_pattern {
struct t_pattern * next_pattern;
char *pattern;
} T_PATTERN;
/* 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 */
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
EXTERN struct FileHandle *debugconsole;
EXTERN char debugmsg[512];
#endif
EXTERN short back; /* backup disk serial number */
EXTERN UBYTE *buffer; /* file copy/cmprs buffer (AllocMem) */
EXTERN ULONG bufsize; /* size of buffer allocated */
EXTERN struct FileHandle *console; /* for informative messages */
EXTERN char conmsg[512];
EXTERN T_FILE *current_dir = NULL; /* current directory node */
EXTERN char destpath[PATH_MAX+1];
EXTERN char destvol[VOLUME_MAX+1];
EXTERN BOOL exclude_has_changed; /* true when new path specified */
EXTERN T_PATTERN *excludelist, *lastexclude;
EXTERN char excludepath[81]; /* list of file patterns to exclude */
EXTERN struct IntuitionBase *IntuitionBase;
EXTERN USHORT level; /* file nesting level */
EXTERN USHORT linecount; /* number of lines in listing */
EXTERN FILE *listing;
EXTERN T_FILE_LIST main_list;
EXTERN struct Window *mywindow;
EXTERN struct DateStamp *now, *since; /* for date comparisons */
EXTERN short size; /* floppy blocks remaining */
EXTERN char srcpath[PATH_MAX];
EXTERN char srcvol[VOLUME_MAX+1]; /* source volume name */
EXTERN char temp[256];
/* The following flags suppress repetition of spoken
* messages. After all, let's not over-do it.
*/
EXTERN UBYTE at_your_service;
/* Preset data */
#ifdef MAIN
char backpath[81] = "DF0:"; /* where backups go and restores
come from. */
char destdrive[5] = "DF0:";
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. */
char listpath[81] = "PRT:"; /* where we send all of that vital
information about backups */
struct NewWindow nw = { /* New window structure */
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.3 09/03/87",/* Window title */
NULL, /* No custom streen */
NULL, /* Not a super bitmap window */
0,0,640,200, /* Not used, but set up anyway */
WBENCHSCREEN
};
#else
/* Declare preset external data without the presets. */
extern char backpath[81];
extern char destdrive[5];
extern USHORT do_compress; /* compression flag */
extern USHORT do_listing; /* listing flag */
extern USHORT do_speech; /* speech flag */
extern char destdrive[];
extern char *erropts[];
extern char homepath[81];
extern char listpath[81];
extern struct NewWindow nw;
#endif
***EOF MRBackup.h***
echo "Creating Main.c"
cat > Main.c <<"***EOF Main.c***"
/* MRBackup - Amiga Hard Disk Backup Utility
* Filename: Main.c
* Author: Mark R. Rinfret
* Date: 08/01/87
*
* This program has been contributed to the public domain. It represents
* a collection of original work and other public domain offerings that
* were found to be useful in writing this application. To the best of
* my knowledge, this program works as described in the accompanying
* document, but no warranties are made in this regard.
* USE AT YOUR OWN RISK.
*
* If you find this program useful, or if you have comments or suggestions
* for enhancing it, please send email to mark@unisec.USI.COM or U.S. Mail
* to:
* Mark R. Rinfret
* 348 Indian Avenue
* Portsmouth, RI 02871
* 401-846-7639 (home)
* 401-849-4174 (work)
*
* History: (most recent change first)
*
* 09/04/87 -MRR- V1.3: Extracted routines related to the backup function
* and placed them in package Backup.c.
*
* 09/03/87 -MRR- V1.3: Fixed a bug in the routines which handle the
* listing file and pathname.
* Extended the IsCompressed() function to check for
* .ARC and .ZOO files.
*
* 08/22/87 -MRR- V1.2: Extracted global data and definitions and placed
* them in a common include file.
*
* 08/11/87 -MRR- V1.1: BUG! The variable 'back' (backup sequence number)
* was not set to 0 by Backup().
*/
#define MAIN
#include "MRBackup.h"
extern struct Requester *pathrequest;
extern struct Window *pathwindow;
/* 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);
}
/* 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);
#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/100/640/90/Progress Report", MODE_NEWFILE)))
CleanUp("Can't open console!", 20);
SetMenuStrip(mywindow, &Titles[0]);
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);
InitBuffer(); /* Allocate copy/compress buffer */
GetUserPrefs(); /* Get user preferences */
SetSpeech();
}
/* Allocate the buffer used for copy/compress operations. */
InitBuffer()
{
for (bufsize = BUFMAX; bufsize > 2048; bufsize -= 2048 )
if (buffer = AllocMem(bufsize, MEMF_CHIP))
return;
CleanUp("Not enough memory for copy buffer!\n",20);
}
/* 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));
if (buffer) FreeMem(buffer, bufsize);
exit(code);
}
/* 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;
}
/* 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;
}
#ifdef DEBUG
DebugWrite(msg)
char *msg;
{
Write(debugconsole, msg, (long) strlen(msg));
}
#endif
/* Handle a gadget action.
* Called with:
* window: window that gadget is displayed in
* class: message class (GADGETUP/GADGETDOWN/?)
* addr: pointer to gadget structure
*/
DoGadget(window, class, addr)
struct Window *window; ULONG class; struct Gadget *addr;
{
USHORT id; /* gadget identifier */
struct Gadget *upgad;
ULONG upclass;
struct IntuiMessage *upmsg; /* require gadget up to complete */
id = addr->GadgetID;
#ifdef TESTING
if (class == GADGETDOWN && window == pathwindow) {/* pathname gadget */
ActivateWindow(pathwindow);
do {
Wait(1L << pathwindow->UserPort->mp_SigBit);
if (upmsg = (struct IntuiMessage *)
GetMsg(pathwindow->UserPort)) {
upclass = upmsg->Class;
upgad = (struct Gadget *) upmsg->IAddress;
ReplyMsg(upmsg);
if (upclass == GADGETUP && upgad->GadgetID == id) {
class = GADGETUP; /* use new class */
}
else {
upmsg = NULL;
ActivateGadget(addr, pathwindow, pathrequest);
}
}
}
while (! upmsg );
}
#endif
if (class == GADGETUP) {
#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 XCLDPATHGAD:
GetXcldPath(addr);
break;
case STOPGAD:
TypeAndSpeak(
"Use the STOP gadget during backup and restore operations.\n");
break;
default:
TypeAndSpeak("Unknown gadget - program error!\n");
break;
}
}
}
/* 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 (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");
strcpy(fullpath, backpath); /* restore previous value */
}
else
strcpy(backpath, fullpath); /* use new value */
RefreshGadgets(gadget, pathwindow, NULL);
}
/* 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... */
}
/* 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];
RemoveGadget(pathwindow, gadget);
fullpath = (UBYTE *) GadgetString(gadget);
BreakPath(fullpath, volume, path);
if (!IsDir(fullpath)) {
badpath:
TypeAndSpeak(
"Home path must be a disk device with optional directory name!\n");
strcpy(fullpath, homepath); /* restore previous value */
}
else if (strlen(volume) != 3 ||
tolower(volume[0]) != 'd' ||
(tolower(volume[1]) != 'h' && tolower(volume[1]) != 'f') ||
!isdigit(volume[2])) {
#ifdef DEBUG
sprintf(debugmsg,"home device = \"%s\" ? \n",volume);
DebugWrite(debugmsg);
#endif
goto badpath;
}
else {
strcpy(homepath, fullpath);
sprintf(conmsg,"Home path is %s\n", homepath);
WriteConsole(conmsg);
}
ResetStringInfo(gadget->SpecialInfo);
AddGadget(pathwindow, gadget, -1L);
RefreshGadgets(gadget, pathwindow, NULL);
}
/* Get the listing pathname.
* Called with:
* gadget: pointer to relevant string gadget
*
* Side-effects:
*/
GetListPath(gadget)
struct Gadget *gadget;
{
UBYTE *path;
RemoveGadget(pathwindow, gadget);
path = (UBYTE *) GadgetString(gadget);
if (!do_listing) {
TypeAndSpeak("Listing mode is not active. ");
TypeAndSpeak("Your change has been ignored.\n");
badpath:
strcpy(path, listpath);
}
else {
if (strcmp(path, listpath)) { /* not same pathname */
if (OpenList(path)) goto badpath;
strcpy(listpath, path);
sprintf(conmsg,"Listing path is %s\n", listpath);
WriteConsole(conmsg);
}
}
ResetStringInfo(gadget->SpecialInfo);
AddGadget(pathwindow, gadget, -1L);
RefreshGadgets(gadget, pathwindow, NULL);
}
GetXcldPath(gadget)
struct Gadget *gadget;
{
UBYTE *path;
RemoveGadget(pathwindow, gadget);
path = (UBYTE *) GadgetString(gadget);
if (!strcmp(path, excludepath)) /* same pathname */
return;
if (access(path, 0)) { /* can't access the file? */
TypeAndSpeak("I can't access the exclude file!\n");
strcpy(path, excludepath); /* restore the gadget */
}
else {
strcpy(excludepath, path);
exclude_has_changed = true;
sprintf(conmsg,"Exclude path is %s\n", excludepath);
}
ResetStringInfo(gadget->SpecialInfo);
AddGadget(pathwindow, gadget, -1L);
RefreshGadgets(gadget, pathwindow, NULL);
}
/* 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;
}
}
/* Determine if a file is compressed. This is currently done by looking
* at the file name suffix. A rather dumb assessment of the file type
* is made based on a match to one of these suffixes.
*
* Called with:
* filename: file name string
* Returns:
* 1 => file is compressed, 0 => file is not compressed
*/
int
IsCompressed(filename)
char *filename;
{
#define NSUFFIX 3 /* number of known suffixes */
typedef struct {
char *sufx;
USHORT length;
} T_SUFFIX;
static T_SUFFIX suffixes[NSUFFIX] = {
{".z", 2} ,
{".arc", 4},
{ ".zoo", 4}
};
USHORT i, length;
char *s;
length = strlen(filename); /* get length of argument filename */
for (i = 0; i < NSUFFIX; ++i) {
if (length < suffixes[i].length) continue;
/* We're just interested in the current suffix length. */
s = filename + length - suffixes[i].length;
if (!strcmpc(s, suffixes[i].sufx))
return true; /* suffixes match */
}
return false;
}
/* 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);
fflush(listing);
++linecount;
}
}
/* 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;
}
/* 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;
}
}
}
/* Open the listing file.
* Called with:
* name: file or device pathname
* Returns:
* status (0 => success)
*/
int
OpenList(name)
char *name;
{
int status = 0;
if (listing) fclose(listing); /* prior listing file open? */
if (!(listing = fopen(name, "w"))) {
status = errno;
sprintf(conmsg,
"I can't open the listing file \"%s\", error %d.\n",
name, status);
TypeAndSpeak(conmsg);
}
else
linecount = LINES_PER_PAGE;
return status;
}
/* Reset the variables in a StringInfo structure.
* Called with:
* s: pointer to a StringInfo
*/
ResetStringInfo(s)
struct StringInfo *s;
{
*(s->UndoBuffer) = '\0';
s->BufferPos = 0;
s->DispPos = 0;
s->UndoPos = 0;
s->NumChars = strlen(s->Buffer);
}
/* Enable/disable speech capability, based on global 'do_speech'. */
SetSpeech()
{
if (do_speech) {
if (!SpeechOn()) {
DateStamp(now);
if (now->ds_Tick < 1500)
Say("That feels good! Thanks for turning me on!");
else
Say("Hi. How may I help you?");
}
}
else
SpeechOff();
}
Speak(msg)
char *msg;
{
if (do_speech) Say(msg);
}
/* Perform a case-insensitive string compare.
* Called with:
* s1, s2: strings to be compared
* Returns:
* comparison code: 0 => strings match
* <0 => s1 < s2
* >0 => s1 > s2
*/
int
strcmpc(s1, s2)
register char *s1, *s2;
{
int c1, c2, cd;
do {
c1 = tolower(*s1++);
c2 = tolower(*s2++);
if (cd = (c1 - c2)) break;
} while (c1 && c2);
return cd;
}
/* 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 */
struct Window *msgwindow; /* window message occurred in */
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
while (!quit) {
ActivateWindow(mywindow);
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;
msgwindow = msg->IDCMPWindow;
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(msgwindow, class, Iadr);
break;
case MENUPICK:
quit = UserMenu(code);
break;
default:
break; /* ignore the rest */
} /* end switch(class) */
}
}
}
/* Handle a menu selection.
* Called with:
* xcode: menu selection code
* Returns:
* status code (1 => Quit was selected)
*/
int
UserMenu(xcode)
USHORT xcode;
{
USHORT code = xcode;
struct MenuItem *item;
USHORT itemnum,menunum;
while (code != MENUNULL) {
menunum = MENUNUM(code);
itemnum = ITEMNUM(code);
#ifdef DEBUG
sprintf(debugmsg,"menu = %d, item = %d\n",menunum,itemnum);
DebugWrite(debugmsg);
#endif
item = ItemAddress(&Titles[0], code);
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;
}
}
#define EXTENDED_SELECT_WORKS
#ifdef EXTENDED_SELECT_WORKS
code = item->NextSelect;
/* This next line is a kludge. Testing has revealed that
* the NextSelect field is returning 0000x. Why?
*/
if (!code) break;
#else
break;
#endif
}
return 0;
}
/* Write a message to the console window.
* Called with:
* msg: message string
*/
WriteConsole(msg)
char *msg;
{
Write(console, msg, (long) strlen(msg));
}
***EOF Main.c***
--
< Mark R. Rinfret, mrr@softie, ..rayssd!unisec!softie!mrr >
< SofTech, Inc. Home: 401-846-7639 >
< 1 Silva Lane, Work: 401-849-4174 >
< Middletown, RI 02840 "The name has changed but I'm still guilty." >