print.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2008, 2010, 2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2001, 2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id: print.c,v 1.37 2010/10/18 23:47:08 tbox Exp $ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <ctype.h>
00025 #include <stdio.h>              /* for sprintf() */
00026 #include <string.h>             /* for strlen() */
00027 
00028 #define ISC__PRINT_SOURCE       /* Used to get the isc_print_* prototypes. */
00029 
00030 #include <isc/assertions.h>
00031 #include <isc/int.h>
00032 #include <isc/msgs.h>
00033 #include <isc/print.h>
00034 #include <isc/stdlib.h>
00035 #include <isc/util.h>
00036 
00037 int
00038 isc_print_sprintf(char *str, const char *format, ...) {
00039         va_list ap;
00040 
00041         va_start(ap, format);
00042         vsprintf(str, format, ap);
00043         va_end(ap);
00044         return (strlen(str));
00045 }
00046 
00047 /*!
00048  * Return length of string that would have been written if not truncated.
00049  */
00050 
00051 int
00052 isc_print_snprintf(char *str, size_t size, const char *format, ...) {
00053         va_list ap;
00054         int ret;
00055 
00056         va_start(ap, format);
00057         ret = vsnprintf(str, size, format, ap);
00058         va_end(ap);
00059         return (ret);
00060 
00061 }
00062 
00063 /*!
00064  * Return length of string that would have been written if not truncated.
00065  */
00066 
00067 int
00068 isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
00069         int h;
00070         int l;
00071         int q;
00072         int alt;
00073         int zero;
00074         int left;
00075         int plus;
00076         int space;
00077         int neg;
00078         isc_int64_t tmpi;
00079         isc_uint64_t tmpui;
00080         unsigned long width;
00081         unsigned long precision;
00082         unsigned int length;
00083         char buf[1024];
00084         char c;
00085         void *v;
00086         char *save = str;
00087         const char *cp;
00088         const char *head;
00089         int count = 0;
00090         int pad;
00091         int zeropad;
00092         int dot;
00093         double dbl;
00094 #ifdef HAVE_LONG_DOUBLE
00095         long double ldbl;
00096 #endif
00097         char fmt[32];
00098 
00099         INSIST(str != NULL);
00100         INSIST(format != NULL);
00101 
00102         while (*format != '\0') {
00103                 if (*format != '%') {
00104                         if (size > 1) {
00105                                 *str++ = *format;
00106                                 size--;
00107                         }
00108                         count++;
00109                         format++;
00110                         continue;
00111                 }
00112                 format++;
00113 
00114                 /*
00115                  * Reset flags.
00116                  */
00117                 dot = neg = space = plus = left = zero = alt = h = l = q = 0;
00118                 width = precision = 0;
00119                 head = "";
00120                 pad = zeropad = 0;
00121 
00122                 do {
00123                         if (*format == '#') {
00124                                 alt = 1;
00125                                 format++;
00126                         } else if (*format == '-') {
00127                                 left = 1;
00128                                 zero = 0;
00129                                 format++;
00130                         } else if (*format == ' ') {
00131                                 if (!plus)
00132                                         space = 1;
00133                                 format++;
00134                         } else if (*format == '+') {
00135                                 plus = 1;
00136                                 space = 0;
00137                                 format++;
00138                         } else if (*format == '0') {
00139                                 if (!left)
00140                                         zero = 1;
00141                                 format++;
00142                         } else
00143                                 break;
00144                 } while (1);
00145 
00146                 /*
00147                  * Width.
00148                  */
00149                 if (*format == '*') {
00150                         width = va_arg(ap, int);
00151                         format++;
00152                 } else if (isdigit((unsigned char)*format)) {
00153                         char *e;
00154                         width = strtoul(format, &e, 10);
00155                         format = e;
00156                 }
00157 
00158                 /*
00159                  * Precision.
00160                  */
00161                 if (*format == '.') {
00162                         format++;
00163                         dot = 1;
00164                         if (*format == '*') {
00165                                 precision = va_arg(ap, int);
00166                                 format++;
00167                         } else if (isdigit((unsigned char)*format)) {
00168                                 char *e;
00169                                 precision = strtoul(format, &e, 10);
00170                                 format = e;
00171                         }
00172                 }
00173 
00174                 switch (*format) {
00175                 case '\0':
00176                         continue;
00177                 case '%':
00178                         if (size > 1) {
00179                                 *str++ = *format;
00180                                 size--;
00181                         }
00182                         count++;
00183                         break;
00184                 case 'q':
00185                         q = 1;
00186                         format++;
00187                         goto doint;
00188                 case 'h':
00189                         h = 1;
00190                         format++;
00191                         goto doint;
00192                 case 'l':
00193                         l = 1;
00194                         format++;
00195                         if (*format == 'l') {
00196                                 q = 1;
00197                                 format++;
00198                         }
00199                         goto doint;
00200                 case 'n':
00201                 case 'i':
00202                 case 'd':
00203                 case 'o':
00204                 case 'u':
00205                 case 'x':
00206                 case 'X':
00207                 doint:
00208                         if (precision != 0)
00209                                 zero = 0;
00210                         switch (*format) {
00211                         case 'n':
00212                                 if (h) {
00213                                         short int *p;
00214                                         p = va_arg(ap, short *);
00215                                         REQUIRE(p != NULL);
00216                                         *p = str - save;
00217                                 } else if (l) {
00218                                         long int *p;
00219                                         p = va_arg(ap, long *);
00220                                         REQUIRE(p != NULL);
00221                                         *p = str - save;
00222                                 } else {
00223                                         int *p;
00224                                         p = va_arg(ap, int *);
00225                                         REQUIRE(p != NULL);
00226                                         *p = str - save;
00227                                 }
00228                                 break;
00229                         case 'i':
00230                         case 'd':
00231                                 if (q)
00232                                         tmpi = va_arg(ap, isc_int64_t);
00233                                 else if (l)
00234                                         tmpi = va_arg(ap, long int);
00235                                 else
00236                                         tmpi = va_arg(ap, int);
00237                                 if (tmpi < 0) {
00238                                         head = "-";
00239                                         tmpui = -tmpi;
00240                                 } else {
00241                                         if (plus)
00242                                                 head = "+";
00243                                         else if (space)
00244                                                 head = " ";
00245                                         else
00246                                                 head = "";
00247                                         tmpui = tmpi;
00248                                 }
00249                                 if (tmpui <= 0xffffffffU)
00250                                         sprintf(buf, "%lu",
00251                                                 (unsigned long)tmpui);
00252                                 else {
00253                                         unsigned long mid;
00254                                         unsigned long lo;
00255                                         unsigned long hi;
00256                                         lo = tmpui % 1000000000;
00257                                         tmpui /= 1000000000;
00258                                         mid = tmpui % 1000000000;
00259                                         hi = tmpui / 1000000000;
00260                                         if (hi != 0)
00261                                                 sprintf(buf, "%lu", hi);
00262                                         else
00263                                                 buf[0] = '\0';
00264                                         sprintf(buf + strlen(buf), "%lu", mid);
00265                                         sprintf(buf + strlen(buf), "%lu", lo);
00266                                 }
00267                                 goto printint;
00268                         case 'o':
00269                                 if (q)
00270                                         tmpui = va_arg(ap, isc_uint64_t);
00271                                 else if (l)
00272                                         tmpui = va_arg(ap, long int);
00273                                 else
00274                                         tmpui = va_arg(ap, int);
00275                                 if (tmpui <= 0xffffffffU)
00276                                         sprintf(buf, alt ?  "%#lo" : "%lo",
00277                                                 (unsigned long)tmpui);
00278                                 else {
00279                                         unsigned long mid;
00280                                         unsigned long lo;
00281                                         unsigned long hi;
00282                                         lo = tmpui % 010000000000;
00283                                         tmpui /= 010000000000;
00284                                         mid = tmpui % 010000000000;
00285                                         hi = tmpui / 010000000000;
00286                                         if (hi != 0) {
00287                                                 sprintf(buf,
00288                                                         alt ?  "%#lo" : "%lo",
00289                                                         hi);
00290                                                 sprintf(buf + strlen(buf),
00291                                                         "%lo", mid);
00292                                         } else
00293                                                 sprintf(buf,
00294                                                         alt ?  "%#lo" : "%lo",
00295                                                         mid);
00296                                         sprintf(buf + strlen(buf), "%lo", lo);
00297                                 }
00298                                 goto printint;
00299                         case 'u':
00300                                 if (q)
00301                                         tmpui = va_arg(ap, isc_uint64_t);
00302                                 else if (l)
00303                                         tmpui = va_arg(ap, unsigned long int);
00304                                 else
00305                                         tmpui = va_arg(ap, unsigned int);
00306                                 if (tmpui <= 0xffffffffU)
00307                                         sprintf(buf, "%lu",
00308                                                 (unsigned long)tmpui);
00309                                 else {
00310                                         unsigned long mid;
00311                                         unsigned long lo;
00312                                         unsigned long hi;
00313                                         lo = tmpui % 1000000000;
00314                                         tmpui /= 1000000000;
00315                                         mid = tmpui % 1000000000;
00316                                         hi = tmpui / 1000000000;
00317                                         if (hi != 0)
00318                                                 sprintf(buf, "%lu", hi);
00319                                         else
00320                                                 buf[0] = '\0';
00321                                         sprintf(buf + strlen(buf), "%lu", mid);
00322                                         sprintf(buf + strlen(buf), "%lu", lo);
00323                                 }
00324                                 goto printint;
00325                         case 'x':
00326                                 if (q)
00327                                         tmpui = va_arg(ap, isc_uint64_t);
00328                                 else if (l)
00329                                         tmpui = va_arg(ap, unsigned long int);
00330                                 else
00331                                         tmpui = va_arg(ap, unsigned int);
00332                                 if (alt) {
00333                                         head = "0x";
00334                                         if (precision > 2)
00335                                                 precision -= 2;
00336                                 }
00337                                 if (tmpui <= 0xffffffffU)
00338                                         sprintf(buf, "%lx",
00339                                                 (unsigned long)tmpui);
00340                                 else {
00341                                         unsigned long hi = tmpui>>32;
00342                                         unsigned long lo = tmpui & 0xffffffff;
00343                                         sprintf(buf, "%lx", hi);
00344                                         sprintf(buf + strlen(buf), "%lx", lo);
00345                                 }
00346                                 goto printint;
00347                         case 'X':
00348                                 if (q)
00349                                         tmpui = va_arg(ap, isc_uint64_t);
00350                                 else if (l)
00351                                         tmpui = va_arg(ap, unsigned long int);
00352                                 else
00353                                         tmpui = va_arg(ap, unsigned int);
00354                                 if (alt) {
00355                                         head = "0X";
00356                                         if (precision > 2)
00357                                                 precision -= 2;
00358                                 }
00359                                 if (tmpui <= 0xffffffffU)
00360                                         sprintf(buf, "%lX",
00361                                                 (unsigned long)tmpui);
00362                                 else  {
00363                                         unsigned long hi = tmpui>>32;
00364                                         unsigned long lo = tmpui & 0xffffffff;
00365                                         sprintf(buf, "%lX", hi);
00366                                         sprintf(buf + strlen(buf), "%lX", lo);
00367                                 }
00368                                 goto printint;
00369                         printint:
00370                                 if (precision != 0 || width != 0) {
00371                                         length = strlen(buf);
00372                                         if (length < precision)
00373                                                 zeropad = precision - length;
00374                                         else if (length < width && zero)
00375                                                 zeropad = width - length;
00376                                         if (width != 0) {
00377                                                 pad = width - length -
00378                                                       zeropad - strlen(head);
00379                                                 if (pad < 0)
00380                                                         pad = 0;
00381                                         }
00382                                 }
00383                                 count += strlen(head) + strlen(buf) + pad +
00384                                          zeropad;
00385                                 if (!left) {
00386                                         while (pad > 0 && size > 1) {
00387                                                 *str++ = ' ';
00388                                                 size--;
00389                                                 pad--;
00390                                         }
00391                                 }
00392                                 cp = head;
00393                                 while (*cp != '\0' && size > 1) {
00394                                         *str++ = *cp++;
00395                                         size--;
00396                                 }
00397                                 while (zeropad > 0 && size > 1) {
00398                                         *str++ = '0';
00399                                         size--;
00400                                         zeropad--;
00401                                 }
00402                                 cp = buf;
00403                                 while (*cp != '\0' && size > 1) {
00404                                         *str++ = *cp++;
00405                                         size--;
00406                                 }
00407                                 while (pad > 0 && size > 1) {
00408                                         *str++ = ' ';
00409                                         size--;
00410                                         pad--;
00411                                 }
00412                                 break;
00413                         default:
00414                                 break;
00415                         }
00416                         break;
00417                 case 's':
00418                         cp = va_arg(ap, char *);
00419                         REQUIRE(cp != NULL);
00420 
00421                         if (precision != 0) {
00422                                 /*
00423                                  * cp need not be NULL terminated.
00424                                  */
00425                                 const char *tp;
00426                                 unsigned long n;
00427 
00428                                 n = precision;
00429                                 tp = cp;
00430                                 while (n != 0 && *tp != '\0')
00431                                         n--, tp++;
00432                                 length = precision - n;
00433                         } else {
00434                                 length = strlen(cp);
00435                         }
00436                         if (width != 0) {
00437                                 pad = width - length;
00438                                 if (pad < 0)
00439                                         pad = 0;
00440                         }
00441                         count += pad + length;
00442                         if (!left)
00443                                 while (pad > 0 && size > 1) {
00444                                         *str++ = ' ';
00445                                         size--;
00446                                         pad--;
00447                                 }
00448                         if (precision != 0)
00449                                 while (precision > 0 && *cp != '\0' &&
00450                                        size > 1) {
00451                                         *str++ = *cp++;
00452                                         size--;
00453                                         precision--;
00454                                 }
00455                         else
00456                                 while (*cp != '\0' && size > 1) {
00457                                         *str++ = *cp++;
00458                                         size--;
00459                                 }
00460                         while (pad > 0 && size > 1) {
00461                                 *str++ = ' ';
00462                                 size--;
00463                                 pad--;
00464                         }
00465                         break;
00466                 case 'c':
00467                         c = va_arg(ap, int);
00468                         if (width > 0) {
00469                                 count += width;
00470                                 width--;
00471                                 if (left && size > 1) {
00472                                         *str++ = c;
00473                                         size--;
00474                                 }
00475                                 while (width-- > 0 && size > 1) {
00476                                         *str++ = ' ';
00477                                         size--;
00478                                 }
00479                                 if (!left && size > 1) {
00480                                         *str++ = c;
00481                                         size--;
00482                                 }
00483                         } else {
00484                                 count++;
00485                                 if (size > 1) {
00486                                         *str++ = c;
00487                                         size--;
00488                                 }
00489                         }
00490                         break;
00491                 case 'p':
00492                         v = va_arg(ap, void *);
00493                         sprintf(buf, "%p", v);
00494                         length = strlen(buf);
00495                         if (precision > length)
00496                                 zeropad = precision - length;
00497                         if (width > 0) {
00498                                 pad = width - length - zeropad;
00499                                 if (pad < 0)
00500                                         pad = 0;
00501                         }
00502                         count += length + pad + zeropad;
00503                         if (!left)
00504                                 while (pad > 0 && size > 1) {
00505                                         *str++ = ' ';
00506                                         size--;
00507                                         pad--;
00508                                 }
00509                         cp = buf;
00510                         if (zeropad > 0 && buf[0] == '0' &&
00511                             (buf[1] == 'x' || buf[1] == 'X')) {
00512                                 if (size > 1) {
00513                                         *str++ = *cp++;
00514                                         size--;
00515                                 }
00516                                 if (size > 1) {
00517                                         *str++ = *cp++;
00518                                         size--;
00519                                 }
00520                                 while (zeropad > 0 && size > 1) {
00521                                         *str++ = '0';
00522                                         size--;
00523                                         zeropad--;
00524                                 }
00525                         }
00526                         while (*cp != '\0' && size > 1) {
00527                                 *str++ = *cp++;
00528                                 size--;
00529                         }
00530                         while (pad > 0 && size > 1) {
00531                                 *str++ = ' ';
00532                                 size--;
00533                                 pad--;
00534                         }
00535                         break;
00536                 case 'D':       /*deprecated*/
00537                         INSIST("use %ld instead of %D" == NULL);
00538                 case 'O':       /*deprecated*/
00539                         INSIST("use %lo instead of %O" == NULL);
00540                 case 'U':       /*deprecated*/
00541                         INSIST("use %lu instead of %U" == NULL);
00542 
00543                 case 'L':
00544 #ifdef HAVE_LONG_DOUBLE
00545                         l = 1;
00546 #else
00547                         INSIST("long doubles are not supported" == NULL);
00548 #endif
00549                         /*FALLTHROUGH*/
00550                 case 'e':
00551                 case 'E':
00552                 case 'f':
00553                 case 'g':
00554                 case 'G':
00555                         if (!dot)
00556                                 precision = 6;
00557                         /*
00558                          * IEEE floating point.
00559                          * MIN 2.2250738585072014E-308
00560                          * MAX 1.7976931348623157E+308
00561                          * VAX floating point has a smaller range than IEEE.
00562                          *
00563                          * precisions > 324 don't make much sense.
00564                          * if we cap the precision at 512 we will not
00565                          * overflow buf.
00566                          */
00567                         if (precision > 512)
00568                                 precision = 512;
00569                         sprintf(fmt, "%%%s%s.%lu%s%c", alt ? "#" : "",
00570                                 plus ? "+" : space ? " " : "",
00571                                 precision, l ? "L" : "", *format);
00572                         switch (*format) {
00573                         case 'e':
00574                         case 'E':
00575                         case 'f':
00576                         case 'g':
00577                         case 'G':
00578 #ifdef HAVE_LONG_DOUBLE
00579                                 if (l) {
00580                                         ldbl = va_arg(ap, long double);
00581                                         sprintf(buf, fmt, ldbl);
00582                                 } else
00583 #endif
00584                                 {
00585                                         dbl = va_arg(ap, double);
00586                                         sprintf(buf, fmt, dbl);
00587                                 }
00588                                 length = strlen(buf);
00589                                 if (width > 0) {
00590                                         pad = width - length;
00591                                         if (pad < 0)
00592                                                 pad = 0;
00593                                 }
00594                                 count += length + pad;
00595                                 if (!left)
00596                                         while (pad > 0 && size > 1) {
00597                                                 *str++ = ' ';
00598                                                 size--;
00599                                                 pad--;
00600                                         }
00601                                 cp = buf;
00602                                 while (*cp != ' ' && size > 1) {
00603                                         *str++ = *cp++;
00604                                         size--;
00605                                 }
00606                                 while (pad > 0 && size > 1) {
00607                                         *str++ = ' ';
00608                                         size--;
00609                                         pad--;
00610                                 }
00611                                 break;
00612                         default:
00613                                 continue;
00614                         }
00615                         break;
00616                 default:
00617                         continue;
00618                 }
00619                 format++;
00620         }
00621         if (size > 0)
00622                 *str = '\0';
00623         return (count);
00624 }

Generated on Tue Apr 28 17:41:05 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha