search_and_replace_strings_in_files.c (6079B)
1 //#!/usr/bin/tcc -run 2 // search and replace 3 // input: 4 // file.txt 5 // replace_configuration.txt 6 // the files to process are listed in file.txt in current directory. 7 // Use # to comment lines in files.txt. 8 // replace_configuration.txt holds the strings to search and replace in the files listed in file.txt 9 // 10 // replace_configuration.txt format: 11 // - line 1: separetor in line 2 and 3 12 // - line 2: strings to search separeted with the characters in line 1 13 // - line 3: replace strings separeted with the characters in line 1 14 15 #include "../release/libsheepy.h" 16 #include "../release/libsheepy.c" 17 #include "pcre.h" 18 19 #define internal static 20 21 #include <stdlib.h> 22 #include <stdbool.h> 23 #include <string.h> 24 #include <stdio.h> 25 26 void replace(); 27 void replaceWithPcre(char **l, pcre *reCompiled, pcre_extra *pcreExtra, char *replaceWith); 28 #ifndef unitTest 29 #endif 30 int MAIN(int ARGC, char** ARGV); 31 32 int argc; char **argv; 33 34 void replace() { 35 char **replace_configuration = NULL; 36 char **search_what = NULL; 37 char **replace_with = NULL; 38 char **config = NULL; 39 40 // Steps 41 // load config 42 // create string regex 43 // compile regexes 44 // optimize the regex 45 // create regex for each search string 46 // for each file in files.txt, search and replace 47 48 printf("\nLoading config...\n"); 49 printf("\n"); 50 51 // load config 52 replace_configuration = readText("replace_configuration.txt"); 53 54 exitFailure(replace_configuration); 55 56 search_what = split(replace_configuration[1], replace_configuration[0]); 57 replace_with = split(replace_configuration[2], replace_configuration[0]); 58 59 if (!search_what || !replace_with) { 60 printf("wrong replace_configuration.txt"); 61 printf("\n"); 62 XFAILURE; 63 } 64 65 // create string regex 66 char **strRegex = NULL; 67 enumerateCharP(search_what, e, i) { 68 printf("Replace: "); 69 printf("\n"); 70 printf("%s\n", *e); 71 printf("With:"); 72 printf("\n"); 73 printf("%s\n", replace_with[i]); 74 char *reg = catS("\\b", *e, "\\b"); 75 pErrorNULL(iListPushS(&strRegex, reg)); 76 } 77 78 //listPrintS(strRegex); 79 80 // compile regexes 81 // optimize the regex 82 size_t nSearch = listLengthS(search_what); 83 pcre **reCompiled = malloc((nSearch+1) * sizeof(pcre *)); 84 reCompiled[nSearch] = NULL; 85 pcre_extra **pcreExtra = malloc((nSearch+1) * sizeof(pcre_extra *)); 86 pcreExtra[nSearch] = NULL; 87 88 const char *pcreErrorStr; 89 int pcreErrorOffset; 90 91 // create regex for each search string 92 enumerateCharP(strRegex, e, j) { 93 reCompiled[j] = pcre_compile(*e, 0, &pcreErrorStr, &pcreErrorOffset, NULL); 94 if (!reCompiled[j]) { 95 printf("ERROR: Could not study >%s<: %s", *e, pcreErrorStr); 96 printf("\n"); 97 XFAILURE; 98 } 99 100 pcreExtra[j] = pcre_study(reCompiled[j], 0, &pcreErrorStr); 101 if (!pcreExtra) { 102 printf("ERROR: Could not study >%s<: %s", *e, pcreErrorStr); 103 printf("\n"); 104 XFAILURE; 105 } 106 } 107 108 109 printf("\n\nProcess files...\n"); 110 printf("\n"); 111 112 config = readText("files.txt"); 113 exitFailure(config); 114 115 // for each file in files.txt, search and replace 116 forEachCharP(config, f) { 117 if (!isBlankS(*f)) { 118 if (*f[0] != '#') { 119 pErrorNULL(iTrimS(f)); 120 char **src = readText(*f); 121 if (!src) { 122 printf("Cant read file %s", *f); 123 printf("\n"); 124 continue; 125 } 126 127 // scan lines 128 forEachCharP(src, l) { 129 enumerateCharP(search_what, a, i) { 130 //iReplaceS_max(l, *a, replace_with[i]); 131 replaceWithPcre(l, reCompiled[i], pcreExtra[i], replace_with[i]); 132 } 133 } 134 135 bool status = writeText(*f, src); 136 if (status) { 137 printf("CHANGED: %s", *f); 138 printf("\n"); 139 } 140 else { 141 printf("DIDNT CHANGE: %s", *f); 142 printf("\n"); 143 } 144 } 145 } 146 } 147 148 listFreeManyS(replace_configuration, search_what, replace_with, config, strRegex); 149 150 forEachType(pcre, reCompiled, e) { 151 pcre_free(*e); 152 } 153 free(reCompiled); 154 155 if (pcreExtra[0]) { 156 forEachType(pcre_extra, pcreExtra, e) { 157 #ifdef PCRE_CONFIG_JIT 158 pcre_free_study(*e); 159 #else 160 pcre_free(*e); 161 #endif 162 } 163 } 164 free(pcreExtra); 165 } 166 167 void replaceWithPcre(char **l, pcre *reCompiled, pcre_extra *pcreExtra, char *replaceWith) { 168 int r; 169 int subStrVec[30]; 170 size_t len; 171 size_t offset = 0;; 172 int allMatch[100]; 173 size_t nMatch = 0;; 174 175 len = strlen(*l); 176 r = pcre_exec(reCompiled, pcreExtra, *l, len, 0, 0, subStrVec, 30); 177 178 while ((offset < len) && (r >= 0)) { 179 180 if (r == 0) { 181 printf("But too many substrings were found to fit in subStrVec!\n"); 182 r = 30/3; 183 } 184 185 for (int j=0; j < r; j++) { 186 allMatch[nMatch] = subStrVec[j*2]; 187 allMatch[nMatch+1] = subStrVec[j*2+1]; 188 nMatch += 2; 189 } 190 191 offset = subStrVec[1]; 192 r = pcre_exec(reCompiled, pcreExtra, *l, len, offset, 0, subStrVec, 30); 193 } 194 195 if (!nMatch) { 196 return; 197 } 198 199 for (int i = nMatch ; i > 0 ; i-=2) { 200 // replace word 201 char *sBefore = emptySF();; 202 203 if (allMatch[i-2]) { 204 // 0 means end of string 205 sBefore = sliceS(*l, 0, allMatch[i-2]); 206 } 207 208 char *sAfter = sliceS(*l, allMatch[i-1], 0); 209 free(*l); 210 *l = catS(sBefore, replaceWith, sAfter); 211 freeManyS(sBefore, sAfter); 212 } 213 } 214 215 // ------------------------------------------------------------------------------------- 216 217 #ifndef unitTest 218 // Remove main when running the unit tests 219 #define MAIN main 220 #endif 221 int MAIN(int ARGC, char** ARGV) { 222 int dum UNUSED; 223 224 argc = ARGC; argv = ARGV;;// 225 226 replace(); 227 228 XSUCCESS; 229 }