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

/src/rec-types.c

#
C | 1691 lines | 1336 code | 228 blank | 127 comment | 212 complexity | 889995b3c56fc048b0e10f8d502774dd MD5 | raw file
Possible License(s): GPL-3.0
  1. /* -*- mode: C -*-
  2. *
  3. * File: rec-types.c
  4. * Date: Fri Apr 23 14:10:05 2010
  5. *
  6. * GNU recutils - Field types.
  7. *
  8. */
  9. /* Copyright (C) 2010-2013 Jose E. Marchesi */
  10. /* This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. */
  23. #include <config.h>
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <regex.h>
  27. #include <string.h>
  28. #include <limits.h>
  29. #include <regex.h>
  30. #include <parse-datetime.h>
  31. #include <gettext.h>
  32. #define _(str) dgettext (PACKAGE, str)
  33. #if defined UUID_TYPE
  34. # include <uuid/uuid.h>
  35. #endif
  36. #include <rec-utils.h>
  37. #include <rec.h>
  38. /*
  39. * Constants.
  40. */
  41. /* Textual name of the types expected in the type description
  42. strings. */
  43. #define REC_TYPE_INT_NAME "int"
  44. #define REC_TYPE_BOOL_NAME "bool"
  45. #define REC_TYPE_RANGE_NAME "range"
  46. #define REC_TYPE_REAL_NAME "real"
  47. #define REC_TYPE_SIZE_NAME "size"
  48. #define REC_TYPE_LINE_NAME "line"
  49. #define REC_TYPE_REGEXP_NAME "regexp"
  50. #define REC_TYPE_DATE_NAME "date"
  51. #define REC_TYPE_ENUM_NAME "enum"
  52. #define REC_TYPE_EMAIL_NAME "email"
  53. #define REC_TYPE_FIELD_NAME "field"
  54. #define REC_TYPE_REC_NAME "rec"
  55. #if defined UUID_TYPE
  56. # define REC_TYPE_UUID_NAME "uuid"
  57. #endif
  58. /* Regular expressions. */
  59. #define REC_TYPE_BLANK_RE "[ \t\n]"
  60. #define REC_TYPE_NO_BLANK_RE "[^ \t\n]"
  61. #define REC_TYPE_BLANKS_RE REC_TYPE_BLANK_RE "+"
  62. #define REC_TYPE_NO_BLANKS_RE REC_TYPE_NO_BLANK_RE "+"
  63. #define REC_TYPE_ZBLANKS_RE REC_TYPE_BLANK_RE "*"
  64. /* Regular expressions denoting values. */
  65. #define REC_TYPE_INT_VALUE_RE \
  66. "^" REC_TYPE_ZBLANKS_RE REC_INT_RE REC_TYPE_ZBLANKS_RE "$"
  67. #define REC_TYPE_BOOL_TRUE_VALUES_RE "1|yes|true"
  68. #define REC_TYPE_BOOL_FALSE_VALUES_RE "0|no|false"
  69. #define REC_TYPE_BOOL_VALUE_RE \
  70. "^" REC_TYPE_ZBLANKS_RE "(" REC_TYPE_BOOL_TRUE_VALUES_RE "|" \
  71. REC_TYPE_BOOL_FALSE_VALUES_RE \
  72. ")" REC_TYPE_ZBLANKS_RE "$"
  73. #define REC_TYPE_REAL_VALUE_RE \
  74. "^" REC_TYPE_ZBLANKS_RE "-?([0-9]+)?(\\.[0-9]+)?" REC_TYPE_ZBLANKS_RE "$"
  75. #define REC_TYPE_LINE_VALUE_RE \
  76. "^[^\n]*$"
  77. #define REC_TYPE_EMAIL_VALUE_RE \
  78. "^[ \n\t]*" \
  79. "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}" \
  80. "[ \n\t]*$"
  81. #define REC_TYPE_ENUM_NAME_RE \
  82. "[a-zA-Z0-9][a-zA-Z0-9_-]*"
  83. #define REC_TYPE_ENUM_VALUE_RE \
  84. "^" \
  85. REC_TYPE_ZBLANKS_RE \
  86. REC_TYPE_ENUM_NAME_RE \
  87. REC_TYPE_ZBLANKS_RE \
  88. "$"
  89. /* REC_FNAME_RE is defined in rec.h */
  90. #define REC_TYPE_FIELD_VALUE_RE \
  91. "^" \
  92. REC_TYPE_ZBLANKS_RE \
  93. REC_FNAME_RE \
  94. REC_TYPE_ZBLANKS_RE \
  95. "$"
  96. #define REC_TYPE_REC_VALUE_RE
  97. /* Regular expression denoting a type name. */
  98. #if defined UUID_TYPE
  99. # define REC_TYPE_CLASS_UUID_RE "|" REC_TYPE_UUID_NAME
  100. #else
  101. # define REC_TYPE_CLASS_UUID_RE
  102. #endif
  103. #define REC_TYPE_CLASS_RE \
  104. "(" REC_TYPE_INT_NAME "|" REC_TYPE_RANGE_NAME "|" \
  105. REC_TYPE_REAL_NAME "|" REC_TYPE_SIZE_NAME "|" \
  106. REC_TYPE_LINE_NAME "|" REC_TYPE_REGEXP_NAME "|" \
  107. REC_TYPE_DATE_NAME "|" REC_TYPE_ENUM_NAME "|" \
  108. REC_TYPE_EMAIL_NAME "|" REC_TYPE_BOOL_NAME "|" \
  109. REC_TYPE_FIELD_NAME "|" REC_TYPE_REC_NAME \
  110. REC_TYPE_CLASS_UUID_RE \
  111. ")"
  112. /* Regular expressions for the type descriptions. */
  113. /* int */
  114. #define REC_TYPE_INT_DESCR_RE \
  115. REC_TYPE_INT_NAME
  116. /* bool */
  117. #define REC_TYPE_BOOL_DESCR_RE \
  118. REC_TYPE_BOOL_NAME
  119. /* range MIN MAX */
  120. #define REC_TYPE_RANGE_MINMAX_RE "MIN | MAX"
  121. #define REC_TYPE_RANGE_DESCR_RE \
  122. REC_TYPE_RANGE_NAME \
  123. REC_TYPE_BLANKS_RE \
  124. "(" REC_INT_RE "|" REC_TYPE_RANGE_MINMAX_RE ")" \
  125. "(" \
  126. REC_TYPE_ZBLANKS_RE \
  127. "(" REC_INT_RE "|" REC_TYPE_RANGE_MINMAX_RE ")"\
  128. ")?"
  129. /* real */
  130. #define REC_TYPE_REAL_DESCR_RE \
  131. REC_TYPE_REAL_NAME
  132. /* size NUM */
  133. #define REC_TYPE_SIZE_DESCR_RE \
  134. REC_TYPE_SIZE_NAME \
  135. REC_TYPE_BLANKS_RE \
  136. REC_INT_RE
  137. /* line */
  138. #define REC_TYPE_LINE_DESCR_RE \
  139. REC_TYPE_LINE_NAME
  140. /* regexp /RE/ */
  141. #define REC_TYPE_REGEXP_DESCR_RE \
  142. REC_TYPE_REGEXP_NAME \
  143. ".+"
  144. /* date */
  145. #define REC_TYPE_DATE_DESCR_RE \
  146. REC_TYPE_DATE_NAME
  147. /* enum NAME NAME NAME*/
  148. #define REC_TYPE_ENUM_DESCR_RE \
  149. REC_TYPE_ENUM_NAME \
  150. REC_TYPE_BLANKS_RE \
  151. REC_TYPE_ENUM_NAME_RE \
  152. "(" REC_TYPE_BLANKS_RE REC_TYPE_ENUM_NAME_RE ")*"
  153. /* field */
  154. #define REC_TYPE_FIELD_DESCR_RE \
  155. REC_TYPE_FIELD_NAME
  156. /* rec RECORD_TYPE */
  157. #define REC_TYPE_REC_DESCR_RE \
  158. REC_TYPE_REC_NAME REC_TYPE_BLANKS_RE REC_RECORD_TYPE_RE
  159. /* email */
  160. #define REC_TYPE_EMAIL_DESCR_RE \
  161. REC_TYPE_EMAIL_NAME
  162. /* Regexp denoting any type description. */
  163. #define REC_TYPE_DESCR_RE \
  164. "^" \
  165. REC_TYPE_ZBLANKS_RE \
  166. REC_FNAME_RE "(," REC_FNAME_RE ")*" \
  167. REC_TYPE_ZBLANKS_RE \
  168. "(" \
  169. "(" REC_TYPE_INT_DESCR_RE ")" \
  170. "|" "(" REC_TYPE_BOOL_DESCR_RE ")" \
  171. "|" "(" REC_TYPE_RANGE_DESCR_RE ")" \
  172. "|" "(" REC_TYPE_REAL_DESCR_RE ")" \
  173. "|" "(" REC_TYPE_SIZE_DESCR_RE ")" \
  174. "|" "(" REC_TYPE_LINE_DESCR_RE ")" \
  175. "|" "(" REC_TYPE_REGEXP_DESCR_RE ")" \
  176. "|" "(" REC_TYPE_DATE_DESCR_RE ")" \
  177. "|" "(" REC_TYPE_EMAIL_DESCR_RE ")" \
  178. "|" "(" REC_TYPE_ENUM_DESCR_RE ")" \
  179. "|" "(" REC_TYPE_FIELD_DESCR_RE ")" \
  180. "|" "(" REC_TYPE_REC_DESCR_RE ")" \
  181. ")" \
  182. REC_TYPE_ZBLANKS_RE \
  183. "$"
  184. /*
  185. * Data types.
  186. */
  187. struct rec_type_s
  188. {
  189. char *name; /* Name of the type. May be NULL in an
  190. anonymous type. */
  191. enum rec_type_kind_e kind; /* Kind of the type. */
  192. char *expr; /* Copy of the type descriptor used to
  193. create the type. */
  194. size_t size; /* Used for enumerations: number of
  195. names. */
  196. union
  197. {
  198. size_t max_size; /* Size of string. */
  199. int range[2]; /* Range. */
  200. regex_t regexp; /* Regular expression. */
  201. char *recname; /* Record. */
  202. #define REC_ENUM_ALLOC_NAMES 50
  203. char **names; /* Names in enumeration. */
  204. } data;
  205. };
  206. #define REC_TYPE_REG_ALLOC_TYPES 100
  207. struct rec_type_reg_entry_s
  208. {
  209. char *type_name;
  210. rec_type_t type;
  211. char *to_type;
  212. bool visited_p;
  213. };
  214. struct rec_type_reg_s
  215. {
  216. size_t num_types;
  217. struct rec_type_reg_entry_s *types;
  218. };
  219. /*
  220. * Forward declarations.
  221. */
  222. static enum rec_type_kind_e rec_type_parse_type_kind (char *str);
  223. static bool rec_type_check_int (rec_type_t type, const char *str, rec_buf_t errors);
  224. static bool rec_type_check_bool (rec_type_t type, const char *str, rec_buf_t errors);
  225. static bool rec_type_check_range (rec_type_t type, const char *str, rec_buf_t errors);
  226. static bool rec_type_check_real (rec_type_t type, const char *str, rec_buf_t errors);
  227. static bool rec_type_check_size (rec_type_t type, const char *str, rec_buf_t errors);
  228. static bool rec_type_check_line (rec_type_t type, const char *str, rec_buf_t errors);
  229. static bool rec_type_check_regexp (rec_type_t type, const char *str, rec_buf_t errors);
  230. static bool rec_type_check_date (rec_type_t type, const char *str, rec_buf_t errors);
  231. static bool rec_type_check_email (rec_type_t type, const char *str, rec_buf_t errors);
  232. static bool rec_type_check_enum (rec_type_t type, const char *str, rec_buf_t errors);
  233. static bool rec_type_check_field (rec_type_t type, const char *str, rec_buf_t errors);
  234. static bool rec_type_check_rec (rec_type_t type, const char *str, rec_buf_t errors);
  235. #if defined UUID_TYPE
  236. static bool rec_type_check_uuid (rec_type_t type, const char *str, rec_buf_t errors);
  237. #endif
  238. /* Parsing routines. */
  239. static const char *rec_type_parse_size (const char *str, rec_type_t type);
  240. static const char *rec_type_parse_enum (const char *str, rec_type_t type);
  241. static const char *rec_type_parse_regexp_type (const char *str, rec_type_t type);
  242. static const char *rec_type_parse_range (const char *str, rec_type_t type);
  243. static const char *rec_type_parse_rec (const char *str, rec_type_t type);
  244. /*
  245. * Public functions.
  246. */
  247. bool
  248. rec_type_descr_p (const char *str)
  249. {
  250. bool ret;
  251. rec_type_t aux_type;
  252. ret = false;
  253. aux_type = rec_type_new (str);
  254. if (aux_type)
  255. {
  256. ret = true;
  257. rec_type_destroy (aux_type);
  258. }
  259. return ret;
  260. }
  261. char *
  262. rec_type_descr_type (char *str)
  263. {
  264. char *result = NULL;
  265. char *name;
  266. const char *p;
  267. if (rec_type_descr_p (str))
  268. {
  269. p = str;
  270. /* Skip blank characters. */
  271. rec_skip_blanks (&p);
  272. /* Skip the FEX */
  273. if (rec_parse_regexp (&p, "^" REC_FNAME_RE "(," REC_FNAME_RE ")*",
  274. &name))
  275. {
  276. free (name);
  277. }
  278. /* Skip blanks. */
  279. rec_skip_blanks (&p);
  280. /* Return the rest of the string. */
  281. result = strdup (p);
  282. }
  283. return result;
  284. }
  285. rec_type_t
  286. rec_type_new (const char *str)
  287. {
  288. rec_type_t new;
  289. const char *p;
  290. char *type_kind_str = NULL;
  291. p = str;
  292. new = malloc (sizeof (struct rec_type_s));
  293. if (!new)
  294. {
  295. goto exit;
  296. }
  297. new->name = NULL; /* Newly created types are anonyous. */
  298. new->size = 0;
  299. rec_skip_blanks (&p);
  300. /* Get the type kind. */
  301. if (!rec_parse_regexp (&p, "^" REC_TYPE_CLASS_RE, &type_kind_str))
  302. {
  303. free (new);
  304. new = NULL;
  305. goto exit;
  306. }
  307. /* Continue parsing depending on the kind of type. */
  308. new->kind = rec_type_parse_type_kind (type_kind_str);
  309. switch (new->kind)
  310. {
  311. case REC_TYPE_SIZE:
  312. {
  313. p = rec_type_parse_size (p, new);
  314. if (!p)
  315. {
  316. free (new);
  317. new = NULL;
  318. }
  319. break;
  320. }
  321. case REC_TYPE_ENUM:
  322. {
  323. p = rec_type_parse_enum (p, new);
  324. if (!p)
  325. {
  326. free (new);
  327. new = NULL;
  328. }
  329. break;
  330. }
  331. case REC_TYPE_REGEXP:
  332. {
  333. p = rec_type_parse_regexp_type (p, new);
  334. if (!p)
  335. {
  336. free (new);
  337. new = NULL;
  338. }
  339. break;
  340. }
  341. case REC_TYPE_RANGE:
  342. {
  343. p = rec_type_parse_range (p, new);
  344. if (!p)
  345. {
  346. free (new);
  347. new = NULL;
  348. }
  349. break;
  350. }
  351. case REC_TYPE_REC:
  352. {
  353. p = rec_type_parse_rec (p, new);
  354. if (!p)
  355. {
  356. free (new);
  357. new = NULL;
  358. }
  359. break;
  360. }
  361. case REC_TYPE_INT:
  362. case REC_TYPE_BOOL:
  363. case REC_TYPE_REAL:
  364. case REC_TYPE_LINE:
  365. case REC_TYPE_FIELD:
  366. case REC_TYPE_DATE:
  367. case REC_TYPE_EMAIL:
  368. #if defined UUID_TYPE
  369. case REC_TYPE_UUID:
  370. #endif
  371. {
  372. /* We are done. */
  373. break;
  374. }
  375. case REC_TYPE_NONE:
  376. {
  377. /* This point should not be reached. */
  378. fprintf (stderr,
  379. _("internal error: rec-types: got REC_TYPE_NONE from rec_type_parse_type_kind() in rec_type_new().\n"));
  380. exit (EXIT_FAILURE);
  381. break;
  382. }
  383. }
  384. if (new)
  385. {
  386. /* Check that all characters until the end of the string are
  387. blank characters. */
  388. while (*p != '\0')
  389. {
  390. if (!rec_blank_p (*p))
  391. {
  392. rec_type_destroy (new);
  393. new = NULL;
  394. break;
  395. }
  396. p++;
  397. }
  398. }
  399. exit:
  400. free (type_kind_str);
  401. return new;
  402. }
  403. enum rec_type_kind_e
  404. rec_type_kind (rec_type_t type)
  405. {
  406. return type->kind;
  407. }
  408. char *
  409. rec_type_kind_str (rec_type_t type)
  410. {
  411. char *res;
  412. switch (type->kind)
  413. {
  414. case REC_TYPE_NONE:
  415. {
  416. res = "";
  417. break;
  418. }
  419. case REC_TYPE_INT:
  420. {
  421. res = REC_TYPE_INT_NAME;
  422. break;
  423. }
  424. case REC_TYPE_BOOL:
  425. {
  426. res = REC_TYPE_BOOL_NAME;
  427. break;
  428. }
  429. case REC_TYPE_RANGE:
  430. {
  431. res = REC_TYPE_RANGE_NAME;
  432. break;
  433. }
  434. case REC_TYPE_REAL:
  435. {
  436. res = REC_TYPE_REAL_NAME;
  437. break;
  438. }
  439. case REC_TYPE_SIZE:
  440. {
  441. res = REC_TYPE_SIZE_NAME;
  442. break;
  443. }
  444. case REC_TYPE_LINE:
  445. {
  446. res = REC_TYPE_LINE_NAME;
  447. break;
  448. }
  449. case REC_TYPE_REGEXP:
  450. {
  451. res = REC_TYPE_REGEXP_NAME;
  452. break;
  453. }
  454. case REC_TYPE_DATE:
  455. {
  456. res = REC_TYPE_DATE_NAME;
  457. break;
  458. }
  459. case REC_TYPE_EMAIL:
  460. {
  461. res = REC_TYPE_EMAIL_NAME;
  462. break;
  463. }
  464. case REC_TYPE_ENUM:
  465. {
  466. res = REC_TYPE_ENUM_NAME;
  467. break;
  468. }
  469. case REC_TYPE_FIELD:
  470. {
  471. res = REC_TYPE_FIELD_NAME;
  472. break;
  473. }
  474. case REC_TYPE_REC:
  475. {
  476. res = REC_TYPE_REC_NAME;
  477. break;
  478. }
  479. #if defined UUID_TYPE
  480. case REC_TYPE_UUID:
  481. {
  482. res = REC_TYPE_UUID_NAME;
  483. break;
  484. }
  485. #endif
  486. default:
  487. {
  488. res = REC_TYPE_NONE;
  489. break;
  490. }
  491. }
  492. return res;
  493. }
  494. bool
  495. rec_type_check (rec_type_t type,
  496. const char *str,
  497. char **error_str)
  498. {
  499. bool res;
  500. rec_buf_t errors;
  501. char *err_str;
  502. size_t errors_size;
  503. errors = rec_buf_new (&err_str, &errors_size);
  504. res = false;
  505. switch (type->kind)
  506. {
  507. case REC_TYPE_NONE:
  508. {
  509. res = true;
  510. break;
  511. }
  512. case REC_TYPE_INT:
  513. {
  514. res = rec_type_check_int (type, str, errors);
  515. break;
  516. }
  517. case REC_TYPE_BOOL:
  518. {
  519. res = rec_type_check_bool (type, str, errors);
  520. break;
  521. }
  522. case REC_TYPE_RANGE:
  523. {
  524. res = rec_type_check_range (type, str, errors);
  525. break;
  526. }
  527. case REC_TYPE_REAL:
  528. {
  529. res = rec_type_check_real (type, str, errors);
  530. break;
  531. }
  532. case REC_TYPE_SIZE:
  533. {
  534. res = rec_type_check_size (type, str, errors);
  535. break;
  536. }
  537. case REC_TYPE_LINE:
  538. {
  539. res = rec_type_check_line (type, str, errors);
  540. break;
  541. }
  542. case REC_TYPE_REGEXP:
  543. {
  544. res = rec_type_check_regexp (type, str, errors);
  545. break;
  546. }
  547. case REC_TYPE_DATE:
  548. {
  549. res = rec_type_check_date (type, str, errors);
  550. break;
  551. }
  552. case REC_TYPE_EMAIL:
  553. {
  554. res = rec_type_check_email (type, str, errors);
  555. break;
  556. }
  557. case REC_TYPE_ENUM:
  558. {
  559. res = rec_type_check_enum (type, str, errors);
  560. break;
  561. }
  562. case REC_TYPE_FIELD:
  563. {
  564. res = rec_type_check_field (type, str, errors);
  565. break;
  566. }
  567. case REC_TYPE_REC:
  568. {
  569. res = rec_type_check_rec (type, str, errors);
  570. break;
  571. }
  572. #if defined UUID_TYPE
  573. case REC_TYPE_UUID:
  574. {
  575. res = rec_type_check_uuid (type, str, errors);
  576. break;
  577. }
  578. #endif
  579. }
  580. /* Terminate the 'errors' string. */
  581. rec_buf_close (errors);
  582. /* err_str[errors_size] = '\0';*/
  583. if (error_str)
  584. {
  585. *error_str = err_str;
  586. }
  587. else
  588. {
  589. free (err_str);
  590. }
  591. return res;
  592. }
  593. void
  594. rec_type_destroy (rec_type_t type)
  595. {
  596. int i;
  597. if (type)
  598. {
  599. if (type->kind == REC_TYPE_ENUM)
  600. {
  601. for (i = 0; i < type->size; i++)
  602. {
  603. free (type->data.names[i]);
  604. }
  605. }
  606. else if (type->kind == REC_TYPE_REGEXP)
  607. {
  608. regfree (&type->data.regexp);
  609. }
  610. free (type->name);
  611. free (type);
  612. }
  613. }
  614. rec_type_reg_t
  615. rec_type_reg_new (void)
  616. {
  617. rec_type_reg_t new;
  618. new = malloc (sizeof (struct rec_type_reg_s));
  619. if (new)
  620. {
  621. new->num_types = 0;
  622. new->types = NULL;
  623. }
  624. return new;
  625. }
  626. void
  627. rec_type_reg_destroy (rec_type_reg_t reg)
  628. {
  629. size_t i;
  630. for (i = 0; i < reg->num_types; i++)
  631. {
  632. if (reg->types[i].type)
  633. {
  634. rec_type_destroy (reg->types[i].type);
  635. }
  636. free (reg->types[i].type_name);
  637. free (reg->types[i].to_type);
  638. }
  639. free (reg->types);
  640. free (reg);
  641. }
  642. void
  643. rec_type_reg_add (rec_type_reg_t reg,
  644. rec_type_t type)
  645. {
  646. size_t i;
  647. const char *type_name = NULL;
  648. type_name = rec_type_name (type);
  649. if (!type_name)
  650. {
  651. /* The registry only contains named types. */
  652. return;
  653. }
  654. for (i = 0; i < reg->num_types; i++)
  655. {
  656. if (strcmp (reg->types[i].type_name, type_name) == 0)
  657. {
  658. /* Replace this entry. */
  659. if (reg->types[i].type)
  660. {
  661. rec_type_destroy (reg->types[i].type);
  662. }
  663. free (reg->types[i].type_name);
  664. free (reg->types[i].to_type);
  665. break;
  666. }
  667. }
  668. /* If we need to add a new entry then allocate it. */
  669. if (i == reg->num_types)
  670. {
  671. reg->types =
  672. realloc (reg->types,
  673. ((i / REC_TYPE_REG_ALLOC_TYPES) + 1) * (sizeof (struct rec_type_reg_entry_s *) * REC_TYPE_REG_ALLOC_TYPES));
  674. reg->num_types++;
  675. }
  676. reg->types[i].type_name = strdup (rec_type_name (type));
  677. reg->types[i].type = type;
  678. reg->types[i].to_type = NULL;
  679. reg->types[i].visited_p = false;
  680. }
  681. void
  682. rec_type_reg_add_synonym (rec_type_reg_t reg,
  683. const char *type_name,
  684. const char *to_type)
  685. {
  686. size_t i;
  687. for (i = 0; i < reg->num_types; i++)
  688. {
  689. if (strcmp (reg->types[i].type_name, type_name) == 0)
  690. {
  691. /* Replace this entry. */
  692. if (reg->types[i].type)
  693. {
  694. rec_type_destroy (reg->types[i].type);
  695. }
  696. free (reg->types[i].type_name);
  697. free (reg->types[i].to_type);
  698. break;
  699. }
  700. }
  701. /* If we need to add a new entry then allocate it. */
  702. if (i == reg->num_types)
  703. {
  704. reg->types =
  705. realloc (reg->types,
  706. ((i / REC_TYPE_REG_ALLOC_TYPES) + 1) * (sizeof (struct rec_type_reg_entry_s *) * REC_TYPE_REG_ALLOC_TYPES));
  707. reg->num_types++;
  708. }
  709. reg->types[i].type_name = strdup (type_name);
  710. reg->types[i].to_type = strdup (to_type);
  711. reg->types[i].type = NULL;
  712. reg->types[i].visited_p = false;
  713. }
  714. rec_type_t
  715. rec_type_reg_get (rec_type_reg_t reg,
  716. const char *type_name)
  717. {
  718. size_t i;
  719. rec_type_t type = NULL;
  720. for (i = 0; i < reg->num_types; i++)
  721. {
  722. if (strcmp (reg->types[i].type_name, type_name) == 0)
  723. {
  724. if (reg->types[i].type)
  725. {
  726. /* Type found. */
  727. type = reg->types[i].type;
  728. break;
  729. }
  730. else
  731. {
  732. /* Loop detection. */
  733. if (reg->types[i].visited_p)
  734. {
  735. break;
  736. }
  737. /* Mark this entry as visited and follow the name. */
  738. reg->types[i].visited_p = true;
  739. type = rec_type_reg_get (reg, reg->types[i].to_type);
  740. }
  741. }
  742. }
  743. /* Reset the visited flags. */
  744. for (i = 0; i < reg->num_types; i++)
  745. {
  746. reg->types[i].visited_p = false;
  747. }
  748. return type;
  749. }
  750. const char *
  751. rec_type_name (rec_type_t type)
  752. {
  753. return type->name;
  754. }
  755. void
  756. rec_type_set_name (rec_type_t type, const char *name)
  757. {
  758. type->name = strdup (name);
  759. }
  760. bool
  761. rec_type_equal_p (rec_type_t type1,
  762. rec_type_t type2)
  763. {
  764. bool ret;
  765. size_t i;
  766. ret = true;
  767. if (type1->kind != type2->kind)
  768. {
  769. ret = false;
  770. }
  771. else
  772. {
  773. if (type1->kind == REC_TYPE_SIZE)
  774. {
  775. ret = (type1->data.max_size == type2->data.max_size);
  776. }
  777. else if (type1->kind == REC_TYPE_RANGE)
  778. {
  779. ret = ((type1->data.range[0] == type2->data.range[0])
  780. && (type1->data.range[1] == type2->data.range[1]));
  781. }
  782. else if (type1->kind == REC_TYPE_ENUM)
  783. {
  784. for (i = 0; i < type1->size; i++)
  785. {
  786. ret = ((i < type2->size)
  787. && (strcmp (type1->data.names[i],
  788. type2->data.names[i]) == 0));
  789. }
  790. }
  791. else if (type1->kind == REC_TYPE_REGEXP)
  792. {
  793. /* Since there is no way to determine whether two
  794. regex_t variables refer to equivalent regexps. */
  795. ret = false;
  796. }
  797. }
  798. return ret;
  799. }
  800. int
  801. rec_type_min (rec_type_t type)
  802. {
  803. int res;
  804. if (type->kind != REC_TYPE_RANGE)
  805. {
  806. res = -1;
  807. }
  808. else
  809. {
  810. res = type->data.range[0];
  811. }
  812. return res;
  813. }
  814. int
  815. rec_type_max (rec_type_t type)
  816. {
  817. int res;
  818. if (type->kind != REC_TYPE_RANGE)
  819. {
  820. res = -1;
  821. }
  822. else
  823. {
  824. res = type->data.range[1];
  825. }
  826. return res;
  827. }
  828. const char *
  829. rec_type_rec (rec_type_t type)
  830. {
  831. const char *res = NULL;
  832. if (type->kind == REC_TYPE_REC)
  833. {
  834. res = type->data.recname;
  835. }
  836. return res;
  837. }
  838. int
  839. rec_type_values_cmp (rec_type_t type,
  840. const char *val1,
  841. const char *val2)
  842. {
  843. int type_comparison;
  844. enum rec_type_kind_e kind = REC_TYPE_NONE;
  845. if (type)
  846. {
  847. kind = type->kind;
  848. }
  849. switch (kind)
  850. {
  851. case REC_TYPE_INT:
  852. case REC_TYPE_RANGE:
  853. {
  854. int int1, int2 = 0;
  855. if (!rec_atoi (val1, &int1) || !rec_atoi (val2, &int2))
  856. {
  857. goto lexi;
  858. }
  859. if (int1 < int2)
  860. {
  861. type_comparison = -1;
  862. }
  863. else if (int1 > int2)
  864. {
  865. type_comparison = 1;
  866. }
  867. else
  868. {
  869. type_comparison = 0;
  870. }
  871. break;
  872. }
  873. case REC_TYPE_REAL:
  874. {
  875. double real1, real2 = 0;
  876. if (!rec_atod (val1, &real1) || !rec_atod (val2, &real2))
  877. {
  878. goto lexi;
  879. }
  880. if (real1 < real2)
  881. {
  882. type_comparison = -1;
  883. }
  884. else if (real1 > real2)
  885. {
  886. type_comparison = 1;
  887. }
  888. else
  889. {
  890. type_comparison = 0;
  891. }
  892. break;
  893. }
  894. case REC_TYPE_BOOL:
  895. {
  896. bool bool1, bool2 = false;
  897. /* Boolean fields storing 'false' come first. */
  898. bool1 = rec_match (val1,
  899. REC_TYPE_ZBLANKS_RE "(" REC_TYPE_BOOL_TRUE_VALUES_RE ")" REC_TYPE_ZBLANKS_RE);
  900. bool2 = rec_match (val2,
  901. REC_TYPE_ZBLANKS_RE "(" REC_TYPE_BOOL_TRUE_VALUES_RE ")" REC_TYPE_ZBLANKS_RE);
  902. if (!bool1 && bool2)
  903. {
  904. type_comparison = -1;
  905. }
  906. else if (bool1 == bool2)
  907. {
  908. type_comparison = 0;
  909. }
  910. else
  911. {
  912. type_comparison = 1;
  913. }
  914. break;
  915. }
  916. case REC_TYPE_DATE:
  917. {
  918. struct timespec op1;
  919. struct timespec op2;
  920. struct timespec diff;
  921. if (parse_datetime (&op1, val1, NULL)
  922. && parse_datetime (&op2, val2, NULL))
  923. {
  924. if ((op1.tv_sec == op2.tv_sec)
  925. && (op1.tv_nsec == op2.tv_nsec))
  926. {
  927. /* op1 == op2 */
  928. type_comparison = 0;
  929. }
  930. else if (rec_timespec_subtract (&diff, &op1, &op2))
  931. {
  932. /* op1 < op2 */
  933. type_comparison = -1;
  934. }
  935. else
  936. {
  937. /* op1 > op2 */
  938. type_comparison = 1;
  939. }
  940. }
  941. else
  942. {
  943. /* Invalid date => lexicographic order. */
  944. goto lexi;
  945. }
  946. break;
  947. }
  948. default:
  949. {
  950. lexi:
  951. /* Lexicographic order. */
  952. type_comparison = strcmp (val1, val2);
  953. break;
  954. }
  955. }
  956. return type_comparison;
  957. }
  958. /*
  959. * Private functions.
  960. */
  961. static enum rec_type_kind_e
  962. rec_type_parse_type_kind (char *str)
  963. {
  964. enum rec_type_kind_e res;
  965. res = REC_TYPE_NONE;
  966. if (strcmp (str, REC_TYPE_INT_NAME) == 0)
  967. {
  968. res = REC_TYPE_INT;
  969. }
  970. if (strcmp (str, REC_TYPE_BOOL_NAME) == 0)
  971. {
  972. res = REC_TYPE_BOOL;
  973. }
  974. if (strcmp (str, REC_TYPE_RANGE_NAME) == 0)
  975. {
  976. res = REC_TYPE_RANGE;
  977. }
  978. if (strcmp (str, REC_TYPE_REAL_NAME) == 0)
  979. {
  980. res = REC_TYPE_REAL;
  981. }
  982. if (strcmp (str, REC_TYPE_SIZE_NAME) == 0)
  983. {
  984. res = REC_TYPE_SIZE;
  985. }
  986. if (strcmp (str, REC_TYPE_LINE_NAME) == 0)
  987. {
  988. res = REC_TYPE_LINE;
  989. }
  990. if (strcmp (str, REC_TYPE_REGEXP_NAME) == 0)
  991. {
  992. res = REC_TYPE_REGEXP;
  993. }
  994. if (strcmp (str, REC_TYPE_DATE_NAME) == 0)
  995. {
  996. res = REC_TYPE_DATE;
  997. }
  998. if (strcmp (str, REC_TYPE_EMAIL_NAME) == 0)
  999. {
  1000. res = REC_TYPE_EMAIL;
  1001. }
  1002. if (strcmp (str, REC_TYPE_ENUM_NAME) == 0)
  1003. {
  1004. res = REC_TYPE_ENUM;
  1005. }
  1006. if (strcmp (str, REC_TYPE_FIELD_NAME) == 0)
  1007. {
  1008. res = REC_TYPE_FIELD;
  1009. }
  1010. if (strcmp (str, REC_TYPE_REC_NAME) == 0)
  1011. {
  1012. res = REC_TYPE_REC;
  1013. }
  1014. #if defined UUID_TYPE
  1015. if (strcmp (str, REC_TYPE_UUID_NAME) == 0)
  1016. {
  1017. res = REC_TYPE_UUID;
  1018. }
  1019. #endif
  1020. return res;
  1021. }
  1022. static bool
  1023. rec_type_check_int (rec_type_t type,
  1024. const char *str,
  1025. rec_buf_t errors)
  1026. {
  1027. bool ret;
  1028. ret = rec_match (str, REC_TYPE_INT_VALUE_RE);
  1029. if (!ret && errors)
  1030. {
  1031. rec_buf_puts (_("invalid integer."), errors);
  1032. }
  1033. return ret;
  1034. }
  1035. static bool
  1036. rec_type_check_rec (rec_type_t type,
  1037. const char *str,
  1038. rec_buf_t errors)
  1039. {
  1040. /* The values of type 'rec' are of whatever type the primary key of
  1041. the referred type is. That check is not implemented here, but in
  1042. rec-types.c.
  1043. So sorry Mario, but the Princess is kept in another castle... */
  1044. return true;
  1045. }
  1046. static bool
  1047. rec_type_check_field (rec_type_t type,
  1048. const char *str,
  1049. rec_buf_t errors)
  1050. {
  1051. bool ret;
  1052. ret = rec_match (str, REC_TYPE_FIELD_VALUE_RE);
  1053. if (!ret && errors)
  1054. {
  1055. rec_buf_puts (_("invalid 'field' value."), errors);
  1056. }
  1057. return ret;
  1058. }
  1059. #if defined UUID_TYPE
  1060. static bool
  1061. rec_type_check_uuid (rec_type_t type,
  1062. const char *str,
  1063. rec_buf_t errors)
  1064. {
  1065. int ret;
  1066. uuid_t uu;
  1067. /* Determine whether the given string is a valid UUID by parsing it
  1068. using the uuid_parse function provided by the libuuid
  1069. library. */
  1070. ret = uuid_parse (str, uu);
  1071. if ((ret == -1) && errors)
  1072. {
  1073. rec_buf_puts (_("invalid 'uuid' value."), errors);
  1074. }
  1075. return (ret == 0);
  1076. }
  1077. #endif /* UUID_TYPE */
  1078. static bool
  1079. rec_type_check_bool (rec_type_t type,
  1080. const char *str,
  1081. rec_buf_t errors)
  1082. {
  1083. bool ret;
  1084. ret = rec_match (str, REC_TYPE_BOOL_VALUE_RE);
  1085. if (!ret && errors)
  1086. {
  1087. rec_buf_puts (_("invalid 'bool' value."), errors);
  1088. }
  1089. return ret;
  1090. }
  1091. static bool
  1092. rec_type_check_range (rec_type_t type,
  1093. const char *str,
  1094. rec_buf_t errors)
  1095. {
  1096. bool ret;
  1097. const char *p;
  1098. int num;
  1099. char *tmp;
  1100. p = str;
  1101. rec_skip_blanks (&p);
  1102. if (!rec_parse_int (&p, &num))
  1103. {
  1104. if (errors)
  1105. {
  1106. rec_buf_puts (_("invalid 'range' value."), errors);
  1107. }
  1108. return false;
  1109. }
  1110. ret = ((num >= type->data.range[0])
  1111. && (num <= type->data.range[1]));
  1112. if (!ret && errors)
  1113. {
  1114. if (asprintf (&tmp, _("expected an integer between %d and %d."),
  1115. type->data.range[0], type->data.range[1]) != -1)
  1116. {
  1117. rec_buf_puts (tmp, errors);
  1118. free (tmp);
  1119. }
  1120. }
  1121. return ret;
  1122. }
  1123. static bool
  1124. rec_type_check_real (rec_type_t type,
  1125. const char *str,
  1126. rec_buf_t errors)
  1127. {
  1128. bool ret;
  1129. ret = rec_match (str, REC_TYPE_REAL_VALUE_RE);
  1130. if (!ret && errors)
  1131. {
  1132. rec_buf_puts (_("invalid 'real' value."), errors);
  1133. }
  1134. return ret;
  1135. }
  1136. static bool
  1137. rec_type_check_size (rec_type_t type,
  1138. const char *str,
  1139. rec_buf_t errors)
  1140. {
  1141. bool ret;
  1142. char *tmp;
  1143. ret = (strlen (str) <= type->data.max_size);
  1144. if (!ret && errors)
  1145. {
  1146. if (asprintf (&tmp,
  1147. _("value too large. Expected a size <= %zu."),
  1148. type->data.max_size) != -1)
  1149. {
  1150. rec_buf_puts (tmp, errors);
  1151. free (tmp);
  1152. }
  1153. }
  1154. return (strlen (str) <= type->data.max_size);
  1155. }
  1156. static bool
  1157. rec_type_check_line (rec_type_t type,
  1158. const char *str,
  1159. rec_buf_t errors)
  1160. {
  1161. bool ret;
  1162. ret = rec_match (str, REC_TYPE_LINE_VALUE_RE);
  1163. if (!ret && errors)
  1164. {
  1165. rec_buf_puts (_("invalid 'line' value."), errors);
  1166. }
  1167. return ret;
  1168. }
  1169. static bool
  1170. rec_type_check_regexp (rec_type_t type,
  1171. const char *str,
  1172. rec_buf_t errors)
  1173. {
  1174. bool ret;
  1175. ret = (regexec (&type->data.regexp,
  1176. str,
  1177. 0,
  1178. NULL,
  1179. 0) == 0);
  1180. if (!ret && errors)
  1181. {
  1182. rec_buf_puts (_("value does not match the regexp."), errors);
  1183. }
  1184. return ret;
  1185. }
  1186. static bool
  1187. rec_type_check_date (rec_type_t type,
  1188. const char *str,
  1189. rec_buf_t errors)
  1190. {
  1191. bool ret;
  1192. struct timespec tm;
  1193. if (strcmp (str, "") == 0)
  1194. {
  1195. /* The parse_datetime call accepts the empty string. */
  1196. return false;
  1197. }
  1198. ret = parse_datetime (&tm, str, NULL);
  1199. if (!ret && errors)
  1200. {
  1201. rec_buf_puts (_("invalid date."), errors);
  1202. }
  1203. return ret;
  1204. }
  1205. static bool
  1206. rec_type_check_email (rec_type_t type,
  1207. const char *str,
  1208. rec_buf_t errors)
  1209. {
  1210. bool ret;
  1211. ret = rec_match (str, REC_TYPE_EMAIL_VALUE_RE);
  1212. if (!ret && errors)
  1213. {
  1214. rec_buf_puts (_("invalid email."), errors);
  1215. }
  1216. return ret;
  1217. }
  1218. static bool
  1219. rec_type_check_enum (rec_type_t type,
  1220. const char *str,
  1221. rec_buf_t errors)
  1222. {
  1223. size_t i;
  1224. const char *p, *b;
  1225. char name[100];
  1226. if (rec_match (str, REC_TYPE_ENUM_VALUE_RE))
  1227. {
  1228. /* Get the name from STR. */
  1229. p = str;
  1230. while (p && rec_blank_p (*p))
  1231. {
  1232. p++;
  1233. }
  1234. b = p;
  1235. while (p && (rec_letter_p (*p)
  1236. || rec_letter_p (*p)
  1237. || rec_digit_p (*p)
  1238. || (*p == '_')
  1239. || (*p == '-')))
  1240. {
  1241. name[p - b] = *p;
  1242. p++;
  1243. }
  1244. name[p - b] = '\0';
  1245. /* Check for the name in the enum types. */
  1246. for (i = 0; i < type->size; i++)
  1247. if (strcmp (name, type->data.names[i]) == 0)
  1248. return true;
  1249. }
  1250. if (errors)
  1251. {
  1252. rec_buf_puts (_("invalid enum value."), errors);
  1253. }
  1254. return false;
  1255. }
  1256. static const char *
  1257. rec_type_parse_size (const char *str, rec_type_t type)
  1258. {
  1259. const char *p;
  1260. int size;
  1261. p = str;
  1262. /* Skip blanks. */
  1263. rec_skip_blanks (&p);
  1264. /* Get the size. */
  1265. if (rec_parse_int (&p, &size)
  1266. && (size >= 0))
  1267. {
  1268. type->data.max_size = size;
  1269. }
  1270. else
  1271. {
  1272. p = NULL;
  1273. }
  1274. return p;
  1275. }
  1276. static const char *
  1277. rec_type_parse_enum (const char *str, rec_type_t type)
  1278. {
  1279. const char *p;
  1280. size_t i;
  1281. p = str;
  1282. type->size = 0;
  1283. type->data.names = NULL;
  1284. while (*p)
  1285. {
  1286. /* Allocate space in the list of enum names if needed. */
  1287. if ((type->size % REC_ENUM_ALLOC_NAMES) == 0)
  1288. type->data.names =
  1289. realloc (type->data.names, ((type->size / REC_ENUM_ALLOC_NAMES) + 1) * (sizeof(char *) * REC_ENUM_ALLOC_NAMES));
  1290. /* Skip blanks. */
  1291. rec_skip_blanks (&p);
  1292. if (*p == '(')
  1293. {
  1294. /* Skip the comment. */
  1295. p++;
  1296. while (*p && (*p != ')') && (*p != '('))
  1297. {
  1298. p++;
  1299. }
  1300. if (*p == ')')
  1301. {
  1302. p++;
  1303. }
  1304. else
  1305. {
  1306. /* Parse error: unterminated comment. */
  1307. p = NULL;
  1308. break;
  1309. }
  1310. }
  1311. else if (*p)
  1312. {
  1313. /* Parse an enum entry. */
  1314. if (!rec_parse_regexp (&p,
  1315. "^" REC_TYPE_ENUM_NAME_RE,
  1316. &(type->data.names[type->size++])))
  1317. {
  1318. p = NULL;
  1319. break;
  1320. }
  1321. }
  1322. }
  1323. if (type->size == 0)
  1324. {
  1325. /* We require at least one entry in the enum. In this case it
  1326. is not needed to save memory. */
  1327. return NULL;
  1328. }
  1329. if (!p)
  1330. {
  1331. /* Free memory. */
  1332. for (i = 0; i < type->size; i++)
  1333. {
  1334. free (type->data.names[i]);
  1335. }
  1336. }
  1337. return p;
  1338. }
  1339. static const char *
  1340. rec_type_parse_regexp_type (const char *str, rec_type_t type)
  1341. {
  1342. const char *p;
  1343. char re[200];
  1344. bool end_regexp;
  1345. size_t i;
  1346. char delim_char;
  1347. p = str;
  1348. /* The regexp type descriptor is like:
  1349. BLANKS BEGIN_RE CHARS END_RE BLANKS
  1350. where BEGIN_RE == END_RE and is the first non-blank
  1351. character found in the string. Escaped apperances of
  1352. BEGIN_RE in CHARS are un-escaped.
  1353. */
  1354. /* Skip blanks. */
  1355. rec_skip_blanks (&p);
  1356. end_regexp = false;
  1357. delim_char = *p;
  1358. p++;
  1359. i = 0;
  1360. while (*p)
  1361. {
  1362. if (*p == delim_char)
  1363. {
  1364. if (*(p + 1) == delim_char)
  1365. {
  1366. re[i++] = delim_char;
  1367. p++;
  1368. }
  1369. else
  1370. {
  1371. /* End of the regexp. */
  1372. p++;
  1373. end_regexp = true;
  1374. break;
  1375. }
  1376. }
  1377. else
  1378. {
  1379. re[i++] = *p;
  1380. }
  1381. p++;
  1382. }
  1383. re[i] = '\0';
  1384. if (!end_regexp)
  1385. {
  1386. /* Error. */
  1387. p = NULL;
  1388. }
  1389. else
  1390. {
  1391. /* Compile the regexp. */
  1392. if (regcomp (&type->data.regexp, re,
  1393. REG_EXTENDED) != 0)
  1394. {
  1395. p = NULL;
  1396. }
  1397. }
  1398. return p;
  1399. }
  1400. static const char *
  1401. rec_type_parse_rec (const char *str, rec_type_t type)
  1402. {
  1403. const char *p = str;
  1404. /* Get the record name. */
  1405. rec_skip_blanks (&p);
  1406. if (!rec_parse_regexp (&p,
  1407. "^" REC_RECORD_TYPE_RE,
  1408. &(type->data.recname)))
  1409. {
  1410. return NULL;
  1411. }
  1412. return p;
  1413. }
  1414. static bool
  1415. rec_type_parse_range_point (const char **str, int *num)
  1416. {
  1417. if (rec_match (*str, "^MIN"))
  1418. {
  1419. *num = INT_MIN;
  1420. *str += 3;
  1421. }
  1422. else if (rec_match (*str, "^MAX"))
  1423. {
  1424. *num = INT_MAX;
  1425. *str += 3;
  1426. }
  1427. else if (!rec_parse_int (str, num))
  1428. {
  1429. return false;
  1430. }
  1431. return true;
  1432. }
  1433. static const char *
  1434. rec_type_parse_range (const char *str, rec_type_t type)
  1435. {
  1436. const char *p;
  1437. p = str;
  1438. rec_skip_blanks (&p);
  1439. if (!rec_type_parse_range_point (&p, &(type->data.range[0])))
  1440. {
  1441. return NULL;
  1442. }
  1443. rec_skip_blanks (&p);
  1444. if (*p == '\0')
  1445. {
  1446. /* One of the indexes is ommitted. The range is of the
  1447. form 0..N. */
  1448. type->data.range[1] = type->data.range[0];
  1449. type->data.range[0] = 0;
  1450. }
  1451. else
  1452. {
  1453. if (!rec_type_parse_range_point (&p, &(type->data.range[1])))
  1454. {
  1455. return NULL;
  1456. }
  1457. }
  1458. return p;
  1459. }
  1460. /* End of rec-types.c */