diff options
| author | Charles Cabergs <me@cacharle.xyz> | 2020-08-09 14:11:22 +0200 |
|---|---|---|
| committer | Charles Cabergs <me@cacharle.xyz> | 2020-08-09 14:11:22 +0200 |
| commit | f34a2016a18a61ce17f0a9b11a1a52642fca062b (patch) | |
| tree | 55d276b439d2ee7768a9fef67dd1cdae692d02b3 /tr.c | |
| parent | 2c513e352142d1e19340ca2c12beb54657e9254a (diff) | |
| download | coreutils-f34a2016a18a61ce17f0a9b11a1a52642fca062b.tar.gz coreutils-f34a2016a18a61ce17f0a9b11a1a52642fca062b.tar.bz2 coreutils-f34a2016a18a61ce17f0a9b11a1a52642fca062b.zip | |
Added tr [WIP]
Diffstat (limited to 'tr.c')
| -rw-r--r-- | tr.c | 229 |
1 files changed, 229 insertions, 0 deletions
@@ -0,0 +1,229 @@ +#define _POSIX_C_SOURCE 2 +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <ctype.h> +#include <stdbool.h> +#include <string.h> +#include <assert.h> + +typedef enum +{ + FLAG_COMPLEMENT = 1 << 0, + FLAG_DELETE = 1 << 1, + FLAG_SQUEEZE = 1 << 2, +} t_flags; + + +typedef enum +{ + MTAG_CHAR, + MTAG_CLASS, + MTAG_RANGE, + /* MTAG_REPEAT, */ + /* MTAG_EQUIVALENT, */ // e.g [=e=] == eéèê +} t_matcher_tag; + +typedef struct +{ + t_matcher_tag tag; + union + { + char c; + int (*class)(int c); + char range[2]; + struct + { + char c; + size_t count; + } repeat; + }; +} t_matcher; + +struct char_class_entry { + char *id; + int (*func)(int c); +}; + +struct char_class_entry char_classes[] = { + {"[:alnum:]", isalnum}, + {"[:alpha:]", isalpha}, + {"[:blank:]", isblank}, + {"[:cntrl:]", iscntrl}, + {"[:digit:]", isdigit}, + {"[:graph:]", isgraph}, + {"[:lower:]", islower}, + {"[:print:]", isprint}, + {"[:punct:]", ispunct}, + {"[:space:]", isspace}, + {"[:upper:]", isupper}, + {"[:xdigit:]", isxdigit}, +}; + +typedef struct +{ + t_matcher *array; + size_t count; +} t_matchers; + +void matchers_push(t_matchers *matchers, t_matcher_tag tag, void *data) +{ + t_matcher *pushed; + + matchers->count++; + matchers->array = realloc(matchers->array, matchers->count); + assert(matchers->array != NULL); + pushed = &matchers->array[matchers->count - 1]; + pushed->tag = tag; + switch (tag) + { + case MTAG_CHAR: + pushed->c = *(char*)data; + break; + case MTAG_CLASS: + pushed->class = (int (*)(int))data; + break; + case MTAG_RANGE: + pushed->range[0] = ((short)data & 0x00ff) >> 0; + pushed->range[1] = ((short)data & 0xff00) >> 8; + break; + default: + abort(); + } +} + +bool isodigit(char c) { return c >= '0' && c <= '7'; } + +void parse(t_matchers *matchers, char *s) +{ + for (size_t i = 0; s[i] != '\0'; i++) + { + if (s[i] == '\\') + { + memmove(&s[i], &s[i + 1], strlen(&s[i + 1])); + + switch (s[i]) + { + case 'a': s[i] = '\a'; break; + case 'b': s[i] = '\b'; break; + case 'f': s[i] = '\f'; break; + case 'n': s[i] = '\n'; break; + case 'r': s[i] = '\r'; break; + case 't': s[i] = '\t'; break; + case 'v': s[i] = '\v'; break; + } + + if (isodigit(s[i])) + { + char num[4] = {'\0'}; + strncpy(num, &s[i], 3); + char *end; + s[i] = strtol(num, &end, 8); + memmove(&s[i + 1], &s[i + 1 + (end - num)], strlen(&s[i + 1 + (end - num)])); + } + matchers_push(matchers, MTAG_CHAR, (void*)s[i]); + } + else if (s[i + 1] == '-' && s[i + 2] != '\0') + matchers_push(matchers, MTAG_RANGE, (void*)(s[i] | (s[i] << 8))); + else if (s[i] == '[' && s[i + 1] == ':') + { + /* for (size_t j = 0; j < sizeof(char_classes) / sizeof(char_class_entry); j++) */ + /* { */ + /* if (strncmp( */ + /* } */ + } + else + matchers_push(matchers, MTAG_CHAR, (void*)s[i]); + } +} + +char *g_name = "tr"; + +void fatal(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + fprintf(stderr, "%s: ", g_name); + vfprintf(stderr, format, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +#define BUFFER_SIZE 256 + +/* +** no 't' flag, truncate is the default behavior +*/ + +int main(int argc, char **argv) +{ + int option; + t_flags flags = 0; + + while ((option = getopt(argc, argv, "cCds")) != -1) + { + switch (option) + { + case 'c': + case 'C': + flags |= FLAG_COMPLEMENT; + break; + case 'd': + flags |= FLAG_DELETE; + break; + case 's': + flags |= FLAG_SQUEEZE; + break; + } + } + if (optind == argc) + fatal("missing operand\n"); + if (argc - optind == 3) + fatal("extra operand '%s'\n", argv[argc - 1]); + + if (flags & FLAG_DELETE && flags & FLAG_SQUEEZE && argc - optind != 2) + fatal("missing operand after '%s'\n" + "Two strings must be given when both deleting and squezzing repeats.\n", + argv[optind]); + + if (flags & FLAG_DELETE && argc - optind != 1) + fatal("extra operand '%s'\n", + "Only one string may be given when deleting without squeezing repeats.\n", + argv[optind + 1]); + + t_matchers set1 = { .array = NULL, .count = 0 }; + t_matchers set2 = { .array = NULL, .count = 0 }; + + char buf[BUFFER_SIZE + 1] = {'\0'}; + size_t read_size; + + while ((read_size = fread(buf, sizeof(char), BUFFER_SIZE, stdin)) > 0) + { + for (size_t i = 0; i < read_size; i++) + { + if (flags & FLAG_DELETE && flags & FLAG_SQUEEZE) + { + + } + else if (flags & FLAG_DELETE && match()) + { + memmove(&buf[i], &buf[i + 1], read_size - i); + + else if (flags & FLAG_SQUEEZE) + { + while (match(s[i + 1])) + + memmove(&buf[i + 1], &buf[i + 2], read_size - i); + } + else + { + if (match()) + buf[i] = set2 + } + } + } + + return EXIT_SUCCESS; +} |
