1 /* tofile.c
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
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 have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * File Name: tofile.c
27 *
28 * Author: Jonathan Kans
29 *
30 * Version Creation Date: 9/24/91
31 *
32 * $Revision: 6.4 $
33 *
34 * File Description: Converts fielded text into final report in a file
35 *
36 * Modifications:
37 * --------------------------------------------------------------------------
38 * Date Name Description of modification
39 * ------- ---------- -----------------------------------------------------
40 *
41 *
42 * $Log: tofile.c,v $
43 * Revision 6.4 2005/06/24 16:48:16 kans
44 * SkipPastNewLine and SendTextToFile use Uint2 because buffer is 64000
45 *
46 * Revision 6.3 2004/12/16 18:14:50 kans
47 * increased buffer to 64000 to deal with pmid 15330847 huge abstract
48 *
49 * Revision 6.2 2003/03/27 18:23:42 kans
50 * increased 16000 character buffer to 24000 to handle long PubMed abstracts (e.g., pmid 12209194 technical report on toxicity studies)
51 *
52 * Revision 6.1 1998/06/12 20:05:48 kans
53 * fixed unix compiler warnings
54 *
55 * Revision 6.0 1997/08/25 18:07:51 madden
56 * Revision changed to 6.0
57 *
58 * Revision 5.2 1997/06/19 18:39:23 vakatov
59 * [WIN32,MSVC++] Adopted for the "NCBIOBJ.LIB" DLL'ization
60 *
61 * Revision 5.1 1996/10/17 19:54:10 kans
62 * fixed centering calculation
63 *
64 * Revision 5.0 1996/05/28 13:23:23 ostell
65 * Set to revision 5.0
66 *
67 * Revision 4.0 1995/07/26 13:49:01 ostell
68 * force revision to 4.0
69 *
70 * Revision 2.2 1995/05/15 21:46:05 ostell
71 * added Log line
72 *
73 *
74 *
75 * ==========================================================================
76 */
77
78 #include <ncbi.h>
79 #include <tofile.h>
80
81 typedef struct cellData {
82 Uint2 start;
83 Int2 count;
84 } CellData, PNTR CellPtr;
85
86 typedef struct tableData {
87 CharPtr text;
88 CellPtr cells;
89 Int2 numCells;
90 Int2 numRows;
91 Int2 numCols;
92 Boolean openSpace;
93 ColPtr colFmt;
94 } TableData, PNTR TablePtr;
95
96 static ColData defaultTable = {0, 0, 0, 'l', TRUE, TRUE, TRUE};
97
98 /* ----- Function Prototypes ----- */
99
100 static Int2 GetNextBlock PROTO((CharPtr title, Int2 maxwid));
101 static void RecordCell PROTO((TablePtr tptr, Uint2 start, Int2 len, Int2 row, Int2 col));
102 static void SetTableFormat PROTO((ColPtr colFmt));
103 static void FormatTable PROTO((TablePtr tptr));
104 static Uint2 SkipPastNewLine PROTO((CharPtr text, Uint2 cnt));
105 static TablePtr TableSegment PROTO((CharPtr text, Int2 len, ParPtr parFmt, ColPtr colFmt));
106 static Boolean SaveTableToFile PROTO((Pointer dat, FILE *f));
107 static void FreeTable PROTO((TablePtr tptr));
108
109 /* ----- Function Bodies ----- */
110
SetTableFormat(ColPtr colFmt)111 static void SetTableFormat (ColPtr colFmt)
112
113 {
114 Int2 i;
115
116 colFmt [0].pos = 0;
117 if (! colFmt [0].last) {
118 i = 0;
119 do {
120 i++;
121 colFmt [i].pos = colFmt [i - 1].pos + colFmt [i - 1].width;
122 } while (! colFmt [i].last);
123 }
124 }
125
GetNextBlock(CharPtr title,Int2 maxwid)126 static Int2 GetNextBlock (CharPtr title, Int2 maxwid)
127
128 {
129 Char ch;
130 Int2 i;
131 Int2 j;
132 Int2 wid;
133
134 i = 0;
135 j = 0;
136 wid = 0;
137 if (title != NULL && maxwid > 0) {
138 ch = title [i];
139 while (ch != '\0' && ch != '\n' && ch != '\r' &&
140 ch != '\t' && wid <= maxwid) {
141 wid++;
142 i++;
143 ch = title [i];
144 }
145 j = i;
146 if (wid > maxwid) {
147 j--;
148 while (i > maxwid) {
149 i--;
150 }
151 while (i > 0 && title [i - 1] != ' ' && title [i - 1] != '-') {
152 i--;
153 }
154 while (title [i] == ' ') {
155 i++;
156 }
157 }
158 }
159 if (i > 0 && i < j) {
160 return i;
161 } else if (j > 0) {
162 return j;
163 } else {
164 return 0;
165 }
166 }
167
RecordCell(TablePtr tptr,Uint2 start,Int2 len,Int2 row,Int2 col)168 static void RecordCell (TablePtr tptr, Uint2 start, Int2 len, Int2 row, Int2 col)
169
170 {
171 Int2 cell;
172 CellPtr cellPtr;
173 Int2 chunk;
174 Int2 newCells;
175 Int2 numCells;
176 Int2 numCols;
177
178 if (tptr != NULL) {
179 chunk = 128;
180 numCells = tptr->numCells;
181 numCols = tptr->numCols;
182 if (col < numCols) {
183 cell = (Int2) ((Int4) row * (Int4) numCols + (Int4) col);
184 cellPtr = tptr->cells;
185 if (cell >= numCells) {
186 newCells = (cell / chunk + 1) * chunk;
187 if (cellPtr != NULL) {
188 cellPtr = MemMore (cellPtr, sizeof (CellData) * newCells);
189 while (numCells < newCells) {
190 cellPtr [numCells].start = 0;
191 cellPtr [numCells].count = 0;
192 numCells++;
193 }
194 } else {
195 cellPtr = MemNew (sizeof (CellData) * newCells);
196 }
197 tptr->cells = cellPtr;
198 tptr->numCells = newCells;
199 }
200 if (cellPtr != NULL) {
201 cellPtr [cell].start = start;
202 cellPtr [cell].count = len;
203 }
204 }
205 }
206 }
207
FormatTable(TablePtr tptr)208 static void FormatTable (TablePtr tptr)
209
210 {
211 Int2 blklen;
212 Char ch;
213 Int2 col;
214 ColPtr colFmt;
215 Int2 insetLeft;
216 Int2 insetRight;
217 Char just;
218 Int2 len = 0;
219 Int2 maxwid;
220 Int2 numCols;
221 Int2 returnRow;
222 Int2 row;
223 Uint2 start;
224 Boolean stripSpaces;
225 Int2 tabRow;
226 CharPtr text;
227
228 text = tptr->text;
229 colFmt = tptr->colFmt;
230 numCols = tptr->numCols;
231 if (text != NULL) {
232 start = 0;
233 row = 0;
234 tabRow = 0;
235 returnRow = 1;
236 col = 0;
237 while (text [start] != '\0') {
238 if (col < numCols) {
239 stripSpaces = colFmt [col].strip;
240 } else {
241 stripSpaces = TRUE;
242 }
243 if (stripSpaces) {
244 while (text [start] == ' ') {
245 start++;
246 }
247 }
248 ch = text [start];
249 if (ch != '\0' && ch != '\n' && ch != '\r' && ch != '\t') {
250 maxwid = INT2_MAX;
251 just = colFmt [col].just;
252 if (just == 'c') {
253 insetLeft = colFmt [col].inset;
254 insetRight = colFmt [col].inset;
255 } else if (just == 'l') {
256 insetLeft = colFmt [col].inset;
257 insetRight = 0;
258 } else if (just == 'r') {
259 insetLeft = 0;
260 insetRight = colFmt [col].inset;
261 } else {
262 insetLeft = 0;
263 insetRight = 0;
264 }
265 if (col < numCols && colFmt [col].wrap && colFmt [col].width > 0 &&
266 colFmt [col].width >= insetLeft + insetRight) {
267 maxwid = colFmt [col].width - insetLeft - insetRight;
268 }
269 blklen = GetNextBlock (text + start, maxwid);
270 len = blklen;
271 if (len > 0) {
272 if (text [start + len] != '\0') {
273 while (len > 0 && text [start + len - 1] == ' ') {
274 len--;
275 }
276 }
277 RecordCell (tptr, start, len, row, col);
278 if (len > 0) {
279 if (colFmt [col].width == 0) {
280 colFmt [col].width = len + 1;
281 }
282 }
283 start += blklen;
284 } else {
285 while (len <= maxwid) {
286 len++;
287 }
288 len--;
289 if (len > 0) {
290 RecordCell (tptr, start, len, row, col);
291 }
292 ch = text [start];
293 while (ch != '\0' && ch != '\n' && ch != '\r' && ch != '\t') {
294 start++;
295 ch = text [start];
296 }
297 }
298 }
299 ch = text [start];
300 if (ch == '\n') {
301 start++;
302 row = returnRow;
303 tabRow = row;
304 returnRow++;
305 col = 0;
306 } else if (ch == '\r') {
307 start++;
308 row++;
309 returnRow = MAX (returnRow, row + 1);
310 } else if (ch == '\t') {
311 start++;
312 row = tabRow;
313 col++;
314 } else if (ch != '\0' && colFmt [col].wrap) {
315 if (len == 0) {
316 start++;
317 }
318 row++;
319 returnRow = MAX (returnRow, row + 1);
320 } else if (ch != '\0') {
321 start++;
322 }
323 }
324 if (row > tptr->numRows) {
325 tptr->numRows = row;
326 }
327 }
328 }
329
TableSegment(CharPtr text,Int2 len,ParPtr parFmt,ColPtr colFmt)330 static TablePtr TableSegment (CharPtr text, Int2 len, ParPtr parFmt, ColPtr colFmt)
331
332 {
333 Int2 i;
334 TablePtr tptr;
335 CharPtr txt;
336
337 tptr = MemNew (sizeof (TableData));
338 if (tptr != NULL) {
339 txt = (CharPtr) MemNew (len + 1);
340 MemCopy (txt, text, len);
341 tptr->text = txt;
342 tptr->cells = NULL;
343 tptr->numCells = 0;
344 tptr->numRows = 0;
345 if (colFmt == NULL) {
346 defaultTable.pos = 0;
347 defaultTable.width = 80;
348 colFmt = &defaultTable;
349 }
350 i = 0;
351 while (! colFmt [i].last) {
352 i++;
353 }
354 i++;
355 tptr->numCols = i;
356 tptr->colFmt = MemNew (i * sizeof (ColData));
357 if (tptr->colFmt != NULL) {
358 MemCopy (tptr->colFmt, colFmt, i * sizeof (ColData));
359 }
360 if (parFmt != NULL) {
361 tptr->openSpace = parFmt->openSpace;
362 } else {
363 tptr->openSpace = TRUE;
364 }
365 SetTableFormat (colFmt);
366 FormatTable (tptr);
367 }
368 return tptr;
369 }
370
SaveTableToFile(Pointer dat,FILE * f)371 static Boolean SaveTableToFile (Pointer dat, FILE *f)
372
373 {
374 Int2 cell;
375 CellPtr cellPtr;
376 Int2 col;
377 ColPtr colFmt;
378 Int2 count;
379 Int2 insetLeft;
380 Int2 insetRight;
381 Char just;
382 Int2 next;
383 Int2 numCells;
384 Int2 numCols;
385 Int2 numRows;
386 Int2 pos;
387 Int2 row;
388 Boolean rsult;
389 Uint2 start;
390 CharPtr text;
391 TablePtr tptr;
392
393 rsult = TRUE;
394 if (dat != NULL && f != NULL) {
395 tptr = (TablePtr) dat;
396 colFmt = tptr->colFmt;
397 SetTableFormat (colFmt);
398 text = tptr->text;
399 cellPtr = tptr->cells;
400 numCells = tptr->numCells;
401 numCols = tptr->numCols;
402 numRows = tptr->numRows;
403 if (tptr->openSpace) {
404 if (fputc ('\n', f) == EOF) {
405 rsult = FALSE;
406 }
407 }
408 for (row = 0; row < numRows; row++) {
409 pos = 0;
410 for (col = 0; col < numCols; col++) {
411 cell = (Int2) ((Int4) row * (Int4) numCols + (Int4) col);
412 if (cell < numCells) {
413 if (text != NULL && cellPtr != NULL) {
414 start = cellPtr [cell].start;
415 count = cellPtr [cell].count;
416 if (count > 0) {
417 just = colFmt [col].just;
418 if (just == 'c') {
419 insetLeft = colFmt [col].inset;
420 insetRight = colFmt [col].inset;
421 } else if (just == 'l') {
422 insetLeft = colFmt [col].inset;
423 insetRight = 0;
424 } else if (just == 'r') {
425 insetLeft = 0;
426 insetRight = colFmt [col].inset;
427 } else {
428 insetLeft = 0;
429 insetRight = 0;
430 }
431 next = colFmt [col].pos + insetLeft;
432 while (pos < next) {
433 if (fputc (' ', f) == EOF) {
434 rsult = FALSE;
435 }
436 pos++;
437 }
438 if (just == 'r') {
439 next = colFmt [col].pos + colFmt [col].width - insetRight - count;
440 while (pos < next) {
441 if (fputc (' ', f) == EOF) {
442 rsult = FALSE;
443 }
444 pos++;
445 }
446 } else if (just == 'c') {
447 next = colFmt [col].pos + (colFmt [col].width - insetRight - count) / 2;
448 while (pos < next) {
449 if (fputc (' ', f) == EOF) {
450 rsult = FALSE;
451 }
452 pos++;
453 }
454 }
455 while (count > 0) {
456 if (fputc (text [start], f) == EOF) {
457 rsult = FALSE;
458 }
459 start++;
460 count--;
461 pos++;
462 }
463 }
464 }
465 }
466 }
467 if (fputc ('\n', f) == EOF) {
468 rsult = FALSE;
469 }
470 }
471 }
472 return rsult;
473 }
474
FreeTable(TablePtr tptr)475 static void FreeTable (TablePtr tptr)
476
477 {
478 CellPtr cellPtr;
479 ColPtr colFmt;
480 CharPtr text;
481
482 if (tptr != NULL) {
483 text = tptr->text;
484 cellPtr = tptr->cells;
485 colFmt = tptr->colFmt;
486 tptr->text = MemFree (text);
487 tptr->cells = MemFree (cellPtr);
488 tptr->colFmt = MemFree (colFmt);
489 MemFree (tptr);
490 }
491 }
492
SkipPastNewLine(CharPtr text,Uint2 cnt)493 static Uint2 SkipPastNewLine (CharPtr text, Uint2 cnt)
494
495 {
496 Char ch;
497
498 ch = *(text + cnt);
499 while (ch != '\0' && ch != '\n' && cnt < 64300) {
500 cnt++;
501 ch = *(text + cnt);
502 }
503 while ((ch == '\n' || ch == '\r') && cnt < 64380) {
504 cnt++;
505 ch = *(text + cnt);
506 }
507 return cnt;
508 }
509
SendTextToFile(FILE * f,CharPtr text,ParPtr parFmt,ColPtr colFmt)510 NLM_EXTERN Boolean SendTextToFile (FILE *f, CharPtr text, ParPtr parFmt, ColPtr colFmt)
511
512 {
513 Uint2 cnt;
514 Uint2 cntr;
515 Boolean rsult;
516 Int2 start;
517 TablePtr tptr;
518
519 rsult = TRUE;
520 start = 0;
521 cntr = StringLen (text);
522 cnt = MIN (cntr, 64000);
523 cnt = SkipPastNewLine (text + start, cnt);
524 while (cnt > 0) {
525 tptr = TableSegment (text + start, cnt, parFmt, colFmt);
526 if (! SaveTableToFile (tptr, f)) {
527 rsult = FALSE;
528 }
529 FreeTable (tptr);
530 start += cnt;
531 cntr -= cnt;
532 cnt = MIN (cntr, 64000);
533 cnt = SkipPastNewLine (text + start, cnt);
534 }
535 return rsult;
536 }
537