1 /*
2  * International Chemical Identifier (InChI)
3  * Version 1
4  * Software version 1.04
5  * September 9, 2011
6  *
7  * The InChI library and programs are free software developed under the
8  * auspices of the International Union of Pure and Applied Chemistry (IUPAC).
9  * Originally developed at NIST. Modifications and additions by IUPAC
10  * and the InChI Trust.
11  *
12  * IUPAC/InChI-Trust Licence for the International Chemical Identifier (InChI)
13  * Software version 1.0.
14  * Copyright (C) IUPAC and InChI Trust Limited
15  *
16  * This library is free software; you can redistribute it and/or modify it under the
17  * terms of the IUPAC/InChI Trust Licence for the International Chemical Identifier
18  * (InChI) Software version 1.0; either version 1.0 of the License, or
19  * (at your option) any later version.
20  *
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24  * See the IUPAC/InChI Trust Licence for the International Chemical Identifier (InChI)
25  * Software version 1.0 for more details.
26  *
27  * You should have received a copy of the IUPAC/InChI Trust Licence for the
28  * International Chemical Identifier (InChI) Software version 1.0 along with
29  * this library; if not, write to:
30  *
31  * The InChI Trust
32  * c/o FIZ CHEMIE Berlin
33  * Franklinstrasse 11
34  * 10587 Berlin
35  * GERMANY
36  *
37  */
38 
39 
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <ctype.h>
44 #include <stdarg.h>
45 #include "mode.h"
46 #include "ichi_io.h"
47 #include "ichicomp.h"
48 #include "util.h"
49 
50 #ifndef INCHI_ADD_STR_LEN
51 #define INCHI_ADD_STR_LEN   32768
52 #endif
53 
54 
55 #ifdef TARGET_LIB_FOR_WINCHI
56 extern void (*FWPRINT) (const char * format, va_list argptr );
57 #endif
58 
59 
60 /*^^^ Internal functions */
61 
62 int inchi_ios_str_getc( INCHI_IOSTREAM *ios );
63 char *inchi_ios_str_gets( char *szLine, int len, INCHI_IOSTREAM *ios );
64 char *inchi_ios_str_getsTab( char *szLine, int len, INCHI_IOSTREAM *ios );
65 int GetMaxPrintfLength( const char *lpszFormat, va_list argList);
66 char *inchi_fgetsTab( char *szLine, int len, FILE *f );
67 int inchi_vfprintf( FILE* f, const char* lpszFormat, va_list argList );
68 
69 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
70 
71 
72                                     INCHI_IOSTREAM OPERATIONS
73 
74 
75 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
76 
77 
78 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
79     Init INCHI_IOSTREAM
80 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
inchi_ios_init(INCHI_IOSTREAM * ios,int io_type,FILE * f)81 void inchi_ios_init(INCHI_IOSTREAM* ios, int io_type, FILE *f)
82 {
83     memset( ios, 0, sizeof(*ios) );
84     switch (io_type)
85     {
86         case INCHI_IOSTREAM_FILE:	ios->type = INCHI_IOSTREAM_FILE;
87                                     break;
88         case INCHI_IOSTREAM_STRING:
89         default:                    ios->type = INCHI_IOSTREAM_STRING;
90                                     break;
91     }
92     ios->f = f;
93     return;
94 }
95 
96 
97 
98 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
99     If INCHI_IOSTREAM type is INCHI_IOSTREAM_STRING,
100         flush INCHI_IOSTREAM string buffer to file (if non-NULL); then free buffer.
101     If INCHI_IOSTREAM type is INCHI_IOSTREAM_FILE, just flush the file.
102 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
inchi_ios_flush(INCHI_IOSTREAM * ios)103 void inchi_ios_flush(INCHI_IOSTREAM* ios)
104 {
105 
106     if (ios->type == INCHI_IOSTREAM_STRING)
107     {
108         if (ios->s.pStr)
109         {
110             if (ios->s.nUsedLength > 0)
111             {
112                 if (ios->f)
113                 {
114                     fprintf(ios->f,"%-s", ios->s.pStr);
115                     fflush(ios->f);
116                 }
117                 inchi_free(ios->s.pStr );
118                 ios->s.pStr = NULL;
119                 ios->s.nUsedLength = ios->s.nAllocatedLength = ios->s.nPtr = 0;
120             }
121         }
122     }
123 
124     else if (ios->type == INCHI_IOSTREAM_FILE)
125     {
126         /* output to plain file: just flush it. */
127         fflush(ios->f);
128     }
129 
130     return;
131 }
132 
133 
134 
135 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
136     If INCHI_IOSTREAM type is INCHI_IOSTREAM_STRING,
137         flush INCHI_IOSTREAM string buffer to file (if non-NULL) and
138         another file f2 supplied as parameter (typically, it will be stderr); then free buffer.
139     If INCHI_IOSTREAM type is INCHI_IOSTREAM_FILE, just flush the both files.
140 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
inchi_ios_flush2(INCHI_IOSTREAM * ios,FILE * f2)141 void inchi_ios_flush2(INCHI_IOSTREAM* ios, FILE *f2)
142 {
143 
144     if (ios->type == INCHI_IOSTREAM_STRING)
145     {
146         if (ios->s.pStr)
147         {
148             if (ios->s.nUsedLength > 0)
149             {
150                 if (ios->f)
151                 {
152                     fprintf(ios->f,"%-s", ios->s.pStr);
153                     fflush(ios->f);
154                 }
155                 if (f2!=ios->f)
156                     fprintf(f2,"%-s", ios->s.pStr);
157 
158                 inchi_free(ios->s.pStr );
159                 ios->s.pStr = NULL;
160                 ios->s.nUsedLength = ios->s.nAllocatedLength = ios->s.nPtr = 0;
161             }
162         }
163     }
164 
165     else if (ios->type == INCHI_IOSTREAM_FILE)
166     {
167         /* output to plain file: just flush it. */
168         if ( (ios->f) && (ios->f!=stderr) && (ios->f!=stdout) )
169             fflush(ios->f);
170         if ( f2 && f2!=stderr && f2!=stdout)
171             fflush(f2);
172 
173 
174     }
175 
176     return;
177 }
178 
179 
180 
181 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
182     Close INCHI_IOSTREAM: free string buffer and close the file.
183 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
inchi_ios_close(INCHI_IOSTREAM * ios)184 void inchi_ios_close(INCHI_IOSTREAM* ios)
185 {
186     if (ios->s.pStr)
187         inchi_free(ios->s.pStr);
188     ios->s.pStr = NULL;
189     ios->s.nUsedLength = ios->s.nAllocatedLength = ios->s.nPtr = 0;
190     if ( (ios->f) && (ios->f!=stderr) && (ios->f!=stdout) && (ios->f!=stdin))
191         fclose(ios->f);
192     return;
193 }
194 
195 
196 
197 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
198     Reset INCHI_IOSTREAM: set string buffer ptr to NULL (but do _not_ free memory)and close the file.
199 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
inchi_ios_reset(INCHI_IOSTREAM * ios)200 void inchi_ios_reset(INCHI_IOSTREAM* ios)
201 {
202     ios->s.pStr = NULL;
203     ios->s.nUsedLength = ios->s.nAllocatedLength = ios->s.nPtr = 0;
204     if ( (ios->f) && (ios->f!=stderr) && (ios->f!=stdout) && (ios->f!=stdin))
205         fclose(ios->f);
206     return;
207 }
208 
209 
210 
211 
212 
213 /*******************************************************************/
inchi_ios_str_getc(INCHI_IOSTREAM * ios)214 int inchi_ios_str_getc(INCHI_IOSTREAM *ios)
215 {
216 
217     if (ios->type==INCHI_IOSTREAM_STRING)
218     {
219         if ( ios->s.nPtr < ios->s.nUsedLength )
220         {
221             return (int)ios->s.pStr[ios->s.nPtr++];
222         }
223         return EOF;
224     }
225 
226     else if (ios->type==INCHI_IOSTREAM_FILE)
227     {
228         return fgetc( ios->f );
229     }
230 
231     /* error */
232     return EOF;
233 }
234 
235 
236 
237 /*******************************************************************/
inchi_ios_str_gets(char * szLine,int len,INCHI_IOSTREAM * f)238 char *inchi_ios_str_gets(char *szLine, int len, INCHI_IOSTREAM *f)
239 {
240 int  length=0, c=0;
241     if ( -- len < 0 )
242     {
243         return NULL;
244     }
245     while ( length < len && EOF != (c = inchi_ios_str_getc( f )) )
246     {
247         szLine[length++] = (char)c;
248         if ( c == '\n' )
249             break;
250     }
251     if ( !length && EOF == c )
252     {
253         return NULL;
254     }
255     szLine[length] = '\0';
256     return szLine;
257 }
258 
259 
260 
261 /********************************************************************************/
262 /* read up to len or tab or LF; if empty read next until finds non-empty line   */
263 /* remove leading and trailing white spaces; keep zero termination              */
264 /********************************************************************************/
inchi_ios_str_getsTab(char * szLine,int len,INCHI_IOSTREAM * f)265 char *inchi_ios_str_getsTab( char *szLine, int len, INCHI_IOSTREAM *f )
266 {
267 int  length=0, c=0;
268     if ( --len < 0 )
269     {
270         return NULL;
271     }
272     while ( length < len && EOF != (c = inchi_ios_str_getc(f)) )
273     {
274         if ( c == '\t' )
275             c = '\n';
276         szLine[length++] = (char)c;
277         if ( c == '\n' )
278             break;
279     }
280     if ( !length && EOF == c )
281     {
282         return NULL;
283     }
284     szLine[length] = '\0';
285     return szLine;
286 }
287 
288 
289 /*******************************************************************/
inchi_ios_gets(char * szLine,int len,INCHI_IOSTREAM * f,int * bTooLongLine)290 int inchi_ios_gets( char *szLine, int len, INCHI_IOSTREAM *f, int *bTooLongLine )
291 {
292 int  length;
293 char *p;
294     do
295     {
296         p = inchi_ios_str_gets( szLine, len-1, f );
297         if ( !p )
298         {
299             *bTooLongLine = 0;
300             return -1; /* end of file or cannot read */
301         }
302         szLine[len-1] = '\0';
303         /*
304         *bTooLongLine = !strchr( szLine, '\n' );
305         */
306         p = strchr( szLine, '\n' );
307         *bTooLongLine = ( !p && ((int)strlen(szLine)) == len-2 );
308         LtrimRtrim( szLine, &length );
309     } while ( !length );
310 
311     return length;
312 }
313 
314 
315 /*******************************************************************/
316 /* read up to len or tab or LF; if empty read next until finds non-empty line   */
317 /* remove leading and trailing white spaces; keep zero termination */
318 /*******************************************************************/
inchi_ios_getsTab(char * szLine,int len,INCHI_IOSTREAM * f,int * bTooLongLine)319 int inchi_ios_getsTab( char *szLine, int len, INCHI_IOSTREAM *f, int *bTooLongLine )
320 {
321 int  length;
322 char *p;
323     do
324     {
325         p = inchi_ios_str_getsTab( szLine, len-1, f );
326         if ( !p )
327         {
328             *bTooLongLine = 0;
329             return -1; /* end of file or cannot read */
330         }
331         szLine[len-1] = '\0';
332         /*
333         *bTooLongLine = !strchr( szLine, '\n' );
334         */
335         p = strchr( szLine, '\n' );
336         *bTooLongLine = ( !p && ((int)strlen(szLine)) == len-2 );
337         LtrimRtrim( szLine, &length );
338     } while ( !length );
339     return length;
340 }
341 
342 /*******************************************************************/
inchi_ios_getsTab1(char * szLine,int len,INCHI_IOSTREAM * f,int * bTooLongLine)343 int inchi_ios_getsTab1( char *szLine, int len, INCHI_IOSTREAM *f, int *bTooLongLine )
344 {
345 int  length;
346 char *p;
347     /*do {*/
348         p = inchi_ios_str_getsTab( szLine, len-1, f );
349         if ( !p )
350         {
351             *bTooLongLine = 0;
352             return -1; /* end of file or cannot read */
353         }
354         szLine[len-1] = '\0';
355         /*
356         *bTooLongLine = !strchr( szLine, '\n' );
357         */
358         p = strchr( szLine, '\n' );
359         *bTooLongLine = ( !p && ((int)strlen(szLine)) == len-2 );
360         LtrimRtrim( szLine, &length );
361     /*} while ( !length );*/
362     return length;
363 }
364 
365 
366 
367 
368 
369 
370 /*****************************************************************/
inchi_ios_print(INCHI_IOSTREAM * ios,const char * lpszFormat,...)371 int inchi_ios_print( INCHI_IOSTREAM * ios, const char* lpszFormat, ... )
372 {
373 int ret=0, ret2=0;
374 va_list argList;
375 
376     if (!ios)
377         return -1;
378 
379     if (ios->type == INCHI_IOSTREAM_STRING)
380     {
381         /* output to string buffer */
382         int max_len;
383         my_va_start( argList, lpszFormat );
384         max_len = GetMaxPrintfLength( lpszFormat, argList);
385         va_end( argList );
386         if ( max_len >= 0 )
387         {
388             if ( ios->s.nAllocatedLength - ios->s.nUsedLength <= max_len )
389             {
390                 /* enlarge output string */
391                 int  nAddLength = inchi_max( INCHI_ADD_STR_LEN, max_len );
392                 char *new_str =
393                     (char *)inchi_calloc( ios->s.nAllocatedLength + nAddLength, sizeof(new_str[0]) );
394                 if ( new_str )
395                 {
396                     if ( ios->s.pStr )
397                     {
398                         if ( ios->s.nUsedLength > 0 )
399                             memcpy( new_str, ios->s.pStr, sizeof(new_str[0])* ios->s.nUsedLength );
400                         inchi_free( ios->s.pStr );
401                     }
402                     ios->s.pStr              = new_str;
403                     ios->s.nAllocatedLength += nAddLength;
404                 }
405                 else return -1; /* failed */
406             }
407             /* output */
408             my_va_start( argList, lpszFormat );
409             ret = vsprintf( ios->s.pStr + ios->s.nUsedLength, lpszFormat, argList );
410             va_end(argList);
411             if ( ret >= 0 )
412                 ios->s.nUsedLength += ret;
413 #ifdef TARGET_LIB_FOR_WINCHI
414             if( FWPRINT )
415             {
416                 my_va_start( argList, lpszFormat );
417                 FWPRINT( lpszFormat, argList );
418                 va_end( argList );
419             }
420 #endif
421             return ret;
422         }
423         return -1;
424     }
425 
426     else if (ios->type == INCHI_IOSTREAM_FILE)
427     {
428         /* output to file */
429         if (ios->f)
430         {
431             my_va_start( argList, lpszFormat );
432             ret = vfprintf( ios->f, lpszFormat, argList );
433             va_end( argList );
434         }
435         else
436         {
437             my_va_start( argList, lpszFormat );
438             ret2 = vfprintf( stdout, lpszFormat, argList );
439             va_end( argList );
440         }
441 #ifdef TARGET_LIB_FOR_WINCHI
442         if( FWPRINT )
443         {
444             my_va_start( argList, lpszFormat );
445             FWPRINT( lpszFormat, argList );
446             va_end( argList );
447         }
448 #endif
449         return ret? ret : ret2;
450     }
451 
452 
453     /* no output */
454     return 0;
455 }
456 
457 
458 
459 
460 /**********************************************************************/
461 /* This function's output should not be displayed in the output pane  */
462 /**********************************************************************/
inchi_ios_print_nodisplay(INCHI_IOSTREAM * ios,const char * lpszFormat,...)463 int inchi_ios_print_nodisplay( INCHI_IOSTREAM * ios, const char* lpszFormat, ... )
464 {
465 va_list argList;
466 
467     if (!ios)
468         return -1;
469 
470     if (ios->type == INCHI_IOSTREAM_STRING)
471     {
472         /* output to string buffer */
473         int ret=0, max_len;
474         my_va_start( argList, lpszFormat );
475         max_len = GetMaxPrintfLength( lpszFormat, argList);
476         va_end( argList );
477         if ( max_len >= 0 )
478         {
479             if ( ios->s.nAllocatedLength - ios->s.nUsedLength <= max_len )
480             {
481                 /* enlarge output string */
482                 int  nAddLength = inchi_max( INCHI_ADD_STR_LEN, max_len );
483                 char *new_str = (char *)inchi_calloc( ios->s.nAllocatedLength + nAddLength, sizeof(new_str[0]) );
484                 if ( new_str )
485                 {
486                     if ( ios->s.pStr )
487                     {
488                         if ( ios->s.nUsedLength > 0 )
489                         {
490                             memcpy( new_str, ios->s.pStr, sizeof(new_str[0])*ios->s.nUsedLength );
491                         }
492                         inchi_free( ios->s.pStr );
493                     }
494                     ios->s.pStr              = new_str;
495                     ios->s.nAllocatedLength += nAddLength;
496                 } else
497                 {
498                     return -1; /* failed */
499                 }
500             }
501             /* output */
502             my_va_start( argList, lpszFormat );
503             ret = vsprintf( ios->s.pStr + ios->s.nUsedLength, lpszFormat, argList );
504             va_end(argList);
505             if ( ret >= 0 )
506             {
507                 ios->s.nUsedLength += ret;
508             }
509             return ret;
510         }
511         return -1;
512     }
513 
514     else if (ios->type == INCHI_IOSTREAM_FILE)
515     {
516         my_va_start( argList, lpszFormat );
517         inchi_print_nodisplay( ios->f, lpszFormat, argList);
518         va_end(argList);
519     }
520 
521     /* no output */
522     return 0;
523 }
524 
525 
526 
527 
528 /*****************************************************************/
529 /* Print to string buffer or to file+stderr */
inchi_ios_eprint(INCHI_IOSTREAM * ios,const char * lpszFormat,...)530 int inchi_ios_eprint( INCHI_IOSTREAM * ios, const char* lpszFormat, ... )
531 {
532 int ret=0, ret2=0;
533 va_list argList;
534 
535     if (!ios)
536         return -1;
537 
538     if (ios->type == INCHI_IOSTREAM_STRING) /* was #if ( defined(TARGET_API_LIB) || defined(INCHI_STANDALONE_EXE) ) */
539     {
540         /* output to string buffer */
541         int max_len, nAddLength = 0;
542         char *new_str = NULL;
543 
544         my_va_start( argList, lpszFormat );
545         max_len = GetMaxPrintfLength( lpszFormat, argList);
546         va_end( argList );
547 
548         if ( max_len >= 0 )
549         {
550             if ( ios->s.nAllocatedLength - ios->s.nUsedLength <= max_len )
551             {
552                 /* enlarge output string */
553                 nAddLength = inchi_max( INCHI_ADD_STR_LEN, max_len );
554                 new_str = (char *)inchi_calloc( ios->s.nAllocatedLength + nAddLength, sizeof(new_str[0]) );
555                 if ( new_str )
556                 {
557                     if ( ios->s.pStr )
558                     {
559                         if ( ios->s.nUsedLength > 0 )
560                         {
561                             memcpy( new_str, ios->s.pStr, sizeof(new_str[0])* ios->s.nUsedLength );
562                         }
563                         inchi_free( ios->s.pStr );
564                     }
565                     ios->s.pStr              = new_str;
566                     ios->s.nAllocatedLength += nAddLength;
567                 }
568                 else
569                 {
570                     return -1; /* failed */
571                 }
572             }
573 
574             /* output */
575             my_va_start( argList, lpszFormat );
576             ret = vsprintf( ios->s.pStr + ios->s.nUsedLength, lpszFormat, argList );
577             va_end(argList);
578             if ( ret >= 0 )
579             {
580                 ios->s.nUsedLength += ret;
581             }
582             return ret;
583         }
584         return -1;
585     }
586 
587     else if (ios->type == INCHI_IOSTREAM_FILE)
588     {
589         if ( ios->f)
590         {
591             /* output to plain file */
592             my_va_start( argList, lpszFormat );
593             ret = inchi_vfprintf( ios->f, lpszFormat, argList );
594             va_end( argList );
595 /*^^^  No output to stderr from within dll or GUI program */
596 #if ( !defined(TARGET_API_LIB) && !defined(TARGET_LIB_FOR_WINCHI) )
597             if ( ios->f != stderr )
598             {
599                 my_va_start( argList, lpszFormat );
600                 ret2 = vfprintf( stderr, lpszFormat, argList );
601                 va_end( argList );
602             }
603 #endif
604             return ret? ret : ret2;
605         }
606     }
607 
608     /* no output */
609     return 0;
610 }
611 
612 
613 
614 
615 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
616 
617 
618                                     PLAIN FILE OPERATIONS
619 
620 
621 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
622 
623 
624 
625 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
626 
627 /* Print to file, echoing to stderr */
inchi_fprintf(FILE * f,const char * lpszFormat,...)628 int inchi_fprintf( FILE* f, const char* lpszFormat, ... )
629 {
630 int ret=0, ret2=0;
631 va_list argList;
632     if (f)
633     {
634         my_va_start( argList, lpszFormat );
635         ret = inchi_vfprintf( f, lpszFormat, argList );
636         va_end( argList );
637 /*^^^  No output to stderr from within dll or GUI program */
638 #if ( !defined(TARGET_API_LIB) && !defined(TARGET_LIB_FOR_WINCHI) )
639         if ( f != stderr )
640         {
641             my_va_start( argList, lpszFormat );
642             ret2 = vfprintf( stderr, lpszFormat, argList );
643             va_end( argList );
644         }
645 #endif
646         return ret? ret : ret2;
647     }
648     return 0;
649 }
650 
651 
652 
653 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
654 
655 /* Print to file */
inchi_vfprintf(FILE * f,const char * lpszFormat,va_list argList)656 int inchi_vfprintf( FILE* f, const char* lpszFormat, va_list argList )
657 {
658 int ret=0;
659     if ( f == stderr && lpszFormat && lpszFormat[0] && '\r' == lpszFormat[strlen(lpszFormat)-1] )
660     {
661 #define CONSOLE_LINE_LEN 80
662 #ifndef COMPILE_ANSI_ONLY
663         char szLine[CONSOLE_LINE_LEN];
664         ret = _vsnprintf( szLine, CONSOLE_LINE_LEN-1, lpszFormat, argList );
665         if ( ret < 0 )
666         {
667             /*  output is longer than the console line */
668             /*^^^ Fixed bug: (CONSOLE_LINE_LEN-4) --> (CONSOLE_LINE_LEN-4-1) 11-22-08 IPl */
669             strcpy(szLine+CONSOLE_LINE_LEN-5, "...\r");
670         }
671         fputs( szLine, f );
672 #else
673         ret = vfprintf( f, lpszFormat, argList );
674 #endif
675 #undef CONSOLE_LINE_LEN
676     }
677     else
678     {
679         ret = vfprintf( f, lpszFormat, argList );
680     }
681     return ret;
682 }
683 
684 
685 
686 /**********************************************************************/
687 /* This function's output should not be displayed in the output pane  */
688 /**********************************************************************/
inchi_print_nodisplay(FILE * f,const char * lpszFormat,...)689 int inchi_print_nodisplay( FILE* f, const char* lpszFormat, ... )
690 {
691 int ret=0;
692 va_list argList;
693 FILE* fi;
694     if (f)
695         fi = f;
696     else
697         fi = stdout;
698     my_va_start( argList, lpszFormat );
699     ret = vfprintf( fi, lpszFormat, argList );
700     return ret;
701 }
702 
703 
704 
705 #if ( FIX_READ_LONG_LINE_BUG == 1 )
706 /********************************************************************/
inchi_fgetsLfTab(char * szLine,int len,FILE * f)707 int inchi_fgetsLfTab( char *szLine, int len, FILE *f )
708 {
709     int  length;
710     char *p;
711     char szSkip[256];
712     int  bTooLongLine = 0;
713     do {
714         p = inchi_fgetsTab( szLine, len, f );
715         if ( !p ) {
716             return -1; /* end of file or cannot read */
717         }
718         bTooLongLine = ( (int)strlen(szLine) == len-1 && szLine[len-2] != '\n' );
719         LtrimRtrim( szLine, &length );
720     } while ( !length );
721     if ( bTooLongLine ) {
722         while ( (p = inchi_fgetsTab( szSkip, sizeof(szSkip)-1, f )) ) {
723             if ( strchr( szSkip, '\n' ) )
724                 break;
725         }
726     }
727     return length;
728 }
729 #else
730 /********************************************************************/
inchi_fgetsLfTab(char * szLine,int len,FILE * f)731 int inchi_fgetsLfTab( char *szLine, int len, FILE *f )
732 {
733     int  length;
734     char *p;
735     char szSkip[256];
736     int  bTooLongLine = 0;
737     do {
738         p = inchi_fgetsTab( szLine, len-1, f );
739         if ( !p ) {
740             return -1; /* end of file or cannot read */
741         }
742         szLine[len-1] = '\0';
743         /*
744         bTooLongLine = !strchr( szLine, '\n' );
745         */
746         bTooLongLine = ( !p && ((int)strlen(szLine)) == len-2 );
747         LtrimRtrim( szLine, &length );
748     } while ( !length );
749     if ( bTooLongLine ) {
750         while ( p = inchi_fgetsTab( szSkip, sizeof(szSkip)-1, f ) ) {
751             szSkip[sizeof(szSkip)-1] = '\0';
752             if ( strchr( szSkip, '\n' ) )
753                 break;
754         }
755     }
756     return length;
757 }
758 #endif
759 
760 
761 /*******************************************************************/
762 /* read up to len or tab or LF; if empty read next until finds non-empty line   */
763 /* remove leading and trailing white spaces; keep zero termination */
764 /*******************************************************************/
inchi_fgetsTab(char * szLine,int len,FILE * f)765 char *inchi_fgetsTab( char *szLine, int len, FILE *f )
766 {
767     int  length=0, c=0;
768     len --;
769     while ( length < len && EOF != (c = fgetc( f )) ) {
770         if ( c == '\t' )
771             c = '\n';
772         szLine[length++] = (char)c;
773         if ( c == '\n' )
774             break;
775     }
776     if ( !length && EOF == c ) {
777         return NULL;
778     }
779     szLine[length] = '\0';
780     return szLine;
781 }
782 
783 
784 
785 /******************************************************************/
786 /* read not more than line_len bytes from an lf-terminated line   */
787 /* if input line is too long quietly ignore the rest of the line  */
inchi_fgetsLf(char * line,int line_len,FILE * inp)788 char* inchi_fgetsLf( char* line, int line_len, FILE* inp )
789 {
790     char *p, *q;
791     memset( line, 0, line_len );
792     if ( NULL != (p = fgets( line, line_len, inp ) ) && NULL == strchr(p, '\n' ) ){
793         char temp[64]; /* bypass up to '\n' or up to end of file whichever comes first*/
794         while ( NULL != fgets( temp, sizeof(temp), inp ) && NULL == strchr(temp,'\n') )
795             ;
796     }
797     if ( p && (q = strchr(line, '\r')) ) { /*  fix CR CR LF line terminator. */
798         q[0] = '\n';
799         q[1] = '\0';
800     }
801     return p;
802 }
803 
804 
805 
806 
807 
808 
809 
810 
811 
812 
813 /*****************************************************************
814  *
815  *  Estimate printf string length
816  *
817  *  The code is based on Microsoft Knowledge Base article Q127038:
818  *  "FIX: CString::Format Gives Assertion Failed, Access Violation"
819  *  (Related to Microsoft Visual C++, 32-bit Editions, versions 2.0, 2.1)
820  *
821  *****************************************************************/
822 
823 #define FORCE_ANSI      0x10000
824 #define FORCE_UNICODE   0x20000
825 
826 /* formatting (using wsprintf style formatting)*/
GetMaxPrintfLength(const char * lpszFormat,va_list argList)827 int GetMaxPrintfLength( const char *lpszFormat, va_list argList)
828 {
829      /*ASSERT(AfxIsValidString(lpszFormat, FALSE));*/
830      const char * lpsz;
831      int nMaxLen, nWidth, nPrecision, nModifier, nItemLen;
832 
833      nMaxLen = 0;
834      /* make a guess at the maximum length of the resulting string */
835      for ( lpsz = lpszFormat; *lpsz; lpsz ++ )
836      {
837           /* handle '%' character, but watch out for '%%' */
838           if (*lpsz != '%' || *( ++ lpsz ) == '%')
839           {
840                nMaxLen += 1;
841                continue;
842           }
843 
844           nItemLen = 0;
845 
846           /*  handle '%' character with format */
847           nWidth = 0;
848           for (; *lpsz; lpsz ++ )
849           {
850                /* check for valid flags */
851                if (*lpsz == '#')
852                     nMaxLen += 2;   /* for '0x' */
853                else if (*lpsz == '*')
854                     nWidth = va_arg(argList, int);
855                else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0'
856                         || *lpsz == ' ')
857                            ;
858                else /* hit non-flag character */
859                           break;
860           }
861           /* get width and skip it */
862           if (nWidth == 0)
863           {
864                /* width indicated by */
865                nWidth = atoi(lpsz);
866                for (; *lpsz && isdigit(*lpsz); lpsz ++ )
867                      ;
868           }
869           /*ASSERT(nWidth >= 0);*/
870           if ( nWidth < 0 )
871               goto exit_error; /* instead of exception */
872 
873           nPrecision = 0;
874           if (*lpsz == '.')
875           {
876                /* skip past '.' separator (width.precision)*/
877                lpsz ++;
878 
879                /* get precision and skip it*/
880                if (*lpsz == '*')
881                {
882                     nPrecision = va_arg(argList, int);
883                     lpsz ++;
884                }
885                else
886                {
887                     nPrecision = atoi(lpsz);
888                     for (; *lpsz && isdigit(*lpsz); lpsz ++)
889                             ;
890                }
891               if ( nPrecision < 0 )
892                   goto exit_error; /* instead of exception */
893           }
894 
895           /* should be on type modifier or specifier */
896           nModifier = 0;
897           switch (*lpsz)
898           {
899           /* modifiers that affect size */
900           case 'h':
901                switch ( lpsz[1] ) {
902                case 'd':
903                case 'i':
904                case 'o':
905                case 'x':
906                case 'X':
907                case 'u':
908                    /* short unsigned, short double, etc. -- added to the original MS example */
909                    /* ignore the fact that these modifiers do affect size */
910                    lpsz ++;
911                    break;
912                default:
913                    nModifier = FORCE_ANSI;
914                    lpsz ++;
915                    break;
916                }
917                break;
918           case 'l':
919                switch ( lpsz[1] ) {
920                case 'd':
921                case 'i':
922                case 'o':
923                case 'x':
924                case 'X':
925                case 'u':
926                case 'f': /* long float -- post ANSI C */
927                    /* long unsigned, long double, etc. -- added to the original MS example */
928                    /* ignore the fact that these modifiers do affect size */
929                    lpsz ++;
930                    break;
931                default:
932                    /*
933                    nModifier = FORCE_UNICODE;
934                    lpsz ++;
935                    break;
936                    */
937                    goto exit_error;  /* no UNICODE, please */
938                }
939                break;
940           /* modifiers that do not affect size */
941           case 'F':
942           case 'N':
943           case 'L':
944                lpsz ++;
945                break;
946           }
947 
948           /* now should be on specifier */
949           switch (*lpsz | nModifier)
950           {
951           /* single characters*/
952           case 'c':
953           case 'C':
954                nItemLen = 2;
955                va_arg(argList, int);
956                break;
957           case 'c'|FORCE_ANSI:
958           case 'C'|FORCE_ANSI:
959                nItemLen = 2;
960                va_arg(argList, int);
961                break;
962           case 'c'|FORCE_UNICODE:
963           case 'C'|FORCE_UNICODE:
964                goto exit_error;  /* no UNICODE, please */
965                /*
966                nItemLen = 2;
967                va_arg(argList, wchar_t);
968                break;
969                */
970 
971           /* strings*/
972           case 's':
973           case 'S':
974                nItemLen = strlen(va_arg(argList, char*));
975                nItemLen = inchi_max(1, nItemLen);
976                break;
977           case 's'|FORCE_ANSI:
978           case 'S'|FORCE_ANSI:
979                nItemLen = strlen(va_arg(argList, char*));
980                nItemLen = inchi_max(1, nItemLen);
981                break;
982 
983           case 's'|FORCE_UNICODE:
984           case 'S'|FORCE_UNICODE:
985                goto exit_error;  /* no UNICODE, please */
986                /*
987                nItemLen = wcslen(va_arg(argList, wchar_t*));
988                nItemLen = inchi_max(1, nItemLen);
989                break;
990                */
991 
992           }
993 
994           /* adjust nItemLen for strings */
995           if (nItemLen != 0)
996           {
997                nItemLen = inchi_max(nItemLen, nWidth);
998                if (nPrecision != 0)
999                     nItemLen = inchi_min(nItemLen, nPrecision);
1000           }
1001           else
1002           {
1003                switch (*lpsz)
1004                {
1005                /* integers */
1006                case 'd':
1007                case 'i':
1008                case 'u':
1009                case 'x':
1010                case 'X':
1011                case 'o':
1012                     va_arg(argList, int);
1013                     nItemLen = 32;
1014                     nItemLen = inchi_max(nItemLen, nWidth+nPrecision);
1015                     break;
1016 
1017                case 'e':
1018                case 'f':
1019                case 'g':
1020                case 'G':
1021                     va_arg(argList, double);
1022                     nItemLen = 32;
1023                     nItemLen = inchi_max(nItemLen, nWidth+nPrecision);
1024                     break;
1025 
1026                case 'p':
1027                     va_arg(argList, void*);
1028                     nItemLen = 32;
1029                     nItemLen = inchi_max(nItemLen, nWidth+nPrecision);
1030                     break;
1031 
1032                /* no output */
1033                case 'n':
1034                     va_arg(argList, int*);
1035                     break;
1036 
1037                default:
1038                    /*ASSERT(FALSE);*/  /* unknown formatting option*/
1039                    goto exit_error; /* instead of exception */
1040                }
1041           }
1042 
1043           /* adjust nMaxLen for output nItemLen */
1044           nMaxLen += nItemLen;
1045      }
1046      return nMaxLen;
1047 
1048 exit_error:
1049      return -1; /* wrong format */
1050 }
1051 
1052