home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 4
/
FreshFish_May-June1994.bin
/
bbs
/
support
/
symlinks.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-05-14
|
10KB
|
444 lines
/*
* This is a quick 3 hour hack that is used to generate a batch file
* that makes symbolic links (or else make the links directly), where
* selected file from my CD-ROM can be linked into one of 26
* subdirectories, according to the first letter of the name of the
* file.
*
* Given a file where each line is <pathname><space><version-number>,
* such as:
*
* cd0:BBS/ALib/d2xx/d234/MuchMore.lha 1.8
*
* This program will emit two lines that look like:
*
* ln -s cd0:BBS/ALib/d2xx/d234/MuchMore.lha m/MuchMore-1.8.lha
* ln -s cd0:BBS/ALib/d2xx/d234/MuchMore.lha.pi m/MuchMore-1.8.lha.pi
*
* In the case where the version number is unknown (I.E. is ?.?),
* the program will attempt to use the last component of the directory
* path in place of the version number, if such component looks like
* a "disk number". I.E. "dNNN". Thus the following:
*
* cd0:BBS/ALib/d2xx/d234/MuchMore.lha ?.?
*
* would produce:
*
* ln -s cd0:BBS/ALib/d2xx/d234/MuchMore.lha m/MuchMore-d234.lha
* ln -s cd0:BBS/ALib/d2xx/d234/MuchMore.lha.pi m/MuchMore-d234.lha.pi
*
* If the last component of the directory name is not a "disk number",
* then no version number is used.
*
* The name of each link is remembered, and name collisions are handled
* by appending "-a", "-b", "-c", etc to the version number, until a
* suitable "-<letter>" is found that results in a unique name.
* The mechanism used here (linear search of a linked list) is horribly
* inefficient. Then again, it processes all 6000+ file names from
* my first FrozenFish CD-ROM with about 30 seconds of cpu time on
* a 50Mhz 486, so it probably isn't worth trying to improve on until
* processing time becomes too intolerable.
*
* Options are:
*
* -v Print the name of each link to be make.
*
* -s Emit script to stdout rather than directly
* making directories and links.
*
* -V1 Assume "view 1", where each file is linked into
* a subdirectory named for the first character
* of the file. Otherwise links are made in the
* current directory.
*
*/
#include <stdio.h>
#include <ctype.h>
#ifndef SEPARATE_GNU
#define SEPARATE_GNU 0
#endif
extern char *strchr ();
extern char *strrchr ();
extern char *strdup ();
extern char *malloc ();
extern char *strstr ();
static char inbuf[256];
static char linkto[64];
static char nameroot[64];
static char extension[64];
static char linkname[64];
static char dlinkname[64];
static char copy[64];
static char scratch1[256];
static char scratch2[256];
struct namelink {
struct namelink *next;
char *name;
};
struct namelink *names;
char *dnames[] =
{
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
#if SEPARATE_GNU
"GNU",
#endif
NULL
};
char *numnames[] =
{
"z", "o", "t", "t", "f", "f", "s", "s", "e", "n",
};
int view = 0;
/* Look up a name in the linked list. Return pointer to it if found,
otherwise NULL. Do the comparison case independently, because
that is how the Amiga file system works. */
char *
findname (char *name)
{
struct namelink *scan;
for (scan = names; scan != NULL; scan = scan ->next)
{
if (strcasecmp (name, scan -> name) == 0)
{
return (scan -> name);
}
}
return (NULL);
}
/* Add a name to the linked list. No testing for duplicates is done,
you should call findname() first to verify it is unique. */
void
addname (char *name)
{
struct namelink *new;
new = (struct namelink *) malloc (sizeof (struct namelink));
new -> name = strdup (name);
new -> next = names;
names = new;
}
char *
dirname (char *sp)
{
char *endp;
static char buf[256];
strcpy (buf, sp);
/* Look first for typical Unix or AmigaDOS separator */
endp = strrchr (buf, '/');
/* Look for special AmigaDOS separator */
#ifdef __amigados__
if (endp == NULL)
{
endp = strrchr (buf, ':');
}
#endif
/* If there was a separator, set up to zap it, otherwise the dirname
is just the empty string. */
if (endp == NULL)
{
endp = buf;
}
*endp = '\000';
return (buf);
}
char *
basename (char *sp)
{
char *bname;
/* Look first for typical Unix or AmigaDOS separator */
bname = strrchr (sp, '/');
/* Look for special AmigaDOS separator */
#ifdef __amigados__
if (bname == NULL)
{
bname = strrchr (sp, ':');
}
#endif
/* If any separator found, skip over it, otherwise the
basename is just the entire string. */
if (bname == NULL)
{
bname = sp;
}
else
{
bname++;
}
return (bname);
}
main (int argc, char **argv)
{
char copychar;
char *verp;
char *scan;
char *dname = NULL;
char **pptr;
char ch;
int verbose = 0;
int script = 0;
extern int optind;
extern char *optarg;
while ((ch = getopt (argc, argv, "vsV:")) != EOF)
{
switch (ch)
{
case 'V':
view = atoi (optarg);
break;
case 'v':
verbose++;
break;
case 's':
script++;
break;
}
}
if (view == 1)
{
for (pptr = dnames; *pptr != NULL; pptr++)
{
if (script)
{
printf ("mkdir %s\n", *pptr);
}
else
{
sprintf (scratch1, "%s", *pptr);
if (mkdir (scratch1) != 0)
{
perror (scratch1);
}
}
}
}
while (gets (inbuf) != NULL)
{
/* Separate pathname and version number */
verp = strchr (inbuf, ' ');
if (verp == NULL)
{
fprintf (stderr, "symlinks: missing separator: '%s'\n", inbuf);
}
*verp++ = '\000';
while (*verp == ' ')
{
verp++;
}
/* Extract rootname and extension. I.E. for "foo.tar.gz",
get "foo" and ".tar.gz" */
strcpy (nameroot, basename (inbuf));
if (nameroot[0] == '\000')
{
/* This is a directory, not an archive. */
continue;
}
scan = strrchr (nameroot, '.');
if (scan == NULL)
{
/* No extension is fine. It may just be a single file such
as an animation or picture. */
extension[0] = '\000';
}
else
{
if (strcmp (scan, ".gz") == 0)
{
strcpy (extension, scan);
*scan++ = '\000';
scan = strrchr (nameroot, '.');
if (strcmp (scan, ".tar") == 0)
{
*scan = '\000';
strcpy (extension, ".tar.gz");
}
}
else
{
strcpy (extension, scan);
*scan++ = '\000';
}
}
/* Get version number */
if (*verp == '?')
{
/* Try using last component of pathname */
verp = basename (dirname (inbuf));
if (*verp != 'd' ||
!isdigit (*(verp + 1)) ||
!isdigit (*(verp + 2)) ||
!isdigit (*(verp + 3)))
{
verp = NULL;
}
}
if (verp != NULL)
{
/* If the name already contains the version string, suppress
adding another copy to it. */
if (strstr (nameroot, verp))
{
verp = NULL;
}
}
if (verp != NULL)
{
/* Check for the special case where the nameroot is DiskNNN.
There are almost 1000 of these for the floppy library, and
it doesn't make sense to have them printed as DiskNNN-dNNN
*/
if ((strncmp (nameroot, "Disk", 4) == 0) &&
isdigit (nameroot[4]) &&
isdigit (nameroot[5]) &&
isdigit (nameroot[6]))
{
verp = NULL;
}
}
if (verp != NULL)
{
/* Replace any embedded blanks in the version string
with '.' */
for (scan = verp; *scan != '\000'; scan++)
{
if (*scan == ' ')
{
*scan = '.';
}
}
}
copy[0] = '\000';
copychar = 'a';
for (;;)
{
if (verp != NULL)
{
sprintf (linkto, "%s-%s%s%s", nameroot, verp, copy,
extension);
}
else
{
sprintf (linkto, "%s%s%s", nameroot, copy, extension);
}
/* Figure out which directory to put the linked name into.
Names that begin with numbers go in the directory that
is the first character of their full name. I.E.
the file "3Dplot.lha" goes in the "t" directory, for
"three-Dplot.lha". */
dlinkname[0] = '\000';
if (view == 1)
{
if (SEPARATE_GNU && (strstr (inbuf, "/GNU/") != NULL))
{