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.