Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- struct parsed_line {
- char * field_name;
- char * contents;
- int level;
- int start;
- };
- struct item {
- int level;
- int count;
- char ** fields;
- char ** values;
- };
- char * get_line(int *);
- struct parsed_line get_next_line(int *);
- void destroy_parsed_line(struct parsed_line);
- int valid_line(const char *);
- void trim(char *);
- int update_current_line(void);
- struct item get_next_item(int *);
- void destroy_item(struct item);
- const char * find_item_field(struct item, const char *);
- void parse_list(void);
- void output_game(const char *, int);
- void output_song(const char *, int);
- void close_output(int);
- void print_escaped_string(const char *);
- struct parsed_line current_line = {NULL, NULL, -1, -1};
- int main (void) {
- int reachedEOF;
- char * line;
- while (1) {
- line = get_line(&reachedEOF);
- trim(line);
- if (!strcmp(line, "---")) break;
- free(line);
- if (reachedEOF) return 1;
- }
- free(line);
- struct parsed_line pl;
- while (1) {
- pl = get_next_line(&reachedEOF);
- if (!(pl.level || strcmp(pl.field_name, "games"))) break;
- destroy_parsed_line(pl);
- if (reachedEOF) return 1;
- }
- parse_list();
- return 0;
- }
- char * get_line (int * reachedEOF) {
- char * result = NULL;
- unsigned length = 0;
- int input;
- while (1) {
- input = getchar();
- if ((input == EOF) || (input == '\n')) {
- if (reachedEOF) *reachedEOF = input == EOF;
- break;
- }
- result = realloc(result, length + 1);
- result[length ++] = input;
- }
- if (result && (result[length - 1] == '\r'))
- result[length - 1] = 0;
- else {
- result = realloc(result, length + 1);
- result[length] = 0;
- }
- return result;
- }
- struct parsed_line get_next_line (int * reachedEOF) {
- char * line = NULL;
- int end;
- do {
- free(line);
- line = get_line(&end);
- } while (!(end || valid_line(line)));
- if (reachedEOF) *reachedEOF = end;
- if (end && !valid_line(line)) {
- free(line);
- return (struct parsed_line) {.field_name = NULL, .contents = NULL, .start = -1, .level = -1};
- }
- struct parsed_line result;
- end = strspn(line, " ");
- if (!strncmp(line + end, "- ", 2)) {
- end += 2;
- result.start = 1;
- } else
- result.start = 0;
- result.level = end >> 2;
- char * real_line = line + end;
- end = strchr(real_line, ':') - real_line;
- result.field_name = malloc(end + 1);
- memcpy(result.field_name, real_line, end);
- result.field_name[end] = 0;
- trim(result.field_name);
- real_line += end + 1;
- if (*real_line) {
- char * quote_begin = strchr(real_line, '"');
- char * quote_end = NULL;
- if (quote_begin) {
- quote_end = strchr(quote_begin + 1, '"');
- while (quote_end && quote_end[-1] == '\\') quote_end = strchr(quote_end + 1, '"');
- }
- if (quote_end) {
- result.contents = malloc(quote_end - quote_begin);
- memcpy(result.contents, quote_begin + 1, quote_end - quote_begin - 1);
- result.contents[quote_end - quote_begin - 1] = 0;
- } else {
- result.contents = strcpy(malloc(strlen(real_line) + 1), real_line);
- trim(result.contents);
- }
- } else
- result.contents = strcpy(malloc(1), "");
- free(line);
- return result;
- }
- void destroy_parsed_line (struct parsed_line parsed_line) {
- free(parsed_line.field_name);
- free(parsed_line.contents);
- }
- int valid_line (const char * line) {
- if (*line == '#') return 0;
- if (!strchr(line, ':')) return 0;
- return 1;
- }
- void trim (char * string) {
- unsigned f;
- for (f = 0; string[f] && isspace(string[f]); f ++);
- unsigned lim = strlen(string) - f;
- memmove(string, string + f, lim + 1);
- if (!*string) return;
- while (isspace(string[lim - 1])) lim --;
- string[lim] = 0;
- }
- int update_current_line (void) {
- int reachedEOF;
- if (current_line.field_name) return 0;
- current_line = get_next_line(&reachedEOF);
- return reachedEOF;
- }
- int update_next_line (void) {
- if (current_line.field_name) destroy_parsed_line(current_line);
- current_line = (struct parsed_line) {.contents = NULL, .field_name = NULL, .level = -1, .start = -1};
- return update_current_line();
- }
- struct item get_next_item (int * reachedEOF) {
- int end = update_current_line();
- if (!(current_line.field_name)) {
- if (reachedEOF) *reachedEOF = 1;
- return (struct item) {.level = -1, .count = -1, .fields = NULL, .values = NULL};
- }
- while (!(current_line.start)) {
- end = update_next_line();
- if (end && !(current_line.field_name)) {
- if (reachedEOF) *reachedEOF = 1;
- return (struct item) {.level = -1, .count = -1, .fields = NULL, .values = NULL};
- }
- }
- struct item result = {.level = current_line.level, .count = 1, .fields = malloc(sizeof(char *)), .values = malloc(sizeof(char *))};
- *(result.fields) = strcpy(malloc(strlen(current_line.field_name) + 1), current_line.field_name);
- *(result.values) = strcpy(malloc(strlen(current_line.contents) + 1), current_line.contents);
- while (1) {
- end = update_next_line();
- if (!(current_line.field_name)) break;
- if (current_line.start) break;
- result.fields = realloc(result.fields, sizeof(char *) * (result.count + 1));
- result.values = realloc(result.values, sizeof(char *) * (result.count + 1));
- result.fields[result.count] = strcpy(malloc(strlen(current_line.field_name) + 1), current_line.field_name);
- result.values[result.count] = strcpy(malloc(strlen(current_line.contents) + 1), current_line.contents);
- result.count ++;
- }
- if (reachedEOF) *reachedEOF = end;
- return result;
- }
- void destroy_item (struct item item) {
- if (item.count < 0) return;
- unsigned p;
- for (p = 0; p < item.count; p ++) {
- free(item.fields[p]);
- free(item.values[p]);
- }
- free(item.fields);
- free(item.values);
- }
- const char * find_item_field (struct item item, const char * field) {
- if (item.count < 0) return NULL;
- unsigned p;
- for (p = 0; p < item.count; p ++)
- if (!strcmp(field, item.fields[p])) return item.values[p];
- return NULL;
- }
- void parse_list (void) {
- struct item current_item = get_next_item(NULL);
- putchar('[');
- int last_level = 0;
- while (current_item.level > 0) {
- switch (current_item.level) {
- case 1:
- output_game(find_item_field(current_item, "title"), last_level);
- break;
- case 2:
- output_song(find_item_field(current_item, "title"), last_level);
- break;
- }
- last_level = current_item.level;
- destroy_item(current_item);
- current_item = get_next_item(NULL);
- }
- close_output(last_level);
- putchar(']');
- }
- void output_game (const char * game, int last_level) {
- switch (last_level) {
- case 1: case 2:
- printf("%s", "]},");
- case 0:
- printf("%s", "{\"game\":");
- print_escaped_string(game);
- printf("%s", ",\"songs\":[");
- }
- }
- void output_song (const char * song, int last_level) {
- switch (last_level) {
- case 2:
- putchar(',');
- case 1:
- printf("\"%s\"", song);
- }
- }
- void close_output (int last_level) {
- switch (last_level) {
- case 1: case 2:
- printf("%s", "]}");
- }
- }
- void print_escaped_string (const char * str) {
- char * string = strcpy(malloc(strlen(str) + 1), str);
- char * s = string;
- putchar('"');
- char c;
- unsigned len;
- while (*string) {
- if (strchr("\"/\\", *string)) {
- printf("\\%c", *string);
- string ++;
- continue;
- }
- len = strcspn(string, "\"/\\");
- c = string[len];
- string[len] = 0;
- printf("%s", string);
- string[len] = c;
- string += len;
- }
- putchar('"');
- free(s);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement