2025-04-27 07:49:33 -04:00

300 lines
7.8 KiB
C

/****************************Module*Header***********************************\
* Module Name: RSCANF.C
*
* Module Descripton: Small substitute for library function sscanf().
*
* Warnings:
*
* Created: 15 July 1993
*
* Author: Raymond E. Endres [rayen@microsoft.com]
\****************************************************************************/
#include <windows.h>
#include <stdio.h>
#include <stdarg.h> // !!! This shouldn't pull in any run-time libs.
#include "rscanf.h"
char achWhiteSpace[128]; // !!! Must be initialized.
void vInitWhiteSpace(void);
BOOL bScanfD(const char **, int *);
BOOL bScanfLD(const char **, long *);
BOOL bScanfS(const char **, char *);
BOOL bScanfU(const char **, UINT *);
/****************************************************************************\
* rscanf
*
* rscanf reads from szBuffer under control of szFormat, and assigns converted
* values through subsequent arguments, each of which must be a pointer.
* It returns when format is exhausted. rscanf returns EOF if end of szBuffer
* or an error occurs before any conversion; otherwise it returns the
* number of input items converted and assigned.
*
* Conversion specifications supported:
* %d decimal integer
* %ld long decimal integer
* %u unsigned integer (!!! This only does decimals.)
* %s string
\****************************************************************************/
int rscanf(const char *szBuffer, const char *szFormat, ...)
{
va_list ap; // Argument pointer: will point to each unnamed arg.
int cItems = 0; // Count of items converted.
vInitWhiteSpace(); // !!! We might want to call this elsewhere.
va_start(ap, szFormat); // Init argument pointer.
// Walk szFormat.
while (TRUE) {
while (achWhiteSpace[*szFormat]) // Find non-white space character.
szFormat++;
if (*szFormat == 0) // Success. End of szFormat.
break;
if (*szFormat != '%') {
cItems = EOF;
break;
}
szFormat++;
if (*szFormat == 'd') { // decimal integer
if (bScanfD(&szBuffer, (int *)va_arg(ap, int *))) {
cItems++;
}
else {
cItems = EOF;
break;
}
szFormat++;
}
else if (*szFormat == 'l' && szFormat[1] == 'd') { // decimal long
if (bScanfLD(&szBuffer, (long *)va_arg(ap, long *))) {
cItems++;
}
else {
cItems = EOF;
break;
}
szFormat += 2;
}
else if (*szFormat == 'u') { // unsigned integer (!!! decimal)
if (bScanfU(&szBuffer, (int *)va_arg(ap, int *))) {
cItems++;
}
else {
cItems = EOF;
break;
}
szFormat++;
}
else if (*szFormat == 's') { // string
if (bScanfS(&szBuffer, (char *)va_arg(ap, char *))) {
cItems++;
}
else {
cItems = EOF;
break;
}
szFormat++;
}
else {
cItems = EOF;
break;
}
}
va_end(ap); // Clean up argument pointer.
return cItems;
}
/****************************************************************************/
void vInitWhiteSpace(void)
{
int i;
for (i=0; i<128; i++)
achWhiteSpace[i] = 0;
achWhiteSpace[' '] = 1; // blanks
achWhiteSpace['\t'] = 1; // tabs
achWhiteSpace['\n'] = 1; // newlines
achWhiteSpace['\r'] = 1; // carriage returns
achWhiteSpace['\v'] = 1; // vertical tabs
achWhiteSpace['\f'] = 1; // form feeds
}
/****************************************************************************/
BOOL bScanfS(const char **pszBuffer, char *psz)
{
int i = 0; // Index of the destination buffer.
// Advance *pszBuffer to the first non-white space character. This will
// also terminate when zero is found.
while (achWhiteSpace[**pszBuffer])
(*pszBuffer)++;
// Return failure if zero was found.
if (**pszBuffer == 0)
return FALSE;
// Copy the string until we hit a white space character or a zero.
while (**pszBuffer && !achWhiteSpace[**pszBuffer]) {
psz[i++] = **pszBuffer;
(*pszBuffer)++;
}
// Terminate the destination string with a zero.
psz[i] = 0;
// NOTE: If **pszBuffer equals zero right now, do we return TRUE or FALSE?
// I'm doing what makes the most sense to me. !!!
return TRUE;
}
/****************************************************************************/
BOOL bScanfD(const char **pszBuffer, int *pi)
{
int iSign = 1; // Set to 1 or -1.
int iValue = 0;
// Advance *pszBuffer to the first non-white space character. This will
// also terminate when zero is found.
while (achWhiteSpace[**pszBuffer])
(*pszBuffer)++;
// Return failure if zero was found.
if (**pszBuffer == 0)
return FALSE;
// Is it negative?
if (**pszBuffer == '-') {
iSign = -1;
(*pszBuffer)++;
}
// Are we at the beginning of a valid decimal integer?
if (**pszBuffer < '0' || **pszBuffer > '9')
return FALSE;
// Compute the value of the decimal integer. This will terminate at the
// first non-decimal character, including zero.
// !!! This could be a little faster if we used another table.
while (**pszBuffer >= '0' && **pszBuffer <= '9') {
iValue *= 10;
iValue += **pszBuffer - '0';
(*pszBuffer)++;
}
// Return the decimal integer.
*pi = iValue * iSign;
return TRUE;
}
/****************************************************************************/
BOOL bScanfLD(const char **pszBuffer, long *pl)
{
long iSign = 1; // Set to 1 or -1.
long iValue = 0;
// Advance *pszBuffer to the first non-white space character. This will
// also terminate when zero is found.
while (achWhiteSpace[**pszBuffer])
(*pszBuffer)++;
// Return failure if zero was found.
if (**pszBuffer == 0)
return FALSE;
// Is it negative?
if (**pszBuffer == '-') {
iSign = -1;
(*pszBuffer)++;
}
// Are we at the beginning of a valid decimal long?
if (**pszBuffer < '0' || **pszBuffer > '9')
return FALSE;
// Compute the value of the decimal long. This will terminate at the
// first non-decimal character, including zero.
// !!! This could be a little faster if we used another table.
while (**pszBuffer >= '0' && **pszBuffer <= '9') {
iValue *= 10;
iValue += **pszBuffer - '0';
(*pszBuffer)++;
}
// Return the decimal long.
*pl = iValue * iSign;
return TRUE;
}
/****************************************************************************/
BOOL bScanfU(const char **pszBuffer, UINT *pu)
{
UINT uValue = 0;
// Advance *pszBuffer to the first non-white space character. This will
// also terminate when zero is found.
while (achWhiteSpace[**pszBuffer])
(*pszBuffer)++;
// Return failure if zero was found.
if (**pszBuffer == 0)
return FALSE;
// Are we at the beginning of a valid decimal integer?
if (**pszBuffer < '0' || **pszBuffer > '9')
return FALSE;
// Compute the value of the decimal integer. This will terminate at the
// first non-decimal character, including zero.
// !!! This could be a little faster if we used another table.
while (**pszBuffer >= '0' && **pszBuffer <= '9') {
uValue *= 10;
uValue += **pszBuffer - '0';
(*pszBuffer)++;
}
// Return the decimal integer.
*pu = uValue;
return TRUE;
}
/****************************************************************************/