QUOTE: Be someone’s rainbow today.

ctl

Static template generator for C

main.c (4252B)


      1#include <stdio.h>
      2#include <stdlib.h>
      3#include <string.h>
      4
      5#define LIB_STR_IMPL
      6#include <libstr.h>
      7
      8typedef enum {
      9  CTL_ERR_OK,
     10  CTL_ERR_NO_ARGS,
     11  CTL_ERR_NO_FILE,
     12  CTL_ERR_UNCLOSED_CODE,
     13} ctl_error_t;
     14
     15void ctl_error_str(ctl_error_t err) {
     16  switch (err) {
     17    case CTL_ERR_OK:
     18      break;
     19    case CTL_ERR_NO_ARGS:
     20      printf("Usage: ctl <filename>\n");
     21      break;
     22    case CTL_ERR_NO_FILE:
     23      printf("Error: No file found!\n");
     24      break;
     25    case CTL_ERR_UNCLOSED_CODE:
     26      printf("Error: Unclosed code block!\n");
     27      break;
     28  }
     29}
     30
     31char *str_replace_all_len(char *buffer, char *str, char *replacement, int len) {
     32  char *ret = NULL;
     33  int str_len = strlen(str);
     34  for (int i = 0; i < len; i++) {
     35    char *ptr = &buffer[i];
     36    if (strncmp(ptr, str, str_len) == 0) {
     37      str_append(&ret, replacement);
     38      i += str_len - 1;
     39    }
     40    else {
     41      str_append_len(&ret, &buffer[i], 1);
     42    }
     43  }
     44  return ret;
     45}
     46
     47char *str_hex_len(char *str, int len) {
     48  const int HEX = 4;
     49  char *ret = calloc(HEX * len + 1, sizeof(char));
     50  for (int i = 0; i < len; i++) {
     51    unsigned char hex = str[i] & 0xff;
     52    snprintf(ret + HEX * i, HEX * len, "\\x%02x", hex);
     53  }
     54  ret[HEX * len] = '\0';
     55  return ret;
     56}
     57
     58ctl_error_t ctl_render(char **template, char *content) {
     59  int len = strlen(content);
     60  int set = 0;
     61  int is_code = 0;
     62  str_append(template, "{\n");
     63  for (int i = 0; i < len; i++) {
     64    if (content[i] == '%') {
     65      // ignore escaped %
     66      if (i + 1 < len && content[i + 1] == '%') {
     67        i += 1;
     68        continue;
     69      }
     70      if (is_code) {
     71        str_append_len(template, content + set, i - set);
     72        str_append(template, "\n");
     73      }
     74      else {
     75        const int STRING_LIMIT = 4095;
     76        int str_len = i - set;
     77        int rem_len = str_len;
     78        int hex_len = 0;
     79        int idx = 0;
     80        while (rem_len > 0) {
     81          if (rem_len > STRING_LIMIT) {
     82            hex_len = STRING_LIMIT;
     83          }
     84          else {
     85            hex_len = str_len - idx;
     86          }
     87          rem_len -= hex_len;
     88          char *str = str_replace_all_len(content + set + idx, "%%", "%", hex_len);
     89          char *hex = str_hex_len(str, strlen(str));
     90          str_append(template, "CTL_OUT(ctl_out, \"");
     91          str_append(template, hex);
     92          str_append(template, "\");\n");
     93          free(str);
     94          free(hex);
     95          idx += hex_len;
     96        }
     97      }
     98      is_code = !is_code;
     99      set = i + 1;
    100    }
    101  }
    102  if (is_code) {
    103    return CTL_ERR_UNCLOSED_CODE;
    104  }
    105  else {
    106    const int STRING_LIMIT = 4095;
    107    int str_len = len - set;
    108    int rem_len = str_len;
    109    int hex_len = 0;
    110    int idx = 0;
    111    while (rem_len > 0) {
    112      if (rem_len > STRING_LIMIT) {
    113        hex_len = STRING_LIMIT;
    114      }
    115      else {
    116        hex_len = str_len - idx;
    117      }
    118      rem_len -= hex_len;
    119      char *str = str_replace_all_len(content + set + idx, "%%", "%", hex_len);
    120      char *hex = str_hex_len(str, strlen(str));
    121      str_append(template, "CTL_OUT(ctl_out, \"");
    122      str_append(template, hex);
    123      str_append(template, "\");\n");
    124      free(str);
    125      free(hex);
    126      idx += hex_len;
    127    }
    128  }
    129  str_append(template, "}\n");
    130  *template = str_replace_all(*template, "%%", "%");
    131  return CTL_ERR_OK;
    132}
    133
    134ctl_error_t ctl_file_read(char **content, const char *filename) {
    135  FILE *fp = fopen(filename, "r");
    136  if (fp == NULL) {
    137    return CTL_ERR_NO_FILE;
    138  }
    139  fseek(fp, 0, SEEK_END);
    140  int len = ftell(fp);
    141  fseek(fp, 0, SEEK_SET);
    142  *content = calloc(len + 1, sizeof(char));
    143  fread(*content, sizeof(char), len, fp);
    144  (*content)[len] = '\0';
    145  fclose(fp);
    146  return CTL_ERR_OK;
    147}
    148
    149int main(int argc, char **argv) {
    150  ctl_error_t err;
    151  if (argc < 2) {
    152    err = CTL_ERR_NO_ARGS;
    153    ctl_error_str(err);
    154    return err;
    155  }
    156  char *filename = argv[1];
    157  char *content = NULL;
    158  err = ctl_file_read(&content, filename);
    159  if (err != CTL_ERR_OK) {
    160    ctl_error_str(err);
    161    return err;
    162  }
    163  char *template = NULL;
    164  err = ctl_render(&template, content);
    165  if (err != CTL_ERR_OK) {
    166    ctl_error_str(err);
    167    free(content);
    168    if (template != NULL) {
    169      free(template);
    170    }
    171    return err;
    172  }
    173  printf("%s\n", template);
    174  free(template);
    175  free(content);
    176  return CTL_ERR_OK;
    177}