New files for parsing age values.
[gedcom-parse.git] / gedcom / age.c
1 /* Age manipulation routines.
2    Copyright (C) 2001,2002 The Genes Development Team
3    This file is part of the Gedcom parser library.
4    Contributed by Peter Verthez <Peter.Verthez@advalvas.be>, 2001.
5
6    The Gedcom parser library is free software; you can redistribute it
7    and/or modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The Gedcom parser library is distributed in the hope that it will be
12    useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the Gedcom parser library; if not, write to the
18    Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 /* $Id$ */
22 /* $Name$ */
23
24 #include <ctype.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <limits.h>
29 #include "gedcom_internal.h"
30 #include "age.h"
31
32 struct age_value age_s;
33 struct age_value def_age_val;
34
35 void copy_age(struct age_value *to, struct age_value from)
36 {
37   memcpy(to, &from, sizeof(struct age_value));
38 }
39
40 void init_age(struct age_value *age)
41 {
42   age->type = AGE_UNRECOGNIZED;
43   age->mod  = AGE_NO_MODIFIER;
44   age->years = -1;
45   age->months = -1;
46   age->days = -1;
47 }
48
49 int parse_numeric_age(struct age_value *age, char *ptr)
50 {
51   char *endptr;
52   while (ptr) {
53     long int number = strtol(ptr, &endptr, 10);
54     if (errno == ERANGE || number < 0 || number > INT_MAX) {
55       gedcom_error(_("Number out of range in age"));
56       return 1;
57     }
58     else {
59       ptr = endptr;
60       if (*ptr == '\0')
61         break;
62       else if (*ptr == 'Y' || *ptr == 'y') {
63         if (age->years == -1)
64           age->years = number;
65         else {
66           gedcom_error(_("Duplicate year indication in age"));
67           return 1;
68         }
69       }
70       else if (*ptr == 'M' || *ptr == 'm') {
71         if (age->months == -1)
72           age->months = number;
73         else {
74           gedcom_error(_("Duplicate month indication in age"));
75           return 1;
76         }
77       }
78       else if (*ptr == 'D' || *ptr == 'd') {
79         if (age->days == -1)
80           age->days = number;
81         else {
82           gedcom_error(_("Duplicate day indication in age"));
83           return 1;
84         }
85       }
86       else {
87         gedcom_error(_("Unrecognized indication in age: '%s'"), ptr);
88         return 1;
89       }
90       ptr++;
91       while (*ptr == ' ') ptr++;
92     }
93   }
94   return 0;
95 }
96
97 struct age_value gedcom_parse_age(char* line_value)
98 {
99   char *ptr = line_value;
100   init_age(&age_s);
101   init_age(&def_age_val);
102
103   if (*ptr == '<') {
104     age_s.mod = AGE_LESS_THAN;
105     ptr++;
106     while (*ptr == ' ') ptr++;
107   }
108   else if (*ptr == '>') {
109     age_s.mod = AGE_GREATER_THAN;
110     ptr++;
111     while (*ptr == ' ') ptr++;
112   }
113
114   if (isdigit(*ptr)) {
115     int result = parse_numeric_age(&age_s, ptr);
116     if (result == 0) {
117       age_s.type = AGE_NUMERIC;
118     }
119   }
120   else if (!strcasecmp(line_value, "CHILD"))
121     age_s.type = AGE_CHILD;
122   else if (!strcasecmp(line_value, "INFANT"))
123     age_s.type = AGE_INFANT;
124   else if (!strcasecmp(line_value, "STILLBORN"))
125     age_s.type = AGE_STILLBORN;
126   else
127     gedcom_error(_("Unrecognized age format"));
128   if (age_s.type == AGE_UNRECOGNIZED)
129     strncpy(age_s.phrase, line_value, MAX_PHRASE_LEN + 1);
130   return age_s;
131 }
132