1 /*   ffprint.c
2 * ===========================================================================
3 *
4 *                            PUBLIC DOMAIN NOTICE
5 *            National Center for Biotechnology Information (NCBI)
6 *
7 *  This software/database is a "United States Government Work" under the
8 *  terms of the United States Copyright Act.  It was written as part of
9 *  the author's official duties as a United States Government employee and
10 *  thus cannot be copyrighted.  This software/database is freely available
11 *  to the public for use. The National Library of Medicine and the U.S.
12 *  Government do not place any restriction on its use or reproduction.
13 *  We would, however, appreciate having the NCBI and the author cited in
14 *  any work or product based on this material
15 *
16 *  Although all reasonable efforts have been taken to ensure the accuracy
17 *  and reliability of the software and data, the NLM and the U.S.
18 *  Government do not and cannot warrant the performance or results that
19 *  may be obtained by using this software or data. The NLM and the U.S.
20 *  Government disclaim all warranties, express or implied, including
21 *  warranties of performance, merchantability or fitness for any particular
22 *  purpose.
23 *
24 * ===========================================================================
25 *
26 * File Name:  ffprint.c
27 *
28 * Author:  Karl Sirotkin, Tom Madden, Tatiana Tatusov
29 *
30 * Version Creation Date:   7/15/95
31 *
32 * $Revision: 6.8 $
33 *
34 * File Description:
35 *
36 * Modifications:
37 * --------------------------------------------------------------------------
38  * $Log: ffprint.c,v $
39  * Revision 6.8  2003/07/15 14:35:56  dondosha
40  * Added #defines for substitutes to fprintf and fflush, needed for gzip compression of Web BLAST results
41  *
42  * Revision 6.7  2002/08/26 22:06:57  kans
43  * ff_RecalculateLinks (MS) to fix hotlink artifact
44  *
45  * Revision 6.6  1999/10/07 19:22:21  bazhin
46  * Changed Int2 to Int4 for one variable. To prevent coredump.
47  *
48  * Revision 6.5  1999/10/06 20:25:28  bazhin
49  * Removed memory leak.
50  *
51  * Revision 6.4  1999/08/31 14:36:06  tatiana
52  * ff_print_string_mem() added
53  *
54  * Revision 6.3  1999/04/09 21:17:18  bazhin
55  * Added functions "FFBSPrint()" and "BSAppend()" to parse ASN.1
56  * data to ByteStore.
57  *
58  * Revision 6.2  1999/04/01 20:44:13  kans
59  * Int2 lengths to Int4 to allow CountGapsInDeltaSeq with buffer > 32K
60  *
61  * Revision 6.1  1999/03/12 17:47:11  tatiana
62  * file was lost
63  *
64  * Revision 6.7  1999/02/02 17:29:20  kans
65  * added ff_MergeString
66  *
67  * Revision 6.6  1998/06/15 15:00:31  tatiana
68  * UNIX compiler warnings fixed
69  *
70  * Revision 6.5  1998/02/26 22:43:46  madden
71  * Used init_buff_ex in ff_StartPrint
72  *
73  * Revision 6.4  1998/02/19 01:54:51  ostell
74  * added use of Thread Local Storage to make functions thread safe
75  *
76  * Revision 6.3  1997/10/23 20:21:31  madden
77  * Fixed ByteStore leak
78  *
79  * Revision 6.2  1997/10/23 20:03:51  tatiana
80  * allocates byte store in init_buf_ex()
81  *
82  * Revision 6.1  1997/09/16 16:56:04  tatiana
83  * buffer reinit in ff_StartPrint
84  *
85  * Revision 6.0  1997/08/25 18:05:32  madden
86  * Revision changed to 6.0
87  *
88  * Revision 5.8  1997/08/04 22:56:21  tatiana
89  * init_buff_ex() added
90  *
91  * Revision 5.7  1997/07/18 20:11:16  vakatov
92  * Restored NLM_EXTERNs which were lost in R5.5
93  *
94  * Revision 5.6  1997/07/16 21:24:12  tatiana
95  * add AddPintLater
96  *
97 Revision 5.3  1997/02/25  22:08:59  tatiana
98 ff_AddStringWithTildes(0 will print out "`~" as real tilde
99 
100 Revision 5.2  1997/01/08  18:52:45  madden
101 Added LIBCALL's.
102 
103 Revision 5.1  1996/09/10  14:26:56  tatiana
104 init_buff() added to ff_StartPrint
105 
106 Revision 4.8  1996/04/15  18:44:41  tatiana
107 free_buff() added
108 
109 Revision 4.4  1996/01/29  22:41:20  tatiana
110 ChangeStringWithTildes function added
111 
112 Revision 4.3  1995/12/13  21:04:47  kans
113 descriptors now store entityID/itemID/itemtype in proper array
114 
115 Revision 4.2  1995/12/13  16:34:06  tatiana
116 itemID added to FFPrintArray structure
117 
118 Revision 4.1  1995/11/17  21:28:35  kans
119 asn2ff now uses gather (Tatiana)
120 
121 Revision 1.5  1995/07/17  19:33:20  kans
122 parameters combined into Asn2ffJobPtr structure
123 *
124 * ==========================================================================
125 */
126 
127 #include <asn2ffp.h>
128 #include <ffprint.h>
129 #include <ncbithr.h>
130 
131 int (*ff_fprintf)(FILE*, const char *, ...) = fprintf;
132 int (*ff_fflush)(FILE*) = fflush;
133 
134 #define fprintf ff_fprintf
135 #define fflush ff_fflush
136 
137 static TNlmTls ffprint_tls = NULL;
138 
free_buff_contents(BuffStructPtr bfp)139 static void free_buff_contents(BuffStructPtr bfp)
140 {
141 	if (bfp == NULL) return;
142 	bfp->buffer = MemFree(bfp->buffer);
143 	bfp->line_prefix = MemFree(bfp->line_prefix);
144 	bfp->line_return = MemFree(bfp->line_return);
145 	if (bfp->byte_sp)
146 		bfp->byte_sp = BSFree(bfp->byte_sp);
147 	return;
148 }
149 
BuffStructCleanup(TNlmTls tls,VoidPtr ptr)150 static void BuffStructCleanup (TNlmTls tls, VoidPtr ptr)
151 {
152 	BuffStructPtr bfp;
153 
154 	bfp = (BuffStructPtr)ptr;
155 	free_buff_contents(bfp);
156 	MemFree(bfp);
157 	return;
158 }
159 
160 
GetBuffStruct(void)161 static BuffStruct PNTR NEAR GetBuffStruct ( void )
162 {
163 	BuffStructPtr bfp = NULL;
164 
165 	if (NlmTlsGetValue( ffprint_tls, (VoidPtr *)(&bfp)))
166 	{
167 		if (bfp == NULL)
168 		{
169 			bfp = MemNew(sizeof(BuffStruct));
170 			NlmTlsSetValue(&ffprint_tls, bfp, BuffStructCleanup);
171 		}
172 	}
173 	return bfp;
174 }
175 
176 /******************************************************************************
177 *
178 *	print utilities to handle the printing of the asn2ff system.
179 *
180 *****************************************************************************/
init_buff(void)181 NLM_EXTERN void LIBCALL init_buff(void)
182 {
183 	BuffStructPtr bfp;
184 
185 	bfp = GetBuffStruct();
186 	bfp->buffer = (CharPtr) MemNew((MAX_BTP_BUF+2)*sizeof(Char));
187 	bfp->line_prefix = (CharPtr) MemNew(3*sizeof(Char));
188 	bfp->newline = NEWLINE;
189 }
190 
init_buff_ex(Int2 init_size)191 NLM_EXTERN void LIBCALL init_buff_ex(Int2 init_size)
192 {
193 	BuffStructPtr bfp;
194 
195 	bfp = GetBuffStruct();
196 	bfp->buffer = (CharPtr) MemNew((init_size+2)*sizeof(Char));
197 	bfp->line_prefix = (CharPtr) MemNew(3*sizeof(Char));
198 	bfp->newline = NEWLINE;
199 	bfp->byte_sp = BSNew(init_size+2);
200 }
201 
free_buff(void)202 NLM_EXTERN void LIBCALL free_buff(void)
203 {
204 	BuffStructPtr bfp;
205 
206 	bfp = GetBuffStruct();
207 	free_buff_contents (bfp);
208 	return;
209 }
210 
211 /***********************************************************************
212 *void asn2ff_set_output (FILE * fp, CharPtr line_return)
213 *
214 **************************************************************************/
215 
asn2ff_set_output(FILE * fp,CharPtr line_return)216 NLM_EXTERN void LIBCALL asn2ff_set_output (FILE *fp, CharPtr line_return)
217 {
218 	BuffStructPtr bfp;
219 
220 	bfp = GetBuffStruct();
221 	bfp->fp = fp;
222 	if (line_return)
223 	{
224 		if(bfp->line_return != NULL)
225 			MemFree(bfp->line_return);
226 		bfp->line_return = StringSave(line_return);
227 	}
228 }
229 
ff_MergeString(void)230 NLM_EXTERN CharPtr LIBCALL ff_MergeString (void)
231 
232 {
233 	ByteStorePtr byte_sp=NULL;
234 	CharPtr string=NULL;
235 	BuffStructPtr bfp;
236 
237 	bfp = GetBuffStruct();
238 
239 	if (! bfp->fp)
240 	{
241 		byte_sp = bfp->byte_sp;
242 
243 		string = BSMerge(byte_sp, NULL);
244 		bfp->byte_sp = BSFree(bfp->byte_sp);
245 	}
246 
247 	return string;
248 }
249 
FFPrint(FFPrintArrayPtr pap,Int4 index,Int4 pap_size)250 NLM_EXTERN CharPtr LIBCALL FFPrint (FFPrintArrayPtr pap, Int4 index, Int4 pap_size)
251 {
252 	GBEntryPtr gbp;
253 	Asn2ffJobPtr ajp;
254 	ByteStorePtr byte_sp=NULL;
255 	CharPtr string=NULL;
256 	FFPrintArray pa=pap[index];
257 	BuffStructPtr bfp;
258 
259 	bfp = GetBuffStruct();
260 
261 	gbp = pa.gbp;
262 	ajp = pa.ajp;
263 	if (ajp == NULL) {
264 		return NULL;
265 	}
266 	ajp->pap_index = pa.index;
267 	ajp->pap_last = pa.last;
268 
269 	if (index == 0 || index == (pap_size-1))
270 	{
271 		flat2asn_delete_locus_user_string();
272 		flat2asn_install_locus_user_string(gbp->locus);
273 		flat2asn_delete_accession_user_string();
274 		flat2asn_install_accession_user_string(gbp->accession);
275 	}
276 
277 	bfp->n_links = 0;
278 	pa.fct(ajp, gbp);
279 	if (pa.descr == NULL) {
280 		pap[index].descr = gbp->descr;
281 	}
282 	if (pa.printxx == PRINTXX) {
283 		PrintXX();
284 	}
285 	if (! bfp->fp) {
286 		byte_sp = bfp->byte_sp;
287 		string = BSMerge(byte_sp, NULL);
288 		bfp->byte_sp = BSFree(bfp->byte_sp);
289 	}
290 
291 	return string;
292 }
293 
294 /**********************************************************/
BSAppend(ByteStorePtr to,ByteStorePtr from)295 static ByteStorePtr BSAppend(ByteStorePtr to, ByteStorePtr from)
296 {
297     Nlm_BSUnitPtr tobup;
298     Nlm_BSUnitPtr frombup;
299 
300     if(from == NULL)
301         return(to);
302 
303     if(to == NULL)
304     {
305         to = MemNew(sizeof(Nlm_ByteStore));
306         to->totlen = 0;
307         to->chain = NULL;
308     }
309 
310     to->seekptr = 0;
311     to->chain_offset = 0;
312 
313     if(to->chain != NULL)
314         for(tobup = to->chain; tobup->next != NULL; tobup = tobup->next)
315             continue;
316     else
317         tobup = NULL;
318 
319     for(frombup = from->chain; frombup != NULL; frombup = frombup->next)
320     {
321         to->totlen += frombup->len;
322         if(tobup == NULL)
323         {
324             to->chain = MemNew(sizeof(Nlm_BSUnit));
325             tobup = to->chain;
326         }
327         else
328         {
329             tobup->next = MemNew(sizeof(Nlm_BSUnit));
330             tobup = tobup->next;
331         }
332         tobup->str = MemNew(frombup->len);
333         MemCpy(tobup->str, frombup->str, frombup->len);
334         tobup->len = frombup->len;
335         tobup->len_avail = frombup->len_avail;
336     }
337     to->curchain = to->chain;
338     return(to);
339 }
340 
341 /**********************************************************/
FFBSPrint(FFPrintArrayPtr pap,Int4 index,Int4 pap_size)342 NLM_EXTERN void LIBCALL FFBSPrint(FFPrintArrayPtr pap, Int4 index,
343                                   Int4 pap_size)
344 {
345     GBEntryPtr    gbp;
346     Asn2ffJobPtr  ajp;
347     ByteStorePtr  byte_sp = NULL;
348     FFPrintArray  pa = pap[index];
349     BuffStructPtr bfp;
350 
351     bfp = GetBuffStruct();
352 
353     gbp = pa.gbp;
354     ajp = pa.ajp;
355     if(ajp == NULL)
356         return;
357 
358     ajp->pap_index = pa.index;
359     ajp->pap_last = pa.last;
360 
361     if(index == 0 || index == pap_size - 1)
362     {
363         flat2asn_delete_locus_user_string();
364         flat2asn_install_locus_user_string(gbp->locus);
365         flat2asn_delete_accession_user_string();
366         flat2asn_install_accession_user_string(gbp->accession);
367     }
368 
369     bfp->n_links = 0;
370     pa.fct(ajp, gbp);
371     if(pa.descr == NULL)
372         pap[index].descr = gbp->descr;
373 
374     if(pa.printxx == PRINTXX)
375     {
376         PrintXX();
377     }
378 
379     ajp->byte_st = BSAppend(ajp->byte_st, bfp->byte_sp);
380     BSFree(bfp->byte_sp);
381     bfp->byte_sp = NULL;
382 }
383 
ff_print_string(FILE * fp,CharPtr string,CharPtr line_return)384 NLM_EXTERN void LIBCALL ff_print_string (FILE *fp, CharPtr string, CharPtr line_return)
385 
386 {
387 	CharPtr s;
388 	Int2	i, l;
389 	BuffStructPtr bfp;
390 
391 	bfp = GetBuffStruct();
392 
393 	if (! fp) {
394 		return;
395 	}
396 	if (! string || *string == *line_return) {
397 		ErrPostEx(SEV_WARNING, 1, 1,
398 			"CAUTION: NULL String in ff_print_string\n\n");
399 		return;
400 	}
401 	for (s = string; (s = strchr(s, *line_return)) != NULL; s++) {
402 		*s = '\n';
403 	}
404 	for (i = 0, s = string; i < bfp->n_links; i++) {
405 		l = string - s + bfp->pos_links[i];
406 		if (s[l-1] == '\n') {
407 			for (; IS_WHITESP(s[l]); l++) ;
408 			fwrite(s, 1, l, fp);
409 		} else {
410 			fwrite(s, 1, l, fp);
411 		}
412 		fwrite(bfp->links[i], 1, StringLen(bfp->links[i]), fp);
413 		MemFree(bfp->links[i]);
414 		s += l;
415 	}
416 	fwrite(s, 1, StringLen(s), fp);
417 	BuffFree();
418 }
419 
ff_print_insert(CharPtr str,CharPtr ins)420 static CharPtr ff_print_insert(CharPtr str, CharPtr ins)
421 {
422 	CharPtr buff;
423 
424 	buff = (CharPtr) MemNew(StringLen(str) + StringLen(ins) + 1);
425 	StringCpy(buff, ins);
426 	StringCat(buff, str);
427 	MemFree(str);
428 	return buff;
429 }
430 
ff_print_string_mem(CharPtr string)431 NLM_EXTERN CharPtr LIBCALL ff_print_string_mem (CharPtr string)
432 
433 {
434 	CharPtr s, buff, bu;
435 	Int2	i, l;
436 	Int4	ll;
437 	BuffStructPtr bfp;
438 
439 	bfp = GetBuffStruct();
440 
441 	if (! string) {
442 		ErrPostEx(SEV_WARNING, 1, 1,
443 			"CAUTION: NULL String in ff_print_string\n\n");
444 		return NULL;
445 	}
446 	ll = StringLen(string);
447 	for (i = 0, s = string; i < bfp->n_links; i++) {
448 		ll += StringLen(bfp->links[i]);
449 	}
450 	buff = (CharPtr) MemNew(ll+1);
451 	bu = buff;
452 	for (i = 0, s = string; i < bfp->n_links; i++) {
453 		l = string - s + bfp->pos_links[i];
454 		if (s[l-1] == '\n') {
455 			for (; IS_WHITESP(s[l]); l++) ;
456 		}
457 		MemCpy(bu, s, l);
458 		s += l;
459 		bu += l;
460 		StringCpy(bu, bfp->links[i]);
461 		bu += StringLen(bfp->links[i]);
462 		MemFree(bfp->links[i]);
463 	}
464 	StringCpy(bu, s);
465 	BuffFree();
466 	MemFree(string);
467 	return buff;
468 }
469 
ff_StartPrint(Int2 init_indent,Int2 cont_indent,Int2 line_max,CharPtr line_prefix)470 NLM_EXTERN Int2 LIBCALL ff_StartPrint (Int2 init_indent, Int2 cont_indent, Int2 line_max, CharPtr line_prefix)
471 
472 {
473 
474 	CharPtr buffer;
475 	Int2 indent_space;
476 	BuffStructPtr bfp;
477 
478 	bfp = GetBuffStruct();
479 
480 	buffer = bfp->buffer;
481 	if (buffer == NULL) {
482 		if (line_max > MAX_BTP_BUF)
483 			init_buff_ex(line_max);
484 		else
485 			init_buff();
486 		buffer = bfp->buffer;
487 	}
488 
489 	bfp->init_indent = init_indent;
490 	bfp->cont_indent = cont_indent;
491 
492 	if (line_max > 0)
493 		bfp->line_max = line_max;
494 	else
495 		bfp->line_max = MAX_BTP_BUF;
496 
497 	if (line_prefix) {
498 		StringCpy(bfp->line_prefix, line_prefix);
499 		*buffer = *line_prefix;
500 		buffer++;
501 		line_prefix++;
502 		*buffer = *line_prefix;
503 		buffer++;
504 		line_prefix++;
505 		indent_space = init_indent - StringLen(bfp->line_prefix);
506 	} else {
507 		bfp->line_prefix[0] = '\0';
508 		indent_space = init_indent;
509 	}
510 
511 	if (indent_space > 0) {
512 		MemSet((VoidPtr) buffer, ' ', indent_space);
513 	}
514 	return init_indent;
515 }	/* ff_StartPrint */
516 
ff_AddString(CharPtr string)517 NLM_EXTERN void LIBCALL ff_AddString (CharPtr string)
518 
519 {
520 	Char newline;
521 	CharPtr buffer;
522 	Int2 increment_string=0, index, length_b/*, length_s -- UNUSED */, line_max;
523 	BuffStructPtr bfp;
524 
525 	bfp = GetBuffStruct();
526 	newline = bfp->newline;
527 	line_max = bfp->line_max;
528 
529 	if (string == NULL)
530 		return;
531 
532 	buffer = CheckBufferState(&increment_string, string[0]);
533 
534 	if (buffer == NULL)
535 		return;
536 
537 	length_b = StringLen(bfp->buffer);
538 
539 	string += increment_string;
540 	index = length_b;
541 	while ((*buffer = *string) != '\0')
542 	{
543 		if (*string == newline)
544 		{
545 			*buffer = '\0';
546 			*string = ' ';
547 			NewContLine();
548 			string++;
549 			ff_AddString(string);
550 			break;
551 		}
552 		else
553 		{
554 			buffer++;
555 			string++;
556 			index++;
557 			if (index == line_max)
558 			{ /* return value for ff_AddString??????? */
559 				ff_AddString(string);
560 				break;
561 			}
562 		}
563 	}
564 
565 /*	length_s = index - length_b; -- NO EFFECT */
566 
567 	return;
568 }	/* ff_AddString */
569 
AddLink(CharPtr str)570 NLM_EXTERN void LIBCALL AddLink (CharPtr str)
571 {
572 	CharPtr 	buffer;
573 	Int2 		increment_string=0;
574 	Int4		l;
575 	CharPtr PNTR buf_links;
576 	Int4 PNTR	buf_pos;
577 	BuffStructPtr bfp;
578 
579 	bfp = GetBuffStruct();
580 
581 	buffer = CheckBufferState(&increment_string, str[0]);
582 	if (buffer == NULL) {
583 		return;
584 	}
585 	l = (bfp->byte_sp == NULL) ? 0 : BSLen(bfp->byte_sp);
586 	if (bfp->n_links >= bfp->buf_n_links) {
587 		buf_pos = MemNew((bfp->buf_n_links + LINKS)*sizeof(buf_pos[0]));
588 		buf_links = MemNew((bfp->buf_n_links + LINKS)*sizeof(buf_links[0]));
589 		if (bfp->buf_n_links > 0) {
590 			MemCpy(buf_pos, bfp->pos_links, bfp->buf_n_links*sizeof(buf_pos[0]));
591 			MemFree(bfp->pos_links);
592 			MemCpy(buf_links, bfp->links, bfp->buf_n_links*sizeof(buf_links[0]));
593 			MemFree(bfp->links);
594 		}
595 		bfp->pos_links = buf_pos;
596 		bfp->links = buf_links;
597 		bfp->buf_n_links += LINKS;
598 	}
599 	bfp->pos_links[bfp->n_links] = (buffer - bfp->buffer + l);
600 	bfp->links[bfp->n_links] = StringSave(str);
601 	bfp->n_links++;
602 	return;
603 }
604 
AddLinkLater(CharPtr str,Int2 prevlen)605 NLM_EXTERN void LIBCALL AddLinkLater (CharPtr str, Int2 prevlen)
606 {
607 	CharPtr 	buffer;
608 	Int2 		increment_string=0;
609 	Int4		l;
610 	CharPtr PNTR buf_links;
611 	Int4 PNTR	buf_pos;
612 	BuffStructPtr bfp;
613 
614 	bfp = GetBuffStruct();
615 
616 	buffer = CheckBufferState(&increment_string, str[0]);
617 	if (buffer == NULL) {
618 		return;
619 	}
620 	l = (bfp->byte_sp == NULL) ? 0 : BSLen(bfp->byte_sp);
621 	if (bfp->n_links >= bfp->buf_n_links) {
622 		buf_pos = MemNew((bfp->buf_n_links + LINKS)*sizeof(buf_pos[0]));
623 		buf_links = MemNew((bfp->buf_n_links + LINKS)*sizeof(buf_links[0]));
624 		if (bfp->buf_n_links > 0) {
625 			MemCpy(buf_pos, bfp->pos_links, bfp->buf_n_links*sizeof(buf_pos[0]));
626 			MemFree(bfp->pos_links);
627 			MemCpy(buf_links, bfp->links, bfp->buf_n_links*sizeof(buf_links[0]));
628 			MemFree(bfp->links);
629 		}
630 		bfp->pos_links = buf_pos;
631 		bfp->links = buf_links;
632 		bfp->buf_n_links += LINKS;
633 	}
634 	bfp->pos_links[bfp->n_links] = buffer - bfp->buffer + l - prevlen;
635 	bfp->links[bfp->n_links] = StringSave(str);
636 	bfp->n_links++;
637 	return;
638 }
639 
ff_AddChar(Char character)640 NLM_EXTERN void LIBCALL ff_AddChar (Char character)
641 {
642 	CharPtr buffer;
643 	Int2 increment_string=0;
644 	BuffStructPtr bfp;
645 
646 	bfp = GetBuffStruct();
647 
648 	if (character == NULLB)
649 		return;
650 
651 	if (character == bfp->newline)
652 	{
653 		NewContLine();
654 	}
655 	else
656 	{
657 		buffer = CheckBufferState(&increment_string, character);
658 		*buffer = character;
659 	}
660 
661 	return ;
662 }	/* ff_AddChar */
663 
PrintXX(void)664 NLM_EXTERN void LIBCALL PrintXX(void)
665 {
666 	ff_StartPrint(0, 0, ASN2FF_EMBL_MAX, "XX");
667 	ff_EndPrint();
668 }
669 
ff_AddInteger(CharPtr fmt,long integer)670 NLM_EXTERN void LIBCALL ff_AddInteger (CharPtr fmt, long integer)
671 {
672 	Char buffer[10];
673 
674 	/* Only one integer read in	*/
675 	sprintf(buffer, fmt, integer);
676 	ff_AddString(buffer);
677 	return;
678 }	/* ff_AddInteger */
679 
680 /***********************************************************************
681 *void ff_AddStringWithTildes (CharPtr string)
682 *
683 *	This function prints out a string and replaces the tiles ("~")
684 *	by new lines (by calling NewContLine).  Before this function is
685 *	called, printing must be initialized by calling ff_StartPrint;
686 *	afterwards ff_EndPrint must be called!
687 *
688 *	Use accent grave (ASCII 96) "`~" to print out real tilde
689 *
690 * Can't this be rewritten to use ff_AddString????  That would be faster!
691 ************************************************************************/
692 
ff_AddStringWithTildes(CharPtr string)693 NLM_EXTERN void LIBCALL ff_AddStringWithTildes (CharPtr string)
694 {
695 /* One "~" is a  new line, "~~" or "~~ ~~" means 2 returns */
696 
697 	while (*string != '\0') {
698 		if (*string == '`' && *(string+1) == '~') {
699 			ff_AddChar('~');
700 			string += 2;
701 		} else if (*string == '~') {
702 			NewContLine();
703 			string++;
704 			if (*string == '~') {
705 				NewContLine();
706 				string++;
707 				if (*string == ' ' && *(string+1) == '~' && *(string+2) == '~')
708 					string += 3;
709              }
710 		} else if (*string == '\"') {
711 			*string = '\'';
712 			ff_AddChar(*string);
713 			string++;
714 		} else {
715 			ff_AddChar(*string);
716 			string++;
717 		}
718 	}
719 
720 }	/* ff_AddStringWithTildes */
721 
ChangeStringWithTildes(CharPtr string)722 NLM_EXTERN void LIBCALL ChangeStringWithTildes (CharPtr string)
723 {
724                 while (*string != '\0') {
725                 /* One "~" is a line return, "~~" or "~~ ~~" means 2 returns */
726 					if (*string == '~') {
727 						*string = '\n';
728 						string++;
729 						if (*string == '~') {
730 							*string = '\n';
731 							string++;
732 							if (*string == ' ' && *(string+1) == '~' &&
733                                  		*(string+2) == '~') {
734 								string += 3;
735 							}
736                         }
737 					} else if (*string == '\"') {
738 						*string = '\'';
739 						string++;
740                     } else {
741 						string++;
742                     }
743                 }
744 
745 }	/* ChangeStringWithTildes */
746 
ff_RecalculateLinks(Int4 indent)747 NLM_EXTERN void LIBCALL ff_RecalculateLinks(Int4 indent) {
748     BuffStructPtr bfp = GetBuffStruct();
749     Int4 len = (bfp->byte_sp == NULL) ? 0 : BSLen(bfp->byte_sp);
750     Int2 i;
751 
752     for ( i = bfp->n_links - 1; i >= 0; --i ) {
753         if ( bfp->pos_links[i] + 1 >= len ) {
754             bfp->pos_links[i] += indent;
755         } else {
756             break;
757         }
758     }
759 }
760 
CheckBufferState(Int2Ptr increment_string,Char next_char)761 NLM_EXTERN CharPtr LIBCALL CheckBufferState(Int2Ptr increment_string, Char next_char)
762 
763 {
764 	CharPtr buffer, line_prefix;
765 	CharPtr buf_ptr_comma=NULL, buf_ptr_dash=NULL, buf_ptr_space=NULL,
766 	buf_ptr_start, ptr_index;
767 	CharPtr temp_ptr, temp_ptr_start;
768 	Char temp[MAX_TO_RT_SIDE+1];
769 	Int2 length, cont_indent, indent_space;
770 	Int2 line_max, line_index;
771 	BuffStructPtr bfp;
772     Int2 IndentSize = 0;
773 
774 	bfp = GetBuffStruct();
775 	cont_indent = bfp->cont_indent;
776 	line_max = bfp->line_max;
777 
778 	*increment_string = 0;
779 	temp_ptr = temp_ptr_start = temp;
780 
781 	buffer = bfp->buffer;
782 	length=StringLen(buffer);
783 
784 	if (length < bfp->line_max) {
785 		return buffer+length;
786 	} else if (length == bfp->line_max && next_char == '\0') {
787 		return buffer+length;
788 	} else {
789 		if (StringLen(bfp->line_prefix) > 0) {
790 			line_prefix = bfp->line_prefix;
791 			indent_space = cont_indent - StringLen(line_prefix);
792 		} else {
793 			line_prefix = NULL;
794 			indent_space = cont_indent;
795 		}
796 
797 		if (next_char == ' ') {
798 			buf_ptr_space = buffer+line_max+1;
799 		} else {
800 			for (ptr_index=buffer+line_max, line_index=line_max-cont_indent;
801 				ptr_index>buffer+line_max-MAX_TO_RT_SIDE &&
802 					line_index > 0;
803 						ptr_index--, line_index--) {
804 				if (ptr_index[0] == ' ') {
805 					buf_ptr_space = ptr_index;
806 					break;
807 				}
808 			}
809 
810 			for (ptr_index=buffer+line_max, line_index=line_max-cont_indent;
811 				ptr_index>buffer+line_max-MAX_TO_RT_SIDE &&
812 					line_index > 0;
813 						ptr_index--, line_index--) {
814 				if (ptr_index[0] == ',') {
815 					buf_ptr_comma = ptr_index;
816 /* Add one on the next line, otherwise the comma is lost, as space is. */
817 					buf_ptr_comma++;
818 					break;
819 				}
820 			}
821 			for (ptr_index=buffer+line_max, line_index=line_max-cont_indent;
822 				ptr_index>buffer+line_max-MAX_TO_RT_SIDE &&
823 					line_index > 0;
824 						ptr_index--, line_index--) {
825 				if (ptr_index[0] == '-') {
826 				 /* Don't put "-" on next line! */
827 					buf_ptr_dash = ptr_index + 1;
828 					break;
829 				}
830 			}
831 		}
832 
833 		if (next_char != ' ' &&
834 			(buf_ptr_space || buf_ptr_comma || buf_ptr_dash)) {
835 			if (buf_ptr_space) {
836 				buf_ptr_start = buf_ptr_space;
837 				buf_ptr_space++;
838 				while((*temp_ptr = *buf_ptr_space) != '\0') {
839 					temp_ptr++;
840 					buf_ptr_space++;
841 				}
842 				buf_ptr_start[0] = '\0';
843 				if (*(buf_ptr_start-1) == ' ') {
844 				/* If there are two spaces in a row */
845 					buf_ptr_start--;
846 					buf_ptr_start[0] = '\0';
847 				}
848 			} else if (buf_ptr_comma) {
849 				buf_ptr_start = buf_ptr_comma;
850 /* Check if a space follows the comma; if so, delete it; otherwise it shows
851 up on the next line and really looks stupid.			*/
852 				if (*buf_ptr_comma == ' ') {
853 					buf_ptr_comma++;
854 				}
855 				while((*temp_ptr = *buf_ptr_comma) != '\0') {
856 					temp_ptr++;
857 					buf_ptr_comma++;
858 				}
859 				buf_ptr_start[0] = '\0';
860 			} else if (buf_ptr_dash) {
861 				buf_ptr_start = buf_ptr_dash;
862 				while((*temp_ptr = *buf_ptr_dash) != '\0') {
863 					temp_ptr++;
864 					buf_ptr_dash++;
865 				}
866 				buf_ptr_start[0] = '\0';
867 			}
868 
869 
870 			FlushBuffer();
871 			if (line_prefix != NULL) {
872 				*buffer = *line_prefix;
873 				buffer++;
874 				line_prefix++;
875 				*buffer = *line_prefix;
876 				buffer++;
877 				line_prefix++;
878 			}
879 			if (indent_space > 0)
880 				MemSet((VoidPtr) buffer, ' ', indent_space);
881 			buffer += indent_space;
882             IndentSize = buffer - bfp->buffer + 1;
883 			temp_ptr = temp_ptr_start;
884 			while((*buffer = *temp_ptr) != '\0') {
885 				temp_ptr++;
886 				buffer++;
887 			}
888 
889             ff_RecalculateLinks(IndentSize);
890 			return buffer;
891 		} else if (next_char == ' ') {
892 			FlushBuffer();
893 			if (line_prefix) {
894 				*buffer = *line_prefix;
895 				buffer++;
896 				line_prefix++;
897 				*buffer = *line_prefix;
898 				buffer++;
899 				line_prefix++;
900 			}
901 			if (indent_space-1 > 0) {
902 				MemSet((VoidPtr) buffer, ' ', indent_space-1);
903                 ff_RecalculateLinks(buffer+indent_space-1 - bfp->buffer);
904 				return buffer+indent_space-1;
905 			} else if (indent_space-1 == 0) {
906 			/* if there is one space indentation! */
907                 ff_RecalculateLinks(buffer - bfp->buffer);
908 				return buffer;
909 			} else if (indent_space-1 < 0) {
910 			/* if there is zero space indentation! */
911 				*increment_string = 1;
912                 ff_RecalculateLinks(buffer - bfp->buffer);
913 				return buffer;
914 			}
915 		} else {
916 			FlushBuffer();
917 			if (line_prefix) {
918 				*buffer = *line_prefix;
919 				buffer++;
920 				line_prefix++;
921 				*buffer = *line_prefix;
922 				buffer++;
923 				line_prefix++;
924 			}
925 			if (indent_space > 0) {
926 				MemSet((VoidPtr) buffer, ' ', indent_space);
927 			}
928             ff_RecalculateLinks(buffer +indent_space - bfp->buffer);
929 			return buffer+indent_space;
930 		}
931 	}
932 	return buffer;	/* never used!  Only put in to make CodeWarrior happy*/
933 }	/* CheckBufferState */
934 
NewContLine(void)935 NLM_EXTERN Int2 LIBCALL NewContLine (void)
936 
937 {
938 	Int2 cont_indent, indent_space;
939 	CharPtr buffer, line_prefix=NULL;
940 	BuffStructPtr bfp;
941 
942 	bfp = GetBuffStruct();
943 	cont_indent = bfp->cont_indent;
944 
945 	FlushBuffer();
946 	buffer=bfp->buffer;
947 
948 	if (StringLen(bfp->line_prefix) > 0)
949 	{
950 		line_prefix = bfp->line_prefix;
951 		indent_space = cont_indent - StringLen(line_prefix);
952 	}
953 	else
954 	{
955 		indent_space = cont_indent;
956 	}
957 
958 	if (line_prefix)
959 	{
960 		*buffer = *line_prefix;
961 		buffer++;
962 		line_prefix++;
963 		*buffer = *line_prefix;
964 		buffer++;
965 		line_prefix++;
966 	}
967 
968 	if (indent_space > 0)
969 		MemSet((VoidPtr) buffer, ' ', indent_space);
970 	return cont_indent;
971 }	/* NewContLine */
972 
973 
TabToColumn(Int2 column)974 NLM_EXTERN Int2 LIBCALL TabToColumn (Int2 column)
975 
976 {
977 	CharPtr start_buffer, buffer;
978 	Int2 increment_string=0, length;
979 	BuffStructPtr bfp;
980 
981 	bfp = GetBuffStruct();
982 	start_buffer = bfp->buffer;
983 
984 	if ((length=StringLen(start_buffer)) > column)
985 		return -1;
986 
987 	buffer = CheckBufferState(&increment_string, '\0');
988 
989 	if ((column-length-1) > 0)
990 		MemSet((VoidPtr) buffer, ' ', (column-length-1));
991 
992 	return length;
993 }
994 
ff_EndPrint(void)995 NLM_EXTERN void LIBCALL ff_EndPrint (void)
996 
997 {
998 	FlushBuffer();
999 }
1000 
FlushBuffer(void)1001 NLM_EXTERN void LIBCALL FlushBuffer (void)
1002 
1003 {
1004 	ByteStorePtr byte_sp=NULL;
1005 	CharPtr line_ret;
1006 	BuffStructPtr bfp;
1007 
1008 	bfp = GetBuffStruct();
1009 	line_ret = bfp->line_return;
1010 
1011 	if (bfp->fp)
1012 	{
1013 		fflush(bfp->fp);
1014 		fprintf(bfp->fp, "%s\n", bfp->buffer);
1015 	}
1016 	else
1017 	{
1018 		byte_sp=bfp->byte_sp;
1019 		if (! byte_sp) {
1020 			bfp->byte_sp = byte_sp = BSNew(MAX_BTP_BUF);
1021 		}
1022 		BSWrite(byte_sp, bfp->buffer, StringLen(bfp->buffer));
1023 		BSWrite(byte_sp, line_ret, StringLen(line_ret));
1024 	}
1025 	MemSet((VoidPtr) bfp->buffer, '\0', bfp->line_max);
1026 }
1027 
1028 
1029 /**************************************************************************
1030 *CheckEndPunctuation
1031 *
1032 *	This code checks to ensure that the last character of a string
1033 *	is the character passed.  Any extra spaces or tabs at the end of
1034 *	the string are eliminated.
1035 *
1036 **************************************************************************/
1037 
CheckEndPunctuation(CharPtr string,Char end)1038 NLM_EXTERN CharPtr LIBCALL CheckEndPunctuation (CharPtr string, Char end)
1039 
1040 {
1041 	CharPtr stringptr, newstring;
1042 	Int4 length;
1043 
1044 	if (string == NULL)
1045 		return NULL;
1046 
1047 	length = StringLen(string);
1048 	newstring = (CharPtr) MemNew((length+2)*sizeof(Char));
1049 
1050 	if (length > 0)
1051 	{
1052 		newstring = StringCpy(newstring, string);
1053 		for (stringptr=newstring+length-1; stringptr > newstring; stringptr--)
1054 		{
1055 			if (*stringptr == ' ' || *stringptr == '\t' || *stringptr == '~')
1056 			{
1057 				*stringptr = '\0';
1058 			}
1059 			else
1060 			{
1061 				break;
1062 			}
1063 		}
1064 
1065 		if (*stringptr != end)
1066 		{
1067 			stringptr++;
1068 			*stringptr = end;
1069 			stringptr++;
1070 			*stringptr = '\0';
1071 		}
1072 	}
1073 	else
1074 	{
1075 		newstring[0] = end;
1076 		newstring[1] = '\0';
1077 	}
1078 
1079 	return newstring;
1080 }
1081 
BuffFree(void)1082 NLM_EXTERN void LIBCALL BuffFree(void)
1083 {
1084 	BuffStructPtr bfp;
1085 
1086 	bfp = GetBuffStruct();
1087 	bfp->buffer[0] = '\0';
1088 	bfp->n_links = 0;
1089 
1090 }
1091 
ReportPrint(FFPrintArrayPtr pap,Int4 index,Int4 pap_size)1092 NLM_EXTERN CharPtr LIBCALL ReportPrint (FFPrintArrayPtr pap, Int4 index, Int4 pap_size)
1093 
1094 {
1095 	GBEntryPtr gbp;
1096 	Asn2ffJobPtr ajp;
1097 	ByteStorePtr byte_sp=NULL;
1098 	CharPtr string=NULL;
1099 	FFPrintArray pa=pap[index];
1100 	BuffStructPtr bfp;
1101 
1102 	bfp = GetBuffStruct();
1103 
1104 	gbp = pa.gbp;
1105 	ajp = pa.ajp;
1106 	ajp->pap_index = pa.index;
1107 	ajp->pap_last = pa.last;
1108 
1109 	if (index == 0 || index == (pap_size-1))
1110 	{
1111 		flat2asn_delete_locus_user_string();
1112 		flat2asn_install_locus_user_string(gbp->locus);
1113 		flat2asn_delete_accession_user_string();
1114 		flat2asn_install_accession_user_string(gbp->accession);
1115 	}
1116 
1117 	pa.fct(ajp, gbp);
1118 
1119 	if (! bfp->fp)
1120 	{
1121 		byte_sp = bfp->byte_sp;
1122 
1123 		string = BSMerge(byte_sp, NULL);
1124 		bfp->byte_sp = BSFree(bfp->byte_sp);
1125 	}
1126 
1127 	return string;
1128 }
1129 
1130 /*****************************************************************************
1131 *Boolean DoSpecialLineBreak (BiotablePtr btp, CharPtr string, Int2 indent)
1132 *
1133 *	Look for line breaks in special cases, such as KEYWORDS, when
1134 *	line breaks are only allowed after semi-colons.
1135 *
1136 *	"length" is reset to zero if string is NULL, "indent" tells how
1137 *	many spaces the line is indented from the left side.
1138 *****************************************************************************/
1139 
DoSpecialLineBreak(CharPtr string,Int2 indent)1140 NLM_EXTERN Boolean LIBCALL DoSpecialLineBreak (CharPtr string, Int2 indent)
1141 
1142 {
1143 	Boolean retval;
1144 	static Int2 length=0;
1145 
1146 	if (string == NULL)
1147 	{
1148 		length = 0;
1149 		retval = FALSE;
1150 	}
1151 	else
1152 	{
1153 		length += StringLen(string);
1154 		length += 2;
1155 		if (length < (ASN2FF_GB_MAX-indent))
1156 		{
1157 			retval = FALSE;
1158 		}
1159 		else
1160 		{
1161 			length = StringLen(string);
1162 			length += 2;
1163 			retval = TRUE;
1164 		}
1165 	}
1166 	return retval;
1167 
1168 }	/* DoSpecialLineBreak */
1169