1 /* @source ajfmt **************************************************************
2 **
3 ** AJAX format functions
4 **
5 ** String formatting routines. Similar to printf, fprintf, vprintf
6 ** etc but the set of conversion specifiers is not fixed, and cannot
7 ** store more characters than it can hold.
8 ** There is also ajFmtScanS / ajFmtScanC which is an extended sscanf.
9 **
10 ** Special formatting provided here:
11 ** %B : AJAX boolean
12 ** %D : AJAX date
13 ** %S : AJAX string
14 ** %z : Dynamic char* allocation in ajFmtScanS
15 **
16 ** Other differences are:
17 ** %s : accepts null strings and prints null in angle brackets
18 **
19 ** @author Copyright (C) 1998 Ian Longden
20 ** @author Copyright (C) 1998 Peter Rice
21 ** @author Copyright (C) 1999 Alan Bleasby
22 ** @version $Revision: 1.82 $
23 ** @modified Copyright (C) 2001 Alan Bleasby. Added ajFmtScanS functions
24 ** @modified Copyright (C) 2003 Jon Ison. Added ajFmtScanC functions
25 ** @modified $Date: 2012/12/07 10:15:22 $ by $Author: rice $
26 ** @@
27 **
28 ** This library is free software; you can redistribute it and/or
29 ** modify it under the terms of the GNU Lesser General Public
30 ** License as published by the Free Software Foundation; either
31 ** version 2.1 of the License, or (at your option) any later version.
32 **
33 ** This library is distributed in the hope that it will be useful,
34 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
35 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36 ** Lesser General Public License for more details.
37 **
38 ** You should have received a copy of the GNU Lesser General Public
39 ** License along with this library; if not, write to the Free Software
40 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
41 ** MA 02110-1301, USA.
42 **
43 ******************************************************************************/
44
45 /* ========================================================================= */
46 /* ============================= include files ============================= */
47 /* ========================================================================= */
48
49 #include "ajfmt.h"
50 #include "ajassert.h"
51 #include "ajmem.h"
52 #include "ajmess.h"
53 #include "ajsys.h"
54 #include "ajexcept.h"
55 #include "ajtime.h"
56
57 #include <stdlib.h>
58 #include <stdio.h>
59 #include <string.h>
60 #include <limits.h>
61 #include <float.h>
62 #include <ctype.h>
63 #include <math.h>
64 #include <time.h>
65
66
67
68
69 /* ========================================================================= */
70 /* =============================== constants =============================== */
71 /* ========================================================================= */
72
73 #define EVF_PERCENT 1
74 #define EVF_NOCON 2
75 #define EVF_LONG 4
76 #define EVF_AJLONG 8
77 #define EVF_UNSIGNED 16
78 #define EVF_NEGATE 32
79
80 #define EVF_BUF 128
81
82 #if defined(__x86_64__) || defined(__amd64__) || defined(__EM64T__) || \
83 defined(__PPC__) && defined(_CALL_SYSV)
84 #define VALIST va_list
85 #define VA_P(x) (x)
86 #define VA_V(x) (x)
87 #else
88 #define VALIST va_list*
89 #define VA_P(x) (&x)
90 #define VA_V(x) (*x)
91 #endif
92
93 #define pad(n,c) do { ajint nn = (n); \
94 while(nn-- > 0) \
95 (*put) ((c), cl); } while(0)
96
97
98
99
100 /* ========================================================================= */
101 /* =========================== global variables ============================ */
102 /* ========================================================================= */
103
104
105
106
107 /* ========================================================================= */
108 /* ============================= private data ============================== */
109 /* ========================================================================= */
110
111
112
113
114 typedef void (*Fmt_T) (ajint code, VALIST ap,
115 int (*put) (int c, void *cl), void *cl,
116 const ajuint *flags, ajint width, ajint precision);
117
118 typedef void (*Fmt_S) (const char *fmt, const char **pos, VALIST ap, int width,
119 AjBool convert, AjBool *ok);
120
121
122
123
124 /* @datastatic FmtPBuf ********************************************************
125 **
126 ** Format definitions
127 **
128 ** @alias FmtSVuf
129 ** @alias FmtOBuf
130 **
131 ** @attr buf [char*] buffer to write
132 ** @attr bp [char*] next position in buffer
133 ** @attr size [size_t] size of buffer from malloc
134 ** @attr fixed [AjBool] if ajTrue, cannot reallocate
135 ** @attr Padding [ajuint] Padding to alignment boundary
136 ** @@
137 ******************************************************************************/
138
139 typedef struct FmtSBuf
140 {
141 char *buf;
142 char *bp;
143 size_t size;
144 AjBool fixed;
145 ajuint Padding;
146 } FmtOBuf;
147
148 #define FmtPBuf FmtOBuf*
149
150
151
152
153 /* ========================================================================= */
154 /* =========================== private variables =========================== */
155 /* ========================================================================= */
156
157
158
159
160 /* ========================================================================= */
161 /* =========================== private functions =========================== */
162 /* ========================================================================= */
163
164 /* static Fmt_T fmtRegister(ajint code, Fmt_T cvt); */
165
166 static AjBool c_notin(ajint c, const char *list);
167
168 static AjBool c_isin(ajint c, const char *list);
169
170 static ajint fmtVscan(const char *thys, const char *fmt, va_list ap);
171
172 static void scvt_uS(const char *fmt, const char **pos, VALIST ap, ajint width,
173 AjBool convert, AjBool *ok);
174
175 static void scvt_d(const char *fmt, const char **pos, VALIST ap, ajint width,
176 AjBool convert, AjBool *ok);
177
178 static void scvt_x(const char *fmt, const char **pos, VALIST ap, ajint width,
179 AjBool convert, AjBool *ok);
180
181 static void scvt_f(const char *fmt, const char **pos, VALIST ap, ajint width,
182 AjBool convert, AjBool *ok);
183
184 static void scvt_s(const char *fmt, const char **pos, VALIST ap, ajint width,
185 AjBool convert, AjBool *ok);
186
187 static void scvt_o(const char *fmt, const char **pos, VALIST ap, ajint width,
188 AjBool convert, AjBool *ok);
189
190 static void scvt_u(const char *fmt, const char **pos, VALIST ap, ajint width,
191 AjBool convert, AjBool *ok);
192
193 static void scvt_p(const char *fmt, const char **pos, VALIST ap, ajint width,
194 AjBool convert, AjBool *ok);
195
196 static void scvt_uB(const char *fmt, const char **pos, VALIST ap, ajint width,
197 AjBool convert, AjBool *ok);
198
199 static void scvt_c(const char *fmt, const char **pos, VALIST ap, ajint width,
200 AjBool convert, AjBool *ok);
201
202 static void scvt_b(const char *fmt, const char **pos, VALIST ap, ajint width,
203 AjBool convert, AjBool *ok);
204
205 static void scvt_z(const char *fmt, const char **pos, VALIST ap, ajint width,
206 AjBool convert, AjBool *ok);
207
208 static void cvt_s(ajint code, VALIST ap, int (*put) (int c, void *cl),
209 void *cl, const ajuint *flags, ajint width,
210 ajint precision);
211
212 static void cvt_uB(ajint code, VALIST ap, int (*put) (int c, void *cl),
213 void *cl, const ajuint *flags, ajint width,
214 ajint precision);
215
216 static void cvt_uD(ajint code, VALIST ap, int (*put) (int c, void *cl),
217 void *cl, const ajuint *flags, ajint width,
218 ajint precision);
219
220 static void cvt_uF(ajint code, VALIST ap, int (*put) (int c, void *cl),
221 void *cl, const ajuint *flags, ajint width,
222 ajint precision);
223
224 static void cvt_uS(ajint code, VALIST ap, int (*put) (int c, void *cl),
225 void *cl, const ajuint *flags, ajint width,
226 ajint precision);
227
228 static void cvt_x(ajint code, VALIST ap, int (*put) (int c, void *cl),
229 void *cl, const ajuint *flags, ajint width,
230 ajint precision);
231
232 static void cvt_b(ajint code, VALIST ap, int (*put) (int c, void *cl),
233 void *cl, const ajuint *flags, ajint width,
234 ajint precision);
235
236 static void cvt_c(ajint code, VALIST ap, int (*put) (int c, void *cl),
237 void *cl, const ajuint *flags, ajint width,
238 ajint precision);
239
240 static void cvt_d(ajint code, VALIST ap, int (*put) (int c, void *cl),
241 void *cl, const ajuint *flags, ajint width,
242 ajint precision);
243
244 static void cvt_f(ajint code, VALIST ap, int (*put) (int c, void *cl),
245 void *cl, const ajuint *flags, ajint width,
246 ajint precision);
247
248 static void cvt_o(ajint code, VALIST ap, int (*put) (int c, void *cl),
249 void *cl, const ajuint *flags, ajint width,
250 ajint precision);
251
252 static void cvt_p(ajint code, VALIST ap, int (*put) (int c, void *cl),
253 void *cl, const ajuint *flags, ajint width,
254 ajint precision);
255
256 static void cvt_u(ajint code, VALIST ap, int (*put) (int c, void *cl),
257 void *cl, const ajuint *flags, ajint width,
258 ajint precision);
259
260 static ajint fmtVfscanf(FILE *stream, const char *fmt, va_list ap);
261
262 #if defined(HAVE64)
263
264 static ajlong sc_long(const char *str);
265
266 static ajulong sc_ulong(const char *str);
267
268 static ajulong sc_hex(const char *str);
269
270 static ajulong sc_octal(const char *str);
271
272 #endif /* HAVE64 */
273
274
275
276
277 /* @funcstatic c_isin *********************************************************
278 **
279 ** Checks whether a character is in a set
280 **
281 ** @param [r] c [ajint] character
282 ** @param [r] list [const char*] set of characters
283 ** @return [AjBool] ajTrue if character is in the set
284 **
285 ** @release 1.10.0
286 ** @@
287 ******************************************************************************/
288
c_isin(ajint c,const char * list)289 static AjBool c_isin(ajint c, const char *list)
290 {
291 while(*list)
292 if(c == (ajint) *(list++))
293 return ajTrue;
294
295 return ajFalse;
296 }
297
298
299
300
301 /* @funcstatic c_notin ********************************************************
302 **
303 ** Checks whether a character is not in a set
304 **
305 ** @param [r] c [ajint] character
306 ** @param [r] list [const char*] set of characters
307 ** @return [AjBool] ajTrue if character is not in the set
308 **
309 ** @release 1.10.0
310 ** @@
311 ******************************************************************************/
312
c_notin(ajint c,const char * list)313 static AjBool c_notin(ajint c, const char *list)
314 {
315 while(*list)
316 if(c == (ajint) *(list++))
317 return ajFalse;
318
319 return ajTrue;
320 }
321
322
323
324
325 /* @funcstatic cvt_s **********************************************************
326 **
327 ** Conversion for %s to print char* text
328 **
329 ** As for C RTL but prints null if given a null pointer.
330 **
331 ** @param [r] code [ajint] Format code specified (usually s)
332 ** @param [r] ap [VALIST] Original arguments at current position
333 ** @param [f] put [int function] Standard function
334 ** @param [u] cl [void*] Standard - where to write results
335 ** @param [r] flags [const ajuint*] Flags (after the %)
336 ** @param [r] width [ajint] Width (before the dot)
337 ** @param [r] precision [ajint] Precision (after the dot)
338 ** @return [void]
339 **
340 ** @release 1.0.0
341 ** @@
342 ******************************************************************************/
343
cvt_s(ajint code,VALIST ap,int (* put)(int c,void * cl),void * cl,const ajuint * flags,ajint width,ajint precision)344 static void cvt_s(ajint code, VALIST ap, int (*put) (int c, void *cl),
345 void *cl, const ajuint *flags, ajint width,
346 ajint precision)
347 {
348 char *str = va_arg(VA_V(ap), char *);
349
350 (void) code;
351
352 if(str)
353 ajFmtPuts(str, strlen(str), put, cl, flags,
354 width, precision);
355 else
356 ajFmtPuts("<null>", 6, put, cl, flags,
357 width, precision);
358
359 return;
360 }
361
362
363
364
365 /* @funcstatic cvt_d **********************************************************
366 **
367 ** Conversion for %d to print integer
368 **
369 ** @param [r] code [ajint] Format code specified (usually d)
370 ** @param [r] ap [VALIST] Original arguments at current position
371 ** @param [f] put [int function] Standard function
372 ** @param [u] cl [void*] Standard - where to write results
373 ** @param [r] flags [const ajuint*] Flags (after the %)
374 ** @param [r] width [ajint] Width (before the dot)
375 ** @param [r] precision [ajint] Precision (after the dot)
376 ** @return [void]
377 **
378 ** @release 1.0.0
379 ** @@
380 ******************************************************************************/
381
cvt_d(ajint code,VALIST ap,int (* put)(int c,void * cl),void * cl,const ajuint * flags,ajint width,ajint precision)382 static void cvt_d(ajint code, VALIST ap, int (*put) (int c, void *cl),
383 void *cl, const ajuint *flags, ajint width,
384 ajint precision)
385 {
386 long val = 0;
387 #if defined(HAVE64)
388 ajlong hval = 0;
389 #endif /* HAVE64 */
390 ajulong m = 0;
391
392 char buf[43];
393 char *p = buf + sizeof buf;
394
395 (void) code;
396
397 if(flags['l'])
398 {
399 val = (long) va_arg(VA_V(ap), long);
400 #if defined(HAVE64)
401 hval = val;
402 #endif /* HAVE64 */
403 }
404 else if(flags['L'])
405 {
406 #if defined(HAVE64)
407 hval = (ajlong) va_arg(VA_V(ap), ajlong);
408 val = hval;
409 #else /* !HAVE64 */
410 val = (long) va_arg(VA_V(ap), ajlong);
411 /*ajDebug("Warning: Use of %%Ld on a 32 bit model");*/
412 #endif /* HAVE64 */
413 }
414 else if(flags['h'])
415 {
416 /* ANSI C converts short to ajint */
417 val = (long) va_arg(VA_V(ap), int);
418 #if defined(HAVE64)
419 hval = val;
420 #endif /* HAVE64 */
421 }
422 else
423 {
424 val = (long) va_arg(VA_V(ap), int);
425 #if defined(HAVE64)
426 hval = val;
427 #endif /* HAVE64 */
428 }
429
430
431 #if defined(HAVE64)
432 if(hval == INT_MIN)
433 m = INT_MAX + 1U;
434 else if(hval < 0)
435 m = -hval;
436 else
437 m = hval;
438
439 do
440 *--p = ajSysCastItoc((ajint) (m % 10 + '0'));
441 while((m /= 10) > 0);
442
443 if(hval < 0)
444 *--p = '-';
445 #else /* !HAVE64 */
446 if(val == INT_MIN)
447 m = INT_MAX + 1U;
448 else if(val < 0)
449 m = -val;
450 else
451 m = val;
452
453 do
454 *--p = ajSysCastItoc((ajint) (m % 10 + '0'));
455 while((m /= 10) > 0);
456
457 if(val < 0)
458 *--p = '-';
459 #endif /* HAVE64 */
460
461 ajFmtPutd(p, (buf + sizeof buf) - p, put, cl, flags,
462 width, precision);
463
464 return;
465 }
466
467
468
469
470 /* @funcstatic cvt_u **********************************************************
471 **
472 ** Conversion for %u to print unsigned integer
473 **
474 ** @param [r] code [ajint] Format code specified (usually u)
475 ** @param [r] ap [VALIST] Original arguments at current position
476 ** @param [f] put [int function] Standard function
477 ** @param [u] cl [void*] Standard - where to write results
478 ** @param [r] flags [const ajuint*] Flags (after the %)
479 ** @param [r] width [ajint] Width (before the dot)
480 ** @param [r] precision [ajint] Precision (after the dot)
481 ** @return [void]
482 **
483 ** @release 1.0.0
484 ** @@
485 ******************************************************************************/
486
cvt_u(ajint code,VALIST ap,int (* put)(int c,void * cl),void * cl,const ajuint * flags,ajint width,ajint precision)487 static void cvt_u(ajint code, VALIST ap, int (*put) (int c, void *cl),
488 void *cl, const ajuint *flags, ajint width,
489 ajint precision)
490 {
491 unsigned long val = 0;
492 #if defined(HAVE64)
493 ajulong hval = 0;
494 #endif /* HAVE64 */
495 char buf[43];
496 char *p;
497
498 (void) code;
499
500 p = buf + sizeof buf;
501
502 if(flags['l'])
503 {
504 val = va_arg(VA_V(ap), unsigned long);
505 #if defined(HAVE64)
506 hval = val;
507 #endif /* HAVE64 */
508 }
509 else if(flags['L'])
510 {
511 #if defined(HAVE64)
512 hval = (ajulong) va_arg(VA_V(ap), ajulong);
513 val = hval;
514 #else /* !HAVE64 */
515 val = (unsigned long) va_arg(VA_V(ap), ajulong);
516 /*ajDebug("Warning: Use of %%Lu on 32 bit model");*/
517 #endif /* HAVE64 */
518 }
519 else if(flags['h'])
520 { /* ANSI C converts short to int */
521 val = (unsigned long) va_arg(VA_V(ap), unsigned int);
522 #if defined(HAVE64)
523 hval = val;
524 #endif /* HAVE64 */
525 }
526 else
527 {
528 val = (unsigned long) va_arg(VA_V(ap), unsigned int);
529 #if defined(HAVE64)
530 hval = val;
531 #endif /* HAVE64 */
532 }
533
534 #if !defined(HAVE64)
535 do
536 *--p = ajSysCastItoc(val % 10 + '0');
537 while((val /= (ajulong) 10) > 0);
538 #else /* HAVE64 */
539 do
540 *--p = ajSysCastItoc((int) (hval % (ajulong) 10 + '0'));
541 while((hval /= (ajulong) 10) > 0);
542 #endif /* !HAVE64 */
543 ajFmtPutd(p, (buf + sizeof buf) - p, put, cl, flags,
544 width, precision);
545
546 return;
547 }
548
549
550
551
552 /* @funcstatic cvt_o **********************************************************
553 **
554 ** Conversion for %o to print unsigned integer as octal
555 **
556 ** @param [r] code [ajint] Format code specified (usually o)
557 ** @param [r] ap [VALIST] Original arguments at current position
558 ** @param [f] put [int function] Standard function
559 ** @param [u] cl [void*] Standard - where to write results
560 ** @param [r] flags [const ajuint*] Flags (after the %)
561 ** @param [r] width [ajint] Width (before the dot)
562 ** @param [r] precision [ajint] Precision (after the dot)
563 ** @return [void]
564 **
565 ** @release 1.0.0
566 ** @@
567 ******************************************************************************/
568
cvt_o(ajint code,VALIST ap,int (* put)(int c,void * cl),void * cl,const ajuint * flags,ajint width,ajint precision)569 static void cvt_o(ajint code, VALIST ap, int (*put) (int c, void *cl),
570 void *cl, const ajuint *flags, ajint width,
571 ajint precision)
572 {
573 unsigned long m = 0;
574 char buf[43];
575 char *p;
576 #if defined(HAVE64)
577 ajulong hm = 0;
578 #endif /* HAVE64 */
579
580 (void) code;
581
582 p = buf + sizeof buf;
583
584 if(flags['l'])
585 m = va_arg(VA_V(ap), unsigned long);
586 if(flags['h'])
587 /* ANSI C converts short to ajint */
588 m = va_arg(VA_V(ap), unsigned int);
589 else if(flags['L'])
590 {
591 #if defined(HAVE64)
592 hm = (ajulong) va_arg(VA_V(ap), ajulong);
593 #else /* !HAVE64 */
594 m = (unsigned long) va_arg(VA_V(ap), ajulong);
595 /*ajDebug("Warning: Use of %%Lo on a 32 bit model");*/
596 #endif /* HAVE64 */
597 }
598 else
599 {
600 m = va_arg(VA_V(ap), unsigned int);
601 #if defined(HAVE64)
602 hm = m;
603 #endif /* HAVE64 */
604 }
605
606 #if !defined(HAVE64)
607 do
608 *--p = ajSysCastItoc((m & 0x7) + '0');
609 while((m >>= 3) != 0);
610 #else /* HAVE64 */
611 do
612 *--p = ajSysCastItoc((int) ((hm & 0x7) + '0'));
613 while((hm >>= 3) != 0);
614 #endif /* !HAVE64 */
615
616 if(flags['#'])
617 *--p = '0';
618
619 ajFmtPutd(p, (buf + sizeof buf) - p, put, cl, flags,
620 width, precision);
621
622 return;
623 }
624
625
626
627
628 /* @funcstatic cvt_x **********************************************************
629 *
630 ** Conversion for %x to print unsigned integer as hexadecimal
631 **
632 ** @param [r] code [ajint] Format code specified (usually x)
633 ** @param [r] ap [VALIST] Original arguments at current position
634 ** @param [f] put [int function] Standard function
635 ** @param [u] cl [void*] Standard - where to write results
636 ** @param [r] flags [const ajuint*] Flags (after the %)
637 ** @param [r] width [ajint] Width (before the dot)
638 ** @param [r] precision [ajint] Precision (after the dot)
639 ** @return [void]
640 **
641 ** @release 1.0.0
642 ** @@
643 ******************************************************************************/
644
cvt_x(ajint code,VALIST ap,int (* put)(int c,void * cl),void * cl,const ajuint * flags,ajint width,ajint precision)645 static void cvt_x(ajint code, VALIST ap, int (*put) (int c, void *cl),
646 void *cl, const ajuint *flags, ajint width,
647 ajint precision)
648 {
649 unsigned long m = 0;
650 #if defined(HAVE64)
651 ajulong hm = 0;
652 #endif /* HAVE64 */
653 char buf[43];
654 char *p;
655
656 p = buf + sizeof buf;
657
658 if(flags['l'])
659 {
660 m = va_arg(VA_V(ap), unsigned long);
661 #if defined(HAVE64)
662 hm = m;
663 #endif /* HAVE64 */
664 }
665 else if(flags['h'])
666 {
667 /* ANSI C converts short to int */
668 m = va_arg(VA_V(ap), unsigned int);
669 #if defined(HAVE64)
670 hm = m;
671 #endif /* HAVE64 */
672 }
673 else if(flags['L'])
674 {
675 #if defined(HAVE64)
676 hm = va_arg(VA_V(ap), ajulong);
677 #else /* !HAVE64 */
678 m = (unsigned long) va_arg(VA_V(ap), ajulong);
679 /* ajDebug("Warning: Use of %%Lx on a 32 bit model"); */
680 #endif /* HAVE64 */
681 }
682 else
683 {
684 m = va_arg(VA_V(ap), unsigned int);
685 #if defined(HAVE64)
686 hm = m;
687 #endif /* HAVE64 */
688 }
689 if(code == 'X')
690 {
691 #if !defined(HAVE64)
692 do
693 *--p = "0123456789ABCDEF"[m & 0xf];
694 while((m >>= 4) != 0);
695 #else /* HAVE64 */
696 do
697 *--p = "0123456789ABCDEF"[hm & 0xf];
698 while((hm >>= 4) != 0);
699 #endif /* !HAVE64 */
700 }
701 else
702 {
703 #if !defined(HAVE64)
704 do
705 *--p = "0123456789abcdef"[m & 0xf];
706 while((m >>= 4) != 0);
707 #else /* HAVE64 */
708 do
709 *--p = "0123456789abcdef"[hm & 0xf];
710 while((hm >>= 4) != 0);
711 #endif /* !HAVE64 */
712 }
713
714 while(precision > buf + sizeof buf - p)
715 *--p = '0';
716
717 if(flags['#'])
718 {
719 *--p = 'x';
720 *--p = '0';
721 }
722
723 ajFmtPutd(p, (buf + sizeof buf) - p, put, cl, flags,
724 width, precision);
725
726 return;
727 }
728
729
730
731
732 /* @funcstatic cvt_p **********************************************************
733 **
734 ** Conversion for %p to print pointers of type void* as hexadecimal
735 **
736 ** @param [r] code [ajint] Format code specified (usually p)
737 ** @param [r] ap [VALIST] Original arguments at current position
738 ** @param [f] put [int function] Standard function
739 ** @param [u] cl [void*] Standard - where to write results
740 ** @param [r] flags [const ajuint*] Flags (after the %)
741 ** @param [r] width [ajint] Width (before the dot)
742 ** @param [r] precision [ajint] Precision (after the dot)
743 ** @return [void]
744 **
745 ** @release 1.0.0
746 ** @@
747 ******************************************************************************/
748
cvt_p(ajint code,VALIST ap,int (* put)(int c,void * cl),void * cl,const ajuint * flags,ajint width,ajint precision)749 static void cvt_p(ajint code, VALIST ap, int (*put) (int c, void *cl),
750 void *cl, const ajuint *flags, ajint width,
751 ajint precision)
752 {
753 unsigned long m;
754 char buf[43];
755 char *p;
756 precision = INT_MIN;
757
758 (void) code;
759
760 m = (unsigned long) va_arg(VA_V(ap), void *);
761 p = buf + sizeof buf;
762
763 do
764 *--p = "0123456789abcdef"[m & 0xf];
765 while((m >>= 4) != 0);
766
767 ajFmtPutd(p, (buf + sizeof buf) - p, put, cl, flags,
768 width, precision);
769
770 return;
771 }
772
773
774
775
776 /* @funcstatic cvt_c **********************************************************
777 **
778 ** Conversion for %c to print an integer (or a character)
779 ** as a single character.
780 **
781 ** Arguments passed in the variable part of an argument list are promoted
782 ** by default, so char is always promoted to ajint by the time it reaches here.
783 **
784 ** @param [r] code [ajint] Format code specified (usually c)
785 ** @param [r] ap [VALIST] Original arguments at current position
786 ** @param [f] put [int function] Standard function
787 ** @param [u] cl [void*] Standard - where to write results
788 ** @param [r] flags [const ajuint*] Flags (after the %)
789 ** @param [r] width [ajint] Width (before the dot)
790 ** @param [r] precision [ajint] Precision (after the dot)
791 ** @return [void]
792 **
793 ** @release 1.0.0
794 ** @@
795 ******************************************************************************/
796
cvt_c(ajint code,VALIST ap,int (* put)(int c,void * cl),void * cl,const ajuint * flags,ajint width,ajint precision)797 static void cvt_c(ajint code, VALIST ap, int (*put) (int c, void *cl),
798 void *cl, const ajuint *flags, ajint width,
799 ajint precision)
800 {
801 ajuint minusflag = flags['-'];
802 ajuint upperflag = flags['U'];
803 ajuint lowerflag = flags['L'];
804
805 (void) code;
806 (void) precision;
807
808 if(width == INT_MIN)
809 width = 0;
810
811 if(width < 0)
812 {
813 minusflag = 1;
814 width = -width;
815 }
816
817 if(!minusflag)
818 pad(width - 1, ' ');
819
820 if(upperflag)
821 (*put) ((unsigned char) toupper(va_arg(VA_V(ap), int)), cl);
822 else if(lowerflag)
823 (*put) ((unsigned char) tolower(va_arg(VA_V(ap), int)), cl);
824 else
825 (*put) (ajSysCastItouc(va_arg(VA_V(ap), int)), cl);
826
827 if(minusflag)
828 pad(width - 1, ' ');
829
830 return;
831 }
832
833
834
835
836 /* @funcstatic cvt_f **********************************************************
837 **
838 ** Conversion for %f to print a floating point number.
839 **
840 ** Because it is generally faster than hand crafted code, the standard
841 ** conversion in sprintf is used, and the resulting string is then
842 ** written out.
843 **
844 ** Precision is limited to 99 decimal places so it will fit in 2 characters
845 ** of the format for sprintf.
846 **
847 ** @param [r] code [ajint] Format code specified (usually f)
848 ** @param [r] ap [VALIST] Original arguments at current position
849 ** @param [f] put [int function] Standard function
850 ** @param [u] cl [void*] Standard - where to write results
851 ** @param [r] flags [const ajuint*] Flags (after the %)
852 ** @param [r] width [ajint] Width (before the dot)
853 ** @param [r] precision [ajint] Precision (after the dot)
854 ** @return [void]
855 **
856 ** @release 1.0.0
857 ** @@
858 ******************************************************************************/
859
cvt_f(ajint code,VALIST ap,int (* put)(int c,void * cl),void * cl,const ajuint * flags,ajint width,ajint precision)860 static void cvt_f(ajint code, VALIST ap, int (*put) (int c, void *cl),
861 void *cl, const ajuint *flags, ajint width,
862 ajint precision)
863 {
864 char buf[DBL_MAX_10_EXP + 1 + 1 + 99 + 1];
865
866 if(precision < 0)
867 {
868 if(code == 'f') precision = 6;
869 else if(code == 'g') precision = 6;
870 else if(code == 'e') precision = 6;
871 else precision = DBL_DIG;
872 }
873
874 if(code == 'g' && precision == 0)
875 precision = 1;
876
877 {
878 /* use sprintf to convert to string */
879 /* using code and precision */
880 static char fmt[12] = "%.dd";
881 ajint i = 2;
882
883 assert(precision <= 99);
884
885 if(precision > 9)
886 fmt[i++] = ajSysCastItoc((precision / 10) % 10 + '0');
887 fmt[i++] = ajSysCastItoc(precision % 10 + '0');
888 fmt[i++] = ajSysCastItoc(code);
889 fmt[i] = '\0';
890
891 sprintf(buf, fmt, va_arg(VA_V(ap), double));
892
893 if(code == 'g')
894 precision = 0;
895 }
896
897 /* now write string and support width */
898 ajFmtPutd(buf, strlen(buf), put, cl, flags,
899 width, precision);
900
901 return;
902 }
903
904
905
906
907 /* @funcstatic cvt_uS *********************************************************
908 **
909 ** Conversion for %S to print a string
910 **
911 ** @param [r] code [ajint] Format code specified (usually S)
912 ** @param [r] ap [VALIST] Original arguments at current position
913 ** @param [f] put [int function] Standard function
914 ** @param [u] cl [void*] Standard - where to write results
915 ** @param [r] flags [const ajuint*] Flags (after the %)
916 ** @param [r] width [ajint] Width (before the dot)
917 ** @param [r] precision [ajint] Precision (after the dot)
918 ** @return [void]
919 **
920 ** @release 1.13.0
921 ** @@
922 ******************************************************************************/
923
cvt_uS(ajint code,VALIST ap,int (* put)(int c,void * cl),void * cl,const ajuint * flags,ajint width,ajint precision)924 static void cvt_uS(ajint code, VALIST ap, int (*put) (int c, void *cl),
925 void *cl, const ajuint *flags, ajint width,
926 ajint precision)
927 {
928 AjPStr str1;
929
930 (void) code;
931
932 str1 = va_arg(VA_V(ap), AjPStr);
933
934 if(str1)
935 ajFmtPuts(str1->Ptr, str1->Len, put, cl, flags,
936 width, precision);
937 else
938 ajFmtPuts("<null>", 6, put, cl, flags,
939 width, precision);
940
941 return;
942 }
943
944
945
946
947 /* @funcstatic cvt_b **********************************************************
948 **
949 ** Conversion for %b to print a boolean as a 1 letter code (Y or N)
950 **
951 ** @param [r] code [ajint] Format code specified (usually b)
952 ** @param [r] ap [VALIST] Original arguments at current position
953 ** @param [f] put [int function] Standard function
954 ** @param [u] cl [void*] Standard - where to write results
955 ** @param [r] flags [const ajuint*] Flags (after the %)
956 ** @param [r] width [ajint] Width (before the dot)
957 ** @param [r] precision [ajint] Precision (after the dot)
958 ** @return [void]
959 **
960 ** @release 1.0.0
961 ** @@
962 ******************************************************************************/
963
cvt_b(ajint code,VALIST ap,int (* put)(int c,void * cl),void * cl,const ajuint * flags,ajint width,ajint precision)964 static void cvt_b(ajint code, VALIST ap, int (*put) (int c, void *cl),
965 void *cl, const ajuint *flags, ajint width,
966 ajint precision)
967 {
968 AjBool bl;
969
970 (void) code;
971
972 bl = va_arg(VA_V(ap), AjBool);
973
974 if(bl)
975 ajFmtPuts("Y", 1, put, cl, flags,
976 width, precision);
977 else
978 ajFmtPuts("N", 1, put, cl, flags,
979 width, precision);
980
981 return;
982 }
983
984
985
986
987 /* @funcstatic cvt_uB *********************************************************
988 **
989 ** Conversion for %B to print a boolean as text (Yes or No)
990 **
991 ** @param [r] code [ajint] Format code specified (usually B)
992 ** @param [r] ap [VALIST] Original arguments at current position
993 ** @param [f] put [int function] Standard function
994 ** @param [u] cl [void*] Standard - where to write results
995 ** @param [r] flags [const ajuint*] Flags (after the %)
996 ** @param [r] width [ajint] Width (before the dot)
997 ** @param [r] precision [ajint] Precision (after the dot)
998 ** @return [void]
999 **
1000 ** @release 1.13.0
1001 ** @@
1002 ******************************************************************************/
1003
cvt_uB(ajint code,VALIST ap,int (* put)(int c,void * cl),void * cl,const ajuint * flags,ajint width,ajint precision)1004 static void cvt_uB(ajint code, VALIST ap, int (*put) (int c, void *cl),
1005 void *cl, const ajuint *flags, ajint width,
1006 ajint precision)
1007 {
1008 AjBool bl;
1009
1010 (void) code;
1011
1012 bl = va_arg(VA_V(ap), AjBool);
1013
1014 if(bl)
1015 ajFmtPuts("Yes", 3, put, cl, flags,
1016 width, precision);
1017 else
1018 ajFmtPuts("No", 2, put, cl, flags,
1019 width, precision);
1020
1021 return;
1022 }
1023
1024
1025
1026
1027 /* @funcstatic cvt_uD *********************************************************
1028 **
1029 ** Conversion for %D to print a datetime value
1030 **
1031 ** @param [r] code [ajint] Format code specified (usually D)
1032 ** @param [r] ap [VALIST] Original arguments at current position
1033 ** @param [f] put [int function] Standard function
1034 ** @param [u] cl [void*] Standard - where to write results
1035 ** @param [r] flags [const ajuint*] Flags (after the %)
1036 ** @param [r] width [ajint] Width (before the dot)
1037 ** @param [r] precision [ajint] Precision (after the dot)
1038 ** @return [void]
1039 **
1040 ** @release 1.13.0
1041 ** @@
1042 ******************************************************************************/
1043
cvt_uD(ajint code,VALIST ap,int (* put)(int c,void * cl),void * cl,const ajuint * flags,ajint width,ajint precision)1044 static void cvt_uD(ajint code, VALIST ap, int (*put) (int c, void *cl),
1045 void *cl, const ajuint *flags, ajint width,
1046 ajint precision)
1047 {
1048 AjPTime timeobj;
1049 struct tm *mytime;
1050 int lenyr;
1051
1052 char buf[280];
1053 char yr[280];
1054
1055 (void) code;
1056
1057 timeobj = va_arg(VA_V(ap), AjPTime);
1058 mytime = &timeobj->time;
1059
1060 if(!timeobj)
1061 {
1062 ajFmtPuts("<null>", 6, put, cl, flags,
1063 width, precision);
1064 return;
1065 }
1066
1067 if(timeobj->format)
1068 strftime(buf, 280, timeobj->format, mytime);
1069 else
1070 {
1071 /* Long-winded but gets around some compilers' %y warnings */
1072 strftime(yr, 280, "%Y", mytime);
1073 lenyr = strlen(yr);
1074 memmove(yr, &yr[lenyr - 2], 3);
1075 strftime(buf, 280, "%d/%m/", mytime);
1076 strcat(buf, yr);
1077 }
1078
1079 if(timeobj->uppercase)
1080 ajCharFmtUpper(buf);
1081
1082 ajFmtPuts(&buf[0], strlen(buf), put, cl, flags,
1083 width, precision);
1084
1085 return;
1086 }
1087
1088
1089
1090
1091 /* @funcstatic cvt_uF *********************************************************
1092 **
1093 ** Conversion for %F to print a file object
1094 **
1095 ** @param [r] code [ajint] Format code specified (usually F)
1096 ** @param [r] ap [VALIST] Original arguments at current position
1097 ** @param [f] put [int function] Standard function
1098 ** @param [u] cl [void*] Standard - where to write results
1099 ** @param [r] flags [const ajuint*] Flags (after the %)
1100 ** @param [r] width [ajint] Width (before the dot)
1101 ** @param [r] precision [ajint] Precision (after the dot)
1102 ** @return [void]
1103 **
1104 ** @release 1.13.0
1105 ** @@
1106 ******************************************************************************/
1107
cvt_uF(ajint code,VALIST ap,int (* put)(int c,void * cl),void * cl,const ajuint * flags,ajint width,ajint precision)1108 static void cvt_uF(ajint code, VALIST ap, int (*put) (int c, void *cl),
1109 void *cl, const ajuint *flags, ajint width,
1110 ajint precision)
1111 {
1112 AjPFile fil;
1113
1114 (void) code;
1115
1116 fil = va_arg(VA_V(ap), AjPFile);
1117
1118 if(fil && fil->Name)
1119 ajFmtPuts(fil->Printname->Ptr, fil->Printname->Len, put, cl, flags,
1120 width, precision);
1121 else
1122 ajFmtPuts("<null>", 6, put, cl, flags,
1123 width, precision);
1124
1125 return;
1126 }
1127
1128
1129
1130
1131 /* @conststatic Fmt_Overflow **************************************************
1132 **
1133 ** Exception for a format overflow
1134 **
1135 ******************************************************************************/
1136
1137 static const Except_T Fmt_Overflow = { "Formatting Overflow" };
1138
1139
1140
1141
1142 /* @funclist Fmt_T ************************************************************
1143 **
1144 ** Conversion functions called for each conversion code.
1145 **
1146 ** Usually, code "x" will call "cvt_x" but there are exceptions. For example,
1147 ** floating point conversions all use cvt_f which sends everything to
1148 ** the standard C library. Also, cvt_d is used by alternative codes.
1149 **
1150 ** @return [void]
1151 ******************************************************************************/
1152
1153 static Fmt_T cvt[256] =
1154 {
1155 /* 0 - 7 */
1156 0, 0, 0, 0, 0, 0, 0, 0,
1157 /* 8 - 15 */
1158 0, 0, 0, 0, 0, 0, 0, 0,
1159 /* 16 - 23 */
1160 0, 0, 0, 0, 0, 0, 0, 0,
1161 /* 24 - 31 */
1162 0, 0, 0, 0, 0, 0, 0, 0,
1163 /* 32 - 39 */
1164 0, 0, 0, 0, 0, 0, 0, 0,
1165 /* 40 - 47 */
1166 0, 0, 0, 0, 0, 0, 0, 0,
1167 /* 48 - 55 */
1168 0, 0, 0, 0, 0, 0, 0, 0,
1169 /* 56 - 63 */
1170 0, 0, 0, 0, 0, 0, 0, 0,
1171 /* 64 - 71 */
1172 0, 0,&cvt_uB, 0,&cvt_uD, 0,&cvt_uF, 0,
1173 /* 72 - 79 */
1174 0, 0, 0, 0, 0, 0, 0, 0,
1175 /* 80 - 87 */
1176 0, 0, 0, cvt_uS, 0, 0, 0, 0,
1177 /* 88 - 95 */
1178 &cvt_x, 0, 0, 0, 0, 0, 0, 0,
1179 /* 96 - 103 */
1180 0, 0, &cvt_b, &cvt_c, &cvt_d, &cvt_f, &cvt_f, &cvt_f,
1181 /* 104 - 111 */
1182 0, 0, 0, 0, 0, 0, &cvt_d, &cvt_o,
1183 /* 112 - 119 */
1184 &cvt_p, 0, 0, &cvt_s, 0, &cvt_u, 0, 0,
1185 /* 120 - 127 */
1186 &cvt_x, 0, 0, 0, 0, 0, 0, 0
1187 };
1188
1189
1190
1191
1192 /* @funclist Fmt_S ************************************************************
1193 **
1194 ** Conversion functions called for each scan conversion code.
1195 **
1196 ** Usually, code "x" will call "cvt_x" but there are exceptions. For example,
1197 ** floating point conversions all use cvt_f which sends everything to
1198 ** the standard C library. Also, cvt_d is used by alternative codes.
1199 **
1200 ** @return [void]
1201 ******************************************************************************/
1202
1203 static Fmt_S scvt[256] =
1204 {
1205 /* 0- 7 */
1206 0, 0, 0, 0, 0, 0, 0, 0,
1207 /* 8- 15 */
1208 0, 0, 0, 0, 0, 0, 0, 0,
1209 /* 16- 23 */
1210 0, 0, 0, 0, 0, 0, 0, 0,
1211 /* 24- 31 */
1212 0, 0, 0, 0, 0, 0, 0, 0,
1213 /* 32- 39 */
1214 0, 0, 0, 0, 0, 0, 0, 0,
1215 /* 40- 47 */
1216 0, 0, 0, 0, 0, 0, 0, 0,
1217 /* 48- 55 */
1218 0, 0, 0, 0, 0, 0, 0, 0,
1219 /* 56- 63 */
1220 0, 0, 0, 0, 0, 0, 0, 0,
1221 /* 64- 71 */
1222 0, 0, &scvt_uB, 0, 0, 0, 0, 0,
1223 /* 72- 79 */
1224 0, 0, 0, 0, 0, 0, 0, 0,
1225 /* 80- 87 */
1226 0, 0, 0, &scvt_uS, 0, 0, 0, 0,
1227 /* 88- 95 */
1228 &scvt_x,0, 0, 0, 0, 0, 0, 0,
1229 /* 96-103 */
1230 0, 0,&scvt_b,&scvt_c,&scvt_d,&scvt_f,&scvt_f,&scvt_f,
1231 /* 104-111 */
1232 0, 0, 0, 0, 0, 0,&scvt_d,&scvt_o,
1233 /* 112-119 */
1234 &scvt_p,0, 0,&scvt_s, 0,&scvt_u, 0, 0,
1235 /* 120-127 */
1236 &scvt_x,0,&scvt_z, 0, 0, 0, 0, 0
1237 };
1238
1239
1240
1241
1242 /* @conststatic Fmt_Flags *****************************************************
1243 **
1244 ** Legal flag characters for conversions:
1245 ** '-' left justify value within field.
1246 ** '+' always put a sign character '+' of '-' for a numeric value.
1247 ** ' ' always put a sign character ' ' or '-' for a numeric value.
1248 ** '0' pad width with zeroes rather than spaces
1249 ** '#' alternative forms of the e, f, g, E, G formats
1250 ** for C this also changes o, x, X but is not yet implemented here.
1251 **
1252 ******************************************************************************/
1253
1254 static const char *Fmt_flags = "-+ 0#";
1255
1256
1257
1258
1259 /* @funcstatic fmtOutC ********************************************************
1260 **
1261 ** General output function to print a single character to a file
1262 **
1263 ** @param [r] c [int] Character to be written
1264 ** @param [u] cl [void*] Output file - will be cast to FILE* internally
1265 ** @return [ajint] Character written
1266 **
1267 ** @release 2.0.0
1268 ******************************************************************************/
1269
fmtOutC(int c,void * cl)1270 static ajint fmtOutC(int c, void *cl)
1271 {
1272 FILE *f = cl;
1273 ajint ret;
1274
1275 ret = putc(c, f);
1276
1277 #ifdef WIN32
1278 /* if((char) c == '\n')
1279 putc((int) '\r', f);*/
1280 #endif /* WIN32 */
1281
1282 return ret;
1283 }
1284
1285
1286
1287
1288 /* @funcstatic fmtInsert ******************************************************
1289 **
1290 ** Inserts a character in a buffer, raises a Fmt_Overflow exception if
1291 ** the buffer is too small.
1292 **
1293 ** @param [r] c [int] Character to be written
1294 ** @param [u] cl [void*] Output file - will be cast to FmtPBuf internally
1295 ** @return [ajint] Character written
1296 **
1297 ** @release 2.4.0
1298 ******************************************************************************/
1299
fmtInsert(int c,void * cl)1300 static ajint fmtInsert(int c, void *cl)
1301 {
1302 FmtPBuf p;
1303
1304 p = cl;
1305
1306 if(p->bp >= p->buf + p->size)
1307 {
1308 if(p->fixed)
1309 AJRAISE(Fmt_Overflow);
1310
1311 AJRESIZE(p->buf, 2 * p->size);
1312 p->bp = p->buf + p->size;
1313 p->size *= 2;
1314 }
1315
1316 *p->bp++ = ajSysCastItoc(c);
1317
1318 return c;
1319 }
1320
1321
1322
1323
1324 /* @funcstatic fmtAppend ******************************************************
1325 **
1326 ** Appends a character to a buffer, resizing it if necessary
1327 **
1328 ** @param [r] c [ajint] Character to be written
1329 ** @param [u] cl [void*] Output file - will be cast to FmtPBuf internally
1330 ** @return [ajint] kCharacter written
1331 **
1332 ** @release 2.4.0
1333 ******************************************************************************/
1334
fmtAppend(ajint c,void * cl)1335 static ajint fmtAppend(ajint c, void *cl)
1336 {
1337 FmtPBuf p;
1338
1339 p = cl;
1340
1341 if(p->bp >= p->buf + p->size)
1342 {
1343 if(p->fixed)
1344 AJRAISE(Fmt_Overflow);
1345
1346 AJRESIZE(p->buf, 2 * p->size);
1347 p->bp = p->buf + p->size;
1348 p->size *= 2;
1349 }
1350
1351 *p->bp++ = ajSysCastItoc(c);
1352
1353 return c;
1354 }
1355
1356
1357
1358
1359 /* @func ajFmtPuts ************************************************************
1360 **
1361 ** Format and emit the converted numeric (ajFmtPutd) or string
1362 ** (ajFmtPuts) in str[0..len - 1] according to Fmt's defaults
1363 ** and the values of flags, width and precision. It is a c.r.e
1364 ** for str = null, len less than 0 or flags = null.
1365 **
1366 ** @param [r] str [const char*] Text to write.
1367 ** @param [r] len [ajint] Text length.
1368 ** @param [f] put [int function] Standard function.
1369 ** @param [u] cl [void*] Standard - where to write the output
1370 ** @param [r] flags [const ajuint*] Flags (after the %)
1371 ** @param [r] width [ajint] Width (before the dot)
1372 ** @param [r] precision [ajint] Precision (after the dot)
1373 ** @return [void]
1374 ** @cre attempting to write over len chars to str
1375 **
1376 **
1377 ** @release 1.0.0
1378 ** @@
1379 ******************************************************************************/
1380
ajFmtPuts(const char * str,ajint len,int (* put)(int c,void * cl),void * cl,const ajuint * flags,ajint width,ajint precision)1381 void ajFmtPuts(const char *str, ajint len, int (*put) (int c, void *cl),
1382 void *cl, const ajuint *flags, ajint width,
1383 ajint precision)
1384 {
1385 ajuint minusflag = flags['-'];
1386 ajuint upperflag = flags['U'];
1387 ajuint lowerflag = flags['L'];
1388 ajint i;
1389
1390 assert(len >= 0);
1391 assert(flags);
1392
1393 if(width == INT_MIN)
1394 width = 0;
1395
1396 if(width < 0)
1397 {
1398 minusflag = 1;
1399 width = -width;
1400 }
1401
1402 if(precision >= 0 && precision < len)
1403 len = precision;
1404
1405 if(!minusflag)
1406 pad(width - len, ' ');
1407
1408 if(upperflag)
1409 {
1410 for(i = 0; i < len; i++)
1411 (*put) ((unsigned char) toupper((int) *str++), cl);
1412 }
1413 else if(lowerflag)
1414 {
1415 for(i = 0; i < len; i++)
1416 (*put) ((unsigned char) tolower((int) *str++), cl);
1417 }
1418 else
1419 {
1420 for(i = 0; i < len; i++)
1421 (*put) ((unsigned char) *str++, cl);
1422 }
1423
1424 if(minusflag)
1425 pad(width - len, ' ');
1426
1427 return;
1428 }
1429
1430
1431
1432
1433 /* @func ajFmtFmt *************************************************************
1434 **
1435 ** formats and emits the "..." arguments according to the format string fmt
1436 **
1437 ** @param [f] put [ajint function] Standard function.
1438 ** @param [u] cl [void*] Standard - where to write the output
1439 ** @param [r] fmt [const char*] Format string
1440 ** @param [v] [...] Variable length argument list
1441 ** @return [void]
1442 **
1443 **
1444 ** @release 1.0.0
1445 ** @@
1446 ******************************************************************************/
1447
ajFmtFmt(ajint (* put)(ajint c,void * cl),void * cl,const char * fmt,...)1448 void ajFmtFmt(ajint (*put) (ajint c, void *cl), void *cl,
1449 const char *fmt, ...)
1450 {
1451 va_list ap;
1452
1453 va_start(ap, fmt);
1454 ajFmtVfmt(put, cl, fmt, ap);
1455 va_end(ap);
1456
1457 return;
1458 }
1459
1460
1461
1462
1463 /* @func ajFmtPrint ***********************************************************
1464 **
1465 ** format and emit the "..." arguments according to fmt;writes to stdout.
1466 **
1467 ** @param [r] fmt [const char*] Format string.
1468 ** @param [v] [...] Variable length argument list
1469 ** @return [void]
1470 **
1471 ** @release 1.0.0
1472 ** @@
1473 ******************************************************************************/
1474
ajFmtPrint(const char * fmt,...)1475 void ajFmtPrint(const char *fmt, ...)
1476 {
1477 va_list ap;
1478
1479 va_start(ap, fmt);
1480 ajFmtVfmt(fmtOutC, stdout, fmt, ap);
1481 va_end(ap);
1482
1483 return;
1484 }
1485
1486
1487
1488
1489 /* @func ajFmtVPrint **********************************************************
1490 **
1491 ** format and emit the "..." arguments according to fmt;writes to stdout.
1492 **
1493 ** @param [r] fmt [const char*] Format string.
1494 ** @param [v] ap [va_list] Variable length argument list
1495 ** @return [void]
1496 **
1497 ** @release 1.0.0
1498 ** @@
1499 ******************************************************************************/
1500
ajFmtVPrint(const char * fmt,va_list ap)1501 void ajFmtVPrint(const char *fmt, va_list ap)
1502 {
1503 ajFmtVfmt(fmtOutC, stdout, fmt, ap);
1504
1505 return;
1506 }
1507
1508
1509
1510
1511 /* @func ajFmtError **********************************************************
1512 **
1513 ** format and emit the "..." arguments according to fmt;writes to stderr.
1514 **
1515 ** @param [r] fmt [const char*] Format string.
1516 ** @param [v] [...] Variable length argument list
1517 ** @return [void]
1518 **
1519 ** @release 1.0.0
1520 ** @@
1521 ******************************************************************************/
1522
ajFmtError(const char * fmt,...)1523 void ajFmtError(const char *fmt, ...)
1524 {
1525 va_list ap;
1526
1527 va_start(ap, fmt);
1528 ajFmtVfmt(fmtOutC, stderr, fmt, ap);
1529 va_end(ap);
1530
1531 return;
1532 }
1533
1534
1535
1536
1537 /* @func ajFmtVError *********************************************************
1538 **
1539 ** format and emit the "..." arguments according to fmt. Writes to stderr.
1540 **
1541 ** @param [r] fmt [const char*] Format string.
1542 ** @param [v] ap [va_list] Variable length argument list
1543 ** @return [void]
1544 **
1545 ** @release 1.0.0
1546 ** @@
1547 ******************************************************************************/
1548
ajFmtVError(const char * fmt,va_list ap)1549 void ajFmtVError(const char *fmt, va_list ap)
1550 {
1551 ajFmtVfmt(fmtOutC, stderr, fmt, ap);
1552
1553 return;
1554 }
1555
1556
1557
1558
1559 /* @func ajFmtPrintF *********************************************************
1560 **
1561 ** format and emit the "..." arguments according to fmt;writes to stream..
1562 **
1563 ** @param [u] file [AjPFile] Output file.
1564 ** @param [r] fmt [const char*] Format string.
1565 ** @param [v] [...] Variable length argument list
1566 ** @return [void]
1567 **
1568 ** @release 1.0.0
1569 ** @@
1570 ******************************************************************************/
1571
ajFmtPrintF(AjPFile file,const char * fmt,...)1572 void ajFmtPrintF(AjPFile file, const char *fmt, ...)
1573 {
1574 va_list ap;
1575
1576 if(!file)
1577 return;
1578
1579 va_start(ap, fmt);
1580 ajFmtVfmt(fmtOutC, file->fp, fmt, ap);
1581 va_end(ap);
1582
1583 return;
1584 }
1585
1586
1587
1588
1589 /* @func ajFmtVPrintF *********************************************************
1590 **
1591 ** format and emit the "..." arguments according to fmt;writes to stream..
1592 **
1593 ** @param [u] file [AjPFile] Output file.
1594 ** @param [r] fmt [const char*] Format string.
1595 ** @param [v] ap [va_list] Variable length argument list
1596 ** @return [void]
1597 **
1598 ** @release 1.0.0
1599 ** @@
1600 ******************************************************************************/
1601
ajFmtVPrintF(AjPFile file,const char * fmt,va_list ap)1602 void ajFmtVPrintF(AjPFile file, const char *fmt, va_list ap)
1603 {
1604 if(!file)
1605 return;
1606
1607 ajFmtVfmt(fmtOutC, file->fp, fmt, ap);
1608
1609 return;
1610 }
1611
1612
1613
1614
1615 /* @func ajFmtVPrintFp ********************************************************
1616 **
1617 ** Format and emit the "..." arguments according to fmt;writes to stream..
1618 **
1619 ** @param [u] stream [FILE*] Output file.
1620 ** @param [r] fmt [const char*] Format string.
1621 ** @param [v] ap [va_list] Variable length argument list
1622 ** @return [void]
1623 **
1624 ** @release 1.0.0
1625 ** @@
1626 ******************************************************************************/
1627
ajFmtVPrintFp(FILE * stream,const char * fmt,va_list ap)1628 void ajFmtVPrintFp(FILE *stream, const char *fmt, va_list ap)
1629 {
1630 ajFmtVfmt(fmtOutC, stream, fmt, ap);
1631
1632 return;
1633 }
1634
1635
1636
1637
1638 /* @func ajFmtPrintFp *********************************************************
1639 **
1640 ** format and emit the "..." arguments according to fmt;writes to stream..
1641 **
1642 ** @param [u] stream [FILE*] Output file.
1643 ** @param [r] fmt [const char*] Format string.
1644 ** @param [v] [...] Variable length argument list
1645 ** @return [void]
1646 **
1647 ** @release 1.0.0
1648 ** @@
1649 ******************************************************************************/
1650
ajFmtPrintFp(FILE * stream,const char * fmt,...)1651 void ajFmtPrintFp(FILE *stream, const char *fmt, ...)
1652 {
1653 va_list ap;
1654
1655 va_start(ap, fmt);
1656 ajFmtVfmt(fmtOutC, stream, fmt, ap);
1657 va_end(ap);
1658
1659 return;
1660 }
1661
1662
1663
1664
1665 /* @func ajFmtVPrintCL ********************************************************
1666 **
1667 ** formats the "..." arguments into buf[1...size - 1] according to fmt,
1668 ** appends a num character, and returns the length of buf. It is a
1669 ** c.r.e for size to be less than or equal to 0. Raises Fmt_Overflow
1670 ** if more than size - 1 characters are emitted.
1671 **
1672 ** @param [w] buf [char*] char string to be written to.
1673 ** @param [r] size [ajint] length of buffer
1674 ** @param [r] fmt [const char*] Format string.
1675 ** @param [v] ap [va_list] Variable length argument list
1676 ** @return [ajint] number of characters written to buf.
1677 **
1678 ** @release 1.0.0
1679 ** @@
1680 ******************************************************************************/
1681
ajFmtVPrintCL(char * buf,ajint size,const char * fmt,va_list ap)1682 ajint ajFmtVPrintCL(char *buf, ajint size, const char *fmt, va_list ap)
1683 {
1684 ajint len;
1685
1686 len = ajFmtVfmtCL(buf, size, fmt, ap);
1687
1688 return len;
1689 }
1690
1691
1692
1693
1694 /* @func ajFmtPrintCL *********************************************************
1695 **
1696 ** formats the "..." arguments into buf[1...size - 1] according to fmt,
1697 ** appends a num character, and returns the length of buf. It is a
1698 ** c.r.e for size to be lass than or equal to 0. Raises Fmt_Overflow
1699 ** if more than size - 1 characters are emitted.
1700 **
1701 ** @param [w] buf [char*] char string to be written to.
1702 ** @param [r] size [ajint] length of buffer
1703 ** @param [r] fmt [const char*] Format string
1704 ** @param [v] [...] Variable length argument list
1705 **
1706 ** @return [] [ajint] number of characters written to buf.
1707 **
1708 **
1709 ** @release 1.0.0
1710 ** @@
1711 ******************************************************************************/
1712
ajFmtPrintCL(char * buf,ajint size,const char * fmt,...)1713 ajint ajFmtPrintCL(char *buf, ajint size, const char *fmt, ...)
1714 {
1715 va_list ap;
1716 ajint len;
1717
1718 va_start(ap, fmt);
1719 len = ajFmtVfmtCL(buf, size, fmt, ap);
1720 va_end(ap);
1721
1722 return len;
1723 }
1724
1725
1726
1727
1728 /* @func ajFmtStr *************************************************************
1729 **
1730 ** Formats the "..." arguments into a New AjPStr according to fmt.
1731 ** It starts with an initial size of 20 then doubles until the
1732 ** fmt output fits.
1733 **
1734 ** The caller is responsible for deleting the AjPStr afterwards.
1735 **
1736 ** @param [r] fmt [const char*] Format string.
1737 ** @param [v] [...] Variable length argument list
1738 **
1739 ** @return [AjPStr] new AjPStr with Ptr holding formatted chars
1740 **
1741 ** @release 1.0.0
1742 ** @@
1743 ******************************************************************************/
1744
ajFmtStr(const char * fmt,...)1745 AjPStr ajFmtStr(const char *fmt, ...)
1746 {
1747 va_list ap;
1748 ajint len = 32;
1749 AjPStr fnew;
1750
1751 fnew = ajStrNewRes(len);
1752 va_start(ap, fmt);
1753 fnew->Len = ajFmtVfmtStrCL(&fnew->Ptr, 0, &fnew->Res, fmt, ap);
1754 va_end(ap);
1755
1756 return fnew;
1757 }
1758
1759
1760
1761
1762 /* @func ajFmtPrintS **********************************************************
1763 **
1764 ** Formats the "..." arguments into an AjPStr according to fmt.
1765 ** If AjPStr is not large enough then if it is the only one i.e
1766 ** Use = 1 then increase till it fits. Else return 0 if it does not
1767 ** fit. If it fits return the address of the new AjPStr.
1768 **
1769 ** @param [u] pthis [AjPStr*] String to be written too.
1770 ** @param [r] fmt [const char*] Format for string.
1771 ** @param [v] [...] Variable length argument list
1772 **
1773 ** @return [AjPStr] Output string
1774 **
1775 ** @error on unsuccessful writing return 0
1776 **
1777 **
1778 ** @release 1.0.0
1779 ** @@
1780 ** NOTE: unsafe may be best to pass a pointer to the pointer new
1781 ** as it passes back 0 if not able to be done
1782 ******************************************************************************/
1783
ajFmtPrintS(AjPStr * pthis,const char * fmt,...)1784 AjPStr ajFmtPrintS(AjPStr *pthis, const char *fmt, ...)
1785 {
1786 AjPStr thys;
1787 va_list ap;
1788
1789 va_start(ap, fmt);
1790
1791 ajStrSetRes(pthis, 32);
1792 thys = *pthis;
1793
1794 thys->Len = ajFmtVfmtStrCL(&thys->Ptr, 0, &thys->Res, fmt, ap);
1795
1796 va_end(ap);
1797
1798 return thys;
1799 }
1800
1801
1802
1803
1804 /* @func ajFmtVPrintS *********************************************************
1805 **
1806 ** Formats the "..." arguments into an AjPStr according to fmt.
1807 ** If AjPStr is not large enough then if it is the only one i.e
1808 ** Use = 1 then increase till it fits. Else return 0 if it does not
1809 ** fit. If it fits return the address of the new AjPStr.
1810 **
1811 ** @param [u] pthis [AjPStr*] String to be written too.
1812 ** @param [r] fmt [const char*] Format for string.
1813 ** @param [v] ap [va_list] Variable length argument list
1814 **
1815 ** @return [AjPStr] Output string
1816 **
1817 ** @error on unsuccessful writing return 0
1818 **
1819 **
1820 ** @release 2.7.0
1821 ** @@
1822 ** NOTE: unsafe may be best to pass a pointer to the pointer new
1823 ** as it passes back 0 if not able to be done
1824 ******************************************************************************/
1825
ajFmtVPrintS(AjPStr * pthis,const char * fmt,va_list ap)1826 AjPStr ajFmtVPrintS(AjPStr *pthis, const char *fmt, va_list ap)
1827 {
1828 AjPStr thys;
1829
1830 ajStrSetRes(pthis, 32);
1831 thys = *pthis;
1832
1833 thys->Len = ajFmtVfmtStrCL(&thys->Ptr, 0, &thys->Res, fmt, ap);
1834
1835 return thys;
1836 }
1837
1838
1839
1840
1841 /* @func ajFmtPrintAppS *******************************************************
1842 **
1843 ** Formats the "..." arguments and appends to an AjPStr according to fmt.
1844 ** If AjPStr is not large enough then if it is the only one i.e
1845 ** Use = 1 then increase till it fits. Else return 0 if it does not
1846 ** fit. If it fits return the address of the new AjPStr.
1847 **
1848 ** @param [u] pthis [AjPStr*] String to be written too.
1849 ** @param [r] fmt [const char*] Format for string.
1850 ** @param [v] [...] Variable length argument list
1851 **
1852 ** @return [AjPStr] Output string.
1853 **
1854 ** @error on unsuccessful writing return 0
1855 **
1856 **
1857 ** @release 1.0.0
1858 ** @@
1859 ******************************************************************************/
1860
ajFmtPrintAppS(AjPStr * pthis,const char * fmt,...)1861 AjPStr ajFmtPrintAppS(AjPStr *pthis, const char *fmt, ...)
1862 {
1863 AjPStr thys;
1864 va_list ap;
1865 ajint len;
1866
1867 va_start(ap, fmt);
1868
1869 ajStrSetRes(pthis, 32);
1870 thys = *pthis;
1871
1872 len = ajFmtVfmtStrCL(&thys->Ptr, thys->Len, &thys->Res, fmt, ap);
1873
1874 thys->Len += len;
1875
1876 va_end(ap);
1877
1878 return thys;
1879 }
1880
1881
1882
1883
1884 /* @func ajFmtVfmtStrCL *******************************************************
1885 **
1886 ** Same as ajFmtPrintCL but takes arguments from the list ap.
1887 **
1888 ** @param [w] pbuf [char**] char string to be written to.
1889 ** @param [r] pos [ajint] position in buffer to start writing
1890 ** @param [u] size [size_t*] allocated size of the buffer
1891 ** @param [r] fmt [const char*] Format string.
1892 ** @param [v] ap [va_list] Variable length argument list.
1893 **
1894 ** @return [] [ajint] number of characters written to buf.
1895 **
1896 **
1897 ** @release 2.4.0
1898 ** @@
1899 ******************************************************************************/
1900
ajFmtVfmtStrCL(char ** pbuf,ajint pos,size_t * size,const char * fmt,va_list ap)1901 ajint ajFmtVfmtStrCL(char **pbuf, ajint pos, size_t *size,
1902 const char *fmt, va_list ap)
1903 {
1904 FmtOBuf cl;
1905
1906 assert(*pbuf);
1907 assert(*size > 0);
1908 assert(fmt);
1909
1910 cl.buf = *pbuf;
1911 cl.bp = cl.buf + pos;
1912 cl.size = *size;
1913 cl.fixed = ajFalse;
1914
1915 ajFmtVfmt(fmtAppend, &cl, fmt, ap);
1916 fmtAppend(0, &cl);
1917
1918 *size = cl.size;
1919 *pbuf = cl.buf;
1920
1921 return cl.bp - cl.buf - 1 - pos;
1922 }
1923
1924
1925
1926
1927 /* @func ajFmtVfmtCL **********************************************************
1928 **
1929 ** Same as ajFmtPrintCL but takes arguments from the list ap.
1930 **
1931 ** @param [w] buf [char*] char string to be written to.
1932 ** @param [r] size [ajint] length of buffer
1933 ** @param [r] fmt [const char*] Format string.
1934 ** @param [v] ap [va_list] Variable length argument list.
1935 **
1936 ** @return [] [ajint] number of characters written to buf.
1937 **
1938 **
1939 ** @release 1.0.0
1940 ** @@
1941 ******************************************************************************/
1942
ajFmtVfmtCL(char * buf,ajint size,const char * fmt,va_list ap)1943 ajint ajFmtVfmtCL(char *buf, ajint size, const char *fmt, va_list ap)
1944 {
1945 FmtOBuf cl;
1946
1947 assert(buf);
1948 assert(size > 0);
1949 assert(fmt);
1950
1951 cl.buf = cl.bp = buf;
1952 cl.size = size;
1953 cl.fixed = ajTrue;
1954
1955 ajFmtVfmt(fmtInsert, &cl, fmt, ap);
1956 fmtInsert(0, &cl);
1957
1958 return cl.bp - cl.buf - 1;
1959 }
1960
1961
1962
1963
1964 /* @func ajFmtString **********************************************************
1965 **
1966 ** formats the "..." arguments into a null-terminated string according to
1967 ** fmt and returns that string.
1968 **
1969 ** @param [r] fmt [const char*] Format string
1970 ** @param [v] [...] Variable length argument list
1971 **
1972 ** @return [char*] Output string.
1973 **
1974 **
1975 ** @release 1.0.0
1976 ** @@
1977 ******************************************************************************/
1978
ajFmtString(const char * fmt,...)1979 char* ajFmtString(const char *fmt, ...)
1980 {
1981 char *str;
1982 va_list ap;
1983
1984 assert(fmt);
1985 va_start(ap, fmt);
1986 str = ajFmtVString(fmt, ap);
1987 va_end(ap);
1988
1989 return str;
1990 }
1991
1992
1993
1994
1995 /* @func ajFmtVString *********************************************************
1996 **
1997 ** as ajFmtString but takes arguments from the list ap.
1998 **
1999 ** @param [r] fmt [const char*] Format string.
2000 ** @param [v] ap [va_list] Variable length argument list.
2001 **
2002 ** @return [char*] Output string.
2003 **
2004 **
2005 ** @release 1.0.0
2006 ** @@
2007 ******************************************************************************/
2008
ajFmtVString(const char * fmt,va_list ap)2009 char* ajFmtVString(const char *fmt, va_list ap)
2010 {
2011 FmtOBuf cl;
2012
2013 assert(fmt);
2014
2015 cl.size = 256;
2016 cl.buf = cl.bp = AJALLOC(cl.size);
2017 cl.fixed = ajFalse;
2018
2019 ajFmtVfmt(fmtAppend, &cl, fmt, ap);
2020 fmtAppend(0, &cl);
2021
2022 return AJRESIZE(cl.buf, cl.bp - cl.buf);
2023 }
2024
2025
2026
2027
2028 /* @func ajFmtVfmt ************************************************************
2029 **
2030 ** as ajFmtPrint but takes arguments from the list ap.
2031 **
2032 ** @param [f] put [int function] Standard function
2033 ** @param [u] cl [void*] Where we are going to write the results
2034 ** @param [r] fmt [const char*] Format string
2035 ** @param [v] ap [va_list] Variable argument list
2036 ** @return [void]
2037 **
2038 ** @release 1.0.0
2039 ** @@
2040 ******************************************************************************/
2041
ajFmtVfmt(int (* put)(int c,void * cl),void * cl,const char * fmt,va_list ap)2042 void ajFmtVfmt(int (*put) (int c, void *cl), void *cl, const char *fmt,
2043 va_list ap)
2044 {
2045 assert(put);
2046 assert(fmt);
2047 assert(cl);
2048
2049 while(*fmt)
2050 {
2051 if(*fmt != '%' || *++fmt == '%') /* %% just outputs '%' */
2052 (*put) ((unsigned char) *fmt++, cl);
2053 else
2054 {
2055 /* we have a % - get working on the format */
2056 unsigned char c;
2057 ajint flags[256];
2058 ajint width = INT_MIN, precision = INT_MIN;
2059
2060 memset(flags, '\0', sizeof flags);
2061
2062 if(Fmt_flags)
2063 {
2064 /* look for any conversion flags */
2065 unsigned char cc = *fmt;
2066
2067 for( ; (int) cc && strchr(Fmt_flags, cc); cc = *++fmt)
2068 {
2069 assert(flags[(int) cc] < 255);
2070 flags[(int) cc]++;
2071 }
2072 }
2073
2074 if(*fmt == '*' || isdigit((int) *fmt))
2075 {
2076 ajint n;
2077
2078 if(*fmt == '*')
2079 {
2080 /* '*' width = ajint arg */
2081 n = va_arg(ap, int);
2082 assert(n != INT_MIN);
2083 fmt++;
2084 }
2085 else
2086 for(n = 0; isdigit((int) *fmt); fmt++)
2087 {
2088 ajint d = *fmt - '0';
2089 assert(n <= (INT_MAX - d) / 10);
2090 n = 10 * n + d;
2091 }
2092
2093 width = n;
2094 }
2095
2096 if(*fmt == '.' && (*++fmt == '*' || isdigit((int) *fmt)))
2097 {
2098 ajint n;
2099
2100 if(*fmt == '*')
2101 { /* '*' precision = ajint arg */
2102 n = va_arg(ap, int);
2103 assert(n != INT_MIN);
2104 fmt++;
2105 }
2106 else
2107 for(n = 0; isdigit((int) *fmt); fmt++)
2108 {
2109 ajint d = *fmt - '0';
2110 assert(n <= (INT_MAX - d) / 10);
2111 n = 10 * n + d;
2112 }
2113
2114 precision = n;
2115 }
2116
2117 if(*fmt == 'l' || *fmt == 'L'|| *fmt == 'h')
2118 {
2119 /* size modifiers, L is also lower case string */
2120 assert(flags[(int) *fmt] < 255); /* store as flags - */
2121 /* values do not clash */
2122 flags[(int) *fmt]++;
2123 fmt++;
2124 }
2125
2126 if(*fmt == 'U')
2127 {
2128 /* upper case */
2129 assert(flags[(int) *fmt] < 255); /* store as flags - */
2130 flags[(int) *fmt]++;
2131 fmt++;
2132 }
2133
2134 /* finally, next character is the code */
2135 c = *fmt++;
2136
2137 /* Calling funclist Fmt_T() */
2138
2139 if(!cvt[(int) c])
2140 ajDie("Bad format %%%c", c);
2141 (*cvt[(int) c]) (c, VA_P(ap), put, cl, (ajuint *) flags, width,
2142 precision);
2143 }
2144 }
2145
2146 return;
2147 }
2148
2149
2150
2151
2152 /* #funcstatic fmtRegister ****************************************************
2153 **
2154 ** Registers 'newcvt' as the conversion routine for format code 'code'
2155 **
2156 ** #param [r] code [ajint] value of char to be replaced
2157 ** #param [f] newcvt [Fmt_T] new routine for conversion
2158 **
2159 ** #return [Fmt_T] old value
2160 ** ##
2161 ******************************************************************************/
2162
2163 /*
2164 //static Fmt_T fmtRegister(ajint code, Fmt_T newcvt)
2165 //{
2166 // Fmt_T old;
2167 //
2168 // assert(0 < code && code < (ajint) (sizeof (cvt) / sizeof (cvt[0])));
2169 // old = cvt[code];
2170 // cvt[code] = newcvt;
2171 //
2172 // return old;
2173 //}
2174 //
2175 */
2176
2177
2178
2179
2180 /* @func ajFmtPutd ************************************************************
2181 **
2182 ** Given a string containing a number in full, converts it using the width
2183 ** and precision values.
2184 **
2185 ** @param [r] str [const char*] Text to write.
2186 ** @param [r] len [ajint] Text length.
2187 ** @param [f] put [int function] Standard function.
2188 ** @param [u] cl [void*] Standard - where to write the output
2189 ** @param [r] flags [const ajuint*] Flags (after the %)
2190 ** @param [r] width [ajint] Width (before the dot)
2191 ** @param [r] precision [ajint] Precision (after the dot)
2192 ** @return [void]
2193 **
2194 ** @release 1.0.0
2195 ** @@
2196 ******************************************************************************/
2197
ajFmtPutd(const char * str,ajint len,int (* put)(int c,void * cl),void * cl,const ajuint * flags,ajint width,ajint precision)2198 void ajFmtPutd(const char *str, ajint len, int (*put) (int c, void *cl),
2199 void *cl, const ajuint *flags, ajint width,
2200 ajint precision)
2201 {
2202 ajint sign;
2203
2204 ajuint minusflag = flags['-'];
2205
2206 assert(str);
2207 assert(len >= 0);
2208 assert(flags);
2209
2210 if(width == INT_MIN)
2211 width = 0;
2212
2213 if(width < 0)
2214 {
2215 minusflag = 1;
2216 width = -width;
2217 }
2218
2219
2220 if(len > 0 && (*str == '-' || *str == '+'))
2221 {
2222 sign = *str++;
2223 len--;
2224 }
2225 else if(flags['+'])
2226 sign = '+';
2227 else if(flags[' '])
2228 sign = ' ';
2229 else
2230 sign = 0;
2231
2232 {
2233 ajint n;
2234 ajint j = 0;
2235
2236 if(precision < 0)
2237 precision = 1;
2238
2239 if(len < precision)
2240 n = precision;
2241 /* else if(precision == 0 && len == 1 && str[0] == '0')
2242 n = 0; */
2243 else
2244 n = len;
2245
2246 if(sign)
2247 n++;
2248
2249 if(flags['#'] && flags['0'])
2250 {
2251 /* make space for the padding */
2252 if(*str == '0' && *(str + 1) == 'x')
2253 {
2254 (*put) ((unsigned char) *str++, cl);
2255 (*put) ((unsigned char) *str++, cl);
2256 j += 2;
2257 }
2258 }
2259
2260 if(flags['-'])
2261 {
2262 if(sign)
2263 (*put) (sign, cl);
2264 }
2265 else if(flags['0'])
2266 {
2267 if(sign)
2268 (*put) (sign, cl);
2269 pad(width - n, '0');
2270 }
2271 else
2272 {
2273 pad(width - n, ' ');
2274 if(sign)
2275 (*put) (sign, cl);
2276 }
2277
2278 /* pad for precision - should be turned off for %g */
2279 pad(precision - len, '0');
2280
2281 {
2282 ajint i;
2283
2284 for(i = j; i < len; i++)
2285 (*put) ((unsigned char) *str++, cl);
2286 }
2287
2288 if(minusflag)
2289 pad(width - n, ' ');
2290 }
2291
2292 return;
2293 }
2294
2295
2296
2297
2298 /* @func ajFmtPrintSplit ******************************************************
2299 **
2300 ** Block and print a string. String is split at given delimiters
2301 **
2302 ** @param [u] outf [AjPFile] output stream
2303 ** @param [r] str [const AjPStr] text to write
2304 ** @param [r] prefix [const char *] prefix string
2305 ** @param [r] len [ajint] maximum span
2306 ** @param [r] delim [const char *] delimiter string
2307 ** @return [void]
2308 **
2309 ** @release 1.8.0
2310 ** @@
2311 ******************************************************************************/
2312
ajFmtPrintSplit(AjPFile outf,const AjPStr str,const char * prefix,ajint len,const char * delim)2313 void ajFmtPrintSplit(AjPFile outf, const AjPStr str,
2314 const char *prefix, ajint len,
2315 const char *delim)
2316 {
2317 AjPStrTok handle = NULL;
2318 AjPStr token = NULL;
2319 AjPStr tmp = NULL;
2320 AjPStr tmp2 = NULL;
2321
2322 ajint n = 0;
2323 ajint l = 0;
2324 ajint c = 0;
2325
2326 if(!outf)
2327 return;
2328
2329 token = ajStrNew();
2330 tmp = ajStrNewC("");
2331
2332 handle = ajStrTokenNewC(str, delim);
2333
2334 while(ajStrTokenNextParse(handle, &token))
2335 {
2336 if(!c)
2337 ajFmtPrintF(outf, "%s", prefix);
2338
2339 if((l = n + ajStrGetLen(token)) < len)
2340 {
2341 if(c++)
2342 ajStrAppendC(&tmp, " ");
2343
2344 ajStrAppendS(&tmp, token);
2345
2346 if(c != 1)
2347 n = ++l;
2348 else
2349 n = l;
2350 }
2351 else
2352 {
2353 ajFmtPrintF(outf, "%S\n", tmp);
2354 ajStrAssignS(&tmp, token);
2355 ajStrAppendC(&tmp, " ");
2356 n = ajStrGetLen(token) + 1;
2357 c = 0;
2358 }
2359 }
2360
2361 if(c)
2362 ajFmtPrintF(outf, "%S\n", tmp);
2363 else
2364 {
2365 n = ajStrGetLen(tmp);
2366 ajStrAssignSubS(&tmp2, tmp, 0, n - 2);
2367 ajFmtPrintF(outf, "%s%S\n", prefix, tmp2);
2368 ajStrDel(&tmp2);
2369 }
2370
2371
2372 ajStrTokenDel(&handle);
2373 ajStrDel(&token);
2374 ajStrDel(&tmp);
2375
2376 return;
2377 }
2378
2379
2380
2381
2382 /* @func ajFmtScanS ***********************************************************
2383 **
2384 ** Scan a string according to fmt and load the ... variable pointers
2385 ** Like C function sscanf.
2386 **
2387 ** @param [r] thys [const AjPStr] String.
2388 ** @param [r] fmt [const char*] Format string.
2389 ** @param [v] [...] Variable length argument list
2390 ** @return [ajint] number of successful conversions
2391 **
2392 ** @release 1.10.0
2393 ** @@
2394 ******************************************************************************/
2395
ajFmtScanS(const AjPStr thys,const char * fmt,...)2396 ajint ajFmtScanS(const AjPStr thys, const char *fmt, ...)
2397 {
2398 va_list ap;
2399 ajint n;
2400
2401 va_start(ap, fmt);
2402 n = fmtVscan(thys->Ptr, fmt, ap);
2403 va_end(ap);
2404
2405 return n;
2406 }
2407
2408
2409
2410
2411 /* @func ajFmtScanC ***********************************************************
2412 **
2413 ** Scan a string according to fmt and load the ... variable pointers
2414 ** Like C function sscanf.
2415 **
2416 ** @param [r] thys [const char*] String.
2417 ** @param [r] fmt [const char*] Format string.
2418 ** @param [v] [...] Variable length argument list
2419 ** @return [ajint] number of successful conversions
2420 **
2421 ** @release 2.8.0
2422 ** @@
2423 ******************************************************************************/
2424
ajFmtScanC(const char * thys,const char * fmt,...)2425 ajint ajFmtScanC(const char *thys, const char *fmt, ...)
2426 {
2427 va_list ap;
2428 ajint n;
2429
2430 va_start(ap, fmt);
2431 n = fmtVscan(thys, fmt, ap);
2432 va_end(ap);
2433
2434 return n;
2435 }
2436
2437
2438
2439
2440 /* @func ajFmtScanF ***********************************************************
2441 **
2442 ** Scan an AjPFile object according to fmt and load the ... variable pointers
2443 ** Like C function fscanf.
2444 **
2445 ** @param [u] thys [AjPFile] Input file object
2446 ** @param [r] fmt [const char*] Format string.
2447 ** @param [v] [...] Variable length argument list
2448 ** @return [ajint] number of successful conversions
2449 **
2450 ** @release 3.0.0
2451 ** @@
2452 ******************************************************************************/
2453
ajFmtScanF(AjPFile thys,const char * fmt,...)2454 ajint ajFmtScanF(AjPFile thys, const char *fmt, ...)
2455 {
2456 va_list ap;
2457 ajint n;
2458 FILE *file;
2459
2460 if(!thys)
2461 return 0;
2462
2463 file = ajFileGetFileptr(thys);
2464
2465 va_start(ap, fmt);
2466 n = fmtVfscanf(file, fmt, ap);
2467 va_end(ap);
2468
2469 return n;
2470 }
2471
2472
2473
2474
2475 /* @funcstatic fmtVfscanf ****************************************************
2476 **
2477 ** EMBOSS version of C99 vfscanf() including %S conversion
2478 **
2479 ** @param [u] stream [FILE*] file pointer.
2480 ** @param [r] fmt [const char*] Format string.
2481 ** @param [v] ap [va_list] Variable length argument list
2482 ** @return [ajint] number of successful conversions
2483 **
2484 ** @release 6.4.0
2485 ** @@
2486 ******************************************************************************/
2487
fmtVfscanf(FILE * stream,const char * fmt,va_list ap)2488 static ajint fmtVfscanf(FILE *stream, const char *fmt, va_list ap)
2489 {
2490 char fch = '\0';
2491 int ipc = 0;
2492 int tpc = 0;
2493
2494 ajuint uflags = 0;
2495 ajint nconv = 0;
2496 ajint width = 0;
2497 AjBool fin = ajFalse;
2498 AjBool idone = ajFalse;
2499
2500 ajulong sum = 0L;
2501
2502 ajuint nread = 0;
2503 ajint ret = EOF;
2504 ajint base = 10;
2505
2506 char *p = NULL;
2507 char fchars[] = "0123456789Ee.";
2508
2509 char buf[EVF_BUF];
2510
2511 AjPStr *str = NULL;
2512
2513 union
2514 {
2515 ajlong L;
2516 long l;
2517 unsigned long ul;
2518 ajulong uL;
2519 ajint i;
2520 ajuint u;
2521 char *c;
2522 double d;
2523 } val;
2524
2525
2526 if(feof(stream))
2527 return EOF;
2528
2529 val.ul = 0L;
2530
2531 while((fch = *fmt))
2532 {
2533 ++fmt;
2534
2535
2536 if(uflags & EVF_PERCENT)
2537 {
2538 /* If %% has been given then do a simple match */
2539 if(fch == '%')
2540 {
2541 uflags &= ~EVF_PERCENT;
2542
2543 if((ipc = getc(stream)) == EOF)
2544 break;
2545
2546 ++sum;
2547
2548 if(ipc != (int) fch)
2549 break;
2550
2551 continue;
2552 }
2553
2554 /* Now in the realm of format specifiers */
2555 /* First test for any width */
2556
2557 if(fch >= '0' && fch <= '0')
2558 {
2559 fch -= '0';
2560
2561 if(width == INT_MAX)
2562 width = 0;
2563 else
2564 width *= 10;
2565
2566 width += (ajint) fch;
2567
2568 continue;
2569 }
2570
2571 if((char) fch != 'S')
2572 fch = tolower((int)fch);
2573
2574 switch(fch)
2575 {
2576 case '*':
2577 uflags |= EVF_NOCON;
2578 continue;
2579
2580 case 'n':
2581 if(!(uflags & EVF_NOCON))
2582 *(va_arg(ap, ajint *)) = (ajint) sum;
2583
2584 break;
2585
2586 case 'c':
2587 if(!(uflags & EVF_NOCON))
2588 val.c = va_arg(ap, char *);
2589
2590 if(width == INT_MAX)
2591 width = 1;
2592
2593 while(width-- > 0)
2594 {
2595 if((ipc = getc(stream)) == EOF)
2596 {
2597 fin = ajTrue;
2598 break;
2599 }
2600
2601 ++nread;
2602
2603 if(!(uflags & EVF_NOCON))
2604 *val.c++ = (char) ipc;
2605 }
2606
2607 break;
2608
2609 case 'h': /* ANSI C converts shorts to ints */
2610 continue;
2611
2612 case 'l':
2613 uflags |= EVF_LONG;
2614 continue;
2615
2616 case 'L':
2617 uflags |= EVF_AJLONG;
2618 continue;
2619
2620 case 's':
2621 if(!(uflags & EVF_NOCON))
2622 val.c = va_arg(ap, char *);
2623
2624 do
2625 {
2626 ipc = getc(stream);
2627 ++sum;
2628 } while(isspace(ipc));
2629
2630 if(ipc == EOF)
2631 {
2632 fin = ajTrue;
2633 break;
2634 }
2635
2636 while(width-- > 0)
2637 {
2638 if(isspace(ipc))
2639 {
2640 ungetc(ipc, stream);
2641 --sum;
2642 break;
2643 }
2644
2645 if(!(uflags & EVF_NOCON))
2646 *val.c++ = (char) ipc;
2647
2648 if((ipc = getc(stream)) == EOF)
2649 break;
2650
2651 ++nread;
2652 }
2653
2654 if(!(uflags & EVF_NOCON))
2655 *val.c = '\0';
2656
2657 break;
2658
2659 case 'S':
2660 if(!(uflags & EVF_NOCON))
2661 {
2662 str = (AjPStr *) va_arg(ap, AjPStr *);
2663 ajStrAssignC(str, "");
2664 }
2665
2666 do
2667 {
2668 ipc = getc(stream);
2669 ++sum;
2670 } while(isspace(ipc));
2671
2672 if(ipc == EOF)
2673 {
2674 fin = ajTrue;
2675 break;
2676 }
2677
2678 while(width-- > 0)
2679 {
2680 if(isspace(ipc))
2681 {
2682 ungetc(ipc, stream);
2683 --sum;
2684 break;
2685 }
2686
2687 if(!(uflags & EVF_NOCON))
2688 ajStrAppendK(str, (char) ipc);
2689
2690 if((ipc = getc(stream)) == EOF)
2691 break;
2692
2693 ++nread;
2694 }
2695
2696 break;
2697
2698 case 'o':
2699 base = 8;
2700 /* Fallthrough */
2701 case 'x':
2702 if(base == 10) /* To protect fallthrough from octal */
2703 base = 16;
2704 /* Fallthrough */
2705 case 'u':
2706 uflags |= EVF_UNSIGNED;
2707 /* Fallthrough */
2708 case 'd':
2709 case 'i':
2710 do
2711 {
2712 ipc = getc(stream);
2713 ++sum;
2714 } while(isspace(ipc));
2715
2716 if(ipc == EOF)
2717 {
2718 fin = ajTrue;
2719 break;
2720 }
2721
2722 if((char) ipc == '+' || (char) ipc == '-')
2723 {
2724 if(--width <= 0)
2725 {
2726 fin = ajTrue;
2727 break;
2728 }
2729
2730 if((char) ipc == '-')
2731 uflags |= EVF_NEGATE;
2732
2733 if((ipc = getc(stream)) == EOF)
2734 {
2735 fin = ajTrue;
2736 break;
2737 }
2738
2739 ++sum;
2740 }
2741
2742 idone = ajFalse;
2743 val.uL = 0;
2744
2745 if((char) ipc == '0')
2746 {
2747 if(--width <= 0)
2748 idone = ajTrue;
2749
2750 if(!idone)
2751 if((ipc = getc(stream)) == EOF)
2752 idone = ajTrue;
2753
2754 if((char) tolower(ipc) == 'x' && !idone)
2755 {
2756 if(fch == 'o' || fch == 'd' || fch == 'u')
2757 {
2758 /* Invalid 0x */
2759 ungetc(ipc, stream);
2760 idone = ajTrue;
2761 }
2762
2763 if(!idone)
2764 base = 16;
2765
2766 if(!idone)
2767 {
2768 if((ipc = getc(stream)) == EOF)
2769 idone = ajTrue;
2770 else
2771 ++sum;
2772 }
2773 }
2774 else if(fch == 'i' && !idone)
2775 base = 8;
2776 }
2777
2778 ++nread;
2779
2780 for(; !idone;)
2781 {
2782 tpc = tolower(ipc);
2783
2784 tpc -= '0';
2785
2786 if(tpc > 9)
2787 {
2788 tpc += '0';
2789 tpc -= 'a';
2790
2791 if(tpc >= 0)
2792 tpc += 10;
2793 }
2794
2795 if(tpc < 0 || tpc >= base)
2796 {
2797 ungetc(ipc, stream);
2798 --nread;
2799 break;
2800 }
2801
2802 val.uL *= base;
2803 val.uL += tpc;
2804
2805 if(--width <= 0)
2806 break;
2807
2808 if((ipc = getc(stream)) == EOF)
2809 break;
2810
2811 ++nread;
2812 }
2813
2814 if((uflags & EVF_NEGATE) && !idone)
2815 val.L = -val.L;
2816
2817 if(!(uflags & EVF_NOCON))
2818 {
2819 if((uflags & (EVF_UNSIGNED | EVF_AJLONG)) ==
2820 (EVF_UNSIGNED | EVF_AJLONG))
2821 *(va_arg(ap, ajulong *)) = val.uL;
2822 else if(uflags & (EVF_AJLONG))
2823 *(va_arg(ap, ajlong *)) = val.L;
2824 else if((uflags & (EVF_UNSIGNED | EVF_LONG)) ==
2825 (EVF_UNSIGNED | EVF_LONG))
2826 *(va_arg(ap, unsigned long *)) = val.ul;
2827 else if(uflags & (EVF_LONG))
2828 *(va_arg(ap, long *)) = val.l;
2829 else if(uflags & (EVF_UNSIGNED))
2830 *(va_arg(ap, ajuint *)) = val.u;
2831 else
2832 *(va_arg(ap, ajint *)) = val.i;
2833 }
2834
2835 break;
2836
2837 case 'e':
2838 case 'f':
2839 case 'g':
2840 do
2841 {
2842 ipc = getc(stream);
2843 ++sum;
2844 } while(isspace(ipc));
2845
2846 if(ipc == EOF)
2847 {
2848 --sum;
2849 fin = ajTrue;
2850 break;
2851 }
2852
2853 if((char) ipc == '+' || (char) ipc == '-')
2854 {
2855 if((char) ipc == '-')
2856 uflags |= EVF_NEGATE;
2857
2858 if((ipc = getc(stream)) == EOF)
2859 {
2860 fin = ajTrue;
2861 break;
2862 }
2863
2864 ++sum;
2865 }
2866
2867 val.d = 0.0;
2868
2869 ++nread;
2870
2871 for(p = buf; p < buf + EVF_BUF - 1 && width > 0; --width)
2872 {
2873 if(!strchr(fchars, ipc))
2874 {
2875 ungetc(ipc, stream);
2876 --nread;
2877 break;
2878 }
2879
2880 if((char) ipc == 'e' || (char) ipc == 'E')
2881 {
2882 fchars[10] = '\0';
2883 *p++ = (char) ipc;
2884
2885 if((ipc = getc(stream)) == EOF)
2886 break;
2887
2888 ++nread;
2889
2890 if((char) ipc != '+' && (char) ipc != '-')
2891 continue;
2892 }
2893 else if((char) ipc == '.')
2894 fchars[12] = '\0';
2895
2896 *p++ = (char) ipc;
2897
2898 if((ipc = getc(stream)) == EOF)
2899 break;
2900
2901 ++nread;
2902 }
2903
2904 *p++ = '\0';
2905
2906 val.d = strtod(buf, 0);
2907
2908 if(uflags & EVF_NEGATE)
2909 val.d = -val.d;
2910
2911 fchars[10] = 'E';
2912 fchars[12] = '.';
2913
2914 *(va_arg(ap, double *)) = val.d;
2915
2916 break;
2917 }
2918
2919 if(fin)
2920 break;
2921
2922 if(nread)
2923 {
2924 if(!(uflags & EVF_NOCON))
2925 ++nconv;
2926
2927 ret = 0;
2928 sum += nread;
2929 }
2930 else if(fch != 'n' || ipc == EOF)
2931 break;
2932
2933 uflags = 0;
2934 }
2935 else if(fch == '%')
2936 {
2937 uflags = EVF_PERCENT;
2938 base = 10;
2939 nread = 0;
2940 width = INT_MAX;
2941 }
2942 else if(isspace((int)fch))
2943 {
2944 do
2945 {
2946 ipc = getc(stream);
2947 ++sum;
2948 } while(isspace(ipc));
2949
2950 --sum;
2951
2952 if(ipc == EOF)
2953 break;
2954
2955 ungetc(ipc, stream);
2956 }
2957 else
2958 {
2959 if((ipc = getc(stream)) == EOF)
2960 break;
2961
2962 ++sum;
2963
2964 if(ipc != (int) fch)
2965 break;
2966 }
2967
2968 }
2969
2970 if((uflags & EVF_PERCENT) && nread)
2971 {
2972 if(!(uflags & EVF_NOCON))
2973 ++nconv;
2974
2975 ret = 0;
2976 }
2977
2978 if(ipc == EOF && nconv == 0)
2979 return ret;
2980
2981
2982 return nconv;
2983 }
2984
2985
2986
2987
2988 /* @funcstatic fmtVscan *******************************************************
2989 **
2990 ** Scan a string according to fmt and load the va_list variable pointers
2991 **
2992 ** @param [r] thys [const char*] String.
2993 ** @param [r] fmt [const char*] Format string.
2994 ** @param [v] ap [va_list] Variable length argument list
2995 ** @return [ajint] number of successful conversions
2996 **
2997 ** @release 2.8.0
2998 ** @@
2999 ******************************************************************************/
3000
fmtVscan(const char * thys,const char * fmt,va_list ap)3001 static ajint fmtVscan(const char *thys, const char *fmt, va_list ap)
3002 {
3003 ajint n;
3004 const char *p;
3005 const char *q;
3006 static const char *wspace = " \n\t";
3007 AjBool convert = ajTrue;
3008 AjBool ok = ajTrue;
3009 ajint width = 0;
3010 ajint v = 0;
3011 ajint d = 0;
3012
3013 n = 0;
3014
3015 /* we update it as a pointer */
3016 p = (const char *) thys;
3017 q = fmt;
3018
3019 while(*p && *q)
3020 {
3021 /* Ignore all whitespace */
3022 if(c_isin((ajint) *p, wspace))
3023 {
3024 ++p;
3025 continue;
3026 }
3027
3028 if(c_isin((ajint) *q, wspace))
3029 {
3030 ++q;
3031 continue;
3032 }
3033
3034 /* If *q isn't '%' then it must match *p */
3035 if(*q != '%')
3036 {
3037 if(*q != *p)
3038 break;
3039 else
3040 {
3041 ++p;
3042 ++q;
3043 continue;
3044 }
3045 }
3046
3047 /* Check for %% */
3048 if(*(++q) == '%')
3049 {
3050 if(*p != '%')
3051 break;
3052 else
3053 {
3054 ++p;
3055 ++q;
3056 continue;
3057 }
3058 }
3059
3060
3061 /*
3062 ** *p now points to a string character to be matched
3063 ** *q points to first character after fmt '%'
3064 */
3065
3066 /* Check for %* format */
3067 convert = ajTrue;
3068 if(*q == '*')
3069 {
3070 ++q;
3071 convert = ajFalse;
3072 }
3073
3074 /* If *q is a numeral then calculate the width else set to INT_MIN */
3075 if(isdigit((int) *q))
3076 {
3077 for(v = 0; isdigit((int) *q); ++q)
3078 {
3079 d = *q - '0';
3080 v = 10 * v + d;
3081 }
3082 width = v;
3083 }
3084 else
3085 width = INT_MIN;
3086
3087 /* Just ignore size modifier for now */
3088 if(*q == 'l' || *q == 'L' || *q == 'h')
3089 ++q;
3090
3091 /* *q is the conversion function to call */
3092 ok = ajTrue;
3093
3094 /* Calling funclist Fmt_S() */
3095 if(!scvt[(int) *q])
3096 ajDie("Bad scan format %%%c", q);
3097 (*scvt[(int) *q]) (q, &p, VA_P(ap), width, convert, &ok);
3098
3099 if(!ok)
3100 break;
3101
3102 if(convert)
3103 ++n;
3104
3105 /*
3106 ** p will already have been incremented by the convert function
3107 ** so just increment q
3108 */
3109 ++q;
3110 }
3111
3112 return n;
3113 }
3114
3115
3116
3117
3118 /* @funcstatic scvt_uS ********************************************************
3119 **
3120 ** Conversion for %S to load a string
3121 **
3122 ** @param [r] fmt [const char*] Format string at conv char position
3123 ** @param [w] pos [const char**] Input string current position
3124 ** @param [r] ap [VALIST] Original arguments at current position
3125 ** @param [r] width [ajint] Width
3126 ** @param [r] convert [AjBool] ajFalse if %* was specified
3127 ** @param [w] ok [AjBool*] set for a successful conversion
3128 ** @return [void]
3129 **
3130 ** @release 1.13.0
3131 ** @@
3132 ******************************************************************************/
3133
scvt_uS(const char * fmt,const char ** pos,VALIST ap,ajint width,AjBool convert,AjBool * ok)3134 static void scvt_uS(const char *fmt, const char **pos, VALIST ap, ajint width,
3135 AjBool convert, AjBool *ok)
3136 {
3137 const char *p;
3138 const char *q;
3139 AjPStr *val = NULL;
3140 static const char *wspace = " \n\t";
3141 ajint c = 0;
3142
3143 (void) fmt; /* make it used */
3144
3145 p = *pos;
3146
3147 *ok = ajFalse;
3148
3149 if(width != INT_MIN)
3150 for(q = p; *q && c_notin((int) *q, wspace) && c < width; ++q, ++c);
3151 else
3152 for(q = p; *q && c_notin((int) *q, wspace); ++q);
3153
3154 if(q - p)
3155 {
3156 if(convert)
3157 {
3158 val = (AjPStr *) va_arg(VA_V(ap), AjPStr *);
3159 ajStrAssignSubC(val, p, 0, q - p - 1);
3160 }
3161
3162 *pos = q;
3163 *ok = ajTrue;
3164 }
3165
3166 return;
3167 }
3168
3169
3170
3171
3172 /* @funcstatic scvt_d *********************************************************
3173 **
3174 ** Conversion for %d to load an integer
3175 **
3176 ** @param [r] fmt [const char*] Format string at conv char position
3177 ** @param [w] pos [const char**] Input string current position
3178 ** @param [r] ap [VALIST] Original arguments at current position
3179 ** @param [r] width [ajint] Width
3180 ** @param [r] convert [AjBool] ajFalse if %* was specified
3181 ** @param [w] ok [AjBool*] set for a successful conversion
3182 ** @return [void]
3183 **
3184 ** @release 1.10.0
3185 ** @@
3186 ******************************************************************************/
3187
scvt_d(const char * fmt,const char ** pos,VALIST ap,ajint width,AjBool convert,AjBool * ok)3188 static void scvt_d(const char *fmt, const char **pos, VALIST ap, ajint width,
3189 AjBool convert, AjBool *ok)
3190 {
3191 const char *p;
3192 const char *q;
3193 long *val = NULL;
3194 ajlong *hval = NULL;
3195 static const char *wspace = " \n\t";
3196 static const char *dig1 = "+-0123456789";
3197 ajint c = 0;
3198 AjPStr t = NULL;
3199 long n = 0;
3200 ajlong hn = 0;
3201 char flag;
3202 ajint beg = 1;
3203
3204 p = *pos;
3205 flag = *(fmt - 1);
3206
3207 *ok = ajFalse;
3208
3209 if(width != INT_MIN)
3210 for(q = p; *q && c_notin((int) *q, wspace) && c<width; ++q, ++c)
3211 {
3212 if(beg)
3213 {
3214 beg = 0;
3215 if(!c_isin((int) *q, dig1))
3216 break;
3217 }
3218 else
3219 {
3220 if(!isdigit((int) *q))
3221 break;
3222 }
3223 }
3224 else
3225 for(q = p; *q && c_notin((int) *q, wspace); ++q)
3226 {
3227 if(beg)
3228 {
3229 beg = 0;
3230 if(!c_isin((int) *q, dig1))
3231 break;
3232 }
3233 else
3234 {
3235 if(!isdigit((int) *q))
3236 break;
3237 }
3238 }
3239
3240 if(q - p)
3241 {
3242 if(convert)
3243 {
3244 if(flag != 'L')
3245 val = (long *) va_arg(VA_V(ap), long *);
3246 else
3247 hval = (ajlong *) va_arg(VA_V(ap), ajlong *);
3248
3249 ajStrAssignSubC(&t, p, 0, q - p - 1);
3250
3251 if(flag != 'L')
3252 sscanf(ajStrGetPtr(t), "%ld", &n);
3253
3254 else /* flag == 'L' define hn */
3255 {
3256 #if defined(HAVE64)
3257 hn = sc_long(ajStrGetPtr(t));
3258 #else /* !HAVE64 */
3259 val = (long *) hval;
3260 sscanf(ajStrGetPtr(t), "%ld", &n);
3261 hn = n;
3262 /* ajDebug("Warning: Use of %%Ld on a 32 bit model"); */
3263 #endif /* HAVE64 */
3264 }
3265 ajStrDel(&t);
3266
3267 if(flag == 'h')
3268 *(short *) val = (short) n;
3269 else if(flag == 'l')
3270 *(long *) val = n;
3271 else if(flag == 'L')
3272 *(ajlong *) hval = hn;
3273 else
3274 *(int *) val = (int) n;
3275 }
3276
3277 *pos = q;
3278 *ok = ajTrue;
3279 }
3280 return;
3281 }
3282
3283
3284
3285
3286 /* @funcstatic scvt_x *********************************************************
3287 **
3288 ** Conversion for %x to load an unsigned hexadecimal
3289 **
3290 ** @param [r] fmt [const char*] Format string at conv char position
3291 ** @param [w] pos [const char**] Input string current position
3292 ** @param [r] ap [VALIST] Original arguments at current position
3293 ** @param [r] width [ajint] Width
3294 ** @param [r] convert [AjBool] ajFalse if %* was specified
3295 ** @param [w] ok [AjBool*] set for a successful conversion
3296 ** @return [void]
3297 **
3298 ** @release 1.10.0
3299 ** @@
3300 ******************************************************************************/
3301
scvt_x(const char * fmt,const char ** pos,VALIST ap,ajint width,AjBool convert,AjBool * ok)3302 static void scvt_x(const char *fmt, const char **pos, VALIST ap, ajint width,
3303 AjBool convert, AjBool *ok)
3304 {
3305 const char *p;
3306 const char *q;
3307 unsigned long *val = NULL;
3308 ajulong *hval = NULL;
3309 static const char *wspace = " \n\t";
3310 static const char *dig = "0123456789abcdefABCDEFx";
3311 ajint c = 0;
3312 AjPStr t = NULL;
3313 unsigned long n = 0;
3314 ajulong hn = 0;
3315 char flag;
3316
3317 p = *pos;
3318 flag = *(fmt - 1);
3319
3320 *ok = ajFalse;
3321
3322 if(width != INT_MIN)
3323 for(q = p; *q && c_notin((int) *q, wspace) && c < width &&
3324 c_isin((int) *q, dig); ++q, ++c);
3325 else
3326 for(q = p; *q && c_notin((int) *q, wspace) && c_isin((int) *q, dig);
3327 ++q);
3328
3329 if(q - p)
3330 {
3331 if(convert)
3332 {
3333 if(flag != 'L')
3334 val = (unsigned long *) va_arg(VA_V(ap), unsigned long *);
3335 else
3336 hval = (ajulong *) va_arg(VA_V(ap), ajulong *);
3337
3338 ajStrAssignSubC(&t, p, 0, q - p - 1);
3339
3340 if(flag != 'L')
3341 {
3342 if(sscanf(ajStrGetPtr(t), "%lx", &n) != 1)
3343 {
3344 ajStrDel(&t);
3345
3346 return;
3347 }
3348 }
3349 else /* flag == 'L' define hn */
3350 {
3351 #if defined(HAVE64)
3352 hn = sc_hex(ajStrGetPtr(t));
3353 #else /* !HAVE64 */
3354 val = (unsigned long *) hval;
3355
3356 if(sscanf(ajStrGetPtr(t), "%lx", &n) != 1)
3357 {
3358 ajStrDel(&t);
3359
3360 return;
3361 }
3362
3363
3364 hn = n;
3365 /* ajDebug("Warning: Use of %%Lx on a 32 bit model"); */
3366 #endif /* HAVE64 */
3367 }
3368 ajStrDel(&t);
3369
3370 if(flag == 'h')
3371 *(unsigned short *) val = (unsigned short) n;
3372 else if(flag == 'l')
3373 *(unsigned long *) val = n;
3374 else if(flag == 'L')
3375 *(ajulong *) hval = hn;
3376 else
3377 *(unsigned int *) val = (unsigned int) n;
3378 }
3379
3380 *pos = q;
3381 *ok = ajTrue;
3382 }
3383
3384 return;
3385 }
3386
3387
3388
3389
3390 /* @funcstatic scvt_f *********************************************************
3391 **
3392 ** Conversion for %f to load a float or double
3393 **
3394 ** @param [r] fmt [const char*] Format string at conv char position
3395 ** @param [w] pos [const char**] Input string current position
3396 ** @param [r] ap [VALIST] Original arguments at current position
3397 ** @param [r] width [ajint] Width
3398 ** @param [r] convert [AjBool] ajFalse if %* was specified
3399 ** @param [w] ok [AjBool*] set for a successful conversion
3400 ** @return [void]
3401 **
3402 ** @release 1.10.0
3403 ** @@
3404 ******************************************************************************/
3405
scvt_f(const char * fmt,const char ** pos,VALIST ap,ajint width,AjBool convert,AjBool * ok)3406 static void scvt_f(const char *fmt, const char **pos, VALIST ap, ajint width,
3407 AjBool convert, AjBool *ok)
3408 {
3409 const char *p;
3410 const char *q;
3411 double *val;
3412 float *fval;
3413 static const char *wspace = " \n\t";
3414 static const char *dig1 = "+-0123456789.eE";
3415 static const char *dig2 = "0123456789.eE";
3416 ajint c = 0;
3417 AjPStr t = NULL;
3418 double n = (double) 0.;
3419 float fn = 0.;
3420 char flag;
3421 ajint beg = 1;
3422
3423 p = *pos;
3424 flag = *(fmt - 1);
3425
3426 *ok = ajFalse;
3427
3428 if(width != INT_MIN)
3429 for(q = p; *q && c_notin((int) *q, wspace) && c < width; ++q, ++c)
3430 {
3431 if(beg)
3432 {
3433 beg = 0;
3434 if(!c_isin((int) *q, dig1))
3435 break;
3436 }
3437 else
3438 {
3439 if(!c_isin((int) *q, dig2))
3440 break;
3441 }
3442 }
3443 else
3444 for(q = p; *q && c_notin((int) *q, wspace); ++q)
3445 {
3446 if(beg)
3447 {
3448 beg = 0;
3449 if(!c_isin((int) *q, dig1))
3450 break;
3451 }
3452 else
3453 {
3454 if(!c_isin((int) *q, dig2))
3455 break;
3456 }
3457 }
3458
3459 if(q - p)
3460 {
3461 if(convert)
3462 {
3463 ajStrAssignSubC(&t, p, 0, q - p - 1);
3464
3465 if(flag == 'l')
3466 {
3467 val = (double *) va_arg(VA_V(ap), double *);
3468
3469 if(sscanf(ajStrGetPtr(t), "%lf", &n) != 1)
3470 {
3471 ajStrDel(&t);
3472
3473 return;
3474 }
3475
3476 *(double *) val = n;
3477 }
3478 else
3479 {
3480 fval = (float *) va_arg(VA_V(ap), float *);
3481
3482 if(sscanf(ajStrGetPtr(t), "%f", &fn) != 1)
3483 {
3484 ajStrDel(&t);
3485
3486 return;
3487 }
3488
3489 *(float *) fval = fn;
3490 }
3491
3492 ajStrDel(&t);
3493 }
3494
3495 *pos = q;
3496 *ok = ajTrue;
3497 }
3498
3499 return;
3500 }
3501
3502
3503
3504
3505 /* @funcstatic scvt_s *********************************************************
3506 **
3507 ** Conversion for %s to load a char *
3508 **
3509 ** @param [r] fmt [const char*] Format string at conv char position
3510 ** @param [w] pos [const char**] Input string current position
3511 ** @param [r] ap [VALIST] Original arguments at current position
3512 ** @param [r] width [ajint] Width
3513 ** @param [r] convert [AjBool] ajFalse if %* was specified
3514 ** @param [w] ok [AjBool*] set for a successful conversion
3515 ** @return [void]
3516 **
3517 ** @release 1.10.0
3518 ** @@
3519 ******************************************************************************/
3520
scvt_s(const char * fmt,const char ** pos,VALIST ap,ajint width,AjBool convert,AjBool * ok)3521 static void scvt_s(const char *fmt, const char **pos, VALIST ap, ajint width,
3522 AjBool convert, AjBool *ok)
3523 {
3524 const char *p;
3525 const char *q;
3526 char *val = NULL;
3527 static const char *wspace = " \n\t";
3528 ajint c = 0;
3529 AjPStr t = NULL;
3530
3531 (void) fmt; /* make it used */
3532
3533 p = *pos;
3534
3535 *ok = ajFalse;
3536
3537 if(width != INT_MIN)
3538 for(q = p; *q && c_notin((int) *q, wspace) && c < width; ++q, ++c);
3539 else
3540 for(q = p; *q && c_notin((int) *q, wspace); ++q);
3541
3542 if(q - p)
3543 {
3544 if(convert)
3545 {
3546 val = (char *) va_arg(VA_V(ap), char *);
3547 ajStrAssignSubC(&t, p, 0, q - p - 1);
3548 strcpy(val, ajStrGetPtr(t));
3549 ajStrDel(&t);
3550 }
3551
3552 *pos = q;
3553 *ok = ajTrue;
3554 }
3555
3556 return;
3557 }
3558
3559
3560
3561
3562 /* @funcstatic scvt_o *********************************************************
3563 **
3564 ** Conversion for %o to load an unsigned octal
3565 **
3566 ** @param [r] fmt [const char*] Format string at conv char position
3567 ** @param [w] pos [const char**] Input string current position
3568 ** @param [r] ap [VALIST] Original arguments at current position
3569 ** @param [r] width [ajint] Width
3570 ** @param [r] convert [AjBool] ajFalse if %* was specified
3571 ** @param [w] ok [AjBool*] set for a successful conversion
3572 ** @return [void]
3573 **
3574 ** @release 1.10.0
3575 ** @@
3576 ******************************************************************************/
3577
scvt_o(const char * fmt,const char ** pos,VALIST ap,ajint width,AjBool convert,AjBool * ok)3578 static void scvt_o(const char *fmt, const char **pos, VALIST ap, ajint width,
3579 AjBool convert, AjBool *ok)
3580 {
3581 const char *p;
3582 const char *q;
3583 unsigned long *val = NULL;
3584 ajulong *hval = NULL;
3585 static const char *wspace = " \n\t";
3586 static const char *dig = "01234567";
3587 ajint c = 0;
3588 AjPStr t = NULL;
3589 unsigned long n = 0;
3590 ajulong hn = 0;
3591 char flag;
3592
3593 p = *pos;
3594 flag = *(fmt - 1);
3595
3596 if(!t)
3597 t = ajStrNew();
3598
3599 *ok = ajFalse;
3600
3601 if(width != INT_MIN)
3602 for(q = p; *q && c_notin((int) *q, wspace) && c < width &&
3603 c_isin((int) *q, dig); ++q, ++c);
3604 else
3605 for(q = p; *q && c_notin((int) *q, wspace) && c_isin((int) *q, dig);
3606 ++q);
3607
3608 if(q - p)
3609 {
3610 if(convert)
3611 {
3612 if(flag != 'L')
3613 val = (unsigned long *) va_arg(VA_V(ap), unsigned long *);
3614 else
3615 hval = (ajulong *) va_arg(VA_V(ap), ajulong *);
3616
3617 ajStrAssignSubC(&t, p, 0, q - p - 1);
3618
3619 if(flag != 'L')
3620 {
3621 if(sscanf(ajStrGetPtr(t), "%lo", &n) != 1)
3622 {
3623 ajStrDel(&t);
3624
3625 return;
3626 }
3627 }
3628 else /* flag == 'L' define hn */
3629 {
3630 #if defined(HAVE64)
3631 hn = sc_octal(ajStrGetPtr(t));
3632 #else /* !HAVE64 */
3633 val = (unsigned long *) hval;
3634
3635 if(sscanf(ajStrGetPtr(t), "%lo", &n) != 1)
3636 {
3637 ajStrDel(&t);
3638
3639 return;
3640 }
3641
3642 hn = n;
3643 /* ajDebug("Warning: Use of %%Lo on a 32 bit model"); */
3644 #endif /* HAVE64 */
3645 }
3646
3647 if(flag == 'h')
3648 *(unsigned short *) val = (unsigned short) n;
3649 else if(flag == 'l')
3650 *(unsigned long *) val = n;
3651 else if(flag == 'L')
3652 *(ajulong *) hval = hn;
3653 else
3654 *(unsigned int *) val = (unsigned int) n;
3655 }
3656
3657 *pos = q;
3658 *ok = ajTrue;
3659 }
3660
3661 ajStrDel(&t);
3662
3663 return;
3664 }
3665
3666
3667
3668
3669 /* @funcstatic scvt_u *********************************************************
3670 **
3671 ** Conversion for %u to load an unsigned integer
3672 **
3673 ** @param [r] fmt [const char*] Format string at conv char position
3674 ** @param [w] pos [const char**] Input string current position
3675 ** @param [r] ap [VALIST] Original arguments at current position
3676 ** @param [r] width [ajint] Width
3677 ** @param [r] convert [AjBool] ajFalse if %* was specified
3678 ** @param [w] ok [AjBool*] set for a successful conversion
3679 ** @return [void]
3680 **
3681 ** @release 1.10.0
3682 ** @@
3683 ******************************************************************************/
3684
scvt_u(const char * fmt,const char ** pos,VALIST ap,ajint width,AjBool convert,AjBool * ok)3685 static void scvt_u(const char *fmt, const char **pos, VALIST ap, ajint width,
3686 AjBool convert, AjBool *ok)
3687 {
3688 const char *p;
3689 const char *q;
3690 unsigned long *val = NULL;
3691 ajulong *hval = NULL;
3692 static const char *wspace = " \n\t";
3693 static const char *dig = "+0123456789";
3694 ajint c = 0;
3695 AjPStr t = NULL;
3696 unsigned long n = 0;
3697
3698 ajulong hn = 0;
3699 char flag;
3700
3701 p = *pos;
3702 flag = *(fmt - 1);
3703
3704 if(!t)
3705 t = ajStrNew();
3706
3707 *ok = ajFalse;
3708
3709 if(width != INT_MIN)
3710 for(q = p; *q && c_notin((int) *q, wspace) && c < width &&
3711 c_isin((int) *q, dig); ++q, ++c);
3712 else
3713 for(q = p; *q && c_notin((int) *q, wspace) && c_isin((int) *q, dig);
3714 ++q);
3715
3716 if(q - p)
3717 {
3718 if(convert)
3719 {
3720 if(flag != 'L')
3721 val = (unsigned long *) va_arg(VA_V(ap), unsigned long *);
3722 else
3723 hval = (ajulong *) va_arg(VA_V(ap), ajulong *);
3724
3725 ajStrAssignSubC(&t, p, 0, q - p - 1);
3726
3727 if(flag != 'L')
3728 {
3729 if(sscanf(ajStrGetPtr(t), "%lu", &n) != 1)
3730 {
3731 ajStrDel(&t);
3732
3733 return;
3734 }
3735 }
3736 else /* flag == 'L' define hn */
3737 {
3738 #if defined(HAVE64)
3739 hn = sc_ulong(ajStrGetPtr(t));
3740 #else /* !HAVE64 */
3741 val = (unsigned long *) hval;
3742
3743 if(sscanf(ajStrGetPtr(t), "%lu", &n) != 1)
3744 {
3745 ajStrDel(&t);
3746
3747 return;
3748 }
3749
3750 hn = n;
3751 /* ajDebug("Warning: Use of %%Lu on a 32 bit model"); */
3752 #endif /* HAVE64 */
3753 }
3754
3755
3756 if(flag == 'h')
3757 *(unsigned short *) val = (unsigned short) n;
3758 else if(flag == 'l')
3759 *(unsigned long *) val = n;
3760 else if(flag == 'L')
3761 *(ajulong *) hval = hn;
3762 else
3763 *(unsigned int *) val = (unsigned int) n;
3764 }
3765
3766 *pos = q;
3767 *ok = ajTrue;
3768 }
3769
3770 ajStrDel(&t);
3771
3772 return;
3773 }
3774
3775
3776
3777
3778 /* @funcstatic scvt_p *********************************************************
3779 **
3780 ** Conversion for %p to load a pointer of type void * as hexadecimal
3781 **
3782 ** @param [r] fmt [const char*] Format string at conv char position
3783 ** @param [w] pos [const char**] Input string current position
3784 ** @param [r] ap [VALIST] Original arguments at current position
3785 ** @param [r] width [ajint] Width
3786 ** @param [r] convert [AjBool] ajFalse if %* was specified
3787 ** @param [w] ok [AjBool*] set for a successful conversion
3788 ** @return [void]
3789 **
3790 ** @release 1.10.0
3791 ** @@
3792 ******************************************************************************/
3793
scvt_p(const char * fmt,const char ** pos,VALIST ap,ajint width,AjBool convert,AjBool * ok)3794 static void scvt_p(const char *fmt, const char **pos, VALIST ap, ajint width,
3795 AjBool convert, AjBool *ok)
3796 {
3797 const char *p;
3798 const char *q;
3799 void **val;
3800 static const char *wspace = " \n\t";
3801 static const char *dig = "0123456789abcdefABCDEFx";
3802 ajint c = 0;
3803 AjPStr t = NULL;
3804 unsigned long n = 0;
3805
3806 (void) fmt; /* make it used */
3807
3808 p = *pos;
3809
3810 if(!t)
3811 t = ajStrNew();
3812
3813 *ok = ajFalse;
3814
3815 if(width != INT_MIN)
3816 for(q = p; *q && c_notin((int) *q, wspace) && c < width &&
3817 c_isin((int) *q, dig); ++q, ++c);
3818 else
3819 for(q = p; *q && c_notin((int) *q, wspace) && c_isin((int) *q, dig);
3820 ++q);
3821
3822 if(q - p)
3823 {
3824 if(convert)
3825 {
3826 val = (void **) va_arg(VA_V(ap), void **);
3827 ajStrAssignSubC(&t, p, 0, q - p - 1);
3828
3829 if(sscanf(ajStrGetPtr(t), "%lx", &n) != 1)
3830 return;
3831
3832 *val = (void *) n;
3833 }
3834
3835 *pos = q;
3836 *ok = ajTrue;
3837 }
3838
3839 ajStrDel(&t);
3840
3841 return;
3842 }
3843
3844
3845
3846
3847 /* @funcstatic scvt_uB ********************************************************
3848 **
3849 ** Conversion for %B to load a boolean (integer or YyNnTtFf)
3850 **
3851 ** @param [r] fmt [const char*] Format string at conv char position
3852 ** @param [w] pos [const char**] Input string current position
3853 ** @param [r] ap [VALIST] Original arguments at current position
3854 ** @param [r] width [ajint] Width
3855 ** @param [r] convert [AjBool] ajFalse if %* was specified
3856 ** @param [w] ok [AjBool*] set for a successful conversion
3857 ** @return [void]
3858 **
3859 ** @release 1.13.0
3860 ** @@
3861 ******************************************************************************/
3862
scvt_uB(const char * fmt,const char ** pos,VALIST ap,ajint width,AjBool convert,AjBool * ok)3863 static void scvt_uB(const char *fmt, const char **pos, VALIST ap, ajint width,
3864 AjBool convert, AjBool *ok)
3865 {
3866 const char *p;
3867 const char *q = NULL;
3868 AjBool *val = NULL;
3869 static const char *wspace = " \n\t";
3870 static const char *dig = "+-0123456789";
3871 static const char *tr = "YyTt";
3872 static const char *fa = "NnFf";
3873 ajint c = 0;
3874 AjPStr t = NULL;
3875 AjBool n = ajFalse;
3876
3877 (void) fmt; /* make it used */
3878
3879 p = *pos;
3880
3881 *ok = ajFalse;
3882
3883 q = p;
3884
3885 if(!strncmp(q, "Yes", 3))
3886 {
3887 *pos = q + 3;
3888
3889 if(convert)
3890 {
3891 val = (AjBool *) va_arg(VA_V(ap), AjBool *);
3892 *(AjBool *) val = ajTrue;
3893 }
3894
3895 *ok = ajTrue;
3896
3897 return;
3898 }
3899
3900 if(!strncmp(q, "No", 2))
3901 {
3902 *pos = q + 2;
3903
3904 if(convert)
3905 {
3906 val = (AjBool *) va_arg(VA_V(ap), AjBool *);
3907 *(AjBool *) val = ajFalse;
3908 }
3909
3910 *ok = ajTrue;
3911
3912 return;
3913 }
3914
3915
3916 if(c_isin((int) *q, tr) && (width == INT_MIN || width == 1))
3917 {
3918 if(convert)
3919 {
3920 val = (AjBool *) va_arg(VA_V(ap), AjBool *);
3921 *(AjBool *) val = ajTrue;
3922 }
3923
3924 *pos = ++q;
3925 *ok = ajTrue;
3926
3927 return;
3928 }
3929
3930 if(c_isin((int) *q, fa) && (width == INT_MIN || width == 1))
3931 {
3932 if(convert)
3933 {
3934 val = (AjBool *) va_arg(VA_V(ap), AjBool *);
3935 *(AjBool *) val = ajFalse;
3936 }
3937
3938 *pos = ++q;
3939 *ok = ajTrue;
3940
3941 return;
3942 }
3943
3944
3945 if(width != INT_MIN)
3946 for(q = p; *q && c_notin((int) *q, wspace) && c < width &&
3947 c_isin((int) *q, dig); ++q, ++c);
3948 else
3949 for(q = p; *q && c_notin((int) * q, wspace) && c_isin((int) *q, dig);
3950 ++q);
3951
3952 if(q - p)
3953 {
3954 if(convert)
3955 {
3956 val = (AjBool *) va_arg(VA_V(ap), AjBool *);
3957 ajStrAssignSubC(&t, p, 0, q - p - 1);
3958 sscanf(ajStrGetPtr(t), "%d", &n);
3959
3960 if(n)
3961 *(AjBool *) val = ajTrue;
3962 else
3963 *(AjBool *) val = ajFalse;
3964
3965 ajStrDel(&t);
3966 }
3967
3968 *pos = q;
3969 *ok = ajTrue;
3970 }
3971
3972 return;
3973 }
3974
3975
3976
3977
3978 /* @funcstatic scvt_c *********************************************************
3979 **
3980 ** Conversion for %c to load a character
3981 **
3982 ** @param [r] fmt [const char*] Format string at conv char position
3983 ** @param [w] pos [const char**] Input string current position
3984 ** @param [r] ap [VALIST] Original arguments at current position
3985 ** @param [r] width [ajint] Width
3986 ** @param [r] convert [AjBool] ajFalse if %* was specified
3987 ** @param [w] ok [AjBool*] set for a successful conversion
3988 ** @return [void]
3989 **
3990 ** @release 1.10.0
3991 ** @@
3992 ******************************************************************************/
3993
scvt_c(const char * fmt,const char ** pos,VALIST ap,ajint width,AjBool convert,AjBool * ok)3994 static void scvt_c(const char *fmt, const char **pos, VALIST ap, ajint width,
3995 AjBool convert, AjBool *ok)
3996 {
3997 const char *p;
3998 const char *q;
3999 char *val = NULL;
4000 char n = '\0';
4001
4002 (void) fmt; /* make it used */
4003
4004 p = *pos;
4005 q = p;
4006
4007 *ok = ajFalse;
4008
4009 if(!(width == INT_MIN || width == 1))
4010 return;
4011
4012 if(convert)
4013 {
4014 n = *q;
4015 val = (char *) va_arg(VA_V(ap), char *);
4016 *val = n;
4017 }
4018
4019
4020 *pos = ++q;
4021 *ok = ajTrue;
4022
4023 return;
4024 }
4025
4026
4027
4028
4029 /* @funcstatic scvt_b *********************************************************
4030 **
4031 ** Conversion for %b to load a boolean (YyNnTtFf)
4032 **
4033 ** @param [r] fmt [const char*] Format string at conv char position
4034 ** @param [w] pos [const char**] Input string current position
4035 ** @param [r] ap [VALIST] Original arguments at current position
4036 ** @param [r] width [ajint] Width
4037 ** @param [r] convert [AjBool] ajFalse if %* was specified
4038 ** @param [w] ok [AjBool*] set for a successful conversion
4039 ** @return [void]
4040 **
4041 ** @release 1.10.0
4042 ** @@
4043 ******************************************************************************/
4044
scvt_b(const char * fmt,const char ** pos,VALIST ap,ajint width,AjBool convert,AjBool * ok)4045 static void scvt_b(const char *fmt, const char **pos, VALIST ap, ajint width,
4046 AjBool convert, AjBool *ok)
4047 {
4048 const char *p;
4049 const char *q;
4050 AjBool *val = NULL;
4051 static const char *tr = "YyTt";
4052 static const char *fa = "NnFf";
4053
4054 (void) fmt; /* make it used */
4055
4056 *ok = ajFalse;
4057
4058 p = *pos;
4059 q = p;
4060
4061 if(c_isin((int) *q, tr) && (width == INT_MIN || width == 1))
4062 {
4063 if(convert)
4064 {
4065 val = (AjBool *) va_arg(VA_V(ap), AjBool *);
4066 *(AjBool *) val = ajTrue;
4067 }
4068
4069 *pos = ++q;
4070 *ok = ajTrue;
4071
4072 return;
4073 }
4074
4075 if(c_isin((int) *q, fa) && (width == INT_MIN || width == 1))
4076 {
4077 if(convert)
4078 {
4079 val = (AjBool *) va_arg(VA_V(ap), AjBool *);
4080 *(AjBool *) val = ajFalse;
4081 }
4082
4083 *pos = ++q;
4084 *ok = ajTrue;
4085 }
4086
4087 return;
4088 }
4089
4090
4091
4092
4093 /* @funcstatic scvt_z *********************************************************
4094 **
4095 ** Conversion for %z to load a char **
4096 **
4097 ** @param [r] fmt [const char*] Format string at conv char position
4098 ** @param [w] pos [const char**] Input string current position
4099 ** @param [r] ap [VALIST] Original arguments at current position
4100 ** @param [r] width [ajint] Width
4101 ** @param [r] convert [AjBool] ajFalse if %* was specified
4102 ** @param [w] ok [AjBool*] set for a successful conversion
4103 ** @return [void]
4104 **
4105 ** @release 1.10.0
4106 ** @@
4107 ******************************************************************************/
4108
scvt_z(const char * fmt,const char ** pos,VALIST ap,ajint width,AjBool convert,AjBool * ok)4109 static void scvt_z(const char *fmt, const char **pos, VALIST ap, ajint width,
4110 AjBool convert, AjBool *ok)
4111 {
4112 const char *p;
4113 const char *q;
4114 char **val = NULL;
4115 static const char *wspace = " \n\t";
4116 ajint c = 0;
4117 AjPStr t = NULL;
4118
4119 (void) fmt; /* make it used */
4120
4121 p = *pos;
4122
4123 *ok = ajFalse;
4124
4125 if(width != INT_MIN)
4126 for(q = p; *q && c_notin((int) *q, wspace) && c < width; ++q, ++c);
4127 else
4128 for(q = p; *q && c_notin((int) *q, wspace); ++q);
4129
4130 if(q - p)
4131 {
4132 if(convert)
4133 {
4134 val = (char **) va_arg(VA_V(ap), char **);
4135 ajStrAssignSubC(&t, p, 0, q - p - 1);
4136
4137 if(!*val)
4138 *val = ajCharNewRes(ajStrGetLen(t) + 1);
4139
4140 strcpy(*val, ajStrGetPtr(t));
4141 ajStrDel(&t);
4142 }
4143
4144 *pos = q;
4145 *ok = ajTrue;
4146 }
4147
4148 return;
4149 }
4150
4151
4152
4153
4154 #if defined(HAVE64)
4155 /* @funcstatic sc_long ********************************************************
4156 **
4157 ** Load a 64 bit long from a char*
4158 **
4159 ** @param [r] str [const char*] long number
4160 ** @return [ajlong] result
4161 **
4162 ** @release 1.10.1
4163 ** @@
4164 ******************************************************************************/
4165
sc_long(const char * str)4166 static ajlong sc_long(const char *str)
4167 {
4168 ajlong v = 0;
4169 ajint d;
4170 const char *p;
4171 char c;
4172
4173 p = str;
4174
4175 while((c = *(p++)))
4176 {
4177 d = c - '0';
4178 v = (ajlong) 10 * v + (ajlong) d;
4179 }
4180
4181 return v;
4182 }
4183
4184
4185
4186
4187 /* @funcstatic sc_ulong *******************************************************
4188 **
4189 ** Load a 64 bit unsigned long from a char*
4190 **
4191 ** @param [r] str [const char*] long number
4192 ** @return [ajulong] result
4193 **
4194 ** @release 1.10.1
4195 ** @@
4196 ******************************************************************************/
4197
sc_ulong(const char * str)4198 static ajulong sc_ulong(const char *str)
4199 {
4200 ajulong v = 0;
4201 ajint d;
4202 const char *p;
4203 char c;
4204
4205 p = str;
4206
4207 while((c = *(p++)))
4208 {
4209 d = c - '0';
4210 v = (ajulong) 10 * v + (ajulong) d;
4211 }
4212
4213 return v;
4214 }
4215
4216
4217
4218
4219 /* @funcstatic sc_hex *********************************************************
4220 **
4221 ** Load a 64 bit unsigned long from a char* hexadecimal
4222 **
4223 ** @param [r] str [const char*] long hex number
4224 ** @return [ajulong] result
4225 **
4226 ** @release 1.10.1
4227 ** @@
4228 ******************************************************************************/
4229
sc_hex(const char * str)4230 static ajulong sc_hex(const char *str)
4231 {
4232 ajulong v = 0;
4233 ajint d;
4234 const char *p;
4235 char c;
4236
4237 p = str + 2;
4238
4239 while((c = toupper((int) *(p++))))
4240 {
4241 if(c >= '0' && c <= '9')
4242 d = c - '0';
4243 else
4244 d = c - 'A' + 10;
4245
4246 v = (ajulong) 16 * v + (ajulong) d;
4247 }
4248
4249 return v;
4250 }
4251
4252
4253
4254
4255 /* @funcstatic sc_octal *******************************************************
4256 **
4257 ** Load a 64 bit unsigned long from a char* octal
4258 **
4259 ** @param [r] str [const char*] long hex number
4260 ** @return [ajulong] result
4261 **
4262 ** @release 1.10.1
4263 ** @@
4264 ******************************************************************************/
4265
sc_octal(const char * str)4266 static ajulong sc_octal(const char *str)
4267 {
4268 ajulong v = 0;
4269 ajint d;
4270 const char *p;
4271 char c;
4272
4273 p = str + 1;
4274
4275 while((c = toupper((int) *(p++))))
4276 {
4277 d = c - '0';
4278 v = (ajulong) 8 * v + (ajulong) d;
4279 }
4280
4281 return v;
4282 }
4283 #endif /* HAVE64 */
4284