/* simulate fwrite() */ size_t x_fwrite(const void *p, size_t size, size_t nmemb, XFILE *f) { ssize_t ret; size_t total=size*nmemb; // we should check for overflow... if (!total) return 0; // this is what fwrite must do according to the standard /* we might be writing unbuffered */ if (f->buftype == X_IONBF || (!f->buf && !x_allocate_buffer(f))) { ret = write(f->fd, p, total); if (ret < 0) return 0; return ret/size; } if (total <= f->bufsize - f->bufused) { memcpy(f->buf + f->bufused, (const char *)p, total); f->bufused += total; } else { size_t buffered = total % f->bufsize; // 0 <= buffered <= total if (x_fflush(f) < 0) return 0; // flush old content before writing more bytes ret = write(f->fd, (const char *)p, total-buffered); // no-op when (buffered == total); write all when (buffered == 0) if (ret < 0) return 0; if (ret < total-buffered) return written/size; memcpy(f->buf, total-buffered+(const char *)p, buffered); // no-op when (buffered == 0); copy all when (buffered == total) f->bufused = buffered; } } /* when line buffered we need to flush at the last linefeed. This can flush a bit more than necessary, but that is harmless */ if (f->buftype == X_IOLBF && f->bufused) { int i; for (i=f->bufused-1; i>=0; i--) { if (*(i+f->buf) == '\n') { if (x_fflush(f) < 0) return (total-f->bufused)/size; break; } } } return nmemb; }