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 */ 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 */ 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 */ 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