home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * Produces a code based on the "Soundex" method originally developed
- * by M.K. Odell and R.C. Russell. Algorithm can be found on page
- * 392 of Knuths' book 'Sorting and Searching', volume 3 of 'The Art
- * of Computer Programming", Addison/Wesley publisher.
- *
- * Program Name: soundx.c
- * coded by: Richard R. Schafer
- *
- *********** RELEASED INTO THE PUBLIC DOMAIN *********************************/
-
- #include "nandef.h"
- #include "extend.h"
-
- #define ISALPHA(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z')
- #define UPPER(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 32 : (c))
-
- #define CODE_ALLOC 5 /** size of code sequence. 4 for code 1 for NIL**/
-
- CLIPPER soundx()
-
- {
- /********************************************
- * the type_defs: Boolean
- * quant
- * byte
- * are defined in the include file "nandef.h"
- ********************************************/
-
- Boolean error;
-
- quant i; /* Both 'i' and 'b' are counters */
- quant b;
- quant name_size;
-
-
- /* 'name' is where we put the parameter and 'short_name' is
-
- where we'll put the string that doesn't contain anything
-
- but ALPHA characters and 'code' is where we'll put the
-
- soundex code that we are developing. */
-
- byte *name;
-
- byte *short_name;
-
- byte *code;
-
-
-
- /* intialize our code holder */
- code = NULL;
-
-
-
- /* If any of these are true, we didn't get a proper parameter */
-
- error = (PCOUNT != 1 || !ISCHAR(1) || _parclen(1) == 0);
-
-
-
- /* If we don't have any errors we'll continue otherwise dropout */
-
- if (!error)
-
- {
-
- /* put the parameter passed into an array */
-
- name = _parc(1);
-
-
-
- /* determine the length the of parameter passed
-
- and add 1 to hold the NIL byte
-
- */
-
- name_size = (quant) (_parclen(1) + 1);
-
-
-
- /* Now that we've got something to work with, lets
-
- convert it to a soundex code. First we have to
-
- allocate some memory for the code to be placed into.
-
- We'll use the function '_exmgrab' to do just that.
-
- */
-
- code = _exmgrab(CODE_ALLOC);
-
-
-
- /* Now we'll initialize all of our arrays to hold NILs */
-
- for (i = 0;i < name_size;i++)
-
- {
-
- short_name[i] = NIL;
- }
-
-
-
- for (i = 0;i < CODE_ALLOC;i++)
-
- {
-
- code[i] = NIL;
-
- }
-
-
-
-
-
- /* now let's get rid of everything we don't want
-
- if it isn't an alpha character, we'll
-
- get rid of it and convert all else to uppercase
-
- */
-
- for (i = 0,b = 0;i < name_size; i++)
-
- {
-
- if (! ISALPHA(name[i]))
-
- {
-
- continue;
-
- }
-
- /* if it is a good character we'll place it into
-
- another array to work from and increment the
-
- second counter 'b' */
-
- short_name[b] = UPPER(name[i]);
-
- b++;
-
- }
-
-
-
- /* The first character gets used as is */
-
- code[0] = short_name[0];
-
-
- /* Then we convert the rest of the string to the proper
-
- soundex numbers according to the algorithm. We'll stay in
-
- the loop until such time as we have either run out of
-
- characters to work with, or we have filled the code.
-
- */
-
- for (i=1,b=1;(short_name[i] != NIL) && (b < (CODE_ALLOC - 1));i++ )
-
- {
-
- switch (short_name[i])
-
- {
-
- /* These are the characters that we want to skip,
-
- so if we match one we'll just go round for the
-
- next character
-
- */
-
- case 'A':
-
- case 'E':
-
- case 'H':
-
- case 'I':
-
- case 'O':
-
- case 'U':
-
- case 'W':
-
- case 'Y':
-
- break;
-
-
-
- /* If we match any of these, they're the good ones
-
- so we'll assign a number to 'code' for them.
-
- */
- case 'B':
-
- case 'F':
-
- case 'P':
-
- case 'V':
-
- code[b] = '1';
-
- b++;
-
- break;
-
- case 'C':
-
- case 'G':
-
- case 'J':
-
- case 'K':
-
- case 'Q':
-
- case 'S':
-
- case 'X':
-
- case 'Z':
-
- code[b] = '2';
-
- b++;
-
- break;
-
- case 'D':
-
- case 'T': code[b] = '3';
-
- b++;
-
- break;
-
- case 'L':
-
- code[b] = '4';
-
- b++;
-
- break;
-
- case 'M':
- case 'N':
-
- code[b] = '5';
-
- b++;
-
- break;
-
- case 'R':
-
- code[b] = '6';
-
- b++;
-
- break;
-
- }
-
-
-
- /* If we haven't gone beyond the last character in
-
- 'short_name'.
-
- */
-
- if (short_name[i + 1] != NIL)
-
- {
-
-
-
- /* Check to see if the next character in the
-
- array is the same as the one we just
-
- evaluated, if so, we want to skip over it.
-
- */
-
- if (short_name[i] == short_name[i + 1])
-
- {
-
- i++;
-
- }
-
- }
-
- }
-
-
- }
-
-
-
- /* If the code isn't filled, we want to pad it with zeroes */
-
- if (b < 4)
-
- {
-
- for (;b < 4;b++)
-
- {
-
- code[b] = '0';
-
- }
-
- }
-
-
-
- /* Now we setup to return the code and then release the memory
-
- that we allocated. We'll use the "_exmback" function to do that.
-
- */
-
- if (!error)
-
- _retc(code);
-
- else
-
- _retc("");
-
-
-
- if (code)
-
- _exmback(code,CODE_ALLOC);
-
-
-
- }
-