[comp.sources.amiga] v89i050: flist - scrollable cli and directory lister v1.2, Part02/03

page@swan.ulowell.edu (Bob Page) (03/16/89)

Submitted-by: alliant!mistress!berry (Steve -Raz- Berry)
Posting-number: Volume 89, Issue 50
Archive-name: workbench/flist12.2

#	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
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	menu.c
#	parse.c
#	pathname.c
#	readme
#	rexxglue.asm
#	rexxport.c
# This archive created: Wed Mar 15 12:12:37 1989
cat << \SHAR_EOF > menu.c
/**************************************************************************
*     M E N U   E X A M P L E    P R O G R A M   -   JOHN DRAPER
*   (originally it was anyway)
*
*  Modified (mangled) by Steve Berry 7/77/88
*
***************************************************************************/

#include <libraries/arpbase.h>
#include "flist.h"

void *OpenLibrary();
struct Window *OpenWindow();
struct IntuiMessage *GetMsg();
struct Window *BuildSysRequest();
extern void Cleanup(),scrprt(),getkey();
extern struct Gadget pg;
extern struct Window *winptr;

extern struct IntuiText TRUEtext;
extern struct Window *winptr;
extern struct Screen *scrptr;
extern struct RastPort *rp;
extern struct FileLock *lock, olddir;
extern long line, numfiles, collum, first;
extern char (*fname[MAXDIR])[FCHARS];
extern char (*finfo[MAXDIR])[4];
extern char conline[256];
long top;

/***************************************************************************
                     M E N U      D E F I N I T I O N S
***************************************************************************/

#define NUM_MENUS 3

/* Copies of this structure will get "stamped" into many more */
/* Allocated later */

struct IntuiText generic = {
  0, 1,                        /* Bluepen, Whitepen */
  JAM2, 5,                     /* mode,  LeftEdge */
  0, NL,                       /* Top (to be filled later), Font */
  NL,                          /* Name (to be filled later) */
  NL                           /* Next one */
};

/* Menu numbers */

#define PROJ_MENU 0
#define DIR_MENU  1
#define SORT_MENU 2

/* Menu Widths */

#define FIL_WIDTH   80
#define DIR_WIDTH   100
#define SORT_WIDTH  120
#define ITEM_WIDTH  150
#define REQ_WIDTH   100

int item_widths[ NUM_MENUS ] = {150,250,150};

/* All items in these menus has the following flags set */

#define BOX_FILL    ITEMTEXT | ITEMENABLED | HIGHBOX     
#define BLACK_FILL  COMMSEQ | ITEMTEXT | ITEMENABLED | HIGHCOMP
#define HAS_CHECKS  COMMSEQ | ITEMTEXT | ITEMENABLED | HIGHCOMP | CHECKIT

                            /** FILE MENU ITEMS  **/
#define NUM_FILE_ITEMS  4
#define DO_ITEM         0
#define ICON_ITEM       1
#define ABOUT_ITEM      2
#define QUIT_ITEM       3

struct MenuItem  file_items[NUM_FILE_ITEMS];
struct IntuiText file_names[NUM_FILE_ITEMS];

char  *filemenu_names[] = {
   "Execute REXX",
   "Iconify",
   "About",
   "Quit"
};

char *filemenu_short[] = {
    "E",
    "I",
    "B",
    "Q"
};

struct Menu fmenu = {
  NL,                        /* Pointer to next menu, fill in later */
  0, 0, FIL_WIDTH, 10,       /* LeftEdge, TopEdge, Width, Height */
  MENUENABLED,               /* FLAGS */
  "Project",                 /* Menu name */
  NL                         /* First item structure */
};

/************ Next menu ****************/

                            /** FILE MENU ITEMS  **/
#define NUM_DIR_ITEMS   7
#define PARENT_ITEM     0
#define CHANGE_ITEM     1
#define ARP_ITEM        2
#define REGET_ITEM      3
#define KILL_ITEM       4
#define RENAME_ITEM     5
#define MAKEDIR_ITEM    6

struct MenuItem  dir_items[NUM_DIR_ITEMS];
struct IntuiText dir_names[NUM_DIR_ITEMS];

char  *dirmenu_names[] = {
    "  Parent Directory",
    "  Change Directory",
    "  ARP Change to Volume",
    "  Get Directory",
    "  Kill File",
    "  Rename File",
    "  Make Dir"
};

char *dirmenu_short[] = {
    "P",
    "D",
    "A",
    "G",
    "K",
    "R",
    "N"
};

struct Menu dmenu = {
  NL,                        /* Pointer to next menu, fill in later */
  100, 0, DIR_WIDTH, 10,     /* LeftEdge, TopEdge, Width, Height */
  MENUENABLED,               /* FLAGS */
  "Directory",               /* Menu name */
  NL                         /* First item structure */
};

/************ Next menu ****************/

                            /** FILE MENU ITEMS  **/
#define NUM_SORT_ITEMS  5
#define ALPHABET_ITEM   0
#define SIZE_ITEM       1
#define TIME_ITEM       2
#define PATTERN_ITEM    3
#define DAY_ITEM        4

struct MenuItem  sort_items[NUM_SORT_ITEMS];
struct IntuiText sort_names[NUM_SORT_ITEMS];

char  *sortmenu_names[] = {
    "Alphabeticly",
    "By Size",
    "By Time",
    "By Pattern",
    "By Day"
};

char *sortmenu_short[] = {
    "S",
    "Z",
    "T",
    "O",
    "Y"
};

struct Menu smenu = {
  NL,                        /* Pointer to next menu, fill in later */
  200, 0, SORT_WIDTH, 10,    /* LeftEdge, TopEdge, Width, Height */
  MENUENABLED,               /* FLAGS */
  "Sort List",           /* Menu name */
  NL                         /* First item structure */
};

/***************************************************************************
                   AUTO REQUEST INTUITEXT STRUCTURES
***************************************************************************/

struct IntuiText Auto3 = {
   REDP,  WHTP,
   JAM1,  15,
   35,    NL,
   "Freely Redistributable for noncomercial purposes. ", NULL
};

struct IntuiText Auto2 = {
   REDP,  WHTP,
   JAM1,  15,
   17,    NL,
   " Inspired by the PD Flist on IBM mainframes ", &Auto3
};

struct IntuiText AboutText = {
   REDP,  WHTP,
   JAM1,  20,
   5,    NL,
   " Flist was written by Steve (Raz) Berry ", &Auto2  
};

/***************************************************************************
                  M A I N     P R O G R A M     M O D U L E
***************************************************************************/
long mousey, mousex;

menu()
{
    ULONG    class;     /* Message class from Intuition                  */
    USHORT   code;      /* Menu code info from Intuition                 */
    struct MenuItem *item;
    long     gadown=FALSE;
    struct IntuiMessage *message;
    struct Gadget *igad;
    register short  prevy=0;
    register int i,temp;
    char buf[256];

    mousey = 0;
    mousex = 0;

    fmenu.FirstItem = &file_items[0];
    fmenu.NextMenu = &dmenu;
    dmenu.NextMenu = &smenu;

    NewMenu( &fmenu, filemenu_names, filemenu_short, file_items, file_names,
            NUM_FILE_ITEMS, item_widths[0], BLACK_FILL);

    dmenu.FirstItem = &dir_items[0];

    NewMenu( &dmenu, dirmenu_names, dirmenu_short, dir_items, dir_names,
            NUM_DIR_ITEMS, item_widths[1], HAS_CHECKS);

    smenu.FirstItem = &sort_items[0];

    NewMenu( &smenu, sortmenu_names, sortmenu_short, sort_items, sort_names,
            NUM_SORT_ITEMS, item_widths[2], BLACK_FILL);

/*    sort_items[0].MutualExclude = 0xfffe; */

    top = 0;     /* this is the pointer to the first file on the screen */
  
    SetMenuStrip(winptr, &fmenu);      /* Set up the menu here */

    ShowTitle(scrptr,TRUE);      /* Do show the screen Title. */

    sort(0);                     /* sort the list alphabetically */
    refresh();
    drawcur();

    for (;;)
    {
      if ((message = (struct IntuiMessage *)GetMsg(winptr->UserPort)) == 0L)  {
          Wait(1L<<winptr->UserPort->mp_SigBit);
          continue;
      }

        class = message->Class;
        code = message->Code;
        igad = (struct Gadget *)message->IAddress;
        mousey = message->MouseY;
        mousex = message->MouseX;

        switch (class) {

            case RAWKEY:
                getkey(message);    /* message is replied to in routine */
                break;          

            case MOUSEMOVE: 
                ReplyMsg(message);
                if(gadown){
#ifdef KILLEXTRA
                        /* get rid of any extra messages */

                        while((message = (struct IntuiMessage *)GetMsg(winptr->UserPort)) != 0L) {
                                mousey = message->MouseY;
                                ReplyMsg(message);
                                if((prevy<mousey)&&(line<numfiles))
                                top++;
                                if((prevy>mousey)&&(top>0))
                                        top--;
                                prevy = mousey;  
                        } 
#endif
                        if((prevy<mousey)&&(line<numfiles-1)){
                                        line++;
                                        top++;
                        }
                        if((prevy>mousey)&&(top>0)){
                                if (line>0)
                                        line--;
                                top--;
                        }
                        prevy = mousey;    
                        temp = numfiles-top;
                        scrprt(temp,top);
                }
                break;
                
        case GADGETUP: 
                ReplyMsg(message);
                drawline(collum,TRUE);
                drawcur();
                gadown = FALSE;
                break;

        case GADGETDOWN:
                ReplyMsg(message);
                blankcur();
                switch ( i = igad->GadgetID) {
                    case FGAD: /* the prop gadget here... */
                        gadown = TRUE;
                        strcpy(buf,conline);
                        conline[first] = 0;
                        drawline(collum,TRUE);
                        strcpy(conline,buf);
                        drawline(collum,TRUE);
                        break;
                }
                break;

        case CLOSEWINDOW: 
                ReplyMsg(message);
                Cleanup();
                exit(0);
                break;

        case MENUPICK:
                ReplyMsg(message);
                blankcur();
                while (code != MENUNULL) {
#ifdef DEBUG
    sprintf(buf,"Code is %ld Menunum is %ld",code, MENUNUM(code));
    auto_req(buf);
#endif
                    domenu(MENUNUM(code), ITEMNUM(code),
                        SUBNUM(code));
                    item = ItemAddress(&fmenu, MENUNUM(code));
                    if (item->NextSelect == code)
                        break;
                    code = item->NextSelect;
                    item->NextSelect = MENUNULL;
                }
                drawcur();
                break;

        case MOUSEBUTTONS: 
                ReplyMsg(message);
                break;

        }   /* Case */
   }  /* for */
}   /* End of Main */

/***************************************************************************
                   C R E A T E    A    N E W    M E N U
***************************************************************************/
NewMenu ( menu, item_names,  item_short, menu_items, menu_text, 
        num_items, Mwidth, flag)

struct Menu      *menu;           /* Menu structure                       */
char             *item_names[];   /* Pointer to array of item names       */
char             *item_short[];   /* Pointer to array of shortcut char    */
struct MenuItem  menu_items[];    /* pointer to array of structures       */
struct IntuiText menu_text[];     /* Pointer to array of text structures  */
int               num_items;      /* Number of items                      */
int               Mwidth;         /* Menu Width */
long                flag;         /* Special Item flag for ALL items */
{
    int i;
    int height = 0;

    for (i=0; i< num_items; i++) {

        menu_text[i] = generic;              /* stamp generic template */
        menu_text[i].IText = item_names[i];          /* mv string ptrs */
        menu_items[i].NextItem = &menu_items[i+1];  /* Lnk to nxt item */
        menu_items[i].TopEdge = 10 * i;            /* Top rect of item */
        menu_items[i].LeftEdge = 2;
        menu_items[i].Height = 8;
        menu_items[i].ItemFill = (APTR)&menu_text[i];
        menu_items[i].Width = Mwidth;
        menu_items[i].MutualExclude = 0;
        menu_items[i].Command = item_short[i][0];
        menu_items[i].Flags = (USHORT)flag;
        menu_items[i].SubItem = NULL;
        menu_items[i].NextSelect = MENUNULL;
        height += 10;
    }
    menu_items[num_items-1].NextItem = NULL;
    menu->Height = height;
}

/* DO THE MENU SELECTIONS */

