PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/config.c

https://bitbucket.org/hudson/magic-lantern/
C | 378 lines | 278 code | 68 blank | 32 comment | 48 complexity | a70df5f8a249ab095811cac73a7424dc MD5 | raw file
Possible License(s): GPL-2.0
  1. /** \file
  2. * Key/value parser until we have a proper config
  3. */
  4. /*
  5. * Copyright (C) 2009 Trammell Hudson <hudson+ml@osresearch.net>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the
  19. * Free Software Foundation, Inc.,
  20. * 51 Franklin Street, Fifth Floor,
  21. * Boston, MA 02110-1301, USA.
  22. */
  23. #include "dryos.h"
  24. #include "config.h"
  25. #include "version.h"
  26. // Don't use isspace since we don't have it
  27. static inline int
  28. is_space( char c )
  29. {
  30. return c == ' ' || c == '\t' || c == '\r' || c == '\n';
  31. }
  32. struct config *
  33. config_parse_line(
  34. const char * line
  35. )
  36. {
  37. int name_len = 0;
  38. int value_len = 0;
  39. struct config * config = malloc( sizeof(*config) );
  40. if( !config )
  41. goto malloc_error;
  42. config->next = 0;
  43. // Trim any leading whitespace
  44. int i = 0;
  45. while( line[i] && is_space( line[i] ) )
  46. i++;
  47. // Copy the name to the name buffer
  48. while( line[i]
  49. && !is_space( line[i] )
  50. && line[i] != '='
  51. && name_len < MAX_NAME_LEN
  52. )
  53. config->name[ name_len++ ] = line[i++];
  54. if( name_len == MAX_NAME_LEN )
  55. goto parse_error;
  56. // And nul terminate it
  57. config->name[ name_len ] = '\0';
  58. // Skip any white space and = signs
  59. while( line[i] && is_space( line[i] ) )
  60. i++;
  61. if( line[i++] != '=' )
  62. goto parse_error;
  63. while( line[i] && is_space( line[i] ) )
  64. i++;
  65. // Copy the value to the value buffer
  66. while( line[i] && value_len < MAX_VALUE_LEN )
  67. config->value[ value_len++ ] = line[ i++ ];
  68. // Back up to trim any white space
  69. while( value_len > 0 && is_space( config->value[ value_len-1 ] ) )
  70. value_len--;
  71. // And nul terminate it
  72. config->value[ value_len ] = '\0';
  73. DebugMsg( DM_MAGIC, 3,
  74. "%s: '%s' => '%s'",
  75. __func__,
  76. config->name,
  77. config->value
  78. );
  79. return config;
  80. parse_error:
  81. DebugMsg( DM_MAGIC, 3,
  82. "%s: PARSE ERROR: len=%d,%d string='%s'",
  83. __func__,
  84. name_len,
  85. value_len,
  86. line
  87. );
  88. free( config );
  89. malloc_error:
  90. return 0;
  91. }
  92. int
  93. read_line(
  94. FILE * file,
  95. char * buf,
  96. size_t size
  97. )
  98. {
  99. size_t len = 0;
  100. while( len < size )
  101. {
  102. int rc = FIO_ReadFile( file, buf+len, 1 );
  103. if( rc <= 0 )
  104. return -1;
  105. if( buf[len] == '\r' )
  106. continue;
  107. if( buf[len] == '\n' )
  108. {
  109. buf[len] = '\0';
  110. return len;
  111. }
  112. len++;
  113. }
  114. return -1;
  115. }
  116. extern struct config_var _config_vars_start[];
  117. extern struct config_var _config_vars_end[];
  118. static void
  119. config_auto_parse(
  120. struct config * config
  121. )
  122. {
  123. struct config_var * var = _config_vars_start;
  124. for( ; var < _config_vars_end ; var++ )
  125. {
  126. if( !streq( var->name, config->name ) )
  127. continue;
  128. DebugMsg( DM_MAGIC, 3,
  129. "%s: '%s' => '%s'",
  130. __func__,
  131. config->name,
  132. config->value
  133. );
  134. if( var->type == 0 )
  135. {
  136. *(unsigned*) var->value = atoi( config->value );
  137. } else {
  138. *(char **) var->value = config->value;
  139. }
  140. return;
  141. }
  142. DebugMsg( DM_MAGIC, 3,
  143. "%s: '%s' unused?",
  144. __func__,
  145. config->name
  146. );
  147. }
  148. int
  149. config_save_file(
  150. struct config * config,
  151. const char * filename
  152. )
  153. {
  154. FILE * file = FIO_CreateFile( filename );
  155. if( file == INVALID_PTR )
  156. return -1;
  157. struct config_var * var = _config_vars_start;
  158. int count = 0;
  159. DebugMsg( DM_MAGIC, 3, "%s: saving to %s", __func__, filename );
  160. fprintf( file,
  161. "# Magic Lantern %s (%s)\n"
  162. "# Build on %s by %s\n",
  163. build_version,
  164. build_id,
  165. build_date,
  166. build_user
  167. );
  168. struct tm now;
  169. LoadCalendarFromRTC( &now );
  170. fprintf( file,
  171. "# Configuration saved on %04d/%02d/%02d %02d:%02d:%02d\n",
  172. now.tm_year + 1900,
  173. now.tm_mon + 1,
  174. now.tm_mday,
  175. now.tm_hour,
  176. now.tm_min,
  177. now.tm_sec
  178. );
  179. for( ; var < _config_vars_end ; var++ )
  180. {
  181. if( var->type == 0 )
  182. fprintf( file,
  183. "%s = %d\n",
  184. var->name,
  185. *(unsigned*) var->value
  186. );
  187. else
  188. fprintf( file,
  189. "%s = %s\n",
  190. var->name,
  191. *(const char**) var->value
  192. );
  193. count++;
  194. }
  195. FIO_CloseFile( file );
  196. return count;
  197. }
  198. struct config *
  199. config_parse(
  200. FILE * file
  201. ) {
  202. char line_buf[ MAX_NAME_LEN + MAX_VALUE_LEN ];
  203. struct config * config = 0;
  204. int count = 0;
  205. while( read_line( file, line_buf, sizeof(line_buf) ) >= 0 )
  206. {
  207. // Ignore any line that begins with # or is empty
  208. if( line_buf[0] == '#'
  209. || line_buf[0] == '\0' )
  210. continue;
  211. struct config * new_config = config_parse_line( line_buf );
  212. if( !new_config )
  213. goto error;
  214. new_config->next = config;
  215. config = new_config;
  216. count++;
  217. config_auto_parse( config );
  218. }
  219. DebugMsg( DM_MAGIC, 3, "%s: Read %d config values", __func__, count );
  220. return config;
  221. error:
  222. DebugMsg( DM_MAGIC, 3, "%s: ERROR Deleting config", __func__ );
  223. while( config )
  224. {
  225. struct config * next = config->next;
  226. DebugMsg( DM_MAGIC, 3, "%s: Deleting '%s' => '%s'",
  227. __func__,
  228. config->name,
  229. config->value
  230. );
  231. free( config );
  232. config = next;
  233. }
  234. return NULL;
  235. }
  236. char *
  237. config_value(
  238. struct config * config,
  239. const char * name
  240. )
  241. {
  242. while( config )
  243. {
  244. if( streq( config->name, name ) )
  245. return config->value;
  246. config = config->next;
  247. }
  248. return NULL;
  249. }
  250. int
  251. config_int(
  252. struct config * config,
  253. const char * name,
  254. int def
  255. )
  256. {
  257. const char * str = config_value( config, name );
  258. if( !str )
  259. {
  260. DebugMsg( DM_MAGIC, 3,
  261. "Config '%s', using default %d",
  262. name,
  263. def
  264. );
  265. return def;
  266. }
  267. def = atoi( str );
  268. DebugMsg( DM_MAGIC, 3,
  269. "Config '%s', using user value %d ('%s')",
  270. name,
  271. def,
  272. str
  273. );
  274. return def;
  275. }
  276. struct config head = { .name = "config.file", .value = "" };
  277. struct config fail = { .name = "config.failure", .value = "1" };
  278. struct config *
  279. config_parse_file(
  280. const char * filename
  281. )
  282. {
  283. FILE * file = FIO_Open( filename, O_SYNC );
  284. strcpy( head.value, filename );
  285. if( file == INVALID_PTR )
  286. {
  287. head.next = &fail;
  288. return &head;
  289. }
  290. struct config * config = config_parse( file );
  291. FIO_CloseFile( file );
  292. head.next = config;
  293. return &head;
  294. }
  295. int
  296. atoi(
  297. const char * s
  298. )
  299. {
  300. int value = 0;
  301. // Only handles base ten for now
  302. while( 1 )
  303. {
  304. char c = *s++;
  305. if( !c || c < '0' || c > '9' )
  306. break;
  307. value = value * 10 + c - '0';
  308. }
  309. return value;
  310. }