00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <errno.h>
00031 #include <stdarg.h>
00032 #include <ctype.h>
00033
00034 #include "argp-fmtstream.h"
00035 #include "argp-namefrob.h"
00036
00037 #ifndef ARGP_FMTSTREAM_USE_LINEWRAP
00038
00039 #ifndef isblank
00040 #define isblank(ch) ((ch)==' ' || (ch)=='\t')
00041 #endif
00042
00043 #if defined _LIBC && defined USE_IN_LIBIO
00044 # include <libio/libioP.h>
00045 # define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a)
00046 #endif
00047
00048 #define INIT_BUF_SIZE 200
00049 #define PRINTF_SIZE_GUESS 150
00050
00051
00052
00053
00054
00055
00056
00057 argp_fmtstream_t
00058 __argp_make_fmtstream (FILE *stream,
00059 size_t lmargin, size_t rmargin, ssize_t wmargin)
00060 {
00061 argp_fmtstream_t fs = malloc (sizeof (struct argp_fmtstream));
00062 if (fs)
00063 {
00064 fs->stream = stream;
00065
00066 fs->lmargin = lmargin;
00067 fs->rmargin = rmargin;
00068 fs->wmargin = wmargin;
00069 fs->point_col = 0;
00070 fs->point_offs = 0;
00071
00072 fs->buf = malloc (INIT_BUF_SIZE);
00073 if (! fs->buf)
00074 {
00075 free (fs);
00076 fs = 0;
00077 }
00078 else
00079 {
00080 fs->p = fs->buf;
00081 fs->end = fs->buf + INIT_BUF_SIZE;
00082 }
00083 }
00084
00085 return fs;
00086 }
00087 #ifdef weak_alias
00088 weak_alias (__argp_make_fmtstream, argp_make_fmtstream)
00089 #endif
00090
00091
00092 void
00093 __argp_fmtstream_free (argp_fmtstream_t fs)
00094 {
00095 __argp_fmtstream_update (fs);
00096 if (fs->p > fs->buf)
00097 FWRITE_UNLOCKED (fs->buf, 1, fs->p - fs->buf, fs->stream);
00098 free (fs->buf);
00099 free (fs);
00100 }
00101 #ifdef weak_alias
00102 weak_alias (__argp_fmtstream_free, argp_fmtstream_free)
00103 #endif
00104
00105
00106
00107 void
00108 __argp_fmtstream_update (argp_fmtstream_t fs)
00109 {
00110 char *buf, *nl;
00111 size_t len;
00112
00113
00114 buf = fs->buf + fs->point_offs;
00115 while (buf < fs->p)
00116 {
00117 size_t r;
00118
00119 if (fs->point_col == 0 && fs->lmargin != 0)
00120 {
00121
00122 const size_t pad = fs->lmargin;
00123 if (fs->p + pad < fs->end)
00124 {
00125
00126
00127 memmove (buf + pad, buf, fs->p - buf);
00128 fs->p += pad;
00129 memset (buf, ' ', pad);
00130 buf += pad;
00131 }
00132 else
00133 {
00134
00135 size_t i;
00136 for (i = 0; i < pad; i++)
00137 PUTC_UNLOCKED (' ', fs->stream);
00138 }
00139 fs->point_col = pad;
00140 }
00141
00142 len = fs->p - buf;
00143 nl = memchr (buf, '\n', len);
00144
00145 if (fs->point_col < 0)
00146 fs->point_col = 0;
00147
00148 if (!nl)
00149 {
00150
00151
00152 if (fs->point_col + len < fs->rmargin)
00153 {
00154
00155
00156
00157 fs->point_col += len;
00158 break;
00159 }
00160 else
00161
00162
00163 nl = fs->p;
00164 }
00165 else if (fs->point_col + (nl - buf) < (ssize_t) fs->rmargin)
00166 {
00167
00168
00169 fs->point_col = 0;
00170 buf = nl + 1;
00171 continue;
00172 }
00173
00174
00175 r = fs->rmargin - 1;
00176
00177 if (fs->wmargin < 0)
00178 {
00179
00180
00181 if (nl < fs->p)
00182 {
00183 memmove (buf + (r - fs->point_col), nl, fs->p - nl);
00184 fs->p -= buf + (r - fs->point_col) - nl;
00185
00186 fs->point_col = 0;
00187 buf += r + 1;
00188 }
00189 else
00190 {
00191
00192
00193
00194 fs->point_col += len;
00195 fs->p -= fs->point_col - r;
00196 break;
00197 }
00198 }
00199 else
00200 {
00201
00202
00203
00204
00205 char *p, *nextline;
00206 int i;
00207
00208 p = buf + (r + 1 - fs->point_col);
00209 while (p >= buf && !isblank (*p))
00210 --p;
00211 nextline = p + 1;
00212
00213 if (nextline > buf)
00214 {
00215
00216 if (p >= buf)
00217 do
00218 --p;
00219 while (p >= buf && isblank (*p));
00220 nl = p + 1;
00221 }
00222 else
00223 {
00224
00225
00226 p = buf + (r + 1 - fs->point_col);
00227
00228 do
00229 ++p;
00230 while (p < nl && !isblank (*p));
00231 if (p == nl)
00232 {
00233
00234 fs->point_col = 0;
00235 buf = nl + 1;
00236 continue;
00237 }
00238
00239 nl = p;
00240
00241 do
00242 ++p;
00243 while (isblank (*p));
00244
00245 nextline = p;
00246 }
00247
00248
00249
00250
00251
00252
00253 if (nextline == buf + len + 1
00254 ? fs->end - nl < fs->wmargin + 1
00255 : nextline - (nl + 1) < fs->wmargin)
00256 {
00257
00258 if (fs->end - fs->p > fs->wmargin + 1)
00259
00260 {
00261 size_t mv = fs->p - nextline;
00262 memmove (nl + 1 + fs->wmargin, nextline, mv);
00263 nextline = nl + 1 + fs->wmargin;
00264 len = nextline + mv - buf;
00265 *nl++ = '\n';
00266 }
00267 else
00268
00269 {
00270 if (nl > fs->buf)
00271 FWRITE_UNLOCKED (fs->buf, 1, nl - fs->buf, fs->stream);
00272 PUTC_UNLOCKED ('\n', fs->stream);
00273 len += buf - fs->buf;
00274 nl = buf = fs->buf;
00275 }
00276 }
00277 else
00278
00279
00280 *nl++ = '\n';
00281
00282 if (nextline - nl >= fs->wmargin
00283 || (nextline == buf + len + 1 && fs->end - nextline >= fs->wmargin))
00284
00285 for (i = 0; i < fs->wmargin; ++i)
00286 *nl++ = ' ';
00287 else
00288 for (i = 0; i < fs->wmargin; ++i)
00289 PUTC_UNLOCKED (' ', fs->stream);
00290
00291
00292
00293 if (nl < nextline)
00294 memmove (nl, nextline, buf + len - nextline);
00295 len -= nextline - buf;
00296
00297
00298 buf = nl;
00299
00300
00301 fs->p = nl + len;
00302
00303
00304
00305
00306 fs->point_col = fs->wmargin ? fs->wmargin : -1;
00307 }
00308 }
00309
00310
00311 fs->point_offs = fs->p - fs->buf;
00312 }
00313
00314
00315
00316 int
00317 __argp_fmtstream_ensure (struct argp_fmtstream *fs, size_t amount)
00318 {
00319 if ((size_t) (fs->end - fs->p) < amount)
00320 {
00321 ssize_t wrote;
00322
00323
00324 __argp_fmtstream_update (fs);
00325
00326 wrote = FWRITE_UNLOCKED (fs->buf, 1, fs->p - fs->buf, fs->stream);
00327 if (wrote == fs->p - fs->buf)
00328 {
00329 fs->p = fs->buf;
00330 fs->point_offs = 0;
00331 }
00332 else
00333 {
00334 fs->p -= wrote;
00335 fs->point_offs -= wrote;
00336 memmove (fs->buf, fs->buf + wrote, fs->p - fs->buf);
00337 return 0;
00338 }
00339
00340 if ((size_t) (fs->end - fs->buf) < amount)
00341
00342 {
00343 size_t new_size = fs->end - fs->buf + amount;
00344 char *new_buf = realloc (fs->buf, new_size);
00345
00346 if (! new_buf)
00347 {
00348 __set_errno (ENOMEM);
00349 return 0;
00350 }
00351
00352 fs->buf = new_buf;
00353 fs->end = new_buf + new_size;
00354 fs->p = fs->buf;
00355 }
00356 }
00357
00358 return 1;
00359 }
00360
00361 ssize_t
00362 __argp_fmtstream_printf (struct argp_fmtstream *fs, const char *fmt, ...)
00363 {
00364 size_t out;
00365 size_t avail;
00366 size_t size_guess = PRINTF_SIZE_GUESS;
00367
00368 do
00369 {
00370 va_list args;
00371
00372 if (! __argp_fmtstream_ensure (fs, size_guess))
00373 return -1;
00374
00375 va_start (args, fmt);
00376 avail = fs->end - fs->p;
00377 out = __vsnprintf (fs->p, avail, fmt, args);
00378 va_end (args);
00379 if (out >= avail)
00380 size_guess = out + 1;
00381 }
00382 while (out >= avail);
00383
00384 fs->p += out;
00385
00386 return out;
00387 }
00388 #ifdef weak_alias
00389 weak_alias (__argp_fmtstream_printf, argp_fmtstream_printf)
00390 #endif
00391
00392
00393
00394 size_t
00395 __argp_fmtstream_write (argp_fmtstream_t __fs,
00396 __const char *__str, size_t __len)
00397 {
00398 if (__fs->p + __len <= __fs->end || __argp_fmtstream_ensure (__fs, __len))
00399 {
00400 memcpy (__fs->p, __str, __len);
00401 __fs->p += __len;
00402 return __len;
00403 }
00404 else
00405 return 0;
00406 }
00407
00408 int
00409 __argp_fmtstream_puts (argp_fmtstream_t __fs, __const char *__str)
00410 {
00411 size_t __len = strlen (__str);
00412 if (__len)
00413 {
00414 size_t __wrote = __argp_fmtstream_write (__fs, __str, __len);
00415 return __wrote == __len ? 0 : -1;
00416 }
00417 else
00418 return 0;
00419 }
00420
00421 int
00422 __argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch)
00423 {
00424 if (__fs->p < __fs->end || __argp_fmtstream_ensure (__fs, 1))
00425 return *__fs->p++ = __ch;
00426 else
00427 return EOF;
00428 }
00429
00430
00431 size_t
00432 __argp_fmtstream_set_lmargin (argp_fmtstream_t __fs, size_t __lmargin)
00433 {
00434 size_t __old;
00435 if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
00436 __argp_fmtstream_update (__fs);
00437 __old = __fs->lmargin;
00438 __fs->lmargin = __lmargin;
00439 return __old;
00440 }
00441
00442
00443 size_t
00444 __argp_fmtstream_set_rmargin (argp_fmtstream_t __fs, size_t __rmargin)
00445 {
00446 size_t __old;
00447 if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
00448 __argp_fmtstream_update (__fs);
00449 __old = __fs->rmargin;
00450 __fs->rmargin = __rmargin;
00451 return __old;
00452 }
00453
00454
00455 size_t
00456 __argp_fmtstream_set_wmargin (argp_fmtstream_t __fs, size_t __wmargin)
00457 {
00458 size_t __old;
00459 if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
00460 __argp_fmtstream_update (__fs);
00461 __old = __fs->wmargin;
00462 __fs->wmargin = __wmargin;
00463 return __old;
00464 }
00465
00466
00467 size_t
00468 __argp_fmtstream_point (argp_fmtstream_t __fs)
00469 {
00470 if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
00471 __argp_fmtstream_update (__fs);
00472 return __fs->point_col >= 0 ? __fs->point_col : 0;
00473 }
00474
00475 #endif