--------------------------------------------------------------------------
*                                                                        *
*                       AMIGA 'C' FOR BEGINNERS                          *
*                                                                        *
* TYPED IN BY RAZOR BLADE OF ALLIANCE.                                   *
*                                                                        * 
* GREETS TO :-  VIPER , BLACKBEARD , ARAMIS , CHAOS , MIT , SHADOWFAX    *
*               AND THE ALCHEMIST.                                       *
*------------------------------------------------------------------------*

--------------------------------------------------------------------------

==========================================================================

--------------------------------------------------------------------------

                     CHAPTER 17 - USER DEFINED LIBRARIES.

One advantage of the programming in C is the modular construction of
programs, which can accept existing functions used in other programs. The
#include directive lets you add external files that have frequently used
functions to the current program before compiling. The compiler processes
one large file instead of several small files.

Every C programmer writes his own functions at some time or another. You've
already entered two functions  (STRLEN and STRCPY); let's use these. Most
compilers contain these functions. However, viewing them can give us an
understanding of how user written functions work.

Save these functions to your own file under the name STRING.C. You can
include these functions in your own program using the #include directive.
The following line searched the main directory for the INCLUDE file
STRING.C

        #include "string.c"

The following line also adds the STRING.C file to the main file;

        #include <string.c>

Of the two syntaxes, the second line is much more flexible than the first
since it searches many different directories for the same file.

Most C implementations have INCLUDE files as standard equipment. Files with
.h extensions contain mostly #define directives. You can find these
functions in a file such as AMIGA.LIB or LC.LIB. Include files can be
included on demand. The syntax reads;

        #include <file.h>

Before starting with INCLUDE, first you need something that can be
included. A useful function can be written to compare strings. Since
strings are not elementary data types they cannot be compared with;

         if(string1 == string2) /* this is wrong ! */

If you wrote the variables string1 and string2 as character arrays, the
name would correspond to the address of the first element (&string1[0]).
Therefore the addresses of the two arrays always differ. Since both arrays
have been assigned by the compiler to separate memory locations for their
char entries the comparison is completely useless. The only case
(theoretically) in which this IF test can be fulfilled is if one or the
other variable was defined as a pointer and if the pointer pointed to the
same string. This method doesn't work.

                                PAGE 153        

--------------------------------------------------------------------------

17.1 THE STRCMP FUNCTION.

You now have to write a program to compare each element of the first string
one at a time with each element of the second string:

        strcmp(s,t)
        register char *s, *t;
        {
           while(*s==*t)
              {
              if (!*s)
              return(0); /* end reached (*s==0) */
              s++;
              t++;
              }
           return(*s - *t);
        }

The STRCMP function compares the characters of the S string with those of
the T string. As long as the characters are equal (*s==*t), the WHILE loop
executes. A test determines whether the last character matches the \0
marker EOS (end of string). If so, both strings must be identical, since S
and T end with EOS. Otherwise the pointers move to the next element and the
process repeats. 

If a character appears within S which differs from the T character, the
WHILE loop terminates and the difference between the two characters (*s -
*t) returns to the calling program. Negative values indicate that the S
string was smaller than T. Positive values mean the opposite. A null
returned after the IF test indicates that both strings are completely
identical.

Store this function and the other two files below as STRINGFUNC.C. Since
the older STRLEN routine could be improved, we will use pointers this time.
Instead of the indices, the pointer moves over all entries of the string up
to the EOS character. The start value must be stored first so that the
number of increments can be computed. That is faster than counting with an
additional variable. The STRINGFUNC.C file therefore appears as follows:

        /* stringfunc.c 17.1 */

        strcpy(to, from)
        register char *to,*from;
        {
           while(*to++ = *from++)
           ;
         }

                                PAGE 154

--------------------------------------------------------------------------

        strlen(s) /* Conversion to pointer */
        register char *s;
        {
           register char *help = s; /* store initial position */
           while(*s)
            s++;
           return (s-help);
           /* difference between pointers is element number */
        }


        strcmp(s,t)
        register char *s, *t;
        {
           while(*s==*t)
           {
              if(!*s)
              return(0); /* end reached (*s==0) */
              s++;
              t++;
           }
           return(*s - *t); /* difference between two strings */
        }

Now let's see if they function properly. For this you'll use two strings
which are initialised in the program.

        /* stringtest.c 17.2 */

        #include "stringfunc.c"

        /* global arrays can be initialised ! */

        char string1[] = "hello!";
        char string2[7] = {'h','e','l','l','o','!',0};

        main()
        {
           printf("\nComparison of >%s< and >%s< is%d\n",string1,string2,
                 strcmp(string1,string2));
           printf("Now >%s< and >%s< result in %d\n\n",string1,"huhu!",
                 strcmp(string1,"huhu!"));
        }

First we will look at the expected results of the function call STRCMP. The
first call returns 0 since both strings are equal. The second function call
returns -16. This number is the result of the comparison of the E and U
characters. This means that the first different character in the string
("hello!") is smaller than the first different character in the second
string ("huhu!").

Array initialisation is new to this program. Until now each element was
stored idividually. Automatic variables wouldn't allow storage in any other
form. With GLOBAL variables, a string can be initialised directly or as in
the second example, every character is initialised separately.

                                PAGE 155

--------------------------------------------------------------------------

