/* * Copyright (C) 2002 Laird Breyer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Author: Laird Breyer */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #if defined HAVE_UNISTD_H #include #endif #include #include #include #include #include #include #include #include "util.h" /*@constant double M_LN2@*/ extern char *progname; extern char *inputfile; extern long inputline; extern options_t u_options; extern options_t m_options; extern int cmd; extern char *textbuf; extern charbuf_len_t textbuf_len; #if defined HAVE_MBRTOWC extern wchar_t *wc_textbuf; extern charbuf_len_t wc_textbuf_len; #endif extern void *in_iobuf; extern void *out_iobuf; extern long system_pagesize; int sa_signal = 0; signal_cleanup_t cleanup = { NULL }; /*********************************************************** * GLOBAL BUFFERS * ***********************************************************/ void init_buffers() { /* preallocate primary text holding buffer */ textbuf_len = system_pagesize; textbuf = (char *)malloc(textbuf_len); MADVISE(textbuf, sizeof(char) * textbuf_len, MADV_SEQUENTIAL); #if defined HAVE_POSIX_MEMALIGN /* buffer must exist until after fclose() if used in setvbuf() */ if( 0 != posix_memalign(&in_iobuf, system_pagesize, BUFFER_MAG * system_pagesize) ) { in_iobuf = NULL; /* just to be sure */ } /* buffer must exist until after fclose() if used in setvbuf() */ if( 0 != posix_memalign(&out_iobuf, system_pagesize, BUFFER_MAG * system_pagesize) ) { out_iobuf = NULL; /* just to be sure */ } #elif defined HAVE_MEMALIGN /* memalign()ed memory can't be reclaimed by free() */ in_iobuf = (void *)memalign(system_pagesize, BUFFER_MAG * system_pagesize); out_iobuf = (void *)memalign(system_pagesize, BUFFER_MAG * system_pagesize); #elif defined HAVE_VALLOC /* valloc()ed memory can't be reclaimed by free() */ in_iobuf = (void *)valloc(BUFFER_MAG * system_pagesize); out_iobuf = (void *)valloc(BUFFER_MAG * system_pagesize); #endif } void cleanup_buffers() { /* free some global resources */ free(textbuf); #if defined HAVE_POSIX_MEMALIGN if( in_iobuf ) { free(in_iobuf); } if( out_iobuf ) { free(out_iobuf); } #endif } void cleanup_tempfiles() { if( cleanup.tempfile ) { unlink(cleanup.tempfile); cleanup.tempfile = NULL; } } void set_iobuf_mode(FILE *input) { struct stat statinfo; if( in_iobuf ) { /* choose appropriate buffering mode */ if( fstat(fileno(input), &statinfo) == 0 ) { switch(statinfo.st_mode & S_IFMT) { case S_IFREG: case S_IFBLK: setvbuf(input, (char *)in_iobuf, _IOFBF, BUFFER_MAG * system_pagesize); break; case S_IFIFO: case S_IFCHR: setvbuf(input, (char *)NULL, (u_options & (1< (1<<(16 - DIG_FACTOR)) ) { return DIGITIZED_WEIGHT_MAX; } else { return (digitized_weight_t)(w * (order<= (l - 1)) ) { textbuf = (char *)realloc(textbuf, 2 * textbuf_len); if( !textbuf ) { fprintf(stderr, "error: not enough memory for input line (%d bytes)\n", textbuf_len); cleanup_tempfiles(); exit(1); } s = textbuf + textbuf_len - (k++); l = textbuf_len; textbuf_len *= 2; MADVISE(textbuf, sizeof(char) * textbuf_len, MADV_SEQUENTIAL); } return 1; } else if( *extra_lines > 0 ) { strcpy(textbuf, "\r\n"); *extra_lines = (*extra_lines) - 1; return 1; } return 0; } /*********************************************************** * WIDE CHARACTER FILE HANDLING FUNCTIONS * * this is needed for any locale whose character set * * encoding can include NUL bytes inside characters * ***********************************************************/ #if defined HAVE_MBRTOWC /* this does the same work as mbstowcs, but unlike the latter, * we continue converting even if an error is detected. That * is why we can't use the standard function. * Returns true if the converted line is nonempty. */ bool_t fill_wc_textbuf(char *pptextbuf, mbstate_t *shiftstate) { char *s; charbuf_len_t k,l; charbuf_len_t wclen; wchar_t *wp; if( !pptextbuf || !*pptextbuf ) { return 0; } if( textbuf_len > wc_textbuf_len ) { wc_textbuf_len = textbuf_len; wc_textbuf = (wchar_t *)realloc(wc_textbuf, wc_textbuf_len * sizeof(wchar_t)); if( !wc_textbuf ) { fprintf(stderr, "error: not enough memory for wide character conversion " "(%ld bytes)\n", (long int)(wc_textbuf_len * sizeof(wchar_t))); cleanup_tempfiles(); exit(1); } MADVISE(wc_textbuf, sizeof(wchar_t) * wc_textbuf_len, MADV_SEQUENTIAL); } /* convert as much as we can of the line into wide characters */ s = pptextbuf; k = textbuf_len; wp = wc_textbuf; wclen = 0; /* since we ensured textbuf_len <= wctextbuf_len there will never be overflow of wctextbuf below */ while( k > 0 ) { l = mbrtowc(wp, s, k, shiftstate); if( l > 0 ) { wp++; wclen++; k -= l; s += l; } else if( l == 0 ) { break; } else if( l == -1 ) { /* try to be robust */ s++; k--; memset(shiftstate, 0, sizeof(mbstate_t)); } else if( l == -2) { /* couldn't parse a complete character */ break; } } *wp = L'\0'; return (wclen > 0); } #endif