aRts audio server
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

debug.cc 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  1. /*
  2. Copyright (C) 2000-2002 Stefan Westerfeld
  3. stefan@space.twc.de
  4. (see also below for details on the copyright of arts_strdup_printf,
  5. which is taken from GLib)
  6. This library is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU Library General Public
  8. License as published by the Free Software Foundation; either
  9. version 2 of the License, or (at your option) any later version.
  10. This library is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. Library General Public License for more details.
  14. You should have received a copy of the GNU Library General Public License
  15. along with this library; see the file COPYING.LIB. If not, write to
  16. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  17. Boston, MA 02110-1301, USA.
  18. */
  19. #include "debug.h"
  20. #include <config.h>
  21. #include <stdlib.h>
  22. #include <stdarg.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include "thread.h"
  26. static int arts_debug_level = Arts::Debug::lInfo;
  27. static bool arts_debug_abort = false;
  28. static const char *arts_debug_prefix = "";
  29. static char *messageAppName = 0;
  30. static Arts::Mutex *arts_debug_mutex = 0;
  31. /* routines for variable length sprintf without buffer overflow (from GLib) */
  32. static char* arts_strdup_vprintf(const char *format, va_list args1);
  33. namespace Arts {
  34. static char * shell_quote(const char *s)
  35. {
  36. char *result;
  37. char *p;
  38. p = result = static_cast<char*>( malloc(strlen(s)*5+1) );
  39. while(*s)
  40. {
  41. if (*s == '\'')
  42. {
  43. *p++ = '\'';
  44. *p++ = '"';
  45. *p++ = *s++;
  46. *p++ = '"';
  47. *p++ = '\'';
  48. }
  49. else
  50. {
  51. *p++ = *s++;
  52. }
  53. }
  54. *p = '\0';
  55. return result;
  56. }
  57. /*
  58. * Call the graphical application to display a message, if
  59. * defined. Otherwise, send to standard error. Debug messages are
  60. * always sent to standard error because they tend to be very verbose.
  61. * Note that the external application is run in the background to
  62. * avoid blocking the sound server.
  63. */
  64. static void output_message(Debug::Level level, const char *msg) {
  65. char *quoted_msg;
  66. char *buff = 0;
  67. /* default to text output if no message app is defined or if it is a debug message. */
  68. if (messageAppName == 0 || !strcmp(messageAppName, "") || (level == Debug::lDebug))
  69. {
  70. fprintf(stderr, "%s\n", msg);
  71. return;
  72. }
  73. quoted_msg = shell_quote(msg);
  74. switch (level) {
  75. case Debug::lFatal:
  76. buff = arts_strdup_printf("%s -e 'Sound server fatal error:\n\n%s' &", messageAppName, quoted_msg);
  77. break;
  78. case Debug::lWarning:
  79. buff = arts_strdup_printf("%s -w 'Sound server warning message:\n\n%s' &", messageAppName, quoted_msg);
  80. break;
  81. case Debug::lInfo:
  82. buff = arts_strdup_printf("%s -i 'Sound server informational message:\n\n%s' &", messageAppName, quoted_msg);
  83. break;
  84. default:
  85. break; // avoid compile warning
  86. }
  87. free(quoted_msg);
  88. if(buff != 0)
  89. {
  90. system(buff);
  91. free(buff);
  92. }
  93. }
  94. /*
  95. * Display a message using output_message. If the message is the same
  96. * as the previous one, just increment a count but don't display
  97. * it. This prevents flooding the user with duplicate warnings. If the
  98. * message is not the same as the previous one, then we report the
  99. * previously repeated message (if any) and reset the last message and
  100. * count.
  101. */
  102. static void display_message(Debug::Level level, const char *msg) {
  103. static char lastMsg[1024];
  104. static Debug::Level lastLevel;
  105. static int msgCount = 0;
  106. if(arts_debug_mutex)
  107. arts_debug_mutex->lock();
  108. if (!strncmp(msg, lastMsg, 1024))
  109. {
  110. msgCount++;
  111. } else {
  112. if (msgCount > 0)
  113. {
  114. char *buff;
  115. buff = arts_strdup_printf("%s\n(The previous message was repeated %d times.)", lastMsg, msgCount);
  116. output_message(lastLevel, buff);
  117. free(buff);
  118. }
  119. strncpy(lastMsg, msg, 1024);
  120. lastMsg[ 1023 ] = '\0';
  121. lastLevel = level;
  122. msgCount = 0;
  123. output_message(level, msg);
  124. }
  125. if(arts_debug_mutex)
  126. arts_debug_mutex->unlock();
  127. }
  128. static class DebugInitFromEnv {
  129. public:
  130. DebugInitFromEnv() {
  131. const char *env = getenv("ARTS_DEBUG");
  132. if(env)
  133. {
  134. if(strcmp(env,"debug") == 0)
  135. arts_debug_level = Debug::lDebug;
  136. else if(strcmp(env,"info") == 0)
  137. arts_debug_level = Debug::lInfo;
  138. else if(strcmp(env,"warning") == 0)
  139. arts_debug_level = Debug::lWarning;
  140. else if(strcmp(env,"quiet") == 0)
  141. arts_debug_level = Debug::lFatal;
  142. else
  143. {
  144. fprintf(stderr,
  145. "ARTS_DEBUG must be one of debug,info,warning,quiet\n");
  146. }
  147. }
  148. env = getenv("ARTS_DEBUG_ABORT");
  149. if(env)
  150. arts_debug_abort = true;
  151. }
  152. } debugInitFromEnv;
  153. }
  154. void Arts::Debug::init(const char *prefix, Level level)
  155. {
  156. arts_debug_level = level;
  157. arts_debug_prefix = prefix;
  158. }
  159. void Arts::Debug::fatal(const char *fmt, ...)
  160. {
  161. char *buff;
  162. va_list ap;
  163. va_start(ap, fmt);
  164. buff = arts_strdup_vprintf(fmt, ap);
  165. va_end(ap);
  166. display_message(Debug::lFatal, buff);
  167. free(buff);
  168. if(arts_debug_abort) abort();
  169. exit(1);
  170. }
  171. void Arts::Debug::warning(const char *fmt, ...)
  172. {
  173. if(lWarning >= arts_debug_level)
  174. {
  175. char *buff;
  176. va_list ap;
  177. va_start(ap, fmt);
  178. buff = arts_strdup_vprintf(fmt, ap);
  179. va_end(ap);
  180. display_message(Debug::lWarning, buff);
  181. free(buff);
  182. }
  183. }
  184. void Arts::Debug::info(const char *fmt, ...)
  185. {
  186. if(lInfo >= arts_debug_level)
  187. {
  188. char *buff;
  189. va_list ap;
  190. va_start(ap, fmt);
  191. buff = arts_strdup_vprintf(fmt, ap);
  192. va_end(ap);
  193. display_message(Debug::lInfo, buff);
  194. free(buff);
  195. }
  196. }
  197. void Arts::Debug::debug(const char *fmt, ...)
  198. {
  199. if(lDebug >= arts_debug_level)
  200. {
  201. char *buff;
  202. va_list ap;
  203. va_start(ap, fmt);
  204. buff = arts_strdup_vprintf(fmt, ap);
  205. va_end(ap);
  206. display_message(Debug::lDebug, buff);
  207. free(buff);
  208. }
  209. }
  210. void Arts::Debug::messageApp(const char *appName)
  211. {
  212. messageAppName = (char*) realloc(messageAppName, strlen(appName)+1);
  213. strcpy(messageAppName, appName);
  214. }
  215. void Arts::Debug::initMutex()
  216. {
  217. arts_return_if_fail(arts_debug_mutex == 0);
  218. arts_debug_mutex = new Arts::Mutex();
  219. }
  220. void Arts::Debug::freeMutex()
  221. {
  222. arts_return_if_fail(arts_debug_mutex != 0);
  223. delete arts_debug_mutex;
  224. arts_debug_mutex = 0;
  225. }
  226. /*
  227. * For the sake of portability (snprintf is non-portable), what follows is an
  228. * implementation of a variant g_strdup_printf, to format debug messages of
  229. * an arbitary length appropriately. This is reduntant with flow/gsl/gslglib.c,
  230. * however, as libmcop doesn't necessarily link against gslglib.c, this is a
  231. * more-or-less complete copy.
  232. */
  233. /* GLIB - Library of useful routines for C programming
  234. * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
  235. *
  236. * GScanner: Flexible lexical scanner for general purpose.
  237. * Copyright (C) 1997, 1998 Tim Janik
  238. *
  239. * This library is free software; you can redistribute it and/or
  240. * modify it under the terms of the GNU Lesser General Public
  241. * License as published by the Free Software Foundation; either
  242. * version 2 of the License, or (at your option) any later version.
  243. *
  244. * This library is distributed in the hope that it will be useful,
  245. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  246. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  247. * Lesser General Public License for more details.
  248. *
  249. * You should have received a copy of the GNU Lesser General Public
  250. * License along with this library; if not, write to the
  251. * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  252. * Boston, MA 02110-1301, USA.
  253. */
  254. /*
  255. * Modified by the GLib Team and others 1997-2000. See the AUTHORS
  256. * file for a list of people on the GLib Team. See the ChangeLog
  257. * files for a list of changes. These files are distributed with
  258. * GLib at ftp://ftp.gtk.org/pub/gtk/.
  259. */
  260. #include <sys/types.h>
  261. #include <stdarg.h>
  262. #include <string.h>
  263. #define g_warning printf
  264. #define g_strerror strerror
  265. /*--- gslglib.h ---*/
  266. #include <limits.h>
  267. #include <float.h>
  268. #include <stddef.h>
  269. #include <stdarg.h>
  270. /* --- GLib typedefs --- */
  271. typedef void* gpointer;
  272. typedef const void* gconstpointer;
  273. typedef char gchar;
  274. typedef unsigned char guchar;
  275. typedef signed short gshort;
  276. typedef unsigned short gushort;
  277. typedef signed int gint;
  278. typedef unsigned int guint;
  279. typedef signed long glong;
  280. typedef unsigned long gulong;
  281. typedef float gfloat;
  282. typedef double gdouble;
  283. typedef size_t gsize;
  284. typedef gchar gint8;
  285. typedef guchar guint8;
  286. typedef gshort gint16;
  287. typedef gushort guint16;
  288. typedef gint gint32;
  289. typedef guint guint32;
  290. typedef gint gboolean;
  291. typedef gint32 GTime;
  292. #ifdef __alpha
  293. typedef long int gint64;
  294. typedef unsigned long int guint64;
  295. #else
  296. typedef long long int gint64;
  297. typedef unsigned long long int guint64;
  298. #endif
  299. typedef struct _GString GString;
  300. /* --- standard macros --- */
  301. #ifndef ABS
  302. #define ABS(a) ((a) > 0 ? (a) : -(a))
  303. #endif
  304. #ifndef MAX
  305. #define MAX(a,b) ((a) > (b) ? (a) : (b))
  306. #endif
  307. #ifndef MIN
  308. #define MIN(a,b) ((a) < (b) ? (a) : (b))
  309. #endif
  310. #ifndef CLAMP
  311. #define CLAMP(v,l,h) ((v) < (l) ? (l) : (v) > (h) ? (h) : (v))
  312. #endif
  313. #ifndef FALSE
  314. #define FALSE 0
  315. #endif
  316. #ifndef TRUE
  317. #define TRUE (!FALSE)
  318. #endif
  319. #ifndef NULL
  320. #define NULL ((void*) 0)
  321. #endif
  322. /* --- configure stuff!!! --- */
  323. #ifdef WORDS_BIGENDIAN
  324. #define G_BYTE_ORDER G_BIG_ENDIAN
  325. #else
  326. #define G_BYTE_ORDER G_LITTLE_ENDIAN
  327. #endif
  328. /* #define GLIB_HAVE_STPCPY 1 */
  329. /* Define G_VA_COPY() to do the right thing for copying va_list variables.
  330. * glibconfig.h may have already defined G_VA_COPY as va_copy or __va_copy.
  331. */
  332. #if !defined (G_VA_COPY)
  333. # if defined (__GNUC__) && defined (__PPC__) && (defined (_CALL_SYSV) || defined (_WIN32) || defined(WIN32)) || defined(__s390__) || defined(__x86_64__)
  334. # define G_VA_COPY(ap1, ap2) (*(ap1) = *(ap2))
  335. # elif defined (G_VA_COPY_AS_ARRAY)
  336. # define G_VA_COPY(ap1, ap2) g_memmove ((ap1), (ap2), sizeof (va_list))
  337. # else /* va_list is a pointer */
  338. # define G_VA_COPY(ap1, ap2) ((ap1) = (ap2))
  339. # endif /* va_list is a pointer */
  340. #endif /* !G_VA_COPY */
  341. /* --- glib macros --- */
  342. #define G_MINFLOAT FLT_MIN
  343. #define G_MAXFLOAT FLT_MAX
  344. #define G_MINDOUBLE DBL_MIN
  345. #define G_MAXDOUBLE DBL_MAX
  346. #define G_MINSHORT SHRT_MIN
  347. #define G_MAXSHORT SHRT_MAX
  348. #define G_MAXUSHORT USHRT_MAX
  349. #define G_MININT INT_MIN
  350. #define G_MAXINT INT_MAX
  351. #define G_MAXUINT UINT_MAX
  352. #define G_MINLONG LONG_MIN
  353. #define G_MAXLONG LONG_MAX
  354. #define G_MAXULONG ULONG_MAX
  355. #define G_USEC_PER_SEC 1000000
  356. #define G_LITTLE_ENDIAN 1234
  357. #define G_BIG_ENDIAN 4321
  358. #define G_STRINGIFY(macro_or_string) G_STRINGIFY_ARG (macro_or_string)
  359. #define G_STRINGIFY_ARG(contents) #contents
  360. #if defined __GNUC__ && !defined __cplusplus
  361. # define G_STRLOC __FILE__ ":" G_STRINGIFY (__LINE__) ":" __PRETTY_FUNCTION__ "()"
  362. #else
  363. # define G_STRLOC __FILE__ ":" G_STRINGIFY (__LINE__)
  364. #endif
  365. /* subtract from biased_exponent to form base2 exponent (normal numbers) */
  366. typedef union _GDoubleIEEE754 GDoubleIEEE754;
  367. typedef union _GFloatIEEE754 GFloatIEEE754;
  368. #define G_IEEE754_FLOAT_BIAS (127)
  369. #define G_IEEE754_DOUBLE_BIAS (1023)
  370. /* multiply with base2 exponent to get base10 exponent (nomal numbers) */
  371. #define G_LOG_2_BASE_10 (0.30102999566398119521)
  372. #if G_BYTE_ORDER == G_LITTLE_ENDIAN
  373. union _GFloatIEEE754
  374. {
  375. gfloat v_float;
  376. struct {
  377. guint mantissa : 23;
  378. guint biased_exponent : 8;
  379. guint sign : 1;
  380. } mpn;
  381. };
  382. union _GDoubleIEEE754
  383. {
  384. gdouble v_double;
  385. struct {
  386. guint mantissa_low : 32;
  387. guint mantissa_high : 20;
  388. guint biased_exponent : 11;
  389. guint sign : 1;
  390. } mpn;
  391. };
  392. #elif G_BYTE_ORDER == G_BIG_ENDIAN
  393. union _GFloatIEEE754
  394. {
  395. gfloat v_float;
  396. struct {
  397. guint sign : 1;
  398. guint biased_exponent : 8;
  399. guint mantissa : 23;
  400. } mpn;
  401. };
  402. union _GDoubleIEEE754
  403. {
  404. gdouble v_double;
  405. struct {
  406. guint sign : 1;
  407. guint biased_exponent : 11;
  408. guint mantissa_high : 20;
  409. guint mantissa_low : 32;
  410. } mpn;
  411. };
  412. #else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
  413. #error unknown ENDIAN type
  414. #endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
  415. #include <errno.h>
  416. #include <stdlib.h>
  417. #include <unistd.h>
  418. #include <stdio.h>
  419. #define GLIB_SIZEOF_INTMAX (8 /* educated guess */)
  420. typedef struct
  421. {
  422. guint min_width;
  423. guint precision;
  424. gboolean alternate_format, zero_padding, adjust_left, locale_grouping;
  425. gboolean add_space, add_sign, possible_sign, seen_precision;
  426. gboolean mod_half, mod_long, mod_extra_long;
  427. } PrintfArgSpec;
  428. static gsize
  429. printf_string_upper_bound (const gchar *format,
  430. gboolean may_warn,
  431. va_list args)
  432. {
  433. static gboolean honour_longs = sizeof(long) > 4 || sizeof(void*) > 4;
  434. gsize len = 1;
  435. if (!format)
  436. return len;
  437. while (*format)
  438. {
  439. register gchar c = *format++;
  440. if (c != '%')
  441. len += 1;
  442. else /* (c == '%') */
  443. {
  444. PrintfArgSpec spec = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  445. gboolean seen_l = FALSE, conv_done = FALSE;
  446. gsize conv_len = 0;
  447. const gchar *spec_start = format;
  448. do
  449. {
  450. c = *format++;
  451. switch (c)
  452. {
  453. GDoubleIEEE754 u_double;
  454. guint v_uint;
  455. gint v_int;
  456. const gchar *v_string;
  457. /* beware of positional parameters
  458. */
  459. case '$':
  460. if (may_warn)
  461. g_warning (G_STRLOC ": unable to handle positional parameters (%%n$)");
  462. len += 1024; /* try adding some safety padding */
  463. break;
  464. /* parse flags
  465. */
  466. case '#':
  467. spec.alternate_format = TRUE;
  468. break;
  469. case '0':
  470. spec.zero_padding = TRUE;
  471. break;
  472. case '-':
  473. spec.adjust_left = TRUE;
  474. break;
  475. case ' ':
  476. spec.add_space = TRUE;
  477. break;
  478. case '+':
  479. spec.add_sign = TRUE;
  480. break;
  481. case '\'':
  482. spec.locale_grouping = TRUE;
  483. break;
  484. /* parse output size specifications
  485. */
  486. case '.':
  487. spec.seen_precision = TRUE;
  488. break;
  489. case '1':
  490. case '2':
  491. case '3':
  492. case '4':
  493. case '5':
  494. case '6':
  495. case '7':
  496. case '8':
  497. case '9':
  498. v_uint = c - '0';
  499. c = *format;
  500. while (c >= '0' && c <= '9')
  501. {
  502. format++;
  503. v_uint = v_uint * 10 + c - '0';
  504. c = *format;
  505. }
  506. if (spec.seen_precision)
  507. spec.precision = MAX (spec.precision, v_uint);
  508. else
  509. spec.min_width = MAX (spec.min_width, v_uint);
  510. break;
  511. case '*':
  512. v_int = va_arg (args, int);
  513. if (spec.seen_precision)
  514. {
  515. /* forget about negative precision */
  516. if (v_int >= 0)
  517. spec.precision = MAX (spec.precision, (unsigned)v_int);
  518. }
  519. else
  520. {
  521. if (v_int < 0)
  522. {
  523. v_int = - v_int;
  524. spec.adjust_left = TRUE;
  525. }
  526. spec.min_width = MAX (spec.min_width, (unsigned)v_int);
  527. }
  528. break;
  529. /* parse type modifiers
  530. */
  531. case 'h':
  532. spec.mod_half = TRUE;
  533. break;
  534. case 'l':
  535. if (!seen_l)
  536. {
  537. spec.mod_long = TRUE;
  538. seen_l = TRUE;
  539. break;
  540. }
  541. /* else, fall through */
  542. case 'L':
  543. case 'q':
  544. spec.mod_long = TRUE;
  545. spec.mod_extra_long = TRUE;
  546. break;
  547. case 'z':
  548. case 'Z':
  549. if (sizeof(size_t))
  550. {
  551. spec.mod_long = TRUE;
  552. spec.mod_extra_long = TRUE;
  553. }
  554. break;
  555. case 't':
  556. if (sizeof(ptrdiff_t) > 4)
  557. {
  558. spec.mod_long = TRUE;
  559. spec.mod_extra_long = TRUE;
  560. }
  561. break;
  562. case 'j':
  563. if (GLIB_SIZEOF_INTMAX > 4)
  564. {
  565. spec.mod_long = TRUE;
  566. spec.mod_extra_long = TRUE;
  567. }
  568. break;
  569. /* parse output conversions
  570. */
  571. case '%':
  572. conv_len += 1;
  573. break;
  574. case 'O':
  575. case 'D':
  576. case 'I':
  577. case 'U':
  578. /* some C libraries feature long variants for these as well? */
  579. spec.mod_long = TRUE;
  580. /* fall through */
  581. case 'o':
  582. conv_len += 2;
  583. /* fall through */
  584. case 'd':
  585. case 'i':
  586. conv_len += 1; /* sign */
  587. /* fall through */
  588. case 'u':
  589. conv_len += 4;
  590. /* fall through */
  591. case 'x':
  592. case 'X':
  593. spec.possible_sign = TRUE;
  594. conv_len += 10;
  595. if (spec.mod_long && honour_longs)
  596. conv_len *= 2;
  597. if (spec.mod_extra_long)
  598. conv_len *= 2;
  599. if (spec.mod_extra_long)
  600. {
  601. (void) va_arg (args, gint64);
  602. }
  603. else if (spec.mod_long)
  604. (void) va_arg (args, long);
  605. else
  606. (void) va_arg (args, int);
  607. break;
  608. case 'A':
  609. case 'a':
  610. /* 0x */
  611. conv_len += 2;
  612. /* fall through */
  613. case 'g':
  614. case 'G':
  615. case 'e':
  616. case 'E':
  617. case 'f':
  618. spec.possible_sign = TRUE;
  619. /* n . dddddddddddddddddddddddd E +- eeee */
  620. conv_len += 1 + 1 + MAX (24, spec.precision) + 1 + 1 + 4;
  621. if (may_warn && spec.mod_extra_long)
  622. g_warning (G_STRLOC ": unable to handle long double, collecting double only");
  623. #ifdef HAVE_LONG_DOUBLE
  624. #error need to implement special handling for long double
  625. #endif
  626. u_double.v_double = va_arg (args, double);
  627. /* %f can expand up to all significant digits before '.' (308) */
  628. if (c == 'f' &&
  629. u_double.mpn.biased_exponent > 0 && u_double.mpn.biased_exponent < 2047)
  630. {
  631. gint exp = u_double.mpn.biased_exponent;
  632. exp -= G_IEEE754_DOUBLE_BIAS;
  633. exp = (gint)(exp * G_LOG_2_BASE_10 + 1);
  634. conv_len += ABS (exp); /* exp can be <0 */
  635. }
  636. /* some printf() implementations require extra padding for rounding */
  637. conv_len += 2;
  638. /* we can't really handle locale specific grouping here */
  639. if (spec.locale_grouping)
  640. conv_len *= 2;
  641. break;
  642. case 'C':
  643. spec.mod_long = TRUE;
  644. /* fall through */
  645. case 'c':
  646. conv_len += spec.mod_long ? MB_LEN_MAX : 1;
  647. (void) va_arg (args, int);
  648. break;
  649. case 'S':
  650. spec.mod_long = TRUE;
  651. /* fall through */
  652. case 's':
  653. v_string = va_arg (args, char*);
  654. if (!v_string)
  655. conv_len += 8; /* hold "(null)" */
  656. else if (spec.seen_precision)
  657. conv_len += spec.precision;
  658. else
  659. conv_len += strlen (v_string);
  660. conv_done = TRUE;
  661. if (spec.mod_long)
  662. {
  663. if (may_warn)
  664. g_warning (G_STRLOC": unable to handle wide char strings");
  665. len += 1024; /* try adding some safety padding */
  666. }
  667. break;
  668. case 'P': /* do we actually need this? */
  669. /* fall through */
  670. case 'p':
  671. spec.alternate_format = TRUE;
  672. conv_len += 10;
  673. if (honour_longs)
  674. conv_len *= 2;
  675. /* fall through */
  676. case 'n':
  677. conv_done = TRUE;
  678. (void) va_arg (args, void*);
  679. break;
  680. case 'm':
  681. /* there's not much we can do to be clever */
  682. v_string = g_strerror (errno);
  683. v_uint = v_string ? strlen (v_string) : 0;
  684. conv_len += MAX (256, v_uint);
  685. break;
  686. /* handle invalid cases
  687. */
  688. case '\000':
  689. /* no conversion specification, bad bad */
  690. conv_len += format - spec_start;
  691. break;
  692. default:
  693. if (may_warn)
  694. g_warning (G_STRLOC": unable to handle `%c' while parsing format",
  695. c);
  696. break;
  697. }
  698. conv_done |= conv_len > 0;
  699. }
  700. while (!conv_done);
  701. /* handle width specifications */
  702. conv_len = MAX (conv_len, MAX (spec.precision, spec.min_width));
  703. /* handle flags */
  704. conv_len += spec.alternate_format ? 2 : 0;
  705. conv_len += (spec.add_space || spec.add_sign || spec.possible_sign);
  706. /* finally done */
  707. len += conv_len;
  708. } /* else (c == '%') */
  709. } /* while (*format) */
  710. return len;
  711. }
  712. static char*
  713. #ifdef __GNUC__
  714. __attribute__ ( (format (printf, 1, 0) ) )
  715. #endif
  716. arts_strdup_vprintf (const char *format, va_list args1)
  717. {
  718. gchar *buffer;
  719. #ifdef HAVE_VASPRINTF
  720. if (vasprintf (&buffer, format, args1) < 0)
  721. buffer = NULL;
  722. #else
  723. va_list args2;
  724. G_VA_COPY (args2, args1);
  725. buffer = (gchar *)malloc (printf_string_upper_bound (format, TRUE, args1));
  726. vsprintf (buffer, format, args2);
  727. va_end (args2);
  728. #endif
  729. return buffer;
  730. }
  731. char*
  732. #ifdef __GNUC__
  733. __attribute__ ( (format (printf, 1, 0) ) )
  734. #endif
  735. arts_strdup_printf (const char *format, ...)
  736. {
  737. gchar *buffer;
  738. va_list args;
  739. va_start (args, format);
  740. buffer = arts_strdup_vprintf (format, args);
  741. va_end (args);
  742. return buffer;
  743. }