113 lines
2.9 KiB
C
113 lines
2.9 KiB
C
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include "liberror.h"
|
|
|
|
void
|
|
exhaust_buffer(char *b, size_t s){
|
|
size_t i;
|
|
for(i = 0; i < s; ++i)
|
|
if(b[i] != 0)
|
|
putc(b[i], stdout);
|
|
free(b);
|
|
return;
|
|
}
|
|
|
|
void
|
|
print_stdin(void){
|
|
char c;
|
|
while((c = getc(stdin)) != EOF)
|
|
putc(c, stdout);
|
|
return;
|
|
}
|
|
|
|
void
|
|
substitute(char *phrase, char *substitution, bool exit_on_first, char *name){
|
|
char *b = (char *)calloc(strlen(phrase)+1, sizeof(char));
|
|
size_t i;
|
|
if(b == NULL)
|
|
error(name, ALLOCATION_ERROR);
|
|
while((b[strlen(phrase)-1] = getc(stdin)) != EOF){
|
|
for(i = 0;
|
|
b[i] == phrase[i]
|
|
&& b[i] != 0
|
|
&& phrase[i] != 0;
|
|
++i);
|
|
if(i == strlen(phrase)){
|
|
fputs(substitution, stdout);
|
|
for(i = 0; i < strlen(phrase);)
|
|
b[i++] = 0;
|
|
if(exit_on_first){
|
|
exhaust_buffer(b, strlen(phrase)+1);
|
|
print_stdin();
|
|
}
|
|
}else
|
|
putc(*b, stdout);
|
|
|
|
/* There's a more efficient way to maintain a buffer here,
|
|
* where I keep an unordered string of chars and form an
|
|
* ordered string when I need to check against the phrase
|
|
* to match. However it's math-intensive, which sucks not just
|
|
* for a self-taught lamer but in general in regards to muh
|
|
* simplicity, and the math undercuts the performance gain
|
|
* from avoiding touching memory. Also, come on, you're never
|
|
* gonna have a phrase longer than 100 bytes! Who cares?! */
|
|
for(i = 0; i < strlen(phrase); ++i)
|
|
b[i] = b[i+1];
|
|
}
|
|
exhaust_buffer(b, strlen(phrase)+1);
|
|
}
|
|
|
|
void
|
|
usage(char *name){
|
|
fprintf(stdout, "Usage: %s (-fhr) [phrase] [substitution]\n", name);
|
|
exit(1);
|
|
}
|
|
|
|
int main(int argc, char *argv[]){
|
|
extern char *optarg;
|
|
extern int optind;
|
|
bool exit_on_first = 0;
|
|
char c;
|
|
char *argv0 = argv[0];
|
|
bool regex_mode = 0;
|
|
|
|
while((c = getopt(argc, argv, "fhr")) != -1){
|
|
switch(c){
|
|
/* -f exists because there exist uses of `sed 's/foo/bar/'`
|
|
* without the trailing `g` for global substitution that
|
|
* would be borked if made global. Perhaps there are other ways
|
|
* to do so that mean that this option doesn't need to be
|
|
* implemented, but it's kind of easy to just add so
|
|
* whatever. */
|
|
case 'f': exit_on_first = 1;
|
|
case 'h': usage(argv0);
|
|
/* By default regex is not parsed; this is because regular
|
|
* expressions are not known to the GENERAL user. The kind of
|
|
* user that uses this utility /does/ know regex, but the kind
|
|
* of user this utility targets does not, so don't implement
|
|
* potentially undesirable functionality by default.
|
|
* If you know regex you know how to look up a manpage. */
|
|
case 'r':
|
|
regex_mode = 1;
|
|
break;
|
|
case '?': default: usage(argv0);
|
|
}
|
|
}
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
if(argc < 2 || argc > 3)
|
|
usage(argv0);
|
|
|
|
if(regex_mode == 0)
|
|
substitute(argv[0], argv[1], exit_on_first, argv0);
|
|
else
|
|
{ printf("Not implemented.\n"); exit(1); }
|
|
// substitute_regex(argv[0], argv[1], exit_on_first, argv0);
|
|
|
|
return 0;
|
|
}
|