melder_ftoa.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. /* melder_ftoa.cpp
  2. *
  3. * Copyright (C) 1992-2008,2010-2012,2014-2018 Paul Boersma
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. * See the GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "melder.h"
  19. /********** NUMBER TO STRING CONVERSION **********/
  20. #define NUMBER_OF_BUFFERS 32
  21. /* = maximum number of arguments to a function call */
  22. #define MAXIMUM_NUMERIC_STRING_LENGTH 800
  23. /* = sign + 324 + point + 60 + e + sign + 3 + null byte + ("·10^^" - "e"), times 2, + i, + 7 extra */
  24. static char buffers8 [NUMBER_OF_BUFFERS] [MAXIMUM_NUMERIC_STRING_LENGTH + 1];
  25. static char32 buffers32 [NUMBER_OF_BUFFERS] [MAXIMUM_NUMERIC_STRING_LENGTH + 1];
  26. static int ibuffer = 0;
  27. #define CONVERT_BUFFER_TO_CHAR32 \
  28. char32 *q = buffers32 [ibuffer]; \
  29. while (*p != '\0') \
  30. * q ++ = (char32) (char8) * p ++; /* change sign before extending (should be unnecessary, because all characters should be below 128) */ \
  31. *q = U'\0'; \
  32. return buffers32 [ibuffer];
  33. const char * Melder8_integer (int64 value) noexcept {
  34. if (++ ibuffer == NUMBER_OF_BUFFERS)
  35. ibuffer = 0;
  36. if (sizeof (long_not_integer) == 8) {
  37. int n = snprintf (buffers8 [ibuffer], MAXIMUM_NUMERIC_STRING_LENGTH + 1, "%ld", (long_not_integer) value); // cast to identical type, to make compiler happy
  38. Melder_assert (n > 0);
  39. Melder_assert (n <= MAXIMUM_NUMERIC_STRING_LENGTH);
  40. } else if (sizeof (long long) == 8) {
  41. /*
  42. * There are buggy platforms (namely 32-bit Mingw on Windows XP) that support long long and %lld but that convert
  43. * the argument to a 32-bit long.
  44. * There are also buggy platforms (namely 32-bit gcc on Linux) that support long long and %I64d but that convert
  45. * the argument to a 32-bit long.
  46. */
  47. static const char *formatString = nullptr;
  48. if (! formatString) {
  49. char tryBuffer [MAXIMUM_NUMERIC_STRING_LENGTH + 1];
  50. formatString = "%lld";
  51. sprintf (tryBuffer, formatString, 1000000000000LL);
  52. if (! strequ (tryBuffer, "1000000000000")) {
  53. formatString = "%I64d";
  54. sprintf (tryBuffer, formatString, 1000000000000LL);
  55. if (! strequ (tryBuffer, "1000000000000"))
  56. Melder_fatal (U"Found no way to print 64-bit integers on this machine.");
  57. }
  58. }
  59. int n = snprintf (buffers8 [ibuffer], MAXIMUM_NUMERIC_STRING_LENGTH + 1, formatString, value);
  60. Melder_assert (n > 0);
  61. Melder_assert (n <= MAXIMUM_NUMERIC_STRING_LENGTH);
  62. } else {
  63. Melder_fatal (U"Neither long nor long long is 8 bytes on this machine.");
  64. }
  65. return buffers8 [ibuffer];
  66. }
  67. conststring32 Melder_integer (int64 value) noexcept {
  68. const char *p = Melder8_integer (value);
  69. CONVERT_BUFFER_TO_CHAR32
  70. }
  71. const char * Melder8_bigInteger (int64 value) noexcept {
  72. if (++ ibuffer == NUMBER_OF_BUFFERS)
  73. ibuffer = 0;
  74. char *text = buffers8 [ibuffer];
  75. text [0] = '\0';
  76. if (value < 0) {
  77. sprintf (text, "-");
  78. value = - value;
  79. }
  80. int quintillions = value / 1000000000000000000LL;
  81. value -= quintillions * 1000000000000000000LL;
  82. int quadrillions = value / 1000000000000000LL;
  83. value -= quadrillions * 1000000000000000LL;
  84. int trillions = value / 1000000000000LL;
  85. value -= trillions * 1000000000000LL;
  86. int billions = value / 1000000000LL;
  87. value -= billions * 1000000000LL;
  88. int millions = value / 1000000LL;
  89. value -= millions * 1000000LL;
  90. int thousands = value / 1000LL;
  91. value -= thousands * 1000LL;
  92. int units = value;
  93. bool firstDigitPrinted = false;
  94. if (quintillions) {
  95. sprintf (text + strlen (text), firstDigitPrinted ? "%03d," : "%d,", quintillions);
  96. firstDigitPrinted = true;
  97. }
  98. if (quadrillions || firstDigitPrinted) {
  99. sprintf (text + strlen (text), firstDigitPrinted ? "%03d," : "%d,", quadrillions);
  100. firstDigitPrinted = true;
  101. }
  102. if (trillions || firstDigitPrinted) {
  103. sprintf (text + strlen (text), firstDigitPrinted ? "%03d," : "%d,", trillions);
  104. firstDigitPrinted = true;
  105. }
  106. if (billions || firstDigitPrinted) {
  107. sprintf (text + strlen (text), firstDigitPrinted ? "%03d," : "%d,", billions);
  108. firstDigitPrinted = true;
  109. }
  110. if (millions || firstDigitPrinted) {
  111. sprintf (text + strlen (text), firstDigitPrinted ? "%03d," : "%d,", millions);
  112. firstDigitPrinted = true;
  113. }
  114. if (thousands || firstDigitPrinted) {
  115. sprintf (text + strlen (text), firstDigitPrinted ? "%03d," : "%d,", thousands);
  116. firstDigitPrinted = true;
  117. }
  118. sprintf (text + strlen (text), firstDigitPrinted ? "%03d" : "%d", units);
  119. return text;
  120. }
  121. conststring32 Melder_bigInteger (int64 value) noexcept {
  122. const char *p = Melder8_bigInteger (value);
  123. CONVERT_BUFFER_TO_CHAR32
  124. }
  125. const char * Melder8_boolean (bool value) noexcept {
  126. return value ? "yes" : "no";
  127. }
  128. conststring32 Melder_boolean (bool value) noexcept {
  129. return value ? U"yes" : U"no";
  130. }
  131. /*@praat
  132. assert string$ (1000000000000) = "1000000000000"
  133. assert string$ (undefined) = "--undefined--"
  134. @*/
  135. const char * Melder8_double (double value) noexcept {
  136. if (isundef (value))
  137. return "--undefined--";
  138. if (++ ibuffer == NUMBER_OF_BUFFERS)
  139. ibuffer = 0;
  140. sprintf (buffers8 [ibuffer], "%.15g", value);
  141. if (strtod (buffers8 [ibuffer], nullptr) != value) {
  142. sprintf (buffers8 [ibuffer], "%.16g", value);
  143. if (strtod (buffers8 [ibuffer], nullptr) != value)
  144. sprintf (buffers8 [ibuffer], "%.17g", value);
  145. }
  146. return buffers8 [ibuffer];
  147. }
  148. conststring32 Melder_double (double value) noexcept {
  149. const char *p = Melder8_double (value);
  150. CONVERT_BUFFER_TO_CHAR32
  151. }
  152. const char * Melder8_single (double value) noexcept {
  153. if (isundef (value)) return "--undefined--";
  154. if (++ ibuffer == NUMBER_OF_BUFFERS) ibuffer = 0;
  155. sprintf (buffers8 [ibuffer], "%.9g", value);
  156. return buffers8 [ibuffer];
  157. }
  158. conststring32 Melder_single (double value) noexcept {
  159. const char *p = Melder8_single (value);
  160. CONVERT_BUFFER_TO_CHAR32
  161. }
  162. const char * Melder8_half (double value) noexcept {
  163. if (isundef (value))
  164. return "--undefined--";
  165. if (++ ibuffer == NUMBER_OF_BUFFERS)
  166. ibuffer = 0;
  167. sprintf (buffers8 [ibuffer], "%.4g", value);
  168. return buffers8 [ibuffer];
  169. }
  170. conststring32 Melder_half (double value) noexcept {
  171. const char *p = Melder8_half (value);
  172. CONVERT_BUFFER_TO_CHAR32
  173. }
  174. const char * Melder8_fixed (double value, integer precision) noexcept {
  175. if (isundef (value))
  176. return "--undefined--";
  177. if (value == 0.0)
  178. return "0";
  179. if (++ ibuffer == NUMBER_OF_BUFFERS)
  180. ibuffer = 0;
  181. if (precision > 60)
  182. precision = 60;
  183. int minimumPrecision = - (int) floor (log10 (fabs (value)));
  184. int n = snprintf (buffers8 [ibuffer], MAXIMUM_NUMERIC_STRING_LENGTH + 1, "%.*f",
  185. (int) (minimumPrecision > precision ? minimumPrecision : precision), value);
  186. Melder_assert (n > 0);
  187. Melder_assert (n <= MAXIMUM_NUMERIC_STRING_LENGTH);
  188. return buffers8 [ibuffer];
  189. }
  190. conststring32 Melder_fixed (double value, integer precision) noexcept {
  191. const char *p = Melder8_fixed (value, precision);
  192. CONVERT_BUFFER_TO_CHAR32
  193. }
  194. const char * Melder8_fixedExponent (double value, integer exponent, integer precision) noexcept {
  195. double factor = pow (10.0, exponent);
  196. if (isundef (value))
  197. return "--undefined--";
  198. if (value == 0.0)
  199. return "0";
  200. if (++ ibuffer == NUMBER_OF_BUFFERS)
  201. ibuffer = 0;
  202. if (precision > 60)
  203. precision = 60;
  204. value /= factor;
  205. int minimumPrecision = - (int) floor (log10 (fabs (value)));
  206. int n = snprintf (buffers8 [ibuffer], MAXIMUM_NUMERIC_STRING_LENGTH + 1, "%.*fE%d",
  207. (int) (minimumPrecision > precision ? minimumPrecision : precision), value, (int) exponent);
  208. Melder_assert (n > 0);
  209. Melder_assert (n <= MAXIMUM_NUMERIC_STRING_LENGTH);
  210. return buffers8 [ibuffer];
  211. }
  212. conststring32 Melder_fixedExponent (double value, integer exponent, integer precision) noexcept {
  213. const char *p = Melder8_fixedExponent (value, exponent, precision);
  214. CONVERT_BUFFER_TO_CHAR32
  215. }
  216. const char * Melder8_percent (double value, integer precision) noexcept {
  217. if (isundef (value))
  218. return "--undefined--";
  219. if (value == 0.0)
  220. return "0";
  221. if (++ ibuffer == NUMBER_OF_BUFFERS)
  222. ibuffer = 0;
  223. if (precision > 60)
  224. precision = 60;
  225. value *= 100.0;
  226. int minimumPrecision = - (int) floor (log10 (fabs (value)));
  227. int n = snprintf (buffers8 [ibuffer], MAXIMUM_NUMERIC_STRING_LENGTH + 1, "%.*f%%",
  228. (int) (minimumPrecision > precision ? minimumPrecision : precision), value);
  229. Melder_assert (n > 0);
  230. Melder_assert (n <= MAXIMUM_NUMERIC_STRING_LENGTH);
  231. return buffers8 [ibuffer];
  232. }
  233. conststring32 Melder_percent (double value, integer precision) noexcept {
  234. const char *p = Melder8_percent (value, precision);
  235. CONVERT_BUFFER_TO_CHAR32
  236. }
  237. const char * Melder8_hexadecimal (integer value, integer precision) noexcept {
  238. if (value < 0)
  239. return "--undefined--";
  240. if (++ ibuffer == NUMBER_OF_BUFFERS)
  241. ibuffer = 0;
  242. if (precision > 60)
  243. precision = 60;
  244. integer integerValue = Melder_iround (value);
  245. int n = snprintf (buffers8 [ibuffer], MAXIMUM_NUMERIC_STRING_LENGTH + 1, "%.*llX",
  246. (int) precision, (unsigned long long) integerValue);
  247. Melder_assert (n > 0);
  248. Melder_assert (n <= MAXIMUM_NUMERIC_STRING_LENGTH);
  249. return buffers8 [ibuffer];
  250. }
  251. conststring32 Melder_hexadecimal (integer value, integer precision) noexcept {
  252. const char *p = Melder8_hexadecimal (value, precision);
  253. CONVERT_BUFFER_TO_CHAR32
  254. }
  255. const char * Melder8_dcomplex (dcomplex value) noexcept {
  256. if (isundef (value.re) || isundef (value.im))
  257. return "--undefined--";
  258. if (++ ibuffer == NUMBER_OF_BUFFERS)
  259. ibuffer = 0;
  260. sprintf (buffers8 [ibuffer], "%.15g", value.re);
  261. if (strtod (buffers8 [ibuffer], nullptr) != value.re) {
  262. sprintf (buffers8 [ibuffer], "%.16g", value.re);
  263. if (strtod (buffers8 [ibuffer], nullptr) != value.re)
  264. sprintf (buffers8 [ibuffer], "%.17g", value.re);
  265. }
  266. char *p = buffers8 [ibuffer] + strlen (buffers8 [ibuffer]);
  267. *p = value.im < 0.0 ? '-' : '+';
  268. value.im = fabs (value.im);
  269. ++ p;
  270. sprintf (p, "%.15g", value.im);
  271. if (strtod (p, nullptr) != value.im) {
  272. sprintf (p, "%.16g", value.im);
  273. if (strtod (p, nullptr) != value.im)
  274. sprintf (p, "%.17g", value.im);
  275. }
  276. strcat (buffers8 [ibuffer], "i");
  277. return buffers8 [ibuffer];
  278. }
  279. conststring32 Melder_dcomplex (dcomplex value) noexcept {
  280. const char *p = Melder8_dcomplex (value);
  281. CONVERT_BUFFER_TO_CHAR32
  282. }
  283. const char * Melder8_scomplex (dcomplex value) noexcept {
  284. if (isundef (value.re) || isundef (value.im))
  285. return "--undefined--";
  286. if (++ ibuffer == NUMBER_OF_BUFFERS)
  287. ibuffer = 0;
  288. sprintf (buffers8 [ibuffer], "%.9g", value.re);
  289. char *p = buffers8 [ibuffer] + strlen (buffers8 [ibuffer]);
  290. *p = value.im < 0.0 ? '-' : '+';
  291. sprintf (++ p, "%.9g", fabs (value.im));
  292. strcat (buffers8 [ibuffer], "i");
  293. return buffers8 [ibuffer];
  294. }
  295. conststring32 Melder_scomplex (dcomplex value) noexcept {
  296. const char *p = Melder8_scomplex (value);
  297. CONVERT_BUFFER_TO_CHAR32
  298. }
  299. conststring32 Melder_float (conststring32 number) noexcept {
  300. if (++ ibuffer == NUMBER_OF_BUFFERS)
  301. ibuffer = 0;
  302. if (! str32chr (number, 'e')) {
  303. str32cpy (buffers32 [ibuffer], number);
  304. } else {
  305. char32 *b = buffers32 [ibuffer];
  306. const char32 *n = & number [0];
  307. while (*n != U'e')
  308. *(b++) = *(n++);
  309. *b = U'\0';
  310. if (number [0] == '1' && number [1] == 'e') {
  311. str32cpy (buffers32 [ibuffer], U"10^^");
  312. b = buffers32 [ibuffer] + 4;
  313. } else {
  314. str32cat (buffers32 [ibuffer], U"·10^^");
  315. b += 5;
  316. }
  317. Melder_assert (*n == U'e');
  318. if (*++n == U'+')
  319. n ++; // ignore leading plus sign in exponent
  320. if (*n == U'-')
  321. *(b++) = *(n++); // copy sign of negative exponent
  322. while (*n == U'0')
  323. n ++; // ignore leading zeroes in exponent
  324. while (*n >= U'0' && *n <= U'9')
  325. *(b++) = *(n++);
  326. *(b++) = U'^';
  327. while (*n != U'\0')
  328. *(b++) = *(n++);
  329. *b = U'\0';
  330. }
  331. return buffers32 [ibuffer];
  332. }
  333. const char * Melder8_naturalLogarithm (double lnNumber) noexcept {
  334. //if (lnNumber == -INFINITY) return "0"; // this would have been nice, but cannot be relied upon
  335. if (isundef (lnNumber))
  336. return "--undefined--";
  337. double log10Number = lnNumber * NUMlog10e;
  338. if (log10Number < -41.0) {
  339. if (++ ibuffer == NUMBER_OF_BUFFERS) ibuffer = 0;
  340. long_not_integer ceiling = (long_not_integer) ceil (log10Number);
  341. double remainder = log10Number - ceiling;
  342. double remainder10 = pow (10.0, remainder);
  343. while (remainder10 < 1.0) {
  344. remainder10 *= 10.0;
  345. ceiling --;
  346. }
  347. sprintf (buffers8 [ibuffer], "%.15g", remainder10);
  348. if (strtod (buffers8 [ibuffer], nullptr) != remainder10) {
  349. sprintf (buffers8 [ibuffer], "%.16g", remainder10);
  350. if (strtod (buffers8 [ibuffer], nullptr) != remainder10)
  351. sprintf (buffers8 [ibuffer], "%.17g", remainder10);
  352. }
  353. sprintf (buffers8 [ibuffer] + strlen (buffers8 [ibuffer]), "e-%ld", (long_not_integer) ceiling);
  354. } else {
  355. return Melder8_double (exp (lnNumber));
  356. }
  357. return buffers8 [ibuffer];
  358. }
  359. conststring32 Melder_naturalLogarithm (double lnNumber) noexcept {
  360. const char *p = Melder8_naturalLogarithm (lnNumber);
  361. CONVERT_BUFFER_TO_CHAR32
  362. }
  363. const char * Melder8_pointer (void *pointer) noexcept {
  364. if (++ ibuffer == NUMBER_OF_BUFFERS) ibuffer = 0;
  365. sprintf (buffers8 [ibuffer], "%p", pointer);
  366. return buffers8 [ibuffer];
  367. }
  368. conststring32 Melder_pointer (void *pointer) noexcept {
  369. const char *p = Melder8_pointer (pointer);
  370. CONVERT_BUFFER_TO_CHAR32
  371. }
  372. conststring32 Melder_character (char32 kar) noexcept {
  373. if (++ ibuffer == NUMBER_OF_BUFFERS) ibuffer = 0;
  374. buffers32 [ibuffer] [0] = kar;
  375. buffers32 [ibuffer] [1] = U'\0';
  376. return buffers32 [ibuffer];
  377. }
  378. /********** TENSOR TO STRING CONVERSION **********/
  379. #define NUMBER_OF_TENSOR_BUFFERS 3
  380. static MelderString theTensorBuffers [NUMBER_OF_TENSOR_BUFFERS] { };
  381. static int iTensorBuffer { 0 };
  382. conststring32 Melder_VEC (constVEC value) {
  383. if (++ iTensorBuffer == NUMBER_OF_TENSOR_BUFFERS)
  384. iTensorBuffer = 0;
  385. MelderString *string = & theTensorBuffers [iTensorBuffer];
  386. MelderString_empty (string);
  387. if (value.at) {
  388. for (integer i = 1; i <= value.size; i ++)
  389. MelderString_append (string, value [i], U'\n');
  390. }
  391. return string -> string;
  392. }
  393. conststring32 Melder_MAT (constMAT value) {
  394. if (++ iTensorBuffer == NUMBER_OF_TENSOR_BUFFERS)
  395. iTensorBuffer = 0;
  396. MelderString *string = & theTensorBuffers [iTensorBuffer];
  397. MelderString_empty (string);
  398. if (value.at) {
  399. for (integer irow = 1; irow <= value.nrow; irow ++) {
  400. for (integer icol = 1; icol <= value.ncol; icol ++) {
  401. MelderString_append (string, value [irow] [icol]);
  402. if (icol < value.ncol)
  403. MelderString_appendCharacter (string, U' ');
  404. }
  405. if (irow < value.nrow)
  406. MelderString_appendCharacter (string, U'\n');
  407. }
  408. }
  409. return string -> string;
  410. }
  411. /********** STRING TO STRING CONVERSION **********/
  412. static MelderString thePadBuffers [NUMBER_OF_BUFFERS];
  413. static int iPadBuffer { 0 };
  414. conststring32 Melder_pad (int64 width, conststring32 string) {
  415. if (++ iPadBuffer == NUMBER_OF_BUFFERS)
  416. iPadBuffer = 0;
  417. int64 length = str32len (string);
  418. int64 tooShort = width - length;
  419. if (tooShort <= 0) return string;
  420. MelderString_empty (& thePadBuffers [iPadBuffer]);
  421. for (int64 i = 0; i < tooShort; i ++)
  422. MelderString_appendCharacter (& thePadBuffers [iPadBuffer], U' ');
  423. MelderString_append (& thePadBuffers [iPadBuffer], string);
  424. return thePadBuffers [iPadBuffer]. string;
  425. }
  426. conststring32 Melder_pad (conststring32 string, int64 width) {
  427. if (++ iPadBuffer == NUMBER_OF_BUFFERS)
  428. iPadBuffer = 0;
  429. int64 length = str32len (string);
  430. int64 tooShort = width - length;
  431. if (tooShort <= 0) return string;
  432. MelderString_copy (& thePadBuffers [iPadBuffer], string);
  433. for (int64 i = 0; i < tooShort; i ++)
  434. MelderString_appendCharacter (& thePadBuffers [iPadBuffer], U' ');
  435. return thePadBuffers [iPadBuffer]. string;
  436. }
  437. conststring32 Melder_truncate (int64 width, conststring32 string) {
  438. if (++ iPadBuffer == NUMBER_OF_BUFFERS)
  439. iPadBuffer = 0;
  440. int64 length = str32len (string);
  441. int64 tooLong = length - width;
  442. if (tooLong <= 0) return string;
  443. MelderString_ncopy (& thePadBuffers [iPadBuffer], string + tooLong, width);
  444. return thePadBuffers [iPadBuffer]. string;
  445. }
  446. conststring32 Melder_truncate (conststring32 string, int64 width) {
  447. if (++ iPadBuffer == NUMBER_OF_BUFFERS)
  448. iPadBuffer = 0;
  449. int64 length = str32len (string);
  450. int64 tooLong = length - width;
  451. if (tooLong <= 0) return string;
  452. MelderString_ncopy (& thePadBuffers [iPadBuffer], string, width);
  453. return thePadBuffers [iPadBuffer]. string;
  454. }
  455. conststring32 Melder_padOrTruncate (int64 width, conststring32 string) {
  456. if (++ iPadBuffer == NUMBER_OF_BUFFERS)
  457. iPadBuffer = 0;
  458. int64 length = str32len (string);
  459. int64 tooLong = length - width;
  460. if (tooLong == 0) return string;
  461. if (tooLong < 0) {
  462. int64 tooShort = - tooLong;
  463. MelderString_empty (& thePadBuffers [iPadBuffer]);
  464. for (int64 i = 0; i < tooShort; i ++)
  465. MelderString_appendCharacter (& thePadBuffers [iPadBuffer], U' ');
  466. MelderString_append (& thePadBuffers [iPadBuffer], string);
  467. } else {
  468. MelderString_ncopy (& thePadBuffers [iPadBuffer], string + tooLong, width);
  469. }
  470. return thePadBuffers [iPadBuffer]. string;
  471. }
  472. conststring32 Melder_padOrTruncate (conststring32 string, int64 width) {
  473. if (++ iPadBuffer == NUMBER_OF_BUFFERS)
  474. iPadBuffer = 0;
  475. int64 length = str32len (string);
  476. int64 tooLong = length - width;
  477. if (tooLong == 0) return string;
  478. if (tooLong < 0) {
  479. int64 tooShort = - tooLong;
  480. MelderString_copy (& thePadBuffers [iPadBuffer], string);
  481. for (int64 i = 0; i < tooShort; i ++)
  482. MelderString_appendCharacter (& thePadBuffers [iPadBuffer], U' ');
  483. } else {
  484. MelderString_ncopy (& thePadBuffers [iPadBuffer], string, width);
  485. }
  486. return thePadBuffers [iPadBuffer]. string;
  487. }
  488. /* End of file melder_ftoa.cpp */