domenu(menu, item, subitem)
int  menu, item, subitem;
{
    char buf[256];
    int i;

    switch (menu) {

        case PROJ_MENU: 
            switch (item) {

               case  DO_ITEM: 
                    dorexx();
                    break;

               case  ICON_ITEM: 
                    tticon();
                    break;

               case  QUIT_ITEM:     
                    if(scrptr->FirstWindow->NextWindow != NULL) 
                        auto_req("Kill all other Applications first");
                    else {
                        Cleanup();
                        exit(0);
                    }
                    break;

               case  ABOUT_ITEM: 
                    AutoRequest(winptr, &AboutText, &TRUEtext, &TRUEtext, 
                                0L, 0L, 450L, 80L );
                    break;
            } 
            break;

        case DIR_MENU:

            for (i=0;i<NUM_DIR_ITEMS;i++)
                dir_items[i].Flags = HAS_CHECKS;

            switch (item) {

                case PARENT_ITEM:
                    parent();
                    refresh();
                    break;

                case CHANGE_ITEM:
                    if (*finfo[line][0] < 0){
                        sprintf(buf,"%s Not a directory",fname[line]);
                        auto_req(buf);
                    }else {
                        changedir(fname[line]);
                        refresh();
                    }
                    break;

                case ARP_ITEM:
                    if (Wbargs() == 0){
                        UnLock(olddir);
                        refresh();
                    }
                    break;

                case REGET_ITEM:
                    getdir();
                    refresh();
                    break;

                case KILL_ITEM:
                    kill(fname[line]);
                    refresh();
                    break;

                case RENAME_ITEM:
                    rename_file(fname[line]);
                    refresh();
                    break;

                case MAKEDIR_ITEM:
                    make_dir();
                    refresh();
                    break;
            }
            break;

        case SORT_MENU:
        
            switch (item) {

                case ALPHABET_ITEM:
                    sort(0);
                    refresh();
                    break;

                case SIZE_ITEM:
                    sort(1);
                    refresh();
                    break;

                case TIME_ITEM:
                    sort(2);
                    refresh();
                    break;

                case PATTERN_ITEM:
                    sort(3);
                    refresh();
                    break;

                case DAY_ITEM:
                    sort(4);
                    refresh();
                    break;

            }
            break;
    }
}

SHAR_EOF
cat << \SHAR_EOF > parse.c
/*
* parse routines for flist...
*
* uses arp functions.
*
*/

#include <libraries/arpbase.h>
#include <stdio.h>
#include "flist.h"

/* Global stuff for ARP */

char *CLI_Template = ",FROM/K";
char *CLI_Help = "Type filename(s) or FROM and a file with name of files";

/* global flist stuff */

struct AnchorPath *ap = NULL;

long (*finfo[MAXDIR])[4];  /* miscelaneous info -- file size,blocks,dir type etc... */
char (*fname[MAXDIR])[FCHARS];     /* file name and comment */
char (*comm[MAXDIR])[FCHARS];
char (*fstring[MAXDIR])[LEN_DATSTRING];
char (*ftime[MAXDIR])[LEN_DATSTRING];

struct FileLock *startdir = NULL, *lock = NULL, *olddir = NULL;

long numfiles,getcurrentdir();

long parse(argc,argv)
long argc;
char *argv[];
{
    long i,rc = -99;
    
    for (i=0;i<MAXDIR;i++)  /* zero out the memory arrays */
        fname[i] = 0;

    ap = (struct AnchorPath *)ArpAllocMem(sizeof(struct AnchorPath),FAST);

    if(ap == NULL)
        return OUT_OF_MEMORY;

    ap->ap_BreakBits = SIGBREAKB_CTRL_C;
    ap->ap_Length = 0;

    if((argv[1] != 0) && (argc > 0)){
        if(!getcurrentdir(argv[1]))
            return -98;
        strcat(argv[1],"*");
        rc = FindFirst(argv[1],ap);
        if(rc == NULL)
            rc = Fillarray();
    }
    else{ 
        if ((argc > 1) && (argv[2] != NULL))
            rc = other_input(argv[2]);
        else{
            if(argc == 0)  
                rc = Wbargs();   /* do we have Workbench? */
            else{
                if(!getcurrentdir(""))
                        return -98;
                rc = FindFirst("*",ap); /* user only typed 'flist' */
                if(rc == NULL)          /* so we are going to give him the */
                    rc = Fillarray();   /* current directory */
            }
        }
    }
    return rc;    /* return code should always be sent */
}

FreeFlistMem()
{
    if(ap != NULL )
        FreeAnchorChain(ap);
}

/* Stuff all the filenames and pertinent information into */
/* the flist arrays */

long Fillarray()
{
    long rc = NULL;
    struct DateTime dt;
    int i;

    numfiles = 0;

    dt.dat_Format = FORMAT_DOS;
    dt.dat_StrDay = NULL;
    dt.dat_Flags = DTB_SUBST;

    while(rc != ERROR_NO_MORE_ENTRIES){

        if(get_array_mem(numfiles) == OUT_OF_MEMORY)
                return OUT_OF_MEMORY;
                
        strcpy(fname[numfiles],&ap->ap_Info.fib_FileName);
        strcpy(comm[numfiles],&ap->ap_Info.fib_Comment); 
        dt.dat_Stamp = ap->ap_Info.fib_Date;
        dt.dat_StrDate = fstring[numfiles];
        dt.dat_StrTime = ftime[numfiles];

        (*finfo[numfiles])[0] = ap->ap_Info.fib_DirEntryType;
        (*finfo[numfiles])[1] = ap->ap_Info.fib_Protection;
        (*finfo[numfiles])[2] = ap->ap_Info.fib_Size;
        (*finfo[numfiles])[3] = ap->ap_Info.fib_NumBlocks;

        if((rc = StamptoStr(&dt)) != NULL)
                break;

        rc = FindNext(ap);

        if( ++numfiles > MAXDIR || rc != NULL)
            break;
    }

    for (i=numfiles;i<MAXDIR;i++)   /* free all array memory not being used */
        if (fname[i] != 0) {
            FreeMem(fname[i],FCHARS);
/*            FreeMem(comm[i],FCHARS); */
            FreeMem(finfo[i],16L);
            FreeMem(fstring[i],LEN_DATSTRING);
            FreeMem(ftime[i],LEN_DATSTRING);
            fname[i] = 0;
            finfo[i] = 0;
            fstring[i] = 0;
            ftime[i] = 0;
        }

    if(rc == ERROR_NO_MORE_ENTRIES)
        return NULL;
    return rc;
}

/* The user has not supplied any filenames or input for the File */
/* template. Here we check for the optional FROM keyword. */

long other_input(argv)
char *argv[];
{

    FILE *fp;
    char *buffer;
    struct DateTime dt;
    register long rc;
    int i;

    if ((buffer = (char *)ArpAllocMem(LINESIZE,FAST)) == NULL)
        return OUT_OF_MEMORY;

    if ((fp = fopen(argv,"r")) == NULL)
        return -99L;

    if (!getcurrentdir(""))
        return -98L;

    dt.dat_Format = FORMAT_USA;
    dt.dat_StrDay = NULL;
    dt.dat_Flags = DTB_SUBST;

    numfiles = 0;
    while (feof(fp) == NULL){

        if(get_array_mem(numfiles) == OUT_OF_MEMORY)
                return OUT_OF_MEMORY;
                
        fscanf(fp,"%s",buffer);
        rc = FindFirst(buffer,ap);
        if (rc != NULL )
            break;

        strcpy(fname[numfiles],buffer);
        strcpy(comm[numfiles],&ap->ap_Info.fib_Comment); 
        (*finfo[numfiles])[0] = ap->ap_Info.fib_DirEntryType;
        (*finfo[numfiles])[1] = ap->ap_Info.fib_Protection;
        (*finfo[numfiles])[2] = ap->ap_Info.fib_Size;
        (*finfo[numfiles])[3] = ap->ap_Info.fib_NumBlocks;
        dt.dat_Stamp = ap->ap_Info.fib_Date;
        dt.dat_StrDate = fstring[numfiles];
        dt.dat_StrTime = ftime[numfiles];

        if((rc = StamptoStr(&dt)) != NULL)
                break;

        if( ++numfiles > MAXDIR | rc != NULL)
            break;
        }

    if (feof(fp) == NULL){
        if (rc == NULL)
            rc = (LONG)ferror(fp);
    }
    else
        numfiles--;

    for (i=numfiles;i<MAXDIR;i++)   /* free all array memory not being used */
        if (fname[i] != 0) {
            FreeMem(fname[i],FCHARS);
/*            FreeMem(comm[i],FCHARS); */
            FreeMem(finfo[i],16L);
            FreeMem(fstring[i],LEN_DATSTRING);
            FreeMem(ftime[i],LEN_DATSTRING);
            fname[i] = 0;
            finfo[i] = 0;
            fstring[i] = 0;
            ftime[i] = 0;
        }
    fclose(fp);
    return rc;        
}