In the first example there wasn't even an indication of how many elements
string1[] should have. This is another indication that the C language was
intended for those who consider laziness a virtue. The compiler must
determine the number of the character on it's own. It initialises string1
with 7 elements (don'f forget the null byte at the end.). Those who prefer
can indicate the value as in the second example.

If you assign elements individually (example 2) to the fields they must be
contained in braces and separated by commas. For multiple dimensions,
multiple braces must be used.

        int field[4][4] =
        {
        { 1, 2, 3, 4 } ,
        ( 6, 3, 4, 9 } ,
        { 3, 4, 5, 6 } ,
        {12, 9, 0, 2 } ,
        };

This formulation assigns field [4][4] the proper values where the first
values {1, 2, 3, 4} are stored in the fields FIELd[0][0] to FIELD[0][3].
The inner braces are not required on some compilers and the directive could
appear as follows:

        int field[4][4] = {1,2,3,4,6,3,4,9,3,4,5,6,12,9,0,2};

When some elements are not initialised, they don't have to be listed. All
elements left out are automatically assigned a null.

        int field[3][3] = 
        {
          {3, 2},
          {4},
          {3, 4, 5},
        };

The fields FIELD[0][2], field[1][1] and field[1][2] contain nulls. A
semicolon must follow the definition. After the inner braces and the last
brace there must be commas. Remember that initialisation only affects
GLOBAL or STATIC variables and not AUTO variables.

                                PAGE 156

--------------------------------------------------------------------------

17.2 ITOA

Another routine seen frequently in connection with strings is ITOA (Integer
to ASCII). It converts an integer value into the corresponding character
string. When you pass the number 123 ITOA returns the string "123" in a
character array. This is very important when preparing text that contains
numbers. All convewrsions usually preformed by PRINTF can also be done with
user functions.

The ITOA function requires, as parameters, an integer value which it can
convert and, and a string to store the result. The head of the function
definition reads as follows;

        itoa(n, s)
        char s[];
        int n;

The modulo operator % performs the conversion. By dividing the number by 10
you obtain the last place. Then the code for the number '0' is added to get
the first character. The number is then divided by 10 to shift it left one
space and the last number drops off. The same procedure is performed on the
new last position. The program section for this process appears as follows,
if the index for the character array is called I;

        do
           s[i++] = n % 10 + '0';
        while ((n/=10) > 0);

The last place is converted and stored in S until the number which was
stored in N has reached 0 through constant division. The sign should not be
forgotten since it could cause problems for the loop (number larger than
0). The simplest process makes the number positive before the conversion and ,
if necessary, sets a flag for a negative value. After the completed
conversion , the string returns the minus sign.

The completed processing converts the number 123 into the string "321", but
only the last place is processed and stored in the string. The solution to
this problem is very simple. Write another function that reverses the
string. Assuming that such a function already exists (see the next section
for the function) the routine would appear as follows:

                                PAGE 137
                                

--------------------------------------------------------------------------

        /**********************************/
        /* Name : itoa                    */
        /* Parameter: n(int), s(string)   */
        /* Function: Convert int to string*/
        /* Comment :Requires Reverse()    */
        /**********************************/

        #define EOS '0'
        #define FALSE 0
        #define TRUE 1

        itoa(n, s)
        register int n;
        register char *s;
        {
            register int i=0;
            register int sign = FALSE;

            if(n < 0)
              {
                sign = TRUE;
                n = -n;
              }
            do
              s[i++] = n % 10 + '0';
            while( n/=10);
            if(sign)
               s[i++] = '-';
            s[i] = EOS;
            reverse(s);
        }

The large header contains important information. The function developed by
the user should be ready for use when it is finished. After some time the
function name and the parameters to be passed may have been forgotten. At
that time you could consult the header with it's comments. The function can
be compiled independant of other functions. If the compiler permits it, it
can be stored in a library. Of course the source files can be included into
the current file with:

        #include "itoa.c"

This increases compiler time, of course.

Since this function should be accepted in the library, it should be the
latest state-of-art. This can be done with the ITOA function by defining
all variables as REGISTER variables. The define required for this function
sshould not be omitted, even it appears somewhat cumbersome to determine a
define for a single application. It improves readability since larger
programs usually access these macros.

                                PAGE 158

--------------------------------------------------------------------------

17.3  REVERSE.

Now to the REVERSE function which can reverse a string passed to it.
Construction of the routine doesn't present a problem. Two pointers, or
indices, are needed for the beginning and end of the string. These pointers
exchange their elements between themselves and are then moved toward each
other. The pointer at the beginning is incremented and the one at the end
is decremented. Exchange continues until the two pointers are equal, i.e.,
point to the same element. The routine is presented complete with a
commented header.

        /***********************************/
        /* Name: Reverse                   */
        /* Parameter: s(string)            */
        /* Function: Reverse string        */
        /* Comment : Requires STRLEN()     */
        /***********************************/

        reverse(s)
        register char *s;
        {
            register int c, i, j;

        for (i=0, j=strlen(s) - 1; i<j; i++,j--)
            {
                c   = s[i];
                s[i]=s[j];
                s[j]=c;
            }
        }

The STRLEN function initialises the index J, which sould point to the last
element of S. Every C compiler pachake has STRLEN included in one of it's
libraries, or you can use the STRLEN function defined in the previous
chapter. Both routine (ITOA and REVERSE) should be stored in the library
labelled ITOA.C since it will be accessed later. Please note that the ITOA
routine also comes as standard equipment with most C compilers. These
standard everyday functions have already been written by others.

                                PAGE 159

--------------------------------------------------------------------------
 



