home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d0xx / d034 / browser.lha / Browser / browser.c next >
Encoding:
C/C++ Source or Header  |  1986-09-03  |  14.0 KB  |  550 lines

  1. #define MANX
  2.  
  3. /*
  4.  * browser - Rummage around on disks.
  5.  *
  6.  *    copyright (c) 1986, Mike Meyer
  7.  *
  8.  * Permission is hereby granted to distribute this program, so long as this
  9.  * source file is distributed with it, and this copyright notice is not
  10.  * removed from the file.
  11.  *
  12.  * Locks, general -    do I need a stack of locks, one per directory level?
  13.  *            do I have to free the lock in done?
  14.  */
  15.  
  16. #ifdef MANX
  17. #include <functions.h>
  18. #endif
  19. #include <exec/types.h>
  20. #include <graphics/gfxbase.h>
  21. #include <libraries/dos.h>
  22. #include <libraries/dosextens.h>
  23. #include <intuition/intuition.h>
  24. #include <stdio.h>
  25. #define INTUITION_REV        1L
  26. #define GRAPHICS_REV        1L
  27.  
  28. #define LONGEST_NAME        80    /* Longest file name we can deal with */
  29. #define LONGEST_LINE        256    /* Longest line we will deal with */
  30. #define AVG_LINE_LENGTH        66    /* A guess, tune it if you need to */
  31.  
  32. #define UP_GADGET        ((unsigned short) 0)
  33. #define DOWN_GADGET        ((unsigned short) 1)
  34. #define SCROLL_GADGET    ((unsigned short) 2)
  35. #define GWIDTH            16    /* Width of my two gadgets */
  36. #define GHEIGHT            9    /* and their heights */
  37.  
  38. #define FIRST 18L
  39. /*
  40.  * Pictures for the up and down arrows
  41.  */
  42. static USHORT arrows[2][GHEIGHT] = {
  43.     {0xFE7F, 0xFC3F, 0xF81F, 0xF00F,    /* Up */
  44.      0xFC3F, 0xFC3F, 0xFC3F, 0xFC3F, 0xFC3F},
  45.     {0xFC3F, 0xFC3F, 0xFC3F, 0xFC3F,    /* Down */
  46.      0xFC3F, 0xF00F, 0xF81F, 0xFC3F, 0xFE7F}
  47.     } ;
  48. /*
  49.  * Now, the Image structures that use the arrows
  50.  */
  51. static struct Image Arrow_Image[2] = {
  52.     {0, 0, GWIDTH, GHEIGHT, 1, arrows[UP_GADGET], 1, 0,  /* Up */
  53.         /*(struct Image *)*/ NULL},
  54.     {0, 0, GWIDTH, GHEIGHT, 1, arrows[DOWN_GADGET], 1, 0,  /* Down */
  55.         /*(struct Image *)*/ NULL}
  56.     };
  57. /*
  58.  * Now, my Gadget structures
  59.  */
  60. static struct PropInfo prop;
  61. static struct Image prop_img;
  62.  
  63. static struct Gadget Scroll_Gadget = {
  64.     /*(struct Gadget *)*/ NULL,    /* End of Gadgets */
  65.     0,11+GHEIGHT,                /* Left, Top */
  66.     GWIDTH, -((GHEIGHT*2)+11),
  67.     GRELHEIGHT | GADGHCOMP | GADGDISABLED,
  68.     RELVERIFY,                    /* Messages when released */
  69.     PROPGADGET,
  70.     (APTR) &prop_img,
  71.     (APTR) NULL,                /* No rendering image, using HCOMP */
  72.     /*(struct IntuiText *)*/ NULL,
  73.     0L,                            /* No mutex */
  74.     (APTR) &prop,
  75.     SCROLL_GADGET,                /* Yes, this is the scroll gadget */
  76.     (APTR) NULL                    /* And nothing of mine */
  77. };
  78.  
  79. static struct Gadget Up_Gadget = {
  80.     &Scroll_Gadget,                /* next gadget is scroll */
  81.     0,11,                        /* Left, Top */
  82.     GWIDTH, GHEIGHT,
  83.     GADGIMAGE | GADGDISABLED | GADGHCOMP,
  84.     RELVERIFY,                    /* Messages when released */
  85.     BOOLGADGET,                    /* These be boolean gadgets */
  86.     (APTR) &(Arrow_Image[UP_GADGET]),
  87.     (APTR) NULL,                /* No rendering image, using HCOMP */
  88.     /*(struct IntuiText *)*/ NULL,
  89.     0L,                            /* No mutex */
  90.     (APTR) NULL,                /* Nothing special */
  91.     UP_GADGET,                    /* Yes, this is the up gadget */
  92.     (APTR) NULL                    /* And nothing of mine */
  93. };
  94.  
  95. static struct Gadget Down_Gadget = {
  96.     &Up_Gadget,                    /* Next gadget is Up_Gadget */
  97.     0, 1 - GHEIGHT,                /* Left, Top */
  98.     GWIDTH, GHEIGHT,
  99.     GRELBOTTOM | GADGIMAGE |    /* Standard bottom border gadget */
  100.     GADGDISABLED | GADGHCOMP,
  101.     RELVERIFY | BOTTOMBORDER,    /* Messages when released */
  102.     BOOLGADGET,                    /* These be boolean gadgets */
  103.     (APTR) &(Arrow_Image[DOWN_GADGET]),
  104.     (APTR) NULL,                /* No rendering image, using HCOMP */
  105.     /*(struct IntuiText *)*/ NULL,
  106.     0L,                            /* No mutex */
  107.     (APTR) NULL,                /* Nothing special */
  108.     DOWN_GADGET,                /* Yes, this is the up gadget */
  109.     (APTR) NULL                    /* And nothing of mine */
  110.     }; 
  111.  
  112. /*
  113.  * Now, the window for it all
  114.  */
  115. static struct NewWindow New_Window = {
  116. #ifdef DEBUG
  117.     0, 0, 540, 150,            /* smaller window to left printf's show up */
  118. #else
  119.     0, 0, 640, 200,            /* Full screen */
  120. #endif
  121.     -1L, -1L,                /* Default pens */
  122.     MENUPICK | CLOSEWINDOW        /* I want to know about menupicks */
  123.     | GADGETUP,            /* Window closes and gadgets */
  124.     ACTIVATE            /* Standard window */
  125.     | SMART_REFRESH | NOCAREREFRESH | SIZEBBOTTOM
  126.     | WINDOWSIZING | WINDOWDEPTH | WINDOWCLOSE | WINDOWDRAG,
  127.     &Down_Gadget,            /* Add my gadgets */
  128.     /*(struct Image *)*/ NULL,
  129.     "   Browser 0.1 with Bob Leivian's additions",    /* Title */
  130.     /*(struct Screen *)*/NULL,
  131.     /*(struct BitMap *)*/NULL,
  132.     100, 40,            /* Minimum sizes */
  133.     640, 200,            /* Maximum sizes */
  134.     WBENCHSCREEN            /* and put it on the workbench */
  135.     } ;
  136.  
  137. /*
  138.  * My very own variables (mostly for done)
  139.  */
  140. static struct Window    *My_Window = NULL ;
  141. static FILE        *infile = NULL ;    /* Current input file */
  142. #ifdef MANX
  143. static void        Page_File();
  144. #else
  145. static void        Page_File(unsigned short) ;
  146. #endif
  147.  
  148. /*
  149.  * And someone else's variables
  150.  */
  151. struct IntuitionBase    *IntuitionBase ;
  152. struct GfxBase        *GfxBase ;
  153. extern struct Menu    *AutoMenu ;
  154.  
  155. /*
  156.  * Finally, declare the string twiddling functions as voids
  157.  */
  158. #ifdef MANX
  159. void    strcat(), strcpy(), strncat();
  160. #else
  161. void    strcat(char *, char *), strcpy(char *, char *) ,
  162.     strncat(char *, char *, int) ;
  163. #endif
  164.  
  165. main() {
  166.     register struct IntuiMessage    *message;
  167.     register unsigned short        class, code ;
  168.  
  169.     /* Set up the world this lives in */
  170.     if ((IntuitionBase = (struct IntuitionBase *)
  171.         OpenLibrary("intuition.library", INTUITION_REV)) == NULL)
  172.         done(20, "can't open intuition library") ;
  173.  
  174.     if ((GfxBase = (struct GfxBase *)
  175.         OpenLibrary("graphics.library", GRAPHICS_REV)) == NULL)
  176.         done(20, "can't open graphics library") ;
  177.  
  178.     /* set up the scroll bar */
  179.     prop.Flags = FREEVERT | AUTOKNOB;
  180.     prop.VertBody = 0x1000;
  181.  
  182.     if ((My_Window = (struct Window *) OpenWindow(&New_Window)) == NULL)
  183.         done(20, "can't open the window") ;
  184.  
  185.     SetAPen(My_Window -> RPort, 1L) ;    /* Should be default! */
  186.  
  187.     show_message("Pick Disk with Menu Button ");
  188.  
  189.     /* Set up the first menu level */
  190.     Menu_Init() ;
  191.     Menu_Add("disks ", 1L) ;
  192.     Menu_Item_Add("df0:", ITEMENABLED, 0L, 0) ;
  193.     Menu_Item_Add("df1:", ITEMENABLED, 0L, 0) ;
  194.     Menu_Item_Add("ram:", ITEMENABLED, 0L, 0) ;
  195.     SetMenuStrip(My_Window, AutoMenu) ;
  196.  
  197.     /* Now spin on messages, handling them as they arrive */
  198.     for (;;) {
  199.         Wait(1L << (long) My_Window -> UserPort -> mp_SigBit) ;
  200.         while ((message = GetMsg(My_Window -> UserPort)) != NULL) {
  201.             class = message -> Class ;
  202.             code = message -> Code ;
  203.             ReplyMsg(message) ;
  204. #ifdef DEBUG
  205. printf("message:%d\n", class);
  206. #endif
  207.             switch (class) {
  208.                 case CLOSEWINDOW:
  209.                     done(0, NULL) ;
  210.  
  211.                 case MENUPICK:
  212.                     if (code != MENUNULL)
  213.                         Examine_Menu_Pick(code) ;
  214.                     break ;
  215.  
  216.                 case GADGETUP:
  217.                     Page_File(((struct Gadget *) (message -> IAddress)) -> GadgetID) ;
  218.                     break ;
  219.  
  220.                 default:
  221.                     printf("browser: intuition event 0x%x\n", class) ;
  222.                     done(20, "unexpected intution event") ;
  223.                     break ;
  224.                 }
  225.             }
  226.         }
  227.     done(20, "broke out of never-breaking loop!") ;
  228. }
  229.  
  230.  
  231. /*
  232.  * Examine_Menu_Pick - takes a menu pick, and twiddles the state variables
  233.  *    to match that pick.
  234.  */
  235. static
  236. Examine_Menu_Pick(Menu_Number)
  237. unsigned short Menu_Number; 
  238. {
  239.     register unsigned short    level, i, dirp ;
  240.     register char        *cp ;
  241.     char            *name, *index() ;
  242. #ifdef MANX
  243.     struct MenuItem        *ItemAddress(/* struct Menu *, long*/) ;
  244. #else
  245.     struct MenuItem        *ItemAddress(struct Menu *, unsigned short) ;
  246. #endif
  247.     /* State variables that describe the current directory */
  248.     static char        Dir_Name[LONGEST_NAME] ;
  249.     static unsigned short    Menu_Level = 0 ;
  250.  
  251.     name = ((struct IntuiText *)
  252.         (ItemAddress(AutoMenu, (long) Menu_Number) -> ItemFill)) -> IText ;
  253.     level = MENUNUM(Menu_Number) ;
  254.  
  255.     /* Got what we want, so clear the menu to avoid confusing the user */
  256.     ClearMenuStrip(My_Window);
  257.     OffGadget((APTR)&Down_Gadget, My_Window, NULL);
  258.     OffGadget((APTR)&Up_Gadget, My_Window, NULL);
  259.     OffGadget((APTR)&Scroll_Gadget, My_Window, NULL);
  260.  
  261.     /* set dirp to FALSE if the name is not a directory or disk */
  262.     dirp = (index(name, '/') != NULL || index(name, ':') != NULL) ;
  263.  
  264.     /* First, set the directory name right */
  265.     if (level > Menu_Level)            /* Not possible, die */
  266.         done(20, "impossible menu value returned") ;
  267.     else if (level == 0)            /* picked a new disk */
  268.         Dir_Name[0] = '\0' ;
  269.     else if (level < Menu_Level) {        /* Throw away some levels */
  270.         for (i = 1, cp = index(Dir_Name, ':'); i < level; i++) {
  271.             if (cp == NULL) done(20, "broken file name") ;
  272.             cp = index(cp, '/') ;
  273.         }
  274.         if (cp == NULL) done(20, "broken file name") ;
  275.         *++cp = '\0' ;
  276.     }
  277.     /* else Menu_Level == level, chose a file at current level */
  278.  
  279.     /* Now, fix up the menu and it's state variable */
  280.     while (Menu_Level > level) {
  281.         Menu_Level-- ;
  282.         Menu_Pop() ;
  283.     }
  284.  
  285.     /* If we added a directory, tack it onto the name */
  286.     if (dirp) {
  287.         Menu_Level++ ;
  288.         strncat(Dir_Name, name,    LONGEST_NAME - strlen(Dir_Name) - 1) ;
  289.     }
  290.  
  291.     /* Now, tell the user all about it */
  292.     if (dirp)
  293.         Add_Dir(Dir_Name, name) ;
  294.     else
  295.         Display_File(Dir_Name, name) ;
  296.     SetMenuStrip(My_Window, AutoMenu) ;
  297. }
  298.  
  299. /*
  300.  * Add_Dir - given a dir and a name, add the menu name with the files in
  301.  *    dir as entries.
  302.  */
  303. static
  304. Add_Dir(dir, name) char *dir, *name; {
  305.     struct FileInfoBlock        File_Info ;
  306.     register char            *last_char ;
  307. #ifdef MANX
  308.     register struct FileLock    *my_lock;
  309. #else
  310.     register struct FileLock    *my_lock, *Lock(char *, int) ;
  311. #endif
  312.     unsigned short            count ;
  313.     static char            Name_Buf[LONGEST_NAME] ;
  314.  
  315.     /* Fix up the trailing / if it needs it */
  316.     last_char = &dir[strlen(dir) - 1] ;
  317.     if (*last_char == '/') *last_char = '\0' ;
  318.  
  319.     /* Now, start on the directory */
  320.     if ((my_lock = Lock(dir, ACCESS_READ)) == NULL) {
  321. #ifdef    DEBUG
  322.         printf("browser: error trying to lock %s, IoErr: %d\n", dir, IoErr()) ;
  323. #endif
  324.         done(20, "can't get lock on file") ;
  325.     }
  326.  
  327.     if (!Examine(my_lock, &File_Info)) done(20, "can't examine file") ;
  328.     if (File_Info . fib_DirEntryType < 0)
  329.         done(20, "Add_Dir called with a non-directory") ;
  330.  
  331.     Menu_Add(name, TRUE) ;
  332.  
  333.     show_message("Loading Directory          ");
  334.  
  335.     for (ExNext(my_lock, &File_Info), count = 0;
  336.          IoErr() != ERROR_NO_MORE_ENTRIES;
  337.          ExNext(my_lock, &File_Info), count++)
  338.         if (File_Info . fib_DirEntryType < 0)
  339.             /* file */
  340.             Menu_Item_Add(File_Info . fib_FileName, ITEMENABLED, 0L, 0) ;
  341.         else {
  342.             /* directory */
  343.             strcpy(Name_Buf, File_Info . fib_FileName) ;
  344. #ifdef DEBUG
  345. printf("dir name: %s\n", Name_Buf);
  346. #endif
  347.             strcat(Name_Buf, "/");
  348.             Menu_Item_Add(Name_Buf, ITEMENABLED, 0L, 0) ;
  349.         }
  350.     if (count == 0) Menu_Item_Add("EMPTY", 0L, 0L, 0) ;
  351.  
  352.     show_message("Directory Available         ");
  353.  
  354.     /* Put everything back */
  355.     if (*last_char == '\0') *last_char = '/' ;
  356.     UnLock(my_lock) ;
  357. }
  358.  
  359. /*
  360.  * Display_File - given a directory path and file name, put the first page of
  361.  *    the file in the window.
  362.  */
  363.  
  364. long aprox_lines, file_size;
  365. long Page_Length = 22L;
  366.  
  367.  
  368. static
  369. Display_File(dir, name)
  370. char *dir, *name;
  371. {
  372.     static char    File_Name[LONGEST_NAME];
  373.     FILE *fopen();
  374.     long ftell();
  375.     long i;
  376.  
  377.     /* Get the file name */
  378.     strcpy(File_Name, dir);
  379.     strcat(File_Name, name);
  380.  
  381.     if (infile != NULL)
  382.         fclose(infile);
  383.  
  384.     if ((infile = fopen(File_Name, "r")) == NULL) {
  385. #ifdef    DEBUG
  386.         printf("Can't open File: %s\n", File_Name) ;
  387. #endif
  388.         done(20, "can't open file") ;
  389.     }
  390.  
  391.     /* set up the prop gadget for scrolling */
  392.     fseek(infile, 0L, 2);
  393.     file_size = ftell(infile);
  394.     aprox_lines = file_size / AVG_LINE_LENGTH;
  395.     prop.Flags = FREEVERT | AUTOKNOB;
  396.     if (Page_Length >= aprox_lines)
  397.         i = 0xAAAA; /* guess 66% for small files */
  398.     else
  399.         i = (Page_Length * 0x10000) / aprox_lines; /* FFFF=100% - 0000=0% */
  400.  
  401.     prop.VertBody = i;
  402.     prop.VertPot = 0;    /* always start at begin of file */
  403.     fseek(infile, 0L, 0);
  404.  
  405.     /* enable the scroll bar */
  406.     OnGadget((APTR)&Down_Gadget, My_Window, NULL);
  407.     OnGadget((APTR)&Up_Gadget, My_Window, NULL);
  408.     OnGadget((APTR)&Scroll_Gadget, My_Window, NULL);
  409.  
  410.     Page_File(DOWN_GADGET);        /* Down from page 0 */
  411. }
  412.  
  413. /*
  414.  * Page_File - move the file up or down one "page"
  415.  */
  416. static void
  417. Page_File(direction) 
  418. int direction; 
  419. {
  420.     register long where;
  421.     static char    buffer[LONGEST_LINE];
  422.     static char edited[84]; /* allow room for a tab at end */
  423.     int end_flag = 0;
  424.     long tabs, size, Line_Length;
  425.     int i,j;
  426.     long new_pos;
  427.     char *p;
  428.  
  429.     if (infile == NULL) return ;
  430.  
  431.     Page_Length = (My_Window -> Height - 20) / 8 ;
  432.     Line_Length = (My_Window -> Width - (3+FIRST)) / 8;
  433.  
  434.     switch (direction) {
  435.     case UP_GADGET:        /* Seek back one page */
  436.         if (ftell(infile) < AVG_LINE_LENGTH * (Page_Length + 2))
  437.             fseek(infile, 0L, 0);
  438.         else {
  439.             fseek(infile, (long) -Page_Length * AVG_LINE_LENGTH, 1) ;
  440.             fgets(buffer, LONGEST_LINE, infile) ;
  441.         }
  442.         break;
  443.  
  444.     case DOWN_GADGET:
  445.         /* we are already down one screen, just print from where we are */
  446.         break;
  447.  
  448.     case SCROLL_GADGET:
  449.         /* compute new position based on the users scroll bar pot */
  450.         new_pos = (file_size * prop.VertPot) / 0x10000;
  451.  
  452. #ifdef DEBUG
  453. printf("file size: %ld, new pos:%ld\n", file_size, new_pos);
  454. #endif
  455.  
  456.         /* if at end of file, back up 1/2 page */
  457.         if (new_pos >= file_size)
  458.             new_pos = file_size - ((Page_Length / 2) * AVG_LINE_LENGTH);
  459.         fseek(infile, new_pos, 0);
  460.  
  461.         /* discard a partial line */
  462.         if (new_pos)
  463.             fgets(buffer, LONGEST_LINE, infile);
  464.         break;
  465.  
  466.     default:
  467.             done(20, "Illegal argument to Page_File");
  468.     }
  469.  
  470.  
  471.     /* now put out one page's worth of the file's data */
  472.     for (where = 17, j = Page_Length; j--; where += 8) {
  473.         Move(My_Window -> RPort, FIRST, where) ;
  474.  
  475.         /* blank the buffer first */
  476.         for (i = 0; i < 80; i++)
  477.             edited[i] = ' ';
  478.  
  479.         if (!end_flag) {
  480.             if (fgets(buffer, LONGEST_LINE, infile) == NULL) 
  481.                 end_flag = TRUE;
  482.             else {
  483.                 size = strlen(buffer);
  484.  
  485.                 /* remove the newline */
  486.                 buffer[size-1] = '\0';
  487.                 size--;
  488.  
  489.                 p = buffer;
  490.                 size = 0;
  491.  
  492.                 /* edit the buffer for tabs and non-printables */
  493.                 while(*p) {
  494.                     if (*p == '\t') {
  495.                         do {
  496.                             edited[size++] = ' ';
  497.                         } while(size&3);
  498.                     } else if(*p < ' ') {
  499.                         edited[size++] = '^';
  500.                         edited[size++] = *p + '@';
  501.                     } else 
  502.                         edited[size++] = *p;
  503.  
  504.                     p++;
  505.  
  506.                     /* mark the line as longer than the window */
  507.                     if (size >= Line_Length) {
  508.                         edited[size-1] = '>';
  509.                         break;
  510.                     }
  511.                 }
  512.             }
  513.         }
  514.         Text(My_Window -> RPort, edited, Line_Length);
  515.     } /* for 1 to size of window */
  516. }
  517.  
  518. /*
  519.  * done - just close everything that's open, and exit.
  520.  */
  521. static
  522. done(how, why)
  523. int how;
  524. char *why; 
  525. {
  526.  
  527.     if (My_Window) {
  528.         ClearMenuStrip(My_Window) ;
  529.         Menu_Clear() ;
  530.         CloseWindow(My_Window) ;
  531.     }
  532.     if (GfxBase) CloseLibrary(GfxBase) ;
  533.     if (IntuitionBase) CloseLibrary(IntuitionBase) ;
  534.     if (infile) fclose(infile) ;
  535.  
  536.     if (why)
  537.         printf("browser: %s\n", why) ;
  538.     (void) OpenWorkBench() ;
  539.     exit(how) ;
  540. }
  541.  
  542. show_message(s)
  543. char *s;
  544. {
  545.     Move(My_Window -> RPort, FIRST, 17L);
  546.     Text(My_Window -> RPort, s, (long) strlen(s));
  547.     Move(My_Window -> RPort, FIRST, 25L);
  548.     Text(My_Window -> RPort, "                    ", 20L);
  549. }
  550.