long get_array_mem(index)
long    index;
{

/* If the memory array already has a block allocated to it return to 
   caller... otherwise allocate one */

    if (fname[index] != 0L)
        return 0L;
    
    fname[index] =      (char *)AllocMem(FCHARS,FAST);
/*    comm[index]  =      (char *)AllocMem(FCHARS,FAST); */
    finfo[index] =      (LONG *)AllocMem(16L,FAST);
    fstring[index] =    (char *)AllocMem(LEN_DATSTRING,FAST);
    ftime[index] =      (char *)AllocMem(LEN_DATSTRING,FAST);

    if( ftime[index] == NULL | fstring[index] == NULL \
    | fname[index] == NULL | /* comm[index] == NULL | */ finfo[index] == NULL )
        return OUT_OF_MEMORY;
    else
        return 0L;
}

/*
** more Arp stuff for Workbench support
*/

BYTE dir[DSIZE], name[FCHARS];

getarp(mask,fib)
ULONG mask;
struct FileInfoBlock *fib;
{

    long rc;
    struct DateTime dt;

    dt.dat_Format = FORMAT_USA;
    dt.dat_StrDay = NULL;
    dt.dat_Flags = DTB_SUBST;

    strcpy(fname[numfiles],&fib->fib_FileName);
    strcpy(comm[numfiles],&fib->fib_Comment); 
    (*finfo[numfiles])[0] = fib->fib_DirEntryType;
    (*finfo[numfiles])[1] = fib->fib_Protection;
    (*finfo[numfiles])[2] = fib->fib_Size;
    (*finfo[numfiles])[3] = fib->fib_NumBlocks;
    dt.dat_Stamp = ap->ap_Info.fib_Date;
    dt.dat_StrDate = fstring[numfiles];
    dt.dat_StrTime = ftime[numfiles];

    if((rc = StamptoStr(&dt)) != NULL)
        return rc;

    numfiles++;

    return 0L;    /* tell Arp to put this entry in the requester */

/* ok, this is the fun part ... cheath told me that there
   is a bug in the handling of the return code. this is the fix. */
#asm
    move.l #0,d0      ; d0 MUST contain the return code 
    move.l d0,4(sp)   ; 4(sp) is the part that gets munged to the 
                      ; correct value 
#endasm
}

struct FileRequester arpfr = {
                                     /* Hailing text */
    (BYTE *)"Select a directory, then click on OK.", 
    NULL,                            /* string to put the final name */
    NULL,                            /* string to put the directory entry */
    NULL,                            /* Window for the files */
    NULL,                            /* what calls getarp? */
    NULL,                            /* reserved */
    NULL,                            /* function to be called */
    NULL                             /* reserved */
};

long Wbargs()   /* use the arp file requester to get the file names */
{
    long dummy;
    char dname[FCHARS];

    strcpy(dir,"RAM:");
    strcpy(dname,"Select directory only.");

    arpfr.fr_Dir = dir;
    arpfr.fr_File = dname;

    dummy = FileRequest(&arpfr);

    if(dummy == NULL)   /* user selects cancel -- so abort */
        return 1;

    olddir = lock;      /* save this for later */

    if(strcmp(dir,"") == 0)
        getcurrentdir("");
    else {
        lock = Lock(dir,ACCESS_READ);
        if(lock == NULL) {
            auto_req("Can't find requested directory.");
            return 1;
        }
    }

    if (startdir == NULL)
        startdir = CurrentDir(lock);
    else
        CurrentDir(lock);

    TackOn(dir,"*");
    dummy = FindFirst(dir,ap);

    if(dummy == NULL)
       dummy = Fillarray();

    return (dummy == NULL || dummy == ERROR_NO_MORE_ENTRIES) ? 0 : 1;
}

long getcurrentdir(str)
char *str;
{
    /* This is the only way I have ever been able to reliably get the
       current directory */
    
    /* Save the Value of the Directory we are in now. */

    if (str[0] == '\0'){
        struct Process *proc = FindTask(NULL);

        lock = DupLock(proc->pr_CurrentDir);
        startdir = CurrentDir(lock);
        return TRUE;
    } else {
        lock = Lock(str);
        startdir = CurrentDir(lock);
        return (startdir == 0) ? FALSE : TRUE;
    }
}
SHAR_EOF
cat << \SHAR_EOF > pathname.c
/** pathname.c
*
*                     Copyright 1988, W.G.J. Langeveld
*                           All Rights Reserved
*                           Freely Distributable
*
*	Expand path name given a lock on a file name. Emulates ARP function
*   of the same name, which is slightly unreliable.
*
*   Mods to device name generation by Steve (Raz) Berry
*   12/31/88 (New Years Eve!)
*
**/

#include <stdio.h>

char *index();
extern void auto_req();

#define FIBSIZ ((long) sizeof(struct FileInfoBlock))

