/* * 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. * * modified Mark Schretlen 86-10-04 * last update 87-01-11 * */ #include #include #include #include #include #include #define INTUITION_REV 1L #define GRAPHICS_REV 1L #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 62 /* A guess, tune it if you need to */ #define FILEINFOBLOCKSIZE 256 /* m.e.s. for memory allocation in Add_Dir */ #define FUDGE 6L /* A fudge factor for the scroll bar */ #define UP_GADGET 0 /* switch flags for Gadget ID */ #define DOWN_GADGET 1 #define SCROLL_GADGET 2 #define NEW_FILE 3 #define GWIDTH 14 /* Width of gadget */ #define GHEIGHT 9 struct SpriteImage { UWORD posctl[2]; UWORD sprdata[2][15]; UWORD reserved[2]; }; #define FIRST 18L /* * Gadget structures put in browser.h */ #include "browser.h" /* * doggy sprite (M.E.S. 86-10-01) */ struct SpriteImage Doggy[34] = { 0x0002, 0x0002, /* VStart, VStop */ 0x0002, 0x0, 0x3A02, 0x0, 0x2A02, 0x1000, 0xFA02, 0x8000, 0xF9FE, 0x0, 0xFFFE, 0x0, 0x1FFE, 0x0, 0x1FFE, 0x0, 0x1FFC, 0x0, 0x1FFC, 0x0, 0x0A14, 0x0, 0x0A14, 0x0, 0x0A14, 0x0, 0x0A14, 0x0, 0x0A14, 0x0, 0x0000, 0x0000 }; /* End of Sprite */ /* * Now, the window for it all */ struct NewWindow New_Window = { 0, 0, 640, 200, /* Full screen */ -1L, -1L, /* 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 scroll gadget */ /*(struct Image *)*/ NULL, "Browser 1.2 by Mark Schretlen ;original-Mike Meyer;scroll-B.Leivian", /* Title */ /*(struct Screen *)*/NULL, /*(struct BitMap *)*/NULL, 100, 57, /* Minimum sizes */ 640, 200, /* Maximum sizes */ WBENCHSCREEN /* and put it on the workbench */ } ; /* * My very own variables (mostly for done) */ struct Window *My_Window = NULL ; static FILE *infile = NULL ; /* Current input file */ static void Page_File(unsigned short) ; /* file statistics M.E.S. 87-01-11 */ struct FStatistics *stats; struct FStatistics fileInformation = { 0L,0L,0L }; /* * 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) ; main() { register struct IntuiMessage *message,*GetMsg(struct MsgPort *); register unsigned short class, code ; APTR address; USHORT gadID; /* 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") ; /* set up the scroll bar */ prop.Flags = FREEVERT | AUTOKNOB | KNOBHIT ; prop.VertBody = 0x1000; if ((My_Window = (struct Window *) OpenWindow(&New_Window)) == NULL) done(20, "can't open the window") ; SetAPen(My_Window -> RPort,3) ; /* Should be default! */ show_message("Pick Disk with Menu Button "); /* Set up the first menu level */ Menu_Init() ; Menu_Add("disks ", 1L) ; Menu_Item_Add("df0:", ITEMENABLED, 0L, 0) ; Menu_Item_Add("df1:", ITEMENABLED, 0L, 0) ; Menu_Item_Add("df2:", ITEMENABLED, 0L, 0) ; Menu_Item_Add("DH0:", ITEMENABLED, 0L, 0) ; Menu_Item_Add("RAM:", ITEMENABLED, 0L, 0) ; Menu_Item_Add("VDK:", ITEMENABLED, 0L, 0) ; SetMenuStrip(My_Window, AutoMenu) ; SetPointer(My_Window, Doggy,15,16,0,-4); /* Now spin on messages, handling them as they arrive */ for (;;) { Wait(1L << (long) My_Window -> UserPort -> mp_SigBit) ; while (message = GetMsg(My_Window -> UserPort)) { class = message -> Class ; code = message -> Code ; address = message -> IAddress; ReplyMsg(message) ; switch (class) { case CLOSEWINDOW: done(0, NULL) ; case MENUPICK: if (code != MENUNULL) Examine_Menu_Pick(code) ; break ; case GADGETUP: gadID = ((struct Gadget *)address) -> GadgetID; Page_File(gadID); break ; default: printf("browser: intuition event 0x%x\n", class) ; 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); OffGadget((APTR)&Scroll_Gadget, My_Window, NULL); OffGadget((APTR)&Up_Gadget, My_Window,NULL); OffGadget((APTR)&Down_Gadget, My_Window,NULL); SetWindowTitles(My_Window,"Browser 1.2 by Mark Schretlen (original by Mike Meyer) ",-1); /* 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; { struct FileInfoBlock *File_Info ; register char *last_char ; register struct FileLock *my_lock, *Lock(char *, int) ; unsigned short count ; static char Name_Buf[LONGEST_NAME] ; File_Info = (struct FileInfoBlock *)AllocMem(FILEINFOBLOCKSIZE,0); /* 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) { 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) ; SetAPen(My_Window -> RPort,3) ; show_message("Loading Directory "); 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) /* file */ Menu_Item_Add(File_Info -> fib_FileName, ITEMENABLED, 0L, 0) ; else { /* directory */ strcpy(Name_Buf, File_Info -> fib_FileName) ; strcat(Name_Buf, "/"); Menu_Item_Add(Name_Buf, ITEMENABLED, 0L, 0) ; } if (count == 0) Menu_Item_Add("EMPTY", 0L, 0L, 0) ; show_message("Directory Available "); /* Put everything back */ if (*last_char == '\0') *last_char = '/' ; FreeMem(File_Info,FILEINFOBLOCKSIZE); UnLock(my_lock) ; } /* * Display_File - given a directory path and file name, put the first page of * the file in the window. */ long aprox_lines,file_size; static long Page_Length = 22L; static Display_File(dir, name) char *dir, *name; { static char File_Name[LONGEST_NAME]; FILE *fopen(); long ftell(); long i,pages; extern char *ChangeToString(); extern FILE *parsefile(); extern struct FStatistics *stats,fileInformation; char *num_of_lines,*num_of_bites; stats = &fileInformation; /* 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("Can't open File: %s\n", File_Name) ; #endif done(20, "can't open file") ; } /* set up the prop gadget for scrolling */ infile = parsefile(infile); aprox_lines = stats->lines; file_size = stats->bites; prop.Flags = FREEVERT | AUTOKNOB; if (Page_Length >= aprox_lines) i = 0xFFFF; else { pages = aprox_lines/Page_Length; if (aprox_lines%Page_Length != 0) pages++; i = 0xFFFF / pages; /* FFFF=100% - 0000=0% */ } prop.VertBody = i; prop.VertPot = 0L; fseek(infile, 0L, 0); if (Page_Length < aprox_lines) { OnGadget((APTR)&Down_Gadget,My_Window,NULL); OnGadget((APTR)&Up_Gadget,My_Window,NULL); /* enable the scroll bar */ OnGadget((APTR)&Scroll_Gadget, My_Window, NULL); } SetWindowTitles(My_Window,"Browser 1.2 **** To page, hit appropriate arrow gadget. ****",-1); Move(My_Window->RPort,FIRST + 5L ,(long)(My_Window->Height - 5L)); Text(My_Window->RPort," ",45L); Move(My_Window->RPort,FIRST + 5L ,(long)(My_Window->Height - 5L)); SetAPen(My_Window->RPort,3); /* SetSoftStyle(My_Window->RPort, FSF_UNDERLINED,255); */ Text(My_Window->RPort,name,(long)strlen(name)); Text(My_Window->RPort," ",3L); num_of_bites = ChangeToString(file_size); Text(My_Window->RPort,num_of_bites,(long)strlen(num_of_bites)); Text(My_Window->RPort," bytes",6L); Text(My_Window->RPort," ",3L); num_of_lines = ChangeToString(aprox_lines); Text(My_Window->RPort,num_of_lines,(long)strlen(num_of_lines)); Text(My_Window->RPort," lines",6L); SetAPen(My_Window->RPort,1); /* SetSoftStyle(My_Window->RPort, FS_NORMAL,255); */ Move(My_Window->RPort,FIRST,17L); Page_File((USHORT)NEW_FILE); /* Down from page 0 */ } /* * Page_File - move the file up or down one "page" */ static void Page_File(direction) USHORT direction; { long where; static char buffer[LONGEST_LINE]; static char edited[84]; /* allow room for a tab at end */ static long old_pos; static long bites_this_page; static long next_page; static long size; int end_flag = 0; long Line_Length; int i,j; long new_pos; char *p; if (infile == NULL) return ; Page_Length = ((My_Window -> Height) - 20) / 8 ; Line_Length = (My_Window -> Width - (3+FIRST)) / 8; switch(direction) { case UP_GADGET: new_pos = old_pos; old_pos = 1L; break; case DOWN_GADGET: new_pos = next_page; break; case SCROLL_GADGET: /* compute new position based on the users scroll bar pot */ new_pos = (file_size * prop.VertPot) / 0xFFFF; break; case NEW_FILE: bites_this_page = 0L; next_page = 0L; new_pos = 0L; old_pos = 1L; size = 0L; break; } if (new_pos < 0) new_pos = 0L; /* if past end of file, back up approx 1/2 page */ if (new_pos > file_size) new_pos = file_size - (bites_this_page / 2); if ( new_pos == old_pos ) return; /* no change */ where = (new_pos * 0xFFFF)/file_size ; ModifyProp(&Scroll_Gadget,My_Window,NULL,prop.Flags,0,where,0,prop.VertBody); old_pos = (new_pos + (size +2)) - bites_this_page ; /* backup one page */ bites_this_page = 0L; fseek(infile, new_pos, 0); /* discard a partial line */ if (new_pos) fgets(buffer, LONGEST_LINE, infile); /* now put out one page's worth of the file's data */ for (where = 17L, j = Page_Length; j--; where = where + 8L) { Move(My_Window -> RPort,FIRST,where ) ; /* blank the buffer first */ for (i = 0; i < 80; i++) edited[i] = ' '; if (!end_flag) { if (fgets(buffer, LONGEST_LINE, infile) == NULL) end_flag = TRUE; else { size = strlen(buffer); bites_this_page = size + bites_this_page; /* remove the newline */ buffer[size-1] = '\0'; size--; p = buffer; size = 0; /* edit the buffer for tabs and non-printables */ while(*p) { if (*p == '\t') { do { edited[size++] = ' '; } while(size&3); } else if(*p < ' ') { edited[size++] = '^'; edited[size++] = *p + '@'; } else edited[size++] = *p; p++; /* mark the line as longer than the window */ if (size >= Line_Length) { edited[size-1] = '>'; break; } } } } Text(My_Window -> RPort, edited, Line_Length); } /* for 1 page to size of window */ next_page = (bites_this_page + new_pos) - (size + 2); 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) ; if (why) printf("browser: %s\n", why) ; (void) OpenWorkBench() ; exit(how) ; } show_message(s) char *s; { Move(My_Window -> RPort, FIRST, 17L); Text(My_Window -> RPort, s, (long) strlen(s)); Move(My_Window -> RPort, FIRST, 25L); Text(My_Window -> RPort, " ", 20L); }