Back to index

openldap  2.4.31
stdio.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1998-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 
00016 #include "portable.h"
00017 
00018 #include <stdio.h>
00019 #include <ac/stdarg.h>
00020 #include <ac/string.h>
00021 #include <ac/ctype.h>
00022 #include <lutil.h>
00023 
00024 #if !defined(HAVE_VSNPRINTF) && !defined(HAVE_EBCDIC)
00025 /* Write at most n characters to the buffer in str, return the
00026  * number of chars written or -1 if the buffer would have been
00027  * overflowed.
00028  *
00029  * This is portable to any POSIX-compliant system. We use pipe()
00030  * to create a valid file descriptor, and then fdopen() it to get
00031  * a valid FILE pointer. The user's buffer and size are assigned
00032  * to the FILE pointer using setvbuf. Then we close the read side
00033  * of the pipe to invalidate the descriptor.
00034  *
00035  * If the write arguments all fit into size n, the write will
00036  * return successfully. If the write is too large, the stdio
00037  * buffer will need to be flushed to the underlying file descriptor.
00038  * The flush will fail because it is attempting to write to a
00039  * broken pipe, and the write will be terminated.
00040  * -- hyc, 2002-07-19
00041  */
00042 /* This emulation uses vfprintf; on OS/390 we're also emulating
00043  * that function so it's more efficient just to have a separate
00044  * version of vsnprintf there.
00045  */
00046 #include <ac/signal.h>
00047 int ber_pvt_vsnprintf( char *str, size_t n, const char *fmt, va_list ap )
00048 {
00049        int fds[2], res;
00050        FILE *f;
00051        RETSIGTYPE (*sig)();
00052 
00053        if (pipe( fds )) return -1;
00054 
00055        f = fdopen( fds[1], "w" );
00056        if ( !f ) {
00057               close( fds[1] );
00058               close( fds[0] );
00059               return -1;
00060        }
00061        setvbuf( f, str, _IOFBF, n );
00062        sig = signal( SIGPIPE, SIG_IGN );
00063        close( fds[0] );
00064 
00065        res = vfprintf( f, fmt, ap );
00066 
00067        fclose( f );
00068        signal( SIGPIPE, sig );
00069        if ( res > 0 && res < n ) {
00070               res = vsprintf( str, fmt, ap );
00071        }
00072        return res;
00073 }
00074 #endif
00075 
00076 #ifndef HAVE_SNPRINTF
00077 int ber_pvt_snprintf( char *str, size_t n, const char *fmt, ... )
00078 {
00079        va_list ap;
00080        int res;
00081 
00082        va_start( ap, fmt );
00083        res = vsnprintf( str, n, fmt, ap );
00084        va_end( ap );
00085        return res;
00086 }
00087 #endif /* !HAVE_SNPRINTF */
00088 
00089 #ifdef HAVE_EBCDIC
00090 /* stdio replacements with ASCII/EBCDIC translation for OS/390.
00091  * The OS/390 port depends on the CONVLIT compiler option being
00092  * used to force character and string literals to be compiled in
00093  * ISO8859-1, and the __LIBASCII cpp symbol to be defined to use the
00094  * OS/390 ASCII-compatibility library. This library only supplies
00095  * an ASCII version of sprintf, so other needed functions are
00096  * provided here.
00097  *
00098  * All of the internal character manipulation is done in ASCII,
00099  * but file I/O is EBCDIC, so we catch any stdio reading/writing
00100  * of files here and do the translations.
00101  */
00102 
00103 #undef fputs
00104 #undef fgets
00105 
00106 char *ber_pvt_fgets( char *s, int n, FILE *fp )
00107 {
00108        s = (char *)fgets( s, n, fp );
00109        if ( s ) __etoa( s );
00110        return s;
00111 }
00112 
00113 int ber_pvt_fputs( const char *str, FILE *fp )
00114 {
00115        char buf[8192];
00116 
00117        strncpy( buf, str, sizeof(buf) );
00118        __atoe( buf );
00119        return fputs( buf, fp );
00120 }
00121 
00122 /* The __LIBASCII doesn't include a working vsprintf, so we make do
00123  * using just sprintf. This is a very simplistic parser that looks for
00124  * format strings and uses sprintf to process them one at a time.
00125  * Literal text is just copied straight to the destination.
00126  * The result is appended to the destination string. The parser
00127  * recognizes field-width specifiers and the 'l' qualifier; it
00128  * may need to be extended to recognize other qualifiers but so
00129  * far this seems to be enough.
00130  */
00131 int ber_pvt_vsnprintf( char *str, size_t n, const char *fmt, va_list ap )
00132 {
00133        char *ptr, *pct, *s2, *f2, *end;
00134        char fm2[64];
00135        int len, rem;
00136 
00137        ptr = (char *)fmt;
00138        s2 = str;
00139        fm2[0] = '%';
00140        if (n) {
00141               end = str + n;
00142        } else {
00143               end = NULL;
00144        }
00145 
00146        for (pct = strchr(ptr, '%'); pct; pct = strchr(ptr, '%')) {
00147               len = pct-ptr;
00148               if (end) {
00149                      rem = end-s2;
00150                      if (rem < 1) return -1;
00151                      if (rem < len) len = rem;
00152               }
00153               s2 = lutil_strncopy( s2, ptr, len );
00154               /* Did we cheat the length above? If so, bail out */
00155               if (len < pct-ptr) return -1;
00156               for (pct++, f2 = fm2+1; isdigit(*pct);) *f2++ = *pct++;
00157               if (*pct == 'l') *f2++ = *pct++;
00158               if (*pct == '%') {
00159                      *s2++ = '%';
00160               } else {
00161                      *f2++ = *pct;
00162                      *f2 = '\0';
00163                      if (*pct == 's') {
00164                             char *ss = va_arg(ap, char *);
00165                             /* Attempt to limit sprintf output. This
00166                              * may be thrown off if field widths were
00167                              * specified for this string.
00168                              *
00169                              * If it looks like the string is too
00170                              * long for the remaining buffer, bypass
00171                              * sprintf and just copy what fits, then
00172                              * quit.
00173                              */
00174                             if (end && strlen(ss) > (rem=end-s2)) {
00175                                    strncpy(s2, ss, rem);
00176                                    return -1;
00177                             } else {
00178                                    s2 += sprintf(s2, fm2, ss);
00179                             }
00180                      } else {
00181                             s2 += sprintf(s2, fm2, va_arg(ap, int));
00182                      }
00183               }
00184               ptr = pct + 1;
00185        }
00186        if (end) {
00187               rem = end-s2;
00188               if (rem > 0) {
00189                      len = strlen(ptr);
00190                      s2 = lutil_strncopy( s2, ptr, rem );
00191                      rem -= len;
00192               }
00193               if (rem < 0) return -1;
00194        } else {
00195               s2 = lutil_strcopy( s2, ptr );
00196        }
00197        return s2 - str;
00198 }
00199 
00200 int ber_pvt_vsprintf( char *str, const char *fmt, va_list ap )
00201 {
00202        return vsnprintf( str, 0, fmt, ap );
00203 }
00204 
00205 /* The fixed buffer size here is a problem, we don't know how
00206  * to flush the buffer and keep printing if the msg is too big. 
00207  * Hopefully we never try to write something bigger than this
00208  * in a log msg...
00209  */
00210 int ber_pvt_vfprintf( FILE *fp, const char *fmt, va_list ap )
00211 {
00212        char buf[8192];
00213        int res;
00214 
00215        vsnprintf( buf, sizeof(buf), fmt, ap );
00216        __atoe( buf );
00217        res = fputs( buf, fp );
00218        if (res == EOF) res = -1;
00219        return res;
00220 }
00221 
00222 int ber_pvt_printf( const char *fmt, ... )
00223 {
00224        va_list ap;
00225        int res;
00226 
00227        va_start( ap, fmt );
00228        res = ber_pvt_vfprintf( stdout, fmt, ap );
00229        va_end( ap );
00230        return res;
00231 }
00232 
00233 int ber_pvt_fprintf( FILE *fp, const char *fmt, ... )
00234 {
00235        va_list ap;
00236        int res;
00237 
00238        va_start( ap, fmt );
00239        res = ber_pvt_vfprintf( fp, fmt, ap );
00240        va_end( ap );
00241        return res;
00242 }
00243 #endif