int PathName(plock, buffer)
struct FileLock *plock;
char *buffer;
{
   struct FileLock *llock, *curdir;
   char *temp, *pos, buf[100];
   struct FileInfoBlock *filinf;
    long rc;

   llock = NULL;
   filinf = NULL;
   temp = NULL;
   buffer[0] = '\0';

   filinf = (struct FileInfoBlock *) AllocMem(FIBSIZ, MEMF_PUBLIC|MEMF_CLEAR);
   if (filinf == NULL) goto cleanuplk;

   temp = (char *) AllocMem(255L, MEMF_PUBLIC|MEMF_CLEAR);
   if (temp == NULL) goto cleanuplk;

#ifdef DEBUG
   if(plock == NULL)
    auto_req("lock is null");
#endif

   rc = Examine(plock, filinf);

   if (rc == NULL) goto cleanuplk;

   strcpy(buffer, filinf->fib_FileName);
   llock = ParentDir(plock);
/*
*  Now loop back through the parent directories until root is found.
*  Meanwhile, keep track of the names.
*/

   while (llock != NULL) {
      if (Examine(llock, filinf) == NULL) goto cleanuplk;

      strcpy(temp, buffer);
      strcpy(buffer, filinf->fib_FileName);
      strcat(buffer, "/");
      strcat(buffer, temp);

      curdir = ParentDir(llock);
      UnLock(llock);
      llock = curdir;
   }
/*
*   Now fix up the name
*/

   if (pos = index(buffer, '/')) {
      *pos = ':';
      if (pos == buffer) {
         strcpy(temp, "ram");
         strcat(temp, buffer);
         strcpy(buffer, temp);
      } 
   } else 
        strcat(buffer, ":");    /* Append : to root names - swb */

cleanuplk:

   if (filinf != NULL) FreeMem(filinf, FIBSIZ);
   if (temp != NULL)   FreeMem(temp, 255L);
   if (llock != NULL)   UnLock(llock);

   return(strlen(buffer));
}

SHAR_EOF
cat << \SHAR_EOF > readme

                    Flist - The wonder program.
                           Version 1.2
                    
                           Written by :
                    
                        Steve (Raz) Berry

This product may be freely distributed, provided only a nominal fee is 
charged, and all files are distributed together. This product may NOT be 
distributed with a commercial product without prior written consent.

See the end of this file for a list of changes.

THINGS THAT YOU MUST DO BEFORE RUNNING FLIST:

    Stack: Set your stack at 10K or so. You can set the stack on Icons
    if they are project icons. Make sure they are! You will crash the 
    system if the stack is at the default of 4K.

    ARP library: This release of Flist requires Version 1.1 of the 
    arp.library to be placed in you LIBS: directory. ARP may be discontinued
    for future Flist releases. 
    
    Path: The easiest way to insure that Flist knows about your favorite
    search paths is to set them in your startup-sequence before it exits.
    (This trick works only under WorkBench 1.3)
    Otherwise you will have to type the full pathname of each command.
    One alternate fix is to install a Path-handler to search for your 
    commands. If you run Flist from the Workbench, you will NOT have any
    default paths no matter what you do (it's not my fault... really).

    Install the NULL: device in your system. See the docs in the 
    distributrion.

THINGS THAT YOU MUST NOT DO TO RUN FLIST:

    Using the PD runback command without redirecting the input and output.

    If you 'run >nil: <nil: flist' and you mount the NULL: device, 
    then you are safe.

    If you just type 'runback flist' then there is an increased chance
    that you will crash your machine. Here's how:
    
    Nobody really wants to do this, do they?
    
        1) runback flist from the CLI (and don't redirect the output).
        2) endcli the CLI that spawned flist.
        3) in Flist type 'run list' and return.
        4) Hit the left mouse button to continue.
    
    The reasons are many and varied as to why, lets just say that the output
    of the 'run list' was sent to a nonexistant CLI.

    I suggest that if you want your CLI back, you do:

        'run <nil: >nil: flist'

    Use only the 1.3 run command and make sure that the NULL device is 
    mounted.

    HINT: If you use a shell, you can make an alias like so:

        alias fb = "run <nil: >nil: flist []"

    The NULL device handler is included in the distribution. Read the docs
    for information on how to install it.

DESCRIPTION and FEATURES:

    Flist is a Scrollable, configurable, interactive CLI and LIST combined.
    ANY command that can be executed in a CLI can be run from Flist.
    
    Flist will work in either the Workbench or the CLI environments.
    
    You can iconify Flist to get it out of the way (thanks Leo!) and save
    the price of a 2 bitplane hires screen.

    Changing directory, changing to a parent directory, Deleting files or
    directories, using the ARP filerequestor (to change directory) are 
    builtin functions.
    
    Hitting the Escape key will insert the file name (on the current line)
    into the input area (to the right of the filename).

    The input area scrolls to the left and right as needed, and allows up to 
    90 characters per line.

    Directory entries of up to 999 files are supported.

    Flist opens windows for execution so it's under the mouse.

    Sort the list of files alphabetically, by size, by time or by
    the supplied pattern.
    
    If you use snipit, type 'snipit x +3 y +5' to snip from Flist.

    Need help remembering the keystrokes? Hit the Help key, that's what its
    there for. You'll get a summary of all of the control sequences that are
    currently available.

    Yes there is an AREXX port. It doesn't do too many things at the moment,
    and you must initiate the conversation, but it's a start. Suggestions
    on further implementations are welcome.

FURTHER CONSIDERATIONS:

    Read the Docs. I mean it. I don't want people sending me e-mail bombs
    that read like :

        "I was using your dumb Flist program when it decided to 
    delete my file when I hit control-k. I though you would get a file
    requestor or somthing!"

    Remember, this is only a README. 

