1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd. 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * All rights reserved. 5*0Sstevel@tonic-gate * 6*0Sstevel@tonic-gate * Permission is hereby granted, free of charge, to any person obtaining a 7*0Sstevel@tonic-gate * copy of this software and associated documentation files (the 8*0Sstevel@tonic-gate * "Software"), to deal in the Software without restriction, including 9*0Sstevel@tonic-gate * without limitation the rights to use, copy, modify, merge, publish, 10*0Sstevel@tonic-gate * distribute, and/or sell copies of the Software, and to permit persons 11*0Sstevel@tonic-gate * to whom the Software is furnished to do so, provided that the above 12*0Sstevel@tonic-gate * copyright notice(s) and this permission notice appear in all copies of 13*0Sstevel@tonic-gate * the Software and that both the above copyright notice(s) and this 14*0Sstevel@tonic-gate * permission notice appear in supporting documentation. 15*0Sstevel@tonic-gate * 16*0Sstevel@tonic-gate * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17*0Sstevel@tonic-gate * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18*0Sstevel@tonic-gate * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 19*0Sstevel@tonic-gate * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 20*0Sstevel@tonic-gate * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL 21*0Sstevel@tonic-gate * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING 22*0Sstevel@tonic-gate * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 23*0Sstevel@tonic-gate * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 24*0Sstevel@tonic-gate * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 25*0Sstevel@tonic-gate * 26*0Sstevel@tonic-gate * Except as contained in this notice, the name of a copyright holder 27*0Sstevel@tonic-gate * shall not be used in advertising or otherwise to promote the sale, use 28*0Sstevel@tonic-gate * or other dealings in this Software without prior written authorization 29*0Sstevel@tonic-gate * of the copyright holder. 30*0Sstevel@tonic-gate */ 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #include <stdlib.h> 35*0Sstevel@tonic-gate #include <stdio.h> 36*0Sstevel@tonic-gate #include <string.h> 37*0Sstevel@tonic-gate #include <errno.h> 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate #include "ioutil.h" 40*0Sstevel@tonic-gate #include "chrqueue.h" 41*0Sstevel@tonic-gate #include "freelist.h" 42*0Sstevel@tonic-gate #include "errmsg.h" 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate /* 45*0Sstevel@tonic-gate * Set the number of bytes allocated to each node of the list of 46*0Sstevel@tonic-gate * character buffers. This facility is designed principally as 47*0Sstevel@tonic-gate * an expandible I/O output buffer, so use the stdio buffer size 48*0Sstevel@tonic-gate * where available. 49*0Sstevel@tonic-gate */ 50*0Sstevel@tonic-gate #ifdef BUFSIZ 51*0Sstevel@tonic-gate #define GL_CQ_SIZE BUFSIZ 52*0Sstevel@tonic-gate #else 53*0Sstevel@tonic-gate #define GL_CQ_SIZE 512 54*0Sstevel@tonic-gate #endif 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate /* 57*0Sstevel@tonic-gate * The queue is contained in a list of fixed sized buffers. New nodes 58*0Sstevel@tonic-gate * are appended to this list as needed to accomodate newly added bytes. 59*0Sstevel@tonic-gate * Old nodes at the head of the list are removed as they are emptied. 60*0Sstevel@tonic-gate */ 61*0Sstevel@tonic-gate typedef struct CqCharBuff CqCharBuff; 62*0Sstevel@tonic-gate struct CqCharBuff { 63*0Sstevel@tonic-gate CqCharBuff *next; /* The next node in the list of buffers */ 64*0Sstevel@tonic-gate char bytes[GL_CQ_SIZE]; /* The fixed size buffer of this node */ 65*0Sstevel@tonic-gate }; 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate /* 68*0Sstevel@tonic-gate * Define the structure that is used to contain a list of character 69*0Sstevel@tonic-gate * buffers. 70*0Sstevel@tonic-gate */ 71*0Sstevel@tonic-gate struct GlCharQueue { 72*0Sstevel@tonic-gate ErrMsg *err; /* A buffer in which to record error messages */ 73*0Sstevel@tonic-gate FreeList *bufmem; /* A free-list of CqCharBuff structures */ 74*0Sstevel@tonic-gate struct { 75*0Sstevel@tonic-gate CqCharBuff *head; /* The head of the list of output buffers */ 76*0Sstevel@tonic-gate CqCharBuff *tail; /* The tail of the list of output buffers */ 77*0Sstevel@tonic-gate } buffers; 78*0Sstevel@tonic-gate int nflush; /* The total number of characters that have been */ 79*0Sstevel@tonic-gate /* flushed from the start of the queue since */ 80*0Sstevel@tonic-gate /* _glq_empty_queue() was last called. */ 81*0Sstevel@tonic-gate int ntotal; /* The total number of characters that have been */ 82*0Sstevel@tonic-gate /* appended to the queue since _glq_empty_queue() */ 83*0Sstevel@tonic-gate /* was last called. */ 84*0Sstevel@tonic-gate }; 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate /*....................................................................... 87*0Sstevel@tonic-gate * Create a new GlCharQueue object. 88*0Sstevel@tonic-gate * 89*0Sstevel@tonic-gate * Output: 90*0Sstevel@tonic-gate * return GlCharQueue * The new object, or NULL on error. 91*0Sstevel@tonic-gate */ 92*0Sstevel@tonic-gate GlCharQueue *_new_GlCharQueue(void) 93*0Sstevel@tonic-gate { 94*0Sstevel@tonic-gate GlCharQueue *cq; /* The object to be returned */ 95*0Sstevel@tonic-gate /* 96*0Sstevel@tonic-gate * Allocate the container. 97*0Sstevel@tonic-gate */ 98*0Sstevel@tonic-gate cq = malloc(sizeof(GlCharQueue)); 99*0Sstevel@tonic-gate if(!cq) { 100*0Sstevel@tonic-gate errno = ENOMEM; 101*0Sstevel@tonic-gate return NULL; 102*0Sstevel@tonic-gate }; 103*0Sstevel@tonic-gate /* 104*0Sstevel@tonic-gate * Before attempting any operation that might fail, initialize the 105*0Sstevel@tonic-gate * container at least up to the point at which it can safely be passed 106*0Sstevel@tonic-gate * to del_GlCharQueue(). 107*0Sstevel@tonic-gate */ 108*0Sstevel@tonic-gate cq->err = NULL; 109*0Sstevel@tonic-gate cq->bufmem = NULL; 110*0Sstevel@tonic-gate cq->buffers.head = NULL; 111*0Sstevel@tonic-gate cq->buffers.tail = NULL; 112*0Sstevel@tonic-gate cq->nflush = cq->ntotal = 0; 113*0Sstevel@tonic-gate /* 114*0Sstevel@tonic-gate * Allocate a place to record error messages. 115*0Sstevel@tonic-gate */ 116*0Sstevel@tonic-gate cq->err = _new_ErrMsg(); 117*0Sstevel@tonic-gate if(!cq->err) 118*0Sstevel@tonic-gate return _del_GlCharQueue(cq); 119*0Sstevel@tonic-gate /* 120*0Sstevel@tonic-gate * Allocate the freelist of CqCharBuff structures. 121*0Sstevel@tonic-gate */ 122*0Sstevel@tonic-gate cq->bufmem = _new_FreeList(sizeof(CqCharBuff), 1); 123*0Sstevel@tonic-gate if(!cq->bufmem) 124*0Sstevel@tonic-gate return _del_GlCharQueue(cq); 125*0Sstevel@tonic-gate return cq; 126*0Sstevel@tonic-gate } 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate /*....................................................................... 129*0Sstevel@tonic-gate * Delete a GlCharQueue object. 130*0Sstevel@tonic-gate * 131*0Sstevel@tonic-gate * Input: 132*0Sstevel@tonic-gate * cq GlCharQueue * The object to be deleted. 133*0Sstevel@tonic-gate * Output: 134*0Sstevel@tonic-gate * return GlCharQueue * The deleted object (always NULL). 135*0Sstevel@tonic-gate */ 136*0Sstevel@tonic-gate GlCharQueue *_del_GlCharQueue(GlCharQueue *cq) 137*0Sstevel@tonic-gate { 138*0Sstevel@tonic-gate if(cq) { 139*0Sstevel@tonic-gate cq->err = _del_ErrMsg(cq->err); 140*0Sstevel@tonic-gate cq->bufmem = _del_FreeList(cq->bufmem, 1); 141*0Sstevel@tonic-gate free(cq); 142*0Sstevel@tonic-gate }; 143*0Sstevel@tonic-gate return NULL; 144*0Sstevel@tonic-gate } 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate /*....................................................................... 147*0Sstevel@tonic-gate * Append an array of n characters to a character queue. 148*0Sstevel@tonic-gate * 149*0Sstevel@tonic-gate * Input: 150*0Sstevel@tonic-gate * cq GlCharQueue * The queue to append to. 151*0Sstevel@tonic-gate * chars const char * The array of n characters to be appended. 152*0Sstevel@tonic-gate * n int The number of characters in chars[]. 153*0Sstevel@tonic-gate * write_fn GL_WRITE_FN * The function to call to output characters, 154*0Sstevel@tonic-gate * or 0 to simply discard the contents of the 155*0Sstevel@tonic-gate * queue. This will be called whenever the 156*0Sstevel@tonic-gate * buffer becomes full. If it fails to release 157*0Sstevel@tonic-gate * any space, the buffer will be extended. 158*0Sstevel@tonic-gate * data void * Anonymous data to pass to write_fn(). 159*0Sstevel@tonic-gate * Output: 160*0Sstevel@tonic-gate * return int The number of characters successfully 161*0Sstevel@tonic-gate * appended. This will only be < n on error. 162*0Sstevel@tonic-gate */ 163*0Sstevel@tonic-gate int _glq_append_chars(GlCharQueue *cq, const char *chars, int n, 164*0Sstevel@tonic-gate GlWriteFn *write_fn, void *data) 165*0Sstevel@tonic-gate { 166*0Sstevel@tonic-gate int ndone = 0; /* The number of characters appended so far */ 167*0Sstevel@tonic-gate /* 168*0Sstevel@tonic-gate * Check the arguments. 169*0Sstevel@tonic-gate */ 170*0Sstevel@tonic-gate if(!cq || !chars) { 171*0Sstevel@tonic-gate errno = EINVAL; 172*0Sstevel@tonic-gate return 0; 173*0Sstevel@tonic-gate }; 174*0Sstevel@tonic-gate /* 175*0Sstevel@tonic-gate * The appended characters may have to be split between multiple 176*0Sstevel@tonic-gate * buffers, so loop for each buffer. 177*0Sstevel@tonic-gate */ 178*0Sstevel@tonic-gate while(ndone < n) { 179*0Sstevel@tonic-gate int ntodo; /* The number of characters remaining to be appended */ 180*0Sstevel@tonic-gate int nleft; /* The amount of space remaining in cq->buffers.tail */ 181*0Sstevel@tonic-gate int nnew; /* The number of characters to append to cq->buffers.tail */ 182*0Sstevel@tonic-gate /* 183*0Sstevel@tonic-gate * Compute the offset at which the next character should be written 184*0Sstevel@tonic-gate * into the tail buffer segment. 185*0Sstevel@tonic-gate */ 186*0Sstevel@tonic-gate int boff = cq->ntotal % GL_CQ_SIZE; 187*0Sstevel@tonic-gate /* 188*0Sstevel@tonic-gate * Since we don't allocate a new buffer until we have at least one 189*0Sstevel@tonic-gate * character to write into it, if boff is 0 at this point, it means 190*0Sstevel@tonic-gate * that we hit the end of the tail buffer segment on the last append, 191*0Sstevel@tonic-gate * so we need to allocate a new one. 192*0Sstevel@tonic-gate * 193*0Sstevel@tonic-gate * If allocating this new node will require a call to malloc(), as 194*0Sstevel@tonic-gate * opposed to using a currently unused node in the freelist, first try 195*0Sstevel@tonic-gate * flushing the current contents of the buffer to the terminal. When 196*0Sstevel@tonic-gate * write_fn() uses blocking I/O, this stops the buffer size ever getting 197*0Sstevel@tonic-gate * bigger than a single buffer node. When it is non-blocking, it helps 198*0Sstevel@tonic-gate * to keep the amount of memory, but it isn't gauranteed to do so. 199*0Sstevel@tonic-gate */ 200*0Sstevel@tonic-gate if(boff == 0 && _idle_FreeListNodes(cq->bufmem) == 0) { 201*0Sstevel@tonic-gate switch(_glq_flush_queue(cq, write_fn, data)) { 202*0Sstevel@tonic-gate case GLQ_FLUSH_DONE: 203*0Sstevel@tonic-gate break; 204*0Sstevel@tonic-gate case GLQ_FLUSH_AGAIN: 205*0Sstevel@tonic-gate errno = 0; /* Don't confuse the caller */ 206*0Sstevel@tonic-gate break; 207*0Sstevel@tonic-gate default: 208*0Sstevel@tonic-gate return ndone; /* Error */ 209*0Sstevel@tonic-gate }; 210*0Sstevel@tonic-gate boff = cq->ntotal % GL_CQ_SIZE; 211*0Sstevel@tonic-gate }; 212*0Sstevel@tonic-gate /* 213*0Sstevel@tonic-gate * Since we don't allocate a new buffer until we have at least one 214*0Sstevel@tonic-gate * character to write into it, if boff is 0 at this point, it means 215*0Sstevel@tonic-gate * that we hit the end of the tail buffer segment on the last append, 216*0Sstevel@tonic-gate * so we need to allocate a new one. 217*0Sstevel@tonic-gate */ 218*0Sstevel@tonic-gate if(boff == 0) { 219*0Sstevel@tonic-gate /* 220*0Sstevel@tonic-gate * Allocate the new node. 221*0Sstevel@tonic-gate */ 222*0Sstevel@tonic-gate CqCharBuff *node = (CqCharBuff *) _new_FreeListNode(cq->bufmem); 223*0Sstevel@tonic-gate if(!node) { 224*0Sstevel@tonic-gate _err_record_msg(cq->err, "Insufficient memory to buffer output.", 225*0Sstevel@tonic-gate END_ERR_MSG); 226*0Sstevel@tonic-gate return ndone; 227*0Sstevel@tonic-gate }; 228*0Sstevel@tonic-gate /* 229*0Sstevel@tonic-gate * Initialize the node. 230*0Sstevel@tonic-gate */ 231*0Sstevel@tonic-gate node->next = NULL; 232*0Sstevel@tonic-gate /* 233*0Sstevel@tonic-gate * Append the new node to the tail of the list. 234*0Sstevel@tonic-gate */ 235*0Sstevel@tonic-gate if(cq->buffers.tail) 236*0Sstevel@tonic-gate cq->buffers.tail->next = node; 237*0Sstevel@tonic-gate else 238*0Sstevel@tonic-gate cq->buffers.head = node; 239*0Sstevel@tonic-gate cq->buffers.tail = node; 240*0Sstevel@tonic-gate }; 241*0Sstevel@tonic-gate /* 242*0Sstevel@tonic-gate * How much room is there for new characters in the current tail node? 243*0Sstevel@tonic-gate */ 244*0Sstevel@tonic-gate nleft = GL_CQ_SIZE - boff; 245*0Sstevel@tonic-gate /* 246*0Sstevel@tonic-gate * How many characters remain to be appended? 247*0Sstevel@tonic-gate */ 248*0Sstevel@tonic-gate ntodo = n - ndone; 249*0Sstevel@tonic-gate /* 250*0Sstevel@tonic-gate * How many characters should we append to the current tail node? 251*0Sstevel@tonic-gate */ 252*0Sstevel@tonic-gate nnew = nleft < ntodo ? nleft : ntodo; 253*0Sstevel@tonic-gate /* 254*0Sstevel@tonic-gate * Append the latest prefix of nnew characters. 255*0Sstevel@tonic-gate */ 256*0Sstevel@tonic-gate memcpy(cq->buffers.tail->bytes + boff, chars + ndone, nnew); 257*0Sstevel@tonic-gate cq->ntotal += nnew; 258*0Sstevel@tonic-gate ndone += nnew; 259*0Sstevel@tonic-gate }; 260*0Sstevel@tonic-gate /* 261*0Sstevel@tonic-gate * Return the count of the number of characters successfully appended. 262*0Sstevel@tonic-gate */ 263*0Sstevel@tonic-gate return ndone; 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate /*....................................................................... 267*0Sstevel@tonic-gate * Discard the contents of a queue of characters. 268*0Sstevel@tonic-gate * 269*0Sstevel@tonic-gate * Input: 270*0Sstevel@tonic-gate * cq GlCharQueue * The queue to clear. 271*0Sstevel@tonic-gate */ 272*0Sstevel@tonic-gate void _glq_empty_queue(GlCharQueue *cq) 273*0Sstevel@tonic-gate { 274*0Sstevel@tonic-gate if(cq) { 275*0Sstevel@tonic-gate /* 276*0Sstevel@tonic-gate * Return all list nodes to their respective free-lists. 277*0Sstevel@tonic-gate */ 278*0Sstevel@tonic-gate _rst_FreeList(cq->bufmem); 279*0Sstevel@tonic-gate /* 280*0Sstevel@tonic-gate * Mark the lists as empty. 281*0Sstevel@tonic-gate */ 282*0Sstevel@tonic-gate cq->buffers.head = cq->buffers.tail = NULL; 283*0Sstevel@tonic-gate cq->nflush = cq->ntotal = 0; 284*0Sstevel@tonic-gate }; 285*0Sstevel@tonic-gate } 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate /*....................................................................... 288*0Sstevel@tonic-gate * Return a count of the number of characters currently in the queue. 289*0Sstevel@tonic-gate * 290*0Sstevel@tonic-gate * Input: 291*0Sstevel@tonic-gate * cq GlCharQueue * The queue of interest. 292*0Sstevel@tonic-gate * Output: 293*0Sstevel@tonic-gate * return int The number of characters in the queue. 294*0Sstevel@tonic-gate */ 295*0Sstevel@tonic-gate int _glq_char_count(GlCharQueue *cq) 296*0Sstevel@tonic-gate { 297*0Sstevel@tonic-gate return (cq && cq->buffers.head) ? (cq->ntotal - cq->nflush) : 0; 298*0Sstevel@tonic-gate } 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate /*....................................................................... 301*0Sstevel@tonic-gate * Write as many characters as possible from the start of a character 302*0Sstevel@tonic-gate * queue via a given output callback function, removing those written 303*0Sstevel@tonic-gate * from the queue. 304*0Sstevel@tonic-gate * 305*0Sstevel@tonic-gate * Input: 306*0Sstevel@tonic-gate * cq GlCharQueue * The queue to write characters from. 307*0Sstevel@tonic-gate * write_fn GL_WRITE_FN * The function to call to output characters, 308*0Sstevel@tonic-gate * or 0 to simply discard the contents of the 309*0Sstevel@tonic-gate * queue. 310*0Sstevel@tonic-gate * data void * Anonymous data to pass to write_fn(). 311*0Sstevel@tonic-gate * Output: 312*0Sstevel@tonic-gate * return GlFlushState The status of the flush operation: 313*0Sstevel@tonic-gate * GLQ_FLUSH_DONE - The flush operation 314*0Sstevel@tonic-gate * completed successfully. 315*0Sstevel@tonic-gate * GLQ_FLUSH_AGAIN - The flush operation 316*0Sstevel@tonic-gate * couldn't be completed 317*0Sstevel@tonic-gate * on this call. Call this 318*0Sstevel@tonic-gate * function again when the 319*0Sstevel@tonic-gate * output channel can accept 320*0Sstevel@tonic-gate * further output. 321*0Sstevel@tonic-gate * GLQ_FLUSH_ERROR Unrecoverable error. 322*0Sstevel@tonic-gate */ 323*0Sstevel@tonic-gate GlqFlushState _glq_flush_queue(GlCharQueue *cq, GlWriteFn *write_fn, 324*0Sstevel@tonic-gate void *data) 325*0Sstevel@tonic-gate { 326*0Sstevel@tonic-gate /* 327*0Sstevel@tonic-gate * Check the arguments. 328*0Sstevel@tonic-gate */ 329*0Sstevel@tonic-gate if(!cq) { 330*0Sstevel@tonic-gate errno = EINVAL; 331*0Sstevel@tonic-gate return GLQ_FLUSH_ERROR; 332*0Sstevel@tonic-gate }; 333*0Sstevel@tonic-gate /* 334*0Sstevel@tonic-gate * If possible keep writing until all of the chained buffers have been 335*0Sstevel@tonic-gate * emptied and removed from the list. 336*0Sstevel@tonic-gate */ 337*0Sstevel@tonic-gate while(cq->buffers.head) { 338*0Sstevel@tonic-gate /* 339*0Sstevel@tonic-gate * Are we looking at the only node in the list? 340*0Sstevel@tonic-gate */ 341*0Sstevel@tonic-gate int is_tail = cq->buffers.head == cq->buffers.tail; 342*0Sstevel@tonic-gate /* 343*0Sstevel@tonic-gate * How many characters more than an exact multiple of the buffer-segment 344*0Sstevel@tonic-gate * size have been added to the buffer so far? 345*0Sstevel@tonic-gate */ 346*0Sstevel@tonic-gate int nmodulo = cq->ntotal % GL_CQ_SIZE; 347*0Sstevel@tonic-gate /* 348*0Sstevel@tonic-gate * How many characters of the buffer segment at the head of the list 349*0Sstevel@tonic-gate * have been used? Note that this includes any characters that have 350*0Sstevel@tonic-gate * already been flushed. Also note that if nmodulo==0, this means that 351*0Sstevel@tonic-gate * the tail buffer segment is full. The reason for this is that we 352*0Sstevel@tonic-gate * don't allocate new tail buffer segments until there is at least one 353*0Sstevel@tonic-gate * character to be added to them. 354*0Sstevel@tonic-gate */ 355*0Sstevel@tonic-gate int nhead = (!is_tail || nmodulo == 0) ? GL_CQ_SIZE : nmodulo; 356*0Sstevel@tonic-gate /* 357*0Sstevel@tonic-gate * How many characters remain to be flushed from the buffer 358*0Sstevel@tonic-gate * at the head of the list? 359*0Sstevel@tonic-gate */ 360*0Sstevel@tonic-gate int nbuff = nhead - (cq->nflush % GL_CQ_SIZE); 361*0Sstevel@tonic-gate /* 362*0Sstevel@tonic-gate * Attempt to write this number. 363*0Sstevel@tonic-gate */ 364*0Sstevel@tonic-gate int nnew = write_fn(data, cq->buffers.head->bytes + 365*0Sstevel@tonic-gate cq->nflush % GL_CQ_SIZE, nbuff); 366*0Sstevel@tonic-gate /* 367*0Sstevel@tonic-gate * Was anything written? 368*0Sstevel@tonic-gate */ 369*0Sstevel@tonic-gate if(nnew > 0) { 370*0Sstevel@tonic-gate /* 371*0Sstevel@tonic-gate * Increment the count of the number of characters that have 372*0Sstevel@tonic-gate * been flushed from the head of the queue. 373*0Sstevel@tonic-gate */ 374*0Sstevel@tonic-gate cq->nflush += nnew; 375*0Sstevel@tonic-gate /* 376*0Sstevel@tonic-gate * If we succeded in writing all of the contents of the current 377*0Sstevel@tonic-gate * buffer segment, remove it from the queue. 378*0Sstevel@tonic-gate */ 379*0Sstevel@tonic-gate if(nnew == nbuff) { 380*0Sstevel@tonic-gate /* 381*0Sstevel@tonic-gate * If we just emptied the last node left in the list, then the queue is 382*0Sstevel@tonic-gate * now empty and should be reset. 383*0Sstevel@tonic-gate */ 384*0Sstevel@tonic-gate if(is_tail) { 385*0Sstevel@tonic-gate _glq_empty_queue(cq); 386*0Sstevel@tonic-gate } else { 387*0Sstevel@tonic-gate /* 388*0Sstevel@tonic-gate * Get the node to be removed from the head of the list. 389*0Sstevel@tonic-gate */ 390*0Sstevel@tonic-gate CqCharBuff *node = cq->buffers.head; 391*0Sstevel@tonic-gate /* 392*0Sstevel@tonic-gate * Make the node that follows it the new head of the queue. 393*0Sstevel@tonic-gate */ 394*0Sstevel@tonic-gate cq->buffers.head = node->next; 395*0Sstevel@tonic-gate /* 396*0Sstevel@tonic-gate * Return it to the freelist. 397*0Sstevel@tonic-gate */ 398*0Sstevel@tonic-gate node = (CqCharBuff *) _del_FreeListNode(cq->bufmem, node); 399*0Sstevel@tonic-gate }; 400*0Sstevel@tonic-gate }; 401*0Sstevel@tonic-gate /* 402*0Sstevel@tonic-gate * If the write blocked, request that this function be called again 403*0Sstevel@tonic-gate * when space to write next becomes available. 404*0Sstevel@tonic-gate */ 405*0Sstevel@tonic-gate } else if(nnew==0) { 406*0Sstevel@tonic-gate return GLQ_FLUSH_AGAIN; 407*0Sstevel@tonic-gate /* 408*0Sstevel@tonic-gate * I/O error. 409*0Sstevel@tonic-gate */ 410*0Sstevel@tonic-gate } else { 411*0Sstevel@tonic-gate _err_record_msg(cq->err, "Error writing to terminal", END_ERR_MSG); 412*0Sstevel@tonic-gate return GLQ_FLUSH_ERROR; 413*0Sstevel@tonic-gate }; 414*0Sstevel@tonic-gate }; 415*0Sstevel@tonic-gate /* 416*0Sstevel@tonic-gate * To get here the queue must now be empty. 417*0Sstevel@tonic-gate */ 418*0Sstevel@tonic-gate return GLQ_FLUSH_DONE; 419*0Sstevel@tonic-gate } 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate /*....................................................................... 422*0Sstevel@tonic-gate * Return extra information (ie. in addition to that provided by errno) 423*0Sstevel@tonic-gate * about the last error to occur in any of the public functions of this 424*0Sstevel@tonic-gate * module. 425*0Sstevel@tonic-gate * 426*0Sstevel@tonic-gate * Input: 427*0Sstevel@tonic-gate * cq GlCharQueue * The container of the history list. 428*0Sstevel@tonic-gate * Output: 429*0Sstevel@tonic-gate * return const char * A pointer to the internal buffer in which 430*0Sstevel@tonic-gate * the error message is temporarily stored. 431*0Sstevel@tonic-gate */ 432*0Sstevel@tonic-gate const char *_glq_last_error(GlCharQueue *cq) 433*0Sstevel@tonic-gate { 434*0Sstevel@tonic-gate return cq ? _err_get_msg(cq->err) : "NULL GlCharQueue argument"; 435*0Sstevel@tonic-gate } 436