Mercurial > repos > blastem
comparison config.c @ 803:236a184bf6f0
Merge
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 26 Jul 2015 16:51:03 -0700 |
parents | 0b692b5d154b |
children | 7ed55a361e79 |
comparison
equal
deleted
inserted
replaced
802:6811f601008f | 803:236a184bf6f0 |
---|---|
7 #include "util.h" | 7 #include "util.h" |
8 #include <stdio.h> | 8 #include <stdio.h> |
9 #include <stdlib.h> | 9 #include <stdlib.h> |
10 #include <string.h> | 10 #include <string.h> |
11 | 11 |
12 #define MAX_NEST 30 //way more than I'll ever need | 12 #ifdef __MINGW64_VERSION_MAJOR |
13 #define MINGW_W64_VERSION (__MINGW64_VERSION_MAJOR * 1000 + __MINGW64_VERSION_MINOR) | |
14 #else | |
15 #define MINGW_W64_VERSION 0 | |
16 #endif | |
13 | 17 |
14 #ifdef _WIN32 | 18 #if defined(_WIN32) && (MINGW_W64_VERSION < 3003) |
15 char * strtok_r(char * input, char * sep, char ** state) | 19 char * strtok_r(char * input, char * sep, char ** state) |
16 { | 20 { |
17 if (input) { | 21 if (input) { |
18 *state = input; | 22 *state = input; |
19 } | 23 } |
30 } | 34 } |
31 return NULL; | 35 return NULL; |
32 } | 36 } |
33 #endif | 37 #endif |
34 | 38 |
35 tern_node * parse_config(char * config_data) | 39 tern_node * parse_config_int(char **state, int started, int *line) |
36 { | 40 { |
37 char *state, *curline; | 41 char *config_data, *curline; |
38 char *prefix = NULL; | |
39 int nest_level = 0; | |
40 char * prefix_parts[MAX_NEST]; | |
41 int line = 1; | |
42 tern_node * head = NULL; | 42 tern_node * head = NULL; |
43 while ((curline = strtok_r(config_data, "\n", &state))) | 43 config_data = started ? NULL : *state; |
44 while ((curline = strtok_r(config_data, "\n", state))) | |
44 { | 45 { |
46 | |
45 config_data = NULL; | 47 config_data = NULL; |
46 curline = strip_ws(curline); | 48 curline = strip_ws(curline); |
47 int len = strlen(curline); | 49 int len = strlen(curline); |
48 if (!len) { | 50 if (!len) { |
51 *line = *line + 1; | |
49 continue; | 52 continue; |
50 } | 53 } |
51 if (curline[0] == '#') { | 54 if (curline[0] == '#') { |
55 *line = *line + 1; | |
52 continue; | 56 continue; |
53 } | 57 } |
54 if (curline[0] == '}') { | 58 if (curline[0] == '}') { |
55 if (!nest_level) { | 59 if (started) { |
56 fprintf(stderr, "unexpected } on line %d\n", line); | 60 return head; |
57 exit(1); | |
58 } | 61 } |
59 if (prefix) { | 62 fatal_error("unexpected } on line %d\n", *line); |
60 free(prefix); | |
61 prefix = NULL; | |
62 } | |
63 nest_level--; | |
64 curline = strip_ws(curline+1); | |
65 } | 63 } |
64 | |
66 char * end = curline + len - 1; | 65 char * end = curline + len - 1; |
67 if (*end == '{') { | 66 if (*end == '{') { |
68 *end = 0; | 67 *end = 0; |
69 curline = strip_ws(curline); | 68 curline = strip_ws(curline); |
70 prefix_parts[nest_level++] = curline; | 69 *line = *line + 1; |
71 if (prefix) { | 70 head = tern_insert_node(head, curline, parse_config_int(state, 1, line)); |
72 free(prefix); | |
73 prefix = NULL; | |
74 } | |
75 } else { | 71 } else { |
76 if (nest_level && !prefix) { | |
77 prefix = alloc_concat_m(nest_level, prefix_parts); | |
78 } | |
79 char * val = strip_ws(split_keyval(curline)); | 72 char * val = strip_ws(split_keyval(curline)); |
80 char * key = curline; | 73 char * key = curline; |
81 if (*key) { | 74 if (*val) { |
82 if (prefix) { | |
83 key = alloc_concat(prefix, key); | |
84 } | |
85 head = tern_insert_ptr(head, key, strdup(val)); | 75 head = tern_insert_ptr(head, key, strdup(val)); |
86 if (prefix) { | 76 } else { |
87 free(key); | 77 fprintf(stderr, "Key %s is missing a value on line %d\n", key, *line); |
88 } | |
89 } | 78 } |
79 *line = *line + 1; | |
90 } | 80 } |
91 } | 81 } |
92 if (prefix) { | |
93 free(prefix); | |
94 } | |
95 return head; | 82 return head; |
83 } | |
84 | |
85 tern_node * parse_config(char * config_data) | |
86 { | |
87 int line = 1; | |
88 return parse_config_int(&config_data, 0, &line); | |
96 } | 89 } |
97 | 90 |
98 tern_node * parse_config_file(char * config_path) | 91 tern_node * parse_config_file(char * config_path) |
99 { | 92 { |
100 tern_node * ret = NULL; | 93 tern_node * ret = NULL; |
104 } | 97 } |
105 long config_size = file_size(config_file); | 98 long config_size = file_size(config_file); |
106 if (!config_size) { | 99 if (!config_size) { |
107 goto config_empty; | 100 goto config_empty; |
108 } | 101 } |
109 char * config_data = malloc(config_size); | 102 char * config_data = malloc(config_size+1); |
110 if (fread(config_data, 1, config_size, config_file) != config_size) { | 103 if (fread(config_data, 1, config_size, config_file) != config_size) { |
111 goto config_read_fail; | 104 goto config_read_fail; |
112 } | 105 } |
106 config_data[config_size] = '\0'; | |
107 | |
113 ret = parse_config(config_data); | 108 ret = parse_config(config_data); |
114 config_read_fail: | 109 config_read_fail: |
115 free(config_data); | 110 free(config_data); |
116 config_empty: | 111 config_empty: |
117 fclose(config_file); | 112 fclose(config_file); |
143 success: | 138 success: |
144 if (ret) { | 139 if (ret) { |
145 return ret; | 140 return ret; |
146 } | 141 } |
147 no_config: | 142 no_config: |
148 fputs("Failed to find a config file in ~/.config/blastem/blastem.cfg or in the blastem executable directory\n", stderr); | 143 fatal_error("Failed to find a config file in ~/.config/blastem/blastem.cfg or in the blastem executable directory\n"); |
149 exit(1); | 144 //this will never get reached, but the compiler doesn't know that. Let's make it happy |
145 return NULL; | |
150 } | 146 } |
151 | 147 |