home *** CD-ROM | disk | FTP | other *** search
- /* --------------------------------- -------
- * |\ | | | | | |.| | \| |/ /|\ |||||||
- * | | | |/ | |\ |/ |/| |\ |/ | ? ---+--- =<
- * | | | | | | | | | | | \qqqqqqqqq/
- * --------------------------------- ~~~~~~~~~~~~~~~~
- * SCD - Smart CD
- * Copyright (C) 1993 Torsten Poulin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * The author can be contacted by s-mail at
- * Torsten Poulin
- * Banebrinken 99, 2, 77
- * DK-2400 Copenhagen NV
- * DENMARK
- *
- * $Id: SCD.c,v 37.4 93/04/28 15:11:53 Torsten Exp $
- * $Log: SCD.c,v $
- * Revision 37.4 93/04/28 15:11:53 Torsten
- * Memory leak plugged.
- *
- * Revision 37.3 93/04/14 19:01:02 Torsten
- * Allows SCDCOMMAND to be an empty string (implicit CD).
- * Adjusted the size of the ListView gadget to avoid having its
- * label overlap the other gadgets on a lores screen.
- *
- * Revision 37.2 93/04/14 10:58:16 Torsten
- * Default place to look for table changed to ENV:SCD/Table
- * to comply with the `User Interface Style Guide'.
- * If the local or global environment variable SCDCOMMAND is
- * set, SCD will queue its value (with ACTION_QUEUE) instead
- * of using CurrentDir() and SetCurrentDirName() to circumvent
- * a problem with WShell.
- *
- * Revision 37.1 93/04/12 23:18:42 Torsten
- * Initial revision
- *
- */
-
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <exec/lists.h>
- #include <exec/nodes.h>
- #include <dos/dos.h>
- #include <dos/dosasl.h>
- #include <dos/var.h>
- #include <intuition/intuition.h>
- #include <intuition/screens.h>
- #include <intuition/gadgetclass.h>
- #include <libraries/gadtools.h>
- #include <rexx/rexxio.h>
-
- #include <clib/dos_protos.h>
- #include <clib/exec_protos.h>
- #include <clib/utility_protos.h>
- #include <clib/gadtools_protos.h>
- #include <clib/intuition_protos.h>
- #include <clib/graphics_protos.h>
- #ifdef __SASC
- #include <pragmas/dos_pragmas.h>
- #include <pragmas/exec_pragmas.h>
- #include <pragmas/utility_pragmas.h>
- #include <pragmas/gadtools_pragmas.h>
- #include <pragmas/intuition_pragmas.h>
- #include <pragmas/graphics_pragmas.h>
- #endif
- #include <string.h>
- #include "tastlib.h"
- #include "scd_rev.h"
-
-
- #define PROGNAME "SCD"
- #define TABNAME "SCDTABLE"
- #define DEFNAME "ENV:SCD/Table"
- #define CDNAME "SCDCOMMAND"
- #define COPYRIGHT "Copyright © 1993 Torsten Poulin"
- #define TEMPLATE "DIR/A"
- #define OPT_DIR 0
-
- typedef struct {
- struct DosLibrary *DOSBase;
- struct Library *UtilityBase;
- struct Library *GadToolsBase;
- struct Library *IntuitionBase;
- struct Library *GfxBase;
- struct FileInfoBlock fib;
- struct List *list;
- UBYTE buf[MAXNAMELEN+1];
- UBYTE pattern[(MAXNAMELEN+1)*2];
- } Global;
-
- typedef struct {
- struct Node nn_Node;
- UBYTE nn_filename[MAXNAMELEN+1];
- } NameNode;
-
-
- LONG initlist(Global *global);
- VOID freelist(Global *global);
- LONG insert(UBYTE *filename, Global *global);
- LONG SCD(UBYTE *, Global *);
- LONG namereq(LONG *, Global *);
- VOID handleevents(struct Window *, LONG *, struct Gadget *g[], Global *);
- LONG changedir(LONG, Global *);
- LONG queuecommand(UBYTE *cmd, UBYTE *arg, Global *);
-
- struct TextAttr Topaz80 = { "topaz.font", 8, 0, 0 };
- char const versionID[] = VERSTAG;
- char const copyright[] = "$COPYRIGHT:" COPYRIGHT "$";
-
- LONG entrypoint(VOID)
- {
- struct DosLibrary *DOSBase;
- struct RDArgs *args;
- Global *global;
- LONG arg[1];
- LONG rc = RETURN_OK;
-
- if (!(DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37L)))
- return RETURN_FAIL;
-
- if (!(global = AllocVec(sizeof(Global), MEMF_CLEAR)))
- {
- PrintFault(ERROR_NO_FREE_STORE, PROGNAME);
- rc = RETURN_FAIL;
- }
- else
- {
- global->DOSBase = DOSBase;
- if (!(global->UtilityBase = OpenLibrary("utility.library", 37L)))
- rc = RETURN_FAIL;
- else
- {
- if (!(global->IntuitionBase = OpenLibrary("intuition.library", 37L)))
- rc = RETURN_FAIL;
- else
- {
- if (!(global->GadToolsBase = OpenLibrary("gadtools.library", 37L)))
- rc = RETURN_FAIL;
- else
- {
- if (!(global->GfxBase = OpenLibrary("graphics.library", 37L)))
- rc = RETURN_FAIL;
- else
- {
- arg[OPT_DIR] = 0L;
-
- if (!(args = ReadArgs(TEMPLATE, arg, NULL)))
- {
- printerror(PROGNAME, global);
- rc = RETURN_ERROR;
- }
- else
- {
- rc = SCD((UBYTE *) arg[OPT_DIR], global);
- FreeArgs(args);
-
- if (rc == ERROR_BREAK)
- {
- PrintFault(ERROR_BREAK, NULL);
- rc = RETURN_WARN;
- }
- else if (rc == ERROR_NO_FREE_STORE)
- {
- PrintFault(ERROR_NO_FREE_STORE, PROGNAME);
- rc = RETURN_FAIL;
- }
- else if (rc != RETURN_OK)
- printerror(PROGNAME, global);
- }
- CloseLibrary(global->GfxBase);
- }
- CloseLibrary(global->GadToolsBase);
- }
- CloseLibrary(global->IntuitionBase);
- }
- CloseLibrary(global->UtilityBase);
- }
- FreeVec(global);
- }
- CloseLibrary((struct Library *) DOSBase);
- return rc;
- }
-
-
- LONG initlist(Global *global)
- {
- if (!(global->list = AllocVec(sizeof(struct List), MEMF_CLEAR)))
- return ERROR_NO_FREE_STORE;
- /* Initialize list header */
- global->list->lh_Head = (struct Node *) &global->list->lh_Tail;
- global->list->lh_Tail = 0;
- global->list->lh_TailPred = (struct Node *) &global->list->lh_Head;
- return RETURN_OK;
- }
-
-
- VOID freelist(Global *global)
- {
- NameNode *worknode;
- NameNode *nextnode;
-
- worknode = (NameNode *) (global->list->lh_Head);
- while (nextnode = (NameNode *) (worknode->nn_Node.ln_Succ))
- {
- FreeVec(worknode);
- worknode = nextnode;
- }
- FreeVec(global->list);
- }
-
-
- LONG insert(UBYTE *filename, Global *global)
- {
- struct Library *UtilityBase = global->UtilityBase;
- NameNode *namenode;
- struct Node *node;
-
- if (!(namenode = AllocVec(sizeof(NameNode), MEMF_CLEAR)))
- return ERROR_NO_FREE_STORE;
- else
- {
- strcpy(namenode->nn_filename, filename);
- namenode->nn_Node.ln_Name = namenode->nn_filename;
-
- if (global->list->lh_TailPred == (struct Node *) global->list)
- AddHead(global->list, (struct Node *) namenode);
- else
- {
- for (node=global->list->lh_Head; node->ln_Succ; node=node->ln_Succ)
- if (Stricmp(node->ln_Name, filename) >= 0)
- break;
- if (node->ln_Succ)
- Insert(global->list, (struct Node *) namenode, node->ln_Pred);
- else
- AddTail(global->list, (struct Node *) namenode);
- }
-
- return RETURN_OK;
- }
- }
-
-
- LONG SCD(UBYTE *dir, Global *global)
- {
- struct DosLibrary *DOSBase = global->DOSBase;
- LONG number = 0;
- LONG rc = RETURN_OK;
- LONG len;
- UBYTE *lastpart;
- BPTR table;
-
- if (ParsePatternNoCase(dir, global->pattern, strlen(dir)*2+2) < 0)
- return RETURN_FAIL;
-
- if (GetVar(TABNAME, global->buf, MAXNAMELEN, 0) < 0)
- strcpy(global->buf, DEFNAME);
-
- if (!(table = Open(global->buf, MODE_OLDFILE)))
- {
- PrintFault(IoErr(), global->buf);
- return RETURN_FAIL;
- }
-
- if ((rc = initlist(global)) != ERROR_NO_FREE_STORE)
- {
- while (FGets(table, global->buf, MAXNAMELEN+1))
- {
- /* remove newline character */
- len = strlen(global->buf);
- if (len > 0 && global->buf[--len] == '\n')
- global->buf[len] = '\0';
-
- lastpart = FilePart(global->buf);
- if (MatchPatternNoCase(global->pattern, lastpart))
- {
- number++;
- rc = insert(global->buf, global);
- }
- }
-
- if (!rc)
- {
- --number;
- if (number == 0)
- rc = changedir(number, global);
- else if (number > 0)
- {
- rc = namereq(&number, global);
- if (number >= 0)
- rc = changedir(number, global);
- }
- else
- {
- MyPrintf(global, "Can't find %s\n", dir);
- rc = RETURN_FAIL;
- }
- }
- freelist(global);
- }
- Close(table);
- return rc;
- }
-
-
- /*
- * The following three functions exist because we need global
- * library bases to call the amiga.lib versions and I
- * don't want the bother of building the taglists.
- */
-
- struct Gadget *MyCreateGadget(Global *global,
- ULONG kind,
- struct Gadget *gad,
- struct NewGadget *ng,
- Tag tag1, ...)
- {
- struct Library *GadToolsBase = global->GadToolsBase;
- return CreateGadgetA(kind, gad, ng, (struct TagItem *) &tag1);
- }
-
-
- struct Window *MyOpenWindowTags(Global *global,
- struct NewWindow *newWindow,
- Tag tag1, ...)
- {
- struct Library *IntuitionBase = global->IntuitionBase;
- return OpenWindowTagList(newWindow, (struct TagItem *) &tag1);
- }
-
-
- struct Screen *MyOpenScreenTags(Global *global,
- struct NewScreen *newScr,
- Tag tag1, ...)
- {
- struct Library *IntuitionBase = global->IntuitionBase;
- return OpenScreenTagList(newScr, (struct TagItem *) &tag1);
- }
-
-
- LONG namereq(LONG *number, Global *global)
- {
- struct Library *IntuitionBase = global->IntuitionBase;
- struct Library *GadToolsBase = global->GadToolsBase;
- struct Library *GfxBase = global->GfxBase;
- struct DrawInfo *drawinfo;
- struct Screen *pubscreen;
- struct Screen *screen;
- struct Window *window;
- struct Gadget *glist, *gad;
- struct Gadget *gadgets[3];
- struct NewGadget ng;
- ULONG modeID;
- APTR vi;
-
- glist = NULL;
- if (pubscreen = LockPubScreen(NULL))
- {
- if (drawinfo = GetScreenDrawInfo(pubscreen))
- {
- if ((modeID = GetVPModeID(&(pubscreen->ViewPort))) != INVALID_ID)
- {
- if (screen = MyOpenScreenTags(global, NULL,
- SA_Pens, (ULONG) (drawinfo->dri_Pens),
- SA_Depth, drawinfo->dri_Depth,
- SA_Height, STDSCREENHEIGHT,
- SA_Width, STDSCREENWIDTH,
- SA_DisplayID, modeID,
- SA_Title, VERS " - " COPYRIGHT,
- SA_Font, &Topaz80,
- TAG_END))
- {
- if (vi = GetVisualInfoA(screen, NULL))
- {
- gad = CreateContext(&glist);
-
- /* ListView gadget */
- ng.ng_TextAttr = &Topaz80;
- ng.ng_VisualInfo = vi;
- ng.ng_LeftEdge = screen->WBorLeft + 2;
- ng.ng_TopEdge = screen->WBorTop + 1;
- ng.ng_Width = screen->Width - (screen->WBorLeft
- + screen->WBorRight + 4);
- ng.ng_Height = (screen->Height
- - ng.ng_TopEdge
- - (screen->Font->ta_YSize + 1)
- - 30);
- ng.ng_GadgetText = "_Select directory";
- ng.ng_GadgetID = 0;
- ng.ng_Flags = PLACETEXT_BELOW;
-
- gadgets[0] = gad = MyCreateGadget(global,
- LISTVIEW_KIND, gad, &ng,
- GTLV_Labels, global->list,
- GTLV_ShowSelected, NULL,
- GTLV_Selected, 0,
- GT_Underscore, '_',
- TAG_END);
-
- ng.ng_Height = screen->Font->ta_YSize + 4;
- ng.ng_Width = 100;
- ng.ng_LeftEdge += INTERWIDTH;
- ng.ng_TopEdge = (screen->Height
- - (screen->WBorTop+(screen->Font->ta_YSize+1))
- - screen->WBorBottom
- - ng.ng_Height
- - INTERHEIGHT);
- ng.ng_GadgetText = "Change _dir";
- ng.ng_Flags = PLACETEXT_IN;
- ng.ng_GadgetID = 1;
- gadgets[1] = gad = MyCreateGadget(global,
- BUTTON_KIND, gad, &ng,
- GT_Underscore, '_',
- TAG_END);
-
- ng.ng_LeftEdge = (screen->Width
- - screen->WBorLeft - screen->WBorRight - 1
- - ng.ng_Width
- - INTERWIDTH);
- ng.ng_GadgetText = "_Cancel";
- ng.ng_GadgetID = 2;
- gadgets[2] = gad = MyCreateGadget(global,
- BUTTON_KIND, gad, &ng,
- GT_Underscore, '_',
- TAG_END);
-
- if (gad)
- {
- if (window = MyOpenWindowTags(global, NULL,
- WA_Gadgets, glist,
- WA_Width, screen->Width,
- WA_Height,
- (screen->Height
- - (screen->WBorTop
- + (screen->Font->ta_YSize
- + 1))),
- WA_RMBTrap, TRUE,
- WA_SimpleRefresh, TRUE,
- WA_Activate, TRUE,
- WA_Backdrop, TRUE,
- WA_IDCMP, IDCMP_REFRESHWINDOW
- | IDCMP_VANILLAKEY
- | LISTVIEWIDCMP
- | BUTTONIDCMP,
- WA_CustomScreen, screen,
- TAG_END))
- {
- GT_RefreshWindow(window, NULL);
- handleevents(window, number, gadgets, global);
- CloseWindow(window);
- }
- }
- FreeGadgets(glist);
- FreeVisualInfo(vi);
- }
- CloseScreen(screen);
- }
- }
- FreeScreenDrawInfo(pubscreen, drawinfo);
- }
- UnlockPubScreen(NULL, pubscreen);
- }
- return RETURN_OK;
- }
-
-
- VOID handleevents(struct Window *window,
- LONG *number,
- struct Gadget *gadgets[],
- Global *global)
- {
- struct Library *GadToolsBase = global->GadToolsBase;
- struct IntuiMessage *imsg;
- struct Gadget *gad;
- struct TagItem lvtags[3];
- LONG n = 0;
- BOOL done = FALSE;
-
- lvtags[0].ti_Tag = GTLV_Selected;
- lvtags[1].ti_Tag = GTLV_Top;
- lvtags[2].ti_Tag = TAG_END;
- lvtags[2].ti_Data = NULL;
-
- while (!done)
- {
- Wait(1 << window->UserPort->mp_SigBit);
-
- while (!done && (imsg = GT_GetIMsg(window->UserPort)))
- {
- switch (imsg->Class)
- {
- case IDCMP_GADGETUP:
- gad = (struct Gadget *) imsg->IAddress;
- switch (gad->GadgetID)
- {
- case 0: n = imsg->Code; break;
- case 1: *number = n; done = TRUE; break;
- case 2: *number = -1; done = TRUE; break;
- }
- break;
- case IDCMP_VANILLAKEY:
- switch (imsg->Code)
- {
- case 'D':
- case 'd': *number = n; done = TRUE; break;
- case 'C':
- case 'c': *number = -1; done = TRUE; break;
- case 'S':
- if (--n < 0)
- n = 0;
- lvtags[0].ti_Data = lvtags[1].ti_Data = (UWORD) n;
- GT_SetGadgetAttrsA(gadgets[0], window, NULL, lvtags);
- break;
- case 's':
- if (++n > *number)
- n = *number;
- lvtags[0].ti_Data = lvtags[1].ti_Data = (UWORD) n;
- GT_SetGadgetAttrsA(gadgets[0], window, NULL, lvtags);
- break;
- }
- break;
- case IDCMP_REFRESHWINDOW:
- GT_BeginRefresh(window);
- GT_EndRefresh(window, TRUE);
- break;
- }
- GT_ReplyIMsg(imsg);
- }
- }
- }
-
-
- LONG changedir(LONG number, Global *global)
- {
- struct DosLibrary *DOSBase = global->DOSBase;
- struct Node *node;
- LONG rc = RETURN_OK;
- LONG n = 0;
- BPTR lock;
-
- for (node=global->list->lh_Head; node->ln_Succ; node=node->ln_Succ, n++)
- if (n == number)
- break;
-
- if (lock = Lock(node->ln_Name, SHARED_LOCK))
- {
- if (Examine(lock, &global->fib)
- && global->fib.fib_DirEntryType > 0
- && global->fib.fib_DirEntryType != ST_SOFTLINK)
- {
- if (GetVar(CDNAME, global->buf, MAXNAMELEN, 0) >= 0)
- rc = queuecommand(global->buf, node->ln_Name, global);
- else
- {
- lock = CurrentDir(lock);
- SetCurrentDirName(node->ln_Name);
- }
- }
- else
- rc = RETURN_ERROR;
- UnLock(lock);
- }
- else
- rc = RETURN_ERROR;
- return rc;
- }
-
-
- /*
- * Send ACTION_QUEUE packet to the handler associated with stdin.
- * The method was learned by `reverse engineering' the QUEUE command
- * shipped with the ConMan 1.3 console handler.
- * Information kindly provided by Kristian Nielsen (bombadil@diku.dk)
- * (and ultimately Bill Hawes, author of ARexx, ConMan, and WShell :-) ).
- */
-
- LONG queuecommand(UBYTE *cmd, UBYTE *arg, Global *global)
- {
- struct DosLibrary *DOSBase = global->DOSBase;
- struct FileHandle *console_fh;
- struct MsgPort *destport;
- struct MsgPort *port;
- struct Process *process;
- UBYTE *line;
- LONG line_len;
- BPTR console_fh_bptr;
- LONG rc = RETURN_OK;
-
- /* Add 1 for space, 2 for quotes, 1 for '\n', and 1 for '\0' */
- line_len = strlen(cmd) + strlen(arg) + 5;
- if (!(line = AllocVec(line_len, 0L)))
- return ERROR_NO_FREE_STORE;
-
- /* Build command line */
- strcpy(line, cmd);
- strcat(line," \"");
- strcat(line, arg);
- strcat(line, "\"\n");
-
- /* Get process and process msgport. */
- process = (struct Process *) FindTask(NULL);
- port = &process->pr_MsgPort;
-
- /*
- * ACTION_QUEUE works like ACTION_READ and ACTION_WRITE.
- * It takes three args: The fh_Arg1 field of the file handle
- * (NOT the file handle itself), the start of the data to queue, and
- * the number of bytes to queue.
- *
- * Since we need a file handle, we cannot just call GetConsoleTask().
- * The ConMan command 'queue' uses the pr_CIS field of the process
- * structure. We simply use Input().
- */
-
- console_fh_bptr = Input(); /* Could use process->pr_CIS */
- if (!console_fh_bptr)
- {
- MyPrintf(global, "%s: Cannot queue %s\n", PROGNAME, line);
- rc = RETURN_FAIL;
- }
- else
- {
- console_fh = BADDR(console_fh_bptr); /* Convert to C pointer. */
- if (!console_fh->fh_Type)
- {
- MyPrintf(global,
- "%s: Input stream not associated with handler process\n",
- PROGNAME);
- rc = RETURN_FAIL;
- }
- else
- {
- destport = console_fh->fh_Type;
- DoPkt(destport, ACTION_QUEUE, console_fh->fh_Arg1,
- (LONG) line, line_len, 0L, 0L);
- }
- }
- FreeVec(line);
- return rc;
- }
-