windows-nt/Source/XPSP1/NT/sdktools/m4/at.c
2020-09-26 16:20:57 +08:00

263 lines
6.8 KiB
C

/*****************************************************************************
*
* at.c
*
* Arithmetic types.
*
*****************************************************************************/
#include "m4.h"
F STDCALL fWhiteTch(TCH tch);
/*****************************************************************************
*
* AddExpAt
*
* Add the (unsigned) arithmetic value to the Exp hold.
*
* Since the value is never very large, we may as well be recursive.
*
*****************************************************************************/
void STDCALL
AddExpAt(AT at)
{
if (at > 9) {
AddExpAt(at / 10);
}
AddExpTch((TCH)(TEXT('0') + at % 10));
}
/*****************************************************************************
*
* PushAtRadixCtch
*
* Push onto the input stream the specified arithmetic value, in the
* requested radix, padded with zeros to the requested width.
*
* The type is always considered signed.
*
* If a negative value needs to be padded, the zeros are inserted after
* the leading minus sign.
*
* QUIRK! Under AT&T, the leading minus sign does *not* contribute
* to the count! I emulate this quirk...
*
* FEATURE! If the radix is invalid, force it to 10. AT&T doesn't
* check the radix, but I will.
*
* QUIRK! Under AT&T, a negative width is treated as zero.
* I emulate this quirk...
*
* INTERESTING HACK! Since characters are pushed LIFO, we can generate
* the entire output string without needing to use a hold or anything
* else gross like that.
*
*****************************************************************************/
void STDCALL
PushAtRadixCtch(AT atConvert, unsigned radix, CTCH ctch)
{
AT at;
if ((int)ctch < 0) {
#ifdef WARN_COMPAT
Warn("Negative eval width %d silently converted to zero");
#endif
ctch = 0;
}
if (radix < 2 || radix > 36) {
#ifdef WARN_COMPAT
Warn("Invalid radix %d silently converted to 10");
#endif
radix = 10;
}
at = atConvert < 0 ? -atConvert : atConvert;
do {
TCH tch = (TCH)((unsigned long)at % radix);
at = (unsigned long)at / radix;
if (tch < 10) {
PushTch((TCH)(tch + '0'));
} else {
PushTch((TCH)(tch + 'A' - 10));
}
ctch--;
} while (at);
while ((int)ctch > 0) {
PushTch('0');
--ctch;
}
if (atConvert < 0) {
PushTch('-');
}
}
/*****************************************************************************
*
* PushAt
*
* Common case where we want to display the value in base 10
* with no padding.
*
*****************************************************************************/
void STDCALL
PushAt(AT at)
{
PushAtRadixCtch(at, 10, 0);
}
/*****************************************************************************
*
* SkipWhitePtok
*
* Skip leading whitespace in a token, *MODIFYING* the token in place.
*
*****************************************************************************/
void STDCALL
SkipWhitePtok(PTOK ptok)
{
AssertSPtok(ptok);
Assert(fScratchPtok(ptok));
while (!fNullPtok(ptok) && fWhiteTch(*ptchPtok(ptok))) {
EatHeadPtokCtch(ptok, 1);
}
}
/*****************************************************************************
*
* atRadixPtok
*
* Parse a number out of a token, given the radix. Leading whitespace
* must already have been streipped.
*
* The token is *MODIFIED* to point to the first unconsumed character.
* If no valid digits are found, then zero is returned and the token
* is unchanged.
*
*****************************************************************************/
AT STDCALL
atRadixPtok(unsigned radix, PTOK ptok)
{
AT at = 0;
while (!fNullPtok(ptok)) {
AT atDigit = (TBYTE)*ptchPtok(ptok) - '0';
if ((unsigned)atDigit > 9) {
atDigit = ((TBYTE)*ptchPtok(ptok) | 0x20) - 'a';
if ((unsigned)atDigit > 5) {
break;
}
atDigit += 10;
}
if ((unsigned)atDigit > radix) {
break;
}
at = at * radix + atDigit;
EatHeadPtokCtch(ptok, 1);
}
return at;
}
/*****************************************************************************
*
* fEvalPtokPat
*
* Parse a number out of a token. Leading whitespace must already have
* been stripped. A leading minus sign is not permitted. (`eval'
* would have already parsed it out as a unary operator.) A leading
* zero forces the value to be parsed as octal; a leading `0x' as hex.
*
* The token is *MODIFIED* to point to the first unconsumed character.
* If no valid number is found, then zero is returned. Otherwise,
* nonzero is returned and pat is filled with the parsed value.
*
*****************************************************************************/
F STDCALL
fEvalPtokPat(PTOK ptok, PAT pat)
{
AT at;
AssertSPtok(ptok);
Assert(fScratchPtok(ptok));
if (!fNullPtok(ptok)) {
PTCH ptchStart;
unsigned radix;
/*
* Get the radix...
*/
if (*ptchPtok(ptok) == '0') {
if (ctchSPtok(ptok) > 2 &&
(ptchPtok(ptok)[1] | 0x20) == 'x') {
EatHeadPtokCtch(ptok, 2);
radix = 16;
} else {
radix = 8;
}
} else {
radix = 10;
}
ptchStart = ptchPtok(ptok); /* Remember the start */
at = atRadixPtok(radix, ptok);
if (ptchStart == ptchPtok(ptok)) {
if (radix == 16) {
EatHeadPtokCtch(ptok, (CTCH)-2); /* Restore the `0x' */
}
return 0;
} else {
*pat = at;
return 1;
}
}
return 0; /* No number found */
}
/*****************************************************************************
*
* atTraditionalPtok
*
* Parse a number out of a token. Leading whitespace is ignored.
* A leading minus sign is permitted. Octal and hex notation is
* not permitted. No space is permitted between the optional
* minus sign and the digit string. An invalid input is parsed as zero.
*
*****************************************************************************/
AT STDCALL PURE
atTraditionalPtok(PCTOK ptok)
{
TOK tok;
AssertSPtok(ptok);
DupStaticPtokPtok(&tok, ptok);
D(tok.tsfl |= tsflScratch);
SkipWhitePtok(&tok);
if (!fNullPtok(&tok)) {
AT at;
BOOL fSign;
if (*ptchPtok(&tok) == '-') {
fSign = 1;
EatHeadPtokCtch(&tok, 1);
} else {
fSign = 0;
}
at = atRadixPtok(10, &tok);
if (fSign) {
at = -at;
}
return at;
} else {
return 0;
}
}