diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2024-03-26 16:43:03 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2024-04-02 18:55:46 -0400 |
commit | 9910a30f0c26b3180d46418abad760f86a253aa2 (patch) | |
tree | 6c5209b5decbdc4206a90dfb3120ebbe88525d65 /src | |
parent | 232763cb702e5b39ec5a051ec41582e42adaef59 (diff) | |
download | stasis-9910a30f0c26b3180d46418abad760f86a253aa2.tar.gz |
Fix replace_text*() functions
* Now return an error code
* Completely rewrote replace_text()
Diffstat (limited to 'src')
-rw-r--r-- | src/relocation.c | 106 |
1 files changed, 76 insertions, 30 deletions
diff --git a/src/relocation.c b/src/relocation.c index b92af2b..8b18efd 100644 --- a/src/relocation.c +++ b/src/relocation.c @@ -10,7 +10,10 @@ * ~~~{.c} * char *str = (char *)calloc(100, sizeof(char)); * strcpy(str, "This are a test."); - * replace_text(str, "are", "is"); + * if (replace_text(str, "are", "is")) { + * fprintf(stderr, "string replacement failed\n"); + * exit(1); + * } * // str is: "This is a test." * free(str); * ~~~ @@ -18,64 +21,106 @@ * @param original string to modify * @param target string value to replace * @param replacement string value + * @return 0 on success, -1 on error */ -void replace_text(char *original, const char *target, const char *replacement) { +int replace_text(char *original, const char *target, const char *replacement) { char buffer[OMC_BUFSIZ]; - char *tmp = original; + char *pos = original; + char *match = NULL; + size_t original_len = strlen(original); + size_t target_len = strlen(target); + size_t rep_len = strlen(replacement); + size_t buffer_len = 0; + + if (original_len > sizeof(buffer)) { + errno = EINVAL; + SYSERROR("The original string is larger than buffer: %zu > %zu\n", original_len, sizeof(buffer)); + return -1; + } memset(buffer, 0, sizeof(buffer)); - while (*tmp != '\0') { - if (!strncmp(tmp, target, strlen(target))) { - size_t replen; - char *stop_at = strchr(tmp, '\n'); - if (stop_at) { - replen = (stop_at - tmp); - } else { - replen = strlen(replacement); + if ((match = strstr(pos, target))) { + while (*pos != '\0') { + // append to buffer the bytes leading up to the match + strncat(buffer, pos, match - pos); + // position in the string jump ahead to the beginning of the match + pos = match; + + // replacement is shorter than the target + if (rep_len < target_len) { + // shrink the string + strcat(buffer, replacement); + memmove(pos, pos + target_len, strlen(pos) - target_len); + memset(pos + (strlen(pos) - target_len), 0, target_len); + } else { // replacement is longer than the target + // write the replacement value to the buffer + strcat(buffer, replacement); + // target consumed. jump to the end of the substring. + pos += target_len; + } + // find more matches + if (!(match = strstr(pos, target))) { + // no more matches + // append whatever remains to the buffer + strcat(buffer, pos); + // stop + break; } - strcat(buffer, replacement); - strcat(buffer, "\n"); - tmp += replen; - } else { - strncat(buffer, tmp, 1); } - tmp++; } + + buffer_len = strlen(buffer); + if (buffer_len < original_len) { + // truncate whatever remains of the original buffer + memset(original + buffer_len, 0, original_len - buffer_len); + } + // replace original with contents of buffer strcpy(original, buffer); + return 0; } /** * Replace `target` with `replacement` in `filename` * * ~~~{.c} - * file_replace_text("/path/to/file.txt, "are", "is"); + * if (file_replace_text("/path/to/file.txt, "are", "is")) { + * fprintf(stderr, "failed to replace strings in file\n"); + * exit(1); + * } * ~~~ * * @param filename path to file * @param target string value to replace * @param replacement string + * @return 0 on success, -1 on error */ -void file_replace_text(const char* filename, const char* target, const char* replacement) { - FILE *fp = fopen(filename, "r"); - if (fp == NULL) { - fprintf(stderr, "unable to open for reading: %s\n", filename); - return; - } - +int file_replace_text(const char* filename, const char* target, const char* replacement) { + int result; char buffer[OMC_BUFSIZ]; char tempfilename[] = "tempfileXXXXXX"; - FILE *tfp = fopen(tempfilename, "w"); + FILE *fp; + FILE *tfp; + + fp = fopen(filename, "r"); + if (!fp) { + fprintf(stderr, "unable to open for reading: %s\n", filename); + return -1; + } - if (tfp == NULL) { - fprintf(stderr, "unable to open temporary fp for writing: %s\n", tempfilename); + tfp = fopen(tempfilename, "w"); + if (!tfp) { + SYSERROR("unable to open temporary fp for writing: %s", tempfilename); fclose(fp); - return; + return -1; } // Write modified strings to temporary file + result = 0; while (fgets(buffer, sizeof(buffer), fp)) { if (strstr(buffer, target)) { - replace_text(buffer, target, replacement); + if (replace_text(buffer, target, replacement)) { + result = -1; + } } fputs(buffer, tfp); } @@ -86,4 +131,5 @@ void file_replace_text(const char* filename, const char* target, const char* rep // Replace original with modified copy remove(filename); rename(tempfilename, filename); + return result; }
\ No newline at end of file |