home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / gnudosck.zip / doschk.c < prev    next >
C/C++ Source or Header  |  1993-05-22  |  11KB  |  487 lines

  1. /*
  2.  * doschk - check filenames for DOS (and SYSV) compatibility
  3.  *
  4.  * Copyright (C) 1993 DJ Delorie
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2, or (at your option)
  9.  * any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to: The Free Software Foundation,
  18.  * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
  19.  *
  20.  * This program is intended as a utility to help software developers
  21.  * ensure that their source file names are distinguishable on MS-DOS and
  22.  * 14-character SYSV platforms.  To perform this task, doschk reads a
  23.  * list of filenames and produces a report of all the conflicts that
  24.  * would arise if the files were transferred to a MS-DOS or SYSV
  25.  * platform.  It also reports any file names that would conflict with
  26.  * MS-DOS device names.
  27.  *
  28.  * To use this program, you must feed it a list of filenames in this
  29.  * format:
  30.  *
  31.  *         dir
  32.  *         dir/file1.ext
  33.  *         dir/file2.exe
  34.  *         dir/dir2
  35.  *         dir/dir2/file3.ext
  36.  *
  37.  * If the list does not include the directory-only lines (like dir/dir2)
  38.  * then their names will not be checked for uniqueness, else they will
  39.  * be.  Typical uses of this program are like these:
  40.  *
  41.  *         find . -print | doschk
  42.  *         tar tf file.tar | doschk
  43.  *
  44.  * If this program produces no output, then all your files are MS-DOS
  45.  * compatible.  Any output messages are designed to be self-explanatory
  46.  * and indicate cases where the files will not transfer to MS-DOS without
  47.  * problems.
  48.  *
  49.  */
  50.  
  51. #include <stdio.h>
  52. #include <ctype.h>
  53. #include <string.h>
  54.  
  55. extern char *malloc ();
  56.  
  57. typedef struct ENT
  58. {
  59.   struct ENT *next;
  60.   char *dos_name;
  61.   char *full_name;
  62.   char *path;
  63.   int tagged;
  64. } ENT;
  65.  
  66. /* 
  67.  * List of filenames in MSDOG that are special devices. 
  68.  * Not all of these are problems on all MSLOSS systems, but most would not
  69.  * work on most of them.
  70.  */
  71. static char *dos_special_names[] = 
  72. {
  73.   "NUL", 
  74.   "CON", 
  75.   "PRN", 
  76.   "AUX", 
  77.   "COM1", 
  78.   "COM2", 
  79.   "COM3",
  80.   "COM4",
  81.   "LPT1",
  82.   "LPT2",
  83.   "LPT3",
  84.   "MS$MOUSE",
  85.   "EMMXXXX0",
  86.   "XMSXXXX0",
  87.   "SMARTAAR",
  88.   "SETVERXX",
  89.   NULL
  90. } ;
  91.  
  92. ENT *eroot = 0;
  93.  
  94. int first_inv = 1;
  95. int first_msg = 1;
  96.  
  97. /****************************************************************\
  98.  *  Utility routines                        *
  99. \****************************************************************/
  100.  
  101. void
  102. invalid_msg ()
  103. {
  104.   if (first_inv)
  105.     {
  106.       if (first_msg)
  107.     first_msg = 0;
  108.       else
  109.     putchar ('\n');
  110.       printf ("The following files are not valid DOS file names:\n");
  111.       first_inv = 0;
  112.     }
  113. }
  114.  
  115. char *
  116. xmalloc (size)
  117.      int size;
  118. {
  119.   char *s;
  120.  
  121.   if (size == 0) 
  122.     return NULL; 
  123.  
  124.   s = (char *) malloc (size);
  125.  
  126.   if (s == NULL)
  127.     {
  128.       fprintf (stderr, "Virtual memory exhausted.\n");
  129.       exit (1);
  130.     }
  131.  
  132.   return s;
  133. }
  134.  
  135. ENT *
  136. alloc_ent ()
  137. {
  138.   ENT *rv = (ENT *) xmalloc (sizeof (ENT));
  139.   memset (rv, 0, sizeof (ENT));
  140.   return rv;
  141. }
  142.  
  143. void
  144. fill_ent (ent, path)
  145.      ENT *ent;
  146.      char *path;
  147. {
  148.   char *first = path;
  149.   char *null = path + strlen (path);
  150.   char *last_slash = strrchr (path, '/');
  151.   char *cp, *dp;
  152.   int dots_seen, chars_seen;
  153.  
  154.   if (last_slash + 1 == null)
  155.     {
  156.       *--null = '\0';
  157.       last_slash = strrchr (path, '/');
  158.     }
  159.  
  160.   if (!last_slash)
  161.     {
  162.       last_slash = first - 1;
  163.     }
  164.  
  165.   if (null - last_slash < 13)
  166.     ent->dos_name = (char *) xmalloc (null - last_slash);
  167.   else
  168.     ent->dos_name = (char *) xmalloc (13);
  169.   ent->full_name = (char *) xmalloc (null - last_slash);
  170.   ent->path = (char *) xmalloc (last_slash - first + 1);
  171.  
  172.   strcpy (ent->full_name, last_slash + 1);
  173.   if (last_slash > first)
  174.     {
  175.       strncpy (ent->path, first, last_slash - first);
  176.       ent->path[last_slash - first] = '\0';
  177.     }
  178.   else
  179.     ent->path = "\0";
  180.  
  181.   cp = last_slash + 1;
  182.   dp = ent->dos_name;
  183.   dots_seen = 0;
  184.   chars_seen = 0;
  185.   while (1)
  186.     {
  187.       if (!*cp)
  188.     break;
  189.       switch (*cp)
  190.     {
  191.     case '.':
  192.       if (cp == last_slash + 1 && strcmp (last_slash + 1, "."))
  193.         {
  194.           invalid_msg ();
  195.           printf ("%s - file name cannot start with dot\n", path);
  196.           *dp = 0;
  197.           break;
  198.         }
  199.       if (dots_seen == 1)
  200.         {
  201.               /* If trailing dot, it will be ignored by MSDOG, so don't */
  202.               /* actually complain. */
  203.               if (*(cp + 1) != 0)
  204.                 {
  205.                   invalid_msg ();
  206.                   printf ("%s - too many dots\n", path);
  207.                 }
  208.           *dp = '\0';
  209.           break;
  210.         }
  211.       *dp++ = '.';
  212.       chars_seen = 0;
  213.       dots_seen++;
  214.       break;
  215.     case '"':
  216.     case '*':
  217.     case '+':
  218.     case ',':
  219.     case ';':
  220.     case '<':
  221.     case '=':
  222.     case '>':
  223.     case '?':
  224.     case '[':
  225.     case '\\':
  226.     case ']':
  227.     case '|':
  228.         case ':':
  229.       invalid_msg ();
  230.       printf ("%s - invalid character `%c'\n", path, *cp);
  231.       *dp++ = '?';
  232.       chars_seen++;
  233.       break;
  234.     default:
  235.       if (dots_seen)
  236.         {
  237.           if (chars_seen >= 3)
  238.         break;
  239.         }
  240.       else if (chars_seen >= 8)
  241.         break;
  242.       if ((*cp <= ' ') || (*cp >= 0x7f))
  243.         {
  244.           invalid_msg ();
  245.           printf ("%s - invalid character `%c'\n", path, *cp);
  246.           *dp++ = '?';
  247.           chars_seen++;
  248.           break;
  249.         }
  250.       if (islower (*cp))
  251.         *dp++ = toupper (*cp);
  252.       else
  253.         *dp++ = *cp;
  254.       chars_seen++;
  255.       break;
  256.     }
  257.       cp++;
  258.     }
  259.   *dp++ = '\0';
  260. }
  261.  
  262. int
  263. compare_ent_dosname (e1, e2)
  264.      ENT **e1;
  265.      ENT **e2;
  266. {
  267.   int r = strcmp ((*e1)->dos_name, (*e2)->dos_name);
  268.   if (r == 0)
  269.     r = strcmp ((*e1)->path, (*e2)->path);
  270.   if (r == 0)
  271.     r = strcmp ((*e1)->full_name, (*e2)->full_name);
  272.   return r;
  273. }
  274.  
  275. int
  276. compare_ent_fullname (e1, e2)
  277.      ENT **e1;
  278.      ENT **e2;
  279. {
  280.   int r = strncmp ((*e1)->full_name, (*e2)->full_name, 14);
  281.   if (r == 0)
  282.     r = strcmp ((*e1)->path, (*e2)->path);
  283.   if (r == 0)
  284.     r = strcmp ((*e1)->full_name, (*e2)->full_name);
  285.   return r;
  286. }
  287.  
  288. char *
  289. mpath (ent)
  290.      ENT *ent;
  291. {
  292.   static char buf[1024];  /* fixed sizes for buffers are bad! */
  293.   if (ent->path && ent->path[0])
  294.     sprintf (buf, "%s/%s", ent->path, ent->full_name);
  295.   else
  296.     return ent->full_name;
  297.   return buf;
  298. }
  299.  
  300. /****************************************************************\
  301.  *  List handling routines                    *
  302. \****************************************************************/
  303.  
  304. void
  305. add_ent (ent)
  306.      ENT *ent;
  307. {
  308.   ent->next = eroot;
  309.   eroot = ent;
  310. }
  311.  
  312. void
  313. handle_input (line)
  314.      char *line;
  315. {
  316.   ENT *ent = alloc_ent ();
  317.   fill_ent (ent, line);
  318.   add_ent (ent);
  319. }
  320.  
  321. void
  322. display_problems ()
  323. {
  324.   ENT **elist, *ent;
  325.   int ecount, i, first, first_err;
  326.   char **dos_dev_name;
  327.  
  328.   for (ecount = 0, ent = eroot; ent; ent = ent->next, ecount++);
  329.   elist = (ENT **) xmalloc (sizeof (ENT *) * ecount);
  330.   for (ecount = 0, ent = eroot; ent; ent = ent->next, ecount++)
  331.     elist[ecount] = ent;
  332.  
  333.   qsort (elist, ecount, sizeof (ENT *), compare_ent_dosname);
  334.  
  335.   first_err = 1;
  336.   for (i = 0; i < ecount; i++)
  337.     {
  338.       int elist_len = strlen (elist[i]->dos_name);
  339.  
  340.       dos_dev_name = dos_special_names; 
  341.       while (*dos_dev_name)
  342.         {
  343.           if ((strcmp (elist[i]->dos_name, *dos_dev_name) == 0)
  344.               || ((*(elist[i]->dos_name + elist_len - 1) == '.')
  345.                   && (strncmp (elist[i]->dos_name, *dos_dev_name, elist_len - 2) == 0)))
  346.             {
  347.               if (first_err)
  348.                 {
  349.                   if (first_msg)
  350.                     first_msg = 0;
  351.                   else
  352.                     putchar ('\n');
  353.                   printf ("The following resolve to special DOS device names:\n");
  354.                   first_err = 0;
  355.                 }
  356.               printf ("%-14s : %s\n", elist[i]->dos_name, mpath (elist[i]));
  357.               break;
  358.             }
  359.           dos_dev_name++;
  360.         }
  361.     }
  362.   
  363.   first = 1;
  364.   first_err = 1;
  365.   for (i = 0; i < ecount - 1; i++)
  366.     {
  367.       int elist1_len = strlen (elist[i + 1]->dos_name);
  368.  
  369.       if (((strcmp (elist[i]->dos_name, elist[i + 1]->dos_name) == 0)
  370.            && (strcmp (elist[i]->path, elist[i + 1]->path) == 0))
  371.           || ((*(elist[i + 1]->dos_name + elist1_len - 1) == '.')
  372.               && (strncmp (elist[i]->dos_name, elist[i + 1]->dos_name, elist1_len - 2) == 0)))
  373.     {
  374.       if (first_err)
  375.         {
  376.           if (first_msg)
  377.         first_msg = 0;
  378.           else
  379.         putchar ('\n');
  380.           printf ("The following resolve to the same DOS file names:\n");
  381.           first_err = 0;
  382.         }
  383.       if (first)
  384.         {
  385.           printf ("%-14s : %s\n", elist[i]->dos_name, mpath (elist[i]));
  386.           first = 0;
  387.         }
  388.       printf ("\t\t %s\n", mpath (elist[i + 1]));
  389.     }
  390.       else
  391.     first = 1;
  392.     }
  393.  
  394.   qsort (elist, ecount, sizeof (ENT *), compare_ent_fullname);
  395.  
  396.   first = 1;
  397.   first_err = 1;
  398.   for (i = 0; i < ecount - 1; i++)
  399.     {
  400.       if ((strncmp (elist[i]->full_name, elist[i + 1]->full_name, 14) == 0) &&
  401.       (strcmp (elist[i]->path, elist[i + 1]->path) == 0))
  402.     {
  403.       if (first_err)
  404.         {
  405.           if (first_msg)
  406.         first_msg = 0;
  407.           else
  408.         putchar ('\n');
  409.           printf ("The following resolve to the same SysV file names:\n");
  410.           first_err = 0;
  411.         }
  412.       if (first)
  413.         {
  414.           printf ("%.14s : %s\n", elist[i]->full_name, mpath (elist[i]));
  415.           first = 0;
  416.           elist[i]->tagged = 1;
  417.         }
  418.       printf ("\t\t %s\n", mpath (elist[i + 1]));
  419.       elist[i + 1]->tagged = 1;
  420.     }
  421.       else
  422.     first = 1;
  423.     }
  424.  
  425.   first_err = 1;
  426.   for (i = 0; i < ecount; i++)
  427.     {
  428.       if ((strlen (elist[i]->full_name) > 14) && !elist[i]->tagged)
  429.     {
  430.       if (first_err)
  431.         {
  432.           if (first_msg)
  433.         first_msg = 0;
  434.           else
  435.         putchar ('\n');
  436.           printf ("The following file names are too long for SysV:\n");
  437.           first_err = 0;
  438.         }
  439.       printf ("%.14s : %s\n", elist[i]->full_name, mpath (elist[i]));
  440.     }
  441.     }
  442. }
  443.  
  444. /****************************************************************\
  445.  *  Main entry point                        *
  446. \****************************************************************/
  447.  
  448. main (argc, argv)
  449.      int argc;
  450.      char **argv;
  451. {
  452.   FILE *input = stdin;
  453.   if (argc > 1)
  454.     {
  455.       input = fopen (argv[1], "r");
  456.       if (!input)
  457.     {
  458.       perror (argv[1]);
  459.       exit (1);
  460.     }
  461.     }
  462.   else
  463.     if ( isatty(0) )
  464.       {
  465.         fprintf(stderr, "\nGNU doschk - check filenames for DOS (and SYSV) compatibility\n"
  466.                         "\nUsage: %s [name-list-file]\n", argv[0]);
  467.         exit(1);
  468.       }
  469.   while (1)
  470.     {
  471.       char line[500];
  472.       char *lp;
  473.       fgets (line, 500, input);
  474.       if (feof (input))
  475.     break;
  476.       lp = line + strlen (line);
  477.       while ((lp != line) && (*lp <= ' '))
  478.     lp--;
  479.       lp[1] = 0;
  480.       handle_input (line);
  481.     }
  482.   display_problems ();
  483.   return 0;
  484. }
  485.  
  486. /* End of file */
  487.