2 * $Id: fixincl.c,v 1.2 1998/12/16 21:19:03 law Exp $
4 * Install modified versions of certain ANSI-incompatible system header
5 * files which are fixed to work correctly with ANSI C and placed in a
6 * directory that GNU C will search.
8 * See README-fixinc for more information.
10 * fixincl is free software.
12 * You may redistribute it and/or modify it under the terms of the
13 * GNU General Public License, as published by the Free Software
14 * Foundation; either version 2, or (at your option) any later version.
16 * fixincl is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 * See the GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with fixincl. See the file "COPYING". If not,
23 * write to: The Free Software Foundation, Inc.,
24 * 59 Temple Place - Suite 330,
25 * Boston, MA 02111-1307, USA.
28 #include <sys/param.h>
30 #include <sys/types.h>
44 #define tSCC static const char
45 #define tCC const char
46 #define tSC static char
50 #define FAILURE ((tSuccess)-1)
51 #define SUCCESS ((tSuccess) 0)
52 #define PROBLEM ((tSuccess) 1)
54 #define SUCCEEDED( p ) ((p) == SUCCESS)
55 #define SUCCESSFUL( p ) SUCCEEDED( p )
56 #define FAILED( p ) ((p) < SUCCESS)
57 #define HADGLITCH( p ) ((p) > SUCCESS)
63 TT_TEST, TT_EGREP, TT_NEGREP
67 typedef struct test_desc tTestDesc;
76 typedef struct patch_desc tPatchDesc;
78 #define FD_MACH_ONLY 0x0000
79 #define FD_MACH_IFNOT 0x0001
80 #define FD_SKIP_TEST 0x8000
82 typedef struct fix_desc tFixDesc;
85 const char* pzFixName; /* Name of the fix */
86 const char* pzFileList; /* List of files it applies to */
87 const char** papzMachs; /* List of machine/os-es it applies to */
92 const char** papzPatchArgs;
95 char *pzDestDir = (char *) NULL;
96 char *pzSrcDir = (char *) NULL;
97 char *pzMachine = (char *) NULL;
99 pid_t chainHead = (pid_t) - 1;
101 const char zInclQuote[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
102 regex_t inclQuoteRegex;
104 char zFileNameBuf[0x8000];
106 char *loadFile (const char *pzFile);
107 void process (char *data, const char *dir, const char *file);
108 void runCompiles (void);
118 static const char zGnuLib[] =
119 "This file is part of the GNU C Library";
120 static const char zVarNotFound[] =
121 "fixincl ERROR: %s environment variable not defined\n";
123 #ifndef NO_BOGOSITY_LIMITS
124 # define BOGUS_LIMIT 256
128 char *apzNames[BOGUS_LIMIT];
135 fputs ("fixincl ERROR: too many command line arguments\n", stderr);
139 if (strcmp (argv[1], "-v") == 0)
141 fputs ("$Id: fixincl.c,v 1.2 1998/12/16 21:19:03 law Exp $\n", stderr);
145 freopen (argv[1], "r", stdin);
149 static const char zVar[] = "TARGET_MACHINE";
150 pzMachine = getenv( zVar );
151 if (pzMachine == (char *)NULL)
153 fprintf( stderr, zVarNotFound, zVar );
159 static const char zVar[] = "DESTDIR";
160 pzDestDir = getenv( zVar );
161 if (pzDestDir == (char *)NULL)
163 fprintf( stderr, zVarNotFound, zVar );
169 static const char zVar[] = "SRCDIR";
170 pzSrcDir = getenv( zVar );
171 if (pzSrcDir == (char *)NULL)
173 fprintf( stderr, zVarNotFound, zVar );
180 signal ( SIGQUIT, SIG_IGN );
181 signal ( SIGIOT, SIG_IGN );
182 signal ( SIGPIPE, SIG_IGN );
183 signal ( SIGALRM, SIG_IGN );
184 signal ( SIGTERM, SIG_IGN );
185 signal ( SIGCHLD, SIG_IGN );
187 #ifndef NO_BOGOSITY_LIMITS
194 * Only the parent process can read from stdin without
195 * confusing the world. (How does the child tell the
196 * parent to skip forward? Pipes and files behave differently.)
198 for (fileNameCt = 0, pzBuf = zFileNameBuf;
199 (fileNameCt < BOGUS_LIMIT)
201 < (zFileNameBuf + sizeof (zFileNameBuf) - MAXPATHLEN));
205 if (fgets (pzBuf, MAXPATHLEN, stdin) == (char *) NULL)
207 while (isspace (*pzBuf))
209 apzNames[fileNameCt++] = pzBuf;
210 pzBuf += strlen (pzBuf);
211 while (isspace (pzBuf[-1]))
220 if (child == NULLPROCESS)
223 if (child == NOPROCESS)
225 fprintf (stderr, "Error %d (%s) forking in main\n",
226 errno, strerror (errno));
230 waitpid (child, (int *) NULL, 0);
233 #error "NON-BOGUS LIMITS NOT SUPPORTED?!?!"
237 * For every file specified in stdandard in
238 * (except as throttled for bogus reasons)...
240 for (loopCt = 0; loopCt < fileNameCt; loopCt++)
243 char *pzFile = apzNames[loopCt];
245 if (access (pzFile, R_OK) != 0)
248 fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
249 pzFile, getcwd ((char *) NULL, MAXPATHLEN),
250 erno, strerror (erno));
252 else if (pzData = loadFile (pzFile),
253 (pzData != (char *) NULL))
256 if (strstr (pzData, zGnuLib) == (char *) NULL)
257 process (pzData, pzDestDir, pzFile);
259 free ((void *) pzData);
276 if (stat (pzFile, &stbf) != 0)
278 fprintf (stderr, "error %d (%s) stat-ing %s\n",
279 errno, strerror (errno), pzFile);
280 return (char *) NULL;
282 fileSize = stbf.st_size;
285 return (char *) NULL;
287 pzDta = (char *) malloc ((fileSize + 16) & ~0x00F);
288 if (pzDta == (char *) NULL)
290 fprintf (stderr, "error: could not malloc %d bytes\n",
296 FILE *fp = fopen (pzFile, "r");
297 size_t sizeLeft = fileSize;
298 char *readPtr = pzDta;
300 if (fp == (FILE *) NULL)
302 fprintf (stderr, "error %d (%s) opening %s\n", errno,
303 strerror (errno), pzFile);
304 free ((void *) pzDta);
305 return (char *) NULL;
310 size_t sizeRead = fread ((void *) readPtr, 1, sizeLeft, fp);
319 fprintf (stderr, "error %d (%s) reading %s\n", errno,
320 strerror (errno), pzFile);
321 free ((void *) pzDta);
323 return (char *) NULL;
328 sizeLeft -= sizeRead;
330 while (sizeLeft != 0);
342 tSCC zBadComp[] = "fixincl ERROR: cannot compile %s regex for %s\n"
343 "\texpr = `%s'\n" "\terror %s\n";
344 tFixDesc *pFD = fixDescList;
345 int fixCt = FIX_COUNT;
348 int reCt = REGEX_COUNT;
350 regex_t *pRegex = (regex_t *) malloc (REGEX_COUNT * sizeof (regex_t));
352 if (pRegex == (regex_t *) NULL)
354 fprintf (stderr, "fixincl ERROR: cannot allocate %d bytes for regex\n",
355 REGEX_COUNT * sizeof (regex_t));
359 re_set_syntax (RE_SYNTAX_EGREP);
360 pzErr = re_compile_pattern (zInclQuote, strlen (zInclQuote),
362 if (pzErr != (char *) NULL)
364 fprintf (stderr, zBadComp, "quoted include", "runCompiles",
370 * FOR every fixup, ...
374 pTD = pFD->pTestDesc;
377 if (pFD->papzMachs != (const char**)NULL) {
378 const char** papzMachs = pFD->papzMachs;
379 char* pz = zFileNameBuf;
383 tSCC zSkip[] = "skip";
386 sprintf( pz, "case %s in\n", pzMachine );
389 if (pFD->fdFlags & FD_MACH_IFNOT) {
398 const char* pzMach = *(papzMachs++);
399 if (pzMach == (const char*)NULL)
401 sprintf( pz, "%s %s", pzSep, pzMach );
405 sprintf( pz, " )\n echo %s ;;\n * )\n echo %s ;;\nesac",
406 pzIfTrue, pzIfFalse );
407 pz = runShell( zFileNameBuf );
409 pFD->fdFlags |= FD_SKIP_TEST;
415 * FOR every test for the fixup, ...
425 fputs ("out of RE's\n", stderr);
429 pTD->pTestRegex = pRegex++;
430 pzErr = re_compile_pattern (pTD->pzTest,
431 strlen (pTD->pzTest),
433 if (pzErr != (char *) NULL)
435 fprintf (stderr, zBadComp, "select test", pFD->pzFixName,
443 while (pFD++, --fixCt > 0);
453 char fname[MAXPATHLEN];
455 sprintf (fname, "%s/%s", pzDestDir, pzFile);
458 fd = open (fname, O_WRONLY | O_CREAT);
460 if ((fd < 0) && (errno == ENOENT))
462 char *pzDir = strchr (fname + 1, '/');
465 while (pzDir != (char *) NULL)
468 if (stat (fname, &stbf) < 0)
470 mkdir (fname, S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP
471 | S_IROTH | S_IXOTH);
475 pzDir = strchr (pzDir + 1, '/');
477 fd = open (fname, O_WRONLY | O_CREAT);
481 fprintf (stderr, "Error %d (%s) creating %s\n",
482 errno, strerror (errno), fname);
485 fprintf (stderr, "Fixed: %s\n", pzFile);
486 pf = fdopen (fd, "w");
490 static const char zHdr[] =
492 " * DO NOT EDIT THIS FILE.\n"
494 " * It has been auto-edited by fixincludes from /usr/include/%s\n"
495 " * This had to be done to correct non-standard usages in the\n"
496 " * original, manufacturer supplied header file.\n"
499 fprintf (pf, zHdr, pzFile);
506 testTest (pTest, pzFile)
511 tSuccess res = FAILURE;
513 static char zCmdBuf[4096];
514 tSCC zCmdFmt[] = "file=%s\nif ( test %s ) > /dev/null 2>&1\n"
515 "then echo TRUE\n" "else echo FALSE\n" "fi";
517 sprintf (zCmdBuf, zCmdFmt, pzFile, pTest->pzTest);
518 pzRes = runShell (zCmdBuf);
521 free ((void *) pzRes);
527 egrepTest (pzDta, pTest)
533 if (pTest->pTestRegex == 0)
534 fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n", pTest->pzTest);
536 if (regexec (pTest->pTestRegex, pzDta, 1, &match, 0) == 0)
544 extractQuotedFiles (pzDta, pzFile, pMatch)
549 char *pzDirEnd = strrchr (pzFile, '/');
550 char *pzInclQuot = pzDta;
552 fprintf (stderr, "Quoted includes in %s\n", pzFile);
555 * Set "pzFile" to point to the containing subdirectory of the source
556 * If there is none, then it is in our current direcory, ".".
558 if (pzDirEnd == (char *) NULL)
565 pzInclQuot += pMatch->rm_so;
568 * Skip forward to the included file name
570 while (isspace (*pzInclQuot))
572 while (isspace (*++pzInclQuot));
573 pzInclQuot += sizeof ("include") - 1;
574 while (*pzInclQuot++ != '"');
577 * Print the source directory and the subdirectory of the file
580 printf ("%s %s/", pzSrcDir, pzFile);
581 pzDirEnd = pzInclQuot;
584 * Append to the directory the relative path of the desired file
586 while (*pzInclQuot != '"')
587 putc (*pzInclQuot++, stdout);
590 * Now print the destination directory appended with the relative
591 * path of the desired file
593 printf (" %s/%s/", pzDestDir, pzFile);
594 while (*pzDirEnd != '"')
595 putc (*pzDirEnd++, stdout);
603 * Find the next entry
605 if (regexec (&inclQuoteRegex, pzInclQuot, 1, pMatch, 0) != 0)
612 * Process the potential fixes for a particular include file
615 process (pzDta, pzDir, pzFile)
620 static char zEnvFile[1024] =
622 tFixDesc *pFD = fixDescList;
623 int todoCt = FIX_COUNT;
628 * IF this is the first time through,
629 * THEN put the 'file' environment variable into the environment.
630 * This is used by some of the subject shell scripts and tests.
632 if (zEnvFile[5] == NUL)
636 * Ghastly as it is, this actually updates the value of the variable:
638 * putenv(3C) C Library Functions putenv(3C)
641 * putenv() makes the value of the environment variable name
642 * equal to value by altering an existing variable or creating
643 * a new one. In either case, the string pointed to by string
644 * becomes part of the environment, so altering the string will
645 * change the environment. string points to a string of the
646 * form ``name=value.'' The space used by string is no longer
647 * used once a new string-defining name is passed to putenv().
649 strcpy (zEnvFile + 5, pzFile);
650 chainHead = NOPROCESS;
653 * For every fix in our fix list, ...
655 for (; todoCt > 0; pFD++, todoCt--)
661 if (pFD->fdFlags & FD_SKIP_TEST)
665 * IF there is a file name restriction,
666 * THEN ensure the current file name matches one in the pattern
668 if (pFD->pzFileList != (char *) NULL)
670 const char *pzFil = pzFile;
671 const char *pzScn = pFD->pzFileList;
674 while ((pzFil[0] == '.') && (pzFil[1] == '/'))
676 nmLen = strlen (pzFil);
680 pzScn = strstr (pzScn + 1, pzFil);
681 if (pzScn == (char *) NULL)
684 if ((pzScn[-1] == '|') && (pzScn[nmLen] == '|'))
692 * IF there are no tests
693 * THEN we always run the fixup
695 for (pTD = pFD->pTestDesc, tstCt = pFD->testCt;
703 * IF *any* of the shell tests fail,
704 * THEN do not process the fix.
706 if (!SUCCESSFUL (testTest (pTD, pzFile)))
712 * IF we have not had a successful egrep test
713 * *AND* this test does not pass,
714 * THEN mark the egrep test as failing. It starts
715 * out as a "PROBLEM", meaning that if we do not
716 * encounter any egrep tests, then we will let it pass.
718 if ((!SUCCESSFUL (egrepRes))
719 && (!SUCCESSFUL (egrepTest (pzDta, pTD))))
727 * IF *any* of the negative egrep tests fail,
728 * THEN do not process the fix.
730 if (SUCCESSFUL (egrepTest (pzDta, pTD)))
737 * IF there were no egrep tests *OR* at least one passed, ...
739 if (!FAILED (egrepRes))
741 fprintf (stderr, "Applying %-32s to %s\n",
742 pFD->pzFixName, pzFile);
744 if (fdp.readFd == -1)
746 fdp.readFd = open (pzFile, O_RDONLY);
749 fprintf (stderr, "Error %d (%s) opening %s\n", errno,
750 strerror (errno), pzFile);
757 int newFd = chainOpen (fdp.readFd,
758 (tpChar *) pFD->papzPatchArgs,
760 ? &chainHead : (pid_t *) NULL);
767 fprintf (stderr, "Error %d (%s) starting filter process "
768 "for %s\n", errno, strerror (errno),
781 * IF after all the tests we did not start any patch programs,
788 FILE *inFp = fdopen (fdp.readFd, "r");
789 FILE *oFp = (FILE *) NULL;
800 if (oFp != (FILE *) NULL)
803 else if (ch != *pzCmp)
805 oFp = createFile (pzFile);
820 if (oFp != (FILE *) NULL)
824 fchmod (fileno (oFp), S_IRUSR | S_IRGRP | S_IROTH);
826 if (regexec (&inclQuoteRegex, pzDta, 1, &match, 0) == 0)
827 extractQuotedFiles (pzDta, pzFile, &match);