#include /* isdigit(3) */ #include /* fprintf(3), getc(3), putc(3) */ #include /* stdin, stderr, stdout */ #include /* EX_DATAERR, EX_OK */ /* Unicode compatibility coming someday */ #define GETC getc #define PUTC putc #define NUMBER_TERMINATOR '*' /* syntax error if a decoding file ends with [char][char] */ /* if(STRICT) just print it out */ #define STRICT 0 static int decode(FILE *input, FILE *output){ int c[2]; unsigned int num; enum{NUMBER_PARSING = 1} state; c[0] = EOF; /* reading -> (current char == prev char)> number parsing -> reading */ while((c[1] = GETC(input)) != EOF) if(state == NUMBER_PARSING){ if(isdigit(c[1])) num = num * 10 + c[1] - '0'; else if(c[1] == NUMBER_TERMINATOR){ for(; num > 0; --num) PUTC(c[0], output); c[0] = EOF; c[1] = EOF; state = 0; }else return EX_DATAERR; }else if(c[1] == c[0]){ num = 0; state = NUMBER_PARSING; }else{ if(c[0] != EOF) PUTC(c[0], output); c[0] = c[1]; } if(state == NUMBER_PARSING && !STRICT) /* it doesn't make sense to put this in a loop */ { PUTC(c[0], output); PUTC(c[0], output); } else if(state == NUMBER_PARSING) return EX_DATAERR; else if(c[0] != EOF) PUTC(c[0], output); return EX_OK; } static int encode(FILE *input, FILE *output){ int c[2]; unsigned int num; enum{COUNTING = 1} state; /* It was more fun to use gotos than to use sane structure. */ for(c[0] = EOF, num = 2, state = 0; ;) if((c[1] = GETC(input)) == EOF){ if(state == COUNTING) goto dump; else goto place; }else if(state == COUNTING){ if(c[1] != c[0]){ dump: PUTC(c[0], output); fprintf(output, "%d%c", num, NUMBER_TERMINATOR ); num = 2; state = 0; goto next; }else ++num; }else if(c[1] == c[0]) state = COUNTING; else{ /* c[1] != c[0] */ if(c[0] != EOF) /* c[0] will be EOF at first */ place: PUTC(c[0], output); next: if(c[1] == EOF) return EX_OK; c[0] = c[1]; } } int main(int argc, char *argv[]){ int r; if(argc != 1){ fprintf(stderr, "Usage: %s\n", argv[0] == NULL ? (f == decode ? "decode" : "encode") : argv[0] ); return EX_USAGE; } if((r = f(stdin, stdout)) == EX_DATAERR) fprintf(stderr, "%s: syntax error.\n", argv[0]); return r; }