├── .gitignore ├── Makefile ├── LICENSE └── find_replace.c /.gitignore: -------------------------------------------------------------------------------- 1 | /find_replace 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | find_replace: find_replace.c 2 | gcc -std=c11 -o find_replace find_replace.c 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2016 Brenton Fletcher (https://github.com/bloopletech i@bloople.net) 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /find_replace.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | //from http://creativeandcritical.net/str-replace-c/ 13 | char *replace_str2(const char *str, const char *old, const char *new) 14 | { 15 | char *ret, *r; 16 | const char *p, *q; 17 | size_t oldlen = strlen(old); 18 | size_t count, retlen, newlen = strlen(new); 19 | int samesize = (oldlen == newlen); 20 | 21 | if (!samesize) { 22 | for (count = 0, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen) 23 | count++; 24 | /* This is undefined if p - str > PTRDIFF_MAX */ 25 | retlen = p - str + strlen(p) + count * (newlen - oldlen); 26 | } else 27 | retlen = strlen(str); 28 | 29 | if ((ret = malloc(retlen + 1)) == NULL) 30 | return NULL; 31 | 32 | r = ret, p = str; 33 | while (1) { 34 | /* If the old and new strings are different lengths - in other 35 | * words we have already iterated through with strstr above, 36 | * and thus we know how many times we need to call it - then we 37 | * can avoid the final (potentially lengthy) call to strstr, 38 | * which we already know is going to return NULL, by 39 | * decrementing and checking count. 40 | */ 41 | if (!samesize && !count--) 42 | break; 43 | /* Otherwise i.e. when the old and new strings are the same 44 | * length, and we don't know how many times to call strstr, 45 | * we must check for a NULL return here (we check it in any 46 | * event, to avoid further conditions, and because there's 47 | * no harm done with the check even when the old and new 48 | * strings are different lengths). 49 | */ 50 | if ((q = strstr(p, old)) == NULL) 51 | break; 52 | /* This is undefined if q - p > PTRDIFF_MAX */ 53 | ptrdiff_t l = q - p; 54 | memcpy(r, p, l); 55 | r += l; 56 | memcpy(r, new, newlen); 57 | r += newlen; 58 | p = q + oldlen; 59 | } 60 | strcpy(r, p); 61 | 62 | return ret; 63 | } 64 | 65 | void find_replace(char *path, char *from, char *to) { 66 | int fd = open(path, O_RDWR); 67 | if(fd == -1) { 68 | error(1, errno, "Error when trying to open file %s", path); 69 | } 70 | 71 | struct stat file_stat; 72 | if(fstat(fd, &file_stat) == -1) { 73 | error(1, errno, "Error when trying to get file metadata %s", path); 74 | } 75 | 76 | char *buffer = malloc(file_stat.st_size + 1); 77 | buffer[file_stat.st_size] = '\0'; 78 | 79 | if(read(fd, buffer, file_stat.st_size) == -1) { 80 | free(buffer); 81 | error(1, errno, "Error when trying to read from %s", path); 82 | } 83 | 84 | if(lseek(fd, 0, SEEK_SET) == -1) { 85 | free(buffer); 86 | error(1, errno, "Error when trying to seek in %s", path); 87 | } 88 | 89 | char *replaced = replace_str2(buffer, from, to); 90 | free(buffer); 91 | 92 | if(!replaced) { 93 | error(1, 0, "Error trying to replace string in %s", path); 94 | } 95 | 96 | if(write(fd, replaced, strlen(replaced)) == -1) { 97 | free(replaced); 98 | error(1, errno, "Error when trying to write to %s", path); 99 | } 100 | 101 | free(replaced); 102 | 103 | if(close(fd) == -1) { 104 | error(1, errno, "Error when trying to close file %s", path); 105 | } 106 | } 107 | 108 | int main(int argc, char *argv[]) { 109 | if(argc < 4) { 110 | error(1, 0, "Usage: find_replace FROM TO file1 [file2 file3...]"); 111 | } 112 | 113 | char *from = argv[1]; 114 | char *to = argv[2]; 115 | 116 | for(int i = 3; i < argc; ++i) { 117 | find_replace(argv[i], from, to); 118 | } 119 | } 120 | --------------------------------------------------------------------------------