725471d2bd
From-SVN: r21614
811 lines
20 KiB
C
811 lines
20 KiB
C
/*
|
|
* $Id: fixincl.c,v 1.4 1998/08/05 10:20:11 korbb Exp $
|
|
*
|
|
* Install modified versions of certain ANSI-incompatible system header
|
|
* files which are fixed to work correctly with ANSI C and placed in a
|
|
* directory that GNU C will search.
|
|
*
|
|
* See README-fixinc for more information.
|
|
*
|
|
* fixincl is free software.
|
|
*
|
|
* You may redistribute it and/or modify it under the terms of the
|
|
* GNU General Public License, as published by the Free Software
|
|
* Foundation; either version 2, or (at your option) any later version.
|
|
*
|
|
* fixincl is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with fixincl. See the file "COPYING". If not,
|
|
* write to: The Free Software Foundation, Inc.,
|
|
* 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <ctype.h>
|
|
|
|
#include "regex.h"
|
|
#include "server.h"
|
|
|
|
#define tSCC static const char
|
|
#define tCC const char
|
|
#define tSC static char
|
|
|
|
typedef int tSuccess;
|
|
|
|
#define FAILURE ((tSuccess)-1)
|
|
#define SUCCESS ((tSuccess) 0)
|
|
#define PROBLEM ((tSuccess) 1)
|
|
|
|
#define SUCCEEDED( p ) ((p) == SUCCESS)
|
|
#define SUCCESSFUL( p ) SUCCEEDED( p )
|
|
#define FAILED( p ) ((p) < SUCCESS)
|
|
#define HADGLITCH( p ) ((p) > SUCCESS)
|
|
|
|
#define NUL '\0'
|
|
|
|
typedef enum
|
|
{
|
|
TT_TEST, TT_EGREP, TT_NEGREP
|
|
}
|
|
teTestType;
|
|
|
|
typedef struct test_desc tTestDesc;
|
|
|
|
struct test_desc
|
|
{
|
|
teTestType type;
|
|
const char *pzTest;
|
|
regex_t *pTestRegex;
|
|
};
|
|
|
|
typedef struct patch_desc tPatchDesc;
|
|
|
|
#define FD_MACH_ONLY 0x0000
|
|
#define FD_MACH_IFNOT 0x0001
|
|
#define FD_SKIP_TEST 0x8000
|
|
|
|
typedef struct fix_desc tFixDesc;
|
|
struct fix_desc
|
|
{
|
|
const char* pzFixName; /* Name of the fix */
|
|
const char* pzFileList; /* List of files it applies to */
|
|
const char** papzMachs; /* List of machine/os-es it applies to */
|
|
regex_t* pListRegex;
|
|
int testCt;
|
|
int fdFlags;
|
|
tTestDesc* pTestDesc;
|
|
const char** papzPatchArgs;
|
|
};
|
|
|
|
char *pzDestDir = (char *) NULL;
|
|
char *pzSrcDir = (char *) NULL;
|
|
char zMachine[] = TARGET_MACHINE;
|
|
|
|
pid_t chainHead = (pid_t) - 1;
|
|
|
|
const char zInclQuote[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
|
|
regex_t inclQuoteRegex;
|
|
|
|
char zFileNameBuf[0x8000];
|
|
|
|
char *loadFile (const char *pzFile);
|
|
void process (char *data, const char *dir, const char *file);
|
|
void runCompiles (void);
|
|
|
|
#include "fixincl.x"
|
|
|
|
|
|
int
|
|
main (argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
static const char zGnuLib[] =
|
|
"This file is part of the GNU C Library";
|
|
|
|
#ifndef NO_BOGOSITY_LIMITS
|
|
size_t loopCt;
|
|
#endif
|
|
|
|
char *apzNames[128];
|
|
size_t fileNameCt;
|
|
|
|
if (argc != 1)
|
|
{
|
|
if (argc != 2)
|
|
{
|
|
fputs ("fixincl ERROR: files specified on command line (not stdin)\n",
|
|
stderr);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
if (strcmp (argv[1], "-v") == 0)
|
|
{
|
|
fputs ("$Id: fixincl.c,v 1.4 1998/08/05 10:20:11 korbb Exp $\n", stderr);
|
|
exit (EXIT_SUCCESS);
|
|
}
|
|
|
|
freopen (argv[1], "r", stdin);
|
|
}
|
|
|
|
pzDestDir = getenv ("DESTDIR");
|
|
if (pzDestDir == (char *) NULL)
|
|
{
|
|
fprintf (stderr, "fixincl ERROR: %s cannot find destination dir\n"
|
|
"\t(`DESTDIR' must be an environment variable)\n", *argv);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
pzSrcDir = getenv ("SRCDIR");
|
|
if (pzSrcDir == (char *) NULL)
|
|
{
|
|
fprintf (stderr, "fixincl ERROR: %s cannot find source dir\n"
|
|
"\t(`SRCDIR' must be an environment variable)\n", *argv);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
runCompiles ();
|
|
|
|
#ifndef NO_BOGOSITY_LIMITS
|
|
for (;;)
|
|
{
|
|
char *pzBuf;
|
|
pid_t child;
|
|
|
|
/*
|
|
* Only the parent process can read from stdin without
|
|
* confusing the world. (How does the child tell the
|
|
* parent to skip forward? Pipes and files behave differently.)
|
|
*/
|
|
for (fileNameCt = 0, pzBuf = zFileNameBuf;
|
|
(fileNameCt < 128)
|
|
&& (pzBuf
|
|
< (zFileNameBuf + sizeof (zFileNameBuf) - MAXPATHLEN));
|
|
)
|
|
{
|
|
|
|
if (fgets (pzBuf, MAXPATHLEN, stdin) == (char *) NULL)
|
|
break;
|
|
while (isspace (*pzBuf))
|
|
pzBuf++;
|
|
apzNames[fileNameCt++] = pzBuf;
|
|
pzBuf += strlen (pzBuf);
|
|
while (isspace (pzBuf[-1]))
|
|
pzBuf--;
|
|
*pzBuf++ = '\0';
|
|
}
|
|
|
|
if (fileNameCt == 0)
|
|
return EXIT_SUCCESS;
|
|
|
|
child = fork ();
|
|
if (child == NULLPROCESS)
|
|
break;
|
|
|
|
if (child == NOPROCESS)
|
|
{
|
|
fprintf (stderr, "Error %d (%s) forking in main\n",
|
|
errno, strerror (errno));
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
waitpid (child, (int *) NULL, 0);
|
|
}
|
|
#else
|
|
#error "NON-BOGUS LIMITS NOT SUPPORTED?!?!"
|
|
#endif
|
|
|
|
/*
|
|
* For every file specified in stdandard in
|
|
* (except as throttled for bogus reasons)...
|
|
*/
|
|
for (loopCt = 0; loopCt < fileNameCt; loopCt++)
|
|
{
|
|
char *pzData;
|
|
char *pzFile = apzNames[loopCt];
|
|
|
|
if (access (pzFile, R_OK) != 0)
|
|
{
|
|
int erno = errno;
|
|
fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
|
|
pzFile, getcwd ((char *) NULL, MAXPATHLEN),
|
|
erno, strerror (erno));
|
|
}
|
|
else if (pzData = loadFile (pzFile),
|
|
(pzData != (char *) NULL))
|
|
{
|
|
|
|
if (strstr (pzData, zGnuLib) == (char *) NULL)
|
|
process (pzData, pzDestDir, pzFile);
|
|
|
|
free ((void *) pzData);
|
|
}
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
|
|
char *
|
|
loadFile (pzFile)
|
|
const char *pzFile;
|
|
{
|
|
char *pzDta;
|
|
size_t fileSize;
|
|
|
|
{
|
|
struct stat stbf;
|
|
if (stat (pzFile, &stbf) != 0)
|
|
{
|
|
fprintf (stderr, "error %d (%s) stat-ing %s\n",
|
|
errno, strerror (errno), pzFile);
|
|
return (char *) NULL;
|
|
}
|
|
fileSize = stbf.st_size;
|
|
}
|
|
if (fileSize == 0)
|
|
return (char *) NULL;
|
|
|
|
pzDta = (char *) malloc ((fileSize + 16) & ~0x00F);
|
|
if (pzDta == (char *) NULL)
|
|
{
|
|
fprintf (stderr, "error: could not malloc %d bytes\n",
|
|
fileSize);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
{
|
|
FILE *fp = fopen (pzFile, "r");
|
|
size_t sizeLeft = fileSize;
|
|
char *readPtr = pzDta;
|
|
|
|
if (fp == (FILE *) NULL)
|
|
{
|
|
fprintf (stderr, "error %d (%s) opening %s\n", errno,
|
|
strerror (errno), pzFile);
|
|
free ((void *) pzDta);
|
|
return (char *) NULL;
|
|
}
|
|
|
|
do
|
|
{
|
|
size_t sizeRead = fread ((void *) readPtr, 1, sizeLeft, fp);
|
|
|
|
if (sizeRead == 0)
|
|
{
|
|
if (feof (fp))
|
|
break;
|
|
|
|
if (ferror (fp))
|
|
{
|
|
fprintf (stderr, "error %d (%s) reading %s\n", errno,
|
|
strerror (errno), pzFile);
|
|
free ((void *) pzDta);
|
|
fclose (fp);
|
|
return (char *) NULL;
|
|
}
|
|
}
|
|
|
|
readPtr += sizeRead;
|
|
sizeLeft -= sizeRead;
|
|
}
|
|
while (sizeLeft != 0);
|
|
|
|
*readPtr = '\0';
|
|
fclose (fp);
|
|
return pzDta;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
runCompiles ()
|
|
{
|
|
tSCC zBadComp[] = "fixincl ERROR: cannot compile %s regex for %s\n"
|
|
"\texpr = `%s'\n" "\terror %s\n";
|
|
tFixDesc *pFD = fixDescList;
|
|
int fixCt = FIX_COUNT;
|
|
tTestDesc *pTD;
|
|
int tstCt;
|
|
int reCt = REGEX_COUNT;
|
|
const char *pzErr;
|
|
regex_t *pRegex = (regex_t *) malloc (REGEX_COUNT * sizeof (regex_t));
|
|
|
|
if (pRegex == (regex_t *) NULL)
|
|
{
|
|
fprintf (stderr, "fixincl ERROR: cannot allocate %d bytes for regex\n",
|
|
REGEX_COUNT * sizeof (regex_t));
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
re_set_syntax (RE_SYNTAX_EGREP);
|
|
pzErr = re_compile_pattern (zInclQuote, strlen (zInclQuote),
|
|
&inclQuoteRegex);
|
|
if (pzErr != (char *) NULL)
|
|
{
|
|
fprintf (stderr, zBadComp, "quoted include", "runCompiles",
|
|
zInclQuote, pzErr);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
/*
|
|
* FOR every fixup, ...
|
|
*/
|
|
do
|
|
{
|
|
pTD = pFD->pTestDesc;
|
|
tstCt = pFD->testCt;
|
|
|
|
if (pFD->papzMachs != (const char**)NULL) {
|
|
const char** papzMachs = pFD->papzMachs;
|
|
char* pz = zFileNameBuf;
|
|
char* pzSep = "";
|
|
tCC* pzIfTrue;
|
|
tCC* pzIfFalse;
|
|
tSCC zSkip[] = "skip";
|
|
tSCC zRun[] = "run";
|
|
|
|
sprintf( pz, "case %s in\n", zMachine );
|
|
pz += strlen( pz );
|
|
|
|
if (pFD->fdFlags & FD_MACH_IFNOT) {
|
|
pzIfTrue = zSkip;
|
|
pzIfFalse = zRun;
|
|
} else {
|
|
pzIfTrue = zRun;
|
|
pzIfFalse = zSkip;
|
|
}
|
|
|
|
for (;;) {
|
|
const char* pzMach = *(papzMachs++);
|
|
if (pzMach == (const char*)NULL)
|
|
break;
|
|
sprintf( pz, "%s %s", pzSep, pzMach );
|
|
pz += strlen( pz );
|
|
pzSep = " | \\\n";
|
|
}
|
|
sprintf( pz, " )\n echo %s ;;\n * )\n echo %s ;;\nesac",
|
|
pzIfTrue, pzIfFalse );
|
|
pz = runShell( zFileNameBuf );
|
|
if (*pz == 's') {
|
|
pFD->fdFlags |= FD_SKIP_TEST;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* FOR every test for the fixup, ...
|
|
*/
|
|
while (--tstCt >= 0)
|
|
{
|
|
switch (pTD->type)
|
|
{
|
|
case TT_EGREP:
|
|
case TT_NEGREP:
|
|
if (--reCt < 0)
|
|
{
|
|
fputs ("out of RE's\n", stderr);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
pTD->pTestRegex = pRegex++;
|
|
pzErr = re_compile_pattern (pTD->pzTest,
|
|
strlen (pTD->pzTest),
|
|
pTD->pTestRegex);
|
|
if (pzErr != (char *) NULL)
|
|
{
|
|
fprintf (stderr, zBadComp, "select test", pFD->pzFixName,
|
|
pTD->pzTest, pzErr);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
pTD++;
|
|
}
|
|
}
|
|
while (pFD++, --fixCt > 0);
|
|
}
|
|
|
|
|
|
FILE *
|
|
createFile (pzFile)
|
|
const char *pzFile;
|
|
{
|
|
int fd;
|
|
FILE *pf;
|
|
char fname[MAXPATHLEN];
|
|
|
|
sprintf (fname, "%s/%s", pzDestDir, pzFile);
|
|
unlink (fname);
|
|
|
|
fd = open (fname, O_WRONLY | O_CREAT);
|
|
|
|
if ((fd < 0) && (errno == ENOENT))
|
|
{
|
|
char *pzDir = strchr (fname + 1, '/');
|
|
struct stat stbf;
|
|
|
|
while (pzDir != (char *) NULL)
|
|
{
|
|
*pzDir = NUL;
|
|
if (stat (fname, &stbf) < 0)
|
|
{
|
|
mkdir (fname, S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP
|
|
| S_IROTH | S_IXOTH);
|
|
}
|
|
|
|
*pzDir = '/';
|
|
pzDir = strchr (pzDir + 1, '/');
|
|
}
|
|
fd = open (fname, O_WRONLY | O_CREAT);
|
|
}
|
|
if (fd < 0)
|
|
{
|
|
fprintf (stderr, "Error %d (%s) creating %s\n",
|
|
errno, strerror (errno), fname);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
fprintf (stderr, "Fixed: %s\n", pzFile);
|
|
pf = fdopen (fd, "w");
|
|
|
|
#ifdef LATER
|
|
{
|
|
static const char zHdr[] =
|
|
"/*\n"
|
|
" * DO NOT EDIT THIS FILE.\n"
|
|
" *\n"
|
|
" * It has been auto-edited by fixincludes from /usr/include/%s\n"
|
|
" * This had to be done to correct non-standard usages in the\n"
|
|
" * original, manufacturer supplied header file.\n"
|
|
" */\n\n";
|
|
|
|
fprintf (pf, zHdr, pzFile);
|
|
}
|
|
#endif
|
|
return pf;
|
|
}
|
|
|
|
tSuccess
|
|
testTest (pTest, pzFile)
|
|
tTestDesc *pTest;
|
|
char* pzFile;
|
|
{
|
|
char *pzRes;
|
|
tSuccess res = FAILURE;
|
|
|
|
static char zCmdBuf[4096];
|
|
tSCC zCmdFmt[] = "file=%s\nif ( test %s ) > /dev/null 2>&1\n"
|
|
"then echo TRUE\n" "else echo FALSE\n" "fi";
|
|
|
|
sprintf (zCmdBuf, zCmdFmt, pzFile, pTest->pzTest);
|
|
pzRes = runShell (zCmdBuf);
|
|
if (*pzRes == 'T')
|
|
res = SUCCESS;
|
|
free ((void *) pzRes);
|
|
return res;
|
|
}
|
|
|
|
|
|
tSuccess
|
|
egrepTest (pzDta, pTest)
|
|
char *pzDta;
|
|
tTestDesc *pTest;
|
|
{
|
|
regmatch_t match;
|
|
#ifndef NO_BOGOSITY
|
|
if (pTest->pTestRegex == 0)
|
|
fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n", pTest->pzTest);
|
|
#endif
|
|
if (regexec (pTest->pTestRegex, pzDta, 1, &match, 0) == 0)
|
|
return SUCCESS;
|
|
return FAILURE;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
extractQuotedFiles (pzDta, pzFile, pMatch)
|
|
char *pzDta;
|
|
const char *pzFile;
|
|
regmatch_t *pMatch;
|
|
{
|
|
char *pzDirEnd = strrchr (pzFile, '/');
|
|
char *pzInclQuot = pzDta;
|
|
|
|
fprintf (stderr, "Quoted includes in %s\n", pzFile);
|
|
|
|
/*
|
|
* Set "pzFile" to point to the containing subdirectory of the source
|
|
* If there is none, then it is in our current direcory, ".".
|
|
*/
|
|
if (pzDirEnd == (char *) NULL)
|
|
pzFile = ".";
|
|
else
|
|
*pzDirEnd = '\0';
|
|
|
|
for (;;)
|
|
{
|
|
pzInclQuot += pMatch->rm_so;
|
|
|
|
/*
|
|
* Skip forward to the included file name
|
|
*/
|
|
while (isspace (*pzInclQuot))
|
|
pzInclQuot++;
|
|
while (isspace (*++pzInclQuot));
|
|
pzInclQuot += sizeof ("include") - 1;
|
|
while (*pzInclQuot++ != '"');
|
|
|
|
/*
|
|
* Print the source directory and the subdirectory of the file
|
|
* in question.
|
|
*/
|
|
printf ("%s %s/", pzSrcDir, pzFile);
|
|
pzDirEnd = pzInclQuot;
|
|
|
|
/*
|
|
* Append to the directory the relative path of the desired file
|
|
*/
|
|
while (*pzInclQuot != '"')
|
|
putc (*pzInclQuot++, stdout);
|
|
|
|
/*
|
|
* Now print the destination directory appended with the relative
|
|
* path of the desired file
|
|
*/
|
|
printf (" %s/%s/", pzDestDir, pzFile);
|
|
while (*pzDirEnd != '"')
|
|
putc (*pzDirEnd++, stdout);
|
|
|
|
/*
|
|
* End of entry
|
|
*/
|
|
putc ('\n', stdout);
|
|
|
|
/*
|
|
* Find the next entry
|
|
*/
|
|
if (regexec (&inclQuoteRegex, pzInclQuot, 1, pMatch, 0) != 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Process the potential fixes for a particular include file
|
|
*/
|
|
void
|
|
process (pzDta, pzDir, pzFile)
|
|
char *pzDta;
|
|
const char *pzDir;
|
|
const char *pzFile;
|
|
{
|
|
static char zEnvFile[1024] =
|
|
{"file="};
|
|
tFixDesc *pFD = fixDescList;
|
|
int todoCt = FIX_COUNT;
|
|
tFdPair fdp =
|
|
{-1, -1};
|
|
|
|
/*
|
|
* IF this is the first time through,
|
|
* THEN put the 'file' environment variable into the environment.
|
|
* This is used by some of the subject shell scripts and tests.
|
|
*/
|
|
if (zEnvFile[5] == NUL)
|
|
putenv (zEnvFile);
|
|
|
|
/*
|
|
* Ghastly as it is, this actually updates the value of the variable:
|
|
*
|
|
* putenv(3C) C Library Functions putenv(3C)
|
|
*
|
|
* DESCRIPTION
|
|
* putenv() makes the value of the environment variable name
|
|
* equal to value by altering an existing variable or creating
|
|
* a new one. In either case, the string pointed to by string
|
|
* becomes part of the environment, so altering the string will
|
|
* change the environment. string points to a string of the
|
|
* form ``name=value.'' The space used by string is no longer
|
|
* used once a new string-defining name is passed to putenv().
|
|
*/
|
|
strcpy (zEnvFile + 5, pzFile);
|
|
chainHead = NOPROCESS;
|
|
|
|
/*
|
|
* For every fix in our fix list, ...
|
|
*/
|
|
for (; todoCt > 0; pFD++, todoCt--)
|
|
{
|
|
tTestDesc *pTD;
|
|
int tstCt;
|
|
tSuccess egrepRes;
|
|
|
|
if (pFD->fdFlags & FD_SKIP_TEST)
|
|
continue;
|
|
|
|
/*
|
|
* IF there is a file name restriction,
|
|
* THEN ensure the current file name matches one in the pattern
|
|
*/
|
|
if (pFD->pzFileList != (char *) NULL)
|
|
{
|
|
const char *pzFil = pzFile;
|
|
const char *pzScn = pFD->pzFileList;
|
|
size_t nmLen;
|
|
|
|
while ((pzFil[0] == '.') && (pzFil[1] == '/'))
|
|
pzFil += 2;
|
|
nmLen = strlen (pzFil);
|
|
|
|
for (;;)
|
|
{
|
|
pzScn = strstr (pzScn + 1, pzFil);
|
|
if (pzScn == (char *) NULL)
|
|
goto nextFix;
|
|
if ((pzScn[-1] == '|') && (pzScn[nmLen] == '|'))
|
|
break;
|
|
}
|
|
}
|
|
|
|
egrepRes = PROBLEM;
|
|
|
|
/*
|
|
* IF there are no tests
|
|
* THEN we always run the fixup
|
|
*/
|
|
for (pTD = pFD->pTestDesc, tstCt = pFD->testCt;
|
|
tstCt-- > 0;
|
|
pTD++)
|
|
{
|
|
switch (pTD->type)
|
|
{
|
|
case TT_TEST:
|
|
/*
|
|
* IF *any* of the shell tests fail,
|
|
* THEN do not process the fix.
|
|
*/
|
|
if (!SUCCESSFUL (testTest (pTD, pzFile)))
|
|
goto nextFix;
|
|
break;
|
|
|
|
case TT_EGREP:
|
|
/*
|
|
* IF we have not had a successful egrep test
|
|
* *AND* this test does not pass,
|
|
* THEN mark the egrep test as failing. It starts
|
|
* out as a "PROBLEM", meaning that if we do not
|
|
* encounter any egrep tests, then we will let it pass.
|
|
*/
|
|
if ((!SUCCESSFUL (egrepRes))
|
|
&& (!SUCCESSFUL (egrepTest (pzDta, pTD))))
|
|
|
|
egrepRes = FAILURE;
|
|
|
|
break;
|
|
|
|
case TT_NEGREP:
|
|
/*
|
|
* IF *any* of the negative egrep tests fail,
|
|
* THEN do not process the fix.
|
|
*/
|
|
if (SUCCESSFUL (egrepTest (pzDta, pTD)))
|
|
goto nextFix;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* IF there were no egrep tests *OR* at least one passed, ...
|
|
*/
|
|
if (!FAILED (egrepRes))
|
|
{
|
|
fprintf (stderr, "Applying %-32s to %s\n",
|
|
pFD->pzFixName, pzFile);
|
|
|
|
if (fdp.readFd == -1)
|
|
{
|
|
fdp.readFd = open (pzFile, O_RDONLY);
|
|
if (fdp.readFd < 0)
|
|
{
|
|
fprintf (stderr, "Error %d (%s) opening %s\n", errno,
|
|
strerror (errno), pzFile);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
int newFd = chainOpen (fdp.readFd,
|
|
(tpChar *) pFD->papzPatchArgs,
|
|
(chainHead == -1)
|
|
? &chainHead : (pid_t *) NULL);
|
|
if (newFd != -1)
|
|
{
|
|
fdp.readFd = newFd;
|
|
break;
|
|
}
|
|
|
|
fprintf (stderr, "Error %d (%s) starting filter process "
|
|
"for %s\n", errno, strerror (errno),
|
|
pFD->pzFixName);
|
|
|
|
if (errno != EAGAIN)
|
|
exit (EXIT_FAILURE);
|
|
sleep (1);
|
|
}
|
|
}
|
|
|
|
nextFix:;
|
|
}
|
|
|
|
/*
|
|
* IF after all the tests we did not start any patch programs,
|
|
* THEN quit now.
|
|
*/
|
|
if (fdp.readFd < 0)
|
|
return;
|
|
|
|
{
|
|
FILE *inFp = fdopen (fdp.readFd, "r");
|
|
FILE *oFp = (FILE *) NULL;
|
|
char *pzCmp = pzDta;
|
|
|
|
for (;;)
|
|
{
|
|
int ch;
|
|
|
|
ch = getc (inFp);
|
|
if (ch == EOF)
|
|
break;
|
|
|
|
if (oFp != (FILE *) NULL)
|
|
putc (ch, oFp);
|
|
|
|
else if (ch != *pzCmp)
|
|
{
|
|
oFp = createFile (pzFile);
|
|
if (pzCmp != pzDta)
|
|
{
|
|
char c = *pzCmp;
|
|
*pzCmp = NUL;
|
|
fputs (pzDta, oFp);
|
|
*pzCmp = c;
|
|
}
|
|
putc (ch, oFp);
|
|
|
|
}
|
|
else
|
|
pzCmp++;
|
|
}
|
|
|
|
if (oFp != (FILE *) NULL)
|
|
{
|
|
regmatch_t match;
|
|
|
|
fchmod (fileno (oFp), S_IRUSR | S_IRGRP | S_IROTH);
|
|
fclose (oFp);
|
|
if (regexec (&inclQuoteRegex, pzDta, 1, &match, 0) == 0)
|
|
extractQuotedFiles (pzDta, pzFile, &match);
|
|
}
|
|
|
|
fclose (inFp);
|
|
}
|
|
|
|
close (fdp.readFd);
|
|
}
|