snprintf.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. /*
  2. * Copyright (c) 1983, 1995, 1996 Eric P. Allman
  3. * Copyright (c) 1988, 1993
  4. * The Regents of the University of California. All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. All advertising materials mentioning features or use of this software
  15. * must display the following acknowledgement:
  16. * This product includes software developed by the University of
  17. * California, Berkeley and its contributors.
  18. * 4. Neither the name of the University nor the names of its contributors
  19. * may be used to endorse or promote products derived from this software
  20. * without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32. * SUCH DAMAGE.
  33. */
  34. /* Some changes made by bbraun@synack.net for use with xinetd */
  35. #if !defined(HAVE_SNPRINTF)
  36. /* Extracted from sendmail 8.8.5 */
  37. #ifndef lint
  38. static char sccsid[] = "@(#)$Id$ excerpted from conf.c 8.333 (Berkeley) 1/21/97";
  39. #endif /* not lint */
  40. # ifdef __STDC__
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #ifndef __P
  44. #define __P(p) p
  45. #endif
  46. #include <stdarg.h>
  47. #define VA_LOCAL_DECL va_list ap;
  48. #define VA_START(f) va_start(ap, f)
  49. #define VA_END va_end(ap)
  50. #else
  51. #include <sys/types.h>
  52. #include <stdio.h>
  53. #ifndef __P
  54. #define __P(p) ()
  55. #endif
  56. #include <varargs.h>
  57. #define VA_LOCAL_DECL va_list ap;
  58. #define VA_START(f) va_start(ap)
  59. #define VA_END va_end(ap)
  60. #endif
  61. /*
  62. ** SNPRINTF, VSNPRINT -- counted versions of printf
  63. **
  64. ** These versions have been grabbed off the net. They have been
  65. ** cleaned up to compile properly and support for .precision and
  66. ** %lx has been added.
  67. */
  68. /**************************************************************
  69. * Original:
  70. * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
  71. * A bombproof version of doprnt (dopr) included.
  72. * Sigh. This sort of thing is always nasty do deal with. Note that
  73. * the version here does not include floating point...
  74. *
  75. * snprintf() is used instead of sprintf() as it does limit checks
  76. * for string length. This covers a nasty loophole.
  77. *
  78. * The other functions are there to prevent NULL pointers from
  79. * causing nast effects.
  80. **************************************************************/
  81. /*static char _id[] = "$Id$";*/
  82. static void dopr();
  83. static char *end;
  84. #ifndef _SCO_DS
  85. /* VARARGS3 */
  86. int
  87. # ifdef __STDC__
  88. snprintf(char *str, size_t count, const char *fmt, ...)
  89. # else
  90. snprintf(str, count, fmt, va_alist)
  91. char *str;
  92. size_t count;
  93. char *fmt;
  94. va_dcl
  95. #endif
  96. {
  97. int len;
  98. VA_LOCAL_DECL
  99. VA_START(fmt);
  100. len = vsnprintf(str, count, fmt, ap);
  101. VA_END;
  102. return len;
  103. }
  104. #endif
  105. # ifndef luna2
  106. int
  107. # ifdef __STDC__
  108. vsnprintf(char *str, size_t count, const char *fmt, va_list args)
  109. #else
  110. vsnprintf(str, count, fmt, args)
  111. char *str;
  112. int count;
  113. char *fmt;
  114. va_list args;
  115. #endif
  116. {
  117. str[0] = 0;
  118. end = str + count - 1;
  119. dopr( str, fmt, args );
  120. if (count > 0)
  121. end[0] = 0;
  122. return strlen(str);
  123. }
  124. /*
  125. * dopr(): poor man's version of doprintf
  126. */
  127. static void fmtstr __P((char *value, int ljust, int len, int zpad, int maxwidth));
  128. static void fmtnum __P((long value, int base, int dosign, int ljust, int len, int zpad));
  129. static void dostr __P(( char * , int ));
  130. static char *output;
  131. static void dopr_outch __P(( int c ));
  132. static void
  133. # ifdef __STDC__
  134. dopr(char * buffer, const char * format, va_list args )
  135. #else
  136. dopr( buffer, format, args )
  137. char *buffer;
  138. char *format;
  139. va_list args;
  140. #endif
  141. {
  142. int ch;
  143. long value;
  144. int longflag = 0;
  145. int pointflag = 0;
  146. int maxwidth = 0;
  147. char *strvalue;
  148. int ljust;
  149. int len;
  150. int zpad;
  151. output = buffer;
  152. while( (ch = *format++) ){
  153. switch( ch ){
  154. case '%':
  155. ljust = len = zpad = maxwidth = 0;
  156. longflag = pointflag = 0;
  157. nextch:
  158. ch = *format++;
  159. switch( ch ){
  160. case 0:
  161. dostr( "**end of format**" , 0);
  162. return;
  163. case '-': ljust = 1; goto nextch;
  164. case '0': /* set zero padding if len not set */
  165. if(len==0 && !pointflag) zpad = '0';
  166. case '1': case '2': case '3':
  167. case '4': case '5': case '6':
  168. case '7': case '8': case '9':
  169. if (pointflag)
  170. maxwidth = maxwidth*10 + ch - '0';
  171. else
  172. len = len*10 + ch - '0';
  173. goto nextch;
  174. case '*':
  175. if (pointflag)
  176. maxwidth = va_arg( args, int );
  177. else
  178. len = va_arg( args, int );
  179. goto nextch;
  180. case '.': pointflag = 1; goto nextch;
  181. case 'l': longflag = 1; goto nextch;
  182. case 'u': case 'U':
  183. /*fmtnum(value,base,dosign,ljust,len,zpad) */
  184. if( longflag ){
  185. value = va_arg( args, long );
  186. } else {
  187. value = va_arg( args, int );
  188. }
  189. fmtnum( value, 10,0, ljust, len, zpad ); break;
  190. case 'o': case 'O':
  191. /*fmtnum(value,base,dosign,ljust,len,zpad) */
  192. if( longflag ){
  193. value = va_arg( args, long );
  194. } else {
  195. value = va_arg( args, int );
  196. }
  197. fmtnum( value, 8,0, ljust, len, zpad ); break;
  198. case 'd': case 'D':
  199. if( longflag ){
  200. value = va_arg( args, long );
  201. } else {
  202. value = va_arg( args, int );
  203. }
  204. fmtnum( value, 10,1, ljust, len, zpad ); break;
  205. case 'x':
  206. if( longflag ){
  207. value = va_arg( args, long );
  208. } else {
  209. value = va_arg( args, int );
  210. }
  211. fmtnum( value, 16,0, ljust, len, zpad ); break;
  212. case 'X':
  213. if( longflag ){
  214. value = va_arg( args, long );
  215. } else {
  216. value = va_arg( args, int );
  217. }
  218. fmtnum( value,-16,0, ljust, len, zpad ); break;
  219. case 's':
  220. strvalue = va_arg( args, char *);
  221. if (maxwidth > 0 || !pointflag) {
  222. if (pointflag && len > maxwidth)
  223. len = maxwidth; /* Adjust padding */
  224. fmtstr( strvalue,ljust,len,zpad, maxwidth);
  225. }
  226. break;
  227. case 'c':
  228. ch = va_arg( args, int );
  229. dopr_outch( ch ); break;
  230. case '%': dopr_outch( ch ); continue;
  231. default:
  232. dostr( "???????" , 0);
  233. }
  234. break;
  235. default:
  236. dopr_outch( ch );
  237. break;
  238. }
  239. }
  240. *output = 0;
  241. }
  242. static void
  243. fmtstr( value, ljust, len, zpad, maxwidth )
  244. char *value;
  245. int ljust, len, zpad, maxwidth;
  246. {
  247. int padlen, strlen; /* amount to pad */
  248. if( value == 0 ){
  249. value = "<NULL>";
  250. }
  251. for( strlen = 0; value[strlen]; ++ strlen ); /* strlen */
  252. if (strlen > maxwidth && maxwidth)
  253. strlen = maxwidth;
  254. padlen = len - strlen;
  255. if( padlen < 0 ) padlen = 0;
  256. if( ljust ) padlen = -padlen;
  257. while( padlen > 0 ) {
  258. dopr_outch( ' ' );
  259. --padlen;
  260. }
  261. dostr( value, maxwidth );
  262. while( padlen < 0 ) {
  263. dopr_outch( ' ' );
  264. ++padlen;
  265. }
  266. }
  267. static void
  268. fmtnum( value, base, dosign, ljust, len, zpad )
  269. long value;
  270. int base, dosign, ljust, len, zpad;
  271. {
  272. int signvalue = 0;
  273. unsigned long uvalue;
  274. char convert[20];
  275. int place = 0;
  276. int padlen = 0; /* amount to pad */
  277. int caps = 0;
  278. /* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n",
  279. value, base, dosign, ljust, len, zpad )); */
  280. uvalue = value;
  281. if( dosign ){
  282. if( value < 0 ) {
  283. signvalue = '-';
  284. uvalue = -value;
  285. }
  286. }
  287. if( base < 0 ){
  288. caps = 1;
  289. base = -base;
  290. }
  291. do{
  292. convert[place++] =
  293. (caps? "0123456789ABCDEF":"0123456789abcdef")
  294. [uvalue % (unsigned)base ];
  295. uvalue = (uvalue / (unsigned)base );
  296. }while(uvalue);
  297. convert[place] = 0;
  298. padlen = len - place;
  299. if( padlen < 0 ) padlen = 0;
  300. if( ljust ) padlen = -padlen;
  301. /* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n",
  302. convert,place,signvalue,padlen)); */
  303. if( zpad && padlen > 0 ){
  304. if( signvalue ){
  305. dopr_outch( signvalue );
  306. --padlen;
  307. signvalue = 0;
  308. }
  309. while( padlen > 0 ){
  310. dopr_outch( zpad );
  311. --padlen;
  312. }
  313. }
  314. while( padlen > 0 ) {
  315. dopr_outch( ' ' );
  316. --padlen;
  317. }
  318. if( signvalue ) dopr_outch( signvalue );
  319. while( place > 0 ) dopr_outch( convert[--place] );
  320. while( padlen < 0 ){
  321. dopr_outch( ' ' );
  322. ++padlen;
  323. }
  324. }
  325. static void
  326. dostr( str , cut)
  327. char *str;
  328. int cut;
  329. {
  330. if (cut) {
  331. while(*str && cut-- > 0) dopr_outch(*str++);
  332. } else {
  333. while(*str) dopr_outch(*str++);
  334. }
  335. }
  336. static void
  337. dopr_outch( c )
  338. int c;
  339. {
  340. #if 0
  341. if( iscntrl(c) && c != '\n' && c != '\t' ){
  342. c = '@' + (c & 0x1F);
  343. if( end == 0 || output < end )
  344. *output++ = '^';
  345. }
  346. #endif
  347. if( end == 0 || output < end )
  348. *output++ = c;
  349. }
  350. # endif /* !luna2 */
  351. #endif /* HAVE_SNPRINTF */