conf.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. /*
  2. * conf.c: implementation of the internal storage format used for
  3. * the configuration of a PuTTY session.
  4. */
  5. #include <stdio.h>
  6. #include <stddef.h>
  7. #include <assert.h>
  8. #include "tree234.h"
  9. #include "putty.h"
  10. /*
  11. * Enumeration of types used in keys and values.
  12. */
  13. typedef enum {
  14. TYPE_NONE, TYPE_BOOL, TYPE_INT, TYPE_STR, TYPE_FILENAME, TYPE_FONT
  15. } Type;
  16. /*
  17. * Arrays which allow us to look up the subkey and value types for a
  18. * given primary key id.
  19. */
  20. #define CONF_SUBKEYTYPE_DEF(valtype, keytype, keyword) TYPE_ ## keytype,
  21. static int subkeytypes[] = { CONFIG_OPTIONS(CONF_SUBKEYTYPE_DEF) };
  22. #define CONF_VALUETYPE_DEF(valtype, keytype, keyword) TYPE_ ## valtype,
  23. static int valuetypes[] = { CONFIG_OPTIONS(CONF_VALUETYPE_DEF) };
  24. /*
  25. * Configuration keys are primarily integers (big enum of all the
  26. * different configurable options); some keys have string-designated
  27. * subkeys, such as the list of environment variables (subkeys
  28. * defined by the variable names); some have integer-designated
  29. * subkeys (wordness, colours, preference lists).
  30. */
  31. struct key {
  32. int primary;
  33. union {
  34. int i;
  35. char *s;
  36. } secondary;
  37. };
  38. /* Variant form of struct key which doesn't contain dynamic data, used
  39. * for lookups. */
  40. struct constkey {
  41. int primary;
  42. union {
  43. int i;
  44. const char *s;
  45. } secondary;
  46. };
  47. struct value {
  48. union {
  49. bool boolval;
  50. int intval;
  51. char *stringval;
  52. Filename *fileval;
  53. FontSpec *fontval;
  54. } u;
  55. };
  56. struct conf_entry {
  57. struct key key;
  58. struct value value;
  59. };
  60. struct conf_tag {
  61. tree234 *tree;
  62. };
  63. /*
  64. * Because 'struct key' is the first element in 'struct conf_entry',
  65. * it's safe (guaranteed by the C standard) to cast arbitrarily back
  66. * and forth between the two types. Therefore, we only need one
  67. * comparison function, which can double as a main sort function for
  68. * the tree (comparing two conf_entry structures with each other)
  69. * and a search function (looking up an externally supplied key).
  70. */
  71. static int conf_cmp(void *av, void *bv)
  72. {
  73. struct key *a = (struct key *)av;
  74. struct key *b = (struct key *)bv;
  75. if (a->primary < b->primary)
  76. return -1;
  77. else if (a->primary > b->primary)
  78. return +1;
  79. switch (subkeytypes[a->primary]) {
  80. case TYPE_INT:
  81. if (a->secondary.i < b->secondary.i)
  82. return -1;
  83. else if (a->secondary.i > b->secondary.i)
  84. return +1;
  85. return 0;
  86. case TYPE_STR:
  87. return strcmp(a->secondary.s, b->secondary.s);
  88. default:
  89. return 0;
  90. }
  91. }
  92. static int conf_cmp_constkey(void *av, void *bv)
  93. {
  94. struct key *a = (struct key *)av;
  95. struct constkey *b = (struct constkey *)bv;
  96. if (a->primary < b->primary)
  97. return -1;
  98. else if (a->primary > b->primary)
  99. return +1;
  100. switch (subkeytypes[a->primary]) {
  101. case TYPE_INT:
  102. if (a->secondary.i < b->secondary.i)
  103. return -1;
  104. else if (a->secondary.i > b->secondary.i)
  105. return +1;
  106. return 0;
  107. case TYPE_STR:
  108. return strcmp(a->secondary.s, b->secondary.s);
  109. default:
  110. return 0;
  111. }
  112. }
  113. /*
  114. * Free any dynamic data items pointed to by a 'struct key'. We
  115. * don't free the structure itself, since it's probably part of a
  116. * larger allocated block.
  117. */
  118. static void free_key(struct key *key)
  119. {
  120. if (subkeytypes[key->primary] == TYPE_STR)
  121. sfree(key->secondary.s);
  122. }
  123. /*
  124. * Copy a 'struct key' into another one, copying its dynamic data
  125. * if necessary.
  126. */
  127. static void copy_key(struct key *to, struct key *from)
  128. {
  129. to->primary = from->primary;
  130. switch (subkeytypes[to->primary]) {
  131. case TYPE_INT:
  132. to->secondary.i = from->secondary.i;
  133. break;
  134. case TYPE_STR:
  135. to->secondary.s = dupstr(from->secondary.s);
  136. break;
  137. }
  138. }
  139. /*
  140. * Free any dynamic data items pointed to by a 'struct value'. We
  141. * don't free the value itself, since it's probably part of a larger
  142. * allocated block.
  143. */
  144. static void free_value(struct value *val, int type)
  145. {
  146. if (type == TYPE_STR)
  147. sfree(val->u.stringval);
  148. else if (type == TYPE_FILENAME)
  149. filename_free(val->u.fileval);
  150. else if (type == TYPE_FONT)
  151. fontspec_free(val->u.fontval);
  152. }
  153. /*
  154. * Copy a 'struct value' into another one, copying its dynamic data
  155. * if necessary.
  156. */
  157. static void copy_value(struct value *to, struct value *from, int type)
  158. {
  159. switch (type) {
  160. case TYPE_BOOL:
  161. to->u.boolval = from->u.boolval;
  162. break;
  163. case TYPE_INT:
  164. to->u.intval = from->u.intval;
  165. break;
  166. case TYPE_STR:
  167. to->u.stringval = dupstr(from->u.stringval);
  168. break;
  169. case TYPE_FILENAME:
  170. to->u.fileval = filename_copy(from->u.fileval);
  171. break;
  172. case TYPE_FONT:
  173. to->u.fontval = fontspec_copy(from->u.fontval);
  174. break;
  175. }
  176. }
  177. /*
  178. * Free an entire 'struct conf_entry' and its dynamic data.
  179. */
  180. static void free_entry(struct conf_entry *entry)
  181. {
  182. free_key(&entry->key);
  183. free_value(&entry->value, valuetypes[entry->key.primary]);
  184. sfree(entry);
  185. }
  186. Conf *conf_new(void)
  187. {
  188. Conf *conf = snew(struct conf_tag);
  189. conf->tree = newtree234(conf_cmp);
  190. return conf;
  191. }
  192. static void conf_clear(Conf *conf)
  193. {
  194. struct conf_entry *entry;
  195. while ((entry = delpos234(conf->tree, 0)) != NULL)
  196. free_entry(entry);
  197. }
  198. void conf_free(Conf *conf)
  199. {
  200. conf_clear(conf);
  201. freetree234(conf->tree);
  202. sfree(conf);
  203. }
  204. static void conf_insert(Conf *conf, struct conf_entry *entry)
  205. {
  206. struct conf_entry *oldentry = add234(conf->tree, entry);
  207. if (oldentry && oldentry != entry) {
  208. del234(conf->tree, oldentry);
  209. free_entry(oldentry);
  210. oldentry = add234(conf->tree, entry);
  211. assert(oldentry == entry);
  212. }
  213. }
  214. void conf_copy_into(Conf *newconf, Conf *oldconf)
  215. {
  216. struct conf_entry *entry, *entry2;
  217. int i;
  218. conf_clear(newconf);
  219. for (i = 0; (entry = index234(oldconf->tree, i)) != NULL; i++) {
  220. entry2 = snew(struct conf_entry);
  221. copy_key(&entry2->key, &entry->key);
  222. copy_value(&entry2->value, &entry->value,
  223. valuetypes[entry->key.primary]);
  224. add234(newconf->tree, entry2);
  225. }
  226. }
  227. Conf *conf_copy(Conf *oldconf)
  228. {
  229. Conf *newconf = conf_new();
  230. conf_copy_into(newconf, oldconf);
  231. return newconf;
  232. }
  233. bool conf_get_bool(Conf *conf, int primary)
  234. {
  235. struct key key;
  236. struct conf_entry *entry;
  237. assert(subkeytypes[primary] == TYPE_NONE);
  238. assert(valuetypes[primary] == TYPE_BOOL);
  239. key.primary = primary;
  240. entry = find234(conf->tree, &key, NULL);
  241. assert(entry);
  242. return entry->value.u.boolval;
  243. }
  244. int conf_get_int(Conf *conf, int primary)
  245. {
  246. struct key key;
  247. struct conf_entry *entry;
  248. assert(subkeytypes[primary] == TYPE_NONE);
  249. assert(valuetypes[primary] == TYPE_INT);
  250. key.primary = primary;
  251. entry = find234(conf->tree, &key, NULL);
  252. assert(entry);
  253. return entry->value.u.intval;
  254. }
  255. int conf_get_int_int(Conf *conf, int primary, int secondary)
  256. {
  257. struct key key;
  258. struct conf_entry *entry;
  259. assert(subkeytypes[primary] == TYPE_INT);
  260. assert(valuetypes[primary] == TYPE_INT);
  261. key.primary = primary;
  262. key.secondary.i = secondary;
  263. entry = find234(conf->tree, &key, NULL);
  264. assert(entry);
  265. return entry->value.u.intval;
  266. }
  267. char *conf_get_str(Conf *conf, int primary)
  268. {
  269. struct key key;
  270. struct conf_entry *entry;
  271. assert(subkeytypes[primary] == TYPE_NONE);
  272. assert(valuetypes[primary] == TYPE_STR);
  273. key.primary = primary;
  274. entry = find234(conf->tree, &key, NULL);
  275. assert(entry);
  276. return entry->value.u.stringval;
  277. }
  278. char *conf_get_str_str_opt(Conf *conf, int primary, const char *secondary)
  279. {
  280. struct key key;
  281. struct conf_entry *entry;
  282. assert(subkeytypes[primary] == TYPE_STR);
  283. assert(valuetypes[primary] == TYPE_STR);
  284. key.primary = primary;
  285. key.secondary.s = (char *)secondary;
  286. entry = find234(conf->tree, &key, NULL);
  287. return entry ? entry->value.u.stringval : NULL;
  288. }
  289. char *conf_get_str_str(Conf *conf, int primary, const char *secondary)
  290. {
  291. char *ret = conf_get_str_str_opt(conf, primary, secondary);
  292. assert(ret);
  293. return ret;
  294. }
  295. char *conf_get_str_strs(Conf *conf, int primary,
  296. char *subkeyin, char **subkeyout)
  297. {
  298. struct constkey key;
  299. struct conf_entry *entry;
  300. assert(subkeytypes[primary] == TYPE_STR);
  301. assert(valuetypes[primary] == TYPE_STR);
  302. key.primary = primary;
  303. if (subkeyin) {
  304. key.secondary.s = subkeyin;
  305. entry = findrel234(conf->tree, &key, NULL, REL234_GT);
  306. } else {
  307. key.secondary.s = "";
  308. entry = findrel234(conf->tree, &key, conf_cmp_constkey, REL234_GE);
  309. }
  310. if (!entry || entry->key.primary != primary)
  311. return NULL;
  312. *subkeyout = entry->key.secondary.s;
  313. return entry->value.u.stringval;
  314. }
  315. char *conf_get_str_nthstrkey(Conf *conf, int primary, int n)
  316. {
  317. struct constkey key;
  318. struct conf_entry *entry;
  319. int index;
  320. assert(subkeytypes[primary] == TYPE_STR);
  321. assert(valuetypes[primary] == TYPE_STR);
  322. key.primary = primary;
  323. key.secondary.s = "";
  324. entry = findrelpos234(conf->tree, &key, conf_cmp_constkey,
  325. REL234_GE, &index);
  326. if (!entry || entry->key.primary != primary)
  327. return NULL;
  328. entry = index234(conf->tree, index + n);
  329. if (!entry || entry->key.primary != primary)
  330. return NULL;
  331. return entry->key.secondary.s;
  332. }
  333. Filename *conf_get_filename(Conf *conf, int primary)
  334. {
  335. struct key key;
  336. struct conf_entry *entry;
  337. assert(subkeytypes[primary] == TYPE_NONE);
  338. assert(valuetypes[primary] == TYPE_FILENAME);
  339. key.primary = primary;
  340. entry = find234(conf->tree, &key, NULL);
  341. assert(entry);
  342. return entry->value.u.fileval;
  343. }
  344. FontSpec *conf_get_fontspec(Conf *conf, int primary)
  345. {
  346. struct key key;
  347. struct conf_entry *entry;
  348. assert(subkeytypes[primary] == TYPE_NONE);
  349. assert(valuetypes[primary] == TYPE_FONT);
  350. key.primary = primary;
  351. entry = find234(conf->tree, &key, NULL);
  352. assert(entry);
  353. return entry->value.u.fontval;
  354. }
  355. void conf_set_bool(Conf *conf, int primary, bool value)
  356. {
  357. struct conf_entry *entry = snew(struct conf_entry);
  358. assert(subkeytypes[primary] == TYPE_NONE);
  359. assert(valuetypes[primary] == TYPE_BOOL);
  360. entry->key.primary = primary;
  361. entry->value.u.boolval = value;
  362. conf_insert(conf, entry);
  363. }
  364. void conf_set_int(Conf *conf, int primary, int value)
  365. {
  366. struct conf_entry *entry = snew(struct conf_entry);
  367. assert(subkeytypes[primary] == TYPE_NONE);
  368. assert(valuetypes[primary] == TYPE_INT);
  369. entry->key.primary = primary;
  370. entry->value.u.intval = value;
  371. conf_insert(conf, entry);
  372. }
  373. void conf_set_int_int(Conf *conf, int primary,
  374. int secondary, int value)
  375. {
  376. struct conf_entry *entry = snew(struct conf_entry);
  377. assert(subkeytypes[primary] == TYPE_INT);
  378. assert(valuetypes[primary] == TYPE_INT);
  379. entry->key.primary = primary;
  380. entry->key.secondary.i = secondary;
  381. entry->value.u.intval = value;
  382. conf_insert(conf, entry);
  383. }
  384. void conf_set_str(Conf *conf, int primary, const char *value)
  385. {
  386. struct conf_entry *entry = snew(struct conf_entry);
  387. assert(subkeytypes[primary] == TYPE_NONE);
  388. assert(valuetypes[primary] == TYPE_STR);
  389. entry->key.primary = primary;
  390. entry->value.u.stringval = dupstr(value);
  391. conf_insert(conf, entry);
  392. }
  393. void conf_set_str_str(Conf *conf, int primary, const char *secondary,
  394. const char *value)
  395. {
  396. struct conf_entry *entry = snew(struct conf_entry);
  397. assert(subkeytypes[primary] == TYPE_STR);
  398. assert(valuetypes[primary] == TYPE_STR);
  399. entry->key.primary = primary;
  400. entry->key.secondary.s = dupstr(secondary);
  401. entry->value.u.stringval = dupstr(value);
  402. conf_insert(conf, entry);
  403. }
  404. void conf_del_str_str(Conf *conf, int primary, const char *secondary)
  405. {
  406. struct key key;
  407. struct conf_entry *entry;
  408. assert(subkeytypes[primary] == TYPE_STR);
  409. assert(valuetypes[primary] == TYPE_STR);
  410. key.primary = primary;
  411. key.secondary.s = (char *)secondary;
  412. entry = find234(conf->tree, &key, NULL);
  413. if (entry) {
  414. del234(conf->tree, entry);
  415. free_entry(entry);
  416. }
  417. }
  418. void conf_set_filename(Conf *conf, int primary, const Filename *value)
  419. {
  420. struct conf_entry *entry = snew(struct conf_entry);
  421. assert(subkeytypes[primary] == TYPE_NONE);
  422. assert(valuetypes[primary] == TYPE_FILENAME);
  423. entry->key.primary = primary;
  424. entry->value.u.fileval = filename_copy(value);
  425. conf_insert(conf, entry);
  426. }
  427. void conf_set_fontspec(Conf *conf, int primary, const FontSpec *value)
  428. {
  429. struct conf_entry *entry = snew(struct conf_entry);
  430. assert(subkeytypes[primary] == TYPE_NONE);
  431. assert(valuetypes[primary] == TYPE_FONT);
  432. entry->key.primary = primary;
  433. entry->value.u.fontval = fontspec_copy(value);
  434. conf_insert(conf, entry);
  435. }
  436. void conf_serialise(BinarySink *bs, Conf *conf)
  437. {
  438. int i;
  439. struct conf_entry *entry;
  440. for (i = 0; (entry = index234(conf->tree, i)) != NULL; i++) {
  441. put_uint32(bs, entry->key.primary);
  442. switch (subkeytypes[entry->key.primary]) {
  443. case TYPE_INT:
  444. put_uint32(bs, entry->key.secondary.i);
  445. break;
  446. case TYPE_STR:
  447. put_asciz(bs, entry->key.secondary.s);
  448. break;
  449. }
  450. switch (valuetypes[entry->key.primary]) {
  451. case TYPE_BOOL:
  452. put_bool(bs, entry->value.u.boolval);
  453. break;
  454. case TYPE_INT:
  455. put_uint32(bs, entry->value.u.intval);
  456. break;
  457. case TYPE_STR:
  458. put_asciz(bs, entry->value.u.stringval);
  459. break;
  460. case TYPE_FILENAME:
  461. filename_serialise(bs, entry->value.u.fileval);
  462. break;
  463. case TYPE_FONT:
  464. fontspec_serialise(bs, entry->value.u.fontval);
  465. break;
  466. }
  467. }
  468. put_uint32(bs, 0xFFFFFFFFU);
  469. }
  470. bool conf_deserialise(Conf *conf, BinarySource *src)
  471. {
  472. struct conf_entry *entry;
  473. unsigned primary;
  474. while (1) {
  475. primary = get_uint32(src);
  476. if (get_err(src))
  477. return false;
  478. if (primary == 0xFFFFFFFFU)
  479. return true;
  480. if (primary >= N_CONFIG_OPTIONS)
  481. return false;
  482. entry = snew(struct conf_entry);
  483. entry->key.primary = primary;
  484. switch (subkeytypes[entry->key.primary]) {
  485. case TYPE_INT:
  486. entry->key.secondary.i = toint(get_uint32(src));
  487. break;
  488. case TYPE_STR:
  489. entry->key.secondary.s = dupstr(get_asciz(src));
  490. break;
  491. }
  492. switch (valuetypes[entry->key.primary]) {
  493. case TYPE_BOOL:
  494. entry->value.u.boolval = get_bool(src);
  495. break;
  496. case TYPE_INT:
  497. entry->value.u.intval = toint(get_uint32(src));
  498. break;
  499. case TYPE_STR:
  500. entry->value.u.stringval = dupstr(get_asciz(src));
  501. break;
  502. case TYPE_FILENAME:
  503. entry->value.u.fileval = filename_deserialise(src);
  504. break;
  505. case TYPE_FONT:
  506. entry->value.u.fontval = fontspec_deserialise(src);
  507. break;
  508. }
  509. if (get_err(src)) {
  510. free_entry(entry);
  511. return false;
  512. }
  513. conf_insert(conf, entry);
  514. }
  515. }