home *** CD-ROM | disk | FTP | other *** search
- /*
- * FAM.c -- Rexx File Access Manager and Directory Buffer.
- * Copyright 1990 Darren New. All Rights Reserved.
- * Originally for DIBBS -- Darren's Innovative Bulletin Board Server
- */
-
- /******************************************************************
-
- This program allows multiple ARexx programs to access a buffered version of
- a directory in a consistent and serialized manner. This program and all
- derivative works are copyright 1990 Darren New. All Rights Reserved.
-
- 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 names of the copyright holder or author not be
- used in advertising or publicity pertaining to disstribution of the
- software without specific, written prior permission.
-
- BOTH THE AUTHOR AND THE COPYRIGHT HOLDER DISCLAIM ALL WARRANTIES WITH
- REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDER OR THE
- AUTHOR 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.
-
- VERSION 1.1 Feb 1990
-
- ***********************************************************/
-
- #define PROGNAME "FAM"
- #define PROGVERS "1.1"
- #define ERRLEVEL 10L /* error level to return */
-
- #include "stdio.h"
- #include "stdlib.h"
- #include "string.h"
- #include "ctype.h"
- #include "minrexx.h"
-
- #ifdef LMS
- #include "low-mem.h" /* ASDG's low memory server */
- #endif
-
- #ifdef CBACK
- #define assert(exp)
- #else
- #include "assert.h"
- #endif
-
- #include "exec/memory.h"
- #include "exec/lists.h"
- #include "libraries/dos.h"
- #include "proto/exec.h"
- #include "proto/dos.h"
-
-
- /* Because remove and insert are used very heavily during rescan, these
- * have been turned into macros to let the optimizer bash at them.
- * The InsertQ only works when the node to be inserted already points
- * to the correct nodes to insert between.
- */
-
- #define Remove(node) ((node)->ln_Pred->ln_Succ=(node)->ln_Succ,(node)->ln_Succ->ln_Pred=(node)->ln_Pred)
- #define InsertQ(node) ((node)->ln_Pred->ln_Succ=(node),(node)->ln_Succ->ln_Pred=(node))
-
- /*
- * Here is our command association list. Note that in this case,
- * we are setting the userdata field to be a function to call.
- * Dispatch will still take place through disp(), so common head
- * and tail stuff can go there.
- *
- * Commands are all lower case, so we match either upper or lower.
- * (This is a requirement of minrexx.)
- */
-
- void FAMversion (struct RexxMsg *msg, char *p);
- void FAMopen (struct RexxMsg *msg, char *p);
- void FAMclose (struct RexxMsg *msg, char *p);
- void FAMclear (struct RexxMsg *msg, char *p);
- void FAMexpunge (struct RexxMsg *msg, char *p);
- void FAMgetioerr (struct RexxMsg *msg, char *p);
- void FAMgetdirname (struct RexxMsg *msg, char *p);
- void FAMgetbinextens (struct RexxMsg *msg, char *p);
- void FAMgetbufendline (struct RexxMsg *msg, char *p);
- void FAMgetnamecount (struct RexxMsg *msg, char *p);
- void FAMgetnames (struct RexxMsg *msg, char *p);
- void FAMgetinfo (struct RexxMsg *msg, char *p);
- void FAMrescan1 (struct RexxMsg *msg, char *p);
- void FAMrescan (struct RexxMsg *msg, char *p);
- void FAMgrep (struct RexxMsg *msg, char *p);
- void FAMnewfile (struct RexxMsg *msg, char *p);
- void FAMlockfile (struct RexxMsg *msg, char *p);
-
- struct rexxCommandList rcl[] = {
- { "version", (APTR)&FAMversion },
- { "open", (APTR)&FAMopen },
- { "close", (APTR)&FAMclose },
- { "clear", (APTR)&FAMclear },
- { "expunge", (APTR)&FAMexpunge },
- { "getioerr", (APTR)&FAMgetioerr },
- { "getdirname", (APTR)&FAMgetdirname },
- { "getbinextens", (APTR)&FAMgetbinextens },
- { "getbufendline", (APTR)&FAMgetbufendline },
- { "getnamecount", (APTR)&FAMgetnamecount },
- { "getnames", (APTR)&FAMgetnames },
- { "getinfo", (APTR)&FAMgetinfo },
- { "rescan1", (APTR)&FAMrescan1 },
- { "rescan", (APTR)&FAMrescan },
- { "grep", (APTR)&FAMgrep },
- { "newfile", (APTR)&FAMnewfile },
- { "lockfile", (APTR)&FAMlockfile },
- { NULL, NULL } } ;
-
-
- /********************************************************************
- * GLOBAL STATUS VARIABLES
- ********************************************************************/
-
- /*
- * Here are the globals used by Lattice's CBack.o
- *
- */
-
- #ifdef CBACK
- LONG _stack = 4000; /* stack space */
- char *_procname = PROGNAME "-task";/* process name */
- LONG _priority = 0; /* default priority */
- LONG _BackGroundIO = 1; /* I want to output some messages */
- extern LONG _Backstdout; /* FileHandle to output to */
- #endif
-
-
- /*
- * Here are the globals for keeping track of our command-line arguments
- * and our current status.
- *
- */
-
- char VersionString[] = PROGNAME " V" PROGVERS " COMPILED " __DATE__ " " __TIME__;
-
- char * PortName; /* name of ARexx port to open */
- char * DirPath; /* full path to directory */
- char * GrepFuncName; /* full path to GREP to LoadSeg() */
- char * BinExtens; /* file extensions of "binary" files */
- char * BufEndLine; /* line to end buffering */
-
- int OpenCount; /* number of outstanding OPENs */
- int ExpungeWanted; /* have received the EXPUNGE command */
- int ClearWanted; /* have received the CLEAR command */
- BPTR GrepEntry; /* GREP function entry point */
-
- #ifdef LMS
- struct Library * LowMemBase;/* ASDG Low Memory Base address */
- struct LowMemMsg LMSSpace; /* ASDG low memory notifier */
- int LowMemIsOpen; /* true if we are handling LowMem stuff */
- #endif
-
- /*
- * Here are the globals for holding the directory information
- *
- */
-
- #include "FAM.h"
-
- struct List ScanList; /* the actual ScanList */
- struct List TempScanList; /* an alternate copy (for sorting) */
-
- /* returns true if list is empty */
- #define IsEmpty(head) ((long) ((head).lh_TailPred) == (long) (&(head)))
-
- /* returns pointer to first node on list */
- #define FirstNode(head) ((struct ScanListNode *)((head)->lh_Head->ln_Succ))
-
- /* returns pointer to next node on list */
- #define NextNode(n) ((struct ScanListNode *)((n)->node.ln_Succ))
-
- /* returns true if node is valid ScanListNode */
- #define NotLastNode(n) ((n)&&(n)->node.ln_Succ)
-
- /* returns true if a < b */
- #define StrLT(a, b) (strcmp((a), (b)) < 0)
-
- /*
- * These globals are passed around during parsing.
- *
- */
-
- long CMDargs[9]; /* what numeric args did we see to this function? */
- int CMDparsed; /* 0 if argument parsing successful, !0 for errnum */
- int CMDuserreplied; /* has the current message been replied to yet? */
-
- /*
- * mallocFAM(), freeFAM() and strdupFAM() have the same interface as
- * malloc(), free(), and strdup() except that they actually return the
- * memory back to the system once it is freed.
- */
-
- char *strdupFAM(char * s);
- void *mallocFAM(unsigned size);
- void freeFAM(void * p);
-
- char *strdupFAM(char * s)
- {
- char * p = mallocFAM(strlen(s)+1);
- if (p) strcpy(p, s);
- return p;
- }
-
- void * mallocFAM(unsigned size)
- {
- long * p = (long *) AllocMem(size+4, MEMF_CLEAR);
- if (p) {
- *p++ = (long) size;
- }
- return p;
- }
-
- void freeFAM(void * ptr)
- {
- long * p = ptr;
- long size = *--p;
- FreeMem(p, size+4);
- }
-
- /*
- * This is our dispatch function. We call our handler function.
- * If our handler replied, we return a 1 to indicate that.
- * If the parse and everything else was successful, we return a 0.
- * Otherwise, we return a failure of 10 to indicate that the arguments
- * were messed up.
- */
- int disp(struct RexxMsg *msg, struct rexxCommandList *dat, char *p);
- int disp(struct RexxMsg *msg, struct rexxCommandList *dat, char *p)
- {
- CMDparsed = 0 ;
- CMDuserreplied = 0 ;
- ((int (*)(struct RexxMsg *, char *))(dat->userdata))(msg, p) ;
- if (CMDparsed == 0) {
- if (!CMDuserreplied)
- replyRexxCmd(msg, 0L, 0L, NULL) ;
- CMDuserreplied = 1;
- }
- else {
- replyRexxCmd(msg, ERRLEVEL, (long) CMDparsed, NULL) ;
- CMDuserreplied = 1;
- }
- return CMDuserreplied;
- }
-
-
- void errout(char * s, int exiting);
- void errout(char * s, int exiting)
- {
- #ifdef CBACK
- if (_Backstdout == NULL) {
- _Backstdout = Open("CON:0/0/400/100/RSD output", MODE_NEWFILE);
- }
- if (_Backstdout)
- Write(_Backstdout, s, (long)strlen(s));
- #else
- fprintf(stderr, "%s", s);
- #endif
-
- #ifdef CBACK
- if (exiting && _Backstdout)
- Close(_Backstdout);
- if (exiting) Delay(500);
- #endif
- if (exiting) {
- fclose(stdin);
- fclose(stdout);
- /* #ifdef CBACK */
- fclose(stderr);
- /* #endif */
- }
- }
-
- #ifdef LMS
-
- /*
- * This handles the Low Memory message coming from the ASDG Low Memory Server.
- *
- */
-
- int HandleLMS(struct Message * msg);
- int HandleLMS(struct Message * msg)
- {
- if (msg != (struct Message *) &LMSSpace) /* EH? */
- return 0;
- if (LMSSpace.lm_flag != LM_LOW_MEMORY_CONDITION) /* EH?? */
- return 0;
- LMSSpace.lm_flag = LM_CONDITION_ACKNOWLEDGED; /* ASDG foolishness */
- FAMclear(NULL, "");
- return 0;
- }
-
- #endif
-
- /*
- * Our main routine
- *
- */
-
- void main(int argc, char * * argv);
- void main(int argc, char * * argv)
- {
- long rexxbit; /* this is the Signal bit to wait for Rexx on */
- BPTR olddir, newdir;
- void FreeScanList(struct List * list);
-
- if (argc == 0) {
- errout("Can't run from WorkBench yet!\n", 1);
- exit(20); /* can't run from workbench yet */
- }
-
- errout(VersionString, 0);
- errout("\n", 0);
-
- if (argc < 4 || 6 < argc) {
- errout("Usage: " PROGNAME " portname dirpath grepfunc [binextens [bufendline]]\n", 1);
- exit(20);
- }
-
- PortName = argv[1];
- DirPath = argv[2];
- GrepFuncName = argv[3];
- if (5 <= argc)
- BinExtens = argv[4];
- if (6 <= argc)
- BufEndLine = argv[5];
-
- GrepEntry = LoadSeg(GrepFuncName);
- if (GrepEntry == 0) {
- char buf[100];
- sprintf(buf, "Could not LoadSeg GREP function \"%s\"!\n", GrepFuncName);
- errout(buf, 1);
- exit(20);
- }
-
- newdir = Lock(DirPath, ACCESS_READ);
- if (newdir) {
- olddir = CurrentDir(newdir);
- /* UnLock(olddir); */ /* CBack seems to munch this */
- }
- else {
- char buf[100];
- sprintf(buf, "Could not change to directory \"%s\"!\n", DirPath);
- errout(buf, 1);
- UnLoadSeg(GrepEntry);
- exit(20);
- }
-
-
- rexxbit = upRexxPort(PortName, rcl, NULL, &disp) ;
- if (rexxbit == 0) {
- char buf[100];
- sprintf(buf, "Could not open ARexx port \"%s\"!\n", PortName);
- errout(buf, 1);
- UnLoadSeg(GrepEntry);
- exit(20);
- }
-
- #ifdef LMS
-
- /* Attempt to use ASDG low memory server; don't gripe if not there */
- LowMemBase = OpenLibrary(LMSName, 0L);
- if (LowMemBase != NULL) {
- if (0 == RegLowMemReq(PortName , &LMSSpace)) {
- HandleNonRexx = HandleLMS;
- LMSSpace.lm_flag = LM_CONDITION_ACKNOWLEDGED;
- LowMemIsOpen = 1;
- }
- else {
- CloseLibrary(LowMemBase);
- LowMemBase = NULL;
- }
- }
-
- #endif
-
-
- { /* all went well */
- char buf[100];
- sprintf(buf, "ARexx port \"%s\" now available.\n", PortName);
- errout(buf, 1);
- }
-
- /* Here, initialize the ScanList */
- NewList(&ScanList); NewList(&TempScanList);
- ScanList.lh_Type = NT_FILELIST;
- TempScanList.lh_Type = NT_FILELIST;
-
- do {
- Wait(rexxbit);
- dispRexxPort();
- } while (! (OpenCount == 0 && ExpungeWanted));
-
- if (GrepEntry)
- UnLoadSeg(GrepEntry);
- GrepEntry = NULL;
-
- #ifdef LMS
-
- if (LowMemIsOpen) {
- LMSSpace.lm_flag = 0; /* cancel any incomming messages */
- DeRegLowMemReq(PortName);
- }
- if (LowMemBase) {
- CloseLibrary(LowMemBase);
- LowMemBase = NULL;
- }
-
- #endif
-
- CurrentDir(olddir); /* CBack doesn't like changing dirs */
- UnLock(newdir);
-
- FreeScanList(&ScanList);
- FreeScanList(&TempScanList);
-
- dnRexxPort();
- exit(0);
-
- }
-
-
- /*****************************************************************
- * Parsing routines
- *****************************************************************/
-
-
- /*
- * This function takes a pointer to a pointer to a string, grabs the
- * next number, returns it, and advances the pointer to the string to
- * point after the number.
- */
- long getnm(char ** where);
- long getnm(char ** where)
- {
- char *p = *where;
- long val = 0;
- long gotone = 0;
-
- while (*p <= ' ' && *p)
- p++;
- if (!*p)
- CMDparsed = 17; /* not enuf args */
- while ('0' <= *p && *p <= '9') {
- gotone = 1;
- val = 10 * val + *p++ - '0';
- }
- if (gotone == 0 && CMDparsed == 0)
- CMDparsed = 47; /* invalid args; not a number */
- *where = p;
- return val;
- }
- /*
- * This function trys to find `n' numeric arguments in the command
- * string, and stuffs them into the CMDargs array.
- */
- void parseargs(char * p, long n);
- void parseargs(char * p, long n)
- {
- int i ;
-
- while (*p > ' ' && *p)
- p++ ;
- for (i=0; i<n && CMDparsed == 0; i++)
- CMDargs[i] = getnm(&p) ;
- }
-
-
- /*******************************************************************
- * List manipulation and directory scanning routines
- *******************************************************************/
-
- /*
- * This function takes a ScanListNode and deallocates it.
- * The node MUST be Remove()d before calling this.
- */
- void FreeNode(struct ScanListNode * node);
- void FreeNode(struct ScanListNode * node)
- {
- assert(node);
- assert(node->node.ln_Type == NT_FILENAME);
- if (node->node.ln_Name) freeFAM(node->node.ln_Name);
- if (node->filenote) freeFAM(node->filenote);
- if (node->contents) freeFAM(node->contents);
- freeFAM(node);
- }
-
- /*
- * This function allocates a new node, clearing out most of the fields.
- */
- struct ScanListNode * AllocNode(void);
- struct ScanListNode * AllocNode(void)
- {
- struct ScanListNode * node;
- node = mallocFAM(sizeof(struct ScanListNode));
- /* mallocFAM MUST clear the memory it gets */
- if (node != NULL)
- node->node.ln_Type = NT_FILENAME;
- return node;
- }
-
-
-
-
-
- /*
- * This function takes a file info block and a ScanListNode and
- * copies the information from the fib to the node. Only items
- * that have changed actually get reallocated. If NULL is passed in for
- * node, then node will be allocated. If NULL is returned, then
- * some memory allocation failed and THE NODE HAS BEEN FREED!
- * Hence, this node must NOT be in a list when FillInNode is called!
- */
-
- struct ScanListNode * FillInNode(struct FileInfoBlock * fib, struct ScanListNode * node);
- struct ScanListNode * FillInNode(struct FileInfoBlock * fib, struct ScanListNode * node)
- {
- long newdate, newtime;
- if (node == NULL) node = AllocNode();
- if (node == NULL) return NULL;
-
- assert(node->node.ln_Type == NT_FILENAME);
-
- if (node->node.ln_Name == NULL ||
- 0 != strcmp(node->node.ln_Name, fib->fib_FileName)) {
- if (node->node.ln_Name != NULL)
- freeFAM(node->node.ln_Name);
- node->node.ln_Name = strdupFAM(fib->fib_FileName);
- if (node->node.ln_Name == NULL) {
- FreeNode(node);
- return NULL;
- }
- }
-
- node->protection = fib->fib_Protection;
- node->isdir = 0 < fib->fib_DirEntryType;
- newdate = fib->fib_Date.ds_Days;
- newtime = (fib->fib_Date.ds_Minute * 60L) +
- (fib->fib_Date.ds_Tick / 50L);
- if (newtime != node->filetime || newdate != node->filedate) {
- /* assume line count didn't change if date didn't change */
- node->sizelines = -1L;
- }
- node->filedate = newdate;
- node->filetime = newtime;
- node->sizebytes = fib->fib_Size;
- node->isNewFile = node->isDeleted = node->isGrepped = 0;
-
- if (node->filenote == NULL ||
- 0 != strcmp(node->filenote, fib->fib_Comment)) {
- if (node->filenote != NULL) {
- freeFAM(node->filenote);
- node->filenote = NULL;
- }
- if (0 < strlen(fib->fib_Comment))
- node->filenote = strdupFAM(fib->fib_Comment);
- if (node->node.ln_Name == NULL) {
- FreeNode(node);
- return NULL;
- }
- }
-
- if (node->sizelines == -1L && BinExtens) {
- register unsigned long i;
- char * fext;
- /* First, check to see if it has an extension */
- fext = strchr(node->node.ln_Name, '.');
- if (fext && *fext) {
- /* we found an extension */
- /* brutally inefficient... */
- for (i = 0; i < strlen(BinExtens); i++) {
- if ( 0 == strncmp(fext, &BinExtens[i], strlen(fext)) &&
- (BinExtens[i+strlen(fext)] == '.' ||
- BinExtens[i+strlen(fext)] == '\0') ) {
- node->sizelines = -2L; /* It's a binary all right */
- break;
- }
- }
- }
- }
-
- if (node->sizelines == -1L && BinExtens) {
- char * buf;
- register char * pnt;
- register long len;
- register unsigned long i;
- long count;
-
- BPTR handle = Open(node->node.ln_Name, MODE_OLDFILE);
- if (handle == NULL) return node; /* could not count */
- buf = mallocFAM(10 + node->sizebytes);
- if (buf == NULL) {
- Close(handle);
- return node;
- }
- len = Read(handle, buf, node->sizebytes + 5);
- if (len != node->sizebytes) {
- freeFAM(buf);
- Close(handle);
- return node;
- }
-
- pnt = buf; count = 0;
- while (pnt = strchr(pnt, '\n')) {count += 1; pnt += 1;}
- node->sizelines = count;
-
- if (node->contents) {
- freeFAM(node->contents);
- node->contents = NULL;
- }
-
- if (BufEndLine) {
- /* first, toss old contents */
- if (node->contents) {
- freeFAM(node->contents);
- node->contents = NULL;
- }
- /* see if we can find BufEndLine in file */
- pnt = buf; len = strlen(BufEndLine);
- while (pnt && 0 != strncmp(BufEndLine, pnt, len)) {
- pnt = strchr(pnt, '\n');
- if (pnt) pnt++;
- }
- if (pnt) {
- /* we found BufEndLine -- move to contents */
- i = pnt - buf;
- node->contents = mallocFAM(i + 2);
- if (node->contents) {
- strncpy(node->contents, buf, i);
- node->contents[i] = '\0';
- }
- }
- }
-
- freeFAM(buf); Close(handle);
- }
-
- return node;
-
- }
-
- /*
- * This function empties the entire list given to it.
- */
- void FreeScanList(struct List * list);
- void FreeScanList(struct List * list)
- {
- struct ScanListNode * node;
- while (!(IsEmpty(*list))) {
- node = (struct ScanListNode *) RemHead(list);
- FreeNode(node);
- }
- }
-
-
- /* This is a secret communication path for optimization of RESCAN */
- static struct ScanListNode * InsAlphaPrev;
-
- /*
- * This function takes a ScanList and a string and finds the node
- * in the list that the string would follow if it were the name
- * of a node to be inserted alphabetically. Assumes the list is already
- * alphabetical.
- */
- struct ScanListNode * FindPrev(struct List * list, struct ScanListNode * node);
- struct ScanListNode * FindPrev(struct List * list, struct ScanListNode * node)
- {
- struct ScanListNode * index;
- char * name = node->node.ln_Name;
-
- if (IsEmpty(*list)) {
- return (struct ScanListNode *) list;
- }
-
- if (InsAlphaPrev && StrLT(InsAlphaPrev->node.ln_Name, name))
- index = InsAlphaPrev;
- else
- index = FirstNode(list);
-
- for ( ; NotLastNode(index); index = NextNode(index)) {
- if (StrLT(name, index->node.ln_Name)) {
- return (struct ScanListNode *) (index->node.ln_Pred);
- }
- }
-
- return (struct ScanListNode *) (&(list->lh_Tail));
- }
-
-
- /*
- * This function takes a node and a list and inserts the node in
- * the correct alphabetical place in the list. The node should not be part
- * of another list at the time.
- */
- void InsAlpha(struct List * list, struct ScanListNode * node);
- void InsAlpha(struct List * list, struct ScanListNode * node)
- {
- struct ScanListNode * prev;
- if (InsAlphaPrev == node) InsAlphaPrev = NULL;
- prev = FindPrev(list, node);
- Insert(list, (struct Node *) node, (struct Node *) prev);
- }
-
-
-
-
- /*******************************************************************
- * Here we have the actual command-handling code.
- *******************************************************************/
-
-
- /*
- * This handler returns the version of the program.
- */
- void FAMversion(struct RexxMsg *msg, char *p)
- {
- CMDuserreplied = 1 ;
- replyRexxCmd(msg, 0L, 0L, VersionString);
- }
-
-
- /*
- * This handler opens the device or file.
- */
- void FAMopen(struct RexxMsg *msg, char *p)
- {
- char buf[20];
-
- if (IsEmpty(ScanList)) {
- FAMrescan(msg, "");
- }
- if (IsEmpty(ScanList)) {
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- }
- else {
- OpenCount += 1;
- sprintf(buf, "%d", OpenCount);
- replyRexxCmd(msg, 0L, 0L, buf);
- CMDuserreplied = 1;
- }
- }
-
- /*
- * This handler closes the device or file.
- */
- void FAMclose(struct RexxMsg *msg, char *p)
- {
- char buf[20];
- while (*p <= ' ' && *p) p++;
- if (OpenCount == 0) {
- return;
- }
- if (0 == strcmp(p, "NOW") && 1 < OpenCount) {
- OpenCount = 1;
- }
- OpenCount -= 1;
- if (OpenCount == 0 && ClearWanted) {
- FreeScanList(&ScanList);
- FreeScanList(&TempScanList);
- ClearWanted = 0;
- }
- sprintf(buf, "%d", OpenCount);
- if (msg) {
- replyRexxCmd(msg, 0L, 0L, buf);
- CMDuserreplied = 1;
- }
- }
-
- /*
- * This handler sets the clear flag and possibly clears the ScanList.
- * It does not reply if msg is NULL, as we might call it from the
- * ASDG low memory handler.
- */
- void FAMclear(struct RexxMsg *msg, char *p)
- {
- char buf[20];
- if (IsEmpty(ScanList)) {
- return;
- }
- if (OpenCount == 0) {
- FreeScanList(&ScanList);
- FreeScanList(&TempScanList);
- }
- else {
- ClearWanted = 1;
- }
- if (msg) {
- sprintf(buf, "%d", OpenCount);
- replyRexxCmd(msg, 0L, 0L, buf);
- CMDuserreplied = 1;
- }
- }
-
- /*
- * This handler expunges the program.
- */
- void FAMexpunge(struct RexxMsg *msg, char *p)
- {
- ExpungeWanted = 1;
- ClearWanted = 1;
- while (*p <= ' ' && *p) p++;
- if (0 == strcmp(p, "NOW")) {
- if (OpenCount) FAMclose(msg, p);
- }
- }
-
- /*
- * This handler returns the most recent IO error number.
- */
- void FAMgetioerr(struct RexxMsg *msg, char *p)
- {
- long ans;
- char buf[20];
-
- ans = IoErr();
- sprintf(buf, "%ld", ans);
-
- replyRexxCmd(msg, 0L, 0L, buf); /* generally errored */
- CMDuserreplied = 1;
-
- }
-
- /*
- * This handler returns the directory path.
- */
- void FAMgetdirname(struct RexxMsg *msg, char *p)
- {
- CMDuserreplied = 1 ;
- replyRexxCmd(msg, 0L, 0L, DirPath);
- }
-
-
- /*
- * This handler returns the binary extensions.
- */
- void FAMgetbinextens(struct RexxMsg *msg, char *p)
- {
- CMDuserreplied = 1 ;
- if (BinExtens)
- replyRexxCmd(msg, 0L, 0L, BinExtens);
- else
- replyRexxCmd(msg, 1L, 0L, NULL);
- }
-
-
- /*
- * This handler returns the buffer end line.
- */
- void FAMgetbufendline(struct RexxMsg *msg, char *p)
- {
- CMDuserreplied = 1 ;
- if (BufEndLine)
- replyRexxCmd(msg, 0L, 0L, BufEndLine);
- else
- replyRexxCmd(msg, 1L, 0L, NULL);
- }
-
-
- /*
- * This handler returns the current count of names.
- */
- void FAMgetnamecount(struct RexxMsg *msg, char *p)
- {
- struct ScanListNode * node;
- long count;
- char buf[20];
-
- if (IsEmpty(ScanList)) {
- count = 0;
- }
- else {
- count = 1;
- for (node = FirstNode(&ScanList); NotLastNode(node);
- node = NextNode(node)) {
- count += 1;
- }
- }
- sprintf(buf, "%ld", count);
- replyRexxCmd(msg, 0L, 0L, buf);
- CMDuserreplied = 1;
- }
-
- /*
- * This handler returns the current list of names.
- */
- void FAMgetnames(struct RexxMsg *msg, char *p)
- {
- char * __stdargs ListNames(struct List *, char); /* in RexxGlue */
- void __stdargs DeleteArgstring(char * arg); /* in RexxGlue */
- char * result;
- char pad = ' ';
-
- while (*p <= ' ' && *p) p++;
- if (' ' < *p && *p <= 0x7F) pad = *p;
-
- if (0 == openRexxLib()) {
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- }
-
- result = ListNames(&ScanList, pad);
- if (result) {
- replyRexxCmd(msg, 0L, 0L, result);
- CMDuserreplied = 1;
- openRexxLib(); /* because replyRexxCmd closes it! */
- DeleteArgstring(result);
- }
- else {
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- }
-
- closeRexxLib();
-
- }
-
- /*
- * This handler returns the information for one file.
- */
- void FAMgetinfo(struct RexxMsg *msg, char *p)
- {
- static char protchars[33] = "DEWRAPSH"; /* allow room for patching */
- char buf[350];
- unsigned short len, i;
- char c;
- struct ScanListNode * node;
- char * argbuf;
-
- while (*p <= ' ' && *p) p++;
- if (!*p) {
- CMDparsed = 17;
- return;
- }
-
- node = (struct ScanListNode *) FindName(&ScanList, p);
- if (node == NULL) {
- CMDparsed = 18;
- return;
- }
-
- strcpy(buf, node->isdir ? "DIR -" : "FILE -");
- /* '-' starts protection bits */
-
- for (len = strlen(buf), i = 0; i < strlen(protchars); i++) {
- if (0 == (node->protection & (1 << i))) {
- buf[len++] = protchars[i];
- }
- }
-
- c = '-';
- if (node->isLocked) c = 'L';
- if (node->isNewFile) c = 'N';
-
- sprintf(&buf[len], " %ld %ld %ld %ld %c ",
- node->sizebytes, node->sizelines,
- node->filedate, node->filetime, c);
-
- strcat(buf, node->node.ln_Name);
- strcat(buf, " ");
- if (node->filenote)
- strcat(buf, node->filenote);
-
- if (sizeof(buf) <= strlen(buf)) exit(250);
-
- if (node->contents) {
- argbuf = mallocFAM(strlen(node->contents)+strlen(buf)+5);
- if (argbuf) {
- strcpy(argbuf, buf);
- strcat(argbuf, "\n");
- strcat(argbuf, node->contents);
- replyRexxCmd(msg, 0L, 0L, argbuf);
- CMDuserreplied = 1;
- freeFAM(argbuf);
- }
- else {
- replyRexxCmd(msg, 0L, 0L, buf);
- CMDuserreplied = 1;
- }
- }
- else {
- replyRexxCmd(msg, 0L, 0L, buf);
- CMDuserreplied = 1;
- }
- }
-
- /*
- * This handler reconstructs the information for one file.
- */
- void FAMrescan1(struct RexxMsg *msg, char *p)
- {
- struct ScanListNode * node;
- struct FileInfoBlock * fib = malloc(sizeof(struct FileInfoBlock));
- BPTR lock;
- char buf[20];
-
- while (*p <= ' ' && *p) p++;
- if (*p == 0 || fib == NULL) {
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- return;
- }
-
- lock = Lock(p, SHARED_LOCK);
- if (!lock) {
- free(fib);
- node = (struct ScanListNode *) FindName(&ScanList, p);
- if (node) {
- Remove((struct Node *) node);
- FreeNode(node);
- }
- sprintf(buf, "%ld", IoErr());
- replyRexxCmd(msg, 0L, 0L, buf);
- CMDuserreplied = 1;
- return;
- }
-
- if (!Examine(lock, fib)) {
- sprintf(buf, "%ld", IoErr());
- replyRexxCmd(msg, 0L, 0L, buf);
- CMDuserreplied = 1;
- free(fib);
- UnLock(lock);
- return;
- }
-
- UnLock(lock);
-
- node = (struct ScanListNode *) FindName(&ScanList, p);
- if (node) {
- Remove((struct Node *) node);
- }
-
- node = FillInNode(fib, node);
- if (node == NULL) {
- free(fib);
- sprintf(buf, "%ld", IoErr());
- replyRexxCmd(msg, 0L, 0L, buf);
- CMDuserreplied = 1;
- return;
- }
-
- InsAlpha(&ScanList, node);
-
- sprintf(buf, "%ld", IoErr());
- replyRexxCmd(msg, 0L, 0L, buf);
- CMDuserreplied = 1;
- }
-
- /*
- * This handler reconstructs the information for all files.
- */
- void FAMrescan(struct RexxMsg *msg, char *p)
- {
- /* right now, the argument is ignored */
-
- struct ScanListNode * node, * next;
- struct FileInfoBlock * fib = malloc(sizeof(struct FileInfoBlock));
- BPTR lock;
-
- #ifdef DEBUG
- long c1 = 0, c2 = 0, c3 = 0; /* performance measurement */
- #endif
-
- while (*p <= ' ' && *p) p++;
- if (fib == NULL) {
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- return;
- }
-
- lock = Lock("", SHARED_LOCK); /* always works on current dir for now */
- if (!lock) {
- free(fib);
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- return;
- }
-
- if (!Examine(lock, fib)) {
- free(fib);
- UnLock(lock);
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- return;
- }
-
- /* delete all files except NEWFILE files */
- for (node = FirstNode(&ScanList); NotLastNode(node); node = NextNode(node)) {
- if (!node->isNewFile)
- node->isDeleted = 1; /* set it to deleted */
- }
-
- while (ExNext(lock, fib)) {
- node = (struct ScanListNode *) FindName(&ScanList, fib->fib_FileName);
- if (node != NULL && !node->isNewFile)
- Remove((struct Node *) node);
- if (node == NULL || !node->isNewFile)
- node = FillInNode(fib, node);
- if (node == NULL) {
- free(fib);
- UnLock(lock);
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- return;
- }
- else {
- /* see if we know where to put it already */
- if ( !IsEmpty(ScanList) &&
- StrLT(ScanList.lh_TailPred->ln_Name,
- node->node.ln_Name) ) {
- AddTail(&ScanList, (struct Node *) node);
- InsAlphaPrev = node;
- #ifdef DEBUG
- c1 += 1;
- #endif
- }
- else if(node->node.ln_Pred && /* has pred *
- node->node.ln_Succ && /* has succ */
- node->node.ln_Pred->ln_Pred && /* not at start */
- node->node.ln_Succ->ln_Succ && /* not at end */
- StrLT(node->node.ln_Pred->ln_Name, /* after pred */
- node->node.ln_Name) &&
- StrLT(node->node.ln_Name, /* before succ */
- node->node.ln_Succ->ln_Name) ) {
- InsertQ((struct Node *) node);
- InsAlphaPrev = node;
- #ifdef DEBUG
- c2 += 1;
- #endif
- }
- else {
- InsAlpha(&ScanList, node);
- InsAlphaPrev = node;
- #ifdef DEBUG
- c3 += 1;
- #endif
- }
- }
- }
-
- UnLock(lock); /* make FileSystem designers happy */
- InsAlphaPrev = NULL;
-
- for (node = FirstNode(&ScanList); NotLastNode(node); ) {
- assert(node && node->node.ln_Type == NT_FILENAME);
- if (node->isDeleted) {
- /* We never saw this node during the rescan! */
- next = NextNode(node);
- if (next != NULL) {
- Remove((struct Node *) node);
- FreeNode(node);
- }
- node = next;
- }
- else {
- node = NextNode(node);
- }
- }
- }
-
- /*
- * This handler matches general user information.
- */
- void FAMgrep(struct RexxMsg *msg, char *p)
- {
- struct ScanListNode * node;
- long count = 0;
- char * buf;
- char pad[2] = " ";
-
- if (' ' < *p && *p <= 0x7F)
- pad[0] = *p++;
-
- while (*p <= ' ' && *p) p++;
-
- if (GrepEntry == NULL) {
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- return;
- }
-
- for (node = FirstNode(&ScanList); NotLastNode(node); node = NextNode(node)) {
- node->isGrepped = 0;
- if ((*(GrepFunc *)(GrepEntry<<2L))(node, p)) {
- node->isGrepped = 1;
- count += strlen(node->node.ln_Name) + 1;
- }
- }
-
- if (count == 0) {
- replyRexxCmd(msg, 0L, 0L, "");
- CMDuserreplied = 1;
- return;
- }
-
- buf = mallocFAM(count + 4);
- if (buf == NULL) {
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- return;
- }
-
- buf[0] = '\0';
- for (node = FirstNode(&ScanList); NotLastNode(node); node = NextNode(node)) {
- if (node->isGrepped) {
- strcat(buf, pad);
- strcat(buf, node->node.ln_Name);
- node->isGrepped = 0;
- }
- }
-
- replyRexxCmd(msg, 0L, 0L, &buf[1]); /* skip initial pad */
- CMDuserreplied = 1;
- freeFAM(buf);
-
- }
-
- /*
- * This handler generates a new pseudo-file.
- */
- void FAMnewfile(struct RexxMsg *msg, char *p)
- {
- struct ScanListNode * node;
- long num, len;
- short full;
- short base;
- char * basepnt;
- char * name, * cp;
- char buf[80];
- extern long __stdargs CVa2i(char *, long *); /* in RexxGlue.a */
- extern void __stdargs CVi2az(char *, long, long); /* in RexxGlue.a */
-
- if (p[0] == '3' && p[1] == '6') {
- base = 36;
- p += 2;
- basepnt = "0123456789ABCDEFGHIJLMNOPQRSTUVWXYZ";
- }
- else {
- /* assume base 10 */
- if (p[0] == '1' && p[1] == '0') p += 2;
- basepnt = "0123456789";
- base = 10;
- }
-
- while (*p <= ' ' && *p) p++;
-
- if (IsEmpty(ScanList) || !*p) {
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- return;
- }
-
- for (node = FirstNode(&ScanList); NotLastNode(node); node = NextNode(node)) {
- if (0 == strncmp(p, node->node.ln_Name, strlen(p))) {
- break;
- }
- }
- if (node == NULL) {
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- return;
- }
-
- for ( ; NotLastNode(node); node = NextNode(node)) {
- if (0 != strncmp(p, node->node.ln_Name, strlen(p))) {
- break;
- }
- }
- node = (struct ScanListNode *) node->node.ln_Pred;
-
- /* at this point, 'node' points to the node our's should follow */
-
- name = node->node.ln_Name;
- if (0 != strncmp(p, name, strlen(p))) {
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- return;
- }
-
- node = AllocNode();
-
- if (0 == openRexxLib() || node == NULL) {
- if (node) FreeNode(node);
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- return;
- }
-
- for ( cp = name + strlen(p), len = 0, num = 0, full = 1;
- isdigit(*cp);
- cp++, len++) {
- full = full && *cp == '9';
- num = num * 10 + *cp - '0';
- }
-
- if (full) {
- FreeNode(node);
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- return;
- }
-
- strcpy(buf, p);
- CVi2az(&buf[strlen(p)], num + 1, len);
-
- node->node.ln_Name = strdupFAM(buf);
- if (node->node.ln_Name == NULL) {
- FreeNode(node);
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- return;
- }
-
- node->isNewFile = 1; /* it's a NEWFILE file */
-
- InsAlpha(&ScanList, node);
-
- replyRexxCmd(msg, 0L, 0L, node->node.ln_Name);
- CMDuserreplied = 1;
-
- }
-
- /*
- * This handler locks or unlocks a file.
- */
- void FAMlockfile(struct RexxMsg *msg, char *p)
- {
- struct ScanListNode * node;
- char old = 0, new = 0;
- int good = 1;
-
- while (*p <= ' ' && *p) p++;
- if (*p) old = *p++;
-
- while (*p <= ' ' && *p) p++;
- if (*p) new = *p++;
-
- while (*p <= ' ' && *p) p++;
-
- if (old != '-' && old != 'L') old = 0;
- if (new != '-' && new != 'L') new = 0;
-
- if (IsEmpty(ScanList) || !*p || old == 0 || new == 0) {
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- return;
- }
-
- for (node = FirstNode(&ScanList); NotLastNode(node); node = NextNode(node)) {
- if (0 == strcmp(p, node->node.ln_Name)) {
- break;
- }
- }
- if (node == NULL) {
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- return;
- }
-
- good = good && (node->isNewFile == 0); /* can't lock NewFiles */
- good = good && ((old == 'L') == node->isLocked);
- if (good) {
- node->isLocked = (new == 'L');
- }
- else {
- replyRexxCmd(msg, ERRLEVEL, 0L, NULL);
- CMDuserreplied = 1;
- return;
- }
-
- }
-
-
-