1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
3*7c478bd9Sstevel@tonic-gate *
4*7c478bd9Sstevel@tonic-gate * All rights reserved.
5*7c478bd9Sstevel@tonic-gate *
6*7c478bd9Sstevel@tonic-gate * Permission is hereby granted, free of charge, to any person obtaining a
7*7c478bd9Sstevel@tonic-gate * copy of this software and associated documentation files (the
8*7c478bd9Sstevel@tonic-gate * "Software"), to deal in the Software without restriction, including
9*7c478bd9Sstevel@tonic-gate * without limitation the rights to use, copy, modify, merge, publish,
10*7c478bd9Sstevel@tonic-gate * distribute, and/or sell copies of the Software, and to permit persons
11*7c478bd9Sstevel@tonic-gate * to whom the Software is furnished to do so, provided that the above
12*7c478bd9Sstevel@tonic-gate * copyright notice(s) and this permission notice appear in all copies of
13*7c478bd9Sstevel@tonic-gate * the Software and that both the above copyright notice(s) and this
14*7c478bd9Sstevel@tonic-gate * permission notice appear in supporting documentation.
15*7c478bd9Sstevel@tonic-gate *
16*7c478bd9Sstevel@tonic-gate * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17*7c478bd9Sstevel@tonic-gate * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18*7c478bd9Sstevel@tonic-gate * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
19*7c478bd9Sstevel@tonic-gate * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20*7c478bd9Sstevel@tonic-gate * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
21*7c478bd9Sstevel@tonic-gate * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
22*7c478bd9Sstevel@tonic-gate * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
23*7c478bd9Sstevel@tonic-gate * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
24*7c478bd9Sstevel@tonic-gate * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25*7c478bd9Sstevel@tonic-gate *
26*7c478bd9Sstevel@tonic-gate * Except as contained in this notice, the name of a copyright holder
27*7c478bd9Sstevel@tonic-gate * shall not be used in advertising or otherwise to promote the sale, use
28*7c478bd9Sstevel@tonic-gate * or other dealings in this Software without prior written authorization
29*7c478bd9Sstevel@tonic-gate * of the copyright holder.
30*7c478bd9Sstevel@tonic-gate */
31*7c478bd9Sstevel@tonic-gate
32*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
33*7c478bd9Sstevel@tonic-gate
34*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
35*7c478bd9Sstevel@tonic-gate #include <stdio.h>
36*7c478bd9Sstevel@tonic-gate #include <string.h>
37*7c478bd9Sstevel@tonic-gate #include <ctype.h>
38*7c478bd9Sstevel@tonic-gate #include <errno.h>
39*7c478bd9Sstevel@tonic-gate
40*7c478bd9Sstevel@tonic-gate #include "ioutil.h"
41*7c478bd9Sstevel@tonic-gate
42*7c478bd9Sstevel@tonic-gate static int _io_pad_line(GlWriteFn *write_fn, void *data, int c, int n);
43*7c478bd9Sstevel@tonic-gate
44*7c478bd9Sstevel@tonic-gate /*.......................................................................
45*7c478bd9Sstevel@tonic-gate * Display a left-justified string over multiple terminal lines,
46*7c478bd9Sstevel@tonic-gate * taking account of the specified width of the terminal. Optional
47*7c478bd9Sstevel@tonic-gate * indentation and an option prefix string can be specified to be
48*7c478bd9Sstevel@tonic-gate * displayed at the start of each new terminal line used, and if
49*7c478bd9Sstevel@tonic-gate * needed, a single paragraph can be broken across multiple calls.
50*7c478bd9Sstevel@tonic-gate * Note that literal newlines in the input string can be used to force
51*7c478bd9Sstevel@tonic-gate * a newline at any point, and that in order to allow individual
52*7c478bd9Sstevel@tonic-gate * paragraphs to be written using multiple calls to this function,
53*7c478bd9Sstevel@tonic-gate * unless an explicit newline character is specified at the end of the
54*7c478bd9Sstevel@tonic-gate * string, a newline will not be started at the end of the last word
55*7c478bd9Sstevel@tonic-gate * in the string. Note that when a new line is started between two
56*7c478bd9Sstevel@tonic-gate * words that are separated by spaces, those spaces are not output,
57*7c478bd9Sstevel@tonic-gate * whereas when a new line is started because a newline character was
58*7c478bd9Sstevel@tonic-gate * found in the string, only the spaces before the newline character
59*7c478bd9Sstevel@tonic-gate * are discarded.
60*7c478bd9Sstevel@tonic-gate *
61*7c478bd9Sstevel@tonic-gate * Input:
62*7c478bd9Sstevel@tonic-gate * write_fn GlWriteFn * The callback function to use to write the
63*7c478bd9Sstevel@tonic-gate * output.
64*7c478bd9Sstevel@tonic-gate * data void * A pointer to arbitrary data to be passed to
65*7c478bd9Sstevel@tonic-gate * write_fn() whenever it is called.
66*7c478bd9Sstevel@tonic-gate * fp FILE * The stdio stream to write to.
67*7c478bd9Sstevel@tonic-gate * indentation int The number of fill characters to use to
68*7c478bd9Sstevel@tonic-gate * indent the start of each new terminal line.
69*7c478bd9Sstevel@tonic-gate * prefix const char * An optional prefix string to write after the
70*7c478bd9Sstevel@tonic-gate * indentation margin at the start of each new
71*7c478bd9Sstevel@tonic-gate * terminal line. You can specify NULL if no
72*7c478bd9Sstevel@tonic-gate * prefix is required.
73*7c478bd9Sstevel@tonic-gate * suffix const char * An optional suffix string to draw at the end
74*7c478bd9Sstevel@tonic-gate * of the terminal line. The line will be padded
75*7c478bd9Sstevel@tonic-gate * where necessary to ensure that the suffix ends
76*7c478bd9Sstevel@tonic-gate * in the last column of the terminal line. If
77*7c478bd9Sstevel@tonic-gate * no suffix is desired, specify NULL.
78*7c478bd9Sstevel@tonic-gate * fill_char int The padding character to use when indenting
79*7c478bd9Sstevel@tonic-gate * and filling up to the suffix.
80*7c478bd9Sstevel@tonic-gate * term_width int The width of the terminal being written to.
81*7c478bd9Sstevel@tonic-gate * start int The number of characters already written to
82*7c478bd9Sstevel@tonic-gate * the start of the current terminal line. This
83*7c478bd9Sstevel@tonic-gate * is primarily used to allow individual
84*7c478bd9Sstevel@tonic-gate * paragraphs to be written over multiple calls
85*7c478bd9Sstevel@tonic-gate * to this function, but can also be used to
86*7c478bd9Sstevel@tonic-gate * allow you to start the first line of a
87*7c478bd9Sstevel@tonic-gate * paragraph with a different prefix or
88*7c478bd9Sstevel@tonic-gate * indentation than those specified above.
89*7c478bd9Sstevel@tonic-gate * string const char * The string to be written.
90*7c478bd9Sstevel@tonic-gate * Output:
91*7c478bd9Sstevel@tonic-gate * return int On error -1 is returned. Otherwise the
92*7c478bd9Sstevel@tonic-gate * return value is the terminal column index at
93*7c478bd9Sstevel@tonic-gate * which the cursor was left after writing the
94*7c478bd9Sstevel@tonic-gate * final word in the string. Successful return
95*7c478bd9Sstevel@tonic-gate * values can thus be passed verbatim to the
96*7c478bd9Sstevel@tonic-gate * 'start' arguments of subsequent calls to
97*7c478bd9Sstevel@tonic-gate * _io_display_text() to allow the printing of a
98*7c478bd9Sstevel@tonic-gate * paragraph to be broken across multiple calls
99*7c478bd9Sstevel@tonic-gate * to _io_display_text().
100*7c478bd9Sstevel@tonic-gate */
_io_display_text(GlWriteFn * write_fn,void * data,int indentation,const char * prefix,const char * suffix,int fill_char,int term_width,int start,const char * string)101*7c478bd9Sstevel@tonic-gate int _io_display_text(GlWriteFn *write_fn, void *data, int indentation,
102*7c478bd9Sstevel@tonic-gate const char *prefix, const char *suffix, int fill_char,
103*7c478bd9Sstevel@tonic-gate int term_width, int start, const char *string)
104*7c478bd9Sstevel@tonic-gate {
105*7c478bd9Sstevel@tonic-gate int ndone; /* The number of characters written from string[] */
106*7c478bd9Sstevel@tonic-gate int nnew; /* The number of characters to be displayed next */
107*7c478bd9Sstevel@tonic-gate int was_space; /* True if the previous character was a space or tab */
108*7c478bd9Sstevel@tonic-gate int last = start; /* The column number of the last character written */
109*7c478bd9Sstevel@tonic-gate int prefix_len; /* The length of the optional line prefix string */
110*7c478bd9Sstevel@tonic-gate int suffix_len; /* The length of the optional line prefix string */
111*7c478bd9Sstevel@tonic-gate int margin_width; /* The total number of columns used by the indentation */
112*7c478bd9Sstevel@tonic-gate /* margin and the prefix string. */
113*7c478bd9Sstevel@tonic-gate int i;
114*7c478bd9Sstevel@tonic-gate /*
115*7c478bd9Sstevel@tonic-gate * Check the arguments?
116*7c478bd9Sstevel@tonic-gate */
117*7c478bd9Sstevel@tonic-gate if(!string || !write_fn) {
118*7c478bd9Sstevel@tonic-gate errno = EINVAL;
119*7c478bd9Sstevel@tonic-gate return -1;
120*7c478bd9Sstevel@tonic-gate };
121*7c478bd9Sstevel@tonic-gate /*
122*7c478bd9Sstevel@tonic-gate * Enforce sensible values on the arguments.
123*7c478bd9Sstevel@tonic-gate */
124*7c478bd9Sstevel@tonic-gate if(term_width < 0)
125*7c478bd9Sstevel@tonic-gate term_width = 0;
126*7c478bd9Sstevel@tonic-gate if(indentation > term_width)
127*7c478bd9Sstevel@tonic-gate indentation = term_width;
128*7c478bd9Sstevel@tonic-gate else if(indentation < 0)
129*7c478bd9Sstevel@tonic-gate indentation = 0;
130*7c478bd9Sstevel@tonic-gate if(start > term_width)
131*7c478bd9Sstevel@tonic-gate start = term_width;
132*7c478bd9Sstevel@tonic-gate else if(start < 0)
133*7c478bd9Sstevel@tonic-gate start = 0;
134*7c478bd9Sstevel@tonic-gate /*
135*7c478bd9Sstevel@tonic-gate * Get the length of the prefix string.
136*7c478bd9Sstevel@tonic-gate */
137*7c478bd9Sstevel@tonic-gate prefix_len = prefix ? strlen(prefix) : 0;
138*7c478bd9Sstevel@tonic-gate /*
139*7c478bd9Sstevel@tonic-gate * Get the length of the suffix string.
140*7c478bd9Sstevel@tonic-gate */
141*7c478bd9Sstevel@tonic-gate suffix_len = suffix ? strlen(suffix) : 0;
142*7c478bd9Sstevel@tonic-gate /*
143*7c478bd9Sstevel@tonic-gate * How many characters are devoted to indenting and prefixing each line?
144*7c478bd9Sstevel@tonic-gate */
145*7c478bd9Sstevel@tonic-gate margin_width = indentation + prefix_len;
146*7c478bd9Sstevel@tonic-gate /*
147*7c478bd9Sstevel@tonic-gate * Write as many terminal lines as are needed to display the whole string.
148*7c478bd9Sstevel@tonic-gate */
149*7c478bd9Sstevel@tonic-gate for(ndone=0; string[ndone]; start=0) {
150*7c478bd9Sstevel@tonic-gate last = start;
151*7c478bd9Sstevel@tonic-gate /*
152*7c478bd9Sstevel@tonic-gate * Write spaces from the current position in the terminal line to the
153*7c478bd9Sstevel@tonic-gate * width of the requested indentation margin.
154*7c478bd9Sstevel@tonic-gate */
155*7c478bd9Sstevel@tonic-gate if(indentation > 0 && last < indentation) {
156*7c478bd9Sstevel@tonic-gate if(_io_pad_line(write_fn, data, fill_char, indentation - last))
157*7c478bd9Sstevel@tonic-gate return -1;
158*7c478bd9Sstevel@tonic-gate last = indentation;
159*7c478bd9Sstevel@tonic-gate };
160*7c478bd9Sstevel@tonic-gate /*
161*7c478bd9Sstevel@tonic-gate * If a prefix string has been specified, display it unless we have
162*7c478bd9Sstevel@tonic-gate * passed where it should end in the terminal output line.
163*7c478bd9Sstevel@tonic-gate */
164*7c478bd9Sstevel@tonic-gate if(prefix_len > 0 && last < margin_width) {
165*7c478bd9Sstevel@tonic-gate int pstart = last - indentation;
166*7c478bd9Sstevel@tonic-gate int plen = prefix_len - pstart;
167*7c478bd9Sstevel@tonic-gate if(write_fn(data, prefix+pstart, plen) != plen)
168*7c478bd9Sstevel@tonic-gate return -1;
169*7c478bd9Sstevel@tonic-gate last = margin_width;
170*7c478bd9Sstevel@tonic-gate };
171*7c478bd9Sstevel@tonic-gate /*
172*7c478bd9Sstevel@tonic-gate * Locate the end of the last complete word in the string before
173*7c478bd9Sstevel@tonic-gate * (term_width - start) characters have been seen. To handle the case
174*7c478bd9Sstevel@tonic-gate * where a single word is wider than the available space after the
175*7c478bd9Sstevel@tonic-gate * indentation and prefix margins, always make sure that at least one
176*7c478bd9Sstevel@tonic-gate * word is printed after the margin, regardless of whether it won't
177*7c478bd9Sstevel@tonic-gate * fit on the line. The two exceptions to this rule are if an embedded
178*7c478bd9Sstevel@tonic-gate * newline is found in the string or the end of the string is reached
179*7c478bd9Sstevel@tonic-gate * before any word has been seen.
180*7c478bd9Sstevel@tonic-gate */
181*7c478bd9Sstevel@tonic-gate nnew = 0;
182*7c478bd9Sstevel@tonic-gate was_space = 0;
183*7c478bd9Sstevel@tonic-gate for(i=ndone; string[i] && (last+i-ndone < term_width - suffix_len ||
184*7c478bd9Sstevel@tonic-gate (nnew==0 && last==margin_width)); i++) {
185*7c478bd9Sstevel@tonic-gate if(string[i] == '\n') {
186*7c478bd9Sstevel@tonic-gate if(!was_space)
187*7c478bd9Sstevel@tonic-gate nnew = i-ndone;
188*7c478bd9Sstevel@tonic-gate break;
189*7c478bd9Sstevel@tonic-gate } else if(isspace((int) string[i])) {
190*7c478bd9Sstevel@tonic-gate if(!was_space) {
191*7c478bd9Sstevel@tonic-gate nnew = i-ndone+1;
192*7c478bd9Sstevel@tonic-gate was_space = 1;
193*7c478bd9Sstevel@tonic-gate };
194*7c478bd9Sstevel@tonic-gate } else {
195*7c478bd9Sstevel@tonic-gate was_space = 0;
196*7c478bd9Sstevel@tonic-gate };
197*7c478bd9Sstevel@tonic-gate };
198*7c478bd9Sstevel@tonic-gate /*
199*7c478bd9Sstevel@tonic-gate * Does the end of the string delimit the last word that will fit on the
200*7c478bd9Sstevel@tonic-gate * output line?
201*7c478bd9Sstevel@tonic-gate */
202*7c478bd9Sstevel@tonic-gate if(nnew==0 && string[i] == '\0')
203*7c478bd9Sstevel@tonic-gate nnew = i-ndone;
204*7c478bd9Sstevel@tonic-gate /*
205*7c478bd9Sstevel@tonic-gate * Write the new line.
206*7c478bd9Sstevel@tonic-gate */
207*7c478bd9Sstevel@tonic-gate if(write_fn(data, string+ndone, nnew) != nnew)
208*7c478bd9Sstevel@tonic-gate return -1;
209*7c478bd9Sstevel@tonic-gate ndone += nnew;
210*7c478bd9Sstevel@tonic-gate last += nnew;
211*7c478bd9Sstevel@tonic-gate /*
212*7c478bd9Sstevel@tonic-gate * Start a newline unless we have reached the end of the input string.
213*7c478bd9Sstevel@tonic-gate * In the latter case, in order to give the caller the chance to
214*7c478bd9Sstevel@tonic-gate * concatenate multiple calls to _io_display_text(), omit the newline,
215*7c478bd9Sstevel@tonic-gate * leaving it up to the caller to write this.
216*7c478bd9Sstevel@tonic-gate */
217*7c478bd9Sstevel@tonic-gate if(string[ndone] != '\0') {
218*7c478bd9Sstevel@tonic-gate /*
219*7c478bd9Sstevel@tonic-gate * If a suffix has been provided, pad out the end of the line with spaces
220*7c478bd9Sstevel@tonic-gate * such that the suffix will end in the right-most terminal column.
221*7c478bd9Sstevel@tonic-gate */
222*7c478bd9Sstevel@tonic-gate if(suffix_len > 0) {
223*7c478bd9Sstevel@tonic-gate int npad = term_width - suffix_len - last;
224*7c478bd9Sstevel@tonic-gate if(npad > 0 && _io_pad_line(write_fn, data, fill_char, npad))
225*7c478bd9Sstevel@tonic-gate return -1;
226*7c478bd9Sstevel@tonic-gate last += npad;
227*7c478bd9Sstevel@tonic-gate if(write_fn(data, suffix, suffix_len) != suffix_len)
228*7c478bd9Sstevel@tonic-gate return -1;
229*7c478bd9Sstevel@tonic-gate last += suffix_len;
230*7c478bd9Sstevel@tonic-gate };
231*7c478bd9Sstevel@tonic-gate /*
232*7c478bd9Sstevel@tonic-gate * Start a new line.
233*7c478bd9Sstevel@tonic-gate */
234*7c478bd9Sstevel@tonic-gate if(write_fn(data, "\n", 1) != 1)
235*7c478bd9Sstevel@tonic-gate return -1;
236*7c478bd9Sstevel@tonic-gate /*
237*7c478bd9Sstevel@tonic-gate * Skip any spaces and tabs that follow the last word that was written.
238*7c478bd9Sstevel@tonic-gate */
239*7c478bd9Sstevel@tonic-gate while(string[ndone] && isspace((int)string[ndone]) &&
240*7c478bd9Sstevel@tonic-gate string[ndone] != '\n')
241*7c478bd9Sstevel@tonic-gate ndone++;
242*7c478bd9Sstevel@tonic-gate /*
243*7c478bd9Sstevel@tonic-gate * If the terminating character was a literal newline character,
244*7c478bd9Sstevel@tonic-gate * skip it in the input string, since we just wrote it.
245*7c478bd9Sstevel@tonic-gate */
246*7c478bd9Sstevel@tonic-gate if(string[ndone] == '\n')
247*7c478bd9Sstevel@tonic-gate ndone++;
248*7c478bd9Sstevel@tonic-gate last = 0;
249*7c478bd9Sstevel@tonic-gate };
250*7c478bd9Sstevel@tonic-gate };
251*7c478bd9Sstevel@tonic-gate /*
252*7c478bd9Sstevel@tonic-gate * Return the column number of the last character printed.
253*7c478bd9Sstevel@tonic-gate */
254*7c478bd9Sstevel@tonic-gate return last;
255*7c478bd9Sstevel@tonic-gate }
256*7c478bd9Sstevel@tonic-gate
257*7c478bd9Sstevel@tonic-gate /*.......................................................................
258*7c478bd9Sstevel@tonic-gate * Write a given number of spaces to the specified stdio output string.
259*7c478bd9Sstevel@tonic-gate *
260*7c478bd9Sstevel@tonic-gate * Input:
261*7c478bd9Sstevel@tonic-gate * write_fn GlWriteFn * The callback function to use to write the
262*7c478bd9Sstevel@tonic-gate * output.
263*7c478bd9Sstevel@tonic-gate * data void * A pointer to arbitrary data to be passed to
264*7c478bd9Sstevel@tonic-gate * write_fn() whenever it is called.
265*7c478bd9Sstevel@tonic-gate * c int The padding character.
266*7c478bd9Sstevel@tonic-gate * n int The number of spaces to be written.
267*7c478bd9Sstevel@tonic-gate * Output:
268*7c478bd9Sstevel@tonic-gate * return int 0 - OK.
269*7c478bd9Sstevel@tonic-gate * 1 - Error.
270*7c478bd9Sstevel@tonic-gate */
_io_pad_line(GlWriteFn * write_fn,void * data,int c,int n)271*7c478bd9Sstevel@tonic-gate static int _io_pad_line(GlWriteFn *write_fn, void *data, int c, int n)
272*7c478bd9Sstevel@tonic-gate {
273*7c478bd9Sstevel@tonic-gate enum {FILL_SIZE=20};
274*7c478bd9Sstevel@tonic-gate char fill[FILL_SIZE+1];
275*7c478bd9Sstevel@tonic-gate /*
276*7c478bd9Sstevel@tonic-gate * Fill the buffer with the specified padding character.
277*7c478bd9Sstevel@tonic-gate */
278*7c478bd9Sstevel@tonic-gate memset(fill, c, FILL_SIZE);
279*7c478bd9Sstevel@tonic-gate fill[FILL_SIZE] = '\0';
280*7c478bd9Sstevel@tonic-gate /*
281*7c478bd9Sstevel@tonic-gate * Write the spaces using the above literal string of spaces as
282*7c478bd9Sstevel@tonic-gate * many times as needed to output the requested number of spaces.
283*7c478bd9Sstevel@tonic-gate */
284*7c478bd9Sstevel@tonic-gate while(n > 0) {
285*7c478bd9Sstevel@tonic-gate int nnew = n <= FILL_SIZE ? n : FILL_SIZE;
286*7c478bd9Sstevel@tonic-gate if(write_fn(data, fill, nnew) != nnew)
287*7c478bd9Sstevel@tonic-gate return 1;
288*7c478bd9Sstevel@tonic-gate n -= nnew;
289*7c478bd9Sstevel@tonic-gate };
290*7c478bd9Sstevel@tonic-gate return 0;
291*7c478bd9Sstevel@tonic-gate }
292*7c478bd9Sstevel@tonic-gate
293*7c478bd9Sstevel@tonic-gate /*.......................................................................
294*7c478bd9Sstevel@tonic-gate * The following is an output callback function which uses fwrite()
295*7c478bd9Sstevel@tonic-gate * to write to the stdio stream specified via its callback data argument.
296*7c478bd9Sstevel@tonic-gate *
297*7c478bd9Sstevel@tonic-gate * Input:
298*7c478bd9Sstevel@tonic-gate * data void * The stdio stream to write to, specified via a
299*7c478bd9Sstevel@tonic-gate * (FILE *) pointer cast to (void *).
300*7c478bd9Sstevel@tonic-gate * s const char * The string to be written.
301*7c478bd9Sstevel@tonic-gate * n int The length of the prefix of s[] to attempt to
302*7c478bd9Sstevel@tonic-gate * write.
303*7c478bd9Sstevel@tonic-gate * Output:
304*7c478bd9Sstevel@tonic-gate * return int The number of characters written from s[]. This
305*7c478bd9Sstevel@tonic-gate * should normally be a number in the range 0 to n.
306*7c478bd9Sstevel@tonic-gate * To signal that an I/O error occurred, return -1.
307*7c478bd9Sstevel@tonic-gate */
GL_WRITE_FN(_io_write_stdio)308*7c478bd9Sstevel@tonic-gate GL_WRITE_FN(_io_write_stdio)
309*7c478bd9Sstevel@tonic-gate {
310*7c478bd9Sstevel@tonic-gate int ndone; /* The total number of characters written */
311*7c478bd9Sstevel@tonic-gate int nnew; /* The number of characters written in the latest write */
312*7c478bd9Sstevel@tonic-gate /*
313*7c478bd9Sstevel@tonic-gate * The callback data is the stdio stream to write to.
314*7c478bd9Sstevel@tonic-gate */
315*7c478bd9Sstevel@tonic-gate FILE *fp = (FILE *) data;
316*7c478bd9Sstevel@tonic-gate /*
317*7c478bd9Sstevel@tonic-gate * Because of signals we may need to do more than one write to output
318*7c478bd9Sstevel@tonic-gate * the whole string.
319*7c478bd9Sstevel@tonic-gate */
320*7c478bd9Sstevel@tonic-gate for(ndone=0; ndone<n; ndone += nnew) {
321*7c478bd9Sstevel@tonic-gate int nmore = n - ndone;
322*7c478bd9Sstevel@tonic-gate nnew = fwrite(s, sizeof(char), nmore, fp);
323*7c478bd9Sstevel@tonic-gate if(nnew < nmore) {
324*7c478bd9Sstevel@tonic-gate if(errno == EINTR)
325*7c478bd9Sstevel@tonic-gate clearerr(fp);
326*7c478bd9Sstevel@tonic-gate else
327*7c478bd9Sstevel@tonic-gate return ferror(fp) ? -1 : ndone + nnew;
328*7c478bd9Sstevel@tonic-gate };
329*7c478bd9Sstevel@tonic-gate };
330*7c478bd9Sstevel@tonic-gate return ndone;
331*7c478bd9Sstevel@tonic-gate }
332*7c478bd9Sstevel@tonic-gate
333