Skip to content

Instantly share code, notes, and snippets.

@neuro-sys
Last active March 28, 2020 09:22
Show Gist options
  • Save neuro-sys/3bf00b6cf28a93e07e44 to your computer and use it in GitHub Desktop.
Save neuro-sys/3bf00b6cf28a93e07e44 to your computer and use it in GitHub Desktop.
Replace string in file (similar to MariaDB/MySQL replace utility)
// This is free and unencumbered software released into the public domain.
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// For more information, please refer to <http://unlicense.org/>
// Usage: ./replace "foobar" "foobaz" < input_file > output_file
// Note: input_file and output_file should be different
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct string_t {
const char * value;
size_t length;
} string;
struct parser_t {
string match_text, replace_text;
char * match_buffer;
unsigned int match_buffer_index;
enum { STATE_INVALID, STATE_IN, STATE_OUT } state;
};
void parser_init(struct parser_t * parser,
const char * match_text,
const char * replace_text)
{
memset(parser, 0, sizeof(struct parser_t));
parser->match_text.value = match_text;
parser->match_text.length = strlen(match_text);
parser->replace_text.value = replace_text;
parser->replace_text.length = strlen(replace_text);
parser->state = STATE_OUT;
parser->match_buffer = malloc(parser->match_text.length);
}
void parser_free(struct parser_t * parser)
{
free(parser->match_buffer);
}
void output_char(char current_char)
{
fwrite(&current_char, sizeof(char), 1, stdout);
}
void buffer_match(struct parser_t * parser, char current_char)
{
parser->match_buffer[parser->match_buffer_index++] = current_char;
}
void buffer_clear(struct parser_t * parser)
{
parser->match_buffer_index = 0;
}
void buffer_flush(struct parser_t * parser)
{
if (parser->match_buffer_index > 0) {
fwrite(parser->match_buffer, sizeof(char), parser->match_buffer_index, stdout);
buffer_clear(parser);
}
}
int process_state_in(struct parser_t * parser, char current_char)
{
if (parser->match_text.value[parser->match_buffer_index] == current_char) {
buffer_match(parser, current_char);
return STATE_IN;
}
if (parser->match_buffer_index == parser->match_text.length) {
fwrite(parser->replace_text.value, sizeof(char), parser->replace_text.length, stdout);
buffer_clear(parser);
output_char(current_char);
return STATE_OUT;
}
if (parser->match_text.value[parser->match_buffer_index] != current_char) {
buffer_flush(parser);
output_char(current_char);
return STATE_OUT;
}
return STATE_INVALID;
}
int process_state_out(struct parser_t * parser, char current_char)
{
if (parser->match_text.value[parser->match_buffer_index] == current_char) {
buffer_match(parser, current_char);
return STATE_IN;
}
if (parser->match_text.value[parser->match_buffer_index] != current_char) {
buffer_flush(parser);
output_char(current_char);
return STATE_OUT;
}
return STATE_INVALID;
}
int main(int argc, char *argv[])
{
char current_char;
struct parser_t parser;
if (argc != 3) {
fprintf(stdout, "Usage:\n\t%s match_text replace_text < in_file > out_file\n\t# note in_file and out_file should be different.\n", argv[0]);
return 0;
}
parser_init(&parser, argv[1], argv[2]);
while (fread(&current_char, sizeof(char), 1, stdin) != 0) {
switch (parser.state) {
case STATE_IN:
{
parser.state = process_state_in(&parser, current_char);
}
break;
case STATE_OUT:
{
parser.state = process_state_out(&parser, current_char);
}
break;
default:
fprintf(stderr, "Error: Invalid state.\n");
return -1;
break;
}
}
parser_free(&parser);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment