home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / support / symlinks.c < prev    next >
C/C++ Source or Header  |  1994-04-06  |  9KB  |  428 lines

  1. /*
  2.  *  This is a quick 3 hour hack that is used to generate a batch file
  3.  *  that makes symbolic links (or else make the links directly), where
  4.  *  selected file from my CD-ROM can be linked into one of 26
  5.  *  subdirectories, according to the first letter of the name of the
  6.  *  file.
  7.  *
  8.  *  Given a file where each line is <pathname><space><version-number>,
  9.  *  such as:
  10.  *
  11.  *    cd0:BBS/ALib/d2xx/d234/MuchMore.lha 1.8
  12.  *
  13.  *  This program will emit two lines that look like:
  14.  * 
  15.  *    ln -s cd0:BBS/ALib/d2xx/d234/MuchMore.lha m/MuchMore-1.8.lha
  16.  *    ln -s cd0:BBS/ALib/d2xx/d234/MuchMore.lha.pi m/MuchMore-1.8.lha.pi
  17.  *
  18.  *  In the case where the version number is unknown (I.E. is ?.?),
  19.  *  the program will attempt to use the last component of the directory
  20.  *  path in place of the version number, if such component looks like
  21.  *  a "disk number".  I.E. "dNNN".  Thus the following:
  22.  *
  23.  *    cd0:BBS/ALib/d2xx/d234/MuchMore.lha ?.?
  24.  *
  25.  *  would produce:
  26.  *
  27.  *    ln -s cd0:BBS/ALib/d2xx/d234/MuchMore.lha m/MuchMore-d234.lha
  28.  *    ln -s cd0:BBS/ALib/d2xx/d234/MuchMore.lha.pi m/MuchMore-d234.lha.pi
  29.  *
  30.  *  If the last component of the directory name is not a "disk number",
  31.  *  then no version number is used.
  32.  *
  33.  *  The name of each link is remembered, and name collisions are handled
  34.  *  by appending "-a", "-b", "-c", etc to the version number, until a
  35.  *  suitable "-<letter>" is found that results in a unique name.
  36.  *  The mechanism used here (linear search of a linked list) is horribly
  37.  *  inefficient.  Then again, it processes all 6000+ file names from
  38.  *  my first FrozenFish CD-ROM with about 30 seconds of cpu time on
  39.  *  a 50Mhz 486, so it probably isn't worth trying to improve on until
  40.  *  processing time becomes too intolerable.
  41.  *
  42.  *  Options are:
  43.  *
  44.  *    -v   Print the name of each link to be make.
  45.  *
  46.  *    -s   Emit script to stdout rather than directly
  47.  *         making directories and links.
  48.  *
  49.  *    -V1  Assume "view 1", where each file is linked into
  50.  *         a subdirectory named for the first character
  51.  *         of the file.  Otherwise links are made in the
  52.  *           current directory.
  53.  *            
  54.  */
  55.  
  56. #include <stdio.h>
  57. #include <ctype.h>
  58.  
  59. extern char *strchr ();
  60. extern char *strrchr ();
  61. extern char *strdup ();
  62. extern char *malloc();
  63.  
  64. static char inbuf[256];
  65. static char linkto[64];
  66. static char nameroot[64];
  67. static char extension[64];
  68. static char linkname[64];
  69. static char dlinkname[64];
  70. static char copy[64];
  71. static char scratch1[256];
  72. static char scratch2[256];
  73.  
  74. struct namelink {
  75.   struct namelink *next;
  76.   char *name;
  77. };
  78.  
  79. struct namelink *names;
  80.  
  81. char *dnames[] =
  82. {
  83.   "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
  84.   "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
  85.   "GNU", NULL
  86. };
  87.  
  88. char *numnames[] =
  89. {
  90.   "z", "o", "t", "t", "f", "f", "s", "s", "e", "n",
  91. };
  92.  
  93. int view = 0;
  94.  
  95. /* Look up a name in the linked list.  Return pointer to it if found,
  96.    otherwise NULL.  Do the comparison case independently, because
  97.    that is how the Amiga file system works. */
  98.  
  99. char *
  100. findname (char *name)
  101. {
  102.   struct namelink *scan;
  103.  
  104.   for (scan = names; scan != NULL; scan = scan ->next)
  105.     {
  106.       if (strcasecmp (name, scan -> name) == 0)
  107.     {
  108.       return (scan -> name);
  109.     }
  110.     }
  111.   return (NULL);
  112. }
  113.  
  114. /* Add a name to the linked list.  No testing for duplicates is done,
  115.    you should call findname() first to verify it is unique. */
  116.  
  117. void
  118. addname (char *name)
  119. {
  120.   struct namelink *new;
  121.  
  122.   new = (struct namelink *) malloc (sizeof (struct namelink));
  123.   new -> name = strdup (name);
  124.   new -> next = names;
  125.   names = new;
  126. }
  127.  
  128. char *
  129. dirname (char *sp)
  130. {
  131.   char *endp;
  132.   static char buf[256];
  133.  
  134.   strcpy (buf, sp);
  135.  
  136.   /* Look first for typical Unix or AmigaDOS separator */
  137.  
  138.   endp = strrchr (buf, '/');
  139.  
  140.   /* Look for special AmigaDOS separator */
  141.  
  142. #ifdef __amigados__
  143.   if (endp == NULL)
  144.     {
  145.       endp = strrchr (buf, ':');
  146.     }
  147. #endif
  148.  
  149.   /* If there was a separator, set up to zap it, otherwise the dirname
  150.      is just the empty string. */
  151.  
  152.   if (endp == NULL)
  153.     {
  154.       endp = buf;
  155.     }
  156.   *endp = '\000';
  157.   return (buf);
  158. }
  159.  
  160. char *
  161. basename (char *sp)
  162. {
  163.   char *bname;
  164.  
  165.   /* Look first for typical Unix or AmigaDOS separator */
  166.  
  167.   bname = strrchr (sp, '/');
  168.  
  169.   /* Look for special AmigaDOS separator */
  170.  
  171. #ifdef __amigados__
  172.   if (bname == NULL)
  173.     {
  174.       bname = strrchr (sp, ':');
  175.     }
  176. #endif
  177.  
  178.   /* If any separator found, skip over it, otherwise the
  179.      basename is just the entire string. */
  180.  
  181.   if (bname == NULL)
  182.     {
  183.       bname = sp;
  184.     }
  185.   else
  186.     {
  187.       bname++;
  188.     }
  189.  
  190.   return (bname);
  191. }
  192.  
  193. main (int argc, char **argv)
  194. {
  195.   char copychar;
  196.   char *verp;
  197.   char *scan;
  198.   char *dname = NULL;
  199.   char **pptr;
  200.   char ch;
  201.   int verbose = 0;
  202.   int script = 0;
  203.   extern int optind;
  204.   extern char *optarg;
  205.  
  206.   while ((ch = getopt (argc, argv, "vsV:")) != EOF)
  207.     {
  208.       switch (ch)
  209.     {
  210.     case 'V':
  211.       view = atoi (optarg);
  212.       break;
  213.     case 'v':
  214.       verbose++;
  215.       break;
  216.     case 's':
  217.       script++;
  218.       break;
  219.     }
  220.     }
  221.   if (view == 1)
  222.     {
  223.       for (pptr = dnames; *pptr != NULL; pptr++)
  224.     {
  225.       if (script)
  226.         {
  227.           printf ("mkdir %s\n", *pptr);
  228.         }
  229.       else
  230.         {
  231.           sprintf (scratch1, "%s", *pptr);
  232.           if (mkdir (scratch1) != 0)
  233.         {
  234.           perror (scratch1);
  235.         }
  236.         }
  237.     }
  238.     }
  239.   while (gets (inbuf) != NULL)
  240.     {
  241.       verp = strchr (inbuf, ' ');
  242.       if (verp == NULL)
  243.     {
  244.       fprintf (stderr, "symlinks: missing separator: '%s'\n", inbuf);
  245.     }
  246.       else
  247.     {
  248.       *verp++ = '\000';
  249.       strcpy (nameroot, basename (inbuf));
  250.       scan = strrchr (nameroot, '.');
  251.       if (strcmp (scan, ".lha") == 0)
  252.         {
  253.           *scan = '\000';
  254.           strcpy (extension, "lha");
  255.         }
  256.       else if (strcmp (scan, ".gz") == 0)
  257.         {
  258.           *scan = '\000';
  259.           scan = strrchr (nameroot, '.');
  260.           if (strcmp (scan, ".tar") == 0)
  261.         {
  262.           *scan = '\000';
  263.           strcpy (extension, "tar.gz");
  264.         }
  265.           else
  266.         {
  267.           fprintf (stderr, 
  268.                "symlinks: unknown extension on '%s.%s'\n",
  269.                nameroot, "gz");
  270.           continue;
  271.         }
  272.         }
  273.       else
  274.         {
  275.           fprintf (stderr, "symlinks: unknown extension on '%s'\n",
  276.                nameroot);
  277.           continue;
  278.         }
  279.       if (*verp == '?')
  280.         {
  281.           /* Try using last component of pathname */
  282.           verp = basename (dirname (inbuf));
  283.           if (*verp != 'd' ||
  284.           !isdigit (*(verp + 1)) ||
  285.           !isdigit (*(verp + 2)) ||
  286.           !isdigit (*(verp + 3)))
  287.         {
  288.           verp = NULL;
  289.         }
  290.         }
  291.       if (verp != NULL)
  292.         {
  293.           /* If the name already contains the version string, suppress
  294.          adding another copy to it. */
  295.           if (strstr (nameroot, verp))
  296.         {
  297.           verp = NULL;
  298.         }
  299.         }
  300.       if (verp != NULL)
  301.         {
  302.           /* Check for the special case where the nameroot is DiskNNN.
  303.          There are almost 1000 of these for the floppy library, and
  304.          it doesn't make sense to have them printed as DiskNNN-dNNN
  305.          */
  306.           if ((strncmp (nameroot, "Disk", 4) == 0) &&
  307.           isdigit (nameroot[4]) &&
  308.           isdigit (nameroot[5]) &&
  309.           isdigit (nameroot[6]))
  310.         {
  311.           verp = NULL;
  312.         }
  313.         }
  314.       if (verp != NULL)
  315.         {
  316.           /* Replace any embedded blanks in the version string 
  317.          with '.' */
  318.           for (scan = verp; *scan != '\000'; scan++)
  319.         {
  320.           if (*scan == ' ')
  321.             {
  322.               *scan = '.';
  323.             }
  324.         }
  325.         }
  326.       copy[0] = '\000';
  327.       copychar = 'a';
  328.       for (;;)
  329.         {
  330.           if (verp != NULL)
  331.         {
  332.           sprintf (linkto, "%s-%s%s.%s", nameroot, verp, copy,
  333.                extension);
  334.         }
  335.           else
  336.         {
  337.           sprintf (linkto, "%s%s.%s", nameroot, copy, extension);
  338.         }
  339.  
  340.           /* Figure out which directory to put the linked name into.
  341.          Names that begin with numbers go in the directory that
  342.          is the first character of their full name.  I.E.
  343.          the file "3Dplot.lha" goes in the "t" directory, for
  344.          "three-Dplot.lha". */
  345.  
  346.           dlinkname[0] = '\000';
  347.           if (view == 1)
  348.         {
  349.           if (strstr (inbuf, "/GNU/") != NULL)
  350.             {
  351.               dname = "GNU";    /* HACK */
  352.             }
  353.           else if (isdigit (linkto[0]))
  354.             {
  355.               dname = numnames[linkto[0] - '0'];
  356.             }
  357.           else
  358.             {
  359.               for (dname = linkto; *dname != '\000'; dname++)
  360.             {
  361.               if ((tolower (*dname) >= 'a') &&
  362.                   (tolower (*dname) <= 'z'))
  363.                 {
  364.                   static char dnamebuf[2];
  365.                   dnamebuf[0] = tolower (*dname);
  366.                   dnamebuf[1] = '\000';
  367.                   dname = dnamebuf;
  368.                   break;
  369.                 }
  370.             }
  371.               if (*dname == '\000')
  372.             {
  373.               dname = "orphans";
  374.             }
  375.             }
  376.           sprintf (dlinkname, "%s/", dname);
  377.         }
  378.  
  379.           /* Build the complete name of the link to make, including
  380.          any directory prefix, and look for name collisions. */
  381.  
  382.           sprintf (linkname, "%s%s", dlinkname, linkto);
  383.           if (findname (linkname) != NULL)
  384.         {
  385.           /* Name collision */
  386.           sprintf (copy, "-%c", copychar++);
  387.         }
  388.           else
  389.         {
  390.           /* Name is unique in all names seen so far, so run
  391.              with it... */
  392.           if (verbose)
  393.             {
  394.               printf ("%s\n", linkname);
  395.             }
  396.           if (strlen (linkname) > 30)
  397.             {
  398.               fprintf (stderr,
  399.                    "symlinks: warning: %s: name may be truncated\n",
  400.                    linkname);
  401.             }
  402.           addname (linkname);
  403.           if (script)
  404.             {
  405.               printf ("ln -s \"%s\" \"%s\"\n", inbuf, linkname);
  406.               printf ("ln -s \"%s.pi\" \"%s.pi\"\n", inbuf,
  407.                   linkname);
  408.             }
  409.           else
  410.             {
  411.               if (symlink (inbuf, linkname) != 0)
  412.             {
  413.               perror (linkname);
  414.             }
  415.               sprintf (scratch1, "%s.pi", inbuf);
  416.               sprintf (scratch2, "%s.pi", linkname);
  417.               if (symlink (scratch1, scratch2) != 0)
  418.             {
  419.               perror (scratch2);
  420.             }
  421.             }
  422.           break;
  423.         }
  424.         }
  425.     }
  426.     }
  427. }
  428.