home *** CD-ROM | disk | FTP | other *** search
- Subject: Amiga file browser
- From: Mike Meyer <harvard!topaz!hplabs!ucbvax!ucbopal.berkeley.edu!mwm>
- Newsgroups: mod.sources
- Approved: jpn@panda.UUCP
-
- Mod.sources: Volume 4, Issue 40
- Submitted by: Mike (I'll be mellow when I'm dead) Meyer <ucbvax!ucbopal!mwm>
-
- # This is a shell archive. Remove anything before this line, then
- # unpack it by saving it in a file and typing "sh file". (Files
- # unpacked will be owned by you and have default permissions.)
- #
- # This archive contains:
- # README browser.c menustack.c
-
- echo x - README
- sed 's/^ //' > "README" << '//E*O*F README//'
- Here we have a file browser for the Amiga. 50% based on the the PARC
- browsers,and 50% based on a browser I wrote for Unix long ago (whose
- name, I now realize, was probably inspired by the PARC browsers).
-
- This is a "level 0" version. Useable, but it needs some things done
- to. I've got more important things to do, so I'm turning it loose to
- the net, in the hopes that someone else will improve it before I get
- back to it.
-
- Things that need to be fixed:
-
- 1) Theres a loose pointer in there somewhere, but it only seem
- to mangle things if DEBUG is turned on. Not sure what's up.
-
- 2) The UP and DOWN gadgets need to turn into a scroll bar gadget.
-
- 3) The routine that pages the file needs to be re-written to
- use the console driver, and handle lines longer than the
- window is wide in a more intelligent manner.
-
- 4) The initial (disks) menu needs to look to see what is
- really there, instead of just giving you the default three.
- Putting in the assigned'ed things at the same time might not
- be a bad idea.
-
- Should you fix #1, or add any of #'s 2-4, please send me the source.
- Likewise, any ideas you have or implement, let me know, and I'll see
- about getting them into the first real version.
-
- <mike
-
-
- //E*O*F README//
-
- echo x - browser.c
- sed 's/^ //' > "browser.c" << '//E*O*F browser.c//'
- /*
- * browser - Rummage around on disks.
- *
- * copyright (c) 1986, Mike Meyer
- *
- * Permission is hereby granted to distribute this program, so long as this
- * source file is distributed with it, and this copyright notice is not
- * removed from the file.
- *
- * Locks, general - do I need a stack of locks, one per directory level?
- * do I have to free the lock in done?
- */
-
- #include <exec/types.h>
- #include <graphics/gfxbase.h>
- #include <libraries/dos.h>
- #include <libraries/dosextens.h>
- #include <intuition/intuition.h>
- #include <stdio.h>
-
- #define INTUITION_REV 1
- #define GRAPHICS_REV 1
-
- #define LONGEST_NAME 80 /* Longest file name we can deal with */
- #define LONGEST_LINE 256 /* Longest line we will deal with */
- #define AVG_LINE_LENGTH 66 /* A guess, tune it if you need to */
-
- #define UP_GADGET ((unsigned short) 0)
- #define DOWN_GADGET ((unsigned short) 1)
- #define GWIDTH 16 /* Width of my two gadgets */
- #define GHEIGHT 9 /* and their heights */
-
- /*
- * Pictures for the up and down arrows
- */
- static USHORT arrows[2][GHEIGHT] = {
- {0xFE7F, 0xFC3F, 0xFA5F, 0xF66F, /* Up */
- 0xFE7F, 0xFE7F, 0xFE7F, 0xFE7F, 0xFE7F},
- {0xFE7F, 0xFE7F, 0xFE7F, 0xFE7F, /* Down */
- 0xFE7F, 0xF66F, 0xFA5F, 0xFC3F, 0xFE7F}
- } ;
- /*
- * Now, the Image structures that use the arrows
- */
- static struct Image Arrow_Image[2] = {
- {0, 0, GWIDTH, GHEIGHT, 1, arrows[UP_GADGET], 1, 0, /* Up */
- (struct Image *) NULL},
- {0, 0, GWIDTH, GHEIGHT, 1, arrows[DOWN_GADGET], 1, 0, /* Down */
- (struct Image *) NULL}
- } ;
- /*
- * Now, my two Gadget structures
- */
- static struct Gadget Up_Gadget = {
- (struct Gadget *) NULL,
- 0, 1 - GHEIGHT, /* Left, Top */
- GWIDTH, GHEIGHT,
- GRELBOTTOM | GADGIMAGE /* Standard bottom border gadget */
- | GADGHCOMP,
- RELVERIFY | BOTTOMBORDER, /* Messages when released */
- BOOLGADGET, /* These be boolean gadgets */
- (APTR) &(Arrow_Image[UP_GADGET]),
- (APTR) NULL, /* No rendering image, using HCOMP */
- (struct IntuiText *) NULL,
- 0, /* No mutex */
- (APTR) NULL, /* Nothing special */
- UP_GADGET, /* Yes, this is the up gadget */
- (APTR) NULL /* And nothing of mine */
- } ;
-
- static struct Gadget Down_Gadget = {
- &Up_Gadget, /* Next gadget is Up_Gadget */
- GWIDTH + 2, 1 - GHEIGHT, /* Left, Top */
- GWIDTH, GHEIGHT,
- GRELBOTTOM | GADGIMAGE /* Standard bottom border gadget */
- | GADGHCOMP,
- RELVERIFY | BOTTOMBORDER, /* Messages when released */
- BOOLGADGET, /* These be boolean gadgets */
- (APTR) &(Arrow_Image[DOWN_GADGET]),
- (APTR) NULL, /* No rendering image, using HCOMP */
- (struct IntuiText *) NULL,
- 0, /* No mutex */
- (APTR) NULL, /* Nothing special */
- DOWN_GADGET, /* Yes, this is the up gadget */
- (APTR) NULL /* And nothing of mine */
- } ;
- /*
- * Now, the window for it all
- */
- static struct NewWindow New_Window = {
- 0, 0, 640, 200, /* Full screen */
- -1, -1, /* Default pens */
- MENUPICK | CLOSEWINDOW /* I want to know about menupicks */
- | GADGETUP, /* Window closes and gadgets */
- ACTIVATE /* Standard window */
- | SMART_REFRESH | NOCAREREFRESH | SIZEBBOTTOM
- | WINDOWSIZING | WINDOWDEPTH | WINDOWCLOSE | WINDOWDRAG,
- &Down_Gadget, /* Add my gadgets */
- (struct Image *) NULL,
- "Browser 0.0", /* Title */
- (struct Screen *) NULL,
- (struct BitMap *) NULL,
- 100, 40, /* Minimum sizes */
- 640, 200, /* Maximum sizes */
- WBENCHSCREEN /* and put it on the workbench */
- } ;
- /*
- * My very own variables (mostly for done)
- */
- static struct Window *My_Window = NULL ;
- static FILE *infile = NULL ; /* Current input file */
- static void Page_File(unsigned short) ;
-
- /*
- * And someone else's variables
- */
- struct IntuitionBase *IntuitionBase ;
- struct GfxBase *GfxBase ;
- extern struct Menu *AutoMenu ;
-
- /*
- * Finally, declare the string twiddling functions as voids
- */
- void strcat(char *, char *), strcpy(char *, char *) ,
- strncat(char *, char *, int) ;
-
- #ifdef DEBUG
- main() {
- #else
- _main() {
- #endif
- register struct IntuiMessage *message, *GetMsg(struct MsgPort *) ;
- register unsigned short class, code ;
-
- /* Set up the world this lives in */
-
- if ((IntuitionBase = (struct IntuitionBase *)
- OpenLibrary("intuition.library", INTUITION_REV)) == NULL)
- done(20, "can't open intuition library") ;
-
- if ((GfxBase = (struct GfxBase *)
- OpenLibrary("graphics.library", GRAPHICS_REV)) == NULL)
- done(20, "can't open graphics library") ;
-
- if ((My_Window = (struct Window *) OpenWindow(&New_Window)) == NULL)
- done(20, "can't open the window") ;
-
- SetAPen(My_Window -> RPort, 1) ; /* Should be default! */
-
- /* Set up the first menu level */
- Menu_Init() ;
- Menu_Add("disks ", TRUE) ;
- Menu_Item_Add("df0:", ITEMENABLED, 0, 0) ;
- Menu_Item_Add("df1:", ITEMENABLED, 0, 0) ;
- Menu_Item_Add("ram:", ITEMENABLED, 0, 0) ;
- SetMenuStrip(My_Window, AutoMenu) ;
-
- /* Now spin on messages, handling them as they arrive */
- for (;;) {
- Wait(1 << My_Window -> UserPort -> mp_SigBit) ;
- while (message = GetMsg(My_Window -> UserPort)) {
- class = message -> Class ;
- code = message -> Code ;
- ReplyMsg(message) ;
-
- switch (class) {
- case CLOSEWINDOW:
- done(0, "exit") ;
-
- case MENUPICK:
- if (code != MENUNULL)
- Examine_Menu_Pick(code) ;
- break ;
-
- case GADGETUP:
- Page_File(((struct Gadget *) (message -> IAddress)) -> GadgetID) ;
- break ;
-
- default:
- #ifdef DEBUG
- printf("browser: intuition event 0x%x\n", class) ;
- #endif
- done(20, "unexpected intution event") ;
- break ;
- }
- }
- }
- done(20, "broke out of never-breaking loop!") ;
- }
- /*
- * Examine_Menu_Pick - takes a menu pick, and twiddles the state variables
- * to match that pick.
- */
- static
- Examine_Menu_Pick(Menu_Number) unsigned short Menu_Number; {
- register unsigned short level, i, dirp ;
- register char *cp ;
- char *name, *strchr(char *, int) ;
- struct MenuItem *ItemAddress(struct Menu *, unsigned short) ;
- /* State variables that describe the current directory */
- static char Dir_Name[LONGEST_NAME] ;
- static unsigned short Menu_Level = 0 ;
-
- name = ((struct IntuiText *)
- (ItemAddress(AutoMenu, Menu_Number) -> ItemFill)) -> IText ;
- level = MENUNUM(Menu_Number) ;
-
- /* Got what we want, so clear the menu to avoid confusing the user */
- ClearMenuStrip(My_Window) ;
-
- /* set dirp to FALSE if the name is not a directory or disk */
- dirp = (strchr(name, '/') != NULL || strchr(name, ':') != NULL) ;
-
- /* First, set the directory name right */
- if (level > Menu_Level) /* Not possible, die */
- done(20, "impossible menu value returned") ;
- else if (level == 0) /* picked a new disk */
- Dir_Name[0] = '\0' ;
- else if (level < Menu_Level) { /* Throw away some levels */
- for (i = 1, cp = strchr(Dir_Name, ':'); i < level; i++) {
- if (cp == NULL) done(20, "broken file name") ;
- cp = strchr(cp, '/') ;
- }
- if (cp == NULL) done(20, "broken file name") ;
- *++cp = '\0' ;
- }
- /* else Menu_Level == level, chose a file at current level */
-
- /* Now, fix up the menu and it's state variable */
- while (Menu_Level > level) {
- Menu_Level-- ;
- Menu_Pop() ;
- }
-
- /* If we added a directory, tack it onto the name */
- if (dirp) {
- Menu_Level++ ;
- strncat(Dir_Name, name, LONGEST_NAME - strlen(Dir_Name) - 1) ;
- }
-
- /* Now, tell the user all about it */
- if (dirp) Add_Dir(Dir_Name, name) ;
- else Display_File(Dir_Name, name) ;
- SetMenuStrip(My_Window, AutoMenu) ;
- }
- /*
- * Add_Dir - given a dir and a name, add the menu name with the files in
- * dir as entries.
- */
- static
- Add_Dir(dir, name) char *dir, *name; {
- register char *last_char ;
- register struct FileLock *my_lock, *Lock(char *, int) ;
- unsigned short count ;
- struct FileInfoBlock File_Info ;
- static char Name_Buf[LONGEST_NAME] ;
-
- /* Fix up the trailing / if it needs it */
- last_char = &dir[strlen(dir) - 1] ;
- if (*last_char == '/') *last_char = '\0' ;
-
- /* Now, start on the directory */
- if ((my_lock = Lock(dir, ACCESS_READ)) == NULL) {
- #ifdef DEBUG
- printf("browser: error trying to lock %s, IoErr says %d\n",
- dir, IoErr()) ;
- #endif
- done(20, "can't get lock on file") ;
- }
-
- if (!Examine(my_lock, &File_Info)) done(20, "can't examine file") ;
- if (File_Info . fib_DirEntryType < 0)
- done(20, "Add_Dir called with a non-directory") ;
-
- Menu_Add(name, TRUE) ;
- for (ExNext(my_lock, &File_Info), count = 0;
- IoErr() != ERROR_NO_MORE_ENTRIES;
- ExNext(my_lock, &File_Info), count++)
- if (File_Info . fib_DirEntryType < 0)
- Menu_Item_Add(File_Info . fib_FileName, ITEMENABLED,
- 0, 0) ;
- else {
- strcpy(Name_Buf, File_Info . fib_FileName) ;
- strcat(Name_Buf, "/") ;
- Menu_Item_Add(Name_Buf, ITEMENABLED, 0, 0) ;
- }
- if (count == 0) Menu_Item_Add("EMPTY", 0, 0, 0) ;
-
- /* Put everything back */
- if (*last_char == '\0') *last_char = '/' ;
- UnLock(my_lock) ;
- }
- /*
- * Display_File - given a directory path and file name, put the first page of
- * the file in the window.
- */
- static
- Display_File(dir, name) char *dir, *name; {
- static char File_Name[LONGEST_NAME] ;
- FILE *fopen(char *, char *) ;
-
- /* Get the file name */
- strcpy(File_Name, dir) ;
- strcat(File_Name, name) ;
-
- if (infile != NULL) fclose(infile) ;
- if ((infile = fopen(File_Name, "r")) == NULL) {
- #ifdef DEBUG
- printf("File: %s\n", File_Name) ;
- #endif
- done(20, "can't open file") ;
- }
- Page_File(DOWN_GADGET) ; /* Down from page 0 */
- }
- /*
- * Page_File - move the file up or down one "page"
- */
- static void
- Page_File(direction) int direction; {
- /* These two should be registers, but it the it breaks the compiler */
- short Page_Length, where ;
- static char buffer[LONGEST_LINE], *blanks ;
-
- if (infile == NULL) return ;
-
- blanks =
- " " ;
-
- Page_Length = (My_Window -> Height - 20) / 8 ;
-
- if (direction == UP_GADGET) { /* Seek back one page */
- if (ftell(infile) < AVG_LINE_LENGTH * (Page_Length + 2))
- fseek(infile, 0L, 0) ;
- else {
- fseek(infile, (long) -Page_Length * AVG_LINE_LENGTH, 1) ;
- fgets(buffer, LONGEST_LINE, infile) ;
- }
- }
- else if (direction != DOWN_GADGET)
- done(20, "Illegal argument to Page_File") ;
-
- for (where = 17; Page_Length--; where += 8) {
- Move(My_Window -> RPort, 3, where) ;
- Text(My_Window -> RPort, blanks, 79) ;
- Move(My_Window -> RPort, 3, where) ;
- if (fgets(buffer, LONGEST_LINE, infile) == NULL)
- return ;
- if (strlen(buffer) < LONGEST_LINE - 1)
- Text(My_Window -> RPort, buffer, strlen(buffer) - 1) ;
- else {
- Text(My_Window -> RPort, "Long line read!", 15) ;
- fclose(infile) ;
- infile = NULL ;
- return ;
- }
- }
- }
- /*
- * done - just close everything that's open, and exit.
- */
- static
- done(how, why) int how; char *why; {
-
- if (My_Window) {
- ClearMenuStrip(My_Window) ;
- Menu_Clear() ;
- CloseWindow(My_Window) ;
- }
- if (GfxBase) CloseLibrary(GfxBase) ;
- if (IntuitionBase) CloseLibrary(IntuitionBase) ;
- if (infile) fclose(infile) ;
-
- #ifdef DEBUG
- printf("browser: %s\n", why) ;
- #endif
- (void) OpenWorkBench() ;
- exit(how) ;
- }
-
- //E*O*F browser.c//
-
- echo x - menustack.c
- sed 's/^ //' > "menustack.c" << '//E*O*F menustack.c//'
- /*
- * Simple menu package. Needs lotsa work to handle some cases.
- *
- * Copyright 1985
- * Louis A. Mamakos
- * Software & Stuff
- * 14813 Ashford Place
- * Laurel, MD 20707
- *
- * For non-commerical use only. This program, or any modifications, may not
- * be sold or incorporated into any product without prior permission from the
- * author.
- *
- * Modified by mwm to handle "stacking" menus.
- * NB - adding item to a menu that's been "popped" back to doesn't work,
- * and probably never will.
- * I took at the subitem code at the same time - mwm
- */
-
- /* Change if your terminal isn't * x 400 */
- #define SCREENHEIGHT 200
-
- #include <exec/types.h>
- #include <exec/nodes.h>
- #include <exec/lists.h>
- #include <exec/ports.h>
- #include <exec/devices.h>
- #include <exec/memory.h>
- #include <hardware/blit.h>
- #include <graphics/copper.h>
- #include <graphics/regions.h>
- #include <graphics/rastport.h>
- #include <graphics/gfxbase.h>
- #include <graphics/gels.h>
- #include <intuition/intuition.h>
-
- #define MNUM(menu,item,sub) (SHIFTMENU(menu)|SHIFTITEM(item)|SHIFTSUB(sub))
-
- struct Mem_Node {
- struct Node mn_Node;
- struct Remember mn_Memory;
- struct Menu *mn_Menu;
- } *Top, *RemHead();
-
- static struct List Memory;
- static int Cur_Menu, Cur_MenuItem, Cur_SubItem;
- static struct Menu *LastMenu;
- static struct MenuItem *LastMenuItem;
-
- struct Menu *AutoMenu; /* menu struct being dynamically built */
-
- char *strsave(); /* Save a string in the remember list */
-
- Menu_Init()
- {
- Memory.lh_Head = (struct Node *) &(Memory.lh_Tail);
- Memory.lh_TailPred = (struct Node *) &(Memory.lh_Head);
- Memory.lh_Tail = NULL;
- Memory.lh_Type = NT_MEMORY;
- Top = NULL;
- Cur_Menu = Cur_MenuItem = -1;
- AutoMenu = LastMenu = NULL; /* no menu chain yet */
- LastMenuItem = NULL;
- }
-
- Menu_Clear()
- {
-
- while ((Top = RemHead(&Memory)) != NULL) {
- FreeRemember(&(Top->mn_Memory), TRUE);
- FreeMem(Top, sizeof(struct Mem_Node));
- }
- Menu_Init(); /* Just for safeties sake */
- }
-
- Menu_Pop()
- {
-
- if ((Top = RemHead(&Memory)) == NULL) return NULL;
- FreeRemember(&(Top->mn_Memory), TRUE);
- FreeMem(Top, sizeof(struct Mem_Node));
- /* Now, set Top back to the real list head */
- Top = (struct Mem_Node *) Memory.lh_Head;
- LastMenu = Top->mn_Menu;
- LastMenuItem = NULL; /* Wrong, but you can't add items here anyway */
- Cur_Menu--;
- }
- /*
- * Add a MENU item. Args are the text of the menu item, and an enable
- * flag. Returns an Intuition type menu number, with the MenuItem and
- * Menu SubItem being NOITEM and NOSUB. The MENUITEM part is valid.
- */
- Menu_Add(name, enabled)
- char *name;
- int enabled;
- {
- register struct Menu *m;
-
- if ((Top = (struct Mem_Node *) AllocMem(
- sizeof(struct Mem_Node), MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
- return NULL;
- Top->mn_Node.ln_Type = NT_MEMORY;
-
- if ((m = (struct Menu *)AllocRemember(&(Top->mn_Memory),
- sizeof (struct Menu), MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
- return NULL;
- Top->mn_Menu = m;
-
- if (LastMenu == NULL)
- AutoMenu = m; /* first menu on list */
- else
- LastMenu->NextMenu = m; /* link it in */
-
- LastMenuItem = NULL; /* end of previous MenuItem list */
- Cur_MenuItem = -1; /* reset item numbers */
- if (LastMenu == NULL)
- m->LeftEdge = 0;
- else
- m->LeftEdge = LastMenu->LeftEdge + LastMenu->Width;
- m->TopEdge = 0;
- m->Width = strlen(name) * 8;
- Top->mn_Node.ln_Name = m->MenuName = strsave(name);
- m->Height = 0;
- m->Flags = enabled ? MENUENABLED : 0;
- m->FirstItem = NULL;
- LastMenu = m;
-
- AddHead(&Memory, Top);
- return MNUM(++Cur_Menu, NOITEM, NOSUB);
- }
-
- /*
- * Add a menu item to the current MENU. Note that Add_Menu *must* be
- * called before this function.
- */
- Menu_Item_Add(name, flags, mux, ch)
- char *name; /* name of menu item */
- USHORT flags;
- LONG mux; /* mutual exclusion mask */
- BYTE ch; /* command sequence character, if COMMSEQ */
- {
- register struct MenuItem *m, *n;
- register struct IntuiText *it;
-
- flags &= CHECKIT|CHECKED|COMMSEQ|MENUTOGGLE|ITEMENABLED|HIGHCOMP|HIGHBOX;
- if (LastMenu == NULL)
- return MNUM(NOMENU, NOITEM, NOSUB);
-
- if ((m = (struct MenuItem *) AllocRemember(&(Top->mn_Memory),
- sizeof(struct MenuItem), MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
- return MNUM(NOMENU, NOITEM, NOSUB);
-
- if (LastMenuItem == NULL)
- LastMenu->FirstItem = m;
- else
- LastMenuItem->NextItem = m;
- m->Flags = flags | ITEMTEXT;
- /*
- * Check for highlight mode: if none selected, use HIGHCOMP
- */
- if ((m->Flags & (HIGHCOMP | HIGHBOX)) == 0)
- m->Flags |= HIGHCOMP;
- m->Command = ch;
- m->MutualExclude = mux;
- m->SubItem = NULL;
- m->ItemFill = (APTR) AllocRemember(&(Top->mn_Memory),
- sizeof(struct IntuiText), MEMF_PUBLIC | MEMF_CLEAR);
- it = (struct IntuiText *) m->ItemFill;
- it->FrontPen = AUTOFRONTPEN;
- it->BackPen = AUTOBACKPEN;
- it->DrawMode = JAM2;
- if (flags & CHECKIT)
- it->LeftEdge = CHECKWIDTH + 1;
- else
- it->LeftEdge = 1;
- it->TopEdge = 1;
- it->ITextFont = NULL; /* default font */
- it->IText = strsave(name);
- it->NextText = NULL;
- m->Width = 0;
- if (LastMenuItem == NULL) {
- m->TopEdge = 2;
- m->LeftEdge = 0;
- } else if (LastMenuItem->TopEdge + 40 > SCREENHEIGHT) {
- m->TopEdge = 2;
- m->LeftEdge = LastMenuItem->LeftEdge + LastMenuItem->Width + 12;
- } else {
- m->TopEdge = LastMenuItem->TopEdge + 12;
- m->LeftEdge = LastMenuItem->LeftEdge;
- }
- if (flags & CHECKIT)
- m->Width += CHECKWIDTH;
- if (flags & COMMSEQ)
- m->Width += COMMWIDTH + 20;
- m->Width += IntuiTextLength(m->ItemFill);
- m->Height = 10;
- /*
- * Check last menu item's width to see if it is larger than this
- * item's. If new item is larger, then update width of all other
- * items.
- */
- if (LastMenuItem) {
- if (LastMenuItem->Width > m->Width)
- m->Width = LastMenuItem->Width;
- else {
- register short delta = m->Width - LastMenuItem->Width;
-
- for (n = LastMenu->FirstItem; n != m; n = n->NextItem) {
- n->Width = m->Width;
- if (n->LeftEdge > 0) n->LeftEdge += delta;
- }
- if (m->LeftEdge > 0) m->LeftEdge += delta;
- }
- }
- LastMenuItem = m;
- return MNUM(Cur_Menu, ++Cur_MenuItem, NOSUB);
- }
-
-
-
- char *
- strsave(string) char *string; {
- char *out ;
-
- out = (char *) AllocRemember(&(Top->mn_Memory), strlen(string) + 1,
- MEMF_PUBLIC) ;
- if (out == NULL) return NULL ;
- (void) strcpy(out, string) ;
- return out ;
- }
- //E*O*F menustack.c//
-
- exit 0
-
-