Advertisement
aaaaaa123456789

TPP song list parser

Nov 18th, 2015
100
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5.  
  6. struct parsed_line {
  7.   char * field_name;
  8.   char * contents;
  9.   int level;
  10.   int start;
  11. };
  12.  
  13. struct item {
  14.   int level;
  15.   int count;
  16.   char ** fields;
  17.   char ** values;
  18. };
  19.  
  20. char * get_line(int *);
  21. struct parsed_line get_next_line(int *);
  22. void destroy_parsed_line(struct parsed_line);
  23. int valid_line(const char *);
  24. void trim(char *);
  25. int update_current_line(void);
  26. struct item get_next_item(int *);
  27. void destroy_item(struct item);
  28. const char * find_item_field(struct item, const char *);
  29. void parse_list(void);
  30. void output_game(const char *, int);
  31. void output_song(const char *, int);
  32. void close_output(int);
  33. void print_escaped_string(const char *);
  34.  
  35. struct parsed_line current_line = {NULL, NULL, -1, -1};
  36.  
  37. int main (void) {
  38.   int reachedEOF;
  39.   char * line;
  40.   while (1) {
  41.     line = get_line(&reachedEOF);
  42.     trim(line);
  43.     if (!strcmp(line, "---")) break;
  44.     free(line);
  45.     if (reachedEOF) return 1;
  46.   }
  47.   free(line);
  48.   struct parsed_line pl;
  49.   while (1) {
  50.     pl = get_next_line(&reachedEOF);
  51.     if (!(pl.level || strcmp(pl.field_name, "games"))) break;
  52.     destroy_parsed_line(pl);
  53.     if (reachedEOF) return 1;
  54.   }
  55.   parse_list();
  56.   return 0;
  57. }
  58.  
  59. char * get_line (int * reachedEOF) {
  60.   char * result = NULL;
  61.   unsigned length = 0;
  62.   int input;
  63.   while (1) {
  64.     input = getchar();
  65.     if ((input == EOF) || (input == '\n')) {
  66.       if (reachedEOF) *reachedEOF = input == EOF;
  67.       break;
  68.     }
  69.     result = realloc(result, length + 1);
  70.     result[length ++] = input;
  71.   }
  72.   if (result && (result[length - 1] == '\r'))
  73.     result[length - 1] = 0;
  74.   else {
  75.     result = realloc(result, length + 1);
  76.     result[length] = 0;
  77.   }
  78.   return result;
  79. }
  80.  
  81. struct parsed_line get_next_line (int * reachedEOF) {
  82.   char * line = NULL;
  83.   int end;
  84.   do {
  85.     free(line);
  86.     line = get_line(&end);
  87.   } while (!(end || valid_line(line)));
  88.   if (reachedEOF) *reachedEOF = end;
  89.   if (end && !valid_line(line)) {
  90.     free(line);
  91.     return (struct parsed_line) {.field_name = NULL, .contents = NULL, .start = -1, .level = -1};
  92.   }
  93.   struct parsed_line result;
  94.   end = strspn(line, " ");
  95.   if (!strncmp(line + end, "- ", 2)) {
  96.     end += 2;
  97.     result.start = 1;
  98.   } else
  99.     result.start = 0;
  100.   result.level = end >> 2;
  101.   char * real_line = line + end;
  102.   end = strchr(real_line, ':') - real_line;
  103.   result.field_name = malloc(end + 1);
  104.   memcpy(result.field_name, real_line, end);
  105.   result.field_name[end] = 0;
  106.   trim(result.field_name);
  107.   real_line += end + 1;
  108.   if (*real_line) {
  109.     char * quote_begin = strchr(real_line, '"');
  110.     char * quote_end = NULL;
  111.     if (quote_begin) {
  112.       quote_end = strchr(quote_begin + 1, '"');
  113.       while (quote_end && quote_end[-1] == '\\') quote_end = strchr(quote_end + 1, '"');
  114.     }
  115.     if (quote_end) {
  116.       result.contents = malloc(quote_end - quote_begin);
  117.       memcpy(result.contents, quote_begin + 1, quote_end - quote_begin - 1);
  118.       result.contents[quote_end - quote_begin - 1] = 0;
  119.     } else {
  120.       result.contents = strcpy(malloc(strlen(real_line) + 1), real_line);
  121.       trim(result.contents);
  122.     }
  123.   } else
  124.     result.contents = strcpy(malloc(1), "");
  125.   free(line);
  126.   return result;
  127. }
  128.  
  129. void destroy_parsed_line (struct parsed_line parsed_line) {
  130.   free(parsed_line.field_name);
  131.   free(parsed_line.contents);
  132. }
  133.  
  134. int valid_line (const char * line) {
  135.   if (*line == '#') return 0;
  136.   if (!strchr(line, ':')) return 0;
  137.   return 1;
  138. }
  139.  
  140. void trim (char * string) {
  141.   unsigned f;
  142.   for (f = 0; string[f] && isspace(string[f]); f ++);
  143.   unsigned lim = strlen(string) - f;
  144.   memmove(string, string + f, lim + 1);
  145.   if (!*string) return;
  146.   while (isspace(string[lim - 1])) lim --;
  147.   string[lim] = 0;
  148. }
  149.  
  150. int update_current_line (void) {
  151.   int reachedEOF;
  152.   if (current_line.field_name) return 0;
  153.   current_line = get_next_line(&reachedEOF);
  154.   return reachedEOF;
  155. }
  156.  
  157. int update_next_line (void) {
  158.   if (current_line.field_name) destroy_parsed_line(current_line);
  159.   current_line = (struct parsed_line) {.contents = NULL, .field_name = NULL, .level = -1, .start = -1};
  160.   return update_current_line();
  161. }
  162.  
  163. struct item get_next_item (int * reachedEOF) {
  164.   int end = update_current_line();
  165.   if (!(current_line.field_name)) {
  166.     if (reachedEOF) *reachedEOF = 1;
  167.     return (struct item) {.level = -1, .count = -1, .fields = NULL, .values = NULL};
  168.   }
  169.   while (!(current_line.start)) {
  170.     end = update_next_line();
  171.     if (end && !(current_line.field_name)) {
  172.       if (reachedEOF) *reachedEOF = 1;
  173.       return (struct item) {.level = -1, .count = -1, .fields = NULL, .values = NULL};
  174.     }
  175.   }
  176.   struct item result = {.level = current_line.level, .count = 1, .fields = malloc(sizeof(char *)), .values = malloc(sizeof(char *))};
  177.   *(result.fields) = strcpy(malloc(strlen(current_line.field_name) + 1), current_line.field_name);
  178.   *(result.values) = strcpy(malloc(strlen(current_line.contents) + 1), current_line.contents);
  179.   while (1) {
  180.     end = update_next_line();
  181.     if (!(current_line.field_name)) break;
  182.     if (current_line.start) break;
  183.     result.fields = realloc(result.fields, sizeof(char *) * (result.count + 1));
  184.     result.values = realloc(result.values, sizeof(char *) * (result.count + 1));
  185.     result.fields[result.count] = strcpy(malloc(strlen(current_line.field_name) + 1), current_line.field_name);
  186.     result.values[result.count] = strcpy(malloc(strlen(current_line.contents) + 1), current_line.contents);
  187.     result.count ++;
  188.   }
  189.   if (reachedEOF) *reachedEOF = end;
  190.   return result;
  191. }
  192.  
  193. void destroy_item (struct item item) {
  194.   if (item.count < 0) return;
  195.   unsigned p;
  196.   for (p = 0; p < item.count; p ++) {
  197.     free(item.fields[p]);
  198.     free(item.values[p]);
  199.   }
  200.   free(item.fields);
  201.   free(item.values);
  202. }
  203.  
  204. const char * find_item_field (struct item item, const char * field) {
  205.   if (item.count < 0) return NULL;
  206.   unsigned p;
  207.   for (p = 0; p < item.count; p ++)
  208.     if (!strcmp(field, item.fields[p])) return item.values[p];
  209.   return NULL;
  210. }
  211.  
  212. void parse_list (void) {
  213.   struct item current_item = get_next_item(NULL);
  214.   putchar('[');
  215.   int last_level = 0;
  216.   while (current_item.level > 0) {
  217.     switch (current_item.level) {
  218.       case 1:
  219.         output_game(find_item_field(current_item, "title"), last_level);
  220.         break;
  221.       case 2:
  222.         output_song(find_item_field(current_item, "title"), last_level);
  223.         break;
  224.     }
  225.     last_level = current_item.level;
  226.     destroy_item(current_item);
  227.     current_item = get_next_item(NULL);
  228.   }
  229.   close_output(last_level);
  230.   putchar(']');
  231. }
  232.  
  233. void output_game (const char * game, int last_level) {
  234.   switch (last_level) {
  235.     case 1: case 2:
  236.       printf("%s", "]},");
  237.     case 0:
  238.       printf("%s", "{\"game\":");
  239.       print_escaped_string(game);
  240.       printf("%s", ",\"songs\":[");
  241.   }
  242. }
  243.  
  244. void output_song (const char * song, int last_level) {
  245.   switch (last_level) {
  246.     case 2:
  247.       putchar(',');
  248.     case 1:
  249.       printf("\"%s\"", song);
  250.   }
  251. }
  252.  
  253. void close_output (int last_level) {
  254.   switch (last_level) {
  255.     case 1: case 2:
  256.       printf("%s", "]}");
  257.   }
  258. }
  259.  
  260. void print_escaped_string (const char * str) {
  261.   char * string = strcpy(malloc(strlen(str) + 1), str);
  262.   char * s = string;
  263.   putchar('"');
  264.   char c;
  265.   unsigned len;
  266.   while (*string) {
  267.     if (strchr("\"/\\", *string)) {
  268.       printf("\\%c", *string);
  269.       string ++;
  270.       continue;
  271.     }
  272.     len = strcspn(string, "\"/\\");
  273.     c = string[len];
  274.     string[len] = 0;
  275.     printf("%s", string);
  276.     string[len] = c;
  277.     string += len;
  278.   }
  279.   putchar('"');
  280.   free(s);
  281. }
Advertisement
RAW Paste Data Copied
Advertisement