1 /* xmlhandler.c: functions to write bibliography style sets to a database */
2 /* markus@mhoenicka.de 12-29-00 */
3 /* $Id: xmlhandler.c,v 1.22.2.25 2006/02/22 21:02:45 mhoenicka Exp $ */
4 
5 /*
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 
20   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
21 
22 /* ToDo: figure out a way to handle out of memory situations properly while parsing a style set. It is not yet proven that the current implementation frees all memory that has been allocated prior to the memory error */
23 
24 /* Overview */
25 /* This set of functions parses a XML file containing bibliography style sets according to the CiteStyle DTD. We use expat as a non-validating XML parser. We register three handlers for start tags, character data, and end tags. The elements are pushed on a stack in the start tags handler. Each structure defining an element contains a start element of another stack for the attributes of this element. These stacks are used in the character data handler and the end tag handler to retrieve parent and ancestor elements and attributes of the current element where necessary. The attribute stack of the current element is freed in the end tag handler and the current element is popped off the stack as well. */
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <expat.h> /* header of the XML parser */
31 #include <syslog.h> /* priority levels of log messages */
32 #include <dbi/dbi.h>
33 
34 #include "backend.h"
35 #include "linklist.h"
36 #include "refdb.h"
37 #include "refdbd.h" /* depends on backend.h */
38 #include "xmlhandler.h"
39 #include "strfncs.h"
40 #include "connect.h"
41 #include "dbfncs.h"
42 
43 #ifndef HAVE_ATOLL
44 long long atoll(const char *str);
45 #endif
46 
47 #ifndef HAVE_STRTOLL
48 long long strtoll(const char *nptr, char **endptr, int base);
49 #endif
50 
51 extern int n_log_level;
52 extern char main_db[];
53 
54 /* forward declarations of local functions */
55 static char* concat_elnames(struct elstack* ptr_current_element, char* exclude_name, char* concat);
56 static char* get_ancestor_attr(struct elstack* ptr_current_element, char* ancestor_name, char* ancestor_attribute);
57 static int set_alternatetext(dbi_result dbires, char** ptr_aempty);
58 
59 
60 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
61   start_handler(): handler for start tags (handling citestyle data)
62 
63   void start_handler has no return value
64 
65   void* ptr_data this is a ptr to "non-global" global data that all
66              handlers share - will be cast to type struct addstyle_data*
67 
68   const char *el ptr to a string containing the element name
69 
70   const char** ptr_attr ptr to an array of attributes (name-value pairs)
71 
72   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
start_handler(void * ptr_data,const char * el,const char ** ptr_attr)73 void start_handler(void *ptr_data, const char *el, const char **ptr_attr) {
74   int i;
75   char sql_command[256];
76   const char *drivername; /* name of the libdbi driver */
77   struct elstack* ptr_el_new;
78   struct attrlist* ptr_attr_new;
79   struct addstyle_data* ptr_asdata;
80   dbi_result dbires;
81 
82 /*    printf("el:attr0:attr1:%s:%s:%s<<\n", el, attr[0], attr[1]);  */
83 
84   ptr_asdata = (struct addstyle_data*)ptr_data;
85 
86   drivername = dbi_driver_get_name(dbi_conn_get_driver(ptr_asdata->conn));
87 
88   if (strcmp(el, "STYLESET") == 0) {
89     (*(ptr_asdata->ptr_depth_adjust))++;
90   }
91   else if (!*(ptr_asdata->ptr_ndb_error) && !*(ptr_asdata->ptr_nmem_error)) {
92     if (strcmp(el, "CITESTYLE") == 0) {
93       /* create new entry in database */
94       dbires = dbi_conn_query(ptr_asdata->conn, "INSERT INTO CITSTYLE (JOURNAL) VALUES (\'DUMMY\')");
95       LOG_PRINT(LOG_DEBUG, "INSERT INTO CITSTYLE (JOURNAL) VALUES (\'DUMMY\')");
96       if (!dbires) {
97 	(*(ptr_asdata->ptr_ndb_error))++;
98 	LOG_PRINT(LOG_WARNING, "error in sql command");
99 	return;
100       }
101       else {
102 	if (!strcmp(my_dbi_conn_get_cap(ptr_asdata->conn, "named_seq"), "f")) {
103 	  *(ptr_asdata->ptr_citstyle_id) = dbi_conn_sequence_last(ptr_asdata->conn, NULL);
104 	}
105 	else {
106 	  *(ptr_asdata->ptr_citstyle_id) = dbi_conn_sequence_last(ptr_asdata->conn, "citstyle_id_seq");
107 	}
108 	dbi_result_free(dbires);
109       }
110     }
111     else if (strcmp(el, "PUBTYPE") == 0 ||
112 	     strcmp(el, "INTEXTDEF") == 0 ||
113 	     strcmp(el, "AUTHORONLY") == 0 ||
114 	     strcmp(el, "YEARONLY") == 0) {
115       /* reset counter */
116       *(ptr_asdata->ptr_position) = 0;
117       sprintf(sql_command, "INSERT INTO REFSTYLE (CITSTYLEID, PUBTYPE) VALUES (%u"", '", *(ptr_asdata->ptr_citstyle_id));
118 
119       if (strcmp(el, "PUBTYPE") == 0) {
120 	/* create new entry in database. PUBTYPE has only one attribute TYPE, the value of which is therefore in attr[1], if at all */
121 	/* NB ptr_attr == NULL is not permitted by the DTD but
122 	   we better check */
123 	if (ptr_attr && ptr_attr[1] && *(ptr_attr[1])) {
124 	  strcat(sql_command, ptr_attr[1]);
125 	}
126 	else {
127 	  strcat(sql_command, "GEN"); /* default as per DTD */
128 	}
129       }
130       else if (strcmp(el, "INTEXTDEF") == 0) {
131 	/* create new entry in database. INTEXTDEF is treated like a PUBTYPE element with the attribute INTEXT */
132 	strcat(sql_command, "INTEXT");
133       }
134       else if (strcmp(el, "AUTHORONLY") == 0) {
135 	/* create new entry in database. AUTHORONLY is treated like a PUBTYPE element with the attribute AUTHORONLY */
136 	strcat(sql_command, "AUTHORONLY");
137       }
138       else { /* yearonly */
139 	/* create new entry in database. YEARONLY is treated like a PUBTYPE element with the attribute YEARONLY */
140 	strcat(sql_command, "YEARONLY");
141       }
142       strcat(sql_command, "\')");
143       /*      printf("%s\n", sql_command); */
144       dbires = dbi_conn_query(ptr_asdata->conn, sql_command);
145       LOG_PRINT(LOG_DEBUG, sql_command);
146       if (!dbires) {
147 	(*(ptr_asdata->ptr_ndb_error))++;
148 	LOG_PRINT(LOG_WARNING, "error in sql command");
149       }
150       else {
151 	if (!strcmp(my_dbi_conn_get_cap(ptr_asdata->conn, "named_seq"), "f")) {
152 	  *(ptr_asdata->ptr_refstyle_id) = dbi_conn_sequence_last(ptr_asdata->conn, NULL);
153 	}
154 	else {
155 	  *(ptr_asdata->ptr_refstyle_id) = dbi_conn_sequence_last(ptr_asdata->conn, "refstyle_id_seq");
156 	}
157 	dbi_result_free(dbires);
158       }
159     }
160     else if (strcmp(el, "SEPARATOR") == 0) {
161       sprintf(sql_command, "INSERT INTO SEPARATORS (VALUE) VALUES ('Dummy')");
162 
163       dbires = dbi_conn_query(ptr_asdata->conn, sql_command);
164       LOG_PRINT(LOG_DEBUG, sql_command);
165       if (!dbires) {
166 	(*(ptr_asdata->ptr_ndb_error))++;
167 	LOG_PRINT(LOG_WARNING, "error in sql command");
168       }
169       else {
170 	if (!strcmp(my_dbi_conn_get_cap(ptr_asdata->conn, "named_seq"), "f")) {
171 	  *(ptr_asdata->ptr_separator_id) = dbi_conn_sequence_last(ptr_asdata->conn, NULL);
172 	}
173 	else {
174 	  *(ptr_asdata->ptr_separator_id) = dbi_conn_sequence_last(ptr_asdata->conn, "separators_id_seq");
175 	}
176 	dbi_result_free(dbires);
177       }
178     }
179   }
180   /*    printf("add to stack\n"); */
181   /* add current element to element stack */
182   ptr_el_new = malloc(sizeof(struct elstack));
183   if (ptr_el_new == NULL) {
184     (*(ptr_asdata->ptr_nmem_error))++;
185   }
186   else {
187     /*    printf("have memory\n"); */
188     strncpy(ptr_el_new->elname, el, 63);
189     ptr_el_new->elname[63] = '\0'; /* terminate just in case */
190     ptr_el_new->n_elvalue_len = ELVALUE_LENGTH;
191     ptr_el_new->ptr_elvalue = malloc(ELVALUE_LENGTH);
192     if (ptr_el_new->ptr_elvalue == NULL) {
193       (*(ptr_asdata->ptr_nmem_error))++;
194     }
195     else {
196       *(ptr_el_new->ptr_elvalue) = '\0';
197     }
198     ptr_el_new->ptr_next = ptr_asdata->ptr_first;
199     ptr_el_new->ptr_attr_first = NULL;
200     ptr_asdata->ptr_first = ptr_el_new;
201     /*    printf("%s", ptr_first->elname); */
202 
203     /* add current attributes to the element */
204     /*    printf("add attributes\n"); */
205     for (i = 0; ptr_attr[i]; i += 2) {
206       ptr_attr_new = malloc(sizeof(struct attrlist));
207       if (ptr_attr_new == NULL) {
208 	(*(ptr_asdata->ptr_nmem_error))++;
209 	break;
210       }
211       strncpy(ptr_attr_new->attribute_name, ptr_attr[i], 63);
212       ptr_attr_new->attribute_name[63] = '\0';
213       strncpy(ptr_attr_new->attribute_value, ptr_attr[i+1], 63);
214       ptr_attr_new->attribute_value[63] = '\0';
215       ptr_attr_new->ptr_next = (ptr_asdata->ptr_first)->ptr_attr_first;
216       (ptr_asdata->ptr_first)->ptr_attr_first = ptr_attr_new;
217 /*        printf(" %s='%s'", attr[i], attr[i + 1]); */
218     }
219     /*    printf("done adding attributes\n"); */
220     (*(ptr_asdata->ptr_depth))++;
221   }
222 }  /* End of start_handler */
223 
224 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
225   end_handler(): handler for end tags (handling citestyle data)
226 
227   void end_handler has no return value
228 
229   void* ptr_data this is a ptr to "non-global" global data that all
230              handlers share - will be cast to type struct addstyle_data*
231 
232   const char *el ptr to a string containing the element name
233 
234   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
end_handler(void * ptr_data,const char * el)235 void end_handler(void *ptr_data, const char *el) {
236   int n_chardata = 0;
237   int n_attrdata = 0;
238   int ignore_role = 0;
239   unsigned int current_id = 0;
240   unsigned int n_id;
241   char column_name[65];
242   char table_name[65];
243   char column_name_attribute[65];
244   char pubtype[32];
245   char sql_command[512];
246   char concat[65];
247   char* ptr_attr = NULL;
248   char* new_msg;
249   struct elstack* ptr_el_remove;
250   struct attrlist* ptr_attr_remove;
251   struct addstyle_data* ptr_asdata;
252   dbi_result dbires;
253 
254   ptr_asdata = (struct addstyle_data*)ptr_data;
255 
256   (*(ptr_asdata->ptr_depth))--;
257   pubtype[0] = '\0';
258   column_name[0] = '\0';
259   table_name[0] = '\0';
260 
261   if (!*(ptr_asdata->ptr_ndb_error) && !*(ptr_asdata->ptr_nmem_error)) {
262 /*    printf("start of end tag handler:%s depth: %d depth_adjust: %d\n", el, *(ptr_asdata->ptr_depth), *(ptr_asdata->ptr_depth_adjust));  */
263 
264     /* we have to update POSXY for these elements */
265     if (strcmp((ptr_asdata->ptr_first)->elname, "SEPARATOR") == 0) {
266       /* encode the id of the separator in the value of the POSXY field */
267       sprintf(sql_command, "INSERT INTO POSITIONS (POS,TYPE,SEPARATORID,REFSTYLEID) VALUES (%d,'SEPARATOR',%u,%u)", *(ptr_asdata->ptr_position), *(ptr_asdata->ptr_separator_id), *(ptr_asdata->ptr_refstyle_id));
268 
269       dbires = dbi_conn_query(ptr_asdata->conn, sql_command);
270       LOG_PRINT(LOG_DEBUG, sql_command);
271       if (!dbires) {
272 	(*(ptr_asdata->ptr_ndb_error))++;
273 	LOG_PRINT(LOG_WARNING, "error in sql command");
274       }
275       else {
276 	/* increment position */
277 	(*(ptr_asdata->ptr_position))++;
278 	dbi_result_free(dbires);
279       }
280     }
281 
282 
283     /* simple elements in REFTYPE, INTEXTDEF, AUTHORONLY, or YEARONLY */
284     else if (strcmp((ptr_asdata->ptr_first)->elname, "REFNUMBER") == 0
285 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "CITEKEY") == 0
286 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "JOURNALNAME") == 0
287 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "VOLUME") == 0
288 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "ISSUE") == 0
289 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "PAGES") == 0
290 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "PUBLISHER") == 0
291 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "PUBPLACE") == 0
292 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "SERIAL") == 0
293 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "ADDRESS") == 0
294 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "NOTES") == 0
295 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "ABSTRACT") == 0
296 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "TYPEOFWORK") == 0
297 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "AREA") == 0
298 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "OSTYPE") == 0
299 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "DEGREE") == 0
300 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "RUNNINGTIME") == 0
301 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "CLASSCODEINTL") == 0
302 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "CLASSCODEUS") == 0
303 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "SENDEREMAIL") == 0
304 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "RECIPIENTEMAIL") == 0
305 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "MEDIATYPE") == 0
306 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "NUMVOLUMES") == 0
307 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "EDITION") == 0
308 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "COMPUTER") == 0
309 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "CONFERENCELOCATION") == 0
310 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "REGISTRYNUM") == 0
311 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "CLASSIFICATION") == 0
312 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "SECTION") == 0
313 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "PAMPHLETNUM") == 0
314 	     ||	strcmp((ptr_asdata->ptr_first)->elname, "CHAPTERNUM") == 0
315 ) {
316 	/* write element name in POSITIONS */
317       sprintf(sql_command, "INSERT INTO POSITIONS (POS,TYPE,SEPARATORID,REFSTYLEID) VALUES (%d, '%s', 0, %u)", *(ptr_asdata->ptr_position), (ptr_asdata->ptr_first)->elname, *(ptr_asdata->ptr_refstyle_id));
318       dbires = dbi_conn_query(ptr_asdata->conn, sql_command);
319       LOG_PRINT(LOG_DEBUG, sql_command);
320       if (!dbires) {
321 	(*(ptr_asdata->ptr_ndb_error))++;
322 	LOG_PRINT(LOG_WARNING, "error in sql command");
323       }
324       else {
325 	/* increment position */
326 	(*(ptr_asdata->ptr_position))++;
327 	dbi_result_free(dbires);
328       }
329     }
330 
331 
332     /* AUTHORLIST, PUBDATE, TITLE, USERDEF, MISC, LINK need special care
333        as the actual column name in the database depends on the ROLE
334        attribute */
335 
336     /* first authorlist */
337     else if (strcmp((ptr_asdata->ptr_first)->elname, "AUTHORLIST") == 0) {
338       ptr_attr = get_attr(ptr_asdata->ptr_first, "ROLE");
339       if (!ptr_attr || strcmp(ptr_attr, "PART") == 0) {
340 	strcpy(concat, "AUTHORLIST");
341       }
342       else if (strcmp(ptr_attr, "PUB") == 0) {
343 	strcpy(concat, "EDITORLIST");
344       }
345       else if (strcmp(ptr_attr, "SERIES") == 0) {
346 	strcpy(concat, "SEDITORLIST");
347       }
348       else if (strcmp(ptr_attr, "ALL") == 0) {
349 	strcpy(concat, "ALLALIST");
350       }
351 
352 	/* write element name in POSITIONS */
353       sprintf(sql_command, "INSERT INTO POSITIONS (POS,TYPE,SEPARATORID,REFSTYLEID) VALUES (%d, '%s', 0, %u)", *(ptr_asdata->ptr_position), concat, *(ptr_asdata->ptr_refstyle_id));
354       dbires = dbi_conn_query(ptr_asdata->conn, sql_command);
355       LOG_PRINT(LOG_DEBUG, sql_command);
356       if (!dbires) {
357 	(*(ptr_asdata->ptr_ndb_error))++;
358 	LOG_PRINT(LOG_WARNING, "error in sql command");
359       }
360       else {
361 	/* increment position */
362 	(*(ptr_asdata->ptr_position))++;
363 	dbi_result_free(dbires);
364       }
365     }
366 
367     /* second pubdate */
368     else if (strcmp((ptr_asdata->ptr_first)->elname, "PUBDATE") == 0) {
369       ptr_attr = get_attr(ptr_asdata->ptr_first, "ROLE");
370       if (!ptr_attr || strcmp(ptr_attr, "PRIMARY") == 0) {
371 	strcpy(concat, "PUBDATE");
372       }
373       else if (strcmp(ptr_attr, "SECONDARY") == 0) {
374 	strcpy(concat, "PUBDATESEC");
375       }
376       else if (strcmp(ptr_attr, "ALL") == 0) {
377 	strcpy(concat, "PUBDATEALL");
378       }
379 
380 	/* write element name in POSITIONS */
381       sprintf(sql_command, "INSERT INTO POSITIONS (POS,TYPE,SEPARATORID,REFSTYLEID) VALUES (%d, '%s', 0, %u)", *(ptr_asdata->ptr_position), concat, *(ptr_asdata->ptr_refstyle_id));
382       dbires = dbi_conn_query(ptr_asdata->conn, sql_command);
383       LOG_PRINT(LOG_DEBUG, sql_command);
384       if (!dbires) {
385 	(*(ptr_asdata->ptr_ndb_error))++;
386 	LOG_PRINT(LOG_WARNING, "error in sql command");
387       }
388       else {
389 	/* increment position */
390 	(*(ptr_asdata->ptr_position))++;
391 	dbi_result_free(dbires);
392       }
393     }
394 
395     /* third title */
396     else if (strcmp((ptr_asdata->ptr_first)->elname, "TITLE") == 0) {
397       ptr_attr = get_attr(ptr_asdata->ptr_first, "ROLE");
398       if (!ptr_attr || strcmp(ptr_attr, "PART") == 0) {
399 	strcpy(concat, "TITLE");
400       }
401       else if (strcmp(ptr_attr, "PUB") == 0) {
402 	strcpy(concat, "BOOKTITLE");
403       }
404       else if (strcmp(ptr_attr, "SERIES") == 0) {
405 	strcpy(concat, "SERIESTITLE");
406       }
407       else if (strcmp(ptr_attr, "ALL") == 0) {
408 	strcpy(concat, "ALLTITLE");
409       }
410 
411 	/* write element name in POSITIONS */
412       sprintf(sql_command, "INSERT INTO POSITIONS (POS,TYPE,SEPARATORID,REFSTYLEID) VALUES (%d, '%s', 0, %u)", *(ptr_asdata->ptr_position), concat, *(ptr_asdata->ptr_refstyle_id));
413       dbires = dbi_conn_query(ptr_asdata->conn, sql_command);
414       LOG_PRINT(LOG_DEBUG, sql_command);
415       if (!dbires) {
416 	(*(ptr_asdata->ptr_ndb_error))++;
417 	LOG_PRINT(LOG_WARNING, "error in sql command");
418       }
419       else {
420 	/* increment position */
421 	(*(ptr_asdata->ptr_position))++;
422 	dbi_result_free(dbires);
423       }
424     }
425     else if (strcmp((ptr_asdata->ptr_first)->elname, "USERDEF") == 0) {
426       ptr_attr = get_attr(ptr_asdata->ptr_first, "ROLE");
427       if (!ptr_attr || strcmp(ptr_attr, "1") == 0) {
428 	strcpy(concat, "USERDEF1");
429       }
430       else if (strcmp(ptr_attr, "2") == 0) {
431 	strcpy(concat, "USERDEF2");
432       }
433       else if (strcmp(ptr_attr, "3") == 0) {
434 	strcpy(concat, "USERDEF3");
435       }
436       else if (strcmp(ptr_attr, "4") == 0) {
437 	strcpy(concat, "USERDEF4");
438       }
439       else if (strcmp(ptr_attr, "5") == 0) {
440 	strcpy(concat, "USERDEF5");
441       }
442 
443 	/* write element name in POSITIONS */
444       sprintf(sql_command, "INSERT INTO POSITIONS (POS,TYPE,SEPARATORID,REFSTYLEID) VALUES (%d, '%s', 0, %u)", *(ptr_asdata->ptr_position), concat, *(ptr_asdata->ptr_refstyle_id));
445       dbires = dbi_conn_query(ptr_asdata->conn, sql_command);
446       LOG_PRINT(LOG_DEBUG, sql_command);
447       if (!dbires) {
448 	(*(ptr_asdata->ptr_ndb_error))++;
449 	LOG_PRINT(LOG_WARNING, "error in sql command");
450       }
451       else {
452 	/* increment position */
453 	(*(ptr_asdata->ptr_position))++;
454 	dbi_result_free(dbires);
455       }
456     }
457     else if (strcmp((ptr_asdata->ptr_first)->elname, "LINK") == 0
458 	     || strcmp((ptr_asdata->ptr_first)->elname, "URL") == 0) {
459       if (*((ptr_asdata->ptr_first)->elname) == 'L') {
460 	ptr_attr = get_attr(ptr_asdata->ptr_first, "ROLE");
461       }
462 
463       if (*((ptr_asdata->ptr_first)->elname) == 'U'
464 	  || ptr_attr == NULL /* 0 is implied default */
465 	  || strcmp(ptr_attr, "0") == 0) {
466 	strcpy(concat, "LINK0");
467       }
468       else if (strcmp(ptr_attr, "1") == 0) {
469 	strcpy(concat, "LINK1");
470       }
471       else if (strcmp(ptr_attr, "2") == 0) {
472 	strcpy(concat, "LINK2");
473       }
474       else if (strcmp(ptr_attr, "3") == 0) {
475 	strcpy(concat, "LINK3");
476       }
477       else if (strcmp(ptr_attr, "4") == 0) {
478 	strcpy(concat, "LINK4");
479       }
480 
481 	/* write element name in POSITIONS */
482       sprintf(sql_command, "INSERT INTO POSITIONS (POS,TYPE,SEPARATORID,REFSTYLEID) VALUES (%d, '%s', 0, %u)", *(ptr_asdata->ptr_position), concat, *(ptr_asdata->ptr_refstyle_id));
483       dbires = dbi_conn_query(ptr_asdata->conn, sql_command);
484       LOG_PRINT(LOG_DEBUG, sql_command);
485       if (!dbires) {
486 	(*(ptr_asdata->ptr_ndb_error))++;
487 	LOG_PRINT(LOG_WARNING, "error in sql command");
488       }
489       else {
490 	/* increment position */
491 	(*(ptr_asdata->ptr_position))++;
492 	dbi_result_free(dbires);
493       }
494     }
495 
496     /* set ignore_role to 1 for those elements that treat the ROLE attribute in a special way (the attribute is used to translate the element name to a different column name than expected) */
497     if (strcmp((ptr_asdata->ptr_first)->elname, "AUTHORLIST") == 0 ||
498 	strcmp((ptr_asdata->ptr_first)->elname, "PUBDATE") == 0 ||
499 	strcmp((ptr_asdata->ptr_first)->elname, "TITLE") == 0 ||
500 	strcmp((ptr_asdata->ptr_first)->elname, "LINK") == 0 ||
501 	strcmp((ptr_asdata->ptr_first)->elname, "USERDEF") == 0) {
502       ignore_role = 1;
503     }
504 
505     /* the name of the style and related style info */
506     if (strcmp((ptr_asdata->ptr_first)->elname, "STYLENAME") == 0) {
507       char* the_item_q = NULL;
508 
509       if ((the_item_q = strdup((ptr_asdata->ptr_first)->ptr_elvalue)) == NULL) {
510 	(*(ptr_asdata->ptr_nmem_error))++;
511 	LOG_PRINT(LOG_CRIT, get_status_msg(801));
512       }
513       else {
514 	if (dbi_conn_quote_string(ptr_asdata->conn, &the_item_q) == 0) {
515 	  (*(ptr_asdata->ptr_nmem_error))++;
516 	  LOG_PRINT(LOG_CRIT, get_status_msg(801));
517 	}
518       }
519 
520       if (the_item_q) {
521 	strncpy(ptr_asdata->the_journal, the_item_q, 255);
522 	ptr_asdata->the_journal[255] = '\0';
523 	free(the_item_q);
524       }
525       else {
526 	ptr_asdata->the_journal[0] = '\0';
527       }
528 
529       strcpy(column_name, "JOURNAL");
530       strcpy(table_name, "CITSTYLE");
531       n_chardata = 1;
532       current_id = *(ptr_asdata->ptr_citstyle_id);
533     }
534 
535     if (strcmp((ptr_asdata->ptr_first)->elname, "AUTHOR") == 0
536 	|| strcmp((ptr_asdata->ptr_first)->elname, "COMMENT") == 0
537 	|| strcmp((ptr_asdata->ptr_first)->elname, "URL") == 0) {
538       strcpy(column_name, (ptr_asdata->ptr_first)->elname);
539       strcpy(table_name, "CITSTYLE");
540       n_chardata = 1;
541       current_id = *(ptr_asdata->ptr_citstyle_id);
542     }
543 
544     /* elements with character data in PUBTYPE, INTEXT, AUTHORONLY, or YEARONLY */
545     else if (strcmp((ptr_asdata->ptr_first)->elname, "ABBREVIATEFIRST") == 0 ||
546 	     strcmp((ptr_asdata->ptr_first)->elname, "ABBREVIATESUBSEQ") == 0 ||
547 	     strcmp((ptr_asdata->ptr_first)->elname, "AEMPTY") == 0 ||
548 	     strcmp((ptr_asdata->ptr_first)->elname, "ASAME") == 0) {
549       /* assemble column name */
550       if (!strcmp(((ptr_asdata->ptr_first)->ptr_next)->elname, "AUTHORLIST")) {
551 	strcpy(column_name, "Q");
552       }
553       else if (!strcmp(((ptr_asdata->ptr_first)->ptr_next)->elname, "EDITORLIST")) {
554 	strcpy(column_name, "X");
555       }
556       else if (!strcmp(((ptr_asdata->ptr_first)->ptr_next)->elname, "SEDITORLIST")) {
557 	strcpy(column_name, "Y");
558       }
559       else if (!strcmp(((ptr_asdata->ptr_first)->ptr_next)->elname, "ALLALIST")) {
560 	strcpy(column_name, "Z");
561       }
562       else {
563 	strcpy(column_name, ((ptr_asdata->ptr_first)->ptr_next)->elname);
564       }
565       strcat(column_name, (ptr_asdata->ptr_first)->elname);
566 
567       /* we expect char data and attr data */
568       n_chardata = 1;
569       n_attrdata = 1;
570       current_id = *(ptr_asdata->ptr_citstyle_id);
571       strcpy(table_name, "REFSTYLE");
572 
573       if (is_descendant_of(ptr_asdata->ptr_first, "PUBTYPE")) {
574 	strcpy(pubtype, get_ancestor_attr(ptr_asdata->ptr_first, "PUBTYPE", "TYPE"));
575       }
576       else if (is_descendant_of(ptr_asdata->ptr_first, "INTEXTDEF")) {
577 	strcpy(pubtype, "INTEXT");
578       }
579       else if (is_descendant_of(ptr_asdata->ptr_first, "AUTHORONLY")) {
580 	strcpy(pubtype, "AUTHORONLY");
581       }
582       else { /* yearonly */
583 	strcpy(pubtype, "YEARONLY");
584       }
585     }
586 
587     /* elements with character data in CITSTYLE */
588     else if (strcmp((ptr_asdata->ptr_first)->elname, "CITSEPARATOR") == 0 ||
589 	     strcmp((ptr_asdata->ptr_first)->elname, "BIBLIOTITLE") == 0) {
590       strcpy(table_name, "CITSTYLE");
591       strcpy(column_name, (ptr_asdata->ptr_first)->elname);
592       n_chardata = 1;
593       current_id = *(ptr_asdata->ptr_citstyle_id);
594     }
595 
596     /* elements with character data at various locations */
597     else if (strcmp((ptr_asdata->ptr_first)->elname, "RANGESEPARATOR") == 0) {
598       if (is_descendant_of(ptr_asdata->ptr_first, "PUBTYPE")) {
599 	strcpy(table_name, "REFSTYLE");
600 	strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "PUBTYPE", concat));
601 	strcpy(pubtype, get_ancestor_attr(ptr_asdata->ptr_first, "PUBTYPE", "TYPE"));
602 	n_chardata = 1;
603 	n_attrdata = 1;
604 	current_id = *(ptr_asdata->ptr_citstyle_id);
605       }
606       else if (is_descendant_of(ptr_asdata->ptr_first, "INTEXTDEF")) {
607 	strcpy(table_name, "REFSTYLE");
608 	strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "INTEXTDEF", concat));
609 	strcpy(pubtype, "INTEXT");
610 	n_chardata = 1;
611 	n_attrdata = 1;
612 	current_id = *(ptr_asdata->ptr_citstyle_id);
613       }
614       else if (is_descendant_of(ptr_asdata->ptr_first, "AUTHORONLY")) {
615 	strcpy(table_name, "REFSTYLE");
616 	strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "AUTHORONLY", concat));
617 	strcpy(pubtype, "AUTHORONLY");
618 	n_chardata = 1;
619 	n_attrdata = 1;
620 	current_id = *(ptr_asdata->ptr_citstyle_id);
621       }
622       else if (is_descendant_of(ptr_asdata->ptr_first, "YEARONLY")) {
623 	strcpy(table_name, "REFSTYLE");
624 	strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "YEARONLY", concat));
625 	strcpy(pubtype, "YEARONLY");
626 	n_chardata = 1;
627 	n_attrdata = 1;
628 	current_id = *(ptr_asdata->ptr_citstyle_id);
629       }
630       else { /* CITSTYLE */
631 	strcpy(table_name, "CITSTYLE");
632 	strcpy(column_name, (ptr_asdata->ptr_first)->elname);
633 	n_chardata = 1;
634 	current_id = *(ptr_asdata->ptr_citstyle_id);
635       }
636     }
637 
638     /* can be level 2, 3, 4, 5, 6 */
639     else if (strcmp((ptr_asdata->ptr_first)->elname, "FOLLOWING") == 0 ||
640 	     strcmp((ptr_asdata->ptr_first)->elname, "PRECEEDING") == 0) {
641 
642 /*        printf("depth:%d\n", depth); */
643       if (*(ptr_asdata->ptr_depth) - *(ptr_asdata->ptr_depth_adjust) == 2) { /* citstyle-following */
644 	strcpy(table_name, "CITSTYLE");
645 	strcpy(column_name, (ptr_asdata->ptr_first)->elname);
646 	n_chardata = 1;
647 	n_attrdata = 1;
648 	current_id = *(ptr_asdata->ptr_citstyle_id);
649       }
650       else if (*(ptr_asdata->ptr_depth) - *(ptr_asdata->ptr_depth_adjust) == 3) { /* citstyle-biblionumbering-following */
651 	strcpy(table_name, "CITSTYLE");
652 	strcpy(column_name, ((ptr_asdata->ptr_first)->ptr_next)->elname);
653 	strcat(column_name, (ptr_asdata->ptr_first)->elname);
654 	n_chardata = 1;
655 	n_attrdata = 1;
656 	current_id = *(ptr_asdata->ptr_citstyle_id);
657       }
658       else {
659 	if (is_descendant_of(ptr_asdata->ptr_first, "PUBTYPE")) {
660 	  strcpy(table_name, "REFSTYLE");
661 	  strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "PUBTYPE", concat));
662 	  strcpy(pubtype, get_ancestor_attr(ptr_asdata->ptr_first, "PUBTYPE", "TYPE"));
663 	}
664 	else if (is_descendant_of(ptr_asdata->ptr_first, "INTEXTDEF")) {
665 	  strcpy(table_name, "REFSTYLE");
666 	  strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "INTEXTDEF", concat));
667 	  strcpy(pubtype, "INTEXT");
668 	}
669 	else if (is_descendant_of(ptr_asdata->ptr_first, "AUTHORONLY")) {
670 	  strcpy(table_name, "REFSTYLE");
671 	  strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "AUTHORONLY", concat));
672 	  strcpy(pubtype, "AUTHORONLY");
673 	}
674 	else { /* yearonly */
675 	  strcpy(table_name, "REFSTYLE");
676 	  strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "YEARONLY", concat));
677 	  strcpy(pubtype, "YEARONLY");
678 	}
679 	n_chardata = 1;
680 	n_attrdata = 1;
681 	current_id = *(ptr_asdata->ptr_citstyle_id);
682       }
683     }
684     else if (strcmp((ptr_asdata->ptr_first)->elname, "SEPARATOR") == 0) {
685       strcpy(table_name, "SEPARATORS");
686       strcpy(column_name, "VALUE");
687       n_chardata = 1;
688       n_attrdata = 0;
689       current_id = *(ptr_asdata->ptr_separator_id);
690     }
691 
692     else if (strcmp((ptr_asdata->ptr_first)->elname, "THREESEPSEACH") == 0 ||
693 	     strcmp((ptr_asdata->ptr_first)->elname, "THREESEPSLAST") == 0 ||
694 	     strcmp((ptr_asdata->ptr_first)->elname, "TWOSEPS") == 0) {
695       strcpy(table_name, "REFSTYLE");
696       if (is_descendant_of(ptr_asdata->ptr_first, "PUBTYPE")) {
697 	strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "PUBTYPE", concat));
698 	strcpy(pubtype, get_ancestor_attr(ptr_asdata->ptr_first, "PUBTYPE", "TYPE"));
699       }
700       else if (is_descendant_of(ptr_asdata->ptr_first, "INTEXTDEF")) {
701 	strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "INTEXTDEF", concat));
702 	strcpy(pubtype, "INTEXT");
703       }
704       else if (is_descendant_of(ptr_asdata->ptr_first, "AUTHORONLY")) {
705 	strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "AUTHORONLY", concat));
706 	strcpy(pubtype, "AUTHORONLY");
707       }
708       else { /* yearonly */
709 	strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "YEARONLY", concat));
710 	strcpy(pubtype, "YEARONLY");
711       }
712       n_chardata = 1;
713       n_attrdata = 1;
714       current_id = *(ptr_asdata->ptr_citstyle_id);
715     }
716 
717     /* only cdata, no attributes */
718     else if (strcmp((ptr_asdata->ptr_first)->elname, "FIRSTSEP") == 0 ||
719 	     strcmp((ptr_asdata->ptr_first)->elname, "SECONDSEP") == 0) {
720       strcpy(table_name, "REFSTYLE");
721       if (is_descendant_of(ptr_asdata->ptr_first, "PUBTYPE")) {
722 	strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "PUBTYPE", concat));
723 	strcpy(pubtype, get_ancestor_attr(ptr_asdata->ptr_first, "PUBTYPE", "TYPE"));
724       }
725       else if (is_descendant_of(ptr_asdata->ptr_first, "INTEXTDEF")) {
726 	strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "INTEXTDEF", concat));
727 	strcpy(pubtype, "INTEXT");
728       }
729       else if (is_descendant_of(ptr_asdata->ptr_first, "AUTHORONLY")) {
730 	strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "AUTHORONLY", concat));
731 	strcpy(pubtype, "AUTHORONLY");
732       }
733       else { /* yearonly */
734 	strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "YEARONLY", concat));
735 	strcpy(pubtype, "YEARONLY");
736       }
737       n_chardata = 1;
738       current_id = *(ptr_asdata->ptr_citstyle_id);
739     }
740 
741     /* refstyle elements with attributes only */
742     else if (strcmp((ptr_asdata->ptr_first)->elname, "AUTHORLIST") == 0 ||
743 	     strcmp((ptr_asdata->ptr_first)->elname, "ISSUE") == 0 ||
744 	     strcmp((ptr_asdata->ptr_first)->elname, "JOURNALNAME") == 0 ||
745 	     strcmp((ptr_asdata->ptr_first)->elname, "NAMEFIRST") == 0 ||
746 	     strcmp((ptr_asdata->ptr_first)->elname, "NAMEOTHER") == 0 ||
747 	     strcmp((ptr_asdata->ptr_first)->elname, "PAGERANGE") == 0 ||
748 	     strcmp((ptr_asdata->ptr_first)->elname, "PAGES") == 0 ||
749 	     strcmp((ptr_asdata->ptr_first)->elname, "PUBDATE") == 0 ||
750 	     strcmp((ptr_asdata->ptr_first)->elname, "PUBLISHER") == 0 ||
751 	     strcmp((ptr_asdata->ptr_first)->elname, "PUBPLACE") == 0 ||
752 	     strcmp((ptr_asdata->ptr_first)->elname, "SERIAL") == 0 ||
753 	     strcmp((ptr_asdata->ptr_first)->elname, "ADDRESS") == 0 ||
754 	     strcmp((ptr_asdata->ptr_first)->elname, "URL") == 0 ||
755 	     strcmp((ptr_asdata->ptr_first)->elname, "NOTES") == 0 ||
756 	     strcmp((ptr_asdata->ptr_first)->elname, "ABSTRACT") == 0 ||
757 	     strcmp((ptr_asdata->ptr_first)->elname, "USERDEF") == 0 ||
758 	     strcmp((ptr_asdata->ptr_first)->elname, "TYPEOFWORK") == 0 ||
759 	     strcmp((ptr_asdata->ptr_first)->elname, "AREA") == 0 ||
760 	     strcmp((ptr_asdata->ptr_first)->elname, "OSTYPE") == 0 ||
761 	     strcmp((ptr_asdata->ptr_first)->elname, "DEGREE") == 0 ||
762 	     strcmp((ptr_asdata->ptr_first)->elname, "RUNNINGTIME") == 0 ||
763 	     strcmp((ptr_asdata->ptr_first)->elname, "CLASSCODEINTL") == 0 ||
764 	     strcmp((ptr_asdata->ptr_first)->elname, "CLASSCODEUS") == 0 ||
765 	     strcmp((ptr_asdata->ptr_first)->elname, "SENDEREMAIL") == 0 ||
766 	     strcmp((ptr_asdata->ptr_first)->elname, "RECIPIENTEMAIL") == 0 ||
767 	     strcmp((ptr_asdata->ptr_first)->elname, "MEDIATYPE") == 0 ||
768 	     strcmp((ptr_asdata->ptr_first)->elname, "NUMVOLUMES") == 0 ||
769 	     strcmp((ptr_asdata->ptr_first)->elname, "EDITION") == 0 ||
770 	     strcmp((ptr_asdata->ptr_first)->elname, "COMPUTER") == 0 ||
771 	     strcmp((ptr_asdata->ptr_first)->elname, "CONFERENCELOCATION") == 0 ||
772 	     strcmp((ptr_asdata->ptr_first)->elname, "REGISTRYNUM") == 0 ||
773 	     strcmp((ptr_asdata->ptr_first)->elname, "CLASSIFICATION") == 0 ||
774 	     strcmp((ptr_asdata->ptr_first)->elname, "SECTION") == 0 ||
775 	     strcmp((ptr_asdata->ptr_first)->elname, "PAMPHLETNUM") == 0 ||
776 	     strcmp((ptr_asdata->ptr_first)->elname, "CHAPTERNUM") == 0 ||
777 	     strcmp((ptr_asdata->ptr_first)->elname, "LINK") == 0 ||
778 	     strcmp((ptr_asdata->ptr_first)->elname, "REFNUMBER") == 0 ||
779 	     strcmp((ptr_asdata->ptr_first)->elname, "CITEKEY") == 0 ||
780 	     strcmp((ptr_asdata->ptr_first)->elname, "SINGLEPAGE") == 0 ||
781 	     strcmp((ptr_asdata->ptr_first)->elname, "TITLE") == 0 ||
782 	     strcmp((ptr_asdata->ptr_first)->elname, "VOLUME") == 0) {
783       strcpy(table_name, "REFSTYLE");
784       if (is_descendant_of(ptr_asdata->ptr_first, "PUBTYPE")) {
785 	strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "PUBTYPE", concat));
786 	strcpy(pubtype, get_ancestor_attr(ptr_asdata->ptr_first, "PUBTYPE", "TYPE"));
787       }
788       else if (is_descendant_of(ptr_asdata->ptr_first, "INTEXTDEF")) {
789 	strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "INTEXTDEF", concat));
790 	strcpy(pubtype, "INTEXT");
791       }
792       else if (is_descendant_of(ptr_asdata->ptr_first, "AUTHORONLY")) {
793 	strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "AUTHORONLY", concat));
794 	strcpy(pubtype, "AUTHORONLY");
795       }
796       else { /* yearonly */
797 	strcpy(column_name, concat_elnames(ptr_asdata->ptr_first, "YEARONLY", concat));
798 	strcpy(pubtype, "YEARONLY");
799       }
800       n_attrdata = 1;
801       current_id = *(ptr_asdata->ptr_citstyle_id);
802     }
803 
804     /* citstyle elements with attributes only, no column_name req */
805     else if (strcmp((ptr_asdata->ptr_first)->elname, "CITSTYLE") == 0
806 	     || strcmp((ptr_asdata->ptr_first)->elname, "BIBSTYLE") == 0) {
807       strcpy(table_name, "CITSTYLE");
808       n_attrdata = 1;
809       current_id = *(ptr_asdata->ptr_citstyle_id);
810     }
811 
812     /* citstyle elements with attributes only, column_name req */
813     else if (strcmp((ptr_asdata->ptr_first)->elname, "JAN") == 0 ||
814 	     strcmp((ptr_asdata->ptr_first)->elname, "FEB") == 0 ||
815 	     strcmp((ptr_asdata->ptr_first)->elname, "MAR") == 0 ||
816 	     strcmp((ptr_asdata->ptr_first)->elname, "APR") == 0 ||
817 	     strcmp((ptr_asdata->ptr_first)->elname, "MAY") == 0 ||
818 	     strcmp((ptr_asdata->ptr_first)->elname, "JUN") == 0 ||
819 	     strcmp((ptr_asdata->ptr_first)->elname, "JUL") == 0 ||
820 	     strcmp((ptr_asdata->ptr_first)->elname, "AUG") == 0 ||
821 	     strcmp((ptr_asdata->ptr_first)->elname, "SEP") == 0 ||
822 	     strcmp((ptr_asdata->ptr_first)->elname, "OCT") == 0 ||
823 	     strcmp((ptr_asdata->ptr_first)->elname, "NOV") == 0 ||
824 	     strcmp((ptr_asdata->ptr_first)->elname, "DEC") == 0) {
825       strcpy(table_name, "CITSTYLE");
826       strcpy(column_name, (ptr_asdata->ptr_first)->elname);
827       n_attrdata = 1;
828       current_id = *(ptr_asdata->ptr_citstyle_id);
829     }
830 
831     /* this set is done. check whether we replace an existing entry */
832     else if (strcmp((ptr_asdata->ptr_first)->elname, "CITESTYLE") == 0) {
833       (*(ptr_asdata->ptr_set_count))++;
834       sprintf(sql_command, "408:%u:%s\n", *(ptr_asdata->ptr_citstyle_id), ptr_asdata->the_journal);
835 
836       if ((new_msg = mstrcat(ptr_asdata->ptr_addresult->msg, sql_command, &(ptr_asdata->ptr_addresult->msg_len), 0)) == NULL) {
837 	(*(ptr_asdata->ptr_nmem_error))++;
838       }
839       else {
840 	ptr_asdata->ptr_addresult->msg = new_msg;
841       }
842 
843       /* the_journal is already quoted */
844       sprintf(sql_command, "SELECT ID FROM CITSTYLE WHERE JOURNAL=%s ORDER BY ID ASC", ptr_asdata->the_journal);
845       dbires = dbi_conn_query(ptr_asdata->conn, sql_command);
846       LOG_PRINT(LOG_DEBUG, sql_command);
847       if (dbires) {
848 	if (dbi_result_next_row(dbires) != 0) {
849 	  n_id = my_dbi_result_get_int_idval(dbires, "ID");
850 	  if (n_id != *(ptr_asdata->ptr_citstyle_id)) {
851 	    if (!remove_style(ptr_asdata->conn, n_id)) {
852 	      sprintf(sql_command, "419:%u:%s\n", n_id, ptr_asdata->the_journal);
853 	    }
854 	    else {
855 	      sprintf(sql_command, "420:%u:%s\n", *(ptr_asdata->ptr_citstyle_id), ptr_asdata->the_journal);
856 	    }
857 
858 	    if ((new_msg = mstrcat(ptr_asdata->ptr_addresult->msg, sql_command, &(ptr_asdata->ptr_addresult->msg_len), 0)) == NULL) {
859 	      (*(ptr_asdata->ptr_nmem_error))++;
860 	    }
861 	    else {
862 	      ptr_asdata->ptr_addresult->msg = new_msg;
863 	    }
864 	  }
865 	}
866 	else {
867 	  LOG_PRINT(LOG_WARNING, "error in retrieving sql result");
868 	}
869 	dbi_result_free(dbires);
870       }
871       else {
872 	LOG_PRINT(LOG_WARNING, "error in sql command");
873       }
874     }
875 
876     /* elements without values or attributes */
877     else if (strcmp((ptr_asdata->ptr_first)->elname, "AUTHORNAMES") == 0 ||
878 	     strcmp((ptr_asdata->ptr_first)->elname, "AUTHORSEPS") == 0 ||
879 	     strcmp((ptr_asdata->ptr_first)->elname, "TEXT") == 0 ||
880 	     strcmp((ptr_asdata->ptr_first)->elname, "TEXTED") == 0 ||
881 	     strcmp((ptr_asdata->ptr_first)->elname, "TEXTMULTIPLE") == 0 ||
882 	     strcmp((ptr_asdata->ptr_first)->elname, "TEXTSINGLE") == 0 ||
883 	     strcmp((ptr_asdata->ptr_first)->elname, "THREESEPS") == 0 ||
884 	     strcmp((ptr_asdata->ptr_first)->elname, "REFSTYLE") == 0  ||
885 	     strcmp((ptr_asdata->ptr_first)->elname, "MONTHS") == 0) {
886       /* do nothing (n_chardata and n_attrdata remain 0) */
887     }
888     /*    printf("%d", depth); */
889     /*    for (i = 0; i < depth; i++) { */
890     /*      printf("  "); */
891     /*    } */
892     /*    printf("endtag:%s\n", ptr_first->elname); */
893 
894     /* no values or attributes, but we have to take care of depth_adjust */
895     else if (strcmp((ptr_asdata->ptr_first)->elname, "STYLESET") == 0) {
896       (*(ptr_asdata->ptr_depth_adjust))--;
897     }
898 
899     if (n_chardata) {
900       char* elvalue_q = NULL;
901 
902       /* quote element value */
903       if ((elvalue_q = strdup((ptr_asdata->ptr_first)->ptr_elvalue)) == NULL) {
904 	/* todo: bail out */
905       }
906       else {
907 	if (dbi_conn_quote_string(ptr_asdata->conn, &elvalue_q) == 0) {
908 	  /* todo: bail out */
909 	}
910       }
911 
912       if (elvalue_q) {
913 	if (pubtype[0]) {
914 	  sprintf(sql_command, "UPDATE REFSTYLE SET %s=%s WHERE CITSTYLEID=%u AND PUBTYPE='", column_name, elvalue_q, current_id);
915 	  /* we have to add pubtype outside of the sprintf call. The reason is unclear, but may be a hidden overflow or something */
916 	  strcat(sql_command, pubtype);
917 	  strcat(sql_command, "\'");
918 	}
919 	else {
920 	  sprintf(sql_command, "UPDATE %s SET %s=%s WHERE ID=%u", table_name, column_name, elvalue_q, current_id);
921 	}
922 
923 	free(elvalue_q);
924 	dbires = dbi_conn_query(ptr_asdata->conn, sql_command);
925 	LOG_PRINT(LOG_DEBUG, sql_command);
926 	if (!dbires) {
927 	  (*(ptr_asdata->ptr_ndb_error))++;
928 	  LOG_PRINT(LOG_WARNING, "error in sql command");
929 	}
930 	else {
931 	  dbi_result_free(dbires);
932 	}
933       } /* end if elvalue_q */
934     } /* end if n_chardata */
935   } /* end if no mem or db errors */
936 
937   /* remove attributes of the current element from the list */
938   ptr_attr_remove = (ptr_asdata->ptr_first)->ptr_attr_first;
939   while (ptr_attr_remove) {
940     /* assemble column name for attribute */
941     if (n_attrdata) {
942       strcpy(column_name_attribute, column_name);
943       strcat(column_name_attribute, ptr_attr_remove->attribute_name);
944       /*      for (i = 0; i < depth; i++) { */
945       /*        printf("  "); */
946       /*      } */
947       if (strcmp(ptr_attr_remove->attribute_name, "ROLE") != 0 || !ignore_role) {
948 	if (pubtype[0]) {
949 	  sprintf(sql_command, "UPDATE REFSTYLE SET %s='%s' WHERE CITSTYLEID=%u AND PUBTYPE='", column_name_attribute, ptr_attr_remove->attribute_value, current_id);
950 	  /* we have to add pubtype outside of the sprintf call. The reason is unclear, but may be a hidden overflow or something */
951 	  strcat(sql_command, pubtype);
952 	  strcat(sql_command, "\'");
953 	}
954 	else {
955 	  sprintf(sql_command, "UPDATE %s SET %s='%s' WHERE ID=%u", table_name, column_name_attribute, ptr_attr_remove->attribute_value, current_id);
956 	}
957 
958 	/*        printf("%s\n", sql_command); */
959 	dbires = dbi_conn_query(ptr_asdata->conn, sql_command);
960 	LOG_PRINT(LOG_DEBUG, sql_command);
961 	if (!dbires) {
962 	  (*(ptr_asdata->ptr_ndb_error))++;
963 	  LOG_PRINT(LOG_WARNING, "error in sql command");
964 	}
965 	else {
966 	  dbi_result_free(dbires);
967 	}
968       }
969     }
970     (ptr_asdata->ptr_first)->ptr_attr_first = ((ptr_asdata->ptr_first)->ptr_attr_first)->ptr_next;
971     free(ptr_attr_remove);
972     ptr_attr_remove = (ptr_asdata->ptr_first)->ptr_attr_first;
973   }
974 
975   /* free element value string */
976   if ((ptr_asdata->ptr_first)->ptr_elvalue) {
977     free((ptr_asdata->ptr_first)->ptr_elvalue);
978   }
979 
980   /* remove current element from element stack */
981   ptr_el_remove = ptr_asdata->ptr_first;
982   ptr_asdata->ptr_first = (ptr_asdata->ptr_first)->ptr_next;
983   free(ptr_el_remove);
984 
985 /*    printf("end tag handler done\n"); */
986 }  /* End of end_handler */
987 
988 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
989   char_handler(): handler for character data. It is limited to 256
990                   chars per element which is way enough for the
991                   citestyle dtd.
992 
993   void char_handler has no return value
994 
995   void* ptr_data this is a ptr to "non-global" global data that all
996              handlers share - will be cast to type struct addstyle_data*
997 
998   const char *string ptr to a string containing the char data
999                      this string is not \0 terminated and could be
1000                      only a part of the character data of an element!
1001 
1002   int len length length of string
1003 
1004   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char_handler(void * ptr_data,const char * string,int len)1005 void char_handler(void *ptr_data, const char *string, int len) {
1006   size_t len_elvalue;
1007   size_t len_string;
1008   struct addstyle_data* ptr_asdata;
1009 
1010   ptr_asdata = (struct addstyle_data*)ptr_data;
1011 
1012   if (*(ptr_asdata->ptr_ndb_error) || *(ptr_asdata->ptr_nmem_error)) {
1013     return;
1014   }
1015   len_elvalue = strlen((ptr_asdata->ptr_first)->ptr_elvalue);
1016   len_elvalue = (len_elvalue > 256) ? 256 : len_elvalue;
1017   len_string = (len > (int)(256-(int)len_elvalue)) ? 256-len_elvalue : (size_t)len;
1018   strncpy(&(((ptr_asdata->ptr_first)->ptr_elvalue)[len_elvalue]), string, len_string);
1019   ((ptr_asdata->ptr_first)->ptr_elvalue)[len_elvalue + len_string] = '\0';
1020 /*    printf(">>%s\n", ptr_first->elvalue); */
1021 }
1022 
1023 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1024   get_ancestor_attr(): returns the value of an attribute of an
1025                        ancestor of the current element
1026 
1027   static char* get_ancestor_attr returns the value of the requested attribute
1028                        or NULL if no such attribute is found
1029 
1030   struct elstack* ptr_current_element ptr to the current element on
1031                        the element stack
1032 
1033   char* ancestor_name name of the requested ancestor element
1034 
1035   char* ancestor_attribute name of the requested ancestor attribute
1036 
1037   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
get_ancestor_attr(struct elstack * ptr_current_element,char * ancestor_name,char * ancestor_attribute)1038 static char* get_ancestor_attr(struct elstack* ptr_current_element, char* ancestor_name, char* ancestor_attribute) {
1039   struct elstack* ptr_el;
1040   struct attrlist* ptr_attr;
1041 
1042   ptr_el = ptr_current_element;
1043 
1044   while (ptr_el != NULL) {
1045     if (strcmp(ptr_el->elname, ancestor_name) == 0) {
1046       ptr_attr = ptr_el->ptr_attr_first;
1047 
1048       while (ptr_attr != NULL) {
1049 	if (strcmp(ptr_attr->attribute_name, ancestor_attribute) == 0) {
1050 	  return ptr_attr->attribute_value;
1051 	}
1052 	ptr_attr = ptr_attr->ptr_next;
1053       }
1054     }
1055     ptr_el = ptr_el->ptr_next;
1056   }
1057   return NULL;
1058 }
1059 
1060 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1061   get_attr(): returns the value of an attribute of the current element
1062 
1063   char* get_attr returns the value of the requested attribute
1064                        or NULL if no such attribute is found
1065 
1066   struct elstack* ptr_current_element ptr to the current element on
1067                        the element stack
1068 
1069   char* attribute name of the requested attribute
1070 
1071   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
get_attr(struct elstack * ptr_current_element,char * attribute)1072 char* get_attr(struct elstack* ptr_current_element, char* attribute) {
1073   struct attrlist* ptr_attr;
1074 
1075   ptr_attr = ptr_current_element->ptr_attr_first;
1076 
1077   while (ptr_attr != NULL) {
1078     if (strcmp(ptr_attr->attribute_name, attribute) == 0) {
1079       return ptr_attr->attribute_value;
1080     }
1081     ptr_attr = ptr_attr->ptr_next;
1082   }
1083 
1084   return NULL;
1085 }
1086 
1087 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1088   is_descendant_of(): tests whether the current element is the
1089                        descendant of a given element
1090 
1091   int is_descendant_of returns 1 if the current element is the
1092                        descendant of the given element, 0 if not
1093 
1094   struct elstack* ptr_current_element ptr to the current element on
1095                        the element stack
1096 
1097   char* ancestor_name name of the requested ancestor element
1098 
1099   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
is_descendant_of(struct elstack * ptr_current_element,char * ancestor_name)1100 int is_descendant_of(struct elstack* ptr_current_element, char* ancestor_name) {
1101   struct elstack* ptr_el;
1102 
1103   ptr_el = ptr_current_element;
1104 
1105   while (ptr_el != NULL) {
1106     if (strcmp(ptr_el->elname, ancestor_name) == 0) {
1107       return 1;
1108     }
1109     ptr_el = ptr_el->ptr_next;
1110   }
1111   return 0;
1112 }
1113 
1114 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1115   concat_elnames(): concatenates the names of all ancestors of the
1116                     current element up to a given element which is not
1117                     to be concatenated to the string. The leftmost
1118                     element name in the concatenated string will be
1119                     of the distal element, the rightmost will be the
1120                     name of the current element
1121 
1122   static char* concat_elnames returns a ptr to the concatenated names.
1123                     This will be an empty string if the current element
1124 		    is identical with the first excluded element
1125 
1126   struct elstack* ptr_current_element ptr to the current element on the
1127                     element stack
1128 
1129   char* exclude_name the name of the first ancestor (as seen from the
1130                     current element) that is not to be included into
1131                     the concatenated names. This is where the concatenating
1132                     stops.
1133 
1134   char* concat ptr to a buffer that receives the concatenated name. This
1135                     buffer must hold at least 64 chars. This ptr is also
1136                     used as the return value for the function
1137 
1138   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
concat_elnames(struct elstack * ptr_current_element,char * exclude_name,char * concat)1139 static char* concat_elnames(struct elstack* ptr_current_element, char* exclude_name, char* concat) {
1140   struct elstack* ptr_el;
1141   char buffer[64];
1142   char* ptr_attr;
1143 
1144   concat[0] = '\0';
1145   ptr_el = ptr_current_element;
1146 
1147   while (ptr_el != NULL) {
1148     if (strcmp(ptr_el->elname, exclude_name) == 0) {
1149       return concat;
1150     }
1151     strcpy(buffer, concat);
1152     /* AUTHORLIST, PUBDATE, TITLE, USERDEF, MISC, LINK need special care
1153        as the actual column name in the database depends on the ROLE
1154        attribute */
1155     if (strcmp(ptr_el->elname, "AUTHORLIST") == 0) {
1156       /* we use short versions of these element names in order not
1157 	 to exceed the column name limit of PostgreSQL */
1158       ptr_attr = get_ancestor_attr(ptr_el, "AUTHORLIST", "ROLE");
1159       if (ptr_attr && strcmp(ptr_attr, "PART") == 0) {
1160 	strcpy(concat, "Q"); /* AUTHORLIST */
1161       }
1162       else if (ptr_attr && strcmp(ptr_attr, "SERIES") == 0) {
1163 	strcpy(concat, "Y"); /* SEDITORLIST */
1164       }
1165       else if (ptr_attr && strcmp(ptr_attr, "ALL") == 0) {
1166 	strcpy(concat, "Z"); /* ALLALIST */
1167       }
1168       else {
1169 	/* DTD uses this as default */
1170 	strcpy(concat, "X"); /* EDITORLIST */
1171       }
1172     }
1173     else if (strcmp(ptr_el->elname, "PUBDATE") == 0) {
1174       ptr_attr = get_ancestor_attr(ptr_el, "PUBDATE", "ROLE");
1175       if (ptr_attr && strcmp(ptr_attr, "SECONDARY") == 0) {
1176 	strcpy(concat, "PUBDATESEC");
1177       }
1178       else if (ptr_attr && strcmp(ptr_attr, "ALL") == 0) {
1179 	strcpy(concat, "PUBDATEALL");
1180       }
1181       else {
1182 	strcpy(concat, "PUBDATE");
1183       }
1184     }
1185     else if (strcmp(ptr_el->elname, "TITLE") == 0) {
1186       ptr_attr = get_ancestor_attr(ptr_el, "TITLE", "ROLE");
1187       if (ptr_attr && strcmp(ptr_attr, "PART") == 0) {
1188 	strcpy(concat, "TITLE");
1189       }
1190       else if (ptr_attr && strcmp(ptr_attr, "SERIES") == 0) {
1191 	strcpy(concat, "SERIESTITLE");
1192       }
1193       else if (ptr_attr && strcmp(ptr_attr, "ALL") == 0) {
1194 	strcpy(concat, "ALLTITLE");
1195       }
1196       else {
1197 	/* DTD uses this as default */
1198 	strcpy(concat, "BOOKTITLE");
1199       }
1200     }
1201     else if (strcmp(ptr_el->elname, "USERDEF") == 0) {
1202       ptr_attr = get_ancestor_attr(ptr_el, "USERDEF", "ROLE");
1203       if (ptr_attr && strcmp(ptr_attr, "2") == 0) {
1204 	strcpy(concat, "USERDEF2");
1205       }
1206       else if (ptr_attr && strcmp(ptr_attr, "3") == 0) {
1207 	strcpy(concat, "USERDEF3");
1208       }
1209       else if (ptr_attr && strcmp(ptr_attr, "4") == 0) {
1210 	strcpy(concat, "USERDEF4");
1211       }
1212       else if (ptr_attr && strcmp(ptr_attr, "5") == 0) {
1213 	strcpy(concat, "USERDEF5");
1214       }
1215       else {
1216 	strcpy(concat, "USERDEF1");
1217       }
1218     }
1219     else if (strcmp(ptr_el->elname, "LINK") == 0) {
1220       ptr_attr = get_ancestor_attr(ptr_el, "LINK", "ROLE");
1221       if (ptr_attr && strcmp(ptr_attr, "1") == 0) {
1222 	strcpy(concat, "LINK1");
1223       }
1224       else if (ptr_attr && strcmp(ptr_attr, "2") == 0) {
1225 	strcpy(concat, "LINK2");
1226       }
1227       else if (ptr_attr && strcmp(ptr_attr, "3") == 0) {
1228 	strcpy(concat, "LINK3");
1229       }
1230       else if (ptr_attr && strcmp(ptr_attr, "4") == 0) {
1231 	strcpy(concat, "LINK4");
1232       }
1233       else {
1234 	strcpy(concat, "LINK0");
1235       }
1236     }
1237     /* in all other cases we can simply use the element name */
1238     else {
1239       strcpy(concat, ptr_el->elname);
1240     }
1241     strcat(concat, buffer);
1242     ptr_el = ptr_el->ptr_next;
1243   }
1244   return concat;
1245 }
1246 
1247 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1248   delete_list(): deletes the linked element list and the associated
1249                  attribute lists. This is to free the memory in case
1250                  of an error
1251 
1252   void delete_list
1253 
1254   struct elstack* ptr_current_element ptr to the first entry in the
1255                   linked list
1256 
1257   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
delete_list(struct elstack * ptr_current_element)1258 void delete_list(struct elstack* ptr_current_element) {
1259   struct elstack* ptr_el;
1260   struct attrlist* ptr_attr;
1261   struct elstack* ptr_el_next;
1262   struct attrlist* ptr_attr_next;
1263 
1264   ptr_el = ptr_current_element;
1265 
1266   while (ptr_el != NULL) {
1267     ptr_attr = ptr_el->ptr_attr_first;
1268 
1269     while (ptr_attr != NULL) {
1270       ptr_attr_next = ptr_attr->ptr_next;
1271       free(ptr_attr);
1272       ptr_attr = ptr_attr_next;
1273     }
1274     ptr_el_next = ptr_el->ptr_next;
1275     free(ptr_el);
1276     ptr_el = ptr_el_next;
1277   }
1278 }
1279 
1280 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1281   id_start_handler(): handler for start tags (handling citation/xref
1282                       data)
1283 
1284   void start_handler has no return value
1285 
1286   void* ptr_data this is a ptr to "non-global" global data that all
1287              handlers share - will be cast to type struct getbib_data*
1288 
1289   const char *el ptr to a string containing the element name
1290 
1291   const char** ptr_attr ptr to an array of attributes (name-value pairs)
1292 
1293   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
id_start_handler(void * ptr_data,const char * el,const char ** ptr_attr)1294 void id_start_handler(void *ptr_data, const char *el, const char **ptr_attr) {
1295   struct simple_elstack* ptr_el_new;
1296   struct getbib_data* ptr_gbdata;
1297 
1298   ptr_gbdata = (struct getbib_data*)ptr_data;
1299 
1300   /* add current element to element stack */
1301   ptr_el_new = malloc(sizeof(struct simple_elstack));
1302   if (ptr_el_new == NULL) {
1303     (*(ptr_gbdata->ptr_nmem_error))++;
1304   }
1305   else {
1306     /*    printf("have memory\n"); */
1307     strncpy(ptr_el_new->elname, el, 63);
1308     ptr_el_new->elname[63] = '\0'; /* terminate just in case */
1309     ptr_el_new->elvalue = malloc(256); /* something to start with */
1310     if (ptr_el_new->elvalue == NULL) {
1311       (*(ptr_gbdata->ptr_nmem_error))++;
1312     }
1313     else {
1314       ptr_el_new->elvalue[0] = '\0';
1315       ptr_el_new->ptr_snext = ptr_gbdata->ptr_sfirst;
1316       ptr_gbdata->ptr_sfirst = ptr_el_new;
1317     }
1318     /*    printf("%s", ptr_first->elname); */
1319 
1320     /* add attribute */
1321     if (ptr_attr[0] && ptr_attr[1]) {
1322       ptr_el_new->attrvalue = mstrdup((char*)ptr_attr[1]);
1323       if (!ptr_el_new->attrvalue) {
1324 	(*(ptr_gbdata->ptr_nmem_error))++;
1325       }
1326     }
1327     else {
1328       ptr_el_new->attrvalue = NULL;
1329     }
1330   }
1331 }
1332 
1333 
1334 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1335   id_end_handler(): handler for end tags (handling citation/xref data)
1336 
1337   void end_handler has no return value
1338 
1339   void* ptr_data this is a ptr to "non-global" global data that all
1340              handlers share - will be cast to type struct getbib_data*
1341 
1342   const char *el ptr to a string containing the element name
1343 
1344   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
id_end_handler(void * ptr_data,const char * el)1345 void id_end_handler(void *ptr_data, const char *el) {
1346   size_t sql_command_len;
1347   int nis_multi = 0;
1348   int errcode; /* receives error code for periodical requests */
1349   char buffer[32];
1350   char* database = "";
1351   char* id_string;
1352   char* multi_id_string;
1353   char* multi_database = "";
1354   char* sql_command;
1355   char* new_sql_command;
1356   const char* query_result;
1357   char* new_el;
1358   char* new_elvalue;
1359   char* new_id;
1360   char* new_attrvalue = NULL;
1361   char* item;
1362   char* reftype = NULL;
1363   char* my_aempty = NULL;
1364   char *my_refdb_title = NULL;
1365   char* escape_buffer;
1366   char titlespec[16];
1367   char periodical[256] = "";
1368   const char *drivername; /* name of the libdbi driver */
1369   int use_title_as_author = 0;
1370   unsigned long long temp_id = 0;
1371   unsigned long long real_orig_id = 0;
1372   dbi_conn conn_source = NULL;
1373   dbi_result dbires;
1374   dbi_result dbires1;
1375   struct getbib_data* ptr_gbdata;
1376   struct simple_elstack* ptr_el_remove;
1377 
1378   ptr_gbdata = (struct getbib_data*)ptr_data;
1379 
1380   drivername = dbi_driver_get_name(dbi_conn_get_driver(ptr_gbdata->conn));
1381 
1382   if ((new_el = mstrdup((char*)el)) == NULL) {
1383     (*(ptr_gbdata->ptr_nmem_error))++;
1384     return;
1385   }
1386 
1387   strup(new_el);
1388 
1389   if ((new_elvalue = mstrdup((char*)((ptr_gbdata->ptr_sfirst)->elvalue))) == NULL) {
1390     (*(ptr_gbdata->ptr_nmem_error))++;
1391     return;
1392   }
1393 
1394   if ((ptr_gbdata->ptr_sfirst)->attrvalue && (new_attrvalue = mstrdup((char*)((ptr_gbdata->ptr_sfirst)->attrvalue))) == NULL) {
1395     (*(ptr_gbdata->ptr_nmem_error))++;
1396     return;
1397   }
1398 
1399 
1400   if (strcmp(new_el, "XREF") == 0) {
1401     sql_command_len = 512;
1402     if ((sql_command = malloc(sql_command_len)) == NULL) {
1403       (*(ptr_gbdata->ptr_nmem_error))++;
1404       return;
1405     }
1406 /*     strup((ptr_gbdata->ptr_sfirst)->elvalue); */
1407     id_string = getid((ptr_gbdata->ptr_sfirst)->elvalue, &database, &nis_multi);
1408 
1409     nis_multi = 0; /* protects against malformed linkends */
1410     if ((ptr_gbdata->ptr_sfirst)->attrvalue) {
1411       multi_id_string = getid((ptr_gbdata->ptr_sfirst)->attrvalue, &multi_database, &nis_multi);
1412     }
1413 
1414     if (database) {
1415       strdn(database); /* use lowercase name */
1416     }
1417     else {
1418       database = ptr_gbdata->ptr_default_db; /* use default database */
1419     }
1420 
1421 
1422     /* check whether orig_id is numerical */
1423     if (!is_number(id_string)) {
1424       /* retrieve corresponding ID for this citekey */
1425       if (!strcmp(my_dbi_conn_get_cap(ptr_gbdata->conn, "multiple_db"), "t")) {
1426 	sprintf(sql_command, "SELECT refdb_id, refdb_type FROM %s.t_refdb WHERE refdb_citekey='%s' AND refdb_type!='DUMMY'", database, id_string);
1427 	dbires = dbi_conn_query(ptr_gbdata->conn, sql_command);
1428       }
1429       else {
1430 	/* get additional connection */
1431 	if ((conn_source = connect_to_db(ptr_gbdata->ptr_clrequest, database, 0)) == NULL) {
1432 	  LOG_PRINT(LOG_ERR, get_status_msg(205));
1433 	  return;
1434 	}
1435 	sprintf(sql_command, "SELECT refdb_id, refdb_type FROM t_refdb WHERE refdb_citekey='%s' AND refdb_type!='DUMMY'", id_string);
1436 	dbires = dbi_conn_query(conn_source, sql_command);
1437       }
1438 
1439       LOG_PRINT(LOG_DEBUG, sql_command);
1440       if (!dbires) {
1441 	LOG_PRINT(LOG_WARNING, "select failed");
1442 	(*(ptr_gbdata->ptr_ndb_error))++;
1443 	real_orig_id = 0;
1444       }
1445       else {
1446 	if (dbi_result_next_row(dbires)) {
1447 	  real_orig_id = my_dbi_result_get_idval(dbires, "refdb_id");
1448 	  reftype = my_dbi_result_get_string_copy(dbires, "refdb_type");
1449 	}
1450 	else {
1451 	  real_orig_id = 0;
1452 	}
1453 	dbi_result_free(dbires);
1454       }
1455       if (strcmp(my_dbi_conn_get_cap(ptr_gbdata->conn, "multiple_db"), "t") && conn_source) {
1456 	dbi_conn_close(conn_source);
1457       }
1458     }
1459     else { /* if id is numeric */
1460       /* we still have to query the database as the dataset may be missing */
1461       if (!strcmp(my_dbi_conn_get_cap(ptr_gbdata->conn, "multiple_db"), "t")) {
1462 	sprintf(sql_command, "SELECT refdb_id, refdb_type FROM %s.t_refdb WHERE refdb_id='%s' AND refdb_type!='DUMMY'", database, id_string);
1463 	dbires = dbi_conn_query(ptr_gbdata->conn, sql_command);
1464       }
1465       else {
1466 	/* get additional connection */
1467 	if ((conn_source = connect_to_db(ptr_gbdata->ptr_clrequest, database, 0)) == NULL) {
1468 	  LOG_PRINT(LOG_ERR, get_status_msg(205));
1469 	  return;
1470 	}
1471 	sprintf(sql_command, "SELECT refdb_id, refdb_type FROM t_refdb WHERE refdb_id='%s' AND refdb_type!='DUMMY'", id_string);
1472 	dbires = dbi_conn_query(conn_source, sql_command);
1473       }
1474 
1475       LOG_PRINT(LOG_DEBUG, sql_command);
1476 
1477       if (!dbires) {
1478 	LOG_PRINT(LOG_WARNING, "select failed");
1479 	(*(ptr_gbdata->ptr_ndb_error))++;
1480 	real_orig_id = 0;
1481       }
1482       else {
1483 	if (dbi_result_next_row(dbires)) {
1484 	  real_orig_id = my_dbi_result_get_idval(dbires, "refdb_id");
1485 	  reftype = my_dbi_result_get_string_copy(dbires, "refdb_type");
1486 	}
1487 	else {
1488 	  real_orig_id = 0;
1489 	}
1490 	dbi_result_free(dbires);
1491       }
1492 
1493       if (strcmp(my_dbi_conn_get_cap(ptr_gbdata->conn, "multiple_db"), "t") && conn_source) {
1494 	dbi_conn_close(conn_source);
1495       }
1496     } /* end if numerical */
1497 
1498 
1499     if (real_orig_id) {
1500       if (nis_multi) { /* true only if a correct endterm was encountered */
1501 	if ((new_id = mstrcpy(ptr_gbdata->ptr_curr_multi_id, new_attrvalue, ptr_gbdata->ptr_cmid_len)) == NULL) {
1502 	  (*(ptr_gbdata->ptr_nmem_error))++;
1503 	  return;
1504 	}
1505 	else {
1506 	  ptr_gbdata->ptr_curr_multi_id = new_id;
1507 	}
1508 	free(reftype);
1509       }
1510       else {
1511 	if (id_string != NULL) {
1512 	  dbi_driver driver;
1513 
1514 	  /* see whether the style requests to use titles in place of
1515 	     missing authors. The style should have the ALTERNATETEXT
1516 	     attribute set to TITLEPART, TITLEPUB, TITLESERIES, or
1517 	     TITLEALL (the latter meaning the first available */
1518 	  if (!strcmp(my_dbi_conn_get_cap(ptr_gbdata->conn_refdb, "multiple_db"), "t")) {
1519 	    sprintf(sql_command, "SELECT QAEMPTY,XAEMPTY,QALTERNATETEXT,XALTERNATETEXT FROM %s.REFSTYLE INNER JOIN %s.CITSTYLE ON REFSTYLE.CITSTYLEID=CITSTYLE.ID WHERE REFSTYLE.PUBTYPE='%s' AND JOURNAL=%s", main_db, main_db, reftype, ptr_gbdata->quoted_journal);
1520 	  }
1521 	  else {
1522 	    sprintf(sql_command, "SELECT QAEMPTY,XAEMPTY,QALTERNATETEXT,XALTERNATETEXT FROM REFSTYLE INNER JOIN CITSTYLE ON REFSTYLE.CITSTYLEID=CITSTYLE.ID WHERE REFSTYLE.PUBTYPE='%s' AND JOURNAL=%s", reftype, ptr_gbdata->quoted_journal);
1523 	  }
1524 
1525 	  LOG_PRINT(LOG_DEBUG, sql_command);
1526 	  dbires = dbi_conn_query(ptr_gbdata->conn_refdb, sql_command);
1527 	  if (!dbires) {
1528 	    LOG_PRINT(LOG_WARNING, "accessing style data failed");
1529 	    (*(ptr_gbdata->ptr_ndb_error))++;
1530 	  }
1531 	  else {
1532 	    if ((use_title_as_author = set_alternatetext(dbires, &my_aempty)) == -1) {
1533 	      /* try GEN instead */
1534 	      dbi_result_free(dbires);
1535 	      if (!strcmp(my_dbi_conn_get_cap(ptr_gbdata->conn_refdb, "multiple_db"), "t")) {
1536 		sprintf(sql_command, "SELECT QAEMPTY,XAEMPTY,QALTERNATETEXT,XALTERNATETEXT FROM %s.REFSTYLE INNER JOIN %s.CITSTYLE ON REFSTYLE.CITSTYLEID=CITSTYLE.ID WHERE REFSTYLE.PUBTYPE='GEN' AND JOURNAL=%s", main_db, main_db, ptr_gbdata->quoted_journal);
1537 	      }
1538 	      else {
1539 		sprintf(sql_command, "SELECT QAEMPTY,XAEMPTY,QALTERNATETEXT,XALTERNATETEXT FROM REFSTYLE INNER JOIN CITSTYLE ON REFSTYLE.CITSTYLEID=CITSTYLE.ID WHERE REFSTYLE.PUBTYPE='GEN' AND JOURNAL=%s", ptr_gbdata->quoted_journal);
1540 	      }
1541 
1542 	      LOG_PRINT(LOG_DEBUG, sql_command);
1543 	      dbires = dbi_conn_query(ptr_gbdata->conn_refdb, sql_command);
1544 	      if (!dbires) {
1545 		LOG_PRINT(LOG_WARNING, "accessing style data failed");
1546 		(*(ptr_gbdata->ptr_ndb_error))++;
1547 	      }
1548 	      else {
1549 		if ((use_title_as_author = set_alternatetext(dbires, &my_aempty)) == -1) {
1550 		  (*(ptr_gbdata->ptr_nmem_error))++;
1551 		}
1552 	      }
1553 	    }
1554 	    dbi_result_free(dbires);
1555 	  } /* end if have result */
1556 
1557 
1558 
1559 
1560 	  if (!has_part_data(reftype)) {
1561 	    strcpy(titlespec, "refdb_booktitle");
1562 	  }
1563 	  else {
1564 	    strcpy(titlespec, "refdb_title");
1565 	  }
1566 	  free(reftype);
1567 
1568 	  driver = dbi_conn_get_driver(ptr_gbdata->conn);
1569 
1570 	  /* select items and stash them into the temporary table */
1571 	  /* all fields that we can get directly from t_refdb */
1572 	  /* create a new row with INSERT */
1573 	  if (!strcmp(my_dbi_conn_get_cap(ptr_gbdata->conn, "multiple_db"), "t")) {
1574 	    sprintf(sql_command, "INSERT INTO %s (article_title,volume,issue,startpage,pubyear, citekey) SELECT %s,refdb_volume,refdb_issue,refdb_startpage,refdb_pubyear, refdb_citekey FROM %s.t_refdb WHERE refdb_id="ULLSPEC, ptr_gbdata->ptr_table_name, titlespec, database, (unsigned long long)real_orig_id);
1575 	    LOG_PRINT(LOG_DEBUG, sql_command);
1576 	    dbires = dbi_conn_query(ptr_gbdata->conn, sql_command);
1577 	    if (!dbires) {
1578 	      LOG_PRINT(LOG_WARNING, "temp table insert failed");
1579 	      (*(ptr_gbdata->ptr_ndb_error))++;
1580 	    }
1581 	    else {
1582 	      dbi_result_free(dbires);
1583 	    }
1584 
1585 	    /* save new temp id */
1586 	    temp_id = dbi_conn_sequence_last(ptr_gbdata->conn, NULL);
1587 
1588 	    /* get refdb_title separately, as we need it further down */
1589 	    sprintf(sql_command, "SELECT %s,refdb_volume,refdb_issue,refdb_startpage,refdb_pubyear, refdb_citekey FROM t_refdb WHERE refdb_id="ULLSPEC, titlespec, (unsigned long long)real_orig_id);
1590 	    LOG_PRINT(LOG_DEBUG, sql_command);
1591 	    dbires = dbi_conn_query(ptr_gbdata->conn, sql_command);
1592 	    if (!dbires) {
1593 	      LOG_PRINT(LOG_WARNING, "source table select failed");
1594 	      (*(ptr_gbdata->ptr_ndb_error))++;
1595 	    }
1596 	    else {
1597 	      if (dbi_result_next_row(dbires)) {
1598 		my_refdb_title = my_dbi_result_get_string_copy(dbires, titlespec);
1599 		/* the quote_string function checks for non-NULL arguments */
1600 		dbi_conn_quote_string(ptr_gbdata->conn, &my_refdb_title);
1601 	      }
1602 	    }
1603 	  }
1604 	  else {
1605 	    /* we've got a small problem here: we can't select values from
1606 	       one database and insert it into another with a single command
1607 	       Instead we've got to do it the hard way */
1608 
1609 	    /* get a connection to the source database */
1610 	    if ((conn_source = connect_to_db(ptr_gbdata->ptr_clrequest, database, 0)) == NULL) {
1611 	      LOG_PRINT(LOG_ERR, get_status_msg(205));
1612 	      return;
1613 	    }
1614 	    sprintf(sql_command, "SELECT %s,refdb_volume,refdb_issue,refdb_startpage,refdb_pubyear, refdb_citekey FROM t_refdb WHERE refdb_id="ULLSPEC, titlespec, (unsigned long long)real_orig_id);
1615 	    LOG_PRINT(LOG_DEBUG, sql_command);
1616 	    dbires = dbi_conn_query(conn_source, sql_command);
1617 	    if (!dbires) {
1618 	      LOG_PRINT(LOG_WARNING, "source table select failed");
1619 	      (*(ptr_gbdata->ptr_ndb_error))++;
1620 	    }
1621 	    else {
1622 	      if (dbi_result_next_row(dbires)) {
1623 		/* get strings quoted properly */
1624 		char *my_refdb_volume;
1625 		char *my_refdb_issue;
1626 		char *my_refdb_startpage;
1627 		char *my_refdb_citekey;
1628 
1629 		my_refdb_title = my_dbi_result_get_string_copy(dbires, titlespec);
1630 		my_refdb_volume = my_dbi_result_get_string_copy(dbires, "refdb_volume");
1631 		my_refdb_issue = my_dbi_result_get_string_copy(dbires, "refdb_issue");
1632 		my_refdb_startpage = my_dbi_result_get_string_copy(dbires, "refdb_startpage");
1633 		my_refdb_citekey = my_dbi_result_get_string_copy(dbires, "refdb_citekey");
1634 
1635 		/* the quote_string function checks for non-NULL arguments */
1636 		dbi_conn_quote_string(ptr_gbdata->conn, &my_refdb_title);
1637 		dbi_conn_quote_string(ptr_gbdata->conn, &my_refdb_volume);
1638 		dbi_conn_quote_string(ptr_gbdata->conn, &my_refdb_issue);
1639 		dbi_conn_quote_string(ptr_gbdata->conn, &my_refdb_startpage);
1640 		dbi_conn_quote_string(ptr_gbdata->conn, &my_refdb_citekey);
1641 
1642 		sprintf(sql_command, "INSERT INTO %s (article_title,volume,issue,startpage,pubyear, citekey) VALUES (%s,%s,%s,%s,%d, %s)", ptr_gbdata->ptr_table_name, (my_refdb_title) ? my_refdb_title : "\'\'", (my_refdb_volume) ? my_refdb_volume : "\'\'", (my_refdb_issue) ? my_refdb_issue : "\'\'", (my_refdb_startpage) ? my_refdb_startpage : "\'\'", dbi_result_get_short(dbires, "refdb_pubyear"), (my_refdb_citekey) ? my_refdb_citekey : "\'\'");
1643 		LOG_PRINT(LOG_DEBUG, sql_command);
1644 
1645 		if (my_refdb_volume) {
1646 		  free(my_refdb_volume);
1647 		}
1648 		if (my_refdb_issue) {
1649 		  free(my_refdb_issue);
1650 		}
1651 		if (my_refdb_startpage) {
1652 		  free(my_refdb_startpage);
1653 		}
1654 
1655 		dbires1 = dbi_conn_query(ptr_gbdata->conn, sql_command);
1656 		if (!dbires1) {
1657 		  LOG_PRINT(LOG_WARNING, "temp table insert failed");
1658 		  (*(ptr_gbdata->ptr_ndb_error))++;
1659 		}
1660 		else {
1661 		  dbi_result_free(dbires1);
1662 		}
1663 		/* save new temp id */
1664 		temp_id = dbi_conn_sequence_last(ptr_gbdata->conn, "getbibtemp_id_seq");
1665 	      }
1666 	      dbi_result_free(dbires);
1667 	    }
1668 	  }
1669 
1670 	  /* dbname, orig_id, entry_id  */
1671 	  sprintf(sql_command, "UPDATE %s SET dbname='%s',citation_pos=%d,xref_pos=%d,orig_id="ULLSPEC",entry_id='%s', multi_id='%s' WHERE id="ULLSPEC, ptr_gbdata->ptr_table_name, database, *(ptr_gbdata->ptr_citation_count), *(ptr_gbdata->ptr_xref_count), (unsigned long long)real_orig_id, new_elvalue, ptr_gbdata->ptr_curr_multi_id, (unsigned long long)temp_id);
1672 	  LOG_PRINT(LOG_DEBUG, sql_command);
1673 	  dbires = dbi_conn_query(ptr_gbdata->conn, sql_command);
1674 	  if (!dbires) {
1675 	    LOG_PRINT(LOG_WARNING, "temp table insert failed");
1676 	    (*(ptr_gbdata->ptr_ndb_error))++;
1677 	  }
1678 	  else {
1679 	    dbi_result_free(dbires);
1680 
1681 	    /* author_concat */
1682 	    sprintf(sql_command, "UPDATE %s SET author_concat=\'", ptr_gbdata->ptr_table_name);
1683 
1684 	    if (!strcmp(my_dbi_conn_get_cap(ptr_gbdata->conn, "multiple_db"), "t")) {
1685 	      dbires1 = request_authors(ptr_gbdata->conn, 4 /* first available */, NULL /* all roles */, database, 0, real_orig_id);
1686 	    }
1687 	    else {
1688 	      dbires1 = request_authors(conn_source, 4 /* first available */, NULL /* all roles */, NULL, 0, real_orig_id);
1689 	    }
1690 	    if (!dbires1) {
1691 	      LOG_PRINT(LOG_WARNING, "temp table author query failed");
1692 	      (*(ptr_gbdata->ptr_ndb_error))++;
1693 	    }
1694 	    else {
1695 	      if (!get_num_authors(dbires1)) {
1696 /*  		printf("num_authors went to zero\n");  */
1697 		/* if no authors, use AEMPTY or title here */
1698 		if (my_aempty) {
1699 /*  		  printf("use xaempty %s\n", my_aempty);  */
1700 		  /* my_aempty is quoted, but we need only the
1701 		     internal quotes */
1702 		  my_aempty[strlen(my_aempty)-1] = '\0';
1703 		  if ((new_sql_command = mstrcat(sql_command, my_aempty + 1, &sql_command_len, 0)) == NULL) {
1704 		    (*(ptr_gbdata->ptr_nmem_error))++;
1705 		  }
1706 		  else {
1707 		    sql_command = new_sql_command;
1708 		  }
1709 		}
1710 		/* todo: make sure title is used */
1711 		else if (use_title_as_author) {
1712 /*  		  printf("use qtitle %s\n", my_refdb_title);  */
1713 		  if (my_refdb_title) {
1714 		    /* my_refdb_title is quoted, but we need only the
1715 		     internal quotes */
1716 		    my_refdb_title[strlen(my_refdb_title)-1] = '\0';
1717 		    if ((new_sql_command = mstrcat(sql_command, my_refdb_title + 1, &sql_command_len, 0)) == NULL) {
1718 		      (*(ptr_gbdata->ptr_nmem_error))++;
1719 		    }
1720 		    else {
1721 		      sql_command = new_sql_command;
1722 		    }
1723 		  }
1724 		}
1725 		else {
1726 /* 		  printf("do nothing\n"); */
1727 		}
1728 	      }
1729 	      else { /* have authors */
1730 /* 		printf("have at least one author\n"); */
1731 		/* reset */
1732 		use_title_as_author = 0;
1733 		while ((query_result = get_author(dbires1)) != NULL) {
1734 		  char *author_q;
1735 
1736 		  author_q = strdup(query_result);
1737 		  if (!author_q || dbi_conn_quote_string(ptr_gbdata->conn, &author_q) == 0) {
1738 		    LOG_PRINT(LOG_WARNING, "out of memory");
1739 		    (*(ptr_gbdata->ptr_nmem_error))++;
1740 		  }
1741 		  else if (*author_q) {
1742 		    /* the quoted author is enclosed in quotes (who
1743 		       would have thought?) but we don't need these
1744 		       here; we need only the internal quotes */
1745 		    author_q[strlen(author_q)-1] = '\0';
1746 
1747 		    if ((new_sql_command = mstrcat(sql_command, author_q + 1, &sql_command_len, 0)) == NULL) {
1748 		      (*(ptr_gbdata->ptr_nmem_error))++;
1749 		      break;
1750 		    }
1751 		    else {
1752 		      sql_command = new_sql_command;
1753 		    }
1754 
1755 		    free(author_q);
1756 		  } /* end if no mem error */
1757 		} /* end while have author */
1758 	      } /* end if have authors */
1759 
1760 	      if (use_title_as_author && my_refdb_title) {
1761 		char buffer[64];
1762 
1763 		sprintf(buffer, "\', title_as_author=%d WHERE id=", use_title_as_author);
1764 		if ((new_sql_command = mstrcat(sql_command, buffer, &sql_command_len, 0)) == NULL) {
1765 		  (*(ptr_gbdata->ptr_nmem_error))++;
1766 		}
1767 		else {
1768 		  sql_command = new_sql_command;
1769 		}
1770 	      }
1771 	      else {
1772 		/* title_as_author has a default of 0, no need to alter it */
1773 		if ((new_sql_command = mstrcat(sql_command, "\' WHERE id=", &sql_command_len, 0)) == NULL) {
1774 		  (*(ptr_gbdata->ptr_nmem_error))++;
1775 		}
1776 		else {
1777 		  sql_command = new_sql_command;
1778 		}
1779 	      }
1780 	      clean_request(dbires1);
1781 
1782 	      sprintf(buffer, ULLSPEC, (unsigned long long)temp_id);
1783 	      if ((new_sql_command = mstrcat(sql_command, buffer, &sql_command_len, 0)) == NULL) {
1784 		(*(ptr_gbdata->ptr_nmem_error))++;
1785 	      }
1786 	      else {
1787 		sql_command = new_sql_command;
1788 		LOG_PRINT(LOG_DEBUG, sql_command);
1789 		dbires1 = dbi_conn_query(ptr_gbdata->conn, sql_command);
1790 		if (!dbires1) {
1791 		  LOG_PRINT(LOG_WARNING, "temp table insert failed");
1792 		  (*(ptr_gbdata->ptr_ndb_error))++;
1793 		}
1794 		dbi_result_free(dbires1);
1795 	      }
1796 	    }
1797 	  }
1798 
1799 	  if (my_refdb_title) {
1800 	    free(my_refdb_title);
1801 	  }
1802 
1803 	  /* journal */
1804 	  sprintf(sql_command, "UPDATE %s SET periodical=", ptr_gbdata->ptr_table_name);
1805 
1806 	  if (!strcmp(my_dbi_conn_get_cap(ptr_gbdata->conn, "multiple_db"), "t")) {
1807 	    item = get_periodical(ptr_gbdata->conn, periodical, database, 4, &errcode, 0, real_orig_id, NULL /* no frequency required */);
1808 	  }
1809 	  else {
1810 	    item = get_periodical(conn_source, periodical, NULL, 4, &errcode, 0, real_orig_id, NULL /* no frequency required */);
1811 	  }
1812 
1813 	  if (!item && errcode != 1) {
1814 	    LOG_PRINT(LOG_WARNING, "temp table periodical query failed");
1815 	    (*(ptr_gbdata->ptr_ndb_error))++;
1816 	  }
1817 	  else if (!errcode) {
1818 	    if (*periodical) {
1819 /* 	      printf("periodical went to:%s<<\n", periodical); */
1820 	      /* string is short enough, don't need mstrcat here */
1821 	      escape_buffer = strdup(item);
1822 
1823 	      if (!escape_buffer) {
1824 		LOG_PRINT(LOG_WARNING, "malloc failed");
1825 		(*(ptr_gbdata->ptr_nmem_error))++;
1826 	      }
1827 
1828 	      /* escape any characters that the database server cannot digest */
1829 	      if (dbi_conn_quote_string(ptr_gbdata->conn, &escape_buffer) == 0) {
1830 		LOG_PRINT(LOG_WARNING, "out of memory");
1831 		(*(ptr_gbdata->ptr_nmem_error))++;
1832 	      }
1833 
1834 /* 	      printf("escape_buffer went to:%s<<\n", escape_buffer); */
1835 	      strcat(sql_command, escape_buffer);
1836 	      free(escape_buffer);
1837 	    }
1838 	    strcat(sql_command, " WHERE id=");
1839 	    /* buffer still has temp_id*/
1840 	    strcat(sql_command, buffer);
1841 	    LOG_PRINT(LOG_DEBUG, sql_command);
1842 	    dbires = dbi_conn_query(ptr_gbdata->conn, sql_command);
1843 	    if (!dbires) {
1844 	      LOG_PRINT(LOG_WARNING, "temp table insert failed");
1845 	      (*(ptr_gbdata->ptr_ndb_error))++;
1846 	    }
1847 	    dbi_result_free(dbires);
1848 	  }
1849 
1850 	  /* close extra connection */
1851 	  if (strcmp(my_dbi_conn_get_cap(ptr_gbdata->conn, "multiple_db"), "t") && conn_source) {
1852 	    dbi_conn_close(conn_source);
1853 	  }
1854 	}
1855 	(*(ptr_gbdata->ptr_xref_count))++;
1856       }
1857     }
1858     else { /* ID not found */
1859       /* don't count the first dummy citation in a multiple citation */
1860       if (!nis_multi) {
1861 	/* requested ref is not in the database */
1862 	(*(ptr_gbdata->ptr_ndb_notfound))++;
1863 
1864 	/* add ID or citation key to the linked list of unfound stuff */
1865 	if (append_lilifstring(ptr_gbdata->ptr_notfound_first, id_string)) {
1866 	  (*(ptr_gbdata->ptr_ndb_error))++;
1867 	}
1868       }
1869     }
1870 
1871     free(sql_command);
1872   }
1873   else if (strcmp(new_el, "CITATION") == 0) {
1874     (*(ptr_gbdata->ptr_citation_count))++;
1875     (*(ptr_gbdata->ptr_xref_count)) = 0;
1876 
1877     /* reset multi-id */
1878     (ptr_gbdata->ptr_curr_multi_id)[0] = '\0';
1879   } /* end if XREF or CITATION */
1880 
1881   /* remove current element from element stack */
1882   ptr_el_remove = ptr_gbdata->ptr_sfirst;
1883   ptr_gbdata->ptr_sfirst = (ptr_gbdata->ptr_sfirst)->ptr_snext;
1884   free(ptr_el_remove->elvalue);
1885   if (ptr_el_remove->attrvalue) {
1886     free(ptr_el_remove->attrvalue);
1887   }
1888   free(ptr_el_remove);
1889 
1890   free(new_el);
1891   free(new_elvalue);
1892 }
1893 
1894 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1895   id_char_handler(): handler for character data (getref).
1896 
1897   void char_handler has no return value
1898 
1899   void* ptr_data this is a ptr to "non-global" global data that all
1900              handlers share - will be cast to type struct getbib_data*
1901 
1902   const char *string ptr to a string containing the char data
1903                      this string is not \0 terminated!
1904 
1905   int len length length of string
1906 
1907   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
id_char_handler(void * ptr_data,const char * string,int len)1908 void id_char_handler(void *ptr_data, const char *string, int len) {
1909   struct getbib_data* ptr_gbdata;
1910   char *term_string;
1911   char *new_string;
1912 
1913   ptr_gbdata = (struct getbib_data*)ptr_data;
1914 
1915   if (*(ptr_gbdata->ptr_ndb_error) || *(ptr_gbdata->ptr_nmem_error)) {
1916     return;
1917   }
1918 
1919   term_string = malloc(len+1);
1920   if (!term_string) {
1921     (*(ptr_gbdata->ptr_nmem_error))++;
1922     return;
1923   }
1924 
1925   strncpy(term_string, string, len);
1926   term_string[len] = '\0';
1927 
1928   if ((new_string = mstrcat((ptr_gbdata->ptr_sfirst)->elvalue, term_string, ptr_gbdata->ptr_cmid_len, 0)) == NULL) {
1929     free(term_string);
1930     (*(ptr_gbdata->ptr_nmem_error))++;
1931     return;
1932   }
1933   else {
1934     (ptr_gbdata->ptr_sfirst)->elvalue = new_string;
1935     free(term_string);
1936   }
1937 /*    printf(">>%s\n", ptr_first->elvalue); */
1938 }
1939 
1940 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1941   idraw_start_handler(): handler for start tags (handling citation/xref
1942                       data for raw bibliographies)
1943 
1944   void idraw_start_handler has no return value
1945 
1946   void* ptr_data this is a ptr to "non-global" global data that all
1947              handlers share - will be cast to type struct getbib_data*
1948 
1949   const char *el ptr to a string containing the element name
1950 
1951   const char** ptr_attr ptr to an array of attributes (name-value pairs)
1952 
1953   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
idraw_start_handler(void * ptr_data,const char * el,const char ** ptr_attr)1954 void idraw_start_handler(void *ptr_data, const char *el, const char **ptr_attr) {
1955   struct simple_elstack* ptr_el_new;
1956   struct getbib_data* ptr_gbdata;
1957 
1958   ptr_gbdata = (struct getbib_data*)ptr_data;
1959 
1960   /* add current element to element stack */
1961   ptr_el_new = malloc(sizeof(struct simple_elstack));
1962   if (ptr_el_new == NULL) {
1963     (*(ptr_gbdata->ptr_nmem_error))++;
1964   }
1965   else {
1966     /*    printf("have memory\n"); */
1967     strncpy(ptr_el_new->elname, el, 63);
1968     ptr_el_new->elname[63] = '\0'; /* terminate just in case */
1969     ptr_el_new->elvalue = malloc(256); /* something to start with */
1970     if (ptr_el_new->elvalue == NULL) {
1971       (*(ptr_gbdata->ptr_nmem_error))++;
1972     }
1973     else {
1974       ptr_el_new->elvalue[0] = '\0';
1975       ptr_el_new->ptr_snext = ptr_gbdata->ptr_sfirst;
1976       ptr_gbdata->ptr_sfirst = ptr_el_new;
1977     }
1978     /*    printf("%s", ptr_first->elname); */
1979 
1980     /* add attribute */
1981     if (ptr_attr[0] && ptr_attr[1]) {
1982       ptr_el_new->attrvalue = mstrdup((char*)ptr_attr[1]);
1983       if (!ptr_el_new->attrvalue) {
1984 	(*(ptr_gbdata->ptr_nmem_error))++;
1985       }
1986     }
1987     else {
1988       ptr_el_new->attrvalue = NULL;
1989     }
1990   }
1991 }
1992 
1993 
1994 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1995   idraw_end_handler(): handler for end tags (handling citation/xref data
1996                        for raw bibliographies)
1997 
1998   void idraw_end_handler has no return value
1999 
2000   void* ptr_data this is a ptr to "non-global" global data that all
2001              handlers share - will be cast to type struct getbib_data*
2002 
2003   const char *el ptr to a string containing the element name
2004 
2005   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
idraw_end_handler(void * ptr_data,const char * el)2006 void idraw_end_handler(void *ptr_data, const char *el) {
2007   size_t sql_command_len;
2008   int nis_multi = 0;
2009   char* database = "";
2010   char* id_string;
2011   char* multi_id_string;
2012   char* multi_database = "";
2013   char* sql_command;
2014   char* new_el;
2015   char* new_elvalue;
2016   char* new_attrvalue = NULL;
2017   char* reftype = NULL;
2018   const char *drivername; /* name of the libdbi driver */
2019   char* real_orig_citekey = NULL;
2020   dbi_conn conn_source = NULL;
2021   dbi_result dbires;
2022   struct getbib_data* ptr_gbdata;
2023   struct simple_elstack* ptr_el_remove;
2024 
2025   ptr_gbdata = (struct getbib_data*)ptr_data;
2026 
2027   drivername = dbi_driver_get_name(dbi_conn_get_driver(ptr_gbdata->conn));
2028 
2029   if ((new_el = mstrdup((char*)el)) == NULL) {
2030     (*(ptr_gbdata->ptr_nmem_error))++;
2031     return;
2032   }
2033 
2034   strup(new_el);
2035 
2036   if ((new_elvalue = mstrdup((char*)((ptr_gbdata->ptr_sfirst)->elvalue))) == NULL) {
2037     (*(ptr_gbdata->ptr_nmem_error))++;
2038     return;
2039   }
2040 
2041   if ((ptr_gbdata->ptr_sfirst)->attrvalue && (new_attrvalue = mstrdup((char*)((ptr_gbdata->ptr_sfirst)->attrvalue))) == NULL) {
2042     (*(ptr_gbdata->ptr_nmem_error))++;
2043     return;
2044   }
2045 
2046 
2047   if (strcmp(new_el, "XREF") == 0) {
2048     sql_command_len = 512;
2049     if ((sql_command = malloc(sql_command_len)) == NULL) {
2050       (*(ptr_gbdata->ptr_nmem_error))++;
2051       return;
2052     }
2053 
2054     id_string = getid((ptr_gbdata->ptr_sfirst)->elvalue, &database, &nis_multi);
2055 
2056     nis_multi = 0; /* protects against malformed linkends */
2057     if ((ptr_gbdata->ptr_sfirst)->attrvalue) {
2058       multi_id_string = getid((ptr_gbdata->ptr_sfirst)->attrvalue, &multi_database, &nis_multi);
2059     }
2060 
2061 /*     printf("id_string:%s<< nis_multi:%d<<\n", id_string, nis_multi); */
2062     if (nis_multi) {
2063       /* no need to add this one as the next xref contains the same ID */
2064       return;
2065     }
2066 
2067     if (database) {
2068       strdn(database); /* use lowercase name */
2069     }
2070     else {
2071       database = ptr_gbdata->ptr_default_db; /* use default database */
2072     }
2073 
2074     /* todo: use two lists for ids and citation keys to avoid database
2075        accesses here (don't care for redundant ID request), or
2076        retrieve ID of those identified by citation key and use a
2077        special linked list add command that eliminates duplicates? */
2078 
2079     /* if orig_id is numerical, retrieve the citation key. This
2080        assumes that most documents will use citation keys anyway, so
2081        that case will be handled most efficiently */
2082     if (is_number(id_string)) {
2083       if (!strcmp(my_dbi_conn_get_cap(ptr_gbdata->conn, "multiple_db"), "t")) {
2084 	sprintf(sql_command, "SELECT refdb_citekey, refdb_type FROM %s.t_refdb WHERE refdb_id='%s' AND refdb_type!='DUMMY'", database, id_string);
2085 	dbires = dbi_conn_query(ptr_gbdata->conn, sql_command);
2086       }
2087       else {
2088 	/* get additional connection */
2089 	if ((conn_source = connect_to_db(ptr_gbdata->ptr_clrequest, database, 0)) == NULL) {
2090 	  LOG_PRINT(LOG_ERR, get_status_msg(205));
2091 	  return;
2092 	}
2093 	sprintf(sql_command, "SELECT refdb_citekey, refdb_type FROM t_refdb WHERE refdb_id='%s' AND refdb_type!='DUMMY'", id_string);
2094 	dbires = dbi_conn_query(conn_source, sql_command);
2095       }
2096 
2097       LOG_PRINT(LOG_DEBUG, sql_command);
2098 
2099       if (!dbires) {
2100 	LOG_PRINT(LOG_WARNING, "select failed");
2101 	(*(ptr_gbdata->ptr_ndb_error))++;
2102       }
2103       else {
2104 	if (dbi_result_next_row(dbires)) {
2105 	  real_orig_citekey = dbi_result_get_string(dbires, "refdb_citekey");
2106 	  reftype = my_dbi_result_get_string_copy(dbires, "refdb_type");
2107 	}
2108 	dbi_result_free(dbires);
2109       }
2110 
2111       if (strcmp(my_dbi_conn_get_cap(ptr_gbdata->conn, "multiple_db"), "t") && conn_source) {
2112 	dbi_conn_close(conn_source);
2113       }
2114     } /* end if numerical */
2115     else {
2116       real_orig_citekey = id_string;
2117     }
2118 
2119     if (real_orig_citekey && *real_orig_citekey) {
2120       /* see whether this citation key is already in the list */
2121       if (!find_lilifstring(ptr_gbdata->ptr_found_first, real_orig_citekey)) {
2122 	(*(ptr_gbdata->ptr_xref_count))++;
2123 	/* add ID or citation key to the linked list of unfound stuff */
2124 	if (append_lilifstring(ptr_gbdata->ptr_found_first, real_orig_citekey)) {
2125 	  (*(ptr_gbdata->ptr_ndb_error))++;
2126 	}
2127       }
2128     }
2129     else { /* ID not found */
2130       /* add ID or citation key to the linked list of unfound stuff */
2131       if (append_lilifstring(ptr_gbdata->ptr_notfound_first, id_string)) {
2132 	(*(ptr_gbdata->ptr_ndb_error))++;
2133       }
2134     }
2135 
2136     free(sql_command);
2137   }
2138   else if (strcmp(new_el, "CITATION") == 0) {
2139     (*(ptr_gbdata->ptr_citation_count))++;
2140     (*(ptr_gbdata->ptr_xref_count)) = 0;
2141 
2142   } /* end if XREF or CITATION */
2143 
2144   /* remove current element from element stack */
2145   ptr_el_remove = ptr_gbdata->ptr_sfirst;
2146   ptr_gbdata->ptr_sfirst = (ptr_gbdata->ptr_sfirst)->ptr_snext;
2147   free(ptr_el_remove->elvalue);
2148   if (ptr_el_remove->attrvalue) {
2149     free(ptr_el_remove->attrvalue);
2150   }
2151   free(ptr_el_remove);
2152 
2153   free(new_el);
2154   free(new_elvalue);
2155 }
2156 
2157 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2158   idraw_char_handler(): handler for character data (ID data for raw
2159                         bibliographies).
2160 
2161   void idraw_char_handler has no return value
2162 
2163   void* ptr_data this is a ptr to "non-global" global data that all
2164              handlers share - will be cast to type struct getbib_data*
2165 
2166   const char *string ptr to a string containing the char data
2167                      this string is not \0 terminated!
2168 
2169   int len length length of string
2170 
2171   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
idraw_char_handler(void * ptr_data,const char * string,int len)2172 void idraw_char_handler(void *ptr_data, const char *string, int len) {
2173   struct getbib_data* ptr_gbdata;
2174   char *term_string;
2175   char *new_string;
2176 
2177   ptr_gbdata = (struct getbib_data*)ptr_data;
2178 
2179   if (*(ptr_gbdata->ptr_ndb_error) || *(ptr_gbdata->ptr_nmem_error)) {
2180     return;
2181   }
2182 
2183   term_string = malloc(len+1);
2184   if (!term_string) {
2185     (*(ptr_gbdata->ptr_nmem_error))++;
2186     return;
2187   }
2188 
2189   strncpy(term_string, string, len);
2190   term_string[len] = '\0';
2191 
2192   if ((new_string = mstrcat((ptr_gbdata->ptr_sfirst)->elvalue, term_string, ptr_gbdata->ptr_cmid_len, 0)) == NULL) {
2193     free(term_string);
2194     (*(ptr_gbdata->ptr_nmem_error))++;
2195     return;
2196   }
2197   else {
2198     (ptr_gbdata->ptr_sfirst)->elvalue = new_string;
2199     free(term_string);
2200   }
2201 }
2202 
2203 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2204   delete_idlist(): deletes the linked element list. This is to free
2205                    the memory in case of an error
2206 
2207   void delete_idlist
2208 
2209   struct simple_elstack* ptr_current_element ptr to the first entry in the
2210                   linked list
2211 
2212   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
delete_idlist(struct simple_elstack * ptr_current_element)2213 void delete_idlist(struct simple_elstack* ptr_current_element) {
2214   struct simple_elstack* ptr_el;
2215   struct simple_elstack* ptr_el_next;
2216 
2217   ptr_el = ptr_current_element;
2218 
2219   while (ptr_el != NULL) {
2220     free(ptr_el->elvalue);
2221     free(ptr_el->attrvalue);
2222     ptr_el_next = ptr_el->ptr_snext;
2223     free(ptr_el);
2224     ptr_el = ptr_el_next;
2225   }
2226 }
2227 
2228 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2229   set_alternatetext(): sets the alternatetext/authorempty stuff
2230 
2231   int set_alternatetext returns the type of title to use if no authors
2232                        are given (1=part, 2=publication, 3=series,
2233                        4=first available), 0 if no title is to be used
2234 		       -1 in case of an error
2235 
2236   dbi_result dbires   result of a query for the style values
2237 
2238   char** ptr_aempty   ptr to a string which will receive an allocated
2239                       copy of the AEMPTY string, if any. If there is
2240                       no such string, the pointer pointed to by this
2241                       parameter will be set to NULL
2242 
2243   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
set_alternatetext(dbi_result dbires,char ** ptr_aempty)2244 static int set_alternatetext(dbi_result dbires, char** ptr_aempty) {
2245   const char *qaempty;
2246   const char *xaempty;
2247   const char *qalternatetext;
2248   const char *xalternatetext;
2249   int use_title_as_author = 0;
2250   dbi_conn conn;
2251 
2252   if (!dbires || !ptr_aempty) {
2253     return -1;
2254   }
2255 
2256   *ptr_aempty = NULL;
2257 
2258   conn = dbi_result_get_conn(dbires);
2259 
2260   if (dbi_result_next_row(dbires)) {
2261     qaempty = my_dbi_result_get_string(dbires, "QAEMPTY");
2262     xaempty = my_dbi_result_get_string(dbires, "XAEMPTY");
2263     qalternatetext = my_dbi_result_get_string(dbires, "QALTERNATETEXT");
2264     xalternatetext = my_dbi_result_get_string(dbires, "XALTERNATETEXT");
2265 /*  	      printf("string went to %s<<\n", string);  */
2266 
2267     /* first check part authors */
2268     if (qalternatetext) {
2269       if (!strcmp(qalternatetext, "TITLEPART")) {
2270 	use_title_as_author = 1; /* use part title */
2271       }
2272       else if (!strcmp(qalternatetext, "TITLEPUB")) {
2273 	use_title_as_author = 2; /* use publication title */
2274       }
2275       else if (!strcmp(qalternatetext, "TITLESERIES")) {
2276 	use_title_as_author = 3; /* use series title */
2277       }
2278       else if (!strcmp(qalternatetext, "TITLEALL")) {
2279 	use_title_as_author = 4; /* use first available title */
2280       }
2281       else { /* AEMPTY */
2282 	use_title_as_author = 0;
2283 
2284 	if (qaempty) {
2285 	  *ptr_aempty = strdup(qaempty);
2286 	  if (!*ptr_aempty || !dbi_conn_quote_string(conn, ptr_aempty)) {
2287 	    LOG_PRINT(LOG_WARNING, "out of memory");
2288 	    return -1;
2289 	  }
2290 	}
2291       }
2292     }
2293     else if (xalternatetext) {
2294       if (!strcmp(xalternatetext, "TITLEPART")) {
2295 	use_title_as_author = 1; /* use part title */
2296       }
2297       else if (!strcmp(xalternatetext, "TITLEPUB")) {
2298 	use_title_as_author = 2; /* use publication title */
2299       }
2300       else if (!strcmp(xalternatetext, "TITLESERIES")) {
2301 	use_title_as_author = 3; /* use series title */
2302       }
2303       else if (!strcmp(xalternatetext, "TITLEALL")) {
2304 	use_title_as_author = 4; /* use first available title */
2305       }
2306       else { /* AEMPTY */
2307 	use_title_as_author = 0;
2308 
2309 	if (xaempty) {
2310 	  *ptr_aempty = strdup(xaempty);
2311 	  if (!ptr_aempty || !dbi_conn_quote_string(conn, ptr_aempty)) {
2312 	    LOG_PRINT(LOG_WARNING, "out of memory");
2313 	    return -1;
2314 	  }
2315 	}
2316       }
2317     }
2318   } /* end if have row */
2319 
2320   return use_title_as_author;
2321 }
2322