diff --git a/src/template.c b/src/template.c index 160b8ce..62e639b 100644 --- a/src/template.c +++ b/src/template.c @@ -37,6 +37,16 @@ enum paratype { HL }; +static const struct { + char c; + char *escape; +} escapes[] = { + {'&', "&"}, + {';', ";"}, + {'<', "<"}, + {'>', ">"}, +}; + static int parsepara(struct linefile *infile, FILE *outfile); static enum paratype identifypara(char *line, char **contentret); @@ -53,6 +63,16 @@ static int parahardcase(struct linefile *infile, FILE *outfile, static int paracodecase(struct linefile *infile, FILE *outfile, char *line, char *buff, char *vars, enum paratype type); +static long strsearch(char *data, long start, size_t datalen, char c, int reps); +/* strsearch finds instances in data with reps repetitions of c. returns the + * last instance in the first group. For example: + * + * c = '.', reps = 2, data = " ...", returns 2 + * c = '.', reps = 2, data = ".. ...", returns 4 + * c = '.', reps = 1, data = " ...", returns 3 + * */ +static int writedata(char *data, size_t len, FILE *outfile); +static int writesimple(char *data, size_t len, FILE *outfile); static void ungetline(struct linefile *file, char *line); static char *getline(struct linefile *file); @@ -217,7 +237,7 @@ static int paraeasycase(struct linefile *infile, FILE *outfile, fprintf(outfile, "<%s>", tag); for (;;) { - fwrite(buff, sizeof(*buff), writelen, outfile); + writedata(buff, writelen, outfile); free(line); line = getline(infile); if (line == NULL) @@ -250,7 +270,7 @@ static int parahardcase(struct linefile *infile, FILE *outfile, if (linetag != NULL) fprintf(outfile, "<%s>", linetag); - fwrite(buff, sizeof(*buff), writelen, outfile); + writedata(buff, writelen, outfile); if (islinebreak(line)) fputs("
", outfile); if (linetag != NULL) @@ -301,7 +321,7 @@ static int paracodecase(struct linefile *infile, FILE *outfile, } if (newtype != CODEBACK) - fputs(buff, outfile); + writesimple(buff, -1, outfile); free(line); line = getline(infile); @@ -323,6 +343,113 @@ static int paracodecase(struct linefile *infile, FILE *outfile, return 0; } +static long strsearch(char *data, long start, size_t datalen, + char c, int reps) { + long i; + + for (i = start; data[i] == c; ++i) ; + + while (i + reps - 1 < datalen) { + int j; + for (j = 0; j < reps; ++j) + if (data[i + j] != c) + goto failure; + goto success; + continue; +failure: + ++i; + } + return -1; + +success: + while (data[i + reps] == c && i + reps < datalen) + ++i; + return i; +} + +/* TODO: Finish this */ +static int writedata(char *data, size_t len, FILE *outfile) { + long i; + long start; + long end; + for (i = 0; i < len; ++i) { + switch (data[i]) { +#define STANDOUT_CHAR(c) \ + case c: \ + if (data[i + 1] == c) { \ + start = i + 2; \ + end = strsearch(data, start, len, \ + c, 2); \ + goto bold; \ + } \ + start = i + 1; \ + end = strsearch(data, start, len, c, 1); \ + goto italic; + STANDOUT_CHAR('*'); + STANDOUT_CHAR('_'); + italic: + if (end < 0) { + putchar(data[i]); + break; + } + fputs("", outfile); + writedata(data + start, end - start, outfile); + fputs("", outfile); + i = end; + break; + bold: + if (end < 0) { + putchar(data[i]); + break; + } + fputs("", outfile); + writedata(data + start, end - start, outfile); + fputs("", outfile); + i = end + 1; + break; + + case '`': + end = strsearch(data, i, len, '`', 1); + if (end < 0) + break; + fputs("", outfile); + writedata(data + i, end - i, outfile); + fputs("", outfile); + i = end; + break; + default: { + int j; + for (j = 0; j < sizeof escapes / sizeof *escapes; ++j) { + if (escapes[j].c == data[i]) { + fputs(escapes[j].escape, outfile); + goto end; + } + } + fputc(data[i], outfile); +end: + break; + } + } + } + return 0; +} + +static int writesimple(char *data, size_t len, FILE *outfile) { + long i; + for (i = 0; (len < 0 && data[i] != '\0') || i < len; ++i) { + int j; + for (j = 0; j < sizeof escapes / sizeof *escapes; ++j) { + if (escapes[j].c == data[i]) { + fputs(escapes[j].escape, outfile); + goto end; + } + } + fputc(data[i], outfile); +end:; + } + return 0; +} + static void ungetline(struct linefile *file, char *line) { file->prevline = line; }