]> git.sur5r.net Git - openldap/blob - libraries/liblber/stdio.c
Fix typo
[openldap] / libraries / liblber / stdio.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 2002-2003 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 #include "portable.h"
8
9 #include <stdio.h>
10 #include <ac/stdarg.h>
11 #include <ac/string.h>
12
13 #if !defined(HAVE_VSNPRINTF) && !defined(HAVE_EBCDIC)
14 /* Write at most n characters to the buffer in str, return the
15  * number of chars written or -1 if the buffer would have been
16  * overflowed.
17  *
18  * This is portable to any POSIX-compliant system. We use pipe()
19  * to create a valid file descriptor, and then fdopen() it to get
20  * a valid FILE pointer. The user's buffer and size are assigned
21  * to the FILE pointer using setvbuf. Then we close the read side
22  * of the pipe to invalidate the descriptor.
23  *
24  * If the write arguments all fit into size n, the write will
25  * return successfully. If the write is too large, the stdio
26  * buffer will need to be flushed to the underlying file descriptor.
27  * The flush will fail because it is attempting to write to a
28  * broken pipe, and the write will be terminated.
29  * -- hyc, 2002-07-19
30  */
31 /* This emulation uses vfprintf; on OS/390 we're also emulating
32  * that function so it's more efficient just to have a separate
33  * version of vsnprintf there.
34  */
35 #include <ac/signal.h>
36 int ber_pvt_vsnprintf( char *str, size_t n, const char *fmt, va_list ap )
37 {
38         int fds[2], res;
39         FILE *f;
40         RETSIGTYPE (*sig)();
41
42         if (pipe( fds )) return -1;
43
44         f = fdopen( fds[1], "w" );
45         if ( !f ) {
46                 close( fds[1] );
47                 close( fds[0] );
48                 return -1;
49         }
50         setvbuf( f, str, _IOFBF, n );
51         sig = signal( SIGPIPE, SIG_IGN );
52         close( fds[0] );
53
54         res = vfprintf( f, fmt, ap );
55
56         fclose( f );
57         signal( SIGPIPE, sig );
58         if ( res > 0 && res < n ) {
59                 res = vsprintf( str, fmt, ap );
60         }
61         return res;
62 }
63 #endif
64
65 #ifndef HAVE_SNPRINTF
66 int ber_pvt_snprintf( char *str, size_t n, const char *fmt, ... )
67 {
68         va_list ap;
69         int res;
70
71         va_start( ap, fmt );
72         res = vsnprintf( str, n, fmt, ap );
73         va_end( ap );
74         return res;
75 }
76 #endif /* !HAVE_VSNPRINTF */
77
78 #ifdef HAVE_EBCDIC
79 /* stdio replacements with ASCII/EBCDIC translation for OS/390.
80  * The OS/390 port depends on the CONVLIT compiler option being
81  * used to force character and string literals to be compiled in
82  * ISO8859-1, and the __LIBASCII cpp symbol to be defined to use the
83  * OS/390 ASCII-compatibility library. This library only supplies
84  * an ASCII version of sprintf, so other needed functions are
85  * provided here.
86  *
87  * All of the internal character manipulation is done in ASCII,
88  * but file I/O is EBCDIC, so we catch any stdio reading/writing
89  * of files here and do the translations.
90  */
91
92 #undef fputs
93 #undef fgets
94
95 char *ber_pvt_fgets( char *s, int n, FILE *fp )
96 {
97         s = (char *)fgets( s, n, fp );
98         if ( s ) __etoa( s );
99         return s;
100 }
101
102 int ber_pvt_fputs( const char *str, FILE *fp )
103 {
104         char buf[8192];
105
106         strncpy( buf, str, sizeof(buf) );
107         __atoe( buf );
108         return fputs( buf, fp );
109 }
110
111 /* The __LIBASCII doesn't include a working vsprintf, so we make do
112  * using just sprintf. This is a very simplistic parser that looks for
113  * format strings and uses sprintf to process them one at a time.
114  * Literal text is just copied straight to the destination.
115  * The result is appended to the destination string. The parser
116  * recognizes field-width specifiers and the 'l' qualifier; it
117  * may need to be extended to recognize other qualifiers but so
118  * far this seems to be enough.
119  */
120 int ber_pvt_vsnprintf( char *str, size_t n, const char *fmt, va_list ap )
121 {
122         char *ptr, *pct, *s2, *f2, *end;
123         char fm2[64];
124         int len, rem;
125
126         ptr = (char *)fmt;
127         s2 = str;
128         fm2[0] = '%';
129         if (n)
130                 end = str + n;
131         else
132                 end = NULL;
133
134         for (pct = strchr(ptr, '%'); pct; pct = strchr(ptr, '%')) {
135                 len = pct-ptr;
136                 if (end) {
137                         rem = end-s2;
138                         if (rem < 1) return -1;
139                         if (rem < len) len = rem;
140                 }
141                 s2 = ber_pvt_strncopy( s2, ptr, len );
142                 /* Did we cheat the length above? If so, bail out */
143                 if (len < pct-ptr) return -1;
144                 for (pct++, f2 = fm2+1; isdigit(*pct);) *f2++ = *pct++;
145                 if (*pct == 'l') *f2++ = *pct++;
146                 if (*pct == '%') *s2++ = '%';
147                 else {
148                         *f2++ = *pct;
149                         *f2 = '\0';
150                         if (*pct == 's') {
151                                 char *ss = va_arg(ap, char *);
152                                 /* Attempt to limit sprintf output. This
153                                  * may be thrown off if field widths were
154                                  * specified for this string.
155                                  *
156                                  * If it looks like the string is too
157                                  * long for the remaining buffer, bypass
158                                  * sprintf and just copy what fits, then
159                                  * quit.
160                                  */
161                                 if (end && strlen(ss) > (rem=end-s2)) {
162                                         strncpy(s2, ss, rem);
163                                         return -1;
164                                 } else {
165                                         s2 += sprintf(s2, fm2, ss);
166                                 }
167                         } else
168                                 s2 += sprintf(s2, fm2, va_arg(ap, int));
169                 }
170                 ptr = pct + 1;
171         }
172         if (end) {
173                 rem = end-s2;
174                 if (rem > 0) {
175                         len = strlen(ptr);
176                         s2 = ber_pvt_strncopy( s2, ptr, rem );
177                         rem -= len;
178                 }
179                 if (rem < 0) return -1;
180         } else {
181                 s2 = ber_pvt_strcopy( s2, ptr );
182         }
183         return s2 - str;
184 }
185
186 int ber_pvt_vsprintf( char *str, const char *fmt, va_list ap )
187 {
188         return vsnprintf( str, 0, fmt, ap );
189 }
190
191 /* The fixed buffer size here is a problem, we don't know how
192  * to flush the buffer and keep printing if the msg is too big. 
193  * Hopefully we never try to write something bigger than this
194  * in a log msg...
195  */
196 int ber_pvt_vfprintf( FILE *fp, const char *fmt, va_list ap )
197 {
198         char buf[8192];
199         int res;
200
201         vsnprintf( buf, sizeof(buf), fmt, ap );
202         __atoe( buf );
203         res = fputs( buf, fp );
204         if (res == EOF) res = -1;
205         return res;
206 }
207
208 int ber_pvt_printf( const char *fmt, ... )
209 {
210         va_list ap;
211         int res;
212
213         va_start( ap, fmt );
214         res = ber_pvt_vfprintf( stdout, fmt, ap );
215         va_end( ap );
216         return res;
217 }
218
219 int ber_pvt_fprintf( FILE *fp, const char *fmt, ... )
220 {
221         va_list ap;
222         int res;
223
224         va_start( ap, fmt );
225         res = ber_pvt_vfprintf( fp, fmt, ap );
226         va_end( ap );
227         return res;
228 }
229 #endif