From: jax AT darkstar DOT cygnus DOT com (Jack Woehr) Subject: Re: Conversion of Unix to DOS file names To: dj AT ctron DOT com (DJ Delorie) Date: Tue, 9 Nov 1993 14:41:18 -0700 (MST) Cc: jon AT halsp DOT hitachi DOT com, djgpp AT sun DOT soe DOT clarkson DOT edu > > If they were uploaded, they would be in pub/msdos/djgpp/pub somewhere. > Note that the djtarx program in djgpp 1.11 does some conversions > automatically (*.info-* to *.i*, for example) and has always allowed > you to specify new names for conflicting files as they're being > untarred. > > The FSF distributes a program called "doschk" (latest version is > doschk-1.1.tar.gz). This program can be used in a Unix area to > identify potential conflicts when those sources are moved to DOS, so > that you can fix the names before tarring them together. If you > encounter a dos-hostile source distribution, please mention this > program to the distribution's maintainers and *politely* ask them to > consider running it on their sources. It also checks for SYSV > 14-character limit conflicts. > > DJ > > /* 8dot3.c ... convert filenames to MS-DOS canonical 8.3 form * $Author: jax $ * $Log: 8dot3.c,v $ * Revision 1.2 1993/09/30 20:28:09 jax * Changed default so that it merely echoes proposed MS-DOS * file names ... added -n option to force renaming of actual files. * Changed help message accordingly. * * Revision 1.5 1993/09/30 20:16:14 jax * Changed typo in help message. * * Revision 1.4 1993/09/30 20:11:55 jax * changed default to not automatically rename files. * * Revision 1.3 1993/09/21 19:15:04 jax * Added more comments. * * Revision 1.2 1993/09/21 07:04:34 jax * Added options. * */ #include #include #include #include #include #define OPTSTRING "Ulfhins" #define USAGE \ "Usage: %s [-U|-l] [-fhin] [-s/regexp/regexp/] file ... \n\ \n\tEchoes file name(s) as legal MS-DOS nnnnnnnn.ext to stdout.\n\ \n\t Options:\ \n\t-U convert filename to uppercase\ \n\t-l convert filename to lowercase\ \n\t-f force overwrite of extant destination files, only valid with -n,\ \n\t ignored with -i option.\ \n\t-h gives this help.\ \n\t-i ignores, simply skipping extant identically-named destination files.\ \n\t-n rename the file itself.\ \n\t-s/regexp/regexp/\ \n\t\t*NOT IMPLEMENTED* use substitution masks when subbing illegals.\n" #define TRUE 1 #define FALSE 0 #define LOWER(c) (('A' <= c) && (c <= 'Z') ? c - 'A' + 'a' : c) #define UPPER(c) (('a' <= c) && (c <= 'z') ? c - 'a' + 'A' : c) #define LEGAL(c) ((('A' <= c) && (c <= 'Z')) || (('0' <= c) && (c <= '9'))\ || (('a' <= c) && (c <= 'z')) || member (c, "_^$~!#%%&-{}()@'`")) /* See IBM Disk Operating System Version 5.0 User's Manual, p. 72 ff. */ char name[9] ; /* 8+\0 */ char ext[4] ; /* 3+\0 */ char dot[2] ; /* 1+\0 */ char newName[14] ; /* 8+dot+3+\0+1 */ int uppercasing = FALSE; /* Default is neither to upper- nor lower-case name */ int lowercasing = FALSE; int echoing = TRUE; /* Default is to rename */ int forcing = FALSE; /* Default is not to force overwrite */ int ignoring = FALSE; /* Default is to ask on overwrite */ extern int optind; /* Index to next argv entry used by getopt () */ extern int errno; /* Error returns */ int processOpts (int, char **); void getname (char *); void dosname (void); int redosname (char *); int main (int argc, char **argv) { int argIndex; int temp; /* No file names? Print usage and quit */ if (argc == 1) { fprintf (stderr, USAGE, *argv); return (0); } /* Process command line options */ if (temp = processOpts (argc, argv)) return (temp); /* set our index into argv array to that left by getopt () */ argIndex = optind; /* Loop processing each file in rest of command line */ while (argv[argIndex]) { getname (argv[argIndex++]); dosname (); if (!echoing) /* "echoing" means "only echoing, not renaming." */ if (redosname (argv[argIndex-1])) { fprintf (stderr, "Couldn't rename %s, errno == %d", argv[argIndex-1], errno); return (errno); } } return (0); } /* Process and resolve command line options. * Return 0 if ok and non-zero if error. */ int processOpts (int argc, char **argv) { int option; /* loop getting options and processing */ while (-1 != (option = getopt (argc, argv, OPTSTRING))) { switch (option) { case 'U': uppercasing = TRUE; lowercasing = FALSE; break; case 'l': lowercasing = TRUE; uppercasing = FALSE; break; case 'f': forcing = TRUE; break; case 'h': fprintf (stderr, USAGE, *argv); exit (0); break; case 'i': ignoring = TRUE; break; case 'n': echoing = FALSE; break; } } return (0); } /* Output the 8.3 */ void dosname (void) { printf ("%s",name); printf ("%s",dot); printf ("%s\n",ext); } /* Rename actual file to 8.3 */ int redosname (char *oldName) { char s[256]; int fp; memset (newName,'\0', sizeof (newName)); strcpy (newName,name); strcat (newName,dot); strcat (newName,ext); /* check to see if file to rename actually exists */ if (-1 == (fp = open (oldName,O_RDONLY))) return -1; /* it exists, close the file id we opened */ close (fp); /* Does a file with the new name already exist? */ fp = open (newName,O_RDONLY); /* If so ... */ if (-1 != fp) { close (fp); /* Close handle we opened */ if (!ignoring) { /* If we're not skipping extants */ if (forcing) { /* If forcibly overwriting, just do it */ return (rename (oldName, newName)); } /* But if we are not forcibly overwriting, query user */ else { fflush (stdin); fflush (stdout); fflush (stderr); fprintf (stderr, "%s exists, overwrite? ", newName); fflush (stderr); /* This is too much work, but I haven't figured out how to do this the right way yet ... suggestions? */ scanf ("%s", s); fflush (stdin); fflush (stdout); fflush (stderr); if ('Y' == (UPPER (*s))) { return (rename (oldName, newName)); } else { return (0); } } return (0); } else return (0); } /* The default, filename didn't already exist, so rename source file */ return (rename (oldName, newName)); } /* Is "c" a member of "set"? */ int member (char c, char *set) { int i; for (i=0; i < strlen (set); i++) if (c == set[i]) return TRUE; return FALSE; } /* Convert a character to a legal MS-DOS filename char, uppercasing or * lowercasing if that option set. */ char convchar (char c) { /* the default, possibly overwritten below */ char cc = c; if (uppercasing) cc = UPPER (c); if (lowercasing) cc = LOWER (c); if (cc == '+') return ('x'); if (LEGAL (cc)) return (cc); else return ('_'); } /* Find the index of the '.' dot in the filename, if any. If two dots, first will be found, second will be an illegal char */ int finddot (char *string) { int i; for (i = 0; i < strlen (string); i++) { if (string[i] == '.') return (i); } return (-1); } /* Create the name, dot, ext portions of new filename */ void getname (char *string) { int i; int dotpos = finddot (string); memset (name, '\0', sizeof (name)); /* re-init all these */ memset (dot, '\0', sizeof (dot)); memset (ext, '\0', sizeof (ext)); /* If no dot, or if dot is last char in string */ if ((dotpos < 0) || (dotpos == (strlen (string) - 1))) for (i = 0; (i < strlen (string)) && (i < 8); i++) name[i] = convchar (string[i]); else { /* Otherwise, there's a dot to take into account */ /* For the characters before the dot, up to eight (8) chars max */ for (i = 0; (i < strlen (string)) && (i < dotpos) && (i < 8); i++) name[i] = convchar (string[i]); /* For the chars after the dot, up to three (3) max */ for (i = (dotpos+1); (i < strlen (string)) && ((i - (dotpos + 1)) < 3); i++) ext[i-(dotpos+1)] = convchar (string[i]); /* insert dot ... made this a separate step for reasons having to do with the NUL: device which no longer apply, but not worth changing now. */ *dot = '.'; } }