/*
* File: stdgen.h
* -----------------------------------------------------
* The basic definitions provided by stdgen.h are:
*
* 1. Declarations for several new "primitive" types
* (most importantly string) that are
* used throughout the other libraries and
* applications as fundamental types.
*
* 2. A new set of functions for memory allocation.
*
* 3. A function for error handling.
*
* 4. A repeat statement for loops with interior exits.
*/
#ifndef _stdgen_h
#define _stdgen_h
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
/* Section 1: Define new "primitive" types */
/* Type: bool
*--------------------
*
*/
#ifdef T_C
typedef int bool
#else
# ifdef TRUE
# ifndef bool
# define bool int
# endif
# else
# ifdef bool
# define FALSE 0
# define TRUE 1
# else
typedef enum{ FALSE,TRUE} bool;
# endif
# endif
#endif
/*
* Type: string
* ------------
* The type string is identical to the type char *, which is
* traditionally used in C programs. The main point of defining a
* new type is to improve program readability. At the abstraction
* levels at which the type string is used, it is usually not
* important to take the string apart into its component characters.
* Declaring it as a string emphasizes this atomicity.
*/
typedef char *string;
/*
* Type: stream
* ------------
* Like string, the stream type is used to provide additional
* readability and is defined to be equivalent to FILE *
* (which is particularly confusing because it violates
* standard case conventions). This type is not used in
* the text but is preserved in genlib.h, so it is possible
* to teach all of CS1 without exposing any pointers.
*/
typedef FILE *stream;
/*
* Constant: UNDEFINED
* -------------------
* Besides NULL, the only other constant of pointer type is
* UNDEFINED, which is used in certain packages as a special
* sentinel to indicate an undefined pointer value. In many
* such contexts, NULL is a legitimate data value and is
* therefore inappropriate as a sentinel.
*/
#define UNDEFINED ((void *) undefined_object)
extern char undefined_object[];
/* Section 2: Memory allocation */
/*
* General notes:
* --------------
* These functions provide a common interface for memory
* allocation. All functions in the library that allocate
* memory do so using GetBlock and FreeBlock.
*/
/*
* Function: GetBlock
* Usage: ptr = (type) GetBlock(nbytes);
* -------------------------------------
* GetBlock allocates a block of memory of the given size. If
* no memory is available, GetBlock generates an error.
*/
void *GetBlock(size_t nbytes);
/*
* Function: FreeBlock
* Usage: FreeBlock(ptr);
* ----------------------
* FreeBlock frees the memory associated with ptr, which must
* have been allocated using GetBlock, New, or NewArray.
*/
void FreeBlock(void *ptr);
/*
* Macro: New
* Usage: p = New(pointer-type);
* -----------------------------
* The New pseudofunction allocates enough space to hold an
* object of the type to which pointer-type points and returns
* a pointer to the newly allocated pointer. Note that
* "New" is different from the "new" operator used in C++;
* the former takes a pointer type and the latter takes the
* target type.
*/
#define New(type) ((type) GetBlock(sizeof *((type) NULL)))
/*
* Macro: NewArray
* Usage: p = NewArray(n, element-type);
* -------------------------------------
* NewArray allocates enough space to hold an array of n
* values of the specified element type.
*/
#define NewArray(n, type) ((type *) GetBlock((n) * sizeof (type)))
/* Section 3: Basic error handling */
/*
* Function: Error
* Usage: Error(msg, ...)
* ----------------------
* Error generates an error string, expanding % constructions
* appearing in the error message string just as printf does.
* If an error handler exception has been introduced, the
* ErrorException exception is raised with the expanded error
* string as argument. If there is no ErrorException defined,
* the program exits with a status code indicating failure.
* The length of the error message string following expansion
* must not exceed MaxErrorMessage, and it is the client's
* responsibility to ensure this.
*/
void Error(string msg, ...);
/* Section 4:The repeat pseudo-statement */
/*
* Statement form: repeat { ... }
* ------------------------------
* Some instructors who have taught CS1 using this library
* have found that using
*
* while (TRUE)
*
* to initiate a loop with an interior exit is confusing to
* students, particularly when it comes at the beginning of
* the course. This macro defines "repeat" as an infinite
* loop construct for instructors who find it easier to
* explain, although it is not used in the text. Similar
* macro definitions are common in industry.
*/
#define repeat for (;;)
#endif /*stdgenlib.h*/
/*
* File: stdgen.c
* -----------------------------------------------------
* This file implements the general C library package. See the
* interface description in stdgen.h for details.
*/
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <stdarg.h>
#include "stdgen.h"
/*
* Constants:
* ----------
* ErrorExitStatus -- Status value used in exit call
* MaxErrorMessage -- Longest error message allowed
*/
#define ErrorExitStatus 1
#define MaxErrorMessage 500
/* Section 1: Define new "primitive" types */
/*
* Constant: UNDEFINED
* -------------------
* This entry defines the target of the UNDEFINED constant.
*/
char undefined_object[] = "UNDEFINED";
/* Section 2: Memory allocation */
/*
* Implementation notes:
* ---------------------
* The code for the memory allocator is The
* intention is to minimize the size of object files
* produced by linkers that search a library for modules
* that are actually referenced.
*/
/* Memory allocation implementation */
void *GetBlock(size_t nbytes)
{
void *result;
result = malloc(nbytes);
if (result == NULL)
Error("No memory available");
return (result);
}
void FreeBlock(void *ptr)
{
free(ptr);
}
/* Section 3:Basic error handling */
/*
* Implementation notes: Error
* ---------------------------
* Writing the Error function requires some care, since it is
* called in circumstances in which parts of the system may be
* broken. In particular, it is not acceptable for Error to
* call GetBlock, since the error condition may be that the
* system is out of memory, in which case calling GetBlock would
* fail. The error string should be allocated dynamically,
* so that this function can be used in reentrant code.
* Note that it is critical to exit if the length bound for
* an error message is exceeded, since this error almost
* certainly corrupts the stack.
*/
void Error(string msg, ...)
{
va_list args;
va_start(args,msg);
fprintf(stderr,"Error: ");
vfprintf(stderr,msg,args);
fprintf(stderr,"\n");
va_end(args);
exit(ErrorExitStatus);
}
/*
* File: stdstr.h
* -----------------------------------------------------
* The strlib.h file defines the interface for a simple
* string library. In the context of this package, strings
* are considered to be an abstract data type, which means
* that the client relies only on the operations defined for
* the type and not on the underlying representation.
*/
/*
* Cautionary note:
* ----------------
* Although this interface provides an extremely convenient
* abstraction for working with strings, it is not appropriate
* for all applications. In this interface, the functions that
* return string values (such as Concat and SubString) do so
* by allocating new memory. Over time, a program that uses
* this package will consume increasing amounts of memory
* and eventually exhaust the available supply. If you are
* writing a program that runs for a short time and stops,
* the fact that the package consumes memory is not a problem.
* If, however, you are writing an application that must run
* for an extended period of time, using this package requires
* that you make some provision for freeing any allocated
* storage.
*/
#ifndef _stdstr_h
#define _stdstr_h
#include "stdgen.h"
/* Section 1:Basic string operations */
/*
* Function: Concat
* Usage: s = Concat(s1, s2);
* --------------------------
* This function concatenates two strings by joining them end
* to end. For example, Concat("ABC", "DE") returns the string
* "ABCDE".
*/
string Concat(string s1, string s2);
/*
* Function: IthChar
* Usage: ch = IthChar(s, i);
* --------------------------
* This function returns the character at position i in the
* string s. It is included in the library to make the type
* string a true abstract type in the sense that all of the
* necessary operations can be invoked using functions. Calling
* IthChar(s, i) is like selecting s[i], except that IthChar
* checks to see if i is within the range of legal index
* positions, which extend from 0 to StringLength(s).
* IthChar(s, StringLength(s)) returns the null character
* at the end of the string.
*/
char IthChar(string s, int i);
/*
* Function: SubString
* Usage: t = SubString(s, p1, p2);
* --------------------------------
* SubString returns a copy of the substring of s consisting
* of the characters between index positions p1 and p2,
* inclusive. The following special cases apply:
*
* 1. If p1 is less than 0, it is assumed to be 0.
* 2. If p2 is greater than the index of the last string
* position, which is StringLength(s) - 1, then p2 is
* set equal to StringLength(s) - 1.
* 3. If p2 < p1, SubString returns the empty string.
*/
string SubString(string s, int p1, int p2);
/*
* Function: CharToString
* Usage: s = CharToString(ch);
* ----------------------------
* This function takes a single character and returns a
* one-character string consisting of that character. The
* CharToString function is useful, for example, if you
* need to concatenate a string and a character. Since
* Concat requires two strings, you must first convert
* the character into a string.
*/
string CharToString(char ch);
/*
* Function: StringLength
* Usage: len = StringLength(s);
* -----------------------------
* This function returns the length of s.
*/
int StringLength(string s);
/*
* Function: CopyString
* Usage: newstr = CopyString(s);
* ------------------------------
* CopyString copies the string s into dynamically allocated
* storage and returns the new string. This function is not
* ordinarily required if this package is used on its own,
* but is often necessary when you are working with more than
* one string package.
*/
string CopyString(string s);
/* Section 2: String comparison functions */
/*
* Function: StringEqual
* Usage: if (StringEqual(s1, s2)) ...
* -----------------------------------
* This function returns TRUE if the strings s1 and s2 are
* equal. For the strings to be considered equal, every
* character in one string must precisely match the
* corresponding character in the other. Uppercase and
* lowercase characters are considered to be different.
*/
bool StringEqual(string s1, string s2);
/*
* Function: StringCompare
* Usage: if (StringCompare(s1, s2) < 0) ...
* -----------------------------------------
* This function returns a number less than 0 if string s1
* comes before s2 in alphabetical order, 0 if they are equal,
* and a number greater than 0 if s1 comes after s2. The
* ordering is determined by the internal representation used
* for characters, which is usually ASCII.
*/
int StringCompare(string s1, string s2);
/* Section 3:Search functions */
/*
* Function: FindChar
* Usage: p = FindChar(ch, text, start);
* -------------------------------------
* Beginning at position start in the string text, this
* function searches for the character ch and returns the
* first index at which it appears or -1 if no match is
* found.
*/
int FindChar(char ch, string text, int start);
/*
* Function: FindString
* Usage: p = FindString(str, text, start);
* ----------------------------------------
* Beginning at position start in the string text, this
* function searches for the string str and returns the
* first index at which it appears or -1 if no match is
* found.
*/
int FindString(string str, string text, int start);
/* Section 4: Case-conversion functions */
/*
* Function: ConvertToLowerCase
* Usage: s = ConvertToLowerCase(s);
* ---------------------------------
* This function returns a new string with all
* alphabetic characters converted to lower case.
*/
string ConvertToLowerCase(string s);
/*
* Function: ConvertToUpperCase
* Usage: s = ConvertToUpperCase(s);
* ---------------------------------
* This function returns a new string with all
* alphabetic characters converted to upper case.
*/
string ConvertToUpperCase(string s);
/* Section 5: Functions for converting numbers to strings */
/*
* Function: IntegerToString
* Usage: s = IntegerToString(n);
* ------------------------------
* This function converts an integer into the corresponding
* string of digits. For example, IntegerToString(123)
* returns "123" as a string.
*/
string IntegerToString(int n);
/*
* Function: StringToInteger
* Usage: n = StringToInteger(s);
* ------------------------------
* This function converts a string of digits into an integer.
* If the string is not a legal integer or contains extraneous
* characters, StringToInteger signals an error condition.
*/
int StringToInteger(string s);
/*
* Function: RealToString
* Usage: s = RealToString(d);
* ---------------------------
* This function converts a floating-point number into the
* corresponding string form. For example, calling
* RealToString(23.45) returns "23.45". The conversion is
* the same as that used for "%G" format in printf.
*/
string RealToString(double d);
/*
* Function: StringToReal
* Usage: d = StringToReal(s);
* ---------------------------
* This function converts a string representing a real number
* into its corresponding value. If the string is not a
* legal floating-point number or if it contains extraneous
* characters, StringToReal signals an error condition.
*/
double StringToReal(string s);
#endif
/*
* File: stdstr.c
* -----------------------------------------------------
* This file implements the stdstr.h interface.
*
* General implementation notes:
* -----------------------------
* This module implements the stdstr library by mapping all
* functions into the appropriate calls to the ANSI <string.h>
* interface. The implementations of the individual functions
* are all quite simple and do not require individual comments.
* For descriptions of the behavior of each function, see the
* interface.
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "stdgen.h"
#include "strlib.h"
/*
* Constant: MaxDigits
* -------------------
* This constant must be larger than the maximum
* number of digits that can appear in a number.
*/
#define MaxDigits 30
/* Private function prototypes */
static string CreateString(int len);
/* Section 1: Basic string operations */
string Concat(string s1, string s2)
{
string s;
int len1, len2;
if (s1 == NULL || s2 == NULL) {
Error("NULL string passed to Concat");
}
len1 = strlen(s1);
len2 = strlen(s2);
s = CreateString(len1 + len2);
strcpy(s, s1);
strcpy(s + len1, s2);
return (s);
}
char IthChar(string s, int i)
{
int len;
if (s == NULL) Error("NULL string passed to IthChar");
len = strlen(s);
if (i < 0 || i > len) {
Error("Index outside of string range in IthChar");
}
return (s[i]);
}
string SubString(string s, int p1, int p2)
{
int len;
string result;
if (s == NULL) Error("NULL string passed to SubString");
len = strlen(s);
if (p1 < 0) p1 = 0;
if (p2 >= len) p2 = len - 1;
len = p2 - p1 + 1;
if (len < 0) len = 0;
result = CreateString(len);
strncpy(result, s + p1, len);
result[len] = '\0';
return (result);
}
string CharToString(char ch)
{
string result;
result = CreateString(1);
result[0] = ch;
result[1] = '\0';
return (result);
}
int StringLength(string s)
{
if (s == NULL) Error("NULL string passed to StringLength");
return (strlen(s));
}
string CopyString(string s)
{
string newstr;
if (s == NULL) Error("NULL string passed to CopyString");
newstr = CreateString(strlen(s));
strcpy(newstr, s);
return (newstr);
}
/* Section 2 : String comparison functions */
bool StringEqual(string s1, string s2)
{
if (s1 == NULL || s2 == NULL) {
Error("NULL string passed to StringEqual");
}
return (strcmp(s1, s2) == 0);
}
int StringCompare(string s1, string s2)
{
if (s1 == NULL || s2 == NULL) {
Error("NULL string passed to StringCompare");
}
return (strcmp(s1, s2));
}
/* Section 3 : Search functions */
int FindChar(char ch, string text, int start)
{
char *cptr;
if (text == NULL) Error("NULL string passed to FindChar");
if (start < 0) start = 0;
if (start > strlen(text)) return (-1);
cptr = strchr(text + start, ch);
if (cptr == NULL) return (-1);
return ((int) (cptr - text));
}
int FindString(string str, string text, int start)
{
char *cptr;
if (str == NULL) Error("NULL pattern string in FindString");
if (text == NULL) Error("NULL text string in FindString");
if (start < 0) start = 0;
if (start > strlen(text)) return (-1);
cptr = strstr(text + start, str);
if (cptr == NULL) return (-1);
return ((int) (cptr - text));
}
/* Section 4 : Case-conversion functions */
string ConvertToLowerCase(string s)
{
string result;
int i;
if (s == NULL) {
Error("NULL string passed to ConvertToLowerCase");
}
result = CreateString(strlen(s));
for (i = 0; s[i] != '\0'; i++) result[i] = tolower(s[i]);
result[i] = '\0';
return (result);
}
string ConvertToUpperCase(string s)
{
string result;
int i;
if (s == NULL) {
Error("NULL string passed to ConvertToUpperCase");
}
result = CreateString(strlen(s));
for (i = 0; s[i] != '\0'; i++) result[i] = toupper(s[i]);
result[i] = '\0';
return (result);
}
/* Section 5 : Functions for converting numbers to strings */
string IntegerToString(int n)
{
char buffer[MaxDigits];
sprintf(buffer, "%d", n);
return (CopyString(buffer));
}
int StringToInteger(string s)
{
int result;
char dummy;
if (s == NULL) {
Error("NULL string passed to StringToInteger");
}
if (sscanf(s, " %d %c", &result, &dummy) != 1) {
Error("StringToInteger called on illegal number %s", s);
}
return (result);
}
string RealToString(double d)
{
char buffer[MaxDigits];
sprintf(buffer, "%G", d);
return (CopyString(buffer));
}
double StringToReal(string s)
{
double result;
char dummy;
if (s == NULL) Error("NULL string passed to StringToReal");
if (sscanf(s, " %lg %c", &result, &dummy) != 1) {
Error("StringToReal called on illegal number %s", s);
}
return (result);
}
/* Private functions */
/*
* Function: CreateString
* Usage: s = CreateString(len);
* -----------------------------
* This function dynamically allocates space for a string of
* len characters, leaving room for the null character at the
* end.
*/
static string CreateString(int len)
{
return ((string) GetBlock(len + 1));
}