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