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  * export.c -- Export GEDCOM file from LifeLines database
27  * Copyright(c) 1992-94 by T.T. Wetmore IV; all rights reserved
28  *   3.0.0 - 29 May 94    3.0.2 - 09 Nov 94
29  *===========================================================*/
30 
31 #include "sys_inc.h"
32 #include <time.h>
33 #include "llstdlib.h"
34 #include "btree.h"
35 #include "table.h"
36 #include "translat.h"
37 #include "gedcom.h"
38 #include "liflines.h"
39 #include "llinesi.h"
40 #include "feedback.h"
41 #include "lloptions.h"
42 #include "codesets.h"
43 #include "impfeed.h"
44 #include "xlat.h"
45 
46 /*********************************************
47  * external/imported variables
48  *********************************************/
49 
50 extern BTREE BTR;
51 
52 /*********************************************
53  * local types
54  *********************************************/
55 
56 struct tag_trav_parm {
57 	struct tag_export_feedback * efeed;
58 	FILE * fp;
59 };
60 
61 /*********************************************
62  * local function prototypes
63  *********************************************/
64 
65 /* alphabetical */
66 static BOOLEAN archive(BTREE btree, BLOCK block, void * param);
67 static void copy_and_translate(FILE *fo, INT len, struct tag_trav_parm * travparm, char ctype, XLAT xlat);
68 
69 /*********************************************
70  * local variables
71  *********************************************/
72 
73 static XLAT xlat_gedout; /* TODO: could do away with this via param to traverse */
74 static char *mabbv[] = {
75 	"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
76 	"JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
77 };
78 
79 static INT nindi, nfam, neven, nsour, nothr;
80 
81 
82 /*********************************************
83  * local & exported function definitions
84  * body of module
85  *********************************************/
86 
87 /*===================================================
88  * archive_in_file -- Archive database in GEDCOM file
89  *=================================================*/
90 BOOLEAN
archive_in_file(struct tag_export_feedback * efeed,FILE * fp)91 archive_in_file (struct tag_export_feedback * efeed, FILE *fp)
92 {
93 	char dat[30]="", tim[20]="";
94 	struct tm *pt=0;
95 	time_t curtime;
96 	STRING str=0;
97 	struct tag_trav_parm travparm;
98 	xlat_gedout = transl_get_predefined_xlat(MINGD); /* internal to GEDCOM */
99 
100 	curtime = time(NULL);
101 	pt = localtime(&curtime);
102 	sprintf(dat, "%d %s %d", pt->tm_mday, mabbv[pt->tm_mon],
103 	    1900 + pt->tm_year);
104 	sprintf(tim, "%d:%.2d", pt->tm_hour, pt->tm_min);
105 	fprintf(fp, "0 HEAD\n1 SOUR LIFELINES %s\n1 DEST ANY\n"
106 		, get_lifelines_version(80));
107 	/* header date & time */
108 	fprintf(fp, "1 DATE %s\n2 TIME %s\n", dat, tim);
109 	/* header submitter entry */
110 	str = getlloptstr("HDR_SUBM", "1 SUBM");
111 	fprintf(fp, "%s\n", str);
112 	/* header gedcom version info */
113 	str = getlloptstr("HDR_GEDC", "1 GEDC\n2 VERS 5.5\n2 FORM LINEAGE-LINKED");
114 	fprintf(fp, "%s\n", str);
115 	/* header character set info */
116 	/* should be outcharset; that is what is being used */
117 	str = getlloptstr("HDR_CHAR", 0);
118 	if (str) {
119 		fprintf(fp, "%s\n", str);
120 	} else {
121 		/* xlat_gedout is the actual conversion used, so
122 		we should use the name of its output */
123 		CNSTRING outcharset = xl_get_dest_codeset(xlat_gedout);
124 		fprintf(fp, "1 CHAR %s\n", outcharset);
125 	}
126 	/* finished header */
127 
128 	nindi = nfam = neven = nsour = nothr = 0;
129 	memset(&travparm, 0, sizeof(travparm));
130 	travparm.efeed = efeed;
131 	travparm.fp = fp;
132 	traverse_index_blocks(BTR, bmaster(BTR), &travparm, NULL, archive);
133 	fprintf(fp, "0 TRLR\n");
134 	return TRUE;
135 }
136 /*========================================================
137  * archive -- Traverse function called on each btree block
138  *======================================================*/
139 static BOOLEAN
archive(BTREE btree,BLOCK block,void * param)140 archive (BTREE btree, BLOCK block, void * param)
141 {
142 	INT i, n, l;
143 	char scratch[100];
144 	FILE *fo=0;
145 	struct tag_trav_parm * travparm = (struct tag_trav_parm *)param;
146 
147 	sprintf(scratch, "%s/%s", bbasedir(btree), fkey2path(ixself(block)));
148 	fo = fopen(scratch, LLREADBINARY);
149 	ASSERT(fo);
150 	n = nkeys(block);
151 	for (i = 0; i < n; i++) {
152 		STRING key = rkey2str(rkeys(block, i));
153 		if (*key != 'I' && *key != 'F' && *key != 'E' &&
154 		    *key != 'S' && *key != 'X')
155 			continue;
156 		if (fseek(fo, (long)(offs(block, i) + BUFLEN), 0))
157 			FATAL();
158 		if ((l = lens(block, i)) > 6)	/* filter deleted records */
159 			copy_and_translate(fo, l, travparm, *key, xlat_gedout);
160 	}
161 	fclose(fo);
162 	return TRUE;
163 }
164 /*===================================================
165  * copy_and_translate -- Copy record with translation
166  *=================================================*/
167 static void
copy_and_translate(FILE * fo,INT len,struct tag_trav_parm * travparm,char ctype,XLAT xlat)168 copy_and_translate (FILE *fo, INT len, struct tag_trav_parm * travparm, char ctype, XLAT xlat)
169 {
170 	char in[BUFLEN]="";
171 	char *inp=0;
172 	int remlen=0, num=0;
173 	FILE * fn = travparm->fp;
174 	struct tag_export_feedback * efeed = travparm->efeed;
175 
176 	inp = in;		/* location for next read */
177 	remlen = BUFLEN;	/* max for next read */
178 	while (len > 0) {
179 		BOOLEAN last=FALSE, ok=FALSE;
180 		if(len < remlen) remlen = len;
181 		ASSERT(fread(inp, remlen, 1, fo) == 1);
182 		len -= remlen;
183 		remlen = (inp + remlen) - in;	/* amount in current buffer */
184 		last = (len <= 0);
185 		ok = translate_write(xlat, in, &remlen, fn, last);
186 		ASSERT(ok);
187 		inp = in + remlen;		/* position for next read */
188 		remlen = BUFLEN - remlen;	/* max for next read */
189 	}
190 	num = 0;
191 	switch (ctype) {
192 	case 'I': num = ++nindi; break;
193 	case 'F': num = ++nfam;  break;
194 	case 'E': num = ++neven; break;
195 	case 'S': num = ++nsour; break;
196 	case 'X': num = ++nothr; break;
197 	default: FATAL();
198 	}
199 	if (efeed && efeed->added_rec_fnc)
200 		efeed->added_rec_fnc(ctype, num);
201 }
202