conf.c 16 KB

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