fioLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:82k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* fioLib.c - formatted I/O library */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 06c,24jul02,tpr  Remove sarcastic comment of fioFormatV.
  8. 06b,14mar02,pfl  changed long long arg support to use 'll' format
  9. 06a,21dec01,an   enabled long long arg support for printf/scanf using 'L' format flag 
  10. 05z,17dec01,max  Simple change just to make WRS doctool happy
  11. 05y,20jun01,kab  Code review cleanup
  12. 05x,19apr01,max  printf & scanf support for ALTIVEC vector data types
  13. 05w,14jun99,pai  removed blocking call to printErr() in printExc() (SPR 22735).
  14. 05v,14mar99,jdi  doc: removed refs to config.h and/or configAll.h (SPR 25663).
  15. 05v,05sep97,dgp  doc: fix SPR 9258, remove NOTE from sprintf()
  16. 05u,04oct95,kvk  fix for PPC architecture varargs float problem.
  17. 05t,21sep95,jdi  doc tweak of man page for fioLibInit().
  18. 05s,14may95,p_m  added fioLibInit().
  19. 05r,03feb95,jdi  doc format tweaks.
  20. 05q,24jan95,rhp  doc: avoid 'L' in printf() and sscanf(), no long doubles 
  21.                  in VxWorks (see SPR#3886)
  22. 05p,13jan95,rhp  make self-refs in sscanf man page refer to sscanf, not fscanf
  23. 05o,12jan95,rhp  fix RETURNS section of fioRdString() man page (SPR#2511)
  24. 05n,21nov94,kdl  made scanCharSet() NOMANUAL.
  25. 05m,19jul94,dvs  doc tweak - added stdio.h to list of include files (SPR #2391).
  26. 05l,02dec93,pad  temporary fixed fioFormatV() to avoid a cc29k problem.
  27. 05k,17aug94,ism  fixed problem with assignment suppression (SPR#2562)
  28. -fixed problem with [] not failing when no characters are scanned
  29. -(SPR#3561)
  30. 05j,21oct93,jmm  fixed return value for scanCharSet
  31. 05i,10mar93,jdi  more documentation cleanup for 5.1.
  32. 05h,22jan93,jdi  documentation cleanup for 5.1.
  33. 05g,13nov92,dnw  added include of taskLib.h
  34. 05f,29oct92,jcf  bumped BUF to 400 to format real big numbers.
  35. 05e,01oct92,jcf  fixed printExc().
  36. 05d,02aug92,jcf  moved printExc() to here.
  37. 05c,30jul92,kdl  prevent printing leading zeroes for "Inf", "Nan".
  38. 05b,30jul92,jcf  redone for the new stdio library.
  39.            +smb
  40. 05a,26may92,rrr  the tree shuffle
  41. 04z,10feb92,kdl  fixed scanf %n problems (SPR 1172).
  42. 04y,29jan92,kdl  made fioRdString return EOF in case of read error (SPR 1142);
  43.  changed copyright date.
  44. 04x,10dec91,gae  removed some ANSI warnings.
  45. 04w,04dec91,rrr  removed VARARG_OK, no longer needed with ansi c.
  46. 04v,19nov91,rrr  shut up some ansi warnings.
  47. 04u,04oct91,rrr  passed through the ansification filter
  48.                   -changed functions to ansi style
  49.   -changed includes to have absolute path from h/
  50.   -changed VOID to void
  51.   -changed copyright notice
  52. 04t,14jul91,del  removed va_end in fioScanV.
  53. 04s,09jun91,del  integrated Intel's mods to interface to floatLib.c.
  54. 04r,18may91,gae  fixed sscanf/varargs for 960.
  55.  redid conditionals with VARARG_OK.
  56. 04q,05may91,jdi  documentation tweak.
  57. 04p,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  58.  doc review by dnw.
  59. 04o,24mar91,del  made functions work with gnu960 tools for I960 architecture.
  60. 04n,06feb91,jaa  documentation cleanup.
  61. 04m,05oct90,dnw  documentation
  62. 04l,18sep90,kdl  removed forward declarations for digtobin and fioToUpper.
  63. 04k,08aug90,dnw  changed to call floatFormat with &vaList instead of vaList.
  64.  changed to call floatFormat with sizeof(buffer)-prefix instead
  65.    of sizeof(buffer)
  66. 04j,04jun90,dnw  extensive rewrite/reorg of printf/scanf family of rtns:
  67.    - consolidation and clean-up,
  68.    - adherence to ANSI definitions for format semantics,
  69.    - use varargs correctly,
  70.    - removed all floating pt refs.
  71.  BUG FIXES:
  72.    spr 501: fixed printf precision bug
  73.    spr 640: printf, fdprintf, printErr return num chars printed
  74.    spr 754: vararg routines no longer limited to 16 args
  75.    spr 766: deleted obsolete fioStd{In,Out,Err} routines
  76.    spr 767: scanf, sscanf, fscanf return EOF properly
  77.    unreported: printf with both "left justify" & "0 fill" flags
  78.    would 0 fill to the right! ("5000" instead of "5   ")
  79.  ANSI STANDARD CHANGES, *NOT* COMPATIBLE WITH 4.0.2:
  80.    - scanf %EFG now same as %efg (no longer means "double"!)
  81.    - sprintf returns number of chars in buffer NOT INCLUDING
  82.        EOS (4.0.2 included EOS in count)
  83.    - printf precision parameter only has effect on %s and %efg
  84.  ANSI STANDARD CHANGES, BACKWARD COMPATIBLE:
  85.    - added vprintf, vfprintf, vsprintf vararg routines
  86.    - printf now supports %i %p %n
  87.    - scanf now supports %i %p %n %% %X
  88.    - scanf now allows optional leading "0x"
  89.  OTHER CHANGES:
  90.    - deleted unused internal routines fioToUpper() & digtobin()
  91.    - fioRead() doesn't set S_fioLib_UNEXPECTED_EOF anymore
  92.    - changes to allow void be defined as void
  93. 04i,07mar90,jdi  documentation cleanup.
  94. 04h,09aug89,gae  did varargs stuff right.
  95.     06jul89,ecs  updated to track 4.0.2.
  96.     07sep88,ecs  varargs.
  97.  added include of varargs.h.
  98. 04g,19aug88,gae  documentation.
  99. 04f,13aug88,gae  fixed bug in convert() for E and F.
  100. 04e,30jun88,gae  fixed bug in sscanf () and convert() for number specifier.
  101. 04d,30may88,dnw  changed to v4 names.
  102. 04c,28may88,dnw  removed NOT_GENERIC stuff.
  103.  removed obsolete rtns: bcdtoi,itobcd,atoi,atow,atos,bprintf
  104.  removed obsolete: fioSet{In,Out,Err},
  105.  removed skipHexSpecifier to bootConfig.
  106.  removed skipSpace to bootConfig and bootLib.
  107.  made itob NOMANUAL.
  108.  made digtobin LOCAL.
  109. 04b,21apr88,gae  added conversion of 'g' for scanf().
  110. 04a,02apr88,gae  rewrote convert and support routines to work with stdio.
  111.  changed fprintf() to fdprintf().
  112.  changed fio{Std,Set}{In,Out,Err}() to use new 0,1,2 I/O scheme.
  113.  made putbuf() local.
  114. 03i,16mar88,gae  fixed bug in convert() to return FALSE for invalid specifier.
  115.          fixed fatal bug in atos() of not handling unterminated table.
  116.  made atos() return ERROR when given invalid table.
  117.  sscanf can now do flag:       "<*>".
  118.  sscanf can now do specifiers: "E|F|c|u|o".
  119.  printf can now do flags:      "<+><sp><#>".
  120.  printf can now do specifiers: "u|E|G|X".
  121.  added nindex() and fioToUpper().
  122. 03h,16feb88,llk  fixed sscanf so that it handles double precision floats.
  123. 03g,10dec87,gae  changed some VARARGS routines to have standard "args"
  124.    parameter for parsing by C interface generator.
  125. 03f,16nov87,jcf  added skipHexSpecifier to aid in hex parsing
  126. 03e,05nov87,jlf  documentation
  127. 03d,12oct87,jlf  added [...] strings to scanf.
  128. 03c,01aug87,gae  moved floating-point support to fltLib.c.
  129.  added fioFltInstall().
  130. 03b,31jul87,gae  replaced homebrew atof() with the real thing.
  131.  renamed gcvtb() to gcvt().  fixed bug in ftob().
  132. 03a,07may87,jlf  added floating point support, with #ifdef's.
  133.    +gae  This involved: %e and %f to format() and convert().
  134.  New routines: ecvtb, fcvtb, gcvt, atof, atoe, ftob, etob,
  135.  frexp, ldexp, and modf.
  136. 02x,04apr87,dnw  fixed bug in format() that limited fields to 128 characters.
  137. 02w,23mar87,jlf  documentation.
  138. 02v,17jan87,gae  made timeConvert and format handle 12 hour clock time code.
  139. 02u,20dec86,dnw  changed to not get include files from default directories.
  140. 02t,10oct86,dnw  documentation.
  141. 02s,04sep86,jlf  documentation.
  142. 02r,29jul86,llk  documentation changes
  143. 02q,27jul86,llk  added standard error file descriptor (std_err)
  144.  added fioSetErr, fioStdErr, printErr
  145. 02p,01jul86,jlf  minor documentation
  146. 02o,27mar86,ecs  changed timeConvert to check for legality of time entered.
  147.  changed timeDecode to return integer rather than bcd.
  148. 02n,11mar86,jlf  changed GENERIC stuff to NOT_GENERIC.
  149. */
  150. /*
  151. DESCRIPTION
  152. This library provides the basic formatting and scanning I/O functions.  It
  153. includes some routines from the ANSI-compliant printf()/scanf()
  154. family of routines.  It also includes several utility routines.
  155. If the floating-point format specifications `e', `E', `f', `g', and `G' are
  156. to be used with these routines, the routine floatInit() must be called
  157. first.  If the configuration macro INCLUDE_FLOATING_POINT is defined,
  158. floatInit() is called by the root task, usrRoot(), in usrConfig.c.
  159. These routines do not use the buffered I/O facilities provided by the
  160. standard I/O facility.  Thus, they can be invoked even if the standard I/O
  161. package has not been included.  This includes printf(), which in most UNIX
  162. systems is part of the buffered standard I/O facilities.  Because printf()
  163. is so commonly used, it has been implemented as an unbuffered I/O function.
  164. This allows minimal formatted I/O to be achieved without the overhead of
  165. the entire standard I/O package.  For more information, see the manual
  166. entry for ansiStdio.
  167. INCLUDE FILES: fioLib.h, stdio.h
  168. SEE ALSO: ansiStdio, floatLib,
  169. .pG "I/O System"
  170. */
  171. #include "vxWorks.h"
  172. #include "ctype.h"
  173. #include "errno.h"
  174. #include "ioLib.h"
  175. #include "string.h"
  176. #include "stdarg.h"
  177. #include "limits.h"
  178. #include "stdio.h"
  179. #include "stdlib.h"
  180. #include "unistd.h"
  181. #include "fioLib.h"
  182. #include "intLib.h"
  183. #include "sysLib.h"
  184. #include "qLib.h"
  185. #include "taskLib.h"
  186. #include "private/kernelLibP.h"
  187. #include "private/vmLibP.h"
  188. #include "private/floatioP.h"
  189. /* Macros for converting digits to letters and vice versa */
  190. #define BUF 400 /* buffer for %dfg etc */
  191. #define PADSIZE 16 /* pad chunk size */
  192. #define to_digit(c) ((c) - '0')
  193. #define is_digit(c) ((unsigned)to_digit(c) <= 9)
  194. #define to_char(n) ((n) + '0')
  195. #define PAD(howmany, with) 
  196.     { 
  197.     if ((n = (howmany)) > 0) 
  198. while (n > PADSIZE)
  199.     {
  200.     if ((*outRoutine) (with, PADSIZE, outarg) != OK)
  201. return (ERROR);
  202.     n -= PADSIZE; 
  203.     }
  204. if ((*outRoutine) (with, n, outarg) != OK)
  205.     return (ERROR);
  206. }
  207.     }
  208. /* to extend shorts, signed and unsigned arg extraction methods are needed */
  209. #define SARG() ((doLongLongInt) ? (long long) va_arg(vaList, long long) : 
  210.  (doLongInt) ? (long long)(long)va_arg(vaList, long) : 
  211.  (doShortInt) ? (long long)(short)va_arg(vaList, int) : 
  212.  (long long)(int) va_arg(vaList, int))
  213. #define UARG() ((doLongLongInt) ? (unsigned long long) va_arg(vaList, unsigned long long) : 
  214.  (doLongInt) ? (unsigned long long)(ulong_t)va_arg(vaList,ulong_t):
  215.  (doShortInt) ? (unsigned long long)(ushort_t)va_arg(vaList,int):
  216.  (unsigned long long)(uint_t) va_arg(vaList, uint_t))
  217. #define GET_CHAR(ch, ix)        ((ix)++, (ch) = (* getRtn) (getArg, -1))
  218. #define ll  1 /* long long format */ 
  219. /* globals */
  220. /* The fieldSzIncludeSign indicates whether the sign should be included
  221.  * in the precision of a number.
  222.  */
  223. BOOL fieldSzIncludeSign = TRUE;
  224. /* locals */
  225. LOCAL FUNCPTR fioFltFormatRtn;
  226. LOCAL FUNCPTR fioFltScanRtn;
  227. /* Choose PADSIZE to trade efficiency vs size.  If larger printf fields occur
  228.  * frequently, increase PADSIZE (and make the initialisers below longer).
  229.  */
  230. LOCAL char blanks[PADSIZE] =
  231.     {
  232.     ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '
  233.     };
  234. LOCAL char zeroes[PADSIZE] =
  235.     {
  236.     '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'
  237.     };
  238. /* forwards */
  239. LOCAL int    getbuf (char ** str);
  240. LOCAL STATUS putbuf (char *inbuf, int length, char ** outptr);
  241. LOCAL STATUS printbuf (char *buf, int nbytes, int fd);
  242. /*LOCAL*/ BOOL scanField (const char **ppFmt, void *pReturn, FUNCPTR getRtn, 
  243.       int getArg, BOOL *pSuppress, int *pCh, int *pNchars);
  244. LOCAL BOOL scanChar (char *pResult, int fieldwidth, FUNCPTR getRtn, 
  245.      int getArg, int *pCh, int *pNchars);
  246. LOCAL BOOL scanString (char *pResult, int fieldwidth, FUNCPTR getRtn, 
  247.        int getArg, int *pCh, int *pNchars);
  248. /*LOCAL*/ BOOL scanCharSet (char *pResult, int fieldwidth, 
  249. const char *charsAllowed, FUNCPTR getRtn, 
  250. int getArg, int *pCh, int *pNchars);
  251. LOCAL BOOL scanNum (int base, void *pReturn, int returnSpec, int fieldwidth,
  252.     FUNCPTR getRtn, int getArg, int *pCh, int *pNchars);
  253. /*******************************************************************************
  254. *
  255. * fioLibInit - initialize the formatted I/O support library
  256. *
  257. * This routine initializes the formatted I/O support library.  It should be
  258. * called once in usrRoot() when formatted I/O functions such as printf() and
  259. * scanf() are used.
  260. *
  261. * RETURNS: N/A
  262. */
  263. void fioLibInit (void)
  264.     {
  265.     _func_printErr = (FUNCPTR) printErr;
  266.     }
  267. /*******************************************************************************
  268. *
  269. * fioFltInstall - install routines to print and scan floating-point numbers
  270. *
  271. * This routine is a hook for floatLib to install its special floating-point
  272. * formatting & scanning routines.  It should only be called by floatInit().
  273. *
  274. * NOMANUAL
  275. */
  276. void fioFltInstall
  277.     (
  278.     FUNCPTR formatRtn,          /* routine to format floats for output */
  279.     FUNCPTR scanRtn             /* routine to scan input for floats */
  280.     )
  281.     {
  282.     fioFltFormatRtn = formatRtn;
  283.     fioFltScanRtn   = scanRtn;
  284.     }
  285. /*******************************************************************************
  286. *
  287. * printf - write a formatted string to the standard output stream (ANSI)
  288. *
  289. * This routine writes output to standard output under control of the string
  290. * <fmt>. The string <fmt> contains ordinary characters, which are written
  291. * unchanged, plus conversion specifications, which cause the arguments that
  292. * follow <fmt> to be converted and printed as part of the formatted string.
  293. *
  294. * The number of arguments for the format is arbitrary, but they must
  295. * correspond to the conversion specifications in <fmt>.  If there are
  296. * insufficient arguments, the behavior is undefined.  If the format is
  297. * exhausted while arguments remain, the excess arguments are evaluated but
  298. * otherwise ignored.  The routine returns when the end of the format string
  299. * is encountered.
  300. *
  301. * The format is a multibyte character sequence, beginning and ending in its
  302. * initial shift state.  The format is composed of zero or more directives:
  303. * ordinary multibyte characters (not `%') that are copied unchanged to the
  304. * output stream; and conversion specification, each of which results in
  305. * fetching zero or more subsequent arguments.  Each conversion specification
  306. * is introduced by the `%' character.  After the `%', the following appear in
  307. * sequence:
  308. * .iP "" 4
  309. * Zero or more flags (in any order) that modify the meaning of the 
  310. * conversion specification.
  311. * .iP
  312. * An optional minimum field width.  If the converted value has fewer
  313. * characters than the field width, it will be padded with spaces (by
  314. * default) on the left (or right, if the left adjustment flag, 
  315. * described later, has been given) to the field width. The field
  316. * width takes the form of an asterisk (`*') (described later) or a decimal
  317. * integer.
  318. * .iP
  319. * An optional precision that gives the minimum number of digits to
  320. * appear for the `d', `i', `o', `u', `x', and `X' conversions, the number of 
  321. * digits to appear after the decimal-point character for `e', `E', and `f'
  322. * conversions, the maximum number of significant digits for the `g' and
  323. * `G' conversions, or the maximum number of characters to be written 
  324. * from a string in the `s' conversion.  The precision takes the form of a 
  325. * period (`.') followed either by an asterisk (`*') (described later) or by
  326. * an optional decimal integer; if only the period is specified, the 
  327. * precision is taken as zero.  If a precision appears with any other
  328. * conversion specifier, the behavior is undefined.
  329. * .iP
  330. * An optional `h' specifying that a following `d', `i', `o', `u', `x', and
  331. * `X' conversion specifier applies to a `short int' or `unsigned short int'
  332. * argument (the argument will have been promoted according to the integral
  333. * promotions, and its value converted to `short int' or `unsigned short int'
  334. * before printing); an optional `h' specifying that a following `n' 
  335. * conversion specifier applies to a pointer to a `short int' argument.  An
  336. * optional `l' (ell) specifying that a following `d', `i', `o', `u', `x', and
  337. * `X' conversion specifier applies to a `long int' or `unsigned long int'
  338. * argument; or an optional `l' specifying that a following `n' conversion
  339. * specifier applies to a pointer to a `long int' argument.  An optional `ll' 
  340. * (ell-ell) specifying that a following `d', `i', `o', `u', `x', and
  341. * `X' conversion specifier applies to a `long long int' or `unsigned long 
  342. * long int' argument; or an optional `ll' specifying that a following `n' 
  343. * conversion specifier applies to a pointer to a `long long int' argument.  
  344. * If a `h', `l' or `ll' appears with any other conversion specifier, the 
  345. * behavior is undefined.
  346. * .iP
  347. * &WARNING: ANSI C also specifies an optional `L' in some of the same
  348. * contexts as `l' above, corresponding to a `long double' argument.
  349. * However, the current release of the VxWorks libraries does not support 
  350. * `long double' data; using the optional `L' gives unpredictable results.
  351. * .iP
  352. * A character that specifies the type of conversion to be applied.
  353. * .LP
  354. *
  355. * As noted above, a field width, or precision, or both, can be indicated by
  356. * an asterisk (`*').  In this case, an `int' argument supplies the field width
  357. * or precision.  The arguments specifying field width, or precision, or both,
  358. * should appear (in that order) before the argument (if any) to be converted.
  359. * A negative field width argument is taken as a `-' flag followed by a positive
  360. * field width.  A negative precision argument is taken as if the precision
  361. * were omitted.
  362. *
  363. * The flag characters and their meanings are:
  364. * .iP `-'
  365. * The result of the conversion will be left-justified within the field.
  366. * (it will be right-justified if this flag is not specified.)
  367. * .iP `+'
  368. * The result of a signed conversion will always begin with a plus or 
  369. * minus sign.  (It will begin with a sign only when a negative value
  370. * is converted if this flag is not specified.)
  371. * .iP `space'
  372. * If the first character of a signed conversion is not a sign, or 
  373. * if a signed conversion results in no characters, a space will be 
  374. * prefixed to the result.  If the `space' and `+' flags both appear, the
  375. * `space' flag will be ignored.
  376. * .iP `#'
  377. * The result is to be converted to an "alternate form."  For `o' conversion
  378. * it increases the precision to force the first digit of the result to be a
  379. * zero.  For `x' (or `X') conversion, a non-zero result will have "0x" (or
  380. * "0X") prefixed to it.  For `e', `E', `f', `g', and `g' conversions, the
  381. * result will always contain a decimal-point character, even if no digits
  382. * follow it.  (Normally, a decimal-point character appears in the result of
  383. * these conversions only if no digit follows it).  For `g' and `G'
  384. * conversions, trailing zeros will not be removed from the result.  For
  385. * other conversions, the behavior is undefined.
  386. * .iP `0'
  387. * For `d', `i', `o', `u', `x', `X', `e', `E', `f', `g', and `G' conversions,
  388. * leading zeros (following any indication of sign or base) are used to pad
  389. * to the field width; no space padding is performed.  If the `0' and `-'
  390. * flags both appear, the `0' flag will be ignored.  For `d', `i', `o', `u',
  391. * `x', and `X' conversions, if a precision is specified, the `0' flag will
  392. * be ignored.  For other conversions, the behavior is undefined.
  393. * .LP
  394. *
  395. * The conversion specifiers and their meanings are:
  396. * .iP "`d', `i'"
  397. * The `int' argument is converted to signed decimal in the style
  398. * `[-]dddd'.  The precision specifies the minimum number of digits 
  399. * to appear; if the value being converted can be represented in
  400. * fewer digits, it will be expanded with leading zeros.  The
  401. * default precision is 1.  The result of converting a zero value
  402. * with a precision of zero is no characters.
  403. * .iP "`o', `u', `x', `X'"
  404. * The `unsigned int' argument is converted to unsigned octal (`o'),
  405. * unsigned decimal (`u'), or unsigned hexadecimal notation (`x' or `X')
  406. * in the style `dddd'; the letters abcdef are used for `x' conversion
  407. * and the letters ABCDEF for `X' conversion.  The precision specifies
  408. * the minimum number of digits to appear; if the value being 
  409. * converted can be represented in fewer digits, it will be 
  410. * expanded with leading zeros.  The default precision is 1.  The
  411. * result of converting a zero value with a precision of zero is 
  412. * no characters.
  413. * .iP `f'
  414. * The `double' argument is converted to decimal notation in the 
  415. * style `[-]ddd.ddd', where the number of digits after the decimal
  416. * point character is equal to the precision specification.  If the
  417. * precision is missing, it is taken as 6; if the precision is zero
  418. * and the `#' flag is not specified, no decimal-point character
  419. * appears.  If a decimal-point character appears, at least one 
  420. * digit appears before it.  The value is rounded to the appropriate
  421. * number of digits.
  422. * .iP "`e', `E'"
  423. * The `double' argument is converted in the style `[-]d.ddde+/-dd',
  424. * where there is one digit before the decimal-point character 
  425. * (which is non-zero if the argument is non-zero) and the number
  426. * of digits after it is equal to the precision; if the precision
  427. * is missing, it is taken as 6; if the precision is zero and the 
  428. * `#' flag is not specified, no decimal-point character appears.  The
  429. * value is rounded to the appropriate number of digits.  The `E'
  430. * conversion specifier will produce a number with `E' instead of `e'
  431. * introducing the exponent.  The exponent always contains at least
  432. * two digits.  If the value is zero, the exponent is zero.
  433. * .iP "`g', `G'"
  434. * The `double' argument is converted in style `f' or `e' (or in style 
  435. * `E' in the case of a `G' conversion specifier), with the precision
  436. * specifying the number of significant digits.  If the precision
  437. * is zero, it is taken as 1.  The style used depends on the 
  438. * value converted; style `e' (or `E') will be used only if the 
  439. * exponent resulting from such a conversion is less than -4 or 
  440. * greater than or equal to the precision.  Trailing zeros are
  441. * removed from the fractional portion of the result; a decimal-point
  442. * character appears only if it is followed by a digit.
  443. * .iP `c'
  444. * The `int' argument is converted to an `unsigned char', and the 
  445. * resulting character is written.
  446. * .iP `s'
  447. * The argument should be a pointer to an array of character type.
  448. * Characters from the array are written up to (but not including)
  449. * a terminating null character; if the precision is specified,
  450. * no more than that many characters are written.  If the precision
  451. * is not specified or is greater than the size of the array, the
  452. * array will contain a null character.
  453. * .iP `p'
  454. * The argument should be a pointer to `void'.  The value of the 
  455. * pointer is converted to a sequence of printable characters,
  456. * in hexadecimal representation (prefixed with "0x").
  457. * .iP `n'
  458. * The argument should be a pointer to an integer into which
  459. * the number of characters written to the output stream
  460. * so far by this call to fprintf() is written.  No argument is converted.
  461. * .iP `%'
  462. * A `%' is written.  No argument is converted.  The complete
  463. * conversion specification is %%.
  464. * .LP
  465. *
  466. * If a conversion specification is invalid, the behavior is undefined.
  467. *
  468. * If any argument is, or points to, a union or an aggregate (except for an 
  469. * array of character type using `s' conversion, or a pointer using `p' 
  470. * conversion), the behavior is undefined.
  471. *
  472. * In no case does a non-existent or small field width cause truncation of a
  473. * field if the result of a conversion is wider than the field width, the
  474. * field is expanded to contain the conversion result.
  475. *
  476. * INCLUDE FILES: fioLib.h 
  477. *
  478. * RETURNS:
  479. * The number of characters written, or a negative value if an
  480. * output error occurs.
  481. *
  482. * SEE ALSO: fprintf(),
  483. * .I "American National Standard for Information Systems -"
  484. * .I "Programming Language - C, ANSI X3.159-1989: Input/Output (stdio.h)"
  485. *
  486. * VARARGS1
  487. */
  488. int printf
  489.     (
  490.     const char *  fmt, /* format string to write */
  491.     ...       /* optional arguments to format string */
  492.     )
  493.     {
  494.     va_list vaList; /* traverses argument list */
  495.     int nChars;
  496.     va_start (vaList, fmt);
  497.     nChars = fioFormatV (fmt, vaList, printbuf, 1);
  498.     va_end (vaList);
  499.     return (nChars);
  500.     }
  501. /*******************************************************************************
  502. *
  503. * printErr - write a formatted string to the standard error stream
  504. *
  505. * This routine writes a formatted string to standard error.  Its function and
  506. * syntax are otherwise identical to printf().
  507. *
  508. * RETURNS: The number of characters output, or ERROR if there is an error
  509. * during output.
  510. *
  511. * SEE ALSO: printf()
  512. *
  513. * VARARGS1
  514. */
  515. int printErr
  516.     (
  517.     const char *  fmt,  /* format string to write */
  518.     ...       /* optional arguments to format */
  519.     )
  520.     {
  521.     va_list vaList; /* traverses argument list */
  522.     int nChars;
  523.     va_start (vaList, fmt);
  524.     nChars = fioFormatV (fmt, vaList, printbuf, 2);
  525.     va_end (vaList);
  526.     return (nChars);
  527.     }
  528. /*******************************************************************************
  529. *
  530. * printExc - print error message
  531. *
  532. * If at interrupt level or other invalid/fatal state, then "print"
  533. * into System Exception Message area.
  534. *
  535. * NOMANUAL
  536. */
  537. void printExc (fmt, arg1, arg2, arg3, arg4, arg5)
  538.     char *fmt; /* format string */
  539.     int arg1;
  540.     int arg2;
  541.     int arg3;
  542.     int arg4;
  543.     int arg5;
  544.     {
  545.     UINT state;
  546.     int pageSize;
  547.     char * pageAddr;
  548.     if ((INT_CONTEXT ()) || (Q_FIRST (&activeQHead) == NULL))
  549. {
  550. /* Exception happened during exception processing, or before
  551.  * any task could be initialized. Tack the message onto the end
  552.  * of a well-known location. 
  553.  */
  554. /* see if we need to write enable the memory */
  555. if (vmLibInfo.vmLibInstalled)
  556.     {
  557.     pageSize = VM_PAGE_SIZE_GET();
  558.     pageAddr = (char *) ((UINT) sysExcMsg / pageSize * pageSize);
  559.     if ((VM_STATE_GET (NULL, (void *) pageAddr, &state) != ERROR) &&
  560. ((state & VM_STATE_MASK_WRITABLE) == VM_STATE_WRITABLE_NOT))
  561. {
  562. TASK_SAFE(); /* safe from deletion */
  563. VM_STATE_SET (NULL, pageAddr, pageSize, VM_STATE_MASK_WRITABLE,
  564.       VM_STATE_WRITABLE);
  565. sysExcMsg += sprintf (sysExcMsg,fmt,arg1,arg2,arg3,arg4,arg5);
  566. VM_STATE_SET (NULL, pageAddr, pageSize, VM_STATE_MASK_WRITABLE,
  567.       VM_STATE_WRITABLE_NOT);
  568. TASK_UNSAFE(); /* unsafe from deletion */
  569. return;
  570. }
  571.     }
  572. sysExcMsg += sprintf (sysExcMsg, fmt, arg1, arg2, arg3, arg4, arg5);
  573. }
  574.     else
  575.         {
  576.         /* queue printErr() so that we do not block here (SPR 22735) */
  577.         excJobAdd ((VOIDFUNCPTR)printErr, (int)fmt, arg1,arg2,arg3,arg4,arg5);
  578.         }
  579.     }
  580. /*******************************************************************************
  581. *
  582. * fdprintf - write a formatted string to a file descriptor
  583. *
  584. * This routine writes a formatted string to a specified file descriptor.  Its
  585. * function and syntax are otherwise identical to printf().
  586. *
  587. * RETURNS: The number of characters output, or ERROR if there is an error
  588. * during output.
  589. *
  590. * SEE ALSO: printf()
  591. *
  592. * VARARGS2
  593. */
  594. int fdprintf
  595.     (
  596.     int fd, /* file descriptor to write to */
  597.     const char *  fmt, /* format string to write */
  598.     ... /* optional arguments to format */
  599.     )
  600.     {
  601.     va_list vaList; /* traverses argument list */
  602.     int nChars;
  603.     va_start (vaList, fmt);
  604.     nChars = fioFormatV (fmt, vaList, printbuf, fd);
  605.     va_end (vaList);
  606.     return (nChars);
  607.     }
  608. /*******************************************************************************
  609. *
  610. * sprintf - write a formatted string to a buffer (ANSI)
  611. *
  612. * This routine copies a formatted string to a specified buffer, which is
  613. * null-terminated.  Its function and syntax are otherwise identical
  614. * to printf().
  615. *
  616. * RETURNS:
  617. * The number of characters copied to <buffer>, not including the NULL 
  618. * terminator.
  619. *
  620. * SEE ALSO: printf(),
  621. * .I "American National Standard for Information Systems -"
  622. * .I "Programming Language - C, ANSI X3.159-1989: Input/Output (stdio.h)"
  623. *
  624. * VARARGS2
  625. */
  626. int sprintf
  627.     (
  628.     char *  buffer, /* buffer to write to */
  629.     const char *  fmt, /* format string */
  630.     ... /* optional arguments to format */
  631.     )
  632.     {
  633.     va_list vaList; /* traverses argument list */
  634.     int nChars;
  635.     va_start (vaList, fmt);
  636.     nChars = fioFormatV (fmt, vaList, putbuf, (int) &buffer);
  637.     va_end (vaList);
  638.     *buffer = EOS;
  639.     return (nChars);
  640.     }
  641. /*******************************************************************************
  642. *
  643. * vprintf - write a string formatted with a variable argument list to standard output (ANSI)
  644. *
  645. * This routine prints a string formatted with a variable argument list to
  646. * standard output.  It is identical to printf(), except that it takes
  647. * the variable arguments to be formatted as a list <vaList> of type `va_list'
  648. * rather than as in-line arguments.
  649. *
  650. * RETURNS: The number of characters output, or ERROR if there is an error
  651. * during output.
  652. *
  653. * SEE ALSO: printf(),
  654. * .I "American National Standard for Information Systems -"
  655. * .I "Programming Language - C, ANSI X3.159-1989: Input/Output (stdio.h)"
  656. */
  657. int vprintf
  658.     (
  659.     const char *  fmt, /* format string to write */
  660.     va_list   vaList /* arguments to format */
  661.     )
  662.     {
  663.     return (fioFormatV (fmt, vaList, printbuf, 1));
  664.     }
  665. /*******************************************************************************
  666. *
  667. * vfdprintf - write a string formatted with a variable argument list to a file descriptor
  668. *
  669. * This routine prints a string formatted with a variable argument list to a
  670. * specified file descriptor.  It is identical to fdprintf(), except
  671. * that it takes the variable arguments to be formatted as a list <vaList> of
  672. * type `va_list' rather than as in-line arguments.
  673. *
  674. * RETURNS: The number of characters output, or ERROR if there is an error
  675. * during output.
  676. *
  677. * SEE ALSO: fdprintf()
  678. */
  679. int vfdprintf
  680.     (
  681.     int   fd, /* file descriptor to print to */
  682.     const char *  fmt, /* format string for print */
  683.     va_list   vaList /* optional arguments to format */
  684.     )
  685.     {
  686.     return (fioFormatV (fmt, vaList, printbuf, fd));
  687.     }
  688. /*******************************************************************************
  689. *
  690. * vsprintf - write a string formatted with a variable argument list to a buffer (ANSI)
  691. *
  692. * This routine copies a string formatted with a variable argument list to
  693. * a specified buffer.  This routine is identical to sprintf(), except that it
  694. * takes the variable arguments to be formatted as a list <vaList> of type
  695. * `va_list' rather than as in-line arguments.
  696. *
  697. * RETURNS: 
  698. * The number of characters copied to <buffer>, not including the NULL 
  699. * terminator.
  700. *
  701. * SEE ALSO: sprintf(),
  702. * .I "American National Standard for Information Systems -"
  703. * .I "Programming Language - C, ANSI X3.159-1989: Input/Output (stdio.h)"
  704. */
  705. int vsprintf
  706.     (
  707.     char *   buffer, /* buffer to write to */
  708.     const char *  fmt, /* format string */
  709.     va_list   vaList /* optional arguments to format */
  710.     )
  711.     {
  712.     int nChars;
  713.     nChars = fioFormatV (fmt, vaList, putbuf, (int) &buffer);
  714.     *buffer = EOS;
  715.     return (nChars);
  716.     }
  717. #ifdef _WRS_ALTIVEC_SUPPORT
  718. typedef union {
  719.       __vector unsigned long  vul;
  720.       float  f32[4];
  721.       unsigned long  u32[4];
  722.       unsigned short  u16[8];
  723.       unsigned char  u8[16];
  724.       signed long  s32[4];
  725.       signed short  s16[8];
  726.       signed char  s8[16];
  727.     } VECTOR;
  728. #endif /* _WRS_ALTIVEC_SUPPORT */
  729. /*******************************************************************************
  730. *
  731. * fioFormatV - convert a format string
  732. *
  733. * This routine is used by the printf() family of routines to handle the
  734. * actual conversion of a format string.  The first argument is a format
  735. * string, as described in the entry for printf().  The second argument is a
  736. * variable argument list <vaList> that was previously established.
  737. *
  738. * As the format string is processed, the result will be passed to the output
  739. * routine whose address is passed as the third parameter, <outRoutine>.
  740. * This output routine may output the result to a device, or put it in a
  741. * buffer.  In addition to the buffer and length to output, the fourth
  742. * argument, <outarg>, will be passed through as the third parameter to the
  743. * output routine.  This parameter could be a file descriptor, a buffer 
  744. * address, or any other value that can be passed in an "int".
  745. *
  746. * The output routine should be declared as follows:
  747. * .CS
  748. *     STATUS outRoutine
  749. *         (
  750. *         char *buffer, /@ buffer passed to routine            @/
  751. *         int  nchars,  /@ length of buffer                    @/
  752. *         int  outarg   /@ arbitrary arg passed to fmt routine @/
  753. *         )
  754. * .CE
  755. * The output routine should return OK if successful, or ERROR if unsuccessful.
  756. *
  757. * RETURNS:
  758. * The number of characters output, or ERROR if the output routine 
  759. * returned ERROR.
  760. *
  761. * INTERNAL
  762. * Warning, this routine is extremely complex and its integrity is easily
  763. * destroyed. Do not change this code without absolute understanding of all
  764. * ramifications and consequences. 
  765. */
  766. int fioFormatV
  767.     (
  768.     FAST const char *fmt,  /* format string */
  769.     va_list vaList,        /* pointer to varargs list */
  770.     FUNCPTR outRoutine,    /* handler for args as they're formatted */
  771.     int outarg          /* argument to routine */
  772.     )
  773.     {
  774.     FAST int ch; /* character from fmt */
  775.     FAST int n; /* handy integer (short term usage) */
  776.     FAST char * cp; /* handy char pointer (short term usage) */
  777.     int width; /* width from format (%8d), or 0 */
  778.     char sign; /* sign prefix (' ', '+', '-', or ) */
  779.     unsigned long long
  780.         ulongLongVal;  /* unsigned 64 bit arguments %[diouxX] */
  781.     int prec; /* precision from format (%.3d), or -1 */
  782.     int oldprec; /* old precision from format (%.3d), or -1 */
  783.     int dprec; /* a copy of prec if [diouxX], 0 otherwise */
  784.     int fpprec; /* `extra' floating precision in [eEfgG] */
  785.     int size; /* size of converted field or string */
  786.     int fieldsz; /* field size expanded by sign, etc */
  787.     int realsz; /* field size expanded by dprec */
  788. #ifdef _WRS_ALTIVEC_SUPPORT
  789.     FAST int i; /* handy integer (short term usage) */
  790.     FAST char * vp; /* handy char pointer (short term usage) */
  791.     char Separator; /* separator for vector elements */
  792.     char C_Separator; /* separator for char vector elements */
  793.     VECTOR vec; /* vector argument */
  794.     BOOL doVector; /* AltiVec vector */
  795. #endif /* _WRS_ALTIVEC_SUPPORT */
  796.     char FMT[20]; /* To collect fmt info */
  797.     FAST char * Collect; /* char pointer to FMT */
  798.     BOOL doLongInt; /* long integer */
  799.     BOOL doLongLongInt; /* long long integer - 64 bit */
  800.     BOOL doShortInt; /* short integer */
  801.     BOOL doAlt; /* alternate form */
  802.     BOOL doLAdjust; /* left adjustment */
  803.     BOOL doZeroPad; /* zero (as opposed to blank) pad */
  804.     BOOL doHexPrefix; /* add 0x or 0X prefix */
  805.     BOOL doSign; /* change sign to '-' */
  806.     char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
  807. #if (CPU_FAMILY != AM29XXX)
  808.     char ox[2]; /* space for 0x hex-prefix */
  809. #else
  810.     char ox[3]; /* space for 0x hex-prefix */
  811. #endif /*(CPU_FAMILY != AM29XXX)*/
  812.     char * xdigs = NULL; /* digits for [xX] conversion */
  813.     int ret = 0; /* return value accumulator */
  814.     enum {OCT, DEC, HEX} base; /* base for [diouxX] conversion */
  815.     FOREVER /* Scan the format for conversions (`%' character) */
  816. {
  817. for (cp = CHAR_FROM_CONST(fmt);((ch=*fmt) != EOS)&&(ch != '%'); fmt++)
  818.     ;
  819. if ((n = fmt - cp) != 0)
  820.     {
  821.     if ((*outRoutine) (cp, n, outarg) != OK)
  822. return (ERROR);
  823.     ret += n;
  824.     }
  825. if (ch == EOS)
  826.     return (ret); /* return total length */
  827. fmt++; /* skip over '%' */
  828. #ifdef _WRS_ALTIVEC_SUPPORT
  829. Separator = ' '; /* the default separator for vector elements */
  830. C_Separator = EOS; /* the default separator for char vector elements */
  831. doVector = FALSE; /* no vector modifier */
  832. #endif /* _WRS_ALTIVEC_SUPPORT */
  833. *FMT = EOS;
  834. Collect = FMT;
  835. doLongInt = FALSE; /* long integer */
  836. doLongLongInt = FALSE; /* 64 bit integer */
  837. doShortInt = FALSE; /* short integer */
  838. doAlt = FALSE; /* alternate form */
  839. doLAdjust = FALSE; /* left adjustment */
  840. doZeroPad = FALSE; /* zero (as opposed to blank) pad */
  841. doHexPrefix = FALSE; /* add 0x or 0X prefix */
  842. doSign = FALSE; /* change sign to '-' */
  843. dprec = 0;
  844. fpprec = 0;
  845. width = 0;
  846. prec = -1;
  847. oldprec = -1;
  848. sign = EOS;
  849. #define get_CHAR  (ch = *Collect++ = *fmt++)
  850. #ifdef _WRS_ALTIVEC_SUPPORT
  851. #define SET_VECTOR_FMT(VFMT,NO)
  852.   do
  853.     {
  854. char * to;
  855. vec.vul =  va_arg (vaList,__vector unsigned long);
  856. cp = buf;
  857. *Collect = EOS;
  858. i = (NO);
  859. to = VFMT = (char *) malloc (i*20);
  860. while(i-- > 0) {
  861. char * from = FMT;
  862. *to++ = '%';
  863. while (*to++ = *from++);
  864. *(char*)((int)(to)-1) = Separator;
  865. }
  866. *(--to) = EOS;
  867.     }
  868.   while (0)
  869. #define RESET_VECTOR_FMT(VFMT)
  870. size = strlen(cp);
  871. sign = EOS;
  872. free(VFMT)
  873. #endif /* _WRS_ALTIVEC_SUPPORT */
  874. rflag:
  875. get_CHAR;
  876. reswitch:
  877. switch (ch) 
  878.     {
  879.     case ' ':
  880.     /* If the space and + flags both appear, the space
  881.      * flag will be ignored. -- ANSI X3J11
  882.      */
  883.     if (!sign)
  884. sign = ' ';
  885.     goto rflag;
  886. #ifdef _WRS_ALTIVEC_SUPPORT
  887.     case ',':
  888.     case ';':
  889.     case ':':
  890.     case '_':
  891.     Collect--;
  892.          Separator = C_Separator = ch;
  893.     goto rflag;
  894. #endif /* _WRS_ALTIVEC_SUPPORT */
  895.     case '#':
  896.     doAlt = TRUE;
  897.     goto rflag;
  898.     case '*':
  899.     /* A negative field width argument is taken as a
  900.      * flag followed by a positive field width.
  901.      * -- ANSI X3J11
  902.      * They don't exclude field widths read from args.
  903.      */
  904.     if ((width = va_arg(vaList, int)) >= 0)
  905. goto rflag;
  906.     width = -width; /* FALLTHROUGH */
  907.     case '-':
  908.     doLAdjust = TRUE;
  909.     goto rflag;
  910.     case '+':
  911.     sign = '+';
  912.     goto rflag;
  913.     case '.':
  914.     get_CHAR;
  915.     if ( ch == '*' ) 
  916. {
  917. n = va_arg(vaList, int);
  918. prec = (n < 0) ? -1 : n;
  919. goto rflag;
  920. }
  921.     n = 0;
  922.     while (is_digit(ch)) 
  923. {
  924. n = 10 * n + to_digit(ch);
  925. get_CHAR;
  926. }
  927.     prec = n < 0 ? -1 : n;
  928.     goto reswitch;
  929.     case '0':
  930.     /* Note that 0 is taken as a flag, not as the
  931.      * beginning of a field width. -- ANSI X3J11
  932.      */
  933.     doZeroPad = TRUE;
  934.     goto rflag;
  935.     case '1':
  936.     case '2':
  937.     case '3':
  938.     case '4':
  939.     case '5':
  940.     case '6':
  941.     case '7':
  942.     case '8':
  943.     case '9':
  944.     n = 0;
  945.     do 
  946. {
  947. n = 10 * n + to_digit(ch);
  948. get_CHAR;
  949. } while (is_digit(ch));
  950.     width = n;
  951.     goto reswitch;
  952.     case 'h':
  953.     doShortInt = TRUE;
  954.     goto rflag;
  955.     case 'l':
  956.     get_CHAR;
  957.     if ( ch == 'l' )
  958. {
  959. doLongLongInt = TRUE;
  960. goto rflag;
  961. }
  962.     else
  963. {
  964.         doLongInt = TRUE;
  965.         goto reswitch;
  966. }
  967. #ifdef _WRS_ALTIVEC_SUPPORT
  968.     case 'v':
  969.     Collect--;
  970.     doVector = TRUE;
  971.     goto rflag;
  972. #endif /* _WRS_ALTIVEC_SUPPORT */
  973.     case 'c':
  974. #ifdef _WRS_ALTIVEC_SUPPORT
  975.     if (doVector)
  976.     {
  977. vec.vul =  va_arg (vaList,__vector unsigned long);
  978. cp = buf;
  979. vp = (unsigned char *)&vec.u8;
  980. i = 15;
  981. while(i-- > 0) {
  982. *cp++ = *vp++;
  983. if (C_Separator) *cp++ = C_Separator;
  984. }
  985. *cp++ = *vp++;
  986. cp = buf;
  987. size = 16 + (C_Separator ? 15:0);
  988. sign = EOS;
  989.     }
  990.     else 
  991.     {
  992. #endif /* _WRS_ALTIVEC_SUPPORT */
  993. *(cp = buf) = va_arg(vaList, int);
  994. size = 1;
  995. sign = EOS;
  996. #ifdef _WRS_ALTIVEC_SUPPORT 
  997.     }
  998. #endif /* _WRS_ALTIVEC_SUPPORT */
  999.     break;
  1000.     case 'D':
  1001.     doLongInt = TRUE;  /* FALLTHROUGH */
  1002.     case 'd':
  1003.     case 'i':
  1004. #ifdef _WRS_ALTIVEC_SUPPORT
  1005.     if (doVector)
  1006.     {
  1007. SET_VECTOR_FMT(vp,doShortInt?8:4);
  1008. if (doShortInt)
  1009. sprintf(cp,vp,vec.s16[0],vec.s16[1],vec.s16[2],vec.s16[3],
  1010.       vec.s16[4],vec.s16[5],vec.s16[6],vec.s16[7]);
  1011. else
  1012. sprintf(cp,vp,vec.s32[0],vec.s32[1],vec.s32[2],vec.s32[3]);
  1013. RESET_VECTOR_FMT(vp);
  1014. break;
  1015.     }
  1016. #endif /* _WRS_ALTIVEC_SUPPORT */
  1017.     ulongLongVal = SARG();
  1018.     if ((long long)ulongLongVal < 0) 
  1019. {
  1020. ulongLongVal = -ulongLongVal;
  1021. sign = '-';
  1022. }
  1023.     base = DEC;
  1024.     goto number;
  1025.     case 'n':
  1026.     /* ret is int, so effectively %lln = %ln */
  1027.     if (doLongLongInt)
  1028. *va_arg(vaList, long long *) = (long long) ret;
  1029.     else if (doLongInt)
  1030. *va_arg(vaList, long *) = ret;
  1031.     else if (doShortInt)
  1032. *va_arg(vaList, short *) = ret;
  1033.     else
  1034. *va_arg(vaList, int *) = ret;
  1035.     continue; /* no output */
  1036.     case 'O':
  1037.     doLongInt = TRUE; /* FALLTHROUGH */
  1038.     case 'o':
  1039. #ifdef _WRS_ALTIVEC_SUPPORT
  1040.     if (doVector)
  1041.     {
  1042. SET_VECTOR_FMT(vp,doShortInt?8:4);
  1043. if (doShortInt)
  1044. sprintf(cp,vp,vec.s16[0],vec.s16[1],vec.s16[2],vec.s16[3],
  1045.       vec.s16[4],vec.s16[5],vec.s16[6],vec.s16[7]);
  1046. else
  1047. sprintf(cp,vp,vec.s32[0],vec.s32[1],vec.s32[2],vec.s32[3]);
  1048. RESET_VECTOR_FMT(vp);
  1049. break;
  1050.     }
  1051. #endif /* _WRS_ALTIVEC_SUPPORT */
  1052.     ulongLongVal = UARG();
  1053.     base = OCT;
  1054.     goto nosign;
  1055.     case 'p':
  1056.     /* The argument shall be a pointer to void.  The
  1057.      * value of the pointer is converted to a sequence
  1058.      * of printable characters, in an implementation
  1059.      * defined manner. -- ANSI X3J11
  1060.      */
  1061. #ifdef _WRS_ALTIVEC_SUPPORT
  1062.     if (doVector)
  1063.     {
  1064. SET_VECTOR_FMT(vp,4);
  1065. sprintf(cp,vp,vec.u32[0],vec.u32[1],vec.u32[2],vec.u32[3]);
  1066. RESET_VECTOR_FMT(vp);
  1067. break;
  1068.     }
  1069. #endif /* _WRS_ALTIVEC_SUPPORT */
  1070.     ulongLongVal = (unsigned long long) (unsigned int)
  1071.            va_arg(vaList, void *);/* NOSTRICT */
  1072.     base = HEX;
  1073.     xdigs = "0123456789abcdef";
  1074.     doHexPrefix = TRUE;
  1075.     ch = 'x';
  1076.     goto nosign;
  1077.     case 's':
  1078.     if ((cp = va_arg(vaList, char *)) == NULL)
  1079. cp = "(null)";
  1080.     if (prec >= 0) 
  1081. {
  1082. /* can't use strlen; can only look for the
  1083.  * NUL in the first `prec' characters, and
  1084.  * strlen() will go further.
  1085.  */
  1086. char *p = (char *)memchr(cp, 0, prec);
  1087. if (p != NULL) 
  1088.     {
  1089.     size = p - cp;
  1090.     if (size > prec)
  1091. size = prec;
  1092.     }
  1093. else
  1094.     size = prec;
  1095. }
  1096.     else
  1097. size = strlen(cp);
  1098.     sign = EOS;
  1099.     break;
  1100.     case 'U':
  1101.     doLongInt = TRUE; /* FALLTHROUGH */
  1102.     case 'u':
  1103. #ifdef _WRS_ALTIVEC_SUPPORT
  1104.     if (doVector)
  1105.     {
  1106. SET_VECTOR_FMT(vp,doShortInt?8:4);
  1107. if (doShortInt)
  1108. sprintf(cp,vp,vec.u16[0],vec.u16[1],vec.u16[2],vec.u16[3],
  1109.       vec.u16[4],vec.u16[5],vec.u16[6],vec.u16[7]);
  1110. else
  1111. sprintf(cp,vp,vec.u32[0],vec.u32[1],vec.u32[2],vec.u32[3]);
  1112. RESET_VECTOR_FMT(vp);
  1113. break;
  1114.     }
  1115. #endif /* _WRS_ALTIVEC_SUPPORT */
  1116.     ulongLongVal = UARG();
  1117.     base = DEC;
  1118.     goto nosign;
  1119.     case 'X':
  1120.     xdigs = "0123456789ABCDEF";
  1121.     goto hex;
  1122.     case 'x':
  1123.     xdigs = "0123456789abcdef";
  1124. hex:
  1125. #ifdef _WRS_ALTIVEC_SUPPORT
  1126.     if (doVector)
  1127.     {
  1128. SET_VECTOR_FMT(vp,doShortInt?8:4);
  1129. if (doShortInt)
  1130. sprintf(cp,vp,vec.s16[0],vec.s16[1],vec.s16[2],vec.s16[3],
  1131.       vec.s16[4],vec.s16[5],vec.s16[6],vec.s16[7]);
  1132. else
  1133. sprintf(cp,vp,vec.s32[0],vec.s32[1],vec.s32[2],vec.s32[3]);
  1134. RESET_VECTOR_FMT(vp);
  1135. break;
  1136.     }
  1137. #endif /* _WRS_ALTIVEC_SUPPORT */
  1138.     ulongLongVal = UARG();
  1139.     base = HEX;
  1140.     /* leading 0x/X only if non-zero */
  1141.     if (doAlt && (ulongLongVal != 0))
  1142. doHexPrefix = TRUE;
  1143.     /* unsigned conversions */
  1144. nosign:     sign = EOS;
  1145.     /* ... diouXx conversions ... if a precision is
  1146.      * specified, the 0 flag will be ignored. -- ANSI X3J11
  1147.      */
  1148. number:     if ((dprec = prec) >= 0)
  1149. doZeroPad = FALSE;
  1150.     /* The result of converting a zero value with an
  1151.      * explicit precision of zero is no characters. 
  1152.      * -- ANSI X3J11
  1153.      */
  1154.     cp = buf + BUF;
  1155.     if ((ulongLongVal != 0) || (prec != 0)) 
  1156. {
  1157. /* unsigned mod is hard, and unsigned mod
  1158.  * by a constant is easier than that by
  1159.  * a variable; hence this switch.
  1160.  */
  1161. switch (base) 
  1162.     {
  1163.     case OCT:
  1164. do 
  1165.     {
  1166.     *--cp = to_char(ulongLongVal & 7);
  1167.     ulongLongVal >>= 3;
  1168.     } while (ulongLongVal);
  1169. /* handle octal leading 0 */
  1170. if (doAlt && (*cp != '0'))
  1171.     *--cp = '0';
  1172. break;
  1173.     case DEC:
  1174. /* many numbers are 1 digit */
  1175. while (ulongLongVal >= 10) 
  1176.     {
  1177.     *--cp = to_char(ulongLongVal % 10);
  1178.     ulongLongVal /= 10;
  1179.     }
  1180. *--cp = to_char(ulongLongVal);
  1181. break;
  1182.     case HEX:
  1183. do 
  1184.     {
  1185.     *--cp = xdigs[ulongLongVal & 15];
  1186.     ulongLongVal >>= 4;
  1187.     } while (ulongLongVal);
  1188. break;
  1189.     default:
  1190. cp = "bug in vfprintf: bad base";
  1191. size = strlen(cp);
  1192. goto skipsize;
  1193.     }
  1194. }
  1195.     size = buf + BUF - cp;
  1196. skipsize:
  1197.     break;
  1198.     case 'L':
  1199.     /* NOT IMPLEMENTED */
  1200.     goto rflag;
  1201.     case 'e':
  1202.     case 'E':
  1203.     case 'f':
  1204.     case 'g':
  1205.     case 'G':
  1206. #ifdef _WRS_ALTIVEC_SUPPORT
  1207.     if (doVector)
  1208.     {
  1209. SET_VECTOR_FMT(vp,4);
  1210. sprintf(cp,vp,vec.f32[0],vec.f32[1],vec.f32[2],vec.f32[3]);
  1211. RESET_VECTOR_FMT(vp);
  1212. break;
  1213.     }
  1214. #endif /* _WRS_ALTIVEC_SUPPORT */
  1215.     if (fioFltFormatRtn != NULL)
  1216. {
  1217. oldprec = prec; /* in case of strange float */
  1218. if (prec > MAXFRACT)  /* do realistic precision */
  1219.     {
  1220.     if (((ch != 'g') && (ch != 'G')) || doAlt)
  1221. fpprec = prec - MAXFRACT;
  1222.     prec = MAXFRACT; /* they asked for it! */
  1223.     }
  1224. else if (prec == -1)
  1225.     prec = 6; /* ANSI default precision */
  1226. cp  = buf; /* where to fill in result */
  1227. *cp = EOS; /* EOS terminate just in case */
  1228. #if ((CPU_FAMILY != I960) && (CPU_FAMILY != PPC))
  1229. size = (*fioFltFormatRtn) (&vaList,prec,doAlt,ch,
  1230.    &doSign,cp,buf+sizeof(buf));
  1231. #else
  1232. size = (*fioFltFormatRtn) (vaList, prec, doAlt, ch,
  1233.    &doSign,cp,buf+sizeof(buf));
  1234. #endif
  1235. if ((int)size < 0) /* strange value (Nan,Inf,..) */
  1236.     {
  1237.     size = -size; /* get string length */
  1238.     prec = oldprec; /* old precision (not default)*/
  1239.     doZeroPad = FALSE; /* don't pad with zeroes */
  1240.     if (doSign) /* is strange value signed? */
  1241. sign = '-';
  1242.     }
  1243. else
  1244.     {
  1245.     if (doSign)
  1246. sign = '-';
  1247.     if (*cp == EOS)
  1248. cp++;
  1249.     }
  1250. break;
  1251. }
  1252.     /* FALLTHROUGH if no floating point format routine */
  1253.     default: /* "%?" prints ?, unless ? is NULL */
  1254.     if (ch == EOS)
  1255. return (ret);
  1256.     /* pretend it was %c with argument ch */
  1257.     cp   = buf;
  1258.     *cp  = ch;
  1259.     size = 1;
  1260.     sign = EOS;
  1261.     break;
  1262.     }
  1263. /* All reasonable formats wind up here.  At this point,
  1264.  * `cp' points to a string which (if not doLAdjust)
  1265.  * should be padded out to `width' places.  If
  1266.  * doZeroPad, it should first be prefixed by any
  1267.  * sign or other prefix; otherwise, it should be blank
  1268.  * padded before the prefix is emitted.  After any
  1269.  * left-hand padding and prefixing, emit zeroes
  1270.  * required by a decimal [diouxX] precision, then print
  1271.  * the string proper, then emit zeroes required by any
  1272.  * leftover floating precision; finally, if doLAdjust,
  1273.  * pad with blanks.
  1274.  */
  1275. /*
  1276.  * compute actual size, so we know how much to pad.
  1277.  * fieldsz excludes decimal prec; realsz includes it
  1278.  */
  1279. fieldsz = size + fpprec;
  1280. if (sign)
  1281.     {
  1282.     fieldsz++;
  1283.     if (fieldSzIncludeSign)
  1284.         dprec++; 
  1285.     }
  1286. else if (doHexPrefix)
  1287.     fieldsz += 2;
  1288. realsz = (dprec > fieldsz) ? dprec : fieldsz;
  1289. /* right-adjusting blank padding */
  1290. if (!doLAdjust && !doZeroPad)
  1291.     PAD(width - realsz, blanks);
  1292. /* prefix */
  1293. if (sign)
  1294.     {
  1295.     if ((*outRoutine) (&sign, 1, outarg) != OK)
  1296. return (ERROR);
  1297.     }
  1298. else if (doHexPrefix) 
  1299.     {
  1300.     ox[0] = '0';
  1301.     ox[1] = ch;
  1302.     if ((*outRoutine) (ox, 2, outarg) != OK)
  1303. return (ERROR);
  1304.     }
  1305. /* right-adjusting zero padding */
  1306. if (!doLAdjust && doZeroPad)
  1307.     PAD(width - realsz, zeroes);
  1308. /* leading zeroes from decimal precision */
  1309. PAD(dprec - fieldsz, zeroes);
  1310. /* the string or number proper */
  1311. if ((*outRoutine) (cp, size, outarg) != OK)
  1312.     return (ERROR);
  1313. /* trailing floating point zeroes */
  1314. PAD(fpprec, zeroes);
  1315. /* left-adjusting padding (always blank) */
  1316. if (doLAdjust)
  1317.     PAD(width - realsz, blanks);
  1318. /* finally, adjust ret */
  1319. ret += (width > realsz) ? width : realsz;
  1320. }
  1321.     }
  1322. /*******************************************************************************
  1323. *
  1324. * putbuf - put characters in a buffer
  1325. *
  1326. * This routine is a support routine for sprintf().
  1327. * This routine copies length bytes from source to destination, leaving the
  1328. * destination buffer pointer pointing at byte following block copied.
  1329. */
  1330. LOCAL STATUS putbuf
  1331.     (
  1332.     char *inbuf,                /* pointer to source buffer */
  1333.     int length,                 /* number of bytes to copy */
  1334.     char **outptr               /* pointer to destination buffer */
  1335.     )
  1336.     {
  1337.     bcopy (inbuf, *outptr, length);
  1338.     *outptr += length;
  1339.     return (OK);
  1340.     }
  1341. /*******************************************************************************
  1342. *
  1343. * printbuf - printf() support routine: print characters in a buffer
  1344. */
  1345. LOCAL STATUS printbuf
  1346.     (
  1347.     char *buf,
  1348.     int nbytes,
  1349.     int fd
  1350.     )
  1351.     {
  1352.     return (write (fd, buf, nbytes) == nbytes ? OK : ERROR);
  1353.     }
  1354. /*******************************************************************************
  1355. *
  1356. * fioRead - read a buffer
  1357. *
  1358. * This routine repeatedly calls the routine read() until <maxbytes> have
  1359. * been read into <buffer>.  If EOF is reached, the number of bytes read
  1360. * will be less than <maxbytes>.
  1361. *
  1362. * RETURNS:
  1363. * The number of bytes read, or ERROR if there is an error during the read
  1364. * operation.
  1365. *
  1366. * SEE ALSO: read()
  1367. */
  1368. int fioRead
  1369.     (
  1370.     int fd, /* file descriptor of file to read */
  1371.     char * buffer, /* buffer to receive input */
  1372.     int maxbytes /* maximum number of bytes to read */
  1373.     )
  1374.     {
  1375.     int original_maxbytes = maxbytes;
  1376.     int nbytes;
  1377.     while (maxbytes > 0)
  1378. {
  1379. nbytes = read (fd, buffer, maxbytes);
  1380. if (nbytes < 0)
  1381.     return (ERROR);
  1382. if (nbytes == 0)
  1383.     return (original_maxbytes - maxbytes);
  1384. maxbytes -= nbytes;
  1385. buffer   += nbytes;
  1386. }
  1387.     return (original_maxbytes);
  1388.     }
  1389. /*******************************************************************************
  1390. *
  1391. * fioRdString - read a string from a file
  1392. *
  1393. * This routine puts a line of input into <string>.  The specified input
  1394. * file descriptor is read until <maxbytes>, an EOF, an EOS, or a newline
  1395. * character is reached.  A newline character or EOF is replaced with EOS,
  1396. * unless <maxbytes> characters have been read.
  1397. *
  1398. * RETURNS:
  1399. * The length of the string read, including the terminating EOS;
  1400. * or EOF if a read error occurred or end-of-file occurred without
  1401. * reading any other character.
  1402. */
  1403. int fioRdString
  1404.     (
  1405.     int fd,             /* fd of device to read */
  1406.     FAST char string[], /* buffer to receive input */
  1407.     int maxbytes        /* max no. of chars to read */
  1408.     )
  1409.     {
  1410.     char c;
  1411.     FAST int nchars = 0;
  1412.     FAST int i = 0;
  1413.     /* read characters until
  1414.      *    1) specified line limit is reached,
  1415.      *    2) end-of-file is reached,
  1416.      *    3) EOS character is read,
  1417.      *    4) newline character is read,
  1418.      * or 5) read error occurs.
  1419.      */
  1420.     while (i < maxbytes)
  1421. {
  1422. nchars = read (fd, &c, 1);
  1423. if (nchars == ERROR) /* if can't read file */
  1424.     break;
  1425. /* check for newline terminator */
  1426. if ((nchars != 1) || (c == 'n') || (c == EOS))
  1427.     {
  1428.     string [i++] = EOS;
  1429.     break;
  1430.     }
  1431. string [i++] = c;
  1432. }
  1433.     if (nchars == ERROR  || ((nchars == 0) && (i == 1)))
  1434. i = EOF;
  1435.     return (i);
  1436.     }
  1437. /*******************************************************************************
  1438. *
  1439. * sscanf - read and convert characters from an ASCII string (ANSI)
  1440. *
  1441. * This routine reads characters from the string <str>, interprets them
  1442. * according to format specifications in the string <fmt>, which specifies
  1443. * the admissible input sequences and how they are to be converted for
  1444. * assignment, using subsequent arguments as pointers to the objects to
  1445. * receive the converted input.
  1446. *
  1447. * If there are insufficient arguments for the format, the behavior is
  1448. * undefined.  If the format is exhausted while arguments remain, the excess
  1449. * arguments are evaluated but are otherwise ignored.
  1450. *
  1451. * The format is a multibyte character sequence, beginning and ending in
  1452. * its initial shift state.  The format is composed of zero or more directives:
  1453. * one or more white-space characters; an ordinary multibyte character (neither
  1454. * `%' nor a white-space character); or a conversion specification.  Each
  1455. * conversion specification is introduced by the `%' character.  After the `%',
  1456. * the following appear in sequence:
  1457. *
  1458. * .iP "" 4
  1459. * An optional assignment-suppressing character `*'.
  1460. * .iP
  1461. * An optional non-zero decimal integer that specifies the maximum field 
  1462. * width.
  1463. * .iP
  1464. * An optional `h', `l' (ell) or `ll' (ell-ell) indicating the size of the 
  1465. * receiving object.  The conversion specifiers `d', `i', and `n' should 
  1466. * be preceded by `h' if the corresponding argument is a pointer to `short 
  1467. * int' rather than a pointer to `int', or by `l' if it is a pointer to 
  1468. * `long int', or by `ll' if it is a pointer to `long long int'.  Similarly, 
  1469. * the conversion specifiers `o', `u', and `x' shall be preceded by `h' if 
  1470. * the corresponding argument is a pointer to `unsigned short int' rather 
  1471. * than a pointer to `unsigned int', or by `l' if it is a pointer to 
  1472. * `unsigned long int', or by `ll' if it is a pointer to `unsigned long 
  1473. * long int'.  Finally, the conversion specifiers `e', `f', and `g' shall 
  1474. * be preceded by `l' if the corresponding argument is a pointer to 
  1475. * `double' rather than a pointer to `float'.  If a `h', `l' or `ll' 
  1476. * appears with any other conversion specifier, the behavior is undefined.
  1477. * .iP
  1478. * &WARNING: ANSI C also specifies an optional `L' in some of the same
  1479. * contexts as `l' above, corresponding to a `long double *' argument.
  1480. * However, the current release of the VxWorks libraries does not support 
  1481. * `long double' data; using the optional `L' gives unpredictable results.
  1482. * .iP
  1483. * A character that specifies the type of conversion to be applied.  The
  1484. * valid conversion specifiers are described below.
  1485. * .LP
  1486. *
  1487. * The sscanf() routine executes each directive of the format in turn.  If a 
  1488. * directive fails, as detailed below, sscanf() returns.  Failures
  1489. * are described as input failures (due to the unavailability of input
  1490. * characters), or matching failures (due to inappropriate input).
  1491. * A directive composed of white-space character(s) is executed by reading
  1492. * input up to the first non-white-space character (which remains unread),
  1493. * or until no more characters can be read.
  1494. *
  1495. * A directive that is an ordinary multibyte character is executed by reading
  1496. * the next characters of the stream.  If one of the characters differs from
  1497. * one comprising the directive, the directive fails, and the differing and
  1498. * subsequent characters remain unread.
  1499. *
  1500. * A directive that is a conversion specification defines a set of matching
  1501. * input sequences, as described below for each specifier.  A conversion
  1502. * specification is executed in the following steps:
  1503. *
  1504. * Input white-space characters (as specified by the isspace() function) are 
  1505. * skipped, unless the specification includes a `[', `c', or `n' specifier.
  1506. *
  1507. * An input item is read from the stream, unless the specification includes
  1508. * an `n' specifier.  An input item is defined as the longest matching
  1509. * sequence of input characters, unless that exceeds a specified field width,
  1510. * in which case it is the initial subsequence of that length in the
  1511. * sequence.  The first character, if any, after the input item remains
  1512. * unread.  If the length of the input item is zero, the execution of the
  1513. * directive fails:  this condition is a matching failure, unless an error
  1514. * prevented input from the stream, in which case it is an input failure.
  1515. *
  1516. * Except in the case of a `%' specifier, the input item is converted to a
  1517. * type appropriate to the conversion specifier.  If the input item is not a
  1518. * matching sequence, the execution of the directive fails:  this condition
  1519. * is a matching failure.  Unless assignment suppression was indicated by a
  1520. * `*', the result of the conversion is placed in the object pointed to by
  1521. * the first argument following the <fmt> argument that has not already
  1522. * received a conversion result.  If this object does not have an appropriate
  1523. * type, or if the result of the conversion cannot be represented in the
  1524. * space provided, the behavior is undefined.
  1525. *
  1526. * The following conversion specifiers are valid:
  1527. *
  1528. * .iP `d'
  1529. * Matches an optionally signed decimal integer whose format is
  1530. * the same as expected for the subject sequence of the strtol()
  1531. * function with the value 10 for the <base> argument.  The 
  1532. * corresponding argument should be a pointer to `int'.
  1533. * .iP `i'
  1534. * Matches an optionally signed integer, whose format is the
  1535. * same as expected for the subject sequence of the strtol()
  1536. * function with the value 0 for the <base> argument.  The 
  1537. * corresponding argument should be a pointer to `int'.
  1538. * .iP `o'
  1539. * Matches an optionally signed octal integer, whose format is the
  1540. * same as expected for the subject sequence of the strtoul()
  1541. * function with the value 8 for the <base> argument.  The
  1542. * corresponding argument should be a pointer to `unsigned int'.
  1543. * .iP `u'
  1544. * Matches an optionally signed decimal integer, whose format is 
  1545. * the same as expected for the subject sequence of the strtoul()
  1546. * function with the value 10 for the <base> argument.  The
  1547. * corresponding argument should be a pointer to `unsigned int'.
  1548. * .iP `x'
  1549. * Matches an optionally signed hexadecimal integer, whose format is
  1550. * the same as expected for the subject sequence of the strtoul()
  1551. * function with the value 16 for the <base> argument.  The
  1552. * corresponding argument should be a pointer to `unsigned int'.
  1553. * .iP "`e', `f', `g'"
  1554. * Match an optionally signed floating-point number, whose format
  1555. * is the same as expected for the subject string of the strtod()
  1556. * function.  The corresponding argument should be a pointer to `float'.
  1557. * .iP `s'
  1558. * Matches a sequence of non-white-space characters.  The 
  1559. * corresponding argument should be a pointer to the initial
  1560. * character of an array large enough to accept the sequence
  1561. * and a terminating null character, which will be added 
  1562. * automatically.
  1563. * .iP `['
  1564. * Matches a non-empty sequence of characters from a set of 
  1565. * expected characters (the `scanset').  The corresponding argument
  1566. * should be a pointer to the initial character of an array large
  1567. * enough to accept the sequence and a terminating null character,
  1568. * which is added automatically.  The conversion specifier
  1569. * includes all subsequent character in the format string, up to
  1570. * and including the matching right bracket (`]').  The characters
  1571. * between the brackets (the `scanlist') comprise the scanset,
  1572. * unless the character after the left bracket is a circumflex (`^')
  1573. * in which case the scanset contains all characters that do not
  1574. * appear in the scanlist between the circumflex and the right
  1575. * bracket.  If the conversion specifier begins with "[]" or "[^]", the
  1576. * right bracket character is in the scanlist and the next 
  1577. * right bracket character is the matching right bracket that ends
  1578. * the specification; otherwise the first right bracket character
  1579. * is the one that ends the specification.
  1580. * .iP `c'
  1581. * Matches a sequence of characters of the number specified by the
  1582. * field width (1 if no field width is present in the directive).
  1583. * The corresponding argument should be a pointer to the initial 
  1584. * character of an array large enough to accept the sequence.
  1585. * No null character is added.
  1586. * .iP `p'
  1587. * Matches an implementation-defined set of sequences, which should be
  1588. * the same as the set of sequences that may be produced by the %p
  1589. * conversion of the fprintf() function.  The corresponding argument
  1590. * should be a pointer to a pointer to `void'.  VxWorks defines its
  1591. * pointer input field to be consistent with pointers written by the
  1592. * fprintf() function ("0x" hexadecimal notation).  If the input item is
  1593. * a value converted earlier during the same program execution, the
  1594. * pointer that results should compare equal to that value; otherwise
  1595. * the behavior of the %p conversion is undefined.
  1596. * .iP `n'
  1597. * No input is consumed.  The corresponding argument should be a pointer to
  1598. * `int' into which the number of characters read from the input stream so
  1599. * far by this call to sscanf() is written.  Execution of a %n directive does
  1600. * not increment the assignment count returned when sscanf() completes
  1601. * execution.
  1602. * .iP `%'
  1603. * Matches a single `%'; no conversion or assignment occurs.  The
  1604. * complete conversion specification is %%.
  1605. * .LP
  1606. *
  1607. * If a conversion specification is invalid, the behavior is undefined.
  1608. *
  1609. * The conversion specifiers `E', `G', and `X' are also valid and behave the
  1610. * same as `e', `g', and `x', respectively.
  1611. *
  1612. * If end-of-file is encountered during input, conversion is terminated.  If 
  1613. * end-of-file occurs before any characters matching the current directive
  1614. * have been read (other than leading white space, where permitted), execution
  1615. * of the current directive terminates with an input failure; otherwise, unless
  1616. * execution of the current directive is terminated with a matching failure,
  1617. * execution of the following directive (if any) is terminated with an input
  1618. * failure.
  1619. *
  1620. * If conversion terminates on a conflicting input character, the offending
  1621. * input character is left unread in the input stream.  Trailing white space
  1622. * (including new-line characters) is left unread unless matched by a
  1623. * directive.  The success of literal matches and suppressed assignments is
  1624. * not directly determinable other than via the %n directive.
  1625. *
  1626. * INCLUDE FILES: fioLib.h 
  1627. *
  1628. * RETURNS:
  1629. * The number of input items assigned, which can be fewer than provided for,
  1630. * or even zero, in the event of an early matching failure; or EOF if an
  1631. * input failure occurs before any conversion.
  1632. *
  1633. * SEE ALSO: fscanf(), scanf(),
  1634. * .I "American National Standard for Information Systems -"
  1635. * .I "Programming Language - C, ANSI X3.159-1989: Input/Output (stdio.h)"
  1636. *
  1637. * VARARGS2
  1638. */
  1639. int sscanf
  1640.     (
  1641.     const char *  str, /* string to scan */
  1642.     const char *  fmt, /* format string */
  1643.     ...       /* optional arguments to format string */
  1644.     )
  1645.     {
  1646.     int nArgs;
  1647.     int unget;
  1648.     va_list vaList; /* vararg list */
  1649.     va_start (vaList, fmt);
  1650.     nArgs = fioScanV (fmt, getbuf, (int) &str, &unget, vaList);
  1651.     va_end (vaList);
  1652.     return (nArgs);
  1653.     }
  1654. /********************************************************************************
  1655. * getbuf - sscanf() support routine: get next character in string
  1656. *
  1657. * RETURNS: Next character or EOF if empty.
  1658. */
  1659. LOCAL int getbuf
  1660.     (
  1661.     char **str
  1662.     )
  1663.     {
  1664.     int c = (int)(**str);
  1665.     if (c == EOS)
  1666.         return (EOF);
  1667.     ++*str;
  1668.     return (c);
  1669.     }
  1670. /******************************************************************************
  1671. *
  1672. * fioScanV - scan processor
  1673. *
  1674. * NOMANUAL
  1675. */
  1676. int fioScanV
  1677.     (
  1678.     const char *fmt,            /* the format string */
  1679.     FUNCPTR     getRtn,         /* routine to get next character */
  1680.     int         getArg,         /* argument to be passed to get */
  1681.     int *       pUnget,         /* where to return unget char (-1 = no unget) */
  1682.     va_list     vaList          /* vararg list */
  1683.     )
  1684.     {
  1685.     BOOL        suppress;                       /* assignment was suppressed */
  1686.     void *      pArg;
  1687.     int         ch;
  1688.     BOOL        countArg;                       /* FALSE for %n, not counted */
  1689.     BOOL        quit            = FALSE;
  1690.     int         argsAssigned    = 0;
  1691.     int         nchars          = 0;
  1692.  
  1693.     pArg = va_arg (vaList, void *);     /* get first pointer arg */
  1694.  
  1695.     ch = (* getRtn) (getArg);           /* get first char */
  1696.  
  1697.  
  1698.     while (!quit && (*fmt != EOS))
  1699.         {
  1700.         countArg = TRUE;                /* default = count arg assignment */
  1701.  
  1702.         switch (*fmt)
  1703.             {
  1704.             case ' ':
  1705.             case 'n':
  1706.             case 't':                  /* skip white space in string */
  1707.                 ++fmt;
  1708.                 while (isspace (ch))
  1709.                     GET_CHAR (ch, nchars);
  1710.                 break;
  1711.  
  1712.             case '%':                   /* conversion specification */
  1713.                 ++fmt;
  1714.  
  1715.                 /* NOTE: if next char is '%' (i.e. "%%") then a normal match
  1716.                  * of '%' is required: FALL THROUGH to default case
  1717.                  */
  1718.                 if (*fmt != '%')
  1719.                     {
  1720.                     /* Skip white space except for 'c', 'n', '[' specifiers.
  1721.                      * Suppress including %n fields in returned count.
  1722.                      */
  1723.  
  1724.                     switch (*fmt)
  1725.                         {
  1726.                         case 'c':
  1727.                         case '[':
  1728.                             break;
  1729.                         case '*':  /* ignore the '*' for purposes of white
  1730.             * space removal                        */
  1731.     switch(*(fmt+1))
  1732.         {
  1733. case 'c':
  1734. case '[':
  1735.     break;
  1736.                          default:
  1737.                                  while (isspace (ch))
  1738.                                  GET_CHAR (ch, nchars);
  1739. }
  1740.     break;
  1741.                         case 'n':
  1742.                             countArg = FALSE;           /* we don't count %n */
  1743.                             break;
  1744.  
  1745.                         case 'h':                       /* %hn, %ln, %Ln, %lln */
  1746. case 'l':
  1747. case 'L':
  1748.     if ((*(fmt + 1) == 'n') || 
  1749.         ((*fmt == 'l') && (*(fmt + 1) == 'l') && (*(fmt + 2) == 'n'))) 
  1750.                                 {
  1751.         countArg = FALSE;
  1752.         break;
  1753.         }
  1754.                         default:
  1755.                             while (isspace (ch))
  1756.                                 GET_CHAR (ch, nchars);
  1757.                         }
  1758.  
  1759.  
  1760.                     /* Quit if at end of input string, unless spec is %[hl]n */
  1761.  
  1762.                     if (ch == EOF)                      /* if at end of input */                        {
  1763.                         switch (*fmt)
  1764.                             {
  1765.                             case 'n':
  1766.                                 break;                  /* %n is still valid */
  1767.  
  1768.                             case 'h':                   /* also %hn, %ln, %lln */
  1769.                             case 'l':
  1770.     case 'L':
  1771. if ((*(fmt + 1) == 'n') || 
  1772.             ((*fmt == 'l') && (*(fmt + 1) == 'l') && (*(fmt + 2) == 'n'))) 
  1773.                                     {
  1774.             break; /* keep going */
  1775.             }
  1776.                                 /* FALL THROUGH */
  1777.  
  1778.                             default:
  1779.                                 quit = TRUE;
  1780.                                 break;
  1781.                             }
  1782.                         }
  1783.  
  1784.                     /* Scan field in input string */
  1785.  
  1786.                     if (scanField (&fmt, pArg, getRtn, getArg, &suppress, &ch,
  1787.                                    &nchars))
  1788.                         {
  1789.                         /* successful scan */
  1790.                         if (!suppress)
  1791.                             {
  1792.                             if (countArg)               /* unless arg was %n */
  1793.                                 ++argsAssigned;         /*  increment count */
  1794.  
  1795.                             pArg = va_arg (vaList, void *);     /* next arg */
  1796.                             }
  1797.                         }
  1798.                     else
  1799.                         quit = TRUE;          /* unsuccessful */
  1800.                     break;
  1801.                     }
  1802.  
  1803.                 /* NOTE: else of above if FALLS THROUGH to default below! */
  1804.  
  1805.             default:                    /* character to match */
  1806.                 if (ch == *fmt)
  1807.                     {
  1808.                     GET_CHAR (ch, nchars);      /* advance past matched char */
  1809.                     ++fmt;                      /* advance past matched char */
  1810.                     }
  1811.                 else
  1812.                     quit = TRUE;                /* match failed */
  1813.                 break;
  1814.             }
  1815.         }
  1816.  
  1817.     *pUnget = ch;
  1818.  
  1819.     if ((argsAssigned == 0) && (ch == EOF))
  1820.         return (EOF);
  1821.  
  1822.     return (argsAssigned);
  1823.     }
  1824. /********************************************************************************
  1825. * scanField - assign value to argument according to format
  1826. *
  1827. * RETURNS:
  1828. * TRUE if conversion successful, otherwise FALSE;
  1829. * <pSuppress> is set TRUE if assignment was suppressed.
  1830. *
  1831. * NOMANUAL
  1832. */
  1833.  
  1834. /*LOCAL*/ BOOL scanField
  1835.     (
  1836.     const char **ppFmt,          /* conversion specification string */
  1837.     FAST void *  pReturn,        /* where to set result */
  1838.     FUNCPTR      getRtn,
  1839.     int          getArg,
  1840.     BOOL *       pSuppress,      /* set to TRUE if argptr was not assigned */
  1841.     int *        pCh,
  1842.     int *        pNchars
  1843.     )
  1844.     {
  1845.     FAST int    fieldwidth = 0;         /* maximum number of chars to convert.
  1846.                                          * default 0 implies no limit */
  1847.     int         returnSpec = 0;         /* 0, 'h', 'l', ll */
  1848.     FAST const char *pFmt = *ppFmt;     /* ptr to current char in fmt string */
  1849.     FAST int    base;
  1850. #ifdef _WRS_ALTIVEC_SUPPORT
  1851.     VECTOR vec; /* vector value accumulator */
  1852.     BOOL doVector = FALSE;/* AltiVec vector */
  1853.     char Separator = ' '; /* separator for vector elements */
  1854.     char C_Separator = EOS; /* separator for char vector elements */
  1855.     FAST int    ch, ix; /* handy variables for GET_CHAR */
  1856.     char  *vp; /* handy char pointer (short term usage) */
  1857.     FAST int i=4; /* handy integer (short term usage) */
  1858.     while(i--) vec.s32[i] = 0;
  1859. #endif /* _WRS_ALTIVEC_SUPPORT */
  1860.     /* check for assignment suppression */
  1861.     *pSuppress = (*pFmt == '*');
  1862.     if (*pSuppress)
  1863.         {
  1864.         ++pFmt;
  1865.         pReturn = NULL;
  1866.         }
  1867.  
  1868.     /* check for specification of maximum fieldwidth */
  1869.  
  1870.     while (isdigit ((int)*pFmt))
  1871.         fieldwidth = 10 * fieldwidth + (*pFmt++ - '0');
  1872. #ifdef _WRS_ALTIVEC_SUPPORT
  1873.     /* check for separator for vector value */
  1874.     switch (*pFmt)
  1875.         {
  1876.         case ',':
  1877.         case ';':
  1878.         case ':':
  1879.         case '_':
  1880.             Separator = C_Separator = *pFmt++;
  1881.             break;
  1882.         }
  1883. #endif /* _WRS_ALTIVEC_SUPPORT */
  1884.     /* check for specification of size of returned value */
  1885.  
  1886.     switch (*pFmt)
  1887.         {
  1888.         case 'h':
  1889. case 'L':
  1890.     returnSpec = *pFmt++;
  1891. #ifdef _WRS_ALTIVEC_SUPPORT            
  1892.             if (*pFmt == 'v') { pFmt++; doVector = TRUE; }
  1893. #endif /* _WRS_ALTIVEC_SUPPORT */
  1894.     break;
  1895. case 'l':
  1896.             if (*(++pFmt) == 'l')
  1897.         {
  1898.         returnSpec = ll;
  1899.         pFmt++;
  1900.         }
  1901.     else
  1902.         returnSpec = 'l';
  1903. #ifdef _WRS_ALTIVEC_SUPPORT            
  1904.             if (*pFmt == 'v') { pFmt++; doVector = TRUE; }
  1905. #endif /* _WRS_ALTIVEC_SUPPORT */ 
  1906.             break;
  1907. #ifdef _WRS_ALTIVEC_SUPPORT            
  1908.         case 'v':
  1909.             pFmt++;
  1910.             doVector = TRUE;
  1911.                 
  1912.     switch (*pFmt)
  1913. {
  1914. case 'h':
  1915. case 'L':
  1916.     returnSpec = *pFmt++;
  1917.     break;
  1918. case 'l':
  1919.             if (*(++pFmt) == 'l')
  1920.         {
  1921.         returnSpec = ll;
  1922.         pFmt++;
  1923.         }
  1924.             else
  1925.                returnSpec = 'l';
  1926.     break;
  1927. }
  1928.             break;
  1929. #endif /* _WRS_ALTIVEC_SUPPORT */
  1930.         }
  1931.  
  1932. #ifdef _WRS_ALTIVEC_SUPPORT            
  1933.     if (C_Separator && !doVector) return (FALSE); /* unsuccessful conversion */
  1934. #endif /* _WRS_ALTIVEC_SUPPORT */
  1935.     /* set default fieldwidth if not specified */
  1936.  
  1937.     if (fieldwidth == 0)
  1938.         fieldwidth = (*pFmt == 'c') ? 1 : INT_MAX;
  1939.  
  1940.  
  1941.     switch (*pFmt)
  1942.         {
  1943.         case 'c':               /* character, or character array */
  1944. #ifdef _WRS_ALTIVEC_SUPPORT
  1945.     if ( doVector )
  1946.       {
  1947. if (fieldwidth != 1) return (FALSE); /* unsuccessful conversion */
  1948. i  = 16;
  1949. ix = 0;
  1950. ch = *pCh;
  1951. vp = (char*) &vec.s8;
  1952. while (i--) {
  1953. if (ch != EOF)
  1954. {
  1955.      *vp++ = (char) ch;
  1956.      GET_CHAR (ch, ix);
  1957. }
  1958. else return (FALSE); /* unsuccessful conversion */
  1959. if (C_Separator && i)
  1960. {
  1961.     if ( (char)ch != C_Separator ) return (FALSE);
  1962.     GET_CHAR (ch, ix);
  1963. }
  1964. }
  1965. *pCh = ch;
  1966. *pNchars += ix;
  1967. if (pReturn != NULL)
  1968. *((__vector unsigned long *) pReturn) = vec.vul;
  1969.         break;
  1970.       }
  1971. #endif /* _WRS_ALTIVEC_SUPPORT */
  1972.       
  1973.             if (!scanChar ((char *) pReturn, fieldwidth, getRtn, getArg,
  1974.                            pCh, pNchars))
  1975.                 return (FALSE);         /* unsuccessful conversion */
  1976.             break;
  1977.  
  1978.         case 'i':               /* integer */
  1979.         case 'o':               /* octal integer */
  1980.         case 'd':               /* decimal integer */
  1981.         case 'u':               /* unsigned decimal integer */
  1982.         case 'x':               /* hex integer */
  1983.         case 'X':               /* hex integer */
  1984.         case 'p':               /* pointer */
  1985.  
  1986.             switch (*pFmt)
  1987.                 {
  1988.                 case 'i':       base = 0;       break;
  1989.                 case 'o':       base = 8;       break;
  1990.                 case 'd':       base = 10;      break;
  1991.                 case 'u':       base = 10;      break;
  1992.                 case 'x':       base = 16;      break;
  1993.                 case 'X':       base = 16;      break;
  1994.                 case 'p':       base = 16;      break;
  1995.                 default :       base = 0;       break;
  1996.                 }
  1997. #ifdef _WRS_ALTIVEC_SUPPORT
  1998.             if ( doVector )
  1999.       {
  2000. i  = ((returnSpec == 'h') ? 8:4);
  2001. ix = 0;
  2002. ch = *pCh;
  2003. while (i--) {
  2004. if (returnSpec != 'h') /* int, long */
  2005. {
  2006.                 if (!scanNum (base,(void*)&vec.u32[3-i], returnSpec,
  2007.                               fieldwidth, getRtn, getArg, pCh, pNchars))
  2008.                     return (FALSE);         /* unsuccessful conversion */
  2009. }
  2010. else /* short int, AltiVec pixel */
  2011. {
  2012.                 if (!scanNum (base,(void*)&vec.u16[7-i], returnSpec,
  2013.                               fieldwidth, getRtn, getArg, pCh, pNchars))
  2014.                     return (FALSE);         /* unsuccessful conversion */
  2015. }
  2016. if (i)
  2017. {
  2018.     if ( *pCh != Separator ) return (FALSE);
  2019.     GET_CHAR (ch, ix);
  2020.     *pCh = ch;
  2021. }
  2022. }
  2023. *pNchars += ix;
  2024. if (pReturn != NULL)
  2025. *((__vector unsigned long *) pReturn) = vec.vul;
  2026.         break;
  2027.       }
  2028. #endif /* _WRS_ALTIVEC_SUPPORT */
  2029.             if (!scanNum (base, pReturn, returnSpec, fieldwidth, getRtn,
  2030.             getArg, pCh, pNchars))
  2031.                 return (FALSE);         /* unsuccessful conversion */
  2032.             break;
  2033.  
  2034.         case 'e':               /* exponential float */
  2035.         case 'f':               /* float */
  2036.         case 'g':               /* float */
  2037.         case 'E':               /* exponential double */
  2038.         case 'F':               /* double */
  2039.         case 'G':               /* double */
  2040. #ifdef _WRS_ALTIVEC_SUPPORT
  2041.             if ( doVector )
  2042.       {
  2043.       
  2044.         if (fioFltScanRtn == NULL) return (FALSE);
  2045. i  = 4;
  2046. ix = 0;
  2047. ch = *pCh;
  2048. while (i--) 
  2049.   {
  2050.                  if (!(* fioFltScanRtn) ((void*)&vec.f32[3-i], 
  2051.     returnSpec, fieldwidth, 
  2052.     getRtn, getArg, pCh, pNchars))
  2053.                     return (FALSE);    /* unsuccessful conversion */
  2054. if (i)
  2055. {
  2056.     if ( *pCh != Separator ) return (FALSE);
  2057.     GET_CHAR (ch, ix);
  2058.     *pCh = ch;
  2059. }
  2060. }
  2061. *pNchars += ix;
  2062. if (pReturn != NULL)
  2063. *((__vector unsigned long *) pReturn) = vec.vul;
  2064.         break;
  2065.       }
  2066. #endif /* _WRS_ALTIVEC_SUPPORT */
  2067.             if ((fioFltScanRtn == NULL) ||
  2068.                 (!(* fioFltScanRtn) (pReturn, returnSpec, fieldwidth, getRtn,
  2069.                                      getArg, pCh, pNchars)))
  2070.                 return (FALSE);         /* unsuccessful conversion */
  2071.             break;
  2072.  
  2073.         case 's':               /* string */
  2074.             if (!scanString ((char *) pReturn, fieldwidth, getRtn, getArg,
  2075.                              pCh, pNchars))
  2076.                 return (FALSE);         /* unsuccessful conversion */
  2077.             break;
  2078.  
  2079.         case '[':               /* non-space-delimited string */
  2080.             if (!scanCharSet ((char *) pReturn, fieldwidth, pFmt, getRtn,
  2081.                               getArg, pCh, pNchars))
  2082.                 return (FALSE);
  2083.             /* get past format specifier string */
  2084.  
  2085.             while (*pFmt != ']')
  2086.                 ++pFmt;
  2087.             break;
  2088.  
  2089.  
  2090.         case 'n':               /* current number of chars scanned */
  2091.             if (pReturn != NULL)
  2092.                 {
  2093.                 switch (returnSpec)
  2094.                     {
  2095.                     case 'h': *((short *) pReturn) = *pNchars; break;
  2096.                     case 'l': *((long *) pReturn)  = *pNchars; break;
  2097.     case (ll) : *((long long *) pReturn) = *pNchars; break;
  2098.                     default:  *((int *) pReturn)   = *pNchars; break;
  2099.                     }
  2100.                 }
  2101.             break;
  2102.  
  2103.         default:
  2104.             return (FALSE);
  2105.         }
  2106.  
  2107.     *ppFmt = pFmt + 1;          /* update callers format string pointer */
  2108.     
  2109.     return (TRUE);              /* successful conversion */
  2110.     }
  2111. /********************************************************************************
  2112. * scanString - perform conversion of space delineated string
  2113. *
  2114. * RETURNS: TRUE if successful, FALSE if unsuccessful.
  2115. */
  2116. LOCAL BOOL scanString
  2117.     (
  2118.     FAST char * pResult,
  2119.     FAST int    fieldwidth,
  2120.     FAST FUNCPTR getRtn,
  2121.     FAST int    getArg,
  2122.     int *       pCh,
  2123.     int *       pNchars
  2124.     )
  2125.     {
  2126.     FAST int ix = 0;
  2127.     FAST int ch = *pCh;
  2128.     while (ch != EOF && ix < fieldwidth)
  2129.         {
  2130.         if (isspace (ch))
  2131.             break;
  2132.         if (pResult != NULL)
  2133.             *pResult++ = (char)ch;
  2134.         GET_CHAR (ch, ix);
  2135.         }
  2136.     if (pResult != NULL)
  2137.         *pResult = EOS;
  2138.  
  2139.     *pCh = ch;
  2140.     *pNchars += ix;
  2141.  
  2142.     return (ix != 0);
  2143.     }
  2144. /********************************************************************************
  2145. * scanChar - perform character conversion
  2146. *
  2147. * RETURNS: TRUE if successful, FALSE if unsuccessful.
  2148. */
  2149. LOCAL BOOL scanChar
  2150.     (
  2151.     FAST char * pResult,
  2152.     FAST int    fieldwidth,
  2153.     FAST FUNCPTR getRtn,
  2154.     FAST int    getArg,
  2155.     FAST int *  pCh,
  2156.     FAST int *  pNchars
  2157.     )
  2158.     {
  2159.     FAST int ch = *pCh;
  2160.     FAST int ix = 0;
  2161.     while (ch != EOF && ix < fieldwidth)
  2162.         {
  2163.         if (pResult != NULL)
  2164.             *(pResult++) = (char) ch;
  2165.         GET_CHAR (ch, ix);
  2166.         }
  2167.     *pCh = ch;
  2168.     *pNchars += ix;
  2169.     return (ix != 0);
  2170.     }
  2171. /********************************************************************************
  2172. * scanCharSet - perform user-specified string conversion
  2173. *
  2174. * RETURNS: TRUE if successful, FALSE if unsuccessful.
  2175. *
  2176. * NOMANUAL
  2177. */
  2178.  
  2179. BOOL scanCharSet
  2180.     (
  2181.     FAST char * pResult,
  2182.     int         fieldwidth,
  2183.     FAST const char *charsAllowed,   /* The chars (not) allowed in the string */
  2184.     FAST FUNCPTR getRtn,
  2185.     FAST int    getArg,
  2186.     int *       pCh,
  2187.     int *       pNchars
  2188.     )
  2189.     {
  2190. #define NUM_ASCII_CHARS 128
  2191.     char lastChar = 0;
  2192.     char charsAllowedTbl [NUM_ASCII_CHARS];
  2193.     FAST BOOL allowed;
  2194.     int nx;
  2195.     FAST int ix;
  2196.     FAST int ch;
  2197.  
  2198.     if (*charsAllowed++ != '[')         /* skip past the [ */
  2199.         return (FALSE);
  2200.  
  2201.     /* chars in table will (not) be allowed */
  2202.  
  2203.     if (*charsAllowed == '^')
  2204.         {
  2205.         allowed = FALSE;
  2206.         ++charsAllowed;                 /* skip past ^ */
  2207.         }
  2208.     else
  2209.         allowed = TRUE;
  2210.  
  2211.     /* initialize table to (not) allow any chars */
  2212.  
  2213.     for (ix = 0; ix < NUM_ASCII_CHARS; ix++)
  2214.         charsAllowedTbl [ix] = !allowed;
  2215.  
  2216.     /* Check for the first char of the set being '-' or ']', in which case
  2217.      * they are not special chars.
  2218.      */
  2219.  
  2220.     if (*charsAllowed == '-' || *charsAllowed == ']')
  2221.         charsAllowedTbl [(int)(*charsAllowed++)] = allowed;
  2222.  
  2223.     /* Examine the rest of the set, and put it into the table. */
  2224.  
  2225.     for (nx = 0; nx < NUM_ASCII_CHARS; nx++)
  2226.         {
  2227.         if (*charsAllowed == ']' || *charsAllowed == EOS)
  2228.             break;      /* all done */
  2229.  
  2230.         /* Check if its of the form x-y.
  2231.          * If x<y, then allow all chars in the range.
  2232.          * If x>=y, its not a legal range.  Just allow '-'.
  2233.          * Also, if the '-' is the last char before the final ']',
  2234.          * just allow '-'.
  2235.          */
  2236.         if (*charsAllowed == '-' &&
  2237.             (lastChar < *(charsAllowed+1) && *(charsAllowed+1) != ']'))
  2238.             {
  2239.             ++charsAllowed;     /* skip - */
  2240.             for (ix = lastChar; ix <= *charsAllowed; ix++)
  2241.                 charsAllowedTbl [ix] = allowed;
  2242.             }
  2243.         else
  2244.             {
  2245.             charsAllowedTbl [(int)(*charsAllowed)] = allowed;
  2246.             lastChar = *charsAllowed;
  2247.             }
  2248.         ++charsAllowed;
  2249.         }
  2250.  
  2251.     /* make sure that ']' appeared */
  2252.  
  2253.     if (*charsAllowed != ']')
  2254.         return (FALSE);
  2255.  
  2256.     /* Copy the appropriate portion of the string */
  2257.  
  2258.     ix = 0;
  2259.     ch = *pCh;
  2260.  
  2261.     while (ch != EOF && ix < fieldwidth)
  2262.         {
  2263.         if (! charsAllowedTbl [(int)ch])
  2264.             break;
  2265.  
  2266.         if (pResult != NULL)
  2267.             *pResult++ = (char) ch;
  2268.  
  2269.         GET_CHAR (ch, ix);
  2270.         }
  2271.  
  2272. /* If no characters were copied from the input, then this assignment
  2273. has failed */
  2274. if(ix == 0)
  2275. return (FALSE);
  2276. else
  2277. {
  2278.      if (pResult != NULL)
  2279.          *pResult = EOS;
  2280.  
  2281.      *pCh = ch;
  2282.      *pNchars += ix;
  2283.      return (TRUE);
  2284. }
  2285.     }
  2286. /********************************************************************************
  2287. * scanNum - perform number conversion
  2288. *
  2289. * RETURNS: TRUE if successful, FALSE if unsuccessful.
  2290. */
  2291.  
  2292. LOCAL BOOL scanNum
  2293.     (
  2294.     int         base,
  2295.     FAST void * pReturn,
  2296.     int         returnSpec,
  2297.     int         fieldwidth,
  2298.     FAST FUNCPTR getRtn,
  2299.     FAST int    getArg,
  2300.     int *       pCh,
  2301.     int *       pNchars
  2302.     )
  2303.     {
  2304.     int         dig;                    /* current digit */
  2305.     BOOL        neg     = FALSE;        /* negative or positive? */
  2306.     long long   num     = 0;            /* scanned number */
  2307.     FAST int    ix      = 0;            /* present used width */
  2308.     FAST int    ch      = *pCh;         /* current character */
  2309.  
  2310.     /* check for sign */
  2311.  
  2312.     if (ix < fieldwidth)
  2313.         {
  2314.         if ((char)ch == '+' || (neg = ((char)ch == '-')))
  2315.             GET_CHAR (ch, ix);
  2316.         }
  2317.  
  2318.  
  2319.     /* check for optional 0 or 0x */
  2320.  
  2321.     if (ix < fieldwidth && ch == '0')
  2322.         {
  2323.         GET_CHAR (ch, ix);
  2324.  
  2325.         if ((ix < fieldwidth) &&
  2326.             (ch == 'x' || ch == 'X') &&
  2327.             (base == 16 || base == 0))
  2328.             {
  2329.             base = 16;
  2330.             GET_CHAR (ch, ix);
  2331.             }
  2332.         else if (base == 0)
  2333.             base = 8;
  2334.         }
  2335.     else
  2336.         {
  2337.         /* default base is 10 */
  2338.         if (base == 0)
  2339.             base = 10;
  2340.         }
  2341.  
  2342.  
  2343.     /* scan digits */
  2344.  
  2345.     while (ch != EOF && ix < fieldwidth)
  2346.         {
  2347.         if (isdigit (ch))
  2348.             dig = ch - '0';
  2349.         else if (islower (ch))
  2350.             dig = ch - 'a' + 10;
  2351.         else if (isupper (ch))
  2352.             dig = ch - 'A' + 10;
  2353.         else
  2354.             break;
  2355.  
  2356.         if (dig >= base)
  2357.             break;
  2358.  
  2359.         num = (num * base) + dig;
  2360.  
  2361.         GET_CHAR (ch, ix);
  2362.         }
  2363.  
  2364.  
  2365.     /* check that we scanned at least one character */
  2366.  
  2367.     if (ix == 0)
  2368.         return (FALSE);
  2369.  
  2370.  
  2371.     /* return value to caller */
  2372.  
  2373.     if (neg)
  2374.         num = -num;
  2375.  
  2376.     if (pReturn != NULL)
  2377.         {
  2378.         switch (returnSpec)
  2379.             {
  2380.             case 'h': *((short *) pReturn) = num; break;
  2381.             case 'l': *((long *) pReturn)  = num; break;
  2382.             case (ll) : *((long long *) pReturn) = num; break;
  2383.             default:  *((int *) pReturn)   = num; break;
  2384.             }
  2385.         }
  2386.  
  2387.     *pCh = ch;
  2388.     *pNchars += ix;
  2389.  
  2390.     return (ix != 0);
  2391.     }