NESe (pronounced "Nessie") is a NES emulator based on the e6502 emulator, also written in C with a focus on speed and portability for use on embedded platforms, especially ARM.
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

211 rindas
6.0KB

  1. #include <ctype.h>
  2. #include <stdint.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include "ini.h"
  7. #include "compat.h"
  8. static inline int stracmp(const char* zstr,
  9. const char* lstr, size_t len) {
  10. int diff = 0;
  11. while (0 == diff && *zstr && len > 0) {
  12. --len;
  13. diff = (*zstr - *lstr);
  14. ++zstr;
  15. ++lstr;
  16. }
  17. if (0 == diff) {
  18. if (0 == len && !*zstr) diff = *zstr;
  19. else if (0 != len && *zstr) diff = *lstr;
  20. }
  21. return diff;
  22. }
  23. static const ini_datum* find_name(const ini_datum* schema,
  24. const char* name, int len,
  25. const ini_data_type type) {
  26. if (0 == stracmp(schema->name, name, len)) {
  27. return schema;
  28. }
  29. for (int i = 0; i < schema->count; ++i) {
  30. if ( ( ini_none == type ||
  31. type == schema->data[i].type) &&
  32. 0 == stracmp(schema->data[i].name, name, len)) {
  33. return &schema->data[i];
  34. }
  35. }
  36. return NULL;
  37. }
  38. static inline int needs_quotes(const char* str) {
  39. while (*str && !isspace(*str) && ',' != *str) ++str;
  40. return !!(*str);
  41. }
  42. static int _write_ini_file(FILE* file, const ini_datum* schema,
  43. const void* data, int level) {
  44. int status = 0;
  45. const void* ptr = (data + schema->offset);
  46. if (ini_section == schema->type) {
  47. fprintf(file, "[%s]\n", schema->name);
  48. for (int i = 0; i < schema->count; ++i) {
  49. _write_ini_file(file, &schema->data[i],
  50. ptr, level + 1);
  51. if (schema->count - 1 != i) fputc('\n', file);
  52. }
  53. if (0 != level) fputc('\n', file);
  54. } else if (ini_comment == schema->type) {
  55. fprintf(file, "; %s", *(char**)ptr);
  56. } else {
  57. fprintf(file, "%s = ", schema->name);
  58. if (ini_string == schema->type) {
  59. const char* str = *(char**)ptr;
  60. if (!needs_quotes(str)) fputs(str, file);
  61. else fprintf(file, "\"%s\"", str);
  62. } else if (ini_integer == schema->type) {
  63. fprintf(file, "%d", *(uint32_t*)ptr);
  64. } else if (ini_flag == schema->type) {
  65. fprintf(file, "%d", !!( *(uint32_t*)ptr &
  66. (1 << schema->shift)));
  67. }
  68. }
  69. return status;
  70. }
  71. int write_ini_file(FILE* file, const ini_datum* schema,
  72. const void* data) {
  73. return _write_ini_file(file, schema, data, 0);
  74. }
  75. static inline const char* first_char(const char* str) {
  76. while (*str && isspace(*str)) ++str;
  77. return str;
  78. }
  79. static inline const char* first_space(const char* str) {
  80. while (*str && !isspace(*str)) ++str;
  81. return str;
  82. }
  83. static inline const char* end_key(const char* str) {
  84. while (*str && '=' != *str && !isspace(*str)) ++str;
  85. return str;
  86. }
  87. static inline const char* last_char(const char* str) {
  88. int len = strlen(str);
  89. const char* end = str + len - 1;
  90. while (end > str && isspace(*end)) --end;
  91. return end;
  92. }
  93. static inline char* parse_string(const char* str) {
  94. const char* last = last_char(str);
  95. if ('"' == str[0] && '"' == *last) {
  96. ++str;
  97. --last;
  98. }
  99. return strndup(str, last - str + 1);
  100. }
  101. static inline int parse_key_value(const char* key_start,
  102. const ini_datum* section,
  103. void* data) {
  104. const char* key_end = end_key(key_start + 1);
  105. if (NULL == key_end) return -1;
  106. const ini_datum* def = find_name(section, key_start,
  107. (key_end - key_start),
  108. ini_none);
  109. if (NULL == def || def->type <= ini_section) return -1;
  110. const char* equal = first_char(key_end);
  111. if (NULL == equal || '=' != *equal) return -1;
  112. const char* val = first_char(equal + 1);
  113. if (NULL == val) return -1;
  114. const char* ptr = data + def->offset;
  115. if (ini_string == def->type) {
  116. *(char**)ptr = parse_string(val);
  117. } else if ( ini_integer == def->type ||
  118. ini_flag == def->type) {
  119. int intval = 0;
  120. if (0 >= sscanf(val, "%d", &intval)) return -1;
  121. if (ini_integer == def->type) {
  122. *(int32_t*)ptr = intval;
  123. } else {
  124. int32_t mask = (1 << def->shift);
  125. if (intval) *(uint32_t*)ptr |= mask;
  126. else *(uint32_t*)ptr &= ~mask;
  127. }
  128. }
  129. return 0;
  130. }
  131. int read_ini_file(FILE* file, const ini_datum* schema,
  132. void* data) {
  133. int status = 0;
  134. const ini_datum* section = NULL;
  135. const ini_datum* subsection = NULL;
  136. void* ptr = data;
  137. char* line = NULL;
  138. size_t sz_line = 0;
  139. while (0 == status && 0 <= getline(&line, &sz_line, file)) {
  140. const char* str = first_char(line);
  141. if ('[' == str[0]) {
  142. const char* start = &str[1];
  143. const char* end = strchr(start, ']');
  144. if (NULL != end) {
  145. ptr = data;
  146. int len = (end - start);
  147. if ('.' == start[0]) {
  148. if (NULL != section) {
  149. subsection = find_name(
  150. section, start, len, ini_section
  151. );
  152. ptr += section->offset;
  153. if (NULL != subsection) {
  154. ptr += subsection->offset;
  155. }
  156. }
  157. } else {
  158. section = find_name(
  159. schema, start, len, ini_section
  160. );
  161. subsection = section;
  162. if (NULL != section) ptr += section->offset;
  163. }
  164. }
  165. } else if (';' == str[0]) {
  166. // Ignore comments
  167. } else if (isalnum(str[0])) {
  168. // Key-value
  169. // Ignoring return value:
  170. // - Unknown sections or keys are ignored
  171. // - Just ignore malformed files, I guess
  172. parse_key_value(str, subsection, ptr);
  173. }
  174. }
  175. free(line);
  176. return status;
  177. }