/* tofile.c * =========================================================================== * * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information * * This software/database is a "United States Government Work" under the * terms of the United States Copyright Act. It was written as part of * the author's official duties as a United States Government employee and * thus cannot be copyrighted. This software/database is freely available * to the public for use. The National Library of Medicine and the U.S. * Government have not placed any restriction on its use or reproduction. * * Although all reasonable efforts have been taken to ensure the accuracy * and reliability of the software and data, the NLM and the U.S. * Government do not and cannot warrant the performance or results that * may be obtained by using this software or data. The NLM and the U.S. * Government disclaim all warranties, express or implied, including * warranties of performance, merchantability or fitness for any particular * purpose. * * Please cite the author in any work or product based on this material. * * =========================================================================== * * File Name: tofile.c * * Author: Jonathan Kans * * Version Creation Date: 9/24/91 * * $Revision: 6.4 $ * * File Description: Converts fielded text into final report in a file * * Modifications: * -------------------------------------------------------------------------- * Date Name Description of modification * ------- ---------- ----------------------------------------------------- * * * $Log: tofile.c,v $ * Revision 6.4 2005/06/24 16:48:16 kans * SkipPastNewLine and SendTextToFile use Uint2 because buffer is 64000 * * Revision 6.3 2004/12/16 18:14:50 kans * increased buffer to 64000 to deal with pmid 15330847 huge abstract * * Revision 6.2 2003/03/27 18:23:42 kans * increased 16000 character buffer to 24000 to handle long PubMed abstracts (e.g., pmid 12209194 technical report on toxicity studies) * * Revision 6.1 1998/06/12 20:05:48 kans * fixed unix compiler warnings * * Revision 6.0 1997/08/25 18:07:51 madden * Revision changed to 6.0 * * Revision 5.2 1997/06/19 18:39:23 vakatov * [WIN32,MSVC++] Adopted for the "NCBIOBJ.LIB" DLL'ization * * Revision 5.1 1996/10/17 19:54:10 kans * fixed centering calculation * * Revision 5.0 1996/05/28 13:23:23 ostell * Set to revision 5.0 * * Revision 4.0 1995/07/26 13:49:01 ostell * force revision to 4.0 * * Revision 2.2 1995/05/15 21:46:05 ostell * added Log line * * * * ========================================================================== */ #include #include typedef struct cellData { Uint2 start; Int2 count; } CellData, PNTR CellPtr; typedef struct tableData { CharPtr text; CellPtr cells; Int2 numCells; Int2 numRows; Int2 numCols; Boolean openSpace; ColPtr colFmt; } TableData, PNTR TablePtr; static ColData defaultTable = {0, 0, 0, 'l', TRUE, TRUE, TRUE}; /* ----- Function Prototypes ----- */ static Int2 GetNextBlock PROTO((CharPtr title, Int2 maxwid)); static void RecordCell PROTO((TablePtr tptr, Uint2 start, Int2 len, Int2 row, Int2 col)); static void SetTableFormat PROTO((ColPtr colFmt)); static void FormatTable PROTO((TablePtr tptr)); static Uint2 SkipPastNewLine PROTO((CharPtr text, Uint2 cnt)); static TablePtr TableSegment PROTO((CharPtr text, Int2 len, ParPtr parFmt, ColPtr colFmt)); static Boolean SaveTableToFile PROTO((Pointer dat, FILE *f)); static void FreeTable PROTO((TablePtr tptr)); /* ----- Function Bodies ----- */ static void SetTableFormat (ColPtr colFmt) { Int2 i; colFmt [0].pos = 0; if (! colFmt [0].last) { i = 0; do { i++; colFmt [i].pos = colFmt [i - 1].pos + colFmt [i - 1].width; } while (! colFmt [i].last); } } static Int2 GetNextBlock (CharPtr title, Int2 maxwid) { Char ch; Int2 i; Int2 j; Int2 wid; i = 0; j = 0; wid = 0; if (title != NULL && maxwid > 0) { ch = title [i]; while (ch != '\0' && ch != '\n' && ch != '\r' && ch != '\t' && wid <= maxwid) { wid++; i++; ch = title [i]; } j = i; if (wid > maxwid) { j--; while (i > maxwid) { i--; } while (i > 0 && title [i - 1] != ' ' && title [i - 1] != '-') { i--; } while (title [i] == ' ') { i++; } } } if (i > 0 && i < j) { return i; } else if (j > 0) { return j; } else { return 0; } } static void RecordCell (TablePtr tptr, Uint2 start, Int2 len, Int2 row, Int2 col) { Int2 cell; CellPtr cellPtr; Int2 chunk; Int2 newCells; Int2 numCells; Int2 numCols; if (tptr != NULL) { chunk = 128; numCells = tptr->numCells; numCols = tptr->numCols; if (col < numCols) { cell = (Int2) ((Int4) row * (Int4) numCols + (Int4) col); cellPtr = tptr->cells; if (cell >= numCells) { newCells = (cell / chunk + 1) * chunk; if (cellPtr != NULL) { cellPtr = MemMore (cellPtr, sizeof (CellData) * newCells); while (numCells < newCells) { cellPtr [numCells].start = 0; cellPtr [numCells].count = 0; numCells++; } } else { cellPtr = MemNew (sizeof (CellData) * newCells); } tptr->cells = cellPtr; tptr->numCells = newCells; } if (cellPtr != NULL) { cellPtr [cell].start = start; cellPtr [cell].count = len; } } } } static void FormatTable (TablePtr tptr) { Int2 blklen; Char ch; Int2 col; ColPtr colFmt; Int2 insetLeft; Int2 insetRight; Char just; Int2 len = 0; Int2 maxwid; Int2 numCols; Int2 returnRow; Int2 row; Uint2 start; Boolean stripSpaces; Int2 tabRow; CharPtr text; text = tptr->text; colFmt = tptr->colFmt; numCols = tptr->numCols; if (text != NULL) { start = 0; row = 0; tabRow = 0; returnRow = 1; col = 0; while (text [start] != '\0') { if (col < numCols) { stripSpaces = colFmt [col].strip; } else { stripSpaces = TRUE; } if (stripSpaces) { while (text [start] == ' ') { start++; } } ch = text [start]; if (ch != '\0' && ch != '\n' && ch != '\r' && ch != '\t') { maxwid = INT2_MAX; just = colFmt [col].just; if (just == 'c') { insetLeft = colFmt [col].inset; insetRight = colFmt [col].inset; } else if (just == 'l') { insetLeft = colFmt [col].inset; insetRight = 0; } else if (just == 'r') { insetLeft = 0; insetRight = colFmt [col].inset; } else { insetLeft = 0; insetRight = 0; } if (col < numCols && colFmt [col].wrap && colFmt [col].width > 0 && colFmt [col].width >= insetLeft + insetRight) { maxwid = colFmt [col].width - insetLeft - insetRight; } blklen = GetNextBlock (text + start, maxwid); len = blklen; if (len > 0) { if (text [start + len] != '\0') { while (len > 0 && text [start + len - 1] == ' ') { len--; } } RecordCell (tptr, start, len, row, col); if (len > 0) { if (colFmt [col].width == 0) { colFmt [col].width = len + 1; } } start += blklen; } else { while (len <= maxwid) { len++; } len--; if (len > 0) { RecordCell (tptr, start, len, row, col); } ch = text [start]; while (ch != '\0' && ch != '\n' && ch != '\r' && ch != '\t') { start++; ch = text [start]; } } } ch = text [start]; if (ch == '\n') { start++; row = returnRow; tabRow = row; returnRow++; col = 0; } else if (ch == '\r') { start++; row++; returnRow = MAX (returnRow, row + 1); } else if (ch == '\t') { start++; row = tabRow; col++; } else if (ch != '\0' && colFmt [col].wrap) { if (len == 0) { start++; } row++; returnRow = MAX (returnRow, row + 1); } else if (ch != '\0') { start++; } } if (row > tptr->numRows) { tptr->numRows = row; } } } static TablePtr TableSegment (CharPtr text, Int2 len, ParPtr parFmt, ColPtr colFmt) { Int2 i; TablePtr tptr; CharPtr txt; tptr = MemNew (sizeof (TableData)); if (tptr != NULL) { txt = (CharPtr) MemNew (len + 1); MemCopy (txt, text, len); tptr->text = txt; tptr->cells = NULL; tptr->numCells = 0; tptr->numRows = 0; if (colFmt == NULL) { defaultTable.pos = 0; defaultTable.width = 80; colFmt = &defaultTable; } i = 0; while (! colFmt [i].last) { i++; } i++; tptr->numCols = i; tptr->colFmt = MemNew (i * sizeof (ColData)); if (tptr->colFmt != NULL) { MemCopy (tptr->colFmt, colFmt, i * sizeof (ColData)); } if (parFmt != NULL) { tptr->openSpace = parFmt->openSpace; } else { tptr->openSpace = TRUE; } SetTableFormat (colFmt); FormatTable (tptr); } return tptr; } static Boolean SaveTableToFile (Pointer dat, FILE *f) { Int2 cell; CellPtr cellPtr; Int2 col; ColPtr colFmt; Int2 count; Int2 insetLeft; Int2 insetRight; Char just; Int2 next; Int2 numCells; Int2 numCols; Int2 numRows; Int2 pos; Int2 row; Boolean rsult; Uint2 start; CharPtr text; TablePtr tptr; rsult = TRUE; if (dat != NULL && f != NULL) { tptr = (TablePtr) dat; colFmt = tptr->colFmt; SetTableFormat (colFmt); text = tptr->text; cellPtr = tptr->cells; numCells = tptr->numCells; numCols = tptr->numCols; numRows = tptr->numRows; if (tptr->openSpace) { if (fputc ('\n', f) == EOF) { rsult = FALSE; } } for (row = 0; row < numRows; row++) { pos = 0; for (col = 0; col < numCols; col++) { cell = (Int2) ((Int4) row * (Int4) numCols + (Int4) col); if (cell < numCells) { if (text != NULL && cellPtr != NULL) { start = cellPtr [cell].start; count = cellPtr [cell].count; if (count > 0) { just = colFmt [col].just; if (just == 'c') { insetLeft = colFmt [col].inset; insetRight = colFmt [col].inset; } else if (just == 'l') { insetLeft = colFmt [col].inset; insetRight = 0; } else if (just == 'r') { insetLeft = 0; insetRight = colFmt [col].inset; } else { insetLeft = 0; insetRight = 0; } next = colFmt [col].pos + insetLeft; while (pos < next) { if (fputc (' ', f) == EOF) { rsult = FALSE; } pos++; } if (just == 'r') { next = colFmt [col].pos + colFmt [col].width - insetRight - count; while (pos < next) { if (fputc (' ', f) == EOF) { rsult = FALSE; } pos++; } } else if (just == 'c') { next = colFmt [col].pos + (colFmt [col].width - insetRight - count) / 2; while (pos < next) { if (fputc (' ', f) == EOF) { rsult = FALSE; } pos++; } } while (count > 0) { if (fputc (text [start], f) == EOF) { rsult = FALSE; } start++; count--; pos++; } } } } } if (fputc ('\n', f) == EOF) { rsult = FALSE; } } } return rsult; } static void FreeTable (TablePtr tptr) { CellPtr cellPtr; ColPtr colFmt; CharPtr text; if (tptr != NULL) { text = tptr->text; cellPtr = tptr->cells; colFmt = tptr->colFmt; tptr->text = MemFree (text); tptr->cells = MemFree (cellPtr); tptr->colFmt = MemFree (colFmt); MemFree (tptr); } } static Uint2 SkipPastNewLine (CharPtr text, Uint2 cnt) { Char ch; ch = *(text + cnt); while (ch != '\0' && ch != '\n' && cnt < 64300) { cnt++; ch = *(text + cnt); } while ((ch == '\n' || ch == '\r') && cnt < 64380) { cnt++; ch = *(text + cnt); } return cnt; } NLM_EXTERN Boolean SendTextToFile (FILE *f, CharPtr text, ParPtr parFmt, ColPtr colFmt) { Uint2 cnt; Uint2 cntr; Boolean rsult; Int2 start; TablePtr tptr; rsult = TRUE; start = 0; cntr = StringLen (text); cnt = MIN (cntr, 64000); cnt = SkipPastNewLine (text + start, cnt); while (cnt > 0) { tptr = TableSegment (text + start, cnt, parFmt, colFmt); if (! SaveTableToFile (tptr, f)) { rsult = FALSE; } FreeTable (tptr); start += cnt; cntr -= cnt; cnt = MIN (cntr, 64000); cnt = SkipPastNewLine (text + start, cnt); } return rsult; }