home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Audio 4.94 - Over 11,000 Files
/
audio-11000.iso
/
amiga
/
midi
/
obrst103.lha
/
OberSuite-1.03
/
SourceCode
/
ranges.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-23
|
7KB
|
243 lines
/**************************************************************************
* ranges.c: Given a numeric range (such as "12-67"), create a bit
* vector that has its appropriate bits (in this case, bits
* 12 through 67 inclusive) turned on, and all others turned
* off.
* Uses a finite automaton.
* A part of OberSuite for the Commodore Amiga.
*
* Author: Daniel Barrett, barrett@cs.umass.edu.
* Version: 1.0.
* Copyright: None! This program is in the Public Domain.
* Please share it with others.
***************************************************************************/
#include "decl.h"
#include "oberheim.h"
#include "bits.h"
/***************************************************************************
* A dash character is used to separate 2 integers, forming a range.
***************************************************************************/
#define RANGECHAR '-'
/***************************************************************************
* Ranges may contain only non-negative integers. Here is an impossible
* value that we may use to indicate an error condition or uninitialized
* value.
***************************************************************************/
#define GARBAGE_NUMBER (-1)
/***************************************************************************
* Convert a digit character to its numeric value.
***************************************************************************/
#define CH_TO_NUM(ch) ((ch) - '0')
/***************************************************************************
* We assume base 10.
***************************************************************************/
#define BASE 10
/***************************************************************************
* The states for our finite automaton. Described below.
***************************************************************************/
#define RANGE_START 0
#define RANGE_INFIRST 1
#define RANGE_ENDFIRST 2
#define RANGE_INSECOND 3
#define RANGE_DONE 4
#define RANGE_ERROR 5
/***************************************************************************
* Upper and lower limits for range values.
***************************************************************************/
#define UPPER_LIMIT LAST_PATCH
#define LOWER_LIMIT FIRST_PATCH
/****************************************************************************
* MakeRange: An automaton that breaks a numeric range (xx-yy) into its
* two bounds "first" and "second". Return value is 0 on success, >0 else.
*
* If the range is a single integer, then both "first" and "second" are set
* to its value. This is an acceptable "degenerate" range.
*
* The 6 automaton states are:
* RANGE_START: Nothing has been read yet.
* RANGE_INFIRST: At least one digit has been found.
* RANGE_ENDFIRST: A dash has been encountered.
* RANGE_INSECOND: At least one digit has been found after the dash.
* RANGE_ERROR: An illegal character was found.
* RANGE_DONE: Terminating state.
***************************************************************************/
int MakeRange(char *str, int *first, int *second)
{
int state = RANGE_START;
int error = 0;
(*first) = (*second) = GARBAGE_NUMBER;
while ((state != RANGE_DONE))
{
switch (state)
{
/*
* Our first character MUST be a digit.
* Get its value and switch to RANGE_INFIRST state.
*/
case RANGE_START:
if (isdigit(*str))
{
(*first) = CH_TO_NUM(*str);
str++;
state = RANGE_INFIRST;
}
else
state = RANGE_ERROR;
break;
/*
* We have already read a digit, but have not encountered a RANGECHAR.
*
* If we encounter another digit, increase the value of *first.
* If we find a RANGECHAR, we are done with the first number.
* If we reach the end of the string, there is no second number, and
* we have a degenerate range (1 integer).
* Anything else is an error.
*/
case RANGE_INFIRST:
if (isdigit(*str))
{
(*first) *= BASE;
(*first) += CH_TO_NUM(*str);
str++;
}
else if (*str == RANGECHAR)
{
state = RANGE_ENDFIRST;
str++;
}
else if (*str == '\0')
{
(*second) = (*first);
state = RANGE_DONE;
}
else
state = RANGE_ERROR;
break;
/*
* We have just read the RANGECHAR separator.
* We MUST find a digit as the next character.
*/
case RANGE_ENDFIRST:
if (isdigit(*str))
{
(*second) = CH_TO_NUM(*str);
str++;
state = RANGE_INSECOND;
}
else
state = RANGE_ERROR;
break;
/*
* We are in the middle of the second integer.
* Similar logic to that of RANGE_INFIRST, but a RANGECHAR is no
* longer an acceptable input.
*/
case RANGE_INSECOND:
if (isdigit(*str))
{
(*second) *= BASE;
(*second) += CH_TO_NUM(*str);
str++;
}
else if (*str == '\0')
state = RANGE_DONE;
else
state = RANGE_ERROR;
break;
case RANGE_ERROR:
error++;
state = RANGE_DONE;
break;
case RANGE_DONE:
break;
default: /* This should never happen!! */
break;
}
}
return(!error);
}
/***************************************************************************
* Check that both "first" and "second" lie within the legal limits.
* Then, turn on all bits in "bitfield" between first and second, inclusive.
* It doesn't matter which of "first" or "second" is larger; the range
* is still valid.
***************************************************************************/
int AddToRange(BITS bitfield[], int first, int second)
{
int i;
if (!Between(first, LOWER_LIMIT, UPPER_LIMIT)
|| !Between(second, LOWER_LIMIT, UPPER_LIMIT))
return(0);
else if (first <= second)
for (i=first; i<=second; i++)
FlipOn(bitfield, i);
else
for (i=first; i>=second; i--)
FlipOn(bitfield, i);
return(1);
}
/***************************************************************************
* A test program to make sure that ranges are working correctly.
* Compile with -DTEST_RANGE_PROGRAM and link with bits.o and parse.o.
***************************************************************************/
#ifdef TEST_RANGE_PROGRAM
void PrintBitfield(BITS bitfield[], int numBits);
main(argc, argv)
int argc; char *argv[];
{
int i, upper, lower;
BITS bitfield[BITFIELD_LENGTH];
ClearBitfield(bitfield);
for (i=1; i<argc; i++)
if (MakeRange(argv[i], &upper, &lower))
AddToRange(bitfield, upper, lower);
PrintBitfield(bitfield, UPPER_LIMIT+1);
}
void PrintBitfield(BITS bitfield[], int numBits)
{
int i;
for (i=0; i<numBits; i++)
if (BitOn(bitfield, i))
printf(" %d", i);
printf("\n");
}
#endif /* TEST_RANGE_PROGRAM */