1 /*
2    Copyright (c) 1991-1999 Thomas T. Wetmore IV
3 
4    Permission is hereby granted, free of charge, to any person
5    obtaining a copy of this software and associated documentation
6    files (the "Software"), to deal in the Software without
7    restriction, including without limitation the rights to use, copy,
8    modify, merge, publish, distribute, sublicense, and/or sell copies
9    of the Software, and to permit persons to whom the Software is
10    furnished to do so, subject to the following conditions:
11 
12    The above copyright notice and this permission notice shall be
13    included in all copies or substantial portions of the Software.
14 
15    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19    BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22    SOFTWARE.
23 */
24 /* modified 05 Jan 2000 by Paul B. McBride (pmcbride@tiac.net) */
25 /*=============================================================
26  * gstrings.c -- Routines to creates child strings
27  * Copyright(c) 1992-94 by T.T. Wetmore IV; all rights reserved
28  *   2.3.4 - 24 Jun 93    2.3.5 - 25 Aug 93
29  *   3.0.0 - 02 May 94    3.0.2 - 24 Nov 94
30  *   3.0.3 - 15 Aug 95
31  *===========================================================*/
32 
33 #include "llstdlib.h"
34 #include "table.h"
35 #include "translat.h"
36 #include "gedcom.h"
37 #include "lloptions.h"
38 
39 /*********************************************
40  * external/imported variables
41  *********************************************/
42 
43 extern STRING qSdspa_mar,qSdspa_bir,qSdspa_chr,qSdspa_dea,qSdspa_bur;
44 extern STRING qSunksps;
45 
46 /*********************************************
47  * local variables
48  *********************************************/
49 
50 static INT nchil = 0, maxchil = 0;
51 static STRING *chstrings = NULL, *chkeys = NULL;
52 
53 static BOOLEAN displaykeys=TRUE;
54 
55 /*********************************************
56  * local function definitions
57  * body of module
58  *********************************************/
59 
60 /*===================================================================
61  * get_child_strings -- Return children strings; each string has name
62  *   and event info, if avail
63  *  fam:   [in] family of interest
64  *  rfmt:  [in] reformatting functions
65  *  pnum:  [out] number of output strings
66  *  pkeys: [out] array of output strings (children descriptions)
67  *=================================================================*/
68 STRING *
get_child_strings(NODE fam,RFMT rfmt,INT * pnum,STRING ** pkeys)69 get_child_strings (NODE fam, RFMT rfmt, INT *pnum, STRING **pkeys)
70 {
71 	NODE chil;
72 	INT i;
73 
74 	for (i = 0; i < nchil; i++) {
75 		stdfree(chstrings[i]);
76 		stdfree(chkeys[i]);
77 	}
78 	nchil = *pnum = 0;
79 	if (!fam || !(chil = CHIL(fam))) return NULL;
80 	nchil = length_nodes(chil);
81 	if (nchil == 0) return NULL;
82 	if (nchil > (maxchil - 1)) {
83 		if (maxchil) {
84 			stdfree(chstrings);
85 			stdfree(chkeys);
86 		}
87 		chstrings = (STRING *) stdalloc((nchil+5)*sizeof(STRING));
88 		chkeys = (STRING *) stdalloc((nchil+5)*sizeof(STRING));
89 		maxchil = nchil + 5;
90 	}
91 	FORCHILDRENx(fam,child,i)
92 		chstrings[i-1] = indi_to_list_string(child, NULL, 66, rfmt, TRUE);
93 		chkeys[i-1] = strsave(rmvat(nxref(child)));
94 	ENDCHILDRENx
95 	*pnum = nchil;
96 	*pkeys = chkeys;
97 	return chstrings;
98 }
99 /*================================================
100  * indi_to_list_string -- Return menu list string.
101  *  returns heap-alloc'd string
102  *  indi:   [IN]  source person
103  *  fam:    [IN]  relevant family (used in spouse lists)
104  *  len:    [IN]  max length desired
105  *  rfmt:   [IN]  reformating functions (may be NULL)
106  *  appkey: [IN]  allow appending key ?
107  *==============================================*/
108 STRING
indi_to_list_string(NODE indi,NODE fam,INT len,RFMT rfmt,BOOLEAN appkey)109 indi_to_list_string (NODE indi, NODE fam, INT len, RFMT rfmt, BOOLEAN appkey)
110 {
111 	char scratch[MAXLINELEN];
112 	STRING name, evt = NULL, p = scratch;
113 	int hasparents;
114 	int hasfamily;
115 	if (len>(INT)sizeof(scratch))
116 		len = sizeof(scratch);
117 	if (indi) {
118 		ASSERT(name = indi_to_name(indi, len));
119 	} else
120 		name = _(qSunksps);
121 	sprintf(p, "%s", name);
122 	/* TODO: Shouldn't we len -= strlen(p) first ? Perry, 2007-09-29 */
123 	p += strlen(p);
124 	if (fam)  evt = fam_to_event(fam, "MARR", _(qSdspa_mar), len, rfmt);
125 	if (!evt) evt = indi_to_event(indi, "BIRT", _(qSdspa_bir), len, rfmt);
126 	if (!evt) evt = indi_to_event(indi, "CHR", _(qSdspa_chr), len, rfmt);
127 	if (!evt) evt = indi_to_event(indi, "DEAT", _(qSdspa_dea), len, rfmt);
128 	if (!evt) evt = indi_to_event(indi, "BURI", _(qSdspa_bur), len, rfmt);
129 	if (evt) {
130 		sprintf(p, ", %s", evt);
131 		p += strlen(p);
132 	}
133 	if (appkey && indi && displaykeys) {
134 		if (getlloptint("DisplayKeyTags", 0) > 0) {
135 			sprintf(p, " (i%s)", key_of_record(indi));
136 		} else {
137 			sprintf(p, " (%s)", key_of_record(indi));
138 		}
139 		p += strlen(p);
140 	}
141 	if (appkey && fam && displaykeys) {
142 		if (getlloptint("DisplayKeyTags", 0) > 0) {
143 			sprintf(p, " (f%s)", key_of_record(fam));
144 		} else {
145 			sprintf(p, " (%s)", key_of_record(fam));
146 		}
147 		p += strlen(p);
148 	}
149 	if(indi) {
150 	    if(FAMC(indi)) hasparents = 1;
151 	    else hasparents = 0;
152 	    if(FAMS(indi)) hasfamily = 1;
153 	    else hasfamily = 0;
154 	    if(hasfamily || hasparents) {
155 		*p++ = ' ';
156 		*p++ = '[';
157 		if(hasparents) *p++ = 'P';
158 		if(hasfamily) *p++ = 'S';
159 		*p++ = ']';
160 		*p = '\0';
161 	    }
162 	}
163 	limit_width(scratch, len, uu8);
164 	return strsave(scratch);
165 }
166 /*================================================
167  * sour_to_list_string -- Return menu list string.
168  * Created: 2000/11/29, Perry Rapp
169  *==============================================*/
170 STRING
sour_to_list_string(NODE sour,INT len,STRING delim)171 sour_to_list_string (NODE sour, INT len, STRING delim)
172 {
173 	char scratch[1024];
174 	STRING name, p=scratch;
175 	INT mylen=len;
176 	if (mylen>(INT)sizeof(scratch))
177 		mylen=sizeof(scratch);
178 	p[0]=0;
179 	llstrcatn(&p, "(S", &mylen);
180 	llstrcatn(&p, rmvat(nxref(sour))+1, &mylen);
181 	llstrcatn(&p, ") ", &mylen);
182 	name = node_to_tag(sour, "REFN", len);
183 	if (name)
184 		llstrcatn(&p, name, &mylen);
185 	name = node_to_tag(sour, "TITL", len);
186 	if (name && mylen > 20)
187 	{
188 		llstrcatn(&p, delim, &mylen);
189 		llstrcatn(&p, name, &mylen);
190 	}
191 	name = node_to_tag(sour, "AUTH", len);
192 	if (name && mylen > 20)
193 	{
194 		llstrcatn(&p, delim, &mylen);
195 		llstrcatn(&p, name, &mylen);
196 	}
197 	limit_width(scratch, len, uu8);
198 	return strsave(scratch);
199 }
200 /*================================================
201  * even_to_list_string -- Return menu list string.
202  * Created: 2001/12/16, Perry Rapp
203  *==============================================*/
204 STRING
even_to_list_string(NODE even,INT len,STRING delim)205 even_to_list_string (NODE even, INT len, STRING delim)
206 {
207 	char scratch[1024];
208 	STRING name, p=scratch;
209 	INT mylen=len;
210 	delim=delim; /* unused */
211 	if (mylen>(INT)sizeof(scratch))
212 		mylen=sizeof(scratch);
213 	p[0]=0;
214 	llstrcatn(&p, "(E", &mylen);
215 	llstrcatn(&p, rmvat(nxref(even))+1, &mylen);
216 	llstrcatn(&p, ") ", &mylen);
217 	name = node_to_tag(even, "NAME", len);
218 	if (name)
219 		llstrcatn(&p, name, &mylen);
220         name = node_to_tag(even, "REFN", len);
221         if (name) {
222 		llstrcatn(&p, " (", &mylen);
223                 llstrcatn(&p, name, &mylen);
224 		llstrcatn(&p, ")", &mylen);
225 	}
226 	limit_width(scratch, len, uu8);
227 	return strsave(scratch);
228 }
229 /*================================================
230  * fam_to_list_string -- Return menu list string.
231  * Created: 2001/02/17, Perry Rapp
232  *==============================================*/
233 STRING
fam_to_list_string(NODE fam,INT len,STRING delim)234 fam_to_list_string (NODE fam, INT len, STRING delim)
235 {
236 	char scratch[1024];
237 	STRING name, p=scratch;
238 	STRING tempname;
239 	INT mylen=len;
240 	char counts[32];
241 	INT husbands=0, wives=0, children=0;
242 	INT templen=0;
243 	NODE refn, husb, wife, chil, rest, node;
244 	if (mylen>(INT)sizeof(scratch))
245 		mylen=sizeof(scratch);
246 	p[0]=0;
247 	llstrcatn(&p, "(F", &mylen);
248 	llstrcatn(&p, rmvat(nxref(fam))+1, &mylen);
249 	llstrcatn(&p, ")", &mylen);
250 	name = node_to_tag(fam, "REFN", len);
251 	if (name) {
252 		llstrcatn(&p, " ", &mylen);
253 		llstrcatn(&p, name, &mylen);
254 	}
255 	split_fam(fam, &refn, &husb, &wife, &chil, &rest);
256 	for (node=husb; node; node=nsibling(node))
257 		husbands++;
258 	for (node=wife; node; node=nsibling(node))
259 		wives++;
260 	for (node=chil; node; node=nsibling(node))
261 		children++;
262 	sprintf(counts, "%ldh,%ldw,%ldch", husbands, wives, children);
263 	llstrcatn(&p, " ", &mylen);
264 	llstrcatn(&p, counts, &mylen);
265 	if (husbands) {
266 		node = qkey_to_indi(rmvat(nval(husb)));
267 		if (node) {
268 			llstrcatn(&p, delim, &mylen);
269 			if (wives)
270 				templen = (mylen-4)/2;
271 			else
272 				templen = mylen;
273 			tempname = indi_to_name(node, templen);
274 			limit_width(tempname, templen, uu8);
275 			llstrcatn(&p, tempname, &mylen);
276 			if (wives)
277 				llstrcatn(&p, " m. ", &mylen);
278 		}
279 	}
280 	if (wives) {
281 		node = qkey_to_indi(rmvat(nval(wife)));
282 		if (node) {
283 			if (!templen)
284 				templen = mylen;
285 			/* othewise we set templen above */
286 			llstrcatn(&p, indi_to_name(node, templen), &mylen);
287 		}
288 	}
289 	join_fam(fam, refn, husb, wife, chil, rest);
290 	/* TO DO - print a husband and a wife out */
291 	limit_width(scratch, len, uu8);
292 	return strsave(scratch);
293 }
294 /*================================================
295  * other_to_list_string -- Return menu list string.
296  * Created: 2000/11/29, Perry Rapp
297  *==============================================*/
298 STRING
other_to_list_string(NODE node,INT len,STRING delim)299 other_to_list_string(NODE node, INT len, STRING delim)
300 {
301 	char scratch[1024];
302 	STRING name, p=scratch;
303 	INT mylen=len;
304 	NODE child;
305 	delim=delim; /* unused */
306 	if (mylen>(INT)sizeof(scratch))
307 		mylen=sizeof(scratch);
308 	p[0]=0;
309 	llstrcatn(&p, "(X", &mylen);
310 	llstrcatn(&p, rmvat(nxref(node))+1, &mylen);
311 	llstrcatn(&p, ") (", &mylen);
312 	llstrcatn(&p, ntag(node), &mylen);
313 	llstrcatn(&p, ") ", &mylen);
314 	name = node_to_tag(node, "REFN", mylen);
315 	if (name)
316 		llstrcatn(&p, name, &mylen);
317 	if (nval(node)) {
318 		llstrcatn(&p, nval(node), &mylen);
319 	}
320 	/* append any CONC/CONT nodes that fit */
321 	child = nchild(node);
322 	while (mylen>5 && child) {
323 		if (!strcmp(ntag(child), "CONC")
324 			|| !strcmp(ntag(child), "CONT")) {
325 			/* skip empty CONC/CONT nodes */
326 			if (nval(child)) {
327 				llstrcatn(&p, " ", &mylen);
328 				llstrcatn(&p, nval(child), &mylen);
329 			}
330 		} else {
331 			break;
332 		}
333 		if (nchild(child))
334 			break;
335 		else if (nsibling(child))
336 			child = nsibling(child);
337 		else
338 			break;
339 	}
340 	limit_width(scratch, len, uu8);
341 	return strsave(scratch);
342 }
343 /*===========================================
344  * generic_to_list_string -- Format a print line from
345  *  a top-level node of any type
346  * Caller may specify either node or key (& leave other NULL)
347  *  returns heap-alloc'd string
348  * Caller must specify either node or key (or both)
349  * Used in lists and in extended gedcom view
350  * Created: 2001/02/12, Perry Rapp
351  *  node:   [IN]  node tree of indi or fam ... to be described
352  *  key:    [IN]  key of record specified by node
353  *  len:    [IN]  max description desired
354  *  delim:  [IN]  separator to use between events
355  *  rfmt:   [IN]  reformatting information
356  *  appkey: [IN]  allow appending key ?
357  *=========================================*/
358 STRING
generic_to_list_string(NODE node,STRING key,INT len,STRING delim,RFMT rfmt,BOOLEAN appkey)359 generic_to_list_string (NODE node, STRING key, INT len, STRING delim, RFMT rfmt, BOOLEAN appkey)
360 {
361 	STRING str;
362 	str=NULL; /* set to appropriate format */
363 	if (!node && key)
364 		node = qkey_to_type(key);
365 	if (!key && node)
366 		key = rmvat(nxref(node));
367 	if (node) {
368 		switch (key[0])
369 		{
370 		case 'I':
371 			str = indi_to_list_string(node, NULL, len, rfmt, appkey);
372 			break;
373 		case 'S':
374 			str = sour_to_list_string(node, len, delim);
375 			break;
376 		case 'F':
377 			str = fam_to_list_string(node, len, delim);
378 			break;
379 		case 'E':
380 			str = even_to_list_string(node, len, delim);
381 			break;
382 		case 'X':
383 			str = other_to_list_string(node, len, delim);
384 			break;
385 		}
386 	}
387 	if (!str) {
388 		if (key)
389 			str = strsave(key);
390 		else
391 			str = strsave("??");
392 	}
393 	return str;
394 }
395 /*=======================================================
396  * set_displaykeys -- Enable/disable keys in list strings
397  *  That is, whether or not to show key numbers in items
398  * Created: 2001/01/01, Perry Rapp
399  *=====================================================*/
400 void
set_displaykeys(BOOLEAN keyflag)401 set_displaykeys (BOOLEAN keyflag)
402 {
403 	displaykeys = keyflag;
404 }
405