Home | History | Annotate | Download | only in Tools
      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 
     23 typedef struct {
     24   char  *Match;
     25   int   MatchSize;
     26   char  *Replace;
     27 } MATCH_PAIR;
     28 
     29 void
     30 Usage (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
     44 int
     45 main (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