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