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