home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 1
/
GoldFishApril1994_CD2.img
/
d4xx
/
d478
/
mp
/
source
/
text.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-18
|
10KB
|
390 lines
/**************************************************************************
* text.c: Functions for text input/output.
* Part of MP, the MIDI Playground.
*
* Author: Daniel Barrett
* Version: See the file "version.h".
* Copyright: None! This program is in the Public Domain.
* Please share it with others.
***************************************************************************/
#include "mp.h"
/* Given the currently read character and the current state, compute
* the new state and the MIDI value. */
STATE_T NewState(int c, STATE_T state, MIDI_VALUE *answer)
{
static BOOL inString = FALSE;
if (inString)
return(DoInString(c, state, answer, &inString));
else if (c == HELP_SYMBOL)
{
InputHelp();
return(state);
}
else if (state == STATE_NORMAL && c == '\"')
{
inString = TRUE;
return(STATE_NORMAL); /* Doesn't matter. */
}
else
return(NonStringState(c, state, answer));
}
/****************************************************************************
* Our finite automaton for non-strings. Process the character and return
* the new state.
****************************************************************************/
STATE_T NonStringState(int c, STATE_T state, MIDI_VALUE *answer)
{
switch (state)
{
case STATE_NORMAL: return(DoNormal(c, answer));
case STATE_INCOMMENT: return(DoComment(c));
case STATE_INDECIMAL: return(DoDecimal(c, answer));
case STATE_INOCTAL: return(DoOctal(c, answer));
case STATE_STARTHEX: return(DoHex(c, answer));
case STATE_INHEX: return(DoInHex(c, answer));
case STATE_LEADZERO: return(DoLeadZero(c, answer));
case STATE_INCHAR: return(DoInChar(c, answer));
case STATE_STARTBINARY: return(DoBinary(c, answer));
case STATE_INBINARY: return(DoInBinary(c, answer));
case STATE_EXPECTQUOTE: return(DoExpectQuote(c, answer));
case STATE_BACKSLASHINCHAR:
return(DoBackslash(c, answer, STATE_EXPECTQUOTE));
case STATE_SUCCESS:
case STATE_OVERFLOW:
case STATE_ERROR: return(state);
}
}
/****************************************************************************
* We are not currently in a number. A character is read; decide what to
* do with it.
****************************************************************************/
STATE_T DoNormal(int c, MIDI_VALUE *answer)
{
if (isspace(c))
return(STATE_NORMAL);
else if (c == START_COMMENT)
return(STATE_INCOMMENT);
else if (c == START_BINARY)
return(STATE_STARTBINARY);
else if (c == '\'')
return(STATE_INCHAR);
else if (c == '0')
return(STATE_LEADZERO);
else if (toupper(c) == 'H')
return(STATE_STARTHEX);
else if (isdigit(c))
{
*answer = D_TO_INT(c);
return(STATE_INDECIMAL);
}
else if (isxdigit(c))
{
*answer = H_TO_INT(c);
return(STATE_INHEX);
}
else
return(STATE_ERROR);
}
/****************************************************************************
* Base 10 (decimal) numbers.
****************************************************************************/
STATE_T DoDecimal(int c, MIDI_VALUE *answer)
{
if (isdigit(c))
return(IncreaseIfPossible(answer, D_TO_INT(c), 10,
STATE_INDECIMAL));
else if (isspace(c))
return(STATE_SUCCESS);
else
return(STATE_ERROR);
}
/****************************************************************************
* Octal numbers.
****************************************************************************/
STATE_T DoOctal(int c, MIDI_VALUE *answer)
{
if (isoctal(c))
return(IncreaseIfPossible(answer, D_TO_INT(c), 8,
STATE_INOCTAL));
else if (isspace(c))
return(STATE_SUCCESS);
else
return(STATE_ERROR);
}
/****************************************************************************
* Hexadecimal numbers.
****************************************************************************/
STATE_T DoHex(int c, MIDI_VALUE *answer)
{
if (isxdigit(c))
{
*answer = H_TO_INT(c);
return(STATE_INHEX);
}
else
return(STATE_ERROR);
}
STATE_T DoInHex(int c, MIDI_VALUE *answer)
{
if (isxdigit(c))
return(IncreaseIfPossible(answer, H_TO_INT(c), 16,
STATE_INHEX));
else if (isspace(c))
return(STATE_SUCCESS);
else
return(STATE_ERROR);
}
/****************************************************************************
* Binary numbers.
****************************************************************************/
STATE_T DoBinary(int c, MIDI_VALUE *answer)
{
if ((c == '0') || (c == '1'))
{
*answer = D_TO_INT(c);
return(STATE_INBINARY);
}
else
return(STATE_ERROR);
}
STATE_T DoInBinary(int c, MIDI_VALUE *answer)
{
if ((c == '0') || (c == '1'))
return(IncreaseIfPossible(answer, D_TO_INT(c), 2,
STATE_INBINARY));
else if (isspace(c))
return(STATE_SUCCESS);
else
return(STATE_ERROR);
}
/****************************************************************************
* Hook for negative numbers. Commented out right now.
****************************************************************************/
#ifdef ALLOW_NEGATIVE
STATE_T DoNegative(int c, MIDI_VALUE *answer)
{
if (c == '0')
return(STATE_LEADZERO);
else if (isdigit(c))
{
return(STATE_INDECIMAL);
}
else
return(STATE_ERROR);
}
#endif /* ALLOW_NEGATIVE */
/****************************************************************************
* Leading zero was found: Do octal or hexadecimal as required.
****************************************************************************/
STATE_T DoLeadZero(int c, MIDI_VALUE *answer)
{
if (toupper(c) == 'X')
return(STATE_STARTHEX);
else if (isoctal(c))
{
*answer = D_TO_INT(c);
return(STATE_INOCTAL);
}
else if (isspace(c))
return(STATE_SUCCESS);
else
return(STATE_ERROR);
}
/****************************************************************************
* Append the digit "newNum" onto the right of the number *answer.
* Don't allow overflow. Works for any base. Return newState on success.
****************************************************************************/
STATE_T IncreaseIfPossible(MIDI_VALUE *answer, int newNum, int base,
STATE_T newState)
{
if ((*answer) > (LARGEST_VALUE / base))
return(STATE_OVERFLOW);
else
{
*answer *= base;
if ((*answer) > (LARGEST_VALUE - newNum))
return(STATE_OVERFLOW);
else
{
*answer += newNum;
return(newState);
}
}
}
/****************************************************************************
* Character-oriented routines.
****************************************************************************/
STATE_T DoInChar(int c, MIDI_VALUE *answer)
{
if (c == '\\')
return(STATE_BACKSLASHINCHAR);
else
{
*answer = c;
return(STATE_EXPECTQUOTE);
}
}
STATE_T DoExpectQuote(int c, MIDI_VALUE *answer)
{
return((c == '\'') ? STATE_SUCCESS : STATE_ERROR);
}
STATE_T DoBackslash(int c, MIDI_VALUE *answer, STATE_T newState)
{
switch (c)
{
case '0': *answer = '\0'; break;
case 'a': *answer = '\a'; break;
case 'b': *answer = '\b'; break;
case 'f': *answer = '\f'; break;
case 'n': *answer = '\n'; break;
case 'r': *answer = '\r'; break;
case 't': *answer = '\t'; break;
case 'v': *answer = '\v'; break;
case '\\':
case '\'':
case '\"': *answer = c; break;
default: return(STATE_ERROR);
}
return(newState);
}
/****************************************************************************
* String-oriented routines.
****************************************************************************/
STATE_T DoInString(int c, STATE_T state, MIDI_VALUE *answer, BOOL *inString)
{
switch (state)
{
case STATE_NORMAL:
if (c == '\"')
{
*inString = FALSE;
return(STATE_NORMAL);
}
else if (c == '\\')
return(STATE_BACKSLASHINSTRING);
else
{
*answer = isspace(c) ? ' ' : c;
return(STATE_SUCCESS);
}
break;
case STATE_BACKSLASHINSTRING:
return(DoBackslash(c, answer, STATE_SUCCESS));
}
}
/****************************************************************************
* Handling comments. Everything from comment symbol to the end of the
* line is a comment.
****************************************************************************/
STATE_T DoComment(int c)
{
return( (c == '\n') ? STATE_NORMAL : STATE_INCOMMENT );
}
/****************************************************************************
* Getting help.
****************************************************************************/
void InputHelp()
{
fprintf(stderr, "INPUT\tMEANING\n"
"1-9...\tDecimal number.\n"
"0...\tOctal number.\n"
"0x...\tHexadecimal number (case-insensitive).\n"
"H...\tHexadecimal number (case-insensitive).\n"
"A-F...\tHexadecimal number (case-insensitive).\n"
"#...\tBinary number.\n"
"'x'\tThe character 'x'."
" C character syntax like \\n and \\t is valid.\n"
"\"...\"\tA text string."
" (Newlines turn into space characters.)\n"
"Largest legal input value is %ld (base 10).\n"
"All values must be separated by whitespace.\n\n",
LARGEST_VALUE);
}
/****************************************************************************
* Text output functions.
****************************************************************************/
void PrintNumber(MIDI_VALUE number, FILE *out)
{
fprintf(out, "Dec %3ld, Oct %3lo, Hex %3lX",
number, number, number);
PrintBinary(number, out);
if (isprint((char)number))
fprintf(out, ", Char '%c'", number);
putc('\n', out);
}
void PrintBinary(MIDI_VALUE number, FILE *out)
{
char buf[BITS_IN_MIDI_VALUE + 1];
int i, on;
for (i=0; i<BITS_IN_MIDI_VALUE; i++)
{
on = number & (1 << i);
buf[BITS_IN_MIDI_VALUE-i-1] = '0' + (char)(on && 1);
}
buf[BITS_IN_MIDI_VALUE] = '\0';
fprintf(out, ", Bin %s", buf);
}