1/*
2**  DosFCheck - check file names for DOS consistency
3**
4**  Distribute freely, it only encourages DOS compatibility!
5**  - DJ Delorie
6*/
7
8/* This file is not part of GCC.  */
9
10#include <stdio.h>
11#ifdef __MSDOS__
12#include <alloc.h>
13#else
14#include <malloc.h>
15#endif
16#include <ctype.h>
17#include <string.h>
18
19typedef struct ENT
20{
21  struct ENT *next;
22  char *dos_name;
23  char *full_name;
24  char *path;
25  int tagged;
26} ENT;
27
28ENT *eroot = 0;
29
30int first_inv = 1;
31int first_msg = 1;
32
33/****************************************************************\
34 *  Utility routines						*
35\****************************************************************/
36
37void
38invalid_msg ()
39{
40  if (first_inv)
41    {
42      if (first_msg)
43	first_msg = 0;
44      else
45	putchar ('\n');
46      printf ("The following files are not valid DOS file names:\n");
47      first_inv = 0;
48    }
49}
50
51ENT *
52alloc_ent ()
53{
54  ENT *rv = (ENT *)malloc (sizeof (ENT));
55  if (rv == 0)
56    {
57      fprintf (stderr, "Unable to allocate memory for an ENT\n");
58      exit (1);
59    }
60  memset (rv, 0, sizeof (ENT));
61  return rv;
62}
63
64void
65fill_ent (ent, path)
66ENT *ent;
67char *path;
68{
69  char *first = path;
70  char *null = path+strlen (path);
71  char *last_slash = strrchr (path, '/');
72  char *cp, *dp;
73  int dots_seen, chars_seen;
74
75  if (last_slash+1 == null)
76    {
77      * --null = '\0';
78      last_slash = strrchr (path, '/');
79    }
80
81  if (!last_slash)
82    {
83      last_slash = first-1;
84    }
85
86  if (null-last_slash < 13)
87    ent->dos_name = (char *)malloc (null-last_slash);
88  else
89    ent->dos_name = (char *)malloc (13);
90  ent->full_name = (char *)malloc (null-last_slash);
91  ent->path = (char *)malloc (last_slash-first+1);
92
93  strcpy (ent->full_name, last_slash+1);
94  if (last_slash > first)
95    {
96      strncpy (ent->path, first, last_slash-first);
97      ent->path[last_slash-first] = '\0';
98    }
99  else
100    *ent->path = '\0';
101
102  cp = last_slash+1;
103  dp = ent->dos_name;
104  dots_seen = 0;
105  chars_seen = 0;
106  while (1)
107    {
108      if (! *cp)
109	break;
110      switch (*cp)
111	{
112	case '.':
113	  if (cp == last_slash+1 && strcmp (last_slash+1, "."))
114	    {
115	      invalid_msg ();
116	      printf ("%s - file name cannot start with dot\n", path);
117	      *dp = 0;
118	      break;
119	    }
120	  if (dots_seen == 1)
121	    {
122	      invalid_msg ();
123	      printf ("%s - too many dots\n", path);
124	      *dp = '\0';
125	      break;
126	    }
127	  *dp++ = '.';
128	  chars_seen = 0;
129	  dots_seen++;
130	  break;
131	case '"':
132	case '*':
133	case '+':
134	case ',':
135	case ';':
136	case '<':
137	case '=':
138	case '>':
139	case '?':
140	case '[':
141	case '\\':
142	case ']':
143	case '|':
144	  invalid_msg ();
145	  printf ("%s - invalid character `%c'\n", path, *cp);
146	  *dp++ = '?';
147	  chars_seen++;
148	  break;
149	default:
150	  if (dots_seen)
151	    {
152	      if (chars_seen >= 3)
153		break;
154	    }
155	  else
156	    if (chars_seen >= 8)
157	      break;
158	  if ((*cp <= ' ') || (*cp >= 0x7f))
159	    {
160	      invalid_msg ();
161	      printf ("%s - invalid character `%c'\n", path, *cp);
162	      *dp++ = '?';
163	      chars_seen++;
164	      break;
165	    }
166	  if (islower (*cp))
167	    *dp++ = toupper (*cp);
168	  else
169	    *dp++ = *cp;
170	  chars_seen++;
171	  break;
172	}
173      cp++;
174    }
175  *dp++ = '\0';
176}
177
178int
179compare_ent_dosname (e1, e2)
180ENT **e1;
181ENT **e2;
182{
183  int r = strcmp ((*e1)->dos_name, (*e2)->dos_name);
184  if (r == 0)
185    r = strcmp ((*e1)->path, (*e2)->path);
186  if (r == 0)
187    r = strcmp ((*e1)->full_name, (*e2)->full_name);
188  return r;
189}
190
191int
192compare_ent_fullname (e1, e2)
193ENT **e1;
194ENT **e2;
195{
196  int r = strncmp ((*e1)->full_name, (*e2)->full_name, 14);
197  if (r == 0)
198    r = strcmp ((*e1)->path, (*e2)->path);
199  if (r == 0)
200    r = strcmp ((*e1)->full_name, (*e2)->full_name);
201  return r;
202}
203
204char *
205mpath (ent)
206ENT *ent;
207{
208  static char buf[500];
209  if (ent->path && ent->path[0])
210    sprintf (buf, "%s/%s", ent->path, ent->full_name);
211  else
212    return ent->full_name;
213  return buf;
214}
215
216/****************************************************************\
217 *  List handling routines					*
218\****************************************************************/
219
220void
221add_ent (ent)
222ENT *ent;
223{
224  ent->next = eroot;
225  eroot = ent;
226}
227
228void
229handle_input (line)
230char *line;
231{
232  ENT *ent = alloc_ent ();
233  fill_ent (ent, line);
234  add_ent (ent);
235}
236
237void
238display_problems ()
239{
240  ENT **elist, *ent;
241  int ecount, i, first, first_err;
242
243  for (ecount=0, ent=eroot; ent; ent=ent->next, ecount++);
244  elist = (ENT **)malloc (sizeof (ENT *) * ecount);
245  for (ecount=0, ent=eroot; ent; ent=ent->next, ecount++)
246    elist[ecount] = ent;
247
248  qsort (elist, ecount, sizeof (ENT *), compare_ent_dosname);
249
250  first = 1;
251  first_err = 1;
252  for (i=0; i<ecount-1; i++)
253    {
254      if ((strcmp (elist[i]->dos_name, elist[i+1]->dos_name) == 0)
255	  && (strcmp (elist[i]->path, elist[i+1]->path) == 0))
256	{
257	  if (first_err)
258	    {
259	      if (first_msg)
260		first_msg = 0;
261	      else
262		putchar ('\n');
263	      printf ("The following resolve to the same DOS file names:\n");
264	      first_err = 0;
265	    }
266	  if (first)
267	    {
268	      printf ("%14s : %s\n", elist[i]->dos_name, mpath (elist[i]));
269	      first = 0;
270	    }
271	  printf ("\t\t %s\n", mpath (elist[i+1]));
272	}
273      else
274	first = 1;
275    }
276
277  qsort (elist, ecount, sizeof (ENT *), compare_ent_fullname);
278
279  first = 1;
280  first_err = 1;
281  for (i=0; i<ecount-1; i++)
282    {
283      if ((strncmp (elist[i]->full_name, elist[i+1]->full_name, 14) == 0)
284	  && (strcmp (elist[i]->path, elist[i+1]->path) == 0))
285	{
286	  if (first_err)
287	    {
288	      if (first_msg)
289		first_msg = 0;
290	      else
291		putchar ('\n');
292	      printf ("The following resolve to the same SysV file names:\n");
293	      first_err = 0;
294	    }
295	  if (first)
296	    {
297	      printf ("%.14s : %s\n", elist[i]->full_name, mpath (elist[i]));
298	      first = 0;
299	      elist[i]->tagged = 1;
300	    }
301	  printf ("\t\t %s\n", mpath (elist[i+1]));
302	  elist[i+1]->tagged = 1;
303	}
304      else
305	first = 1;
306    }
307
308  first_err = 1;
309  for (i=0; i<ecount; i++)
310    {
311      if ((strlen (elist[i]->full_name) > 14) && !elist[i]->tagged)
312	{
313	  if (first_err)
314	    {
315	      if (first_msg)
316		first_msg = 0;
317	      else
318		putchar ('\n');
319	      printf ("The following file names are too long for SysV:\n");
320	      first_err = 0;
321	    }
322	  printf ("%.14s : %s\n", elist[i]->full_name, mpath (elist[i]));
323	}
324    }
325}
326
327/****************************************************************\
328 *  Main entry point						*
329\****************************************************************/
330
331main (argc, argv)
332int argc;
333char **argv;
334{
335  FILE *input = stdin;
336  if (argc > 1)
337    {
338      input = fopen (argv[1], "r");
339      if (!input)
340	{
341	  perror (argv[1]);
342	  exit (1);
343	}
344    }
345  while (1)
346    {
347      char line[500];
348      char *lp;
349      fgets (line, 500, input);
350      if (feof (input))
351	break;
352      lp = line+strlen (line);
353      while ((lp != line) && (*lp <= ' '))
354	lp--;
355      lp[1] = 0;
356      handle_input (line);
357    }
358  display_problems ();
359}
360
361