20221212
[devspec.git] / devspec.en_US / project / recutils / src / rec-int.c
blobbd648b92ba46a939a84538560acb25a6c8b6c8b6
1 /* -*- mode: C -*-
3 * File: rec-int.c
4 * Date: Thu Jul 15 18:23:26 2010
6 * GNU recutils - Data integrity.
8 */
10 /* Copyright (C) 2010-2019 Jose E. Marchesi */
12 /* This program is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, either version 3 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include <config.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <regex.h>
32 #include <gettext.h>
33 #define _(str) dgettext (PACKAGE, str)
34 #include <tempname.h>
36 #if defined REMOTE_DESCRIPTORS
37 # include <curl/curl.h>
38 #endif
40 #include <rec.h>
41 #include <rec-utils.h>
44 * Forward references.
47 static int rec_int_check_descriptor (rec_rset_t rset, rec_buf_t errors);
48 static int rec_int_check_record_key (rec_rset_t rset,
49 rec_record_t orig_record, rec_record_t record,
50 rec_buf_t errors);
51 static int rec_int_check_record_types (rec_db_t db,
52 rec_rset_t rset,
53 rec_record_t record,
54 rec_buf_t errors);
55 static int rec_int_check_record_mandatory (rec_rset_t rset, rec_record_t record,
56 rec_buf_t errors);
57 static int rec_int_check_record_unique (rec_rset_t rset, rec_record_t record,
58 rec_buf_t errors);
59 static int rec_int_check_record_prohibit (rec_rset_t rset, rec_record_t record,
60 rec_buf_t errors);
61 static int rec_int_check_record_sex_constraints (rec_rset_t rset, rec_record_t record,
62 rec_buf_t errors);
63 static int rec_int_check_record_allowed (rec_rset_t rset, rec_record_t record,
64 rec_buf_t errors);
66 #if defined REC_CRYPT_SUPPORT
67 static int rec_int_check_record_secrets (rec_rset_t rset, rec_record_t record,
68 rec_buf_t errors);
69 #endif
71 static int rec_int_merge_remote (rec_rset_t rset, rec_buf_t errors);
72 static bool rec_int_rec_type_p (const char *str);
74 /* The following macros are used by some functions in this file to
75 reduce verbosity. */
77 #define FNAME(id) rec_std_field_name ((id))
79 #define ADD_ERROR(buf,str,...) \
80 do \
81 { \
82 char *tmp = NULL; \
83 if (asprintf (&tmp, (str), __VA_ARGS__) != -1) \
84 { \
85 rec_buf_puts (tmp, (buf)); \
86 free (tmp); \
87 } \
88 } \
89 while (0)
92 * Public functions.
95 int
96 rec_int_check_db (rec_db_t db,
97 bool check_descriptors_p,
98 bool remote_descriptors_p,
99 rec_buf_t errors)
101 int ret;
102 size_t db_size;
103 size_t n_rset;
104 rec_rset_t rset;
106 ret = 0;
108 db_size = rec_db_size (db);
109 for (n_rset = 0; n_rset < db_size; n_rset++)
111 rset = rec_db_get_rset (db, n_rset);
112 ret = ret + rec_int_check_rset (db,
113 rset,
114 check_descriptors_p,
115 remote_descriptors_p,
116 errors);
119 return ret;
123 rec_int_check_rset (rec_db_t db,
124 rec_rset_t rset,
125 bool check_descriptor_p,
126 bool remote_descriptor_p,
127 rec_buf_t errors)
129 int res;
130 rec_mset_iterator_t iter;
131 rec_record_t record;
132 rec_record_t descriptor;
133 size_t num_records, min_records, max_records;
135 res = 0;
137 if (remote_descriptor_p
138 && (descriptor = rec_rset_descriptor (rset)))
140 /* Make a backup of the record descriptor to restore it
141 later. */
142 descriptor = rec_record_dup (descriptor);
144 /* Fetch the remote descriptor, if any, and merge it with the
145 local descriptor. If there is any error, stop and report
146 it. */
147 res = rec_int_merge_remote (rset, errors);
148 if (res > 0)
150 return res;
154 if (check_descriptor_p)
156 res += rec_int_check_descriptor (rset, errors);
159 if (res > 0)
161 /* Stop here, since a lot of errors in the records will be
162 generated due to errors in the record descriptor. */
163 return res;
166 /* Verify rset size restrictions. */
167 num_records = rec_rset_num_records (rset);
168 min_records = rec_rset_min_records (rset);
169 max_records = rec_rset_max_records (rset);
171 if (min_records == max_records)
173 if (num_records != min_records)
175 ADD_ERROR (errors,
176 _("%s: error: the number of records of type %s should be %zd.\n"),
177 rec_rset_source (rset), rec_rset_type (rset), min_records);
178 res++;
181 else
183 if (num_records > rec_rset_max_records (rset))
185 ADD_ERROR (errors,
186 _("%s: error: too many records of type %s. Maximum allowed are %zd.\n"),
187 rec_rset_source (rset), rec_rset_type (rset), rec_rset_max_records (rset));
188 res++;
190 if (num_records < rec_rset_min_records (rset))
192 ADD_ERROR (errors,
193 _("%s: error: too few records of type %s. Minimum allowed are %zd.\n"),
194 rec_rset_source (rset), rec_rset_type (rset), rec_rset_min_records (rset));
195 res++;
199 iter = rec_mset_iterator (rec_rset_mset (rset));
200 while (rec_mset_iterator_next (&iter, MSET_RECORD, (const void **) &record, NULL))
202 res += rec_int_check_record (db,
203 rset,
204 record, record,
205 errors);
208 rec_mset_iterator_free (&iter);
210 if (remote_descriptor_p)
212 /* Restore the original descriptor in the record set. */
213 rec_rset_set_descriptor (rset, descriptor);
216 return res;
220 rec_int_check_record (rec_db_t db,
221 rec_rset_t rset,
222 rec_record_t orig_record,
223 rec_record_t record,
224 rec_buf_t errors)
226 int res;
228 res =
229 rec_int_check_record_key (rset, orig_record, record, errors)
230 + rec_int_check_record_types (db, rset, record, errors)
231 + rec_int_check_record_mandatory (rset, record, errors)
232 + rec_int_check_record_unique (rset, record, errors)
233 #if defined REC_CRYPT_SUPPORT
234 + rec_int_check_record_secrets (rset, record, errors)
235 #endif
236 + rec_int_check_record_prohibit (rset, record, errors)
237 + rec_int_check_record_sex_constraints (rset, record, errors)
238 + rec_int_check_record_allowed (rset, record, errors);
240 return res;
243 bool
244 rec_int_check_field_type (rec_db_t db,
245 rec_rset_t rset,
246 rec_field_t field,
247 rec_buf_t errors)
249 bool res = true;
250 rec_type_t type;
251 char *errors_str;
253 res = true;
256 /* Get the proper type to check 'field' with, checking with the type
257 from the type registry of 'rset', if any. */
259 type = rec_rset_get_field_type (rset, rec_field_name (field));
261 /* Check the field with the type. This is done by simply invoking
262 rec_type_check on the field value. An exception to this is the
263 'rec' type. The 'rec' type is used to implement foreign keys,
264 and its effect on the type integrity system is that the value of
265 the field must be considered to be of whatever type the primary
266 key of the referred record set is. */
268 if (type)
270 if (rec_type_kind (type) == REC_TYPE_REC)
272 /* Get the name of the referred record set. Check the type
273 if and only if:
275 - The referred rset exists in DB and
276 - The referred rset has a primary key.
277 - The primary key of the referred rset has a type.
280 const char *rset_type = rec_type_rec (type);
281 rec_rset_t rset = rec_db_get_rset_by_type (db, rset_type);
283 if (rset)
285 const char *key = rec_rset_key (rset);
286 rec_type_t key_type = rec_rset_get_field_type (rset, key);
288 if (key_type)
290 if (!rec_type_check (key_type, rec_field_value (field), &errors_str))
292 if (errors)
294 ADD_ERROR (errors,
295 "%s:%s: error: %s\n",
296 rec_field_source (field), rec_field_location_str (field),
297 errors_str);
299 free (errors_str);
300 res = false;
305 else
307 if (!rec_type_check (type, rec_field_value (field), &errors_str))
309 if (errors)
311 ADD_ERROR (errors,
312 "%s:%s: error: %s\n",
313 rec_field_source (field), rec_field_location_str (field),
314 errors_str);
316 free (errors_str);
317 res = false;
322 return res;
326 * Private functions
329 static rec_fex_t
330 rec_int_collect_field_list (rec_record_t record,
331 const char *fname)
333 size_t i, j = 0;
334 size_t num_fields = rec_record_get_num_fields_by_name (record, fname);
335 rec_fex_t res = rec_fex_new (NULL, REC_FEX_SIMPLE);
337 if (!res)
338 return NULL; /* Out of memory. */
340 for (i = 0; i < num_fields; i++)
342 rec_field_t field = rec_record_get_field_by_name (record, fname, i);
343 rec_fex_t fex = rec_fex_new (rec_field_value (field), REC_FEX_SIMPLE);
344 if (!fex)
345 /* Invalid value in the field. Ignore it. */
346 continue;
348 for (j = 0; j < rec_fex_size (fex); j++)
350 rec_fex_elem_t elem = rec_fex_get (fex, j);
351 char *field_name = strdup (rec_fex_elem_field_name (elem));
353 if (!field_name
354 || !rec_fex_append (res,
355 field_name,
356 rec_fex_elem_min (elem),
357 rec_fex_elem_max (elem)))
358 /* Not enough memory: panic and retreat! */
359 return NULL;
361 rec_fex_destroy (fex);
364 return res;
367 static int
368 rec_int_check_record_types (rec_db_t db,
369 rec_rset_t rset,
370 rec_record_t record,
371 rec_buf_t errors)
373 int res;
374 rec_field_t field;
375 rec_mset_iterator_t iter;
377 res = 0;
379 iter = rec_mset_iterator (rec_record_mset (record));
380 while (rec_mset_iterator_next (&iter, MSET_FIELD, (const void **) &field, NULL))
382 /* Check for the type. */
383 if (!rec_int_check_field_type (db, rset, field, errors))
385 res++;
389 rec_mset_iterator_free (&iter);
391 return res;
394 static int
395 rec_int_check_record_mandatory (rec_rset_t rset,
396 rec_record_t record,
397 rec_buf_t errors)
399 rec_fex_t fex_mandatory = NULL;
400 int res = 0;
401 size_t i;
403 rec_record_t descriptor = rec_rset_descriptor (rset);
404 if (descriptor)
406 fex_mandatory = rec_int_collect_field_list (descriptor, FNAME(REC_FIELD_MANDATORY));
407 if (!fex_mandatory)
409 ADD_ERROR (errors, _("out of memory\n"), "");
410 res = 1;
411 goto cleanup;
414 /* Make sure that all fields in the mandatory fields list are in
415 this record. */
417 for (i = 0; i < rec_fex_size (fex_mandatory); i++)
419 const char *fname = rec_fex_elem_field_name (rec_fex_get (fex_mandatory, i));
420 if (rec_record_get_num_fields_by_name (record, fname)
421 == 0)
423 ADD_ERROR (errors,
424 _("%s:%s: error: mandatory field '%s' not found in record\n"),
425 rec_record_source (record),
426 rec_record_location_str (record),
427 fname);
428 res++;
433 cleanup:
435 rec_fex_destroy (fex_mandatory);
436 return res;
439 static int
440 rec_int_check_record_allowed (rec_rset_t rset,
441 rec_record_t record,
442 rec_buf_t errors)
444 /* If %allowed is specified then fields with names not in the union
445 of %allowed + %mandatory + %key are not allowed in records, and
446 thus that situation is an integrity error. */
448 rec_fex_t fex_allowed = NULL;
449 rec_fex_t fex_mandatory = NULL;
450 rec_fex_t fex_key = NULL;
452 int res = 0;
453 rec_record_t descriptor = rec_rset_descriptor (rset);
455 if (descriptor)
457 fex_allowed = rec_int_collect_field_list (descriptor, FNAME(REC_FIELD_ALLOWED));
458 fex_mandatory = rec_int_collect_field_list (descriptor, FNAME(REC_FIELD_MANDATORY));
459 fex_key = rec_int_collect_field_list (descriptor, FNAME(REC_FIELD_KEY));
461 if (!fex_allowed || !fex_mandatory || !fex_key)
463 ADD_ERROR (errors, _("out of memory\n"), "");
464 res = 1;
465 goto cleanup;
469 if (rec_fex_size (fex_allowed) == 0)
470 /* Nothing to do. */
471 goto cleanup;
473 /* Make sure that all the fields in RECORD are in either
474 %allowed, %mandatory or %key. */
476 rec_field_t field = NULL;
477 rec_mset_iterator_t iter = rec_mset_iterator (rec_record_mset (record));
478 while (rec_mset_iterator_next (&iter, MSET_FIELD, (const void **) &field, NULL))
480 const char *field_name = rec_field_name (field);
481 if (!(rec_fex_member_p (fex_allowed, field_name, -1, -1)
482 || rec_fex_member_p (fex_mandatory, field_name, -1, -1)
483 || rec_fex_member_p (fex_key, field_name, -1, -1)))
485 /* This field is not allowed. */
486 ADD_ERROR (errors,
487 _("%s:%s: error: field '%s' not allowed in this record set\n"),
488 rec_record_source (record),
489 rec_record_location_str (record),
490 field_name);
491 res++;
494 rec_mset_iterator_free (&iter);
497 cleanup:
499 rec_fex_destroy (fex_allowed);
500 rec_fex_destroy (fex_mandatory);
501 rec_fex_destroy (fex_key);
502 return res;
505 static int
506 rec_int_check_record_unique (rec_rset_t rset,
507 rec_record_t record,
508 rec_buf_t errors)
510 rec_fex_t fex_unique = NULL;
511 int res = 0;
512 size_t i;
514 rec_record_t descriptor = rec_rset_descriptor (rset);
515 if (descriptor)
517 fex_unique = rec_int_collect_field_list (descriptor, FNAME(REC_FIELD_UNIQUE));
518 if (!fex_unique)
520 ADD_ERROR (errors, _("out of memory\n"), "");
521 res = 1;
522 goto cleanup;
525 /* Make sure that all fields in the unique fields list are
526 unique in this record. */
528 for (i = 0; i < rec_fex_size (fex_unique); i++)
530 const char *fname = rec_fex_elem_field_name (rec_fex_get (fex_unique, i));
531 if (rec_record_get_num_fields_by_name (record, fname) > 1)
533 ADD_ERROR (errors,
534 _("%s:%s: error: field '%s' should be unique in this record\n"),
535 rec_record_source (record),
536 rec_record_location_str (record),
537 fname);
538 res++;
543 cleanup:
545 rec_fex_destroy (fex_unique);
546 return res;
549 static int
550 rec_int_check_record_prohibit (rec_rset_t rset,
551 rec_record_t record,
552 rec_buf_t errors)
554 rec_fex_t fex_prohibit = NULL;
555 int res = 0;
556 size_t i;
558 rec_record_t descriptor = rec_rset_descriptor (rset);
559 if (descriptor)
561 fex_prohibit = rec_int_collect_field_list (descriptor, FNAME(REC_FIELD_PROHIBIT));
562 if (!fex_prohibit)
564 ADD_ERROR (errors, _("out of memory\n"), "");
565 res = 1;
566 goto cleanup;
569 /* Make sure that no field in the prohibit fields list is
570 present in the record. */
572 for (i = 0; i < rec_fex_size (fex_prohibit); i++)
574 const char *fname = rec_fex_elem_field_name (rec_fex_get (fex_prohibit, i));
575 if (rec_record_get_num_fields_by_name (record, fname) > 0)
577 ADD_ERROR (errors,
578 _("%s:%s: error: prohibited field '%s' found in record\n"),
579 rec_record_source (record),
580 rec_record_location_str (record),
581 fname);
582 res++;
587 cleanup:
589 rec_fex_destroy (fex_prohibit);
590 return res;
593 static int
594 rec_int_check_record_sex_constraints (rec_rset_t rset,
595 rec_record_t record,
596 rec_buf_t errors)
598 int res = 0;
599 size_t i = 0;
600 size_t num_constraints = rec_rset_num_sex_constraints (rset);
602 for (i = 0; i < num_constraints; i++)
604 bool status = false;
605 rec_sex_t sex = rec_rset_sex_constraint (rset, i);
607 if (!rec_sex_eval (sex, record, &status))
609 ADD_ERROR (errors,
610 _("%s:%s: error: %%constraint[%d] violated in record\n"),
611 rec_record_source (record),
612 rec_record_location_str (record),
614 res++;
618 return res;
621 #if defined REC_CRYPT_SUPPORT
623 static int
624 rec_int_check_record_secrets (rec_rset_t rset,
625 rec_record_t record,
626 rec_buf_t errors)
628 int res;
629 rec_field_t field;
630 rec_mset_iterator_t iter;
632 res = 0;
634 iter = rec_mset_iterator (rec_record_mset (record));
635 while (rec_mset_iterator_next (&iter, MSET_FIELD, (const void**) &field, NULL))
637 /* If the field is confidential it must be encrypted. Encrypted
638 field values can be recognized by the "encrypted-"
639 prefix. */
640 #define REC_ENCRYPTED_PREFIX "encrypted-"
641 if (rec_rset_field_confidential_p (rset, rec_field_name (field))
642 && (strncmp (rec_field_value (field),
643 REC_ENCRYPTED_PREFIX,
644 strlen (REC_ENCRYPTED_PREFIX)) != 0))
646 ADD_ERROR (errors,
647 _("%s:%s: error: confidential field is not encrypted\n"),
648 rec_record_source (record),
649 rec_record_location_str (record));
650 res++;
654 rec_mset_iterator_free (&iter);
656 return res;
659 #endif /* REC_CRYPT_SUPPORT */
661 static int
662 rec_int_check_record_key (rec_rset_t rset,
663 rec_record_t orig_record,
664 rec_record_t record,
665 rec_buf_t errors)
667 int res;
668 rec_record_t descriptor;
669 rec_record_t other_record;
670 rec_mset_iterator_t iter;
671 char *key_field_name;
672 rec_field_t field;
673 rec_field_t key;
674 rec_field_t other_key;
675 bool duplicated_key;
676 size_t i;
677 size_t num_fields;
679 res = 0;
681 descriptor = rec_rset_descriptor (rset);
682 if (descriptor)
684 for (i = 0; i < rec_record_get_num_fields_by_name (descriptor,
685 FNAME(REC_FIELD_KEY));
686 i++)
688 field = rec_record_get_field_by_name (descriptor, FNAME(REC_FIELD_KEY), i);
690 /* Parse the field name from the value of %key: */
691 key_field_name = rec_parse_field_name_str (rec_field_value (field));
692 if (key_field_name)
694 num_fields = rec_record_get_num_fields_by_name (record, key_field_name);
696 if (num_fields == 0)
698 ADD_ERROR (errors,
699 _("%s:%s: error: key field '%s' not found in record\n"),
700 rec_record_source (record),
701 rec_record_location_str (record),
702 rec_field_value (field));
703 res++;
705 else if (num_fields > 1)
707 ADD_ERROR (errors,
708 _("%s:%s: error: multiple key fields '%s' in record\n"),
709 rec_record_source (record),
710 rec_record_location_str (record),
711 rec_field_value (field));
712 res++;
714 else /* num_fields == 1 */
716 /* Check that the value specified as the key is
717 unique in the whole record set. */
718 key = rec_record_get_field_by_name (record,
719 key_field_name,
721 duplicated_key = false;
723 iter = rec_mset_iterator (rec_rset_mset (rset));
724 while (rec_mset_iterator_next (&iter, MSET_RECORD, (const void**) &other_record, NULL))
726 if (other_record != orig_record)
728 /* XXX: Only the first key field is considered. */
729 other_key = rec_record_get_field_by_name (other_record,
730 key_field_name,
732 if (other_key)
734 if (strcmp (rec_field_value (other_key),
735 rec_field_value (key)) == 0)
737 /* Found a key field with the same
738 value in other record. */
739 duplicated_key = true;
740 break;
746 rec_mset_iterator_free (&iter);
748 if (duplicated_key)
750 ADD_ERROR (errors,
751 _("%s:%s: error: duplicated key value in field '%s' in record\n"),
752 rec_record_source (orig_record),
753 rec_record_location_str (orig_record),
754 rec_field_name (key));
755 res++;
756 break;
760 free (key_field_name);
765 return res;
768 static int
769 rec_int_check_descriptor (rec_rset_t rset,
770 rec_buf_t errors)
772 int res;
773 rec_record_t descriptor;
774 rec_mset_iterator_t iter;
775 rec_field_t field;
776 const char *field_name;
777 const char *field_value;
778 rec_fex_t fex;
779 const char *auto_field_name;
780 size_t i;
781 rec_type_t type;
782 char *type_name = NULL;
783 const char *p, *q = NULL;
785 res = 0;
787 descriptor = rec_rset_descriptor (rset);
788 if (descriptor)
790 /* Check the type of the record set:
792 1. There should be one (and only one) %rec: field in the
793 record.
794 2. The value of the %rec: field shall be well-formed.
796 if (rec_record_get_num_fields_by_name (descriptor, FNAME(REC_FIELD_REC)) == 0)
798 ADD_ERROR (errors,
799 _("%s:%s: error: missing %%rec field in record descriptor\n"),
800 rec_record_source (descriptor),
801 rec_record_location_str (descriptor));
802 res++;
804 else if (rec_record_get_num_fields_by_name (descriptor, FNAME(REC_FIELD_REC)) > 1)
806 ADD_ERROR (errors,
807 _("%s:%s: error: too many %%rec fields in record descriptor\n"),
808 rec_record_source (descriptor),
809 rec_record_location_str (descriptor));
810 res++;
813 field = rec_record_get_field_by_name (descriptor, FNAME(REC_FIELD_REC), 0);
814 if (!rec_int_rec_type_p (rec_field_value (field)))
816 ADD_ERROR (errors,
817 _("%s:%s: error: invalid record type %s\n"),
818 rec_field_source (field),
819 rec_field_location_str (field),
820 rec_field_value (field));
821 res++;
824 /* Only one 'key:' entry is allowed, if any. */
825 if (rec_record_get_num_fields_by_name (descriptor, FNAME(REC_FIELD_KEY)) > 1)
827 ADD_ERROR (errors,
828 _("%s:%s: error: only one %%key field is allowed in a record descriptor\n"),
829 rec_record_source (descriptor),
830 rec_record_location_str (descriptor));
831 res++;
834 /* Only one 'size:' entry is allowed, if any. */
835 if (rec_record_get_num_fields_by_name (descriptor, FNAME(REC_FIELD_SIZE)) > 1)
837 ADD_ERROR (errors,
838 _("%s:%s: error: only one %%size field is allowed in a record descriptor\n"),
839 rec_record_source (descriptor),
840 rec_record_location_str (descriptor));
841 res++;
844 /* Only one 'sort:' entry is allowed, if any. */
845 if (rec_record_get_num_fields_by_name (descriptor, FNAME(REC_FIELD_SORT)) > 1)
847 ADD_ERROR (errors,
848 _("%s:%s: error: only one %%sort field is allowed in a record descriptor\n"),
849 rec_record_source (descriptor),
850 rec_record_location_str (descriptor));
851 res++;
854 /* Iterate on fields. */
856 iter = rec_mset_iterator (rec_record_mset (descriptor));
857 while (rec_mset_iterator_next (&iter, MSET_FIELD, (const void**) &field, NULL))
859 field_name = rec_field_name (field);
860 field_value = rec_field_value (field);
862 if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_TYPE)))
864 /* Check for the list of fields. */
865 p = field_value;
866 rec_skip_blanks (&p);
867 if (!rec_parse_regexp (&p, "^" REC_FNAME_RE "(," REC_FNAME_RE ")*",
868 NULL))
870 ADD_ERROR (errors,
871 _("%s:%s: error: expected a comma-separated list of fields \
872 before the type specification\n"),
873 rec_field_source (field),
874 rec_field_location_str (field));
875 res++;
878 /* Check the type descriptor. Note that it can be
879 either a type specification or a type name. */
880 rec_skip_blanks (&p);
881 if (!rec_type_descr_p (p))
883 q = p;
884 if (rec_parse_regexp (&q, "^" REC_TYPE_NAME_RE "[ \t\n]*$",
885 NULL))
887 /* The named type shall exist in the record set
888 type registry.
890 XXX: but this is probably a warning rather
891 than an error. */
893 rec_parse_regexp (&p, "^" REC_TYPE_NAME_RE, &type_name);
894 if (!rec_type_reg_get (rec_rset_get_type_reg (rset), type_name))
896 ADD_ERROR (errors,
897 _("%s:%s: error: the referred type %s \
898 does not exist\n"),
899 rec_field_source (field),
900 rec_field_location_str (field),
901 type_name);
902 res++;
905 else
907 /* XXX: make rec_type_descr_p to report more details. */
908 ADD_ERROR (errors,
909 _("%s:%s: error: invalid type specification\n"),
910 rec_field_source (field),
911 rec_field_location_str (field));
912 res++;
916 else if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_TYPEDEF)))
918 /* Check for the type name. */
919 p = field_value;
920 rec_skip_blanks (&p);
921 if (!rec_parse_regexp (&p, "^" REC_TYPE_NAME_RE, NULL))
923 ADD_ERROR (errors,
924 _("%s:%s: error: expected a type name before the type \
925 specification\n"),
926 rec_field_source (field),
927 rec_field_location_str (field));
928 res++;
931 /* Check the type descriptor. Note that it can be
932 either a type specification or a type name. */
933 rec_skip_blanks (&p);
934 if (!rec_type_descr_p (p))
936 q = p;
937 if (rec_parse_regexp (&q, "^" REC_TYPE_NAME_RE "[ \t\n]*$",
938 NULL))
940 /* The named type shall exist in the record set
941 type registry.
943 XXX: but this is probably a warning rather
944 than an error. */
946 rec_parse_regexp (&p, "^" REC_TYPE_NAME_RE, &type_name);
947 if (!rec_type_reg_get (rec_rset_get_type_reg (rset), type_name))
949 ADD_ERROR (errors,
950 _("%s:%s: error: the referred type %s \
951 does not exist\n"),
952 rec_field_source (field),
953 rec_field_location_str (field),
954 type_name);
955 res++;
958 else
960 /* XXX: make rec_type_descr_p to report more details. */
961 ADD_ERROR (errors,
962 _("%s:%s: error: invalid typedef specification\n"),
963 rec_field_source (field),
964 rec_field_location_str (field));
965 res++;
969 else if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_CONSTRAINT)))
971 /* Check that the value of this field is a valid
972 selection expression. */
974 rec_sex_t sex = rec_sex_new (false);
975 if (sex)
977 if (rec_sex_compile (sex, field_value))
979 rec_sex_destroy (sex);
981 else
983 ADD_ERROR (errors,
984 _("%s:%s: error: value for %s[%zd] is not a valid selection expression\n"),
985 rec_record_source (descriptor),
986 rec_record_location_str (descriptor),
987 rec_field_name (field),
988 rec_record_get_field_index_by_name (descriptor, field));
989 res++;
992 else
994 /* Out of memory. */
995 res++;
998 else if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_MANDATORY))
999 || rec_field_name_equal_p (field_name, FNAME(REC_FIELD_UNIQUE))
1000 || rec_field_name_equal_p (field_name, FNAME(REC_FIELD_PROHIBIT))
1001 || rec_field_name_equal_p (field_name, FNAME(REC_FIELD_AUTO))
1002 || rec_field_name_equal_p (field_name, FNAME(REC_FIELD_SORT))
1003 || rec_field_name_equal_p (field_name, FNAME(REC_FIELD_ALLOWED)))
1005 /* Check that the value of this field is a parseable
1006 list of field names. */
1007 fex = rec_fex_new (field_value, REC_FEX_SIMPLE);
1008 if (fex)
1010 rec_fex_destroy (fex);
1012 else
1014 ADD_ERROR (errors,
1015 _("%s:%s: error: value for %s[%zd] is not a list of field names\n"),
1016 rec_record_source (descriptor),
1017 rec_record_location_str (descriptor),
1018 rec_field_name (field),
1019 rec_record_get_field_index_by_name (descriptor, field));
1020 res++;
1023 else if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_SIZE)))
1025 if (!rec_match (field_value, REC_INT_SIZE_RE))
1027 ADD_ERROR (errors,
1028 _("%s:%s: error: value for %s should be a number optionally preceded by >, <, >= or <=.\n"),
1029 rec_field_source (field),
1030 rec_field_location_str (field),
1031 field_name);
1032 res++;
1035 #if defined REC_CRYPT_SUPPORT
1036 else if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_CONFIDENTIAL)))
1038 if (!rec_match (field_value,
1040 "[ \n\t]*" REC_FNAME_RE "([ \n\t]+" REC_FNAME_RE ")*"
1041 "[ \n\t]*$"))
1043 ADD_ERROR (errors,
1044 _("%s:%s: error: value for %s should be a list of field names.\n"),
1045 rec_field_source (field),
1046 rec_field_location_str (field),
1047 field_name);
1048 res++;
1051 #endif /* REC_CRYPT_SUPPORT */
1053 if ((rec_field_name_equal_p (field_name, FNAME(REC_FIELD_AUTO)))
1054 && (fex = rec_fex_new (field_value, REC_FEX_SIMPLE)))
1056 /* Check that the auto incremented fields have not been
1057 declared with a type other than 'int'. */
1058 for (i = 0; i < rec_fex_size (fex); i++)
1060 auto_field_name = rec_fex_elem_field_name (rec_fex_get (fex, i));
1061 type = rec_rset_get_field_type (rset, auto_field_name);
1062 if ((!type) ||
1063 ! ((rec_type_kind (type) == REC_TYPE_INT)
1064 || (rec_type_kind (type) == REC_TYPE_RANGE)
1065 #if defined UUID_TYPE
1066 || (rec_type_kind (type) == REC_TYPE_UUID)
1067 #endif
1068 || (rec_type_kind (type) == REC_TYPE_DATE)))
1070 ADD_ERROR (errors,
1071 #if defined UUID_TYPE
1072 _("%s:%s: error: auto-incremented field %s should be of type int, range, uuid or date\n"),
1073 #else
1074 _("%s:%s: error: auto-incremented field %s should be of type int, range or date\n"),
1075 #endif
1076 rec_record_source (descriptor),
1077 rec_record_location_str (descriptor),
1078 auto_field_name);
1079 res++;
1085 rec_mset_iterator_free (&iter);
1088 return res;
1092 rec_int_merge_remote (rec_rset_t rset,
1093 rec_buf_t errors)
1095 int res;
1096 rec_parser_t parser;
1097 rec_record_t descriptor;
1098 rec_db_t remote_db;
1099 rec_rset_t remote_rset;
1100 rec_field_t remote_field;
1101 rec_mset_iterator_t iter;
1102 rec_record_t remote_descriptor;
1103 rec_field_t rec_field;
1104 char *rec_type;
1105 char *rec_url = NULL;
1106 char *rec_file = NULL;
1107 char *rec_source = NULL;
1108 FILE *external_file;
1109 char tmpfile_name[14];
1111 res = 0;
1113 tmpfile_name[0] = '\0';
1115 /* If a remote descriptor is defined in the record descriptor of
1116 RSET, fetch it and merge it with the local descriptor. */
1118 descriptor = rec_rset_descriptor (rset);
1119 if (descriptor)
1121 /* Check if there is an URL in the %rec: field. */
1122 rec_field = rec_record_get_field_by_name (descriptor, FNAME(REC_FIELD_REC), 0);
1124 if (!rec_int_rec_type_p (rec_field_value (rec_field)))
1126 return 0;
1129 rec_type = rec_extract_type (rec_field_value (rec_field));
1130 rec_file = rec_extract_file (rec_field_value (rec_field));
1131 rec_url = rec_extract_url (rec_field_value (rec_field));
1133 if (rec_file || rec_url)
1135 if (rec_url)
1137 #if defined REMOTE_DESCRIPTORS
1138 CURL *curl;
1139 int tmpfile_des;
1141 /* Fetch the remote descriptor. */
1142 curl = curl_easy_init ();
1144 /* Create a temporary file. */
1145 memcpy (tmpfile_name, "recint-XXXXXX", 13);
1146 tmpfile_name[13] = '\0';
1147 tmpfile_des = gen_tempname (tmpfile_name, 0, 0, GT_FILE);
1148 external_file = fdopen (tmpfile_des, "r+");
1150 /* Fetch the remote file. */
1151 curl_easy_setopt (curl, CURLOPT_URL, rec_url);
1152 curl_easy_setopt (curl, CURLOPT_WRITEDATA, external_file);
1153 curl_easy_setopt (curl, CURLOPT_FAILONERROR, 1);
1154 if (curl_easy_perform (curl) != 0)
1156 ADD_ERROR (errors,
1157 _("%s:%s: error: could not fetch remote descriptor from url %s.\n"),
1158 rec_field_source (rec_field), rec_field_location_str (rec_field),
1159 rec_url);
1160 res++;
1161 goto exit;
1163 curl_easy_cleanup (curl);
1164 rec_source = rec_url;
1165 #else
1166 goto exit;
1167 #endif /* REMOTE_DESCRIPTORS */
1169 else
1171 /* Try to open the file. */
1172 external_file = fopen (rec_file, "r");
1173 if (!external_file)
1175 ADD_ERROR (errors,
1176 _("%s:%s: error: could not read external descriptor from file %s.\n"),
1177 rec_field_source (rec_field), rec_field_location_str (rec_field),
1178 rec_file);
1179 res++;
1180 goto exit;
1182 rec_source = rec_file;
1185 /* Parse the contents of the external file. */
1186 fseek (external_file, 0, SEEK_SET);
1187 parser = rec_parser_new (external_file, rec_source);
1188 if (!rec_parse_db (parser, &remote_db))
1190 ADD_ERROR (errors,
1191 _("%s:%s: error: %s does not contain valid rec data.\n"),
1192 rec_field_source (rec_field), rec_field_location_str (rec_field),
1193 rec_source);
1194 res++;
1195 goto exit;
1197 rec_parser_destroy (parser);
1199 /* Get the proper external descriptor and merge it with
1200 the local one. */
1201 remote_rset = rec_db_get_rset_by_type (remote_db, rec_type);
1202 if (!remote_rset)
1204 ADD_ERROR (errors,
1205 _("%s:%s: error: %s does not contain information for type %s.\n"),
1206 rec_field_source (rec_field), rec_field_location_str (rec_field),
1207 rec_source, rec_type);
1208 res++;
1209 goto exit;
1211 remote_descriptor = rec_rset_descriptor (remote_rset);
1212 if (!remote_descriptor)
1214 /* Do nothing. */
1215 goto exit;
1218 iter = rec_mset_iterator (rec_record_mset (remote_descriptor));
1219 while (rec_mset_iterator_next (&iter, MSET_FIELD, (const void**) &remote_field, NULL))
1221 /* Merge the descriptors, but take care to not add a new
1222 %rec: field. */
1224 if (!rec_field_name_equal_p (rec_field_name (remote_field), FNAME(REC_FIELD_REC)))
1226 rec_mset_append (rec_record_mset (descriptor), MSET_FIELD, (void *) rec_field_dup (remote_field), MSET_ANY);
1230 rec_mset_iterator_free (&iter);
1232 /* Update the record descriptor (triggering the creation
1233 of a new type registry). */
1234 rec_rset_set_descriptor (rset, rec_record_dup (descriptor));
1236 rec_db_destroy (remote_db);
1237 fclose (external_file);
1241 exit:
1243 if (rec_url && (tmpfile_name[0] != '\0'))
1245 remove (tmpfile_name);
1248 free (rec_url);
1249 free (rec_file);
1251 return res;
1254 static bool
1255 rec_int_rec_type_p (const char *str)
1257 return rec_match (str,
1258 "^[ \t]*"
1259 REC_RECORD_TYPE_RE
1260 "[ \n\t]*"
1262 "(" REC_URL_REGEXP ")"
1264 "(" REC_FILE_REGEXP ")"
1265 "[ \t]*)?"
1266 "$");
1269 /* End of rec-int.c */