/* * bp.c -- * * This file contains the "bp" ("binary patch") program. It is used * to replace configuration strings in Tcl/Tk binaries as part of * installation. * * Usage: bp file search replace * * This program searches file bp for the first occurrence of the * character string given by "search". If it is found, then the * first characters of that string get replaced by the string * given by "replace". The replacement string is NULL-terminated. * * Copyright (c) 1996 Sun Microsystems, Inc. * All rights reserved. * This file is NOT subject to the terms described in "license.terms". * * SCCS: @(#) bp.c 1.2 96/03/12 09:08:26 */ #include #include extern int errno; /* * The array below saves the last few bytes read from the file, so that * they can be compared against a particular string that we're looking * for. */ #define BUFFER_SIZE 200 char buffer[BUFFER_SIZE]; int main(argc, argv) int argc; /* Number of command-line arguments. */ char **argv; /* Values of command-line arguments. */ { int length, matchChar, fileChar, cur, fileIndex, stringIndex; char *s; FILE *f; if (argc != 4) { fprintf(stderr, "Wrong # args: should be \"%s fileName string replace\"\n", argv[0]); exit(1); } f = fopen(argv[1], "r+"); if (f == NULL) { fprintf(stderr, "Couldn't open \"%s\" for writing: %s\n", argv[1], strerror(errno)); exit(1); } for (cur = 0; cur < BUFFER_SIZE; cur++) { buffer[cur] = 0; } s = argv[2]; length = strlen(s); if (length > BUFFER_SIZE) { fprintf(stderr, "String \"%s\" too long; must be %d or fewer chars.\n", s, BUFFER_SIZE); exit(1); } matchChar = s[length-1]; while (1) { fileChar = getc(f); if (fileChar == EOF) { if (ferror(f)) { goto ioError; } fprintf(stderr, "Couldn't find string \"%s\"\n", argv[2]); exit(1); } buffer[cur] = fileChar; if (fileChar == matchChar) { /* * Last character of the string matches the current character * from the file. Search backwards through the buffer to * see if the preceding characters from the file match the * characters from the string. */ for (fileIndex = cur-1, stringIndex = length-2; stringIndex >= 0; fileIndex--, stringIndex--) { if (fileIndex < 0) { fileIndex = BUFFER_SIZE-1; } if (buffer[fileIndex] != s[stringIndex]) { goto noMatch; } } /* * Matched! Backup to the start of the string, then * overwrite it with the replacement value. */ if (fseek(f, -length, SEEK_CUR) == -1) { goto ioError; } if (fwrite(argv[3], strlen(argv[3])+1, 1, f) == 0) { goto ioError; } exit(0); } /* * No match; go on to next character of file. */ noMatch: cur++; if (cur >= BUFFER_SIZE) { cur = 0; } } ioError: fprintf(stderr, "I/O error: %s\n", strerror(errno)); exit(1); }