/* * 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)); }