home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 570.lha / ccd_v2.4 / ccd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-08-16  |  26.9 KB  |  1,061 lines

  1. /*       ccd
  2.  *   Cedric's ccd
  3.  *
  4.  *  (C) 1991 Cedric BEUST (beust@taloa.unice.fr)
  5.  *
  6.  * This is _NOT_ public domain. Just freeware. Redistribute to whoever
  7.  * you want, use it for your own sake but don't spread modified versions
  8.  * without my prior consent. Thanks!
  9.  *
  10.  * Compiled with DICE v2.x (a mere 'dcc -o ccd ccd.c' will do)
  11.  *
  12.  */
  13.  
  14.  
  15. #include <stdio.h>
  16. #include <assert.h>
  17. #include <proto/dos.h>
  18. #include <proto/intuition.h>
  19. #include <libraries/dos.h>
  20. #include <libraries/dosextens.h>
  21. #include <exec/memory.h>
  22. #include <exec/types.h>
  23. #include <intuition/intuition.h>
  24. #include <graphics/gfxbase.h>
  25.  
  26. #include "ccd.h"
  27. #include "win.h"
  28.  
  29. #define GRAPHICS
  30. #define VERSION "24"
  31. #define FVERSION "2.4"
  32. #define WINDOWTITLE "ccd v2.4         by Cédric BEUST"
  33.  
  34. #define CCDCONFIGFILE "ccd:.ccdconfig"
  35. #define WIDTH 640             /* width of the display */
  36. int HEIGHT = 199;            /* its height (bigger if PAL) */
  37. #define DELTAX 80           /* # of pixels between two entries */
  38. #define DELTAY 8           /* vertical step */
  39. #define UPPERX 25         /* upper corner where we start to write */
  40. #define UPPERY 10        /* ditto */
  41. #define LINESPAL 30     /* # of lines when in PAL mode */
  42. #define EXTRALINES 2   /* # of lines the config file that are not dirs */
  43.  
  44. #define BETWEEN_GADGETS 6        /* # of vert pixels between gadgets */
  45.  
  46. #define min(a,b) (a < b ? a : b)
  47.  
  48. #define NEW(v, t) v = (t *) malloc(sizeof(*v))
  49.  
  50. static char actualdir[128];
  51. struct Window *mainwindow;
  52. struct Screen *mainscreen;
  53. long IntuitionBase;
  54. struct GfxBase *GfxBase;
  55. int configlines = 0;          /* # of lines in ccdconfig */
  56. int actualline = 1;
  57. int nbvolumes = 0;          /* # of volumes found */
  58. int volumesid = 0;         /* id of the first Volume gadgets */
  59. int linesperwindow = 24;  /* # of lines on the display (more if PAL) */
  60.  
  61. USHORT *chippointer = NULL, *chippointer2 = NULL;
  62.  
  63. struct Tree_t {
  64.   struct Tree_t *brother;
  65.   struct Tree_t *son;      /* could be sister and daughter... */
  66.   char name[128];         /* last name */
  67.   char fullname[128];    /* fully qualified name */
  68.   int x;                /* position on the screen */
  69.   int line;            /* its line in the config file */
  70. } *the_tree = NULL;
  71.  
  72. WORD color0 = 0x0555,
  73.      color1 = 0x0FFF,
  74.      color2 = 0x0000,
  75.      color3 = 0x0F00;
  76.  
  77. /* Flags set through the command line */
  78.  
  79. int show_ambiguities = 0;
  80. int update_list = 0;
  81. int no_expand = 0;
  82. int no_graphics = 0;
  83. int exact_cd = 0;
  84. int verbose = 0;
  85. int workbenchscreen = 0;
  86.  
  87. /* An attempt to keep track of all the Locks I use */
  88. BPTR locklist[128];
  89. int lockpt = 0;
  90.  
  91. BPTR
  92. get_a_lock(char *name, long code)
  93. {
  94.   locklist[lockpt] = Lock(name, code);
  95.   if (locklist[lockpt])
  96.     return locklist[lockpt++];
  97.   else
  98.     return 0;
  99. }
  100.  
  101. void
  102. unlock(BPTR lock)
  103. {
  104. /*
  105.   UnLock(lock);
  106. */
  107. }
  108.  
  109. WORD
  110. atow(char *s)
  111. /* Ascii to word. s is a hex number (e.g. "3FE") */
  112. /* Return its true value */
  113. {
  114.   char *inits = s;
  115.   WORD result = 0, temp; 
  116.   while (*s) {
  117.     if (*s >= 'a') *s -= 0x20;
  118.     temp = *s - 'A' + 10;
  119.     if (*s <= '9') temp += 7;
  120.     result = result * 16 + temp;
  121.     s++;
  122.   }
  123.   return result;
  124. }
  125.  
  126. void
  127. free_all_locks()
  128. {
  129.   int i;
  130.   for (i = 0; i < lockpt; i++)
  131.     UnLock(locklist[i]);
  132. }
  133.  
  134. void
  135. myputs(char *s)
  136. {
  137.   Write(Output(), s, strlen(s));
  138. }
  139.  
  140. void
  141. Read_Dirs(char *dir, FILE *f)
  142. /* Read directories in dir and add them to the file f (should be .ccdconfig) */
  143. {
  144.   BPTR lock;
  145.   struct FileInfoBlock info, *fib;
  146.  
  147.   lock = Lock(dir, ACCESS_READ);
  148.   if (lock == 0) {
  149.     fprintf(stderr,"*** Yup! Couldn't lock %s\n", dir);
  150.     return;
  151.   }
  152.  
  153. /* Strange statements, uh? */
  154.   fib = (struct FileInfoBlock *) Examine(lock, &info);
  155.   fib = &info;
  156.  
  157.   while (1) {
  158.     if (ExNext(lock, fib) == 0) break;
  159.     if (fib -> fib_DirEntryType > 0) {
  160.       char t[50],c;
  161.       strcpy(t, dir);
  162.       if ((c = t[strlen(t) - 1]) != ':' && c != '/')
  163.         strcat(t,"/");
  164.       strcat(t, fib -> fib_FileName);
  165.       fprintf(f, "%s\n", t);
  166.       if (verbose) printf("%s\n", t);
  167.       Read_Dirs(t,f);
  168.     }
  169.   }
  170.   unlock(lock);
  171. }
  172.  
  173. FILE *
  174. Open_Config_File(char *mode)
  175. {
  176.   FILE *f;
  177.   f = fopen(CCDCONFIGFILE, mode);
  178.   if (f == NULL) {
  179.     fprintf(stderr, "*** Couldn't open '%s', maybe an assign is missing?\n", CCDCONFIGFILE);
  180.     if (mainwindow) CloseWindow(mainwindow);
  181.     if (mainscreen) CloseScreen(mainscreen);
  182.     exit(0);
  183.   }
  184.   if (mode[0] == 'r') Check_Version(f);
  185.   return f;
  186. }
  187.  
  188. void
  189. Add_Current_Dir()
  190. /* Add to the end of the config file the current dir (and its subdirs) */
  191. {
  192.    struct Process *pr = (struct Process *) FindTask(0L);
  193.    struct CommandLineInterface *cli =
  194.      (struct CommandLineInterface *) (pr -> pr_CLI) << 2;
  195.    char *p = (char *) (cli -> cli_SetName) << 2;
  196.    FILE *f;
  197.    char name[128], n2[128], *pn = name;
  198.    int i, l = *p++;
  199.  
  200. /* Copy the current dir into name */
  201.    for (i = 0; i < l; i++) *pn++ = *p++;
  202.    *pn++ = '\0';
  203.    f = Open_Config_File("a");
  204.    if (f == NULL) {
  205.      fprintf(stderr, "*** Couldn't open '%s', maybe an assign is missing?\n", CCDCONFIGFILE);
  206.      if (mainwindow) CloseWindow(mainwindow);
  207.      if (mainscreen) CloseScreen(mainscreen);
  208.      exit(0);
  209.    }
  210.  
  211.    fprintf(f, "%s\n", name);
  212.  
  213.    printf("Adding %s to the config file... ", name);
  214.    fflush(stdout);
  215.    Read_Dirs(name, f);
  216.    printf(" -- done!\n");
  217. }
  218.  
  219. void
  220. Update(char **dirname, int ndirs)
  221. /* Create the config file with the list of dirs (dirname) of length ndirs */
  222. {
  223.   FILE *f = Open_Config_File("w");
  224.   int i;
  225.  
  226.   Put_Version(f);
  227.   Put_Dirs(f, dirname);
  228.   printf("Creating %s with", CCDCONFIGFILE);
  229.   for (i = 0; i < ndirs; i++) {
  230.     printf(" %s", *dirname);
  231.     fflush(stdout);
  232.     fprintf(f, "%s\n", *dirname);
  233.     Read_Dirs(*dirname++, f);
  234.   }
  235.   printf(" -- done!\n");
  236.   fclose(f);
  237. }
  238.  
  239. int
  240. mystricmp(char *bigdir, char *shortdir)
  241. /* Check if shortdir is part of the path bigdir, return 0 if it is */
  242. {
  243.   char t[50], *pt = t, *ps;
  244.   int end = 0;
  245.   int i = 0;
  246.  
  247.   while (*bigdir) {
  248.     while (*bigdir && *bigdir != ':' && *bigdir != '/' && *bigdir != '\n')
  249.       *pt++ = *bigdir++;
  250.     if (*bigdir) bigdir++;
  251.     *pt++ = '\0';
  252.     pt = t;
  253.   }
  254.  
  255.   if (exact_cd) {    /* strings must be equal */
  256.      return stricmp(t, shortdir);
  257.   }
  258.   else {
  259.  
  260. /* We must see if shortdir is included in t */
  261.  
  262.    for (i = 0; i <= strlen(t) - strlen(shortdir); i++) {
  263.       pt = &t[i]; ps = shortdir;
  264.       while (*pt && *ps && (*pt | 0x20) == (*ps | 0x20)) {
  265.          ps++; pt++;
  266.       };
  267.       if (*pt == 0 || *ps == 0) return(0);   /* match! */
  268.    }
  269.   }
  270.   return(1);
  271. }
  272.  
  273. void
  274. Update_Prompt(char *currentdir)
  275. /* Update the concerned field with the new current dir                 */
  276. /* This routine is for users of wshell or such, thar display this name */
  277. /* as the shell prompt.                                                */
  278. /* This trick was previously pointed to me by Henry J. Cobb on Usenet  */
  279. /* for my 'find' program (another great utility of mine :-)).          */
  280. /* Let him be thanked again!                                           */
  281. {
  282.   struct Process *pr = (struct Process *) FindTask(0L);
  283.   struct CommandLineInterface *cli =
  284.     (struct CommandLineInterface *) (pr -> pr_CLI) << 2;
  285.   char *p = (char *) (cli -> cli_SetName) << 2;
  286.  
  287.   *p++ = strlen(currentdir);          /* it is a BSTR, so length first */
  288.   while (*currentdir) *p++ = *currentdir++;  /* don't add '\0' */
  289. }
  290.  
  291. int
  292. Check_Version(FILE *f)
  293. {
  294.    char v[100], l[128], c;
  295.  
  296.    fscanf(f, "%s\n", v);
  297.    if (! isdigit(v[0]) || atoi(v) < atoi(VERSION)) {
  298.       printf("*** config file is obsolete for this version\n");
  299.       printf("*** you should run 'ccd -c <dirs>', I think...\n");
  300.       fclose(f);
  301.       if (mainwindow) CloseWindow(mainwindow);
  302.       if (mainscreen) CloseScreen(mainscreen);
  303.       exit(0);
  304.    }
  305. /*
  306.       printf("*** Do you want me to create it for you with the following dirs:\n*** ");
  307.       fgets(l, 128, f);
  308.       l[strlen(l) - 1] = '\0';
  309.       printf("%s ", l);
  310.       printf("? (y/n) ");
  311.       c = getchar();
  312.       if (c != 'y' && c != 'Y') {
  313.          printf("Alright, do it yourself, then!\n");
  314.          fclose(f);
  315.          if (mainwindow) CloseWindow(mainwindow);
  316.          if (mainscreen) CloseScreen(mainscreen);
  317.          exit(0);
  318.       }
  319.       else {
  320.          char *fakelist[10], **pf = fakelist;
  321.                      /*@@ not 10, should be dynamically alloc'ed *
  322.          char vol[20], *pvol = vol;
  323.          char *p = l;
  324.  
  325.          nbvolumes = 0;
  326.          while (1) {
  327.             if (*p == '\0') break;
  328.             if (*p == '\n' || *p == ' ') {
  329.                nbvolumes++;
  330.                *pvol++ = '\0';
  331.                *pf = (char *) malloc(strlen(pvol));
  332.                strcpy(*pf, vol);
  333.                *pf++; p++;
  334.                pvol = vol;
  335.             }
  336.             else *pvol++ = *p++;
  337.          }
  338.          fclose(f);
  339.          Update(fakelist, nbvolumes);
  340.       }
  341.    }
  342. */
  343.    else   /* Version is okay, skip the dir list */
  344.       fgets(l, 128, f);
  345. }
  346.  
  347. int
  348. Put_Version(FILE *f)
  349. {
  350.    fprintf(f, "%s\n", VERSION);
  351. }
  352.  
  353. int
  354. Put_Dirs(FILE *f, char **dirnames)
  355. {
  356.    while (*dirnames) {
  357.       fprintf(f, "%s ", *dirnames++);
  358.    }
  359.    fprintf(f, "\n");
  360. }
  361.  
  362. char *
  363. locate_dir(char *dir, FILE *f)
  364. /* Return the complete path for the fragment given, if any, in file *f */
  365. {
  366.   int match = 0;
  367.   static char onedir[100];
  368.  
  369.   while (! feof(f) && ! match) {
  370.     int i;
  371.     fgets(onedir, 100, f);
  372.     i = strlen(onedir) - 1;
  373.     if (onedir[i] == '\n')
  374.       onedir[i] = '\0';     /* strip trailing \n */
  375.     if (mystricmp(onedir, dir) == 0) {
  376.       match = 1;
  377.       break;
  378.     }
  379.   }
  380.   if (match) return(onedir);
  381.   else return(NULL);
  382. }
  383.  
  384. char *
  385. reverse(char *s)
  386. /* Return the string s backwards (modify s)*/
  387. {
  388.   register char c;
  389.   char *result = s + strlen(s) - 1, *r2 = s;
  390.  
  391.   while (result > s) {
  392.     c = *result;
  393.     *result = *s;
  394.     *s = c;
  395.     s++; result--;
  396.   }
  397.   return(r2);
  398. }
  399.  
  400. void
  401. Get_Real_Name(BPTR lock, char *result)
  402. /* This is a very useful function! Put in result path of lock */
  403. /* Assume lock is not null */
  404. /* Result always device:dir/dir/...   */
  405. {
  406.   char *p = result;
  407.   struct FileInfoBlock ib;  
  408.  
  409.   assert(lock);
  410.  
  411.   if (no_expand) return;
  412.   Examine(lock, &ib);
  413.   strcpy(result, reverse(ib.fib_FileName));
  414.   strcat(result, "/");
  415.   while (lock) {
  416.     lock = ParentDir(lock);
  417.     if (lock) {
  418.       Examine(lock, &ib);
  419.       strcat(result, reverse(ib.fib_FileName));
  420.       strcat(result,"/");
  421.       unlock(lock);
  422.     }
  423.   }
  424.   p = &p[strlen(p) - 1];
  425.   *p-- = '\0';
  426.   while (*p != '/') p--;
  427.   *p = ':';
  428.   reverse(result);
  429. }
  430.  
  431. void
  432. Call_CurrentDir(char *actualdir)
  433. {
  434.    BPTR lock;
  435.  
  436.    if (actualdir[0]) {
  437.       lock = Lock(actualdir, ACCESS_READ);
  438.       if (lock == 0) {
  439.          fprintf(stderr,
  440.       "*** Couldn't cd to %s, '%s' probably outdated (re-run ccd -c)\n",
  441.             actualdir, CCDCONFIGFILE);
  442.          exit(0);
  443.       }
  444.       CurrentDir(lock);
  445.       Get_Real_Name(lock, actualdir);
  446.       printf("Current directory is now %s\n", actualdir);
  447.       Update_Prompt(actualdir);
  448.       unlock(lock);
  449.   }
  450.   else
  451.     printf("%s: no such dir\n", actualdir);
  452. }
  453.  
  454. void
  455. Change_Dir(char *dir, int occ)
  456. /* The main function to change to the fragment of dir given,  */
  457. /* to the occ'th occurence found in the config file */
  458. /* New 1.3: first, try to cd right into 'dir' */
  459. {
  460.   char cmd[50];
  461.   FILE *f = Open_Config_File("r");
  462.   int match = 0;
  463.   BPTR lock;
  464.  
  465.   strcpy(actualdir, dir);
  466.   if ((lock = Lock(actualdir, ACCESS_READ))) {   /* can we cd directly? */
  467.     BPTR old;
  468.     Get_Real_Name(lock, actualdir);
  469.     lock = get_a_lock(actualdir, ACCESS_READ);
  470.     printf("Current directory is now %s\n", actualdir);
  471.     Update_Prompt(actualdir);
  472.     old = CurrentDir(lock);                     /* yes! Do it and end */
  473. /*
  474.     UnLock(lock);
  475.     UnLock(old);
  476. */
  477.     return;
  478.   }
  479.  
  480.                            /* no, dir is a path fragment */
  481.    if (f == NULL) {
  482.      fprintf(stderr,
  483.         "*** Couldn't open '%s'; run ccd -c first, will you?\n", CCDCONFIGFILE);
  484.      exit(0);
  485.    };
  486.  
  487.    while (occ--) {
  488.      strcpy(actualdir, locate_dir(dir, f));
  489.    }
  490.  
  491.    Call_CurrentDir(actualdir);
  492.  
  493.   fclose(f);
  494. }
  495.  
  496. void
  497. Show_Ambiguities(char *dir)
  498. {
  499.   char *onedir = NULL;
  500.   char cmd[50];
  501.   FILE *f = Open_Config_File("r");
  502.   int match = 0;
  503.  
  504.   while ((onedir = locate_dir(dir, f))) {
  505.      myputs(onedir);
  506.      myputs("\n");
  507.   }
  508.  
  509.   fclose(f);  
  510. }
  511.  
  512. void
  513. Usage()
  514. {
  515.   myputs("\nccd v");
  516.   myputs(FVERSION);
  517.   myputs(",  by Cedric Beust    (C) 1991\n\n");
  518.   myputs("    Usage:\n");
  519.   myputs("           ccd                           Bring up the graphic display\n");
  520.   myputs("     or    ccd -c[v] <dir> <dir> ...     Create dir list with dirs\n");
  521.   myputs("     or    ccd -a <partial dir>          Show ambiguities\n");
  522.   myputs("     or    ccd -u                        Update file with current dir\n");
  523.   myputs("     or    ccd [opt] <partial dir> [n]   Change to this dir, nth occurence\n");
  524.   myputs("             where opt is one of\n");
  525.   myputs("                 -n    No path expansion\n");
  526.   myputs("                 -w    Open on Workbench screen\n");
  527.   myputs("                 -nxxx Set color n (0-3) to RGB xxx (hex digits)\n");
  528.   myputs("                 -e    CD to this exact dir\n\n");
  529.  
  530.   exit(0);
  531. }
  532.  
  533. void
  534. get_vol(char *path, char *vol)
  535. /* String is a line of the .ccdconfig (volume:a/b/c) */
  536. /* Return volume in the variable vol */
  537. {
  538.    char *p = path;
  539.    while (*p && *p != ':') *vol++ = *p++;
  540.    *vol++ = '\0';  
  541. }
  542.  
  543. int
  544. numberofdirs(char *path)
  545. /* path is 'vol:a/b/c' */
  546. /* Return number of dirs in it (3 here), actually = number of '/' + 1 */
  547. {
  548.    int result = 0;
  549.  
  550.    while (*path) {
  551.       while (*path && *path != '/') path++;
  552.       if (*path == '/') {
  553.          result++;
  554.          path++;
  555.       }
  556.    }
  557.    return(++result);
  558. }
  559.  
  560. void
  561. nthdir(char *dir, char *path, int n)
  562. /* Path is 'volume:a/b/c' */
  563. /* Return in dir the nth dir in it (e.g. with n=2, it's b) */
  564. {
  565.    char *dirhead = dir;
  566.    while (*path && *path != ':') path++;
  567.    if (*path == ':') {
  568.      path++;
  569.      while (*path) {
  570.          while (*path && *path != '/') {
  571.             *dir++ = *path++;
  572.          }
  573.          if (*(dir - 1) == '\n') dir--;
  574.          *dir++ = '\0';
  575.          if (*path == '/') path++;
  576.          if (n == 1) return;
  577.          else {
  578.             n--; dir = dirhead;
  579.          }
  580.       }
  581.    }
  582.    else {
  583.       printf("nthdir: problem\n");
  584.       exit(0);
  585.    }
  586. }
  587.  
  588. struct Tree_t *
  589. new_node(char *s, int line, int x, char *fullname)
  590. {
  591.    struct Tree_t *newnode;
  592.  
  593.    NEW(newnode, struct Tree_t);
  594.    if (s[strlen(s) - 1] == '\n')
  595.       s[strlen(s) - 1] = '\0';
  596.    strcpy(newnode -> name, s);
  597.    strcpy(newnode -> fullname, fullname);
  598.    newnode -> brother = NULL;
  599.    newnode -> son = NULL;
  600.    newnode -> line = line;
  601.    newnode -> x = x;
  602.    return(newnode);
  603. }
  604.  
  605. struct Tree_t *
  606. get_line(struct Tree_t *root, int line)
  607. /* Return the struct for line line, searching from root */
  608. {
  609. /*
  610.    printf("get_line with %s, %d\n", root->name, line);
  611. */
  612.    if (root) {
  613.       if (root -> line == line) return root;
  614.       else if (root -> brother) {
  615.          if (root -> brother -> line <= line)
  616.             return get_line(root -> brother, line);
  617.          else
  618.             return get_line(root -> son, line);
  619.       }
  620.       else
  621.          return get_line(root -> son, line);
  622.    }
  623.    return NULL;
  624. }
  625.  
  626. void
  627. add_node(char *s, struct Tree_t *root, int line)
  628. /* Add the appropriate node to the tree */
  629. /* Assert root != NULL */
  630. /*
  631.       dh0:   ->    dh1:    ->   dh2:
  632.                     | 
  633.                   Anews
  634.                     |
  635.                    New
  636. */
  637. {
  638.    char vol[30];
  639.    char dir[30];
  640.    struct Tree_t *newnode;
  641.    int i;
  642.    int x = UPPERX - DELTAX;
  643.  
  644.    get_vol(s, vol);
  645.    assert(root);
  646.    while (root -> brother && stricmp(root -> name, vol))
  647.       root = root -> brother;
  648.  
  649.    if (strcmp(root -> name, vol)) {   /* new vol, must create a new node */
  650.       root -> brother = new_node(vol, line, x + DELTAX, s);
  651.       newnode = root -> brother;
  652.    }
  653.    else {
  654.       struct Tree_t *t = root;
  655.       newnode = root;
  656.    }
  657.    assert(newnode);
  658.    assert(stricmp(newnode -> name, vol) == 0);
  659.  
  660. /* Now, newnode is a node that contains the volume. Create the path */
  661.  
  662.    for (i = 1; i <= numberofdirs(s); i++) {             
  663.       x = newnode -> x;
  664.       nthdir(dir, s, i);
  665.       if (newnode -> son) {
  666.          root = newnode -> son;     /* get down one level */
  667.  
  668. /* Search amid the brothers if we have a matching name */
  669.          while (root -> brother && stricmp(dir, root -> name)) {
  670.             root = root -> brother;
  671.          }
  672.          if (stricmp(root -> name, dir)) {    /* new dir, create new node */
  673.             newnode = root -> brother = new_node(dir, line, x + DELTAX, s);
  674.          }
  675.          else {
  676.             newnode = root;
  677.          }
  678.       }
  679.       else {    /* no son yet, have to create one */
  680.          newnode -> son = new_node(dir, line, x + DELTAX, s);
  681.          newnode = newnode -> son;
  682.       }
  683.  
  684. /* Now, newnode is a node that contains how far we've got in the path */
  685. /* Let's go on */
  686.       root = newnode;
  687.    }
  688. }
  689.  
  690. struct Tree_t *
  691. Build_Tree()
  692. {
  693.    FILE *f;
  694.    char string[128];
  695.    char currentvol[30];
  696.    struct Tree_t *result;
  697.  
  698.    f = Open_Config_File("r");
  699.    NEW(result, struct Tree_t);
  700.    strcpy(result -> name, "Root");
  701.    result -> brother = NULL;
  702.    result -> son = NULL;
  703.    result -> line = -1;
  704.  
  705.    while (! feof(f)) {
  706.       configlines++;
  707.       fgets(string, 128, f);
  708.       if (string[strlen(string) - 1] == '\n')
  709.          string[strlen(string) - 1] = '\0';
  710.       add_node(string, result, configlines);
  711.    }
  712.    return result;
  713. }
  714.  
  715. void
  716. Find_Dir_Coo(int x, int y, int line)
  717. {
  718.    struct Tree_t *root;
  719.  
  720.    root = get_line(the_tree, line + (y / DELTAY) - 2);
  721.    Call_CurrentDir(root -> fullname);
  722. }
  723.  
  724. int
  725. Display_Tree(struct Tree_t *root, int line, int x, int y)
  726. /* Graphically display the tree for the volume 'vol', from the line */
  727. /* line in the ccdconfig file, at coordinates x and y */
  728. /* Return the y coordinate at the end */
  729. {
  730.    int len, i;
  731.    struct RastPort *rp = mainwindow -> RPort;
  732.    int xinit = x;
  733.  
  734.    root = get_line(the_tree, line);
  735.    while (root && y < HEIGHT - DELTAY) {
  736.       y += DELTAY;
  737. #ifdef GRAPHICS
  738.       assert(rp);
  739.       Move(rp, root -> x, y);
  740.       Text(rp, root -> name, strlen(root -> name));
  741. #endif
  742.       y = Display_Tree(root -> son, line + 1, x, y);
  743.       root = root -> brother;
  744.    }
  745.    return y;
  746. }
  747.  
  748. int
  749. Create_Gadgets()
  750. /* Create the Volumes gadgets. Return the id of the first one */
  751. {
  752.    struct Tree_t *t;
  753.    struct Gadget *gad = mainwindow -> FirstGadget, *lastgadget = NULL;
  754.    struct IntuiText *tex;
  755.    int id = 1, result;
  756.    int gady = w1Gadget2.TopEdge;
  757.  
  758. /* First, transfer the gadget imageries into chip ram */
  759.    chippointer = (USHORT *)
  760.        AllocMem(sizeof(w1ImageData1), MEMF_PUBLIC | MEMF_CHIP);
  761.    if (chippointer == 0) {
  762.       printf("*** Couldn't allocate in chip mem...\n");
  763.       exit(0);
  764.    }
  765.    memcpy(chippointer, w1ImageData1, sizeof(w1ImageData1));
  766.    w1Image1.ImageData = chippointer;
  767.  
  768.    chippointer2 = (USHORT *)
  769.        AllocMem(sizeof(w1ImageData2), MEMF_PUBLIC | MEMF_CHIP);
  770.    if (chippointer2 == 0) {
  771.       printf("*** Couldn't allocate in chip mem...\n");
  772.       exit(0);
  773.    }
  774.    memcpy(chippointer2, w1ImageData2, sizeof(w1ImageData2));
  775.    w1Image2.ImageData = chippointer2;
  776.  
  777.    while (gad -> NextGadget) {
  778.       gad = gad -> NextGadget;
  779.    }
  780.    lastgadget = gad;
  781.    result = lastgadget -> GadgetID + 1;
  782.    id = result;
  783.    t = the_tree -> brother;
  784.    while (t) {
  785.  
  786. /* Dynamically create the gadget, using w1Gadget2 as template */
  787.       gad = (struct Gadget *) malloc(sizeof(*gad));
  788.       memcpy(gad, & w1Gadget2, sizeof(*gad));
  789.       gad -> TopEdge = gady;
  790.       gady += BETWEEN_GADGETS + w1Gadget2.Height;
  791.       gad -> GadgetID = id++;
  792.  
  793. /* Link the previous gadget to the one we're building up */
  794.       if (lastgadget) lastgadget -> NextGadget = gad;
  795.       lastgadget = gad;
  796.       gad -> NextGadget = NULL;
  797.  
  798. /* And now create its IntuiText structure, using w1IText1 */
  799.       tex = (struct IntuiText *) malloc(sizeof(*tex));
  800.       memcpy(tex, & w1IText1, sizeof(*tex));
  801.       tex -> IText = (char *) malloc(sizeof(t -> name) + 1);
  802.       strcpy(tex -> IText, t -> name);
  803.  
  804. /* Link the text to the gadget */
  805.       gad -> GadgetText = tex;
  806.  
  807.       nbvolumes++;
  808.       t = t -> brother;
  809.    }
  810.    return result;
  811. }
  812.  
  813. void
  814. Display_Dir(int line)
  815. /* Display the directory of the volume in the window, starting at the */
  816. /* line in the config file */
  817. {
  818.    struct Tree_t *t;
  819.    char dir[128];
  820.    struct Window *w = mainwindow;
  821.    struct Gadget *gad = NULL, *lastgadget;
  822.    struct IntuiText *tex = NULL;
  823.    int gady = w1Gadget2.TopEdge;
  824.    int id = 2;
  825.  
  826.    assert(mainwindow);
  827.  
  828. /* Warning!!! Here, I assume the 1st gadget is the scrollbar, so I */
  829. /* start from the second... */
  830.    lastgadget = w -> FirstGadget;
  831.    if (! the_tree) the_tree = Build_Tree();
  832.    dir[0] = '\0';
  833.  
  834.    actualline = 1;
  835.    SetAPen(w -> RPort, 0);
  836.    RectFill(w -> RPort, UPPERX, UPPERY + 2, WIDTH - 4, HEIGHT - 2);
  837.    SetAPen(w -> RPort, 2);
  838.    (void) Display_Tree(the_tree -> brother, line, UPPERX + DELTAX, UPPERY);
  839. }
  840.  
  841. int
  842. Locate_Vol(char *vol)
  843. /* Return first line where vol (dh0:, dh1:, ...) appears */
  844. {
  845.    struct Tree_t *t = the_tree -> brother;
  846.  
  847.    while (t && stricmp(vol, t -> name)) {
  848.       t = t -> brother;
  849.    }
  850.    if (t) return t -> line;
  851.    else assert(0);
  852. }
  853.  
  854. void
  855. Display_Window()
  856. /* Main routine for the graphic display */
  857. {
  858.    struct IntuiMessage *message;
  859.    long class, code;
  860.    int i, fin = 0;
  861.    int firstline = 1, previousline = 1, prev2;
  862.    struct Gadget *g;
  863.    struct PropInfo *info;
  864.    struct Tree_t *highlight;
  865.  
  866.    IntuitionBase = OpenLibrary("intuition.library", 0);
  867.    GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0);
  868.  
  869. #ifdef GRAPHICS
  870.    if (GfxBase -> DisplayFlags & PAL) {  /* we're in PAL, open a big one */
  871.       linesperwindow = LINESPAL;
  872.       NewScreenStructure.Height += 55;
  873.       w1NewWindowStructure1.Height += 55;
  874.       HEIGHT += 55;
  875.       w1Gadget1.Height += 55;
  876.    }
  877.    if (! workbenchscreen) {
  878.       mainscreen = OpenScreen(& NewScreenStructure);
  879.       Palette[0] = color0;
  880.       Palette[1] = color1;
  881.       Palette[2] = color2;
  882.       Palette[3] = color3;
  883.       LoadRGB4(&mainscreen -> ViewPort, Palette, PaletteColorCount);
  884.       w1NewWindowStructure1.Screen = mainscreen;
  885.    }
  886.    else {
  887.       w1NewWindowStructure1.Type = WBENCHSCREEN;
  888.    }
  889.    w1NewWindowStructure1.Title = (char *) malloc(sizeof(WINDOWTITLE));
  890.    strcpy(w1NewWindowStructure1.Title, WINDOWTITLE);
  891.    w1Gadget1.NextGadget = NULL;
  892.    mainwindow = OpenWindow(& w1NewWindowStructure1);
  893. #endif
  894.    Display_Dir(1);
  895. #ifdef GRAPHICS
  896.    volumesid = Create_Gadgets();
  897.    info = (struct PropInfo *) w1Gadget1.SpecialInfo;
  898.    info -> VertBody = (0xffff * (linesperwindow - 3)) / (configlines + 1);
  899.    RefreshGadgets(mainwindow -> FirstGadget, mainwindow, NULL);
  900.  
  901.    while (! fin) {
  902.       while ((message = (struct IntuiMessage *)
  903.                            GetMsg(mainwindow -> UserPort))) {
  904.          class = message -> Class;
  905.          code = message -> Code;
  906.          ReplyMsg(message);
  907.  
  908.          switch(class) {
  909.             case CLOSEWINDOW:
  910.                fin = 1;
  911.                break;
  912.             case GADGETUP:
  913.                g = (struct Gadget *) message -> IAddress;
  914.                if (g -> GadgetID >= volumesid) {
  915.                   firstline = Locate_Vol(g -> GadgetText -> IText);
  916.                   w1w1Gadget1SInfo.VertPot = (firstline * 0xffff) / configlines;
  917.                }
  918.                else
  919.                   firstline = ((configlines - 1)* w1w1Gadget1SInfo.VertPot) / 0xffff;
  920.                   prev2 = firstline;
  921.  
  922. /* Take care of trunc problems */
  923. /*
  924.                printf("pot: %d, previous: %d, lpw: %d, first: %d\n",
  925.                   w1w1Gadget1SInfo.VertPot,
  926.                   previousline, linesperwindow, firstline);
  927. */
  928.                if (previousline + linesperwindow - 2 <= firstline &&
  929.                    firstline <= previousline + linesperwindow + 2) {
  930.                       firstline = previousline + linesperwindow;
  931.                       previousline = prev2;
  932.                    }
  933.                else
  934.                if (previousline - linesperwindow - 2 <= firstline &&
  935.                      firstline <= previousline - linesperwindow + 2) {
  936.                         firstline = previousline - linesperwindow;
  937.                         previousline = prev2;
  938.                      }
  939.                if (firstline == 0) firstline = 1;
  940.                if (firstline > configlines - linesperwindow - 1)
  941.                   firstline = configlines - linesperwindow - 1;
  942. /*
  943.                printf("after, first: %d\n", firstline);
  944. */
  945.                if (previousline != prev2) previousline = firstline;
  946.                Display_Dir(firstline);
  947.                RefreshGadgets(mainwindow -> FirstGadget, mainwindow, NULL);
  948.                break;
  949.  
  950.             case GADGETDOWN:
  951. /*
  952.                printf("Gadgetdown, class=%d, code=%d\n", class, code);
  953.                g = (struct Gadget *) message -> IAddress;
  954.                printf("Gadgetdown, gadget id: %d\n", g -> GadgetID);
  955. */
  956.                break;
  957.  
  958.             case MOUSEBUTTONS:
  959.                if (message -> MouseX >= UPPERX && message -> MouseY>=UPPERY
  960.                    && code == SELECTDOWN) {
  961.                   Find_Dir_Coo(message -> MouseX, message -> MouseY, firstline);
  962.                   fin = 1;
  963.                }
  964.                break;
  965.  
  966.             case MOUSEMOVE:
  967.                printf("Mousemove\n");
  968.                highlight = get_line(the_tree, firstline + (message -> MouseY / DELTAY) - 1);
  969.                SetAPen(mainwindow -> RPort, 1);
  970.                Move(mainwindow -> RPort, highlight -> x, message -> MouseY);
  971.                Text(mainwindow -> RPort, highlight -> name, strlen(highlight -> name));
  972.                break;
  973.  
  974.             default:
  975. /*
  976.                printf("Class=%d, Code = %d\n", class, code);
  977. */
  978.                break;
  979.  
  980.          } /* switch class */
  981.       } /* while message */
  982.    }
  983.    if (mainwindow) CloseWindow(mainwindow);
  984.    if (mainscreen) CloseScreen(mainscreen);
  985. #endif
  986. }
  987.  
  988. int
  989. main(int argc, char **argv)
  990. {
  991.   int i = 1;
  992.   int change_dir = 1;
  993.  
  994.   while (argv[i][0] == '-') {
  995.     switch(argv[i][1]) {
  996.       case 'c' :         /* create config file */
  997.         if (argc == i + 1) Usage();
  998.         if (argv[i][2] == 'v') verbose = 1;
  999.         update_list = 1;
  1000.         break;
  1001.       case 'a' :         /* show ambiguities */
  1002.         if (argc == i) Usage();
  1003.         show_ambiguities = 1;
  1004.         break;
  1005.       case 'n' :
  1006.          if (i + 2 != argc && i + 3 != argc) Usage();
  1007.          no_expand = 1;
  1008.          break;
  1009.       case 'e' :
  1010.          if (i + 2 != argc && i + 3 != argc) Usage();
  1011.          exact_cd = 1;
  1012.          break;
  1013.       case 'u' :
  1014.          if (i + 1 != argc) Usage();
  1015.          change_dir = 0;
  1016.          no_graphics = 1;
  1017.          Add_Current_Dir();
  1018.          break;
  1019.       case 'w' :
  1020.          workbenchscreen = 1;
  1021.          break;
  1022.       case '0' :
  1023.          color0 = atow(&argv[i][2]);
  1024.          break;
  1025.       case '1' :
  1026.          color1 = atow(&argv[i][2]);
  1027.          break;
  1028.       case '2' :
  1029.          color2 = atow(&argv[i][2]);
  1030.          break;
  1031.       case '3' :
  1032.          color3 = atow(&argv[i][2]);
  1033.          break;
  1034.       default :
  1035.          Usage();
  1036.     } /* switch */
  1037.     i++;
  1038.   } /* while */
  1039.  
  1040.   if (! no_graphics && i == argc) {
  1041.       Display_Window();
  1042.       exit(0);
  1043.   }
  1044.   else if (update_list)
  1045.      Update(&argv[i], argc - 2);
  1046.   else if (show_ambiguities) {
  1047.      printf("Ambiguities for %s\n", argv[i]);
  1048.      Show_Ambiguities(argv[i]);
  1049.   }
  1050.   else if (change_dir)
  1051.      Change_Dir(argv[i], (argc == i + 2 ? atoi(argv[i+1]) : 1));
  1052.  
  1053. /*
  1054.   free_all_locks();
  1055. */
  1056.   if (chippointer) FreeMem(chippointer, sizeof(w1ImageData1));
  1057.   if (chippointer2) FreeMem(chippointer2, sizeof(w1ImageData2));
  1058.   exit(0);
  1059. }
  1060.  
  1061.