KNOWN BUGS:

    Sorting by time will sort using the hour of creation only.

    If you slide the screen down and open a window on the Workbench screen,
    leaving both screens visible, the window will open on the Flist screen
    instead of the Workbench.

    *** This is more interesting than a bug, (in other words I can't fix it)
    but if you spawn a 'loadwb' (Load Workbench) from Flist, or even when
    Flist is the frontmost screen, the Amiga workbench takes over the screen
    permanent like, and uses it for its own. Flist remains running but
    can't be terminated.

    Fifteen color Pointer animations change the workbench screen colors to 
    those matching Flist.

    Not so configurable in this release. Sorry.

    Still haven't allowed for any screen size other than 640x200. 
    I know this is stupid but this utility is for me, and this is what I
    use. If someone is persistant enough and sends me the code for figuring
    out the current screen size...

RELEASE HISTORY:

    V1.0    Initial release. (Only jdow saw this)
    V1.1    Bug fixes to the Arexx port. No major changes from V1.0

    V1.2    Major new release. Lots of changes and additions.

            1.  It's harder to hang flist from the REXX port
                (I haven't been able to do it yet)

            2.  New REXX Commands:
                makedir     - make a new directory
                changedir   - change to a directory eg:
                              'changedir flist'
                rename      - rename a file using string requestor.
                redraw      - redraw the screen.
                request     - bring up the ARP requestor.

            3.  Menu support (and shortcuts) for all keystrokes.
                (as well as an attempt at extended selection support)

            4.  New commands added:
                makedir
                execute rexx macro (via string requestor)
                rename file
                sort by pattern
                sort by date.
                sort by day.

            5.  Bug fixes to cursor movment routines, as well as adding
                cntrl-U (erase line). Also insert mode is now the only 
                mode of entry.
            
            6.  Supports SHIFT-UP and SHIFT-DOWN cursor keys to move
                10 lines up or down the list. Also SHIFT left, right
                to move to the begining or the end of the line respectively.

            7.  Uses default screen colors.

            8.  Internal changes to static memory allocation for 
                efficiency. In other words, it uses less memory.

            9.  Fixed misterious bug causing the original CLI to 
                generate a Software Error. All better now.

swb 1/23/89

Flist is a BeerWare product of 'The Checkered Ball'
SHAR_EOF
cat << \SHAR_EOF > rexxglue.asm
* === rexxglue.asm =====================================================
*
* Copyright (c) 1986, 1987 by William S. Hawes (All Rights Reserved)
*
* ======================================================================
* "Glue" routines for calling functions in the ARexx Systems Library.
* All calls assume that the external _RexxSysBase has been set to the
* ARexx SYstems library base by a call to OpenLibrary.

         INCLUDE  "rexx/storage.i"
         INCLUDE  "rexx/rxslib.i"

         XREF     _RexxSysBase

* First calling convention:
* 1, 2, or 3 parameters in (A0,A1,D0), return value in D0.

         ; node = AddClipNode(&header,&name,value,length)

         XDEF     _AddClipNode
_AddClipNode:
         move.w   #_LVOAddClipNode,d1
         bra      CallSeq1

         ; node = AddRsrcNode(&header,&name,size)

         XDEF     _AddRsrcNode
_AddRsrcNode:
         move.w   #_LVOAddRsrcNode,d1
         bra      CallSeq1

         ; count = CloseF(filehandle)

         XDEF     _CloseF
_CloseF
         move.w   #_LVOCloseF,d1
         bra.s    CallSeq1

         ; test = CmpString(&string1,&string2)

         XDEF     _CmpString
_CmpString:
         move.w   #_LVOCmpString,d1
         bra.s    CallSeq1

         ; envptr = CurrentEnv(rxtptr)

         XDEF     _CurrentEnv
_CurrentEnv:
         moveq    #_LVOCurrentEnv,d1
         bra.s    CallSeq1

         ; error = CVc2x(&buffer,&string,length)

         XDEF     _CVc2x
_CVc2x:
         move.w   #_LVOCVc2x,d1
         bra.s    CallSeq1

         ; error = CVx2c(&buffer,&string,length)

         XDEF     _CVx2c
_CVx2c:
         move.w   #_LVOCVx2c,d1
         bra.s    CallSeq1

         ; ClosePublicPort(&header,&name)

         XDEF     _ClosePublicPort
_ClosePublicPort:
         move.w   #_LVOClosePublicPort,d1
         bra.s    CallSeq1

         ; spptr = CreateDOSPkt()

         XDEF     _CreateDOSPkt
_CreateDOSPkt:
         move.w   #_LVOCreateDOSPkt,d1
         bra.s    CallSeq1

         ; msgptr = CreateRexxMsg(&replyport,&fileext,&hostname)

         XDEF     _CreateRexxMsg
_CreateRexxMsg:
         move.w   #_LVOCreateRexxMsg,d1
         bra.s    CallSeq1

         ; DeleteArgstring(argptr)

         XDEF     _DeleteArgstring
_DeleteArgstring:
         move.w   #_LVODeleteArgstring,d1
         bra.s    CallSeq1

         ; DeleteRexxMsg(msgptr)

         XDEF     _DeleteRexxMsg
_DeleteRexxMsg:
         move.w   #_LVODeleteRexxMsg,d1
         bra.s    CallSeq1

         ; code = DOSCommand(&string,filehandle)

         XDEF     _DOSCommand
_DOSCommand:
         move.w   #_LVODOSCommand,d1
         bra.s    CallSeq1

         ; count = DOSRead(filehandle,&buffer,length)

         XDEF     _DOSRead
_DOSRead:
         move.w   #_LVODOSRead,d1
         bra.s    CallSeq1

         ; count = DOSWrite(filehandle,&buffer,length)

         XDEF     _DOSWrite
_DOSWrite:
         move.w   #_LVODOSWrite,d1
         bra.s    CallSeq1

         ; DeleteDOSPkt(&stdpkt)

         XDEF     _DeleteDOSPkt
_DeleteDOSPkt:
         move.w   #_LVODeleteDOSPkt,d1
         bra.s    CallSeq1

         ; count = ExistF(filehandle,&buffer,length)

         XDEF     _ExistF
_ExistF:
         move.w   #_LVOExistF,d1
         bra.s    CallSeq1

         ; devptr = FindDevice(&name)

         XDEF     _FindDevice
_FindDevice:
         move.w   #_LVOFindDevice,d1
         bra.s    CallSeq1

         ; FreeSpace(envptr,memptr,length)

         XDEF     _FreeSpace
_FreeSpace:
         moveq    #_LVOFreeSpace,d1
         bra.s    CallSeq1

         ; FreePort(&msgport)

         XDEF     _FreePort
_FreePort:
         move.w   #_LVOFreePort,d1
         bra.s    CallSeq1

         ; type = IsSymbol(&string)

         XDEF     _IsSymbol
_IsSymbol:
         moveq    #_LVOIsSymbol,d1
         bra.s    CallSeq1

         ; InitList(&header)

         XDEF     _InitList
_InitList:
         move.w   #_LVOInitList,d1
         bra.s    CallSeq1

         ; signal = InitPort(&replyport)

         XDEF     _InitPort
_InitPort:
         move.w   #_LVOInitPort,d1
         bra.s    CallSeq1

         ; boolean = IsRexxMsg(msgptr)

         XDEF     _IsRexxMsg
_IsRexxMsg:
         move.w   #_LVOIsRexxMsg,d1
         bra.s    CallSeq1

         ; length = LengthArgstring(argptr)

         XDEF     _LengthArgstring
_LengthArgstring:
         move.w   #_LVOLengthArgstring,d1

         ; Load three arguments into (A0,A1,D0)

CallSeq1 movea.l  4(sp),a0
         movea.l  8(sp),a1
         move.l   12(sp),d0

         ; Call the library function

CallFunc move.l   a6,-(sp)
         movea.l  _RexxSysBase,a6
         jsr      0(a6,d1.w)
         movea.l  (sp)+,a6
         rts

         ; argptr = ListNames(&header)

         XDEF     _ListNames
_ListNames:
         move.w   #_LVOListNames,d1
         bra.s    CallSeq1

         ; iobptr = OpenF(filehandle,&buffer,length)

         XDEF     _OpenF
_OpenF:
         move.w   #_LVOOpenF,d1
         bra.s    CallSeq1

         ; nodeptr = OpenPublicPort(&header,&name)

         XDEF     _OpenPublicPort
_OpenPublicPort:
         move.w   #_LVOOpenPublicPort,d1
         bra.s    CallSeq1

         ; count = QueueF(filehandle,&buffer,length)

         XDEF     _QueueF
_QueueF:
         move.w   #_LVOQueueF,d1
         bra.s    CallSeq1

         ; count = ReadF(filehandle,&buffer,length)

         XDEF     _ReadF
_ReadF:
         move.w   #_LVOReadF,d1
         bra.s    CallSeq1

         ; count = ReadStr(filehandle,&buffer,length)

         XDEF     _ReadStr
_ReadStr:
         move.w   #_LVOReadStr,d1
         bra.s    CallSeq1

         ; RemRsrcList(&header)

         XDEF     _RemRsrcList
_RemRsrcList:
         move.w   #_LVORemRsrcList,d1
         bra.s    CallSeq1

         ; RemRsrcNode(&header,&node)

         XDEF     _RemRsrcNode
_RemRsrcNode:
         move.w   #_LVORemRsrcNode,d1
         bra.s    CallSeq1

         ; RemClipNode(&header,&node)

         XDEF     _RemClipNode
_RemClipNode:
         move.w   #_LVORemClipNode,d1
         bra.s    CallSeq1

         ; test = StrcmpN(&string1,&string2)

         XDEF     _StrcmpN
_StrcmpN:
         move.w   #_LVOStrcmpN,d1
         bra.s    CallSeq1

         ; test = StrcmpU(&string1,&string2)

         XDEF     _StrcmpU
_StrcmpU:
         move.w   #_LVOStrcmpU,d1
         bra.s    CallSeq1

         ; test = StrcpyA(&string1,&string2)

         XDEF     _StrcpyA
_StrcpyA:
         move.w   #_LVOStrcpyA,d1
         bra.s    CallSeq1

         ; test = StrcpyN(&string1,&string2)

         XDEF     _StrcpyN
_StrcpyN:
         move.w   #_LVOStrcpyN,d1
         bra.s    CallSeq1

         ; test = StrcpyU(&string1,&string2)

         XDEF     _StrcpyU
_StrcpyU:
         move.w   #_LVOStrcpyU,d1
         bra.s    CallSeq1

         ; length = Strlen(&string)

         XDEF     _Strlen
_Strlen:
         move.w   #_LVOStrlen,d1
         bra.s    CallSeq1

         ; count = SeekF(filehandle,&buffer,length)

         XDEF     _SeekF
_SeekF:
         move.w   #_LVOSeekF,d1
         bra.s    CallSeq1

         ; count = StackF(filehandle,&buffer,length)

         XDEF     _StackF
_StackF:
         move.w   #_LVOStackF,d1
         bra      CallSeq1

         ; count = WriteF(filehandle,&buffer,length)

         XDEF     _WriteF
_WriteF:
         move.w   #_LVOWriteF,d1
         bra      CallSeq1

* Second calling convention:  2 parameters in (A0,D0), return value in D0.

         ; argptr = CreateArgstring(&string,length)

         XDEF     _CreateArgstring
_CreateArgstring:
         moveq    #_LVOCreateArgstring,d1
         bra.s    CallSeq2

         ; ClearMem(address,length)

         XDEF     _ClearMem
_ClearMem:
         move.w   #_LVOClearMem,d1
         bra.s    CallSeq2

         ; count = ClearRexxMsg(msgptr,count)

         XDEF     _ClearRexxMsg
_ClearRexxMsg:
         move.w   #_LVOClearRexxMsg,a1
         bra.s    CallSeq2

         ; nodeptr = FindRsrcNode(&header,type)

         XDEF     _FindRsrcNode
_FindRsrcNode:
         move.w   #_LVOFindRsrcNode,d1
         bra.s    CallSeq2

         ; block = GetSpace(envptr,size)

         XDEF     _GetSpace
_GetSpace:
         moveq    #_LVOGetSpace,d1
         bra.s    CallSeq2

         ; test = StrFlipN(&string1,length)

         XDEF     _StrflipN
_StrflipN:
         move.w   #_LVOStrflipN,d1

         ; Load two arguments (A0,D0)

CallSeq2 movea.l  4(sp),a0
         move.l   8(sp),d0
         bra      CallFunc

* Third calling convention:  1 parameter in D0, return value in D0.

         ; argptr = CVi2arg(value)

         XDEF     _CVi2arg
_CVi2arg:
         move.w   #_LVOCVi2arg,d1
         bra.s    CallSeq3

         ; LockRexxBase(resource)

         XDEF     _LockRexxBase
_LockRexxBase:
         move.w   #_LVOLockRexxBase,d1
         bra.s    CallSeq3

         ; char = ToUpper(char)

         XDEF     _ToUpper
_ToUpper:
         move.w   #_LVOToUpper,d1
         bra.s    CallSeq3

         ; UnlockRexxBase(resource)

         XDEF     _UnlockRexxBase
_UnlockRexxBase:
         move.w   #_LVOUnlockRexxBase,d1

         ; Load one argument in D0

CallSeq3 move.l   4(sp),d0
         bra      CallFunc

* Fourth calling sequence:  3 parameters in (A0,D0,D1), return value in D0.

         ; value = CVi2a(&buffer,value,length)

         XDEF     _CVi2a
_CVi2a:
         move.w   #_LVOCVi2a,a1
         bra.s    CallSeq4

         ; boolean = FillRexxMsg(msgptr,count,mask)

         XDEF     _FillRexxMsg
_FillRexxMsg:
         move.w   #_LVOFillRexxMsg,a1

CallSeq4 movea.l  4(sp),a0
         move.l   8(sp),d0
         move.l   12(sp),d1

         ; Call the library function

         move.l   a6,-(sp)
         movea.l  _RexxSysBase,a6
         jsr      0(a6,a1.w)
         movea.l  (sp)+,a6
         rts

* Special calling sequences for multiple returns.

         ; value = CVa2i(&string,&digits)

         XDEF     _CVa2i
_CVa2i:
         movea.l  4(sp),a0             ; scan pointer
         move.w   #_LVOCVa2i,d1
         bsr      CallFunc             ; D0=converted value
         movea.l  8(sp),a1             ; return pointer
         move.l   d1,(a1)              ; digits scanned
         rts

         ; boolean = ErrorMsg(code,&ssptr)

         XDEF     _ErrorMsg
_ErrorMsg:
         move.l   4(sp),d0
         moveq    #_LVOErrorMsg,d1
         bsr      CallFunc             ; D0=boolean  A0=string structure
         movea.l  8(sp),a1             ; return pointer
         move.l   a0,(a1)              ; string structure
         rts

         END
SHAR_EOF
cat << \SHAR_EOF > rexxport.c
/*

    This module is responsible for communicating with Rexx.
    Specifically it opens a message port and tells rexx to execute
    a program. Rexx should signal host of errors or death.
 
*/

#include <rexx/storage.h>
#include <rexx/rxslib.h>
#include <rexx/errors.h>
#include "flist.h"

/* system types */

extern void ClearMem(),AddPort(),FreePort(),InitPort(),RemPort(),Forbid();
extern void Permit();
extern LONG OpenLibrary();
extern struct RexxMsg *GetMsg();
extern struct RexxMsg myrexxport;
extern struct Library *RexxSysBase;
extern void control_keys();

/* My stuff */

struct FileHandle *fh;
struct RexxMsg *rxmsg;
extern char strbuf[256];
extern long collum, row, line, first, top;

#define PUBFAST MEMF_FAST+MEMF_PUBLIC+MEMF_CLEAR

void OpenRexxPort(string,port)
char *string;
struct MsgPort *port;
{

    ClearMem(port,(LONG)sizeof(struct MsgPort));
    InitPort(port,string);
    AddPort(port);
}

void DeleteRexxPort(port)
struct MsgPort *port;
{
    if(port != NULL){
        RemPort(port);
        FreePort(port);
    }
}

struct RexxMsg *PollRexxPort(port)
struct MsgPort *port;
{
    struct RexxMsg *rxport;

    rxport = GetMsg(port);
    return(rxport);

}

struct RexxMsg *WaitRexxPort(port)
struct MsgPort *port;
{

    WaitPort(port);
    return(PollRexxPort(port));
}

void CleanupRexx()
{

/*    Close(fh); */
    DeleteArgstring(rxmsg->rm_Args[0]);
    DeleteRexxMsg(rxmsg);
}

long StartRexxProg(rexport)
struct MsgPort *rexport;
{
    struct MsgPort *port;
    struct Window *strptr;

    strbuf[0] = '\0';
    strptr = make_gadget("Enter the REXX macro name ");

    if (strptr == NULL) {
        auto_req("Couldn't open Requestor!");
        return FALSE;
    }

    wait_for_event(strptr); 

    if (strbuf[0] == '\0') {
        return FALSE;
    }

    rxmsg = CreateRexxMsg(rexport,"flex","flport");
    rxmsg->rm_Args[0] = strbuf;
    rxmsg->rm_Action = RXCOMM;
/*    rxmsg->rm_Stdout = Output(); */

    if(!FillRexxMsg(rxmsg, 1L, 0L)) {
        DeleteRexxMsg(rxmsg);
        return FALSE;
    }

    Forbid();
    port = (struct RexxMsg *)FindPort("REXX");
    if(port == NULL){
        Permit();
        auto_req("REXX is not here!");
        CleanupRexx();
        return FALSE;
    }

    PutMsg(port,rxmsg);         /* email in it's truest form */
    Permit();
    return TRUE;
}

char *rexx_strings[] = {
    "end",
    "iconify",
    "sort s",
    "sort z",
    "sort t",
    "sort o",
    "parent",
    "redraw",
    "reget",
    "request",
    "makedir",
    "changedir",
    "sort y"
};

dorexx()
{
    struct RexxMsg *resultmsg;
    char buf[256];
    int equal, i;
                
    if(RexxSysBase == NULL){
        auto_req(" Rexx library not Available");
        return;
    }

    if(!StartRexxProg(&myrexxport)){    /* start up fl.flex as a rexx task */
        if (strbuf[0] != '\0')
            auto_req(" PANIC - couldn't start up rexx program!");
        return;
    }

    /* this is a communication test ... */

    for(;;) {

        resultmsg = WaitRexxPort(&myrexxport);

#ifdef DEBUG
        sprintf(buf,"Return of -%d- , -%s-",resultmsg->rm_Result1,resultmsg->rm_Args[0]);
        auto_req(buf);
#endif

        if (resultmsg->rm_Result1 > 0) {

            if (Strcmp(strbuf, resultmsg->rm_Args[0]) == 0) {
                sprintf(buf,"Error %d in -%s.flex-.",
                    resultmsg->rm_Result1,strbuf);
                auto_req(buf);
                resultmsg->rm_Result1 = 5; 
                resultmsg->rm_Result2 = 0; 
                CleanupRexx();
                return;
            }
        }

        resultmsg->rm_Result1 = 0;  /* no error  */
        resultmsg->rm_Result2 = 0;  /* no secondary */

        for(i=0;i<13;i++){
            equal = Strncmp(resultmsg->rm_Args[0],rexx_strings[i],
                        strlen(rexx_strings[i]));
            if (equal == 0)
                break;
        }

#ifdef DEBUG
        sprintf(buf,"I = %d, string is %s",i,rexx_strings[i]);
        auto_req(buf);
#endif

        blankcur();
        switch (i) {
        
            case 0:
                ReplyMsg(resultmsg);        /* send back 'end' message */
                WaitRexxPort(&myrexxport);  /* wait for original Msg to ret */
                CleanupRexx();
                return;

            case 1:         /* Iconify */
                tticon();
                break;

            case 2:         /* sort by name */
                sort(0);
                refresh();
                break;

            case 3:         /* sort by size */
                sort(1);
                refresh();
                break;

            case 4:         /* sort by time */
                sort(2);
                refresh();
                break;

            case 5:         /* sort by pattern */
                sort(3);
                refresh();
                break;

            case 6:         /* get parent dir */
                parent();
                refresh();
                break;

            case 7:         /* redraw screen */
                control_keys(0x0c);
                break;

            case 8:         /* reget directory */
                getdir();
                refresh();
                break;

            case 9:
                control_keys(0x01); /* ARP requestor */
                break;

            case 10:
                control_keys(0x0e); /* Makedir */
                break;

            case 11:                /* changedir 'string' */
                if (strlen(resultmsg->rm_Args[0]) > 10) {
#ifdef DEBUG
                    auto_req(&resultmsg->rm_Args[0][10]);
#endif
                    strcpy(buf,&resultmsg->rm_Args[0][10]);
                    changedir(buf);
                    refresh();
                } else
                    auto_req("Bad arguments to CHANGEDIR.");
                break;

            case 12:         /* sort by day */
                sort(4);
                refresh();
                break;

            default:
                resultmsg->rm_Result1 = 5;  /* shows an error code */
                resultmsg->rm_Result2 = 0;  /* no secondary        */

                if (Strcmp(strbuf, resultmsg->rm_Args[0]) == 0) {
                    sprintf(buf,"End keyword not found in -%s.flex-.",
                        strbuf);
                    auto_req(buf);
                    ReplyMsg(resultmsg);
                    WaitRexxPort(&myrexxport);
                    CleanupRexx();
                    return;
                }
                sprintf(buf,"Bad command -%s- from macro %s.flex",
                    resultmsg->rm_Args[0],strbuf);
                auto_req(buf);
                break;
        }
        ReplyMsg(resultmsg);
        drawcur();
    }   /* end of forever */
}
SHAR_EOF
#	End of shell archive
exit 0
-- 
Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.