1//
2// Quick hack to work around not having sed, or any other reasonable
3// way to edit a file from a script on Windows......
4//
5// Copyright (c) 2010, Apple Inc. All rights reserved.<BR>
6//
7//  This program and the accompanying materials
8//  are licensed and made available under the terms and conditions of the BSD License
9//  which accompanies this distribution.  The full text of the license may be found at
10//  http://opensource.org/licenses/bsd-license.php
11//
12//  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13//  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14//
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <limits.h>
19
20#define TRUE  1
21#define FALSE 0
22
23typedef struct {
24  char  *Match;
25  int   MatchSize;
26  char  *Replace;
27} MATCH_PAIR;
28
29void
30Usage (char *Name)
31{
32  printf ("\n%s OldFile NewFile MatchString ReplaceString [MatchString2 ReplaceString2]*\n", Name);
33  printf ("    OldFile - Must be arg[1] File to search for MatchStrings\n");
34  printf ("    NewFile - Must be arg[2] File where MatchString has been replaced with ReplaceString\n");
35  printf ("    MatchString & ReplaceString. Required arguments.\n");
36  printf ("    More MatchString/ReplaceString pairs are supported.\n");
37}
38
39//
40// argv[1] - Old File
41// argv[2] - New File
42// argv[3+n] - Match String
43// argv[4+n] - Replace string
44int
45main (int argc, char **argv)
46{
47  FILE *In, *Out;
48  char *Key, *Replace;
49  int  c, i, n, Len, MaxLenKey = 0, MinLenKey = INT_MAX;
50  unsigned long  InFileSize, InFilePos;
51  MATCH_PAIR *Match;
52  int MaxMatch;
53  int ReadCount;
54  int Found;
55
56  if (argc < 5) {
57    fprintf (stderr, "Need at least two files and one Match/Replacement string pair\n");
58    Usage (argv[0]);
59    return -1;
60  } else if ((argc % 2) == 0) {
61    fprintf (stderr, "Match and Replace string must come in pairs\n");
62    return -4;
63  }
64
65  In  = fopen (argv[1], "r");
66  fseek (In, 0, SEEK_END);
67  InFileSize = ftell (In);
68  if (InFileSize == 0) {
69    fprintf (stderr, "Could not open %s\n", argv[1]);
70    return -6;
71  }
72  fseek (In, 0, SEEK_SET);
73
74
75  Out = fopen (argv[2], "w+");
76  if ((In == NULL) || (Out == NULL)) {
77    fprintf (stderr, "Could not open %s\n", argv[2]);
78    return -2;
79  }
80
81  MaxMatch = (argc - 2)/2;
82  Match = calloc (MaxMatch, sizeof (MATCH_PAIR));
83  if (Match == NULL) {
84    return -7;
85  }
86
87  for (n=0; n < MaxMatch; n++) {
88    Match[n].Match   = argv[3 + n*2];
89    Match[n].MatchSize = strlen (argv[3 + n*2]);
90    Match[n].Replace = argv[3 + n*2 + 1];
91    if (Match[n].MatchSize > MaxLenKey) {
92      // Max size of match/replace string pair
93      MaxLenKey = Match[n].MatchSize;
94    }
95    if (Match[n].MatchSize < MinLenKey) {
96      MinLenKey = Match[n].MatchSize;
97    }
98  }
99
100  Key = malloc (MaxLenKey);
101  if (Key == NULL) {
102    return -5;
103  }
104
105  // Search for a match by reading every possition of the file
106  // into a buffer that is as big as the maximum search key size.
107  // Then we can search the keys for a match. If no match
108  // copy the old file character to the new file. If it is a match
109  // then copy the replacement string into the output file.
110  // This code assumes the file system is smart and caches the
111  // file in a buffer. So all the reads don't really hit the disk.
112  InFilePos = 0;
113  while (InFilePos < (InFileSize - MinLenKey)) {
114    fseek (In, InFilePos, SEEK_SET);
115    ReadCount = fread (Key, 1, MaxLenKey, In);
116    for (i = 0, Found = FALSE;i < MaxMatch; i++) {
117      if (ReadCount >= Match[i].MatchSize) {
118        if (!memcmp (Key, Match[i].Match, Match[i].MatchSize)) {
119          InFilePos += (Match[i].MatchSize - 1);
120          fputs (Match[i].Replace, Out);
121          Found = TRUE;
122          break;
123        }
124      }
125    }
126    if (!Found) {
127      fputc (Key[0], Out);
128    }
129
130    InFilePos++;
131  }
132
133  // We stoped searching when we got to the point that we could no longer match.
134  // So the last few bytes of the file are not copied in the privous loop
135  fseek (In, InFilePos, SEEK_SET);
136  while ((c = fgetc (In)) != EOF) {
137    fputc (c, Out);
138  }
139
140  fclose (In);
141  fclose (Out);
142  free (Key);
143  free (Match);
144  return 0;
145}
146
147