Copied from old documentation. Removed all Gedcom_val details.
[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 "buffer.h"
31 #include "age.h"
32
33 struct age_value age_s;
34 struct age_value def_age_val;
35
36 void cleanup_age_buffer();
37 struct safe_buffer age_buffer = { NULL, 0, NULL, 0, cleanup_age_buffer };
38
39 void cleanup_age_buffer()
40 {
41   cleanup_buffer(&age_buffer);
42 }
43
44 void copy_age(struct age_value *to, struct age_value from)
45 {
46   memcpy(to, &from, sizeof(struct age_value));
47 }
48
49 void init_age(struct age_value *age)
50 {
51   age->type = AGE_UNRECOGNIZED;
52   age->mod  = AGE_NO_MODIFIER;
53   age->years = -1;
54   age->months = -1;
55   age->days = -1;
56 }
57
58 int parse_numeric_age(struct age_value *age, const char *ptr)
59 {
60   char *endptr;
61   while (ptr) {
62     long int number = strtol(ptr, &endptr, 10);
63     if (errno == ERANGE || number < 0 || number > INT_MAX) {
64       gedcom_error(_("Number out of range in age"));
65       return 1;
66     }
67     else {
68       ptr = endptr;
69       if (*ptr == '\0')
70         break;
71       else if (*ptr == 'Y' || *ptr == 'y') {
72         if (age->years == -1)
73           age->years = number;
74         else {
75           gedcom_error(_("Duplicate year indication in age"));
76           return 1;
77         }
78       }
79       else if (*ptr == 'M' || *ptr == 'm') {
80         if (age->months == -1)
81           age->months = number;
82         else {
83           gedcom_error(_("Duplicate month indication in age"));
84           return 1;
85         }
86       }
87       else if (*ptr == 'D' || *ptr == 'd') {
88         if (age->days == -1)
89           age->days = number;
90         else {
91           gedcom_error(_("Duplicate day indication in age"));
92           return 1;
93         }
94       }
95       else {
96         gedcom_error(_("Unrecognized indication in age: '%s'"), ptr);
97         return 1;
98       }
99       ptr++;
100       while (*ptr == ' ') ptr++;
101     }
102   }
103   return 0;
104 }
105
106 struct age_value* gedcom_new_age_value(const struct age_value* copy_from)
107 {
108   struct age_value* age_ptr;
109   age_ptr = (struct age_value*) malloc(sizeof(struct age_value));
110   if (! age_ptr)
111     MEMORY_ERROR;
112   else {
113     if (copy_from)
114       memcpy(age_ptr, copy_from, sizeof(struct age_value));
115     else 
116       init_age(age_ptr);
117   }
118   return age_ptr;
119 }
120
121 struct age_value gedcom_parse_age(const char* line_value)
122 {
123   const char *ptr = line_value;
124   init_age(&age_s);
125   init_age(&def_age_val);
126
127   if (*ptr == '<') {
128     age_s.mod = AGE_LESS_THAN;
129     ptr++;
130     while (*ptr == ' ') ptr++;
131   }
132   else if (*ptr == '>') {
133     age_s.mod = AGE_GREATER_THAN;
134     ptr++;
135     while (*ptr == ' ') ptr++;
136   }
137
138   if (isdigit((unsigned char)*ptr)) {
139     int result = parse_numeric_age(&age_s, ptr);
140     if (result == 0) {
141       age_s.type = AGE_NUMERIC;
142     }
143   }
144   else if (!strcasecmp(line_value, "CHILD"))
145     age_s.type = AGE_CHILD;
146   else if (!strcasecmp(line_value, "INFANT"))
147     age_s.type = AGE_INFANT;
148   else if (!strcasecmp(line_value, "STILLBORN"))
149     age_s.type = AGE_STILLBORN;
150   else
151     gedcom_error(_("Unrecognized age format"));
152   if (age_s.type == AGE_UNRECOGNIZED)
153     strncpy(age_s.phrase, line_value, MAX_PHRASE_LEN + 1);
154   return age_s;
155 }
156
157 char* gedcom_age_to_string(const struct age_value* val)
158 {
159   int num = 0;
160   reset_buffer(&age_buffer);
161
162   switch (val->mod) {
163     case AGE_LESS_THAN:
164       safe_buf_append(&age_buffer, "<"); break;
165     case AGE_GREATER_THAN:
166       safe_buf_append(&age_buffer, ">"); break;
167     default:
168       break;
169   }
170
171   switch (val->type) {
172     case AGE_UNRECOGNIZED:
173       reset_buffer(&age_buffer);
174       safe_buf_append(&age_buffer, val->phrase); break;
175     case AGE_CHILD:
176       safe_buf_append(&age_buffer, "CHILD"); break;
177     case AGE_INFANT:
178       safe_buf_append(&age_buffer, "INFANT"); break;
179     case AGE_STILLBORN:
180       safe_buf_append(&age_buffer, "STILLBORN"); break;
181     case AGE_NUMERIC:
182       if (val->years != -1) {
183         num = 1;
184         safe_buf_append(&age_buffer, "%dy", val->years);
185       }
186       if (val->months != -1) {
187         if (num)
188           safe_buf_append(&age_buffer, " ");
189         num = 1;
190         safe_buf_append(&age_buffer, "%dm", val->months);
191       }
192       if (val->days != -1) {
193         if (num)
194           safe_buf_append(&age_buffer, " ");
195         num = 1;
196         safe_buf_append(&age_buffer, "%dd", val->days);
197       }
198       break;
199     default:
200       break;
201   }
202   
203   return get_buf_string(&age_buffer);
204 }