Article View: alt.dcom.telecom
Article #292phonewrd - phone # to words and phrases, now using GNU dictionary
From: Eric Haines
Date: Thu, 27 May 1993 20:10
Date: Thu, 27 May 1993 20:10
1727 lines
48251 bytes
48251 bytes
This is for those of you on wimpy commercial systems or girly-man PC's who
were embittered when you watched the various incarnations of phonewrd stream
by on alt.sources. Yes, phonewrd, that fabulous program which looks at your
drab phone number of 364-3663 and finds important phrases like "dogfood" (or
"Enid & Moe" or "Eng. dome" or "fog done" or...). Anywell, this one's for
you: it now accepts the GNU ispell dictionary format (as well as
/usr/dict/words) and creates all the valid word prefix/suffix combinations.
So now just get the ispell distribution dictionaries (details are in the man
page) and you're on your way.
In the fine tradition of Unix (though it also works on PC's), phonewrd has a
man page and a bazillion command line options (maybe three of which are
useful). I was going to add "just one more feature" but decided to call it a
day. So, go ahead: enjoy searching for the hidden meanings in CIA phone
numbers and other paranoia-inducing agencies. Add your own special
dictionaries of extra words and maybe your number will spell "I am Borg" or
something equally nerdy. Show your friends you are indeed a person with too
much time on his/her hands.
All you poor losers with phone numbers having 0's or 1's please ignore this
posting (well, actually, the program will still do its best, and you can also
define these numerals to be Q or Z or sorta O or sorta I or whatever - the
program should allow multiple mappings of numerals to a single letter, but it
doesn't right now. Feel free to fix this if you can understand my
accidentally obfuscatory code).
Eric "asp jig 4" Haines
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Eric Haines <erich@hemlock> on Thu May 27 10:28:15 1993
#
# This archive contains:
# phonewrd.1 phonewrd.c
#
LANG=""; export LANG
PATH=/bin:/usr/bin:$PATH; export PATH
echo x - phonewrd.1
sed 's/^@//' >phonewrd.1 <<'@EOF'
@.\" -*-Text-*-
@.\";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@.\"
@.\" File: phonewrd.1
@.\" Description: phonewrd man page
@.\" Author: Eric Haines, erich@eye.com
@.\" Modified: 4/21/93
@.\" Package: phonewrd
@.\"
@.\" (c) Copyright 1993, Eric Haines, all rights reserved.
@.\"
@.\";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@.TH PHONEWRD 1 "" ""
@.ad l
@.SH NAME
phonewrd \- find words or phrases for phone numbers
@.SH SYNOPSIS
@.BR phonewrd
[\fB-n \fInumerals allowed\fR]
[\fB-s \fIsingle letter words\fR]
[\fB-q \fIq mapping\fR]
[\fB-z \fIz mapping\fR]
[\fB-d \fIdictionary path\fR]
[\fB-l \fIword length\fR]
[\fB-m \fInumeral map\fR]
[\fB-v\fR]
[\fB-r\fR]
[\fB-c\fR]
[\fB-C\fR]
\fBphone_number1[*...]\fR [\fBphone_number2[*...] ...\fR]
@.SH DESCRIPTION
@.B phonewrd
finds words or phrases which match the input phone numbers.
It uses the dictionary word list
@.I /usr/dict/words
by default, ignoring one letter words (see \fB-s\fR).
There are a wide variety of options available to allow various sorts of
pattern matching.
Words with apostrophes or other punctuation are acceptable.
If more than one phone number is given, each number and its combinations are
output.
If the input phone number ends with one or more \fI*\fR, e.g. \fI555-1212**\fR,
then the output phrases can be up to that many characters longer that the input
number.
This usually yields a few extra phrases, and
dialing those extra digits at the end normally doesn't cause problems.
The input phone number can have letters in it, in which case that digit is
forced to be that letter in any phrase.
This can help pare down a long output list for a number.
If the number is entirely letters, it is converted to numbers and output.
If you don't have a dictionary on your system,
a free set of dictionary files are available via FTP from prep.ai.mit.edu
in /pub/gnu/ispell*.tar.z (you'll also need "gzip" in this same directory
to uncompress this archive).
@.B phonewrd
understands the "affix" format in english.aff used for the
dictionaries in version 3.0 of ispell and expands words accordingly.
If you can't get your hands on any dictionary files,
look at the \fB-r\fR, \fB-c\fR, and (for the totally insane) \fB-C\fR options.
These options do not need a dictionary (and so will do either very little or
too much).
@.SH Options
@.ifn .TP 5
@.ift .TP 15
@.B -n \fInumerals allowed\fP
This option allows phone digits to be replaced by numerals, up to the limit
set.
For example
@.B -n 2
means that any two digits of the phone number can be left as digits and not
made a part of any word.
This can help find phrases for phone numbers with poor letter combinations.
Note that numerals that have no corresponding letters
(i.e. 0 and 1 by default) do not count against this total, nor do one letter
words set using \fB-s\fR.
Default setting is 0.
@.TP
@.B -s \fIsingle letter words\fP
This option gives all allowed single letter words (including numeral "words",
e.g. "I love U 2").
Normally dictionaries have all letters of the alphabet as being legal words,
which gives a ton of useless phrases.
By default the only allowed single letter words are "a", "i", and "o".
As an example of how to change this,
@.B -s abcdgimoptuxy248
means that any of these single letters are now considered words.
This can help find phrases for phone numbers with awful
letter combinations and in general open up more possibilities.
To have no single letter words at all, use \fB-s =\fR.
@.TP
@.B -q \fImapping\fP
This option maps the letter
@.I q
to the given numeral.
For example,
@.B -q 0
means that phone numbers with 0's in them can have \fIq\fR's
substituted for the 0's.
This usually doesn't help much anyway, and it's up to you to remember that
@.I q
== 0, but there you go.
By default
@.I q
is not mapped.
@.TP
@.B -z \fImapping\fP
Amazingly similar to \fB-q\fR.
This option maps the letter
@.I z
to the given numeral.
For example,
@.B -z 0
means that phone numbers with 0's in them can have \fIz\fR's
substituted for the 0's.
This usually doesn't help much anyway, and it's up to you to remember that
@.I z
== 0, but there it is.
By default
@.I z
is not mapped.
@.TP
@.B -d \fIdictionary path\fP
This option allows alternate dictionaries to be used.
For example,
@.in +0.5i
@.B -d /users/fred/dict/star_trek_words
@.in -0.5i
will use (only) Fred's geek-speak dictionary.
Default is \fI/usr/dict/words\fR (or whatever it is on your system),
which is not used if any dictionary path is specified.
Multiple dictionaries can be used by specifying multiple paths. For example,
to use the geek speak dictionary along with the regular system dictionary, do:
@.in +0.5i
@.B -d /users/fred/dict/star_trek_words -d /usr/dict/words
@.in -0.5i
A path of "." means use the default dictionary, so quicker yet is:
@.in +0.5i
@.B -d . -d /users/fred/dict/star_trek_words
@.in -0.5i
In this way additional
dictionaries can either replace or be added to the default.
Note that
@.B phonewrd
understands the "affix" format in english.aff used for the
dictionaries in version 3.0 of GNU's ispell and expands words accordingly,
so these can be used to add more words to the search.
@.TP
@.B -l \fIword length\fP
This option allows a minimum word length to be set.
For example,
@.B -l 3
means no words shorter than 3 letters are used for building phrases.
User defined single letter words (see \fB-s\fR) are not affected by this
option.
Single letter words from the dictionary are ignored no matter
what the setting (since most dictionaries include exciting words like "h",
"w" and so on).
Default is 1.
@.TP
@.B -m \fInumeral map\fP
For those of you from a different planet, this will remap the letters to
different numerals.
For example,
@.in +0.5i
@.B -m 2223334445556667.77888999.
@.in -0.5i
is the default setting, a normal telephone.
The "\fB.\fR" (or any other non-numeric value) means don't map the letter to
any key.
You get a banana for using \fB-v\fR with this command.
@.TP
@.B -v
Verbose option: words fitting into the various number slots are output
and other warnings and whatnot are all output to stderr.
This can help you "roll your own" if the program does not find anything to
your liking.
@.TP
@.B -r
This option is for those without a dictionary.
It simply outputs the letters
possible for each digit in a column so that you can search for combinations
more easily.
No dictionary search is done, so none is needed.
@.TP
@.B -c
This option is also for those without a dictionary.
It generates all
permutations of letters and numerals valid for the input phone number and
outputs these one per line.
If you do:
phonewrd -c 234-5678 > junk1
@.br
spell junk1 > junk2
@.br
diff junk1 junk2 | grep "<"
you'll get any 7 letter words formed which pass the spell checker.
It's a long shot, but you never know...
@.TP
@.B -C
This option is also for those without a dictionary and too much disk space and
CPU time.
It generates all
permutations of letters and numerals valid for the input phone number and
outputs these one per line, plus it makes all permutations of spacing for
each of these permutations.
3^7 * 2^6 = 139968 phrases for a phone number without 0's and 1's.
Then send each one through your spell checker and if any errors are found,
discard it and go to the next.
It will take awhile, but this is the price you pay for not having any
dictionary available.
@.SH EXAMPLES
@.ne 4
@.B phonewrd 542-5968
gives the words:
@.br
kick you
@.br
lick you
@.ne 7
@.B phonewrd 542-5968 -n 1
@.br
allows more slack, letting one character be a numeral:
@.br
kick you
@.br
lick you
@.br
5 gal you
@.br
5 Hal you
@.br
which gives a little wider range of possibilities.
@.ne 5
@.B phonewrd 5683968 -l 3
@.br
gives words 3 characters or longer:
@.br
Jove you
@.br
loud you
@.br
love you
@.B phonewrd 486-9364 -s aio248
@.br
gives many combinations, but the
@.B -s aio248
allows the extra combination
@.br
I 8 my dog
@.br
@.B phonewrd 787-3648*
@.br
allows the extra combination
@.br
strength
@.br
as one \fI*\fR at the end means up to 1 additional character can be output
at the end of the phrase.
@.B phonewrd 861-2076
@.br
doesn't yield much of anything, so setting \fI0\fR to \fIo\fR and
\fI1\fR to \fIi\fR:
@.br
@.B phonewrd 86i-2o76
@.br
we get
@.br
unicorn
@.br
so \fIun1c0rn\fR fits the original phone number.
Putting a letter in a phone number
forces the use of that letter in that position.
@.B phonewrd -r 266-7883
@.br
yields
@.ne 3
@.br
a m m p t t d
@.br
b n n r u u e
@.br
c o o s v v f
@.br
The letters for each numeral are output in columns and so can be more easily
searched by hand for interesting phrases.
Yes, I know you found \fIbon stud\fR
in there, but what seven letter word can be found?
If you find it, pat
yourself on the cranium for having a brain and being able to quickly cull
through the 2187 possibilities.
@.B phonewrd -c 2667883
@.br
will list all the possible combinations, e.g.
@.br
ammpttd
@.br
ammptte
@.br
ammpttf
@.br
ammptud
@.br
ammptue
@.br
...
@.br
which can then be run through a spell checker and so searched for seven
letter words (see the \fB-c\fR option for how to do this).
@.B phonewrd 234-5678 -v
@.br
will output all words which fit into the various places in the phone number.
For example, one output entry is:
@.ne 2
@.br
Digit 5, length 3:
@.br
opt
@.br
which means that for the fifth digit of the number, all words of length three
which fit (i.e. translate into "678" in this case) are displayed.
@.SH AUTHOR
Eric Haines, erich@eye.com
@EOF
chmod 644 phonewrd.1
echo x - phonewrd.c
cat >phonewrd.c <<'@EOF'
/*
Phonewrd - given a phone number, find all words or phrases in a dictionary
which fit it.
version 1.5 - 4/21/93
(c) copyright 1993, Eric Haines, all rights reserved (erich@eye.com)
See the man page for details.
History:
1.5 changes: added the ability to recognize and expand GNU ispell
dictionary words. Multiple dictionaries can also be input.
1.4 changes: another change in search_for_match to avoid out of bounds
condition for NumeralMapped, added more error flagging for options.
1.3 changes: change in search_for_match to avoid dereferencing NULL
pointer, bug found by Nathan Loofbourrow.
1.2 changes: changed strdup() [not available on all machines] to
str_duplicate(). Fixed ProgName assignment to argv[0]. String
constants changed to allow compiling with K&R compiler. Many
thanks to Pat Myrto for these last two fixes.
1.1 changes: fixed bug in which phone numbers with 0 or 1 would not
properly output word matches.
*/
#include <stdlib.h> /* if you don't have stdlib, use malloc.h instead */
#include <stdio.h>
#include <string.h>
/*============= default related =========================================== */
/* path to dictionary */
#define DICT_PATH "/usr/dict/words"
/* number of digits in phone number */
#define NUM_DIGITS 7
/* how many numerals are allowed in our phrase? */
#define NUMERALS_ALLOWED 0
/* minimum length of words: note that 1 always gets bumped to 2, because of
* OneLetter below.
*/
#define MIN_LENGTH 1
/* one letter words that are acceptable */
#define ONE_LETTER "aio"
/* If you like things like "CDB" (see the bee) or "IM4U, use or modify the
* array below. Yes, "j" and "k" are potential names, "m" is only in "I am",
* "q" is queue, etc - you decide... This option tends to generate lots of
* useless goop, but it's good if you're desperate.
*/
/* #define ONE_LETTER "abcdgimoptuxy248" */
#define NO_NUMBER -2
/* to make Q and Z not be anything, set them to NO_NUMBER, else set them
* to the digit you want (e.g. 0 or 1)
*/
#define Q NO_NUMBER
#define Z NO_NUMBER
/* translation table for letters to numbers */
int Letter2Numeral[] =
/* a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z */
{ 2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,Q,7,7,8,8,8,9,9,9,Z } ;
/* true if a character is a vowel */
#define Vowel(c) strchr( "aeiou", (c) )
/*============= storage space related ===================================== */
#define MAX_DIGITS 14
#define MAX_INDICES (((MAX_DIGITS+1)*MAX_DIGITS)/2)
/* increment for word list memory space */
#define WORD_LIST_SIZE 50
/*============= internal use constants ==================================== */
#define FIXED_LETTER -1
#define BUFSIZE 256
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
/*============= structures ================================================ */
/* array of words, indexed by digit location and length of word. This list is
* built up in the first part of the program, as each dictionary word is
* categorized and put in its list. Then this structure is traversed to make
* up the combinations.
*/
typedef struct {
char **p_word ; /* list of pointers to words */
int count ; /* current count */
int size ; /* allocated size */
} wordlist, *p_wordlist ;
/*============= data and macros =========================================== */
#define IndexWL( digit_loc, length ) ( WLoffset[digit_loc] + length - 1 )
wordlist WL[MAX_INDICES] ;
int WLoffset[MAX_DIGITS] ;
int PhoneNum[MAX_DIGITS+1] ; /* phone number translation */
char PhoneStr[MAX_DIGITS+1] ; /* phone number letter, if specified */
int NumeralMapped[10] ; /* if TRUE, then index # is mapped */
char OneLetter[BUFSIZE] ;
char *DictPath[100] ;
int DictTot ;
char *ProgName ;
int NumDigits ;
int NumIndices ;
int NumNumerals ;
int MinLength ;
int RollOwn ;
int Concat ;
int Verbose ;
int MatchTot ;
int Wildcard ;
int TotBrk ;
int HoldSize ;
int HoldCount ;
char **HoldWord ;
char OutputGrid[MAX_DIGITS][27] ;
#define USAGE fprintf(stderr, "usage: %s [options] phone#[*...]\n", ProgName); \
fprintf(stderr, " [*...] - extra *'s at the end mean optional wildcard letters\n"); \
fprintf(stderr, " -l # - minimum length of words (cur. == %d)\n", MinLength); \
fprintf(stderr, " -n # - number of numerals allowed in phrase (cur. == %d)\n", NumNumerals); \
fprintf(stderr, " -q # - mapping of q (cur. == %d)\n", Q); \
fprintf(stderr, " -z # - mapping of z (cur. == %d)\n", Z); \
fprintf(stderr, " -d string - dictionary path (cur. == %s)\n", *DictPath); \
fprintf(stderr, " -s string - allowed single letter words (cur. == \"%s\")\n", OneLetter); \
fprintf(stderr, " -m char[26] - mapping of entire alphabet\n"); \
fprintf(stderr, " -r - output the corresponding letters in an array (no dictionary)\n"); \
fprintf(stderr, " -c - output all combinations (no dictionary)\n"); \
fprintf(stderr, " -C - output all combinations and spacings (no dictionary)\n"); \
fprintf(stderr, " -v - verbose output (show words that do fit)\n");
/*============= procedure declarations ==================================== */
int phone_check() ;
void roll_own() ;
void concat_it() ;
void concat_letter_out() ;
void concat_letter_breaks_out() ;
void init_wl() ;
int fit_word() ;
int permute_word() ;
void search_for_match() ;
void hold_word() ;
int store_word() ;
void free_wl() ;
int scan_options() ;
char *str_duplicate() ;
/*============= procedures ================================================ */
main(argc,argv)
int argc; char *argv[];
{
int nargc ;
char *nargv[BUFSIZE], *targv ;
int i, hdr_out ;
ProgName = argv[0] ;
HoldSize = HoldCount = 0 ;
NumNumerals = NUMERALS_ALLOWED ;
MinLength = MIN_LENGTH ;
RollOwn = FALSE ;
Concat = 0 ;
Verbose = FALSE ;
strcpy( OneLetter, ONE_LETTER ) ;
*DictPath = str_duplicate( DICT_PATH ) ;
if ( !(*DictPath) ) {
fprintf( stderr, "Ugh, we're out of memory!\n" ) ;
exit(1) ;
}
DictTot = 1 ;
/* translate phone number */
if ( argc < 2 ) {
fprintf( stderr, "Not enough arguments.\n" ) ;
USAGE ;
return( 1 ) ;
}
if ( !scan_options( argc, argv, &nargc, nargv ) ) {
return( 1 ) ;
}
if ( nargc < 1 ) {
fprintf( stderr, "No phone number found.\n" ) ;
USAGE ;
return( 1 ) ;
}
/* loop through phone number(s), output headers if more than one */
hdr_out = ( nargc > 1 ) ;
for ( i = 0 ; i < nargc ; i++ ) {
if ( i ) {
/* output carriage returns before 2nd, 3rd, etc */
fprintf( stdout, "\n" ) ;
}
targv = nargv[i] ;
if ( hdr_out ) {
fprintf( stdout, "# %s\n", targv ) ;
}
if ( phone_check( targv ) ) {
/* something very bad happened, so quit */
return( 1 ) ;
}
}
return( 0 ) ;
}
int
phone_check( numeral_string )
char *numeral_string ;
{
int i, tot, word_count, length, min_length, found_digit, val ;
char tchr, *tstr, **dp ;
char dict_word[BUFSIZE] ;
char out_string[BUFSIZE] ;
p_wordlist p_wl ;
FILE *infile ;
NumDigits = 0 ;
TotBrk = -1 ;
tstr = numeral_string ;
tchr = *tstr++ ;
found_digit = FALSE ;
while ( tchr != '\0' && tchr != '*' && (NumDigits <= MAX_DIGITS ) ) {
if ( ( tchr >= '0' ) && ( tchr <= '9' ) ) {
/* convert to digit */
PhoneNum[NumDigits] = (int)(tchr - '0') ;
PhoneStr[NumDigits++] = tchr ;
found_digit = TRUE ;
} else if ( ( (tchr >= 'A') && (tchr <= 'Z') ) ||
( (tchr >= 'a') && (tchr <= 'z') ) ) {
PhoneNum[NumDigits] = FIXED_LETTER ;
PhoneStr[NumDigits++] = tolower( tchr ) ;
}
tchr = *tstr++ ;
}
PhoneStr[NumDigits]='\0' ;
if ( NumDigits <= 0 ) {
fprintf( stderr, "Sorry, no digits input in `%s'\n", numeral_string ) ;
fprintf( stderr, "Recompile with a higher MAX_DIGITS setting.\n" ) ;
USAGE ;
return(0) ;
}
/* check if we're in roll own mode */
if ( RollOwn ) {
roll_own() ;
return(0) ;
}
/* check if we're in concat output mode */
if ( Concat ) {
concat_it() ;
return(0) ;
}
/* check if any numbers were input */
if ( !found_digit ) {
/* entirely alphabetic input, so translate to number */
for ( i = 0 ; i < NumDigits ; i++ ) {
val = Letter2Numeral[PhoneStr[i]-'a'] ;
if ( val != NO_NUMBER ) {
fprintf( stdout, "%d", val ) ;
} else {
fprintf( stdout, "*" ) ;
}
}
fprintf( stdout, "\n" ) ;
return(0) ;
}
if ( tchr == '*' ) {
/* the phone number ends in a wild card - phrases can be longer */
Wildcard = 1 ;
while ( *tstr++ == '*' ) {
Wildcard++ ;
}
} else {
Wildcard = 0 ;
}
if ( NumDigits > MAX_DIGITS ) {
fprintf(stderr, "Sorry, too many digits input in `%s'; ", numeral_string);
fprintf(stderr, "only %d allowed.\n", NumDigits);
USAGE ;
return(0) ;
}
/* set up offset array for indexing WL */
tot = 0 ;
for ( i = 0 ; i < NumDigits ; i++ ) {
WLoffset[i] = tot ;
tot += (NumDigits-i) ;
}
NumIndices = ((NumDigits+1)*NumDigits)/2 ;
/* build WL */
word_count = 0 ;
init_wl() ;
dp = DictPath ;
while ( DictTot-- ) {
infile = fopen( *dp, "r") ;
min_length = MinLength > 1 ? MinLength : 2 ;
if ( infile != NULL ) {
while ( fgets( dict_word, BUFSIZE, infile ) ) {
word_count += fit_word( dict_word, min_length ) ;
}
} else {
fprintf( stderr, "Sorry, couldn't find dictionary at `%s'.\n",
*dp ) ;
return(1) ;
}
fclose( infile ) ;
dp++ ;
}
if ( Verbose ) {
for ( i = 0 ; i < NumDigits ; i++ ) {
for ( length = 1 ; length <= NumDigits-i ; length++ ) {
p_wl = &WL[IndexWL( i, length )] ;
if ( p_wl->count ) {
fprintf( stdout, "\nDigit %d, length %d:\n", i+1, length ) ;
for ( tot = 0 ; tot < p_wl->count ; tot++ ) {
fprintf( stdout, " %s\n", p_wl->p_word[tot] ) ;
}
}
}
}
}
MatchTot = 0 ; /* number of words matched */
/* search through WL for paths */
if ( word_count ) {
/* good, there's something to work with: search away! */
*out_string = '\0' ;
search_for_match( 0, out_string, out_string, 0 ) ;
if ( !MatchTot ) {
fprintf( stderr,
"Bad luck: dictionary words fit, but there's too much numeral goop.\n");
fprintf( stderr,
"I'd try again with the option `-n %d' or so.\n",
NumNumerals+1 ) ;
}
} else {
fprintf( stderr,
"Worst luck: no dictionary words fit anywhere in %s.\n",
PhoneStr ) ;
fprintf( stderr,
"Maybe try again with the option `-s abcdgimoptuxy248'.\n" ) ;
}
free_wl() ;
return(0) ;
}
void
roll_own()
{
int digit_letter[MAX_DIGITS], found_one, search, i, j, k ;
for ( i = 0 ; i < NumDigits ; i++ ) {
if ( PhoneNum[i] == FIXED_LETTER ) {
digit_letter[i] = -2 ;
} else {
digit_letter[i] = -1 ;
}
}
found_one = TRUE ;
for ( i = 0 ; i < 26 && found_one ; i++ ) {
found_one = FALSE ;
for ( j = 0 ; j < NumDigits ; j++ ) {
if ( digit_letter[j] >= 26 ) {
/* done with this one */
fprintf( stdout, " " ) ;
} else {
if ( digit_letter[j] == -2 ) {
found_one = TRUE ;
digit_letter[j] = 26 ;
fprintf( stdout, " %c", PhoneStr[j] ) ;
} else {
for ( k = digit_letter[j] + 1, search = TRUE
; k < 26 && search
; k++ ) {
if ( Letter2Numeral[k] == PhoneNum[j] ) {
search = FALSE ;
found_one = TRUE ;
fprintf( stdout, " %c", (char)(k+'a') ) ;
digit_letter[j] = k ;
}
}
if ( search ) {
/* no further match found */
if ( digit_letter[j] < 0 ) {
/* numeral is not mapped, so output it directly */
fprintf( stdout, " %c", PhoneStr[j] ) ;
}
digit_letter[j] = 26 ;
}
}
}
}
fprintf( stdout, "\n" ) ;
}
}
void
concat_it()
{
int i, j, tot ;
char full_string[MAX_DIGITS+1] ;
for ( i = 0 ; i < NumDigits ; i++ ) {
if ( PhoneNum[i] == FIXED_LETTER ) {
OutputGrid[i][0] = PhoneStr[i] ;
OutputGrid[i][1] = '\0' ;
} else {
tot = 0 ;
for ( j = 0 ; j < 26 ; j++ ) {
if ( Letter2Numeral[j] == PhoneNum[i] ) {
OutputGrid[i][tot++] = (char)(j+'a') ;
}
}
if ( !tot ) {
/* no match found */
OutputGrid[i][tot++] = PhoneStr[i] ;
}
OutputGrid[i][tot] = '\0' ;
}
}
if ( Concat == 1 ) {
concat_letter_out( 0, full_string ) ;
} else {
concat_letter_breaks_out( 0, full_string ) ;
}
}
void
concat_letter_out( digit, full_string )
int digit ;
char *full_string ;
{
int i, length ;
char *cstr ;
if ( digit >= NumDigits ) {
full_string[digit] = '\0' ;
fprintf( stdout, "%s\n", full_string ) ;
} else {
length = strlen( cstr = OutputGrid[digit] ) ;
for ( i = 0 ; i < length ; i++ ) {
full_string[digit] = *cstr++ ;
concat_letter_out( digit+1, full_string ) ;
}
}
}
void
concat_letter_breaks_out( digit, full_string )
int digit ;
char *full_string ;
{
char brk_string[MAX_DIGITS*2] ;
int i, j, bny, index, length ;
char *cstr ;
if ( digit >= NumDigits ) {
if ( TotBrk == -1 ) {
TotBrk = 1 ;
for ( i = 1 ; i < NumDigits ; i++ ) {
TotBrk *= 2 ;
}
}
for ( i = 0 ; i < TotBrk ; i++ ) {
bny = i ;
index = 0 ;
for ( j = 0 ; j < NumDigits ; j++ ) {
brk_string[index++] = full_string[j] ;
if ( bny & 0x1 ) {
brk_string[index++] = ' ' ;
}
bny = bny >> 1 ;
}
brk_string[index] = '\0' ;
fprintf( stdout, "%s\n", brk_string ) ;
}
} else {
length = strlen( cstr = OutputGrid[digit] ) ;
for ( i = 0 ; i < length ; i++ ) {
full_string[digit] = *cstr++ ;
concat_letter_breaks_out( digit+1, full_string ) ;
}
}
}
/* create structures needed for the word list, etc */
void
init_wl()
{
p_wordlist p_wl ;
int i, j, length, search ;
char tstr[2] ;
for ( i = 0, p_wl = WL ; i < NumIndices ; i++, p_wl++ ) {
p_wl->p_word = NULL ;
p_wl->count = 0 ;
p_wl->size = 0 ;
}
/* figure out which numerals don't have any letter translations */
for ( i = 0 ; i < 10 ; i++ ) {
for ( j = 0, search = TRUE ; j < 26 && search ; j++ ) {
if ( i == Letter2Numeral[j] ) {
search = FALSE ;
}
}
/* set to TRUE if numeral is mapped by something */
NumeralMapped[i] = !search ;
}
tstr[1] = '\0' ;
/* add one number values as possible */
/* we rely on the fact that the first word in the single letter word
* lists is actually a numeral, so change the following at your own
* peril.
*/
for ( i = 0 ; i < 10 ; i++ ) {
tstr[0] = (char)i + '0' ;
(void)fit_word( tstr, 1 ) ;
}
/* add one letter words as possible */
length = strlen( OneLetter ) ;
for ( i = 0 ; i < length ; i++ ) {
tstr[0] = OneLetter[i] ;
(void)fit_word( tstr, 1 ) ;
}
}
/* see if the word fits in the database anywhere */
int
fit_word( dict_word, min_length )
char *dict_word ;
int min_length ;
{
int length, compare_length, true_length, index_length, nl ;
int i, j, num_match ;
int word_val[MAX_DIGITS], hit[MAX_DIGITS], *wv, check_length, match, tot ;
char lc_dict_word[MAX_DIGITS], *wc, *lc, tchr, *cc ;
char clean_dict_word[BUFSIZE], new_word[BUFSIZE] ;
/* set new_word to empty string to initialize permute_word */
tot = 0 ;
*new_word = '\0' ;
while( permute_word( dict_word, new_word ) ) {
/* convert word to numbers */
length = strlen( new_word ) ;
compare_length = true_length = 0 ;
for ( i = 0, wv = word_val, wc = new_word, lc = lc_dict_word,
cc = clean_dict_word
; ( i < length ) && ( compare_length < NumDigits )
; i++, wc++ ) {
/* remove apostrophes, hyphens, etc for matching */
tchr = tolower(*wc) ;
if ( ( tchr >= 'a' ) && ( tchr <= 'z' ) ) {
*wv++ = Letter2Numeral[(*lc++ = tchr) -'a'] ;
compare_length++ ;
} else if ( ( tchr >= '0' ) && ( tchr <= '9' ) ) {
*wv++ = (*lc++ = tchr) -'0' ;
compare_length++ ;
}
*cc++ = *wc ;
}
true_length = compare_length ;
while ( *wc ) {
tchr = tolower( *wc++ ) ;
/* get true length of word in valid characters */
if ( ( tchr >= 'a' ) && ( tchr <= 'z' ) ) {
true_length++ ;
} else if ( ( tchr >= '0' ) && ( tchr <= '9' ) ) {
true_length++ ;
}
/* copy the rest of the word */
*cc++ = tchr ;
}
/* end the cleaned word */
*cc = '\0' ;
/* is the word too long? */
if ( true_length > NumDigits + Wildcard ) {
/* the word was too long: for ispell words we know that the
* first word is going to be as short as it gets, so we bail
* out of successive word generation here now.
*/
goto LastWord ;
}
/* is the word too short? */
if ( true_length < min_length ) {
/* the word was too short */
goto NextWord ;
}
/* now look for matches */
if ( Wildcard ) {
check_length = NumDigits - true_length + Wildcard ;
if ( check_length >= NumDigits ) {
/* cannot index into array at higher than NumDigits-1,
* so reduce length.
*/
check_length = NumDigits - 1 ;
}
} else {
check_length = NumDigits - true_length ;
}
for ( i = 0, num_match = 0 ; i <= check_length ; i++ ) {
index_length = compare_length+i ;
if ( Wildcard ) {
if ( index_length > NumDigits ) {
/* cut comparisons down to numerals available */
index_length = NumDigits ;
}
}
for ( j = i, wv = word_val, match = TRUE
; match && (j < index_length)
; j++, wv++ ) {
/* numerical match? */
if ( PhoneNum[j] != *wv ) {
/* no; exact letter match? */
if ( ( PhoneNum[j] != FIXED_LETTER ) ||
( PhoneStr[j] != lc_dict_word[j-i] ) ) {
/* no match, stop testing */
match = FALSE ;
}
}
}
if ( match ) {
/* word fits, store index */
hit[num_match++] = i ;
}
}
/* were there any matches? */
if ( num_match ) {
/* make one copy of the word */
wc = str_duplicate( clean_dict_word ) ;
if ( !wc ) {
fprintf( stderr, "Ugh, we're out of memory!\n" ) ;
exit(1) ;
}
hold_word( wc ) ;
for ( i = 0 ; i < num_match ; i++ ) {
if ( Wildcard ) {
if ( hit[i] + true_length <= NumDigits ) {
nl = true_length ;
} else {
nl = NumDigits - hit[i] ;
}
if ( !store_word( wc, hit[i], nl ) ) {
/* duplicate word, so free it and go to next word */
free( wc ) ;
goto NextWord ;
}
} else {
if ( !store_word( wc, hit[i], true_length ) ) {
/* duplicate word, so free it and go to next word */
free( wc ) ;
goto NextWord ;
}
}
}
/* got here, so the word must have been stored */
tot++ ;
}
NextWord: ;
}
LastWord: ;
return( tot ) ;
}
/* take permutations of word if "/" GNU ispell format detected, else just
* strip out invalid characters and return new word
*/
int
permute_word( dict_word, new_word )
char *dict_word ;
char *new_word ;
{
int search_word ;
char *ppc, *psc, *dc, *wc, tchr, ttchr ;
static char perm_word[BUFSIZE], perm_pre_word[BUFSIZE] ;
static char perm_pre_cmd[BUFSIZE], perm_suf_cmd[BUFSIZE] ;
static int perm_pre_count, perm_suf_count ;
static int perm_cur_pre_count, perm_cur_suf_count, pre_length ;
if ( *new_word ) {
/* on successive call of this routine by calling procedure, so get
* a permutation (if available) and return it.
*/
/* subtract previous output permutation from count and see if done */
search_word = 0 ;
do {
if ( perm_cur_suf_count <= 0 ) {
if ( perm_cur_pre_count <= 0 ) {
/* no more permutations */
return( 0 ) ;
}
perm_cur_suf_count = perm_suf_count ;
switch( perm_pre_cmd[--perm_cur_pre_count] ) {
case 'A': /* enter -> reenter */
strcpy( perm_pre_word, "re" ) ;
strcat( perm_pre_word, perm_word ) ;
break ;
case 'I': /* disposed -> indisposed */
strcpy( perm_pre_word, "re" ) ;
strcat( perm_pre_word, perm_word ) ;
break ;
case 'U': /* natural -> unnatural */
strcpy( perm_pre_word, "un" ) ;
strcat( perm_pre_word, perm_word ) ;
break ;
default:
fprintf( stderr,
"warning: unrecognized word flag `%c' for word `%s'\n",
tchr, perm_word ) ;
return( 0 ) ;
}
pre_length = strlen( perm_pre_word ) ;
/* for the first prefix addition just return rest of word
* without any suffix
*/
strcpy( new_word, perm_pre_word ) ;
} else {
strcpy( new_word, perm_pre_word ) ;
switch( perm_suf_cmd[--perm_cur_suf_count] ) {
case 'V': /* create -> creative */
/* use only when there is no prefix */
if ( perm_cur_pre_count == perm_pre_count ) {
tchr = tolower(new_word[pre_length-1]) ;
if ( tchr == 'e' ) {
new_word[pre_length-1] = '\0' ;
}
strcat( new_word, "ive" ) ;
} else {
/* invalid combination, so continue */
search_word = 1 ;
}
break ;
case 'N': /* create -> creation */
tchr = tolower(new_word[pre_length-1]) ;
if ( tchr == 'e' ) {
new_word[pre_length-1] = '\0' ;
strcat( new_word, "ion" ) ;
} else if ( tchr == 'y' ) {
new_word[pre_length-1] = '\0' ;
strcat( new_word, "ication" ) ;
} else {
strcat( new_word, "en" ) ;
}
break ;
case 'X': /* create -> creations */
tchr = tolower(new_word[pre_length-1]) ;
if ( tchr == 'e' ) {
new_word[pre_length-1] = '\0' ;
strcat( new_word, "ions" ) ;
} else if ( tchr == 'y' ) {
new_word[pre_length-1] = '\0' ;
strcat( new_word, "ications" ) ;
} else {
strcat( new_word, "ens" ) ;
}
break ;
case 'H': /* twenty -> twentieth */
/* use only when there is no prefix */
if ( perm_cur_pre_count == perm_pre_count ) {
tchr = tolower(new_word[pre_length-1]) ;
if ( tchr == 'y' ) {
new_word[pre_length-1] = '\0' ;
strcat( new_word, "ieth" ) ;
} else {
strcat( new_word, "th" ) ;
}
} else {
/* invalid combination, so continue */
search_word = 1 ;
}
break ;
case 'Y': /* quick -> quickly */
strcat( new_word, "ly" ) ;
break ;
case 'G': /* file -> filing */
tchr = tolower(new_word[pre_length-1]) ;
if ( tchr == 'e' ) {
new_word[pre_length-1] = '\0' ;
}
strcat( new_word, "ing" ) ;
break ;
case 'J': /* file -> filings */
tchr = tolower(new_word[pre_length-1]) ;
if ( tchr == 'e' ) {
new_word[pre_length-1] = '\0' ;
}
strcat( new_word, "ings" ) ;
break ;
case 'D': /* create -> created */
tchr = tolower(new_word[pre_length-1]) ;
if ( tchr == 'e' ) {
strcat( new_word, "d" ) ;
} else if ( tchr == 'y' ) {
ttchr = tolower(new_word[pre_length-2]) ;
if ( Vowel(ttchr) ) {
strcat( new_word, "ed" ) ;
} else {
new_word[pre_length-1] = '\0' ;
strcat( new_word, "ied" ) ;
}
} else {
strcat( new_word, "ed" ) ;
}
break ;
case 'T': /* late -> latest */
/* use only when there is no prefix */
if ( perm_cur_pre_count == perm_pre_count ) {
tchr = tolower(new_word[pre_length-1]) ;
if ( tchr == 'e' ) {
strcat( new_word, "st" ) ;
} else if ( tchr == 'y' ) {
ttchr = tolower(new_word[pre_length-2]) ;
if ( Vowel(ttchr) ) {
strcat( new_word, "est" ) ;
} else {
new_word[pre_length-1] = '\0' ;
strcat( new_word, "iest" ) ;
}
} else {
strcat( new_word, "est" ) ;
}
} else {
/* invalid combination, so continue */
search_word = 1 ;
}
break ;
case 'R': /* late -> later */
tchr = tolower(new_word[pre_length-1]) ;
if ( tchr == 'e' ) {
strcat( new_word, "r" ) ;
} else if ( tchr == 'y' ) {
ttchr = tolower(new_word[pre_length-2]) ;
if ( Vowel(ttchr) ) {
strcat( new_word, "er" ) ;
} else {
new_word[pre_length-1] = '\0' ;
strcat( new_word, "ier" ) ;
}
} else {
strcat( new_word, "er" ) ;
}
break ;
case 'Z': /* skate ->skaters */
tchr = tolower(new_word[pre_length-1]) ;
if ( tchr == 'e' ) {
strcat( new_word, "rs" ) ;
} else if ( tchr == 'y' ) {
ttchr = tolower(new_word[pre_length-2]) ;
if ( Vowel(ttchr) ) {
strcat( new_word, "ers" ) ;
} else {
new_word[pre_length-1] = '\0' ;
strcat( new_word, "iers" ) ;
}
} else {
strcat( new_word, "ers" ) ;
}
break ;
case 'S': /* imply -> implies */
tchr = tolower(new_word[pre_length-1]) ;
if ( tchr == 'y' ) {
ttchr = tolower(new_word[pre_length-2]) ;
if ( Vowel(ttchr) ) {
strcat( new_word, "s" ) ;
} else {
new_word[pre_length-1] = '\0' ;
strcat( new_word, "ies" ) ;
}
} else {
if ( strchr( "sxzh", tchr ) ) {
strcat( new_word, "es" ) ;
} else {
strcat( new_word, "s" ) ;
}
}
break ;
case 'P': /* cloudy -> cloudiness */
tchr = tolower(new_word[pre_length-1]) ;
if ( tchr == 'y' ) {
ttchr = tolower(new_word[pre_length-2]) ;
if ( Vowel(ttchr) ) {
strcat( new_word, "ness" ) ;
} else {
new_word[pre_length-1] = '\0' ;
strcat( new_word, "iness" ) ;
}
} else {
strcat( new_word, "ness" ) ;
}
break ;
case 'M': /* dog -> dog's */
strcat( new_word, "'s" ) ;
break ;
default:
fprintf( stderr,
"warning: unrecognized word flag `%c' for word `%s'\n",
tchr, perm_word ) ;
return( 0 ) ;
}
}
} while ( search_word ) ;
} else {
/* first call, so check if we need to permute */
if ( wc = strchr( dict_word, '/' ) ) {
/* GNU ispell format detected, so save word and permutations */
strncpy( perm_word, dict_word, wc-dict_word ) ;
perm_word[wc-dict_word] = '\0' ;
wc++ ;
ppc = perm_pre_cmd ;
psc = perm_suf_cmd ;
perm_pre_count = 0 ;
perm_suf_count = 0 ;
while ( tchr = toupper( *wc++ ) ) {
/* save only permutation characters */
if ( ( tchr >= 'A' ) && ( tchr <= 'Z' ) ) {
if ( (tchr == 'A') || (tchr == 'I') || (tchr == 'U') ) {
*ppc++ = tchr ;
perm_pre_count++ ;
} else {
*psc++ = tchr ;
perm_suf_count++ ;
}
}
}
*ppc = '\0' ;
*psc = '\0' ;
perm_cur_pre_count = perm_pre_count ;
perm_cur_suf_count = perm_suf_count ;
strcpy( perm_pre_word, perm_word ) ;
pre_length = strlen( perm_pre_word ) ;
/* and finally, copy the basic word for use */
strcpy( new_word, perm_word ) ;
} else {
/* no permutation, so set permutation list to empty */
perm_cur_pre_count = 0 ;
perm_cur_suf_count = 0 ;
/* cull out line feeds, etc */
wc = dict_word ;
dc = new_word ;
while ( tchr = *wc++ ) {
if ( tchr > 13 ) {
*dc++ = tchr ;
}
}
*dc = '\0' ;
}
}
return( 1 ) ;
}
/* yeah, I could combine this with store_word - call me lazy... */
void
hold_word( word )
char *word ;
{
if ( HoldSize <= HoldCount ) {
if ( HoldSize ) {
HoldSize += WORD_LIST_SIZE * NumDigits ;
HoldWord = (char **)realloc( (void *)HoldWord,
HoldSize * sizeof(char *)) ;
} else {
HoldSize = WORD_LIST_SIZE * NumDigits ;
HoldWord =
(char **)malloc( HoldSize * sizeof(char *)) ;
}
if ( HoldWord == NULL ) {
fprintf( stderr, "Ugh, we're out of memory!\n" ) ;
exit(1) ;
}
}
HoldWord[HoldCount++] = word ;
}
/* store word in the given location, return 1 if word not a duplicate */
int
store_word( word, digit, length )
char *word ;
int digit ;
int length ;
{
p_wordlist p_wl ;
int i ;
p_wl = &WL[IndexWL( digit, length )] ;
/* check if word is already on list */
for ( i = 0 ; i < p_wl->count ; i++ ) {
if ( !strcmp( word, p_wl->p_word[i] ) ) {
/* duplicate word - don't store it */
return( 0 ) ;
}
}
/* check storage space */
if ( p_wl->size <= p_wl->count ) {
if ( p_wl->size ) {
p_wl->size += WORD_LIST_SIZE ;
p_wl->p_word = (char **)realloc( (void *)p_wl->p_word,
p_wl->size * sizeof(char *)) ;
} else {
p_wl->size = WORD_LIST_SIZE ;
p_wl->p_word =
(char **)malloc( p_wl->size * sizeof(char *)) ;
}
if ( p_wl->p_word == NULL ) {
fprintf( stderr, "Ugh, we're out of memory!\n" ) ;
exit(1) ;
}
}
/* store word in structure */
p_wl->p_word[p_wl->count++] = word ;
return( 1 ) ;
}
/* search through the stored words for matches */
void
search_for_match( digit, full_string, suffix_loc, numeral_count )
int digit ;
char *full_string ;
char *suffix_loc ;
int numeral_count ;
{
int length, tot_len, tot_word, wn, add_num, val ;
p_wordlist p_wl ;
char **p_word ;
tot_len = NumDigits - digit ;
/* loop through all possible word lengths from this point */
/* count down so that the longer strings are output first */
for ( length = tot_len ; length > 0 ; length-- ) {
p_wl = &WL[IndexWL( digit, length )] ;
tot_word = p_wl->count ;
/* now go through all words on the list */
if ( ( length == 1 ) && tot_word ) {
val = **(p_wl->p_word) - '0' ;
/* is the first word a numeral, and is it mapped? */
if ( ( val >= 0 ) && ( val <= 9 ) && NumeralMapped[val] ) {
/* don't include first word (a mapped numeral) if we've used
* up our quota.
*/
wn = (numeral_count >= NumNumerals ) ;
add_num = 1 ;
} else {
/* an unmapped numeral, so definitely do it */
wn = 0 ;
add_num = 0 ;
}
} else {
/* not on the one letter word list, so do all words */
wn = 0 ;
add_num = 0 ;
}
for ( p_word = p_wl->p_word + wn
; wn < tot_word
; wn++, p_word++ ) {
strcpy( suffix_loc, *p_word ) ;
if ( length == tot_len ) {
/* finished - output it! */
fprintf( stdout, "%s\n", full_string ) ;
MatchTot++ ;
} else {
strcat( suffix_loc, " " ) ;
/* Add one to numeral_count only if numeral is used */
search_for_match( digit+length, full_string,
suffix_loc + strlen( suffix_loc ),
numeral_count + add_num ) ;
}
}
}
}
void
free_wl()
{
int i ;
p_wordlist p_wl ;
for ( i = 0, p_wl = WL ; i < NumIndices ; i++, p_wl++ ) {
if ( p_wl->size ) {
p_wl->size = 0 ;
p_wl->count = 0 ;
free( p_wl->p_word ) ;
}
}
/* the only function of HoldWord is to be able to free the word memory */
if ( HoldSize ) {
for ( i = 0 ; i < HoldCount ; i++ ) {
free( HoldWord[i] ) ;
}
free( HoldWord ) ;
}
HoldCount = HoldSize = 0 ;
}
/* strip out all valid "-" arguments and their values */
int
scan_options( argc, argv, nargc, nargv )
int argc ;
char *argv[] ;
int *nargc ;
char *nargv[] ;
{
int num_arg ;
int i, first_dict ;
char str[BUFSIZE] ;
*nargc = num_arg = 0 ;
first_dict = 1 ; /* haven't received a dictionary path yet */
while ( ++num_arg < argc ) {
if ( *argv[num_arg] == '-' ) {
switch( argv[num_arg][1] ) {
case 'l': /* minimum length of words */
if ( ++num_arg < argc ) {
sscanf( argv[num_arg], "%d", &i ) ;
if ( i < 1 ) {
fprintf( stderr,
"Minimum word length too low!\n" ) ;
USAGE ;
return( FALSE ) ;
}
MinLength = i ;
} else {
fprintf( stderr, "No minimum length given for -l.\n" ) ;
USAGE ;
return( FALSE ) ;
}
break ;
case 'n': /* number of numerals allowed */
if ( ++num_arg < argc ) {
sscanf( argv[num_arg], "%d", &i ) ;
if ( i < 0 ) {
fprintf( stderr, "Number of numerals too low!\n" ) ;
USAGE ;
return( FALSE ) ;
}
NumNumerals = i ;
} else {
fprintf( stderr,
"No number of numerals given for -n.\n" ) ;
USAGE ;
return( FALSE ) ;
}
break ;
case 'q': /* mapping of q */
if ( ++num_arg < argc ) {
sscanf( argv[num_arg], "%d", &i ) ;
if ( (i >= 0) && (i <= 9) ) {
Letter2Numeral['q'-'a'] = i ;
}
} else {
fprintf( stderr, "No mapped number given for -q.\n" ) ;
USAGE ;
return( FALSE ) ;
}
break ;
case 'z': /* mapping of z */
if ( ++num_arg < argc ) {
sscanf( argv[num_arg], "%d", &i ) ;
if ( (i >= 0) && (i <= 9) ) {
Letter2Numeral['z'-'a'] = i ;
}
} else {
fprintf( stderr, "No mapped number given for -z.\n" ) ;
USAGE ;
return( FALSE ) ;
}
break ;
case 'd': /* dictionary path */
if ( ++num_arg < argc ) {
if ( first_dict ) {
first_dict = 0 ;
/* erase first dictionary, since we're
* overriding by giving a path.
*/
DictTot = 0 ;
free( *DictPath ) ;
}
sscanf( argv[num_arg], "%s", str ) ;
if ( *str == '.' ) {
/* use the default dictionary */
strcpy( str, DICT_PATH ) ;
}
DictPath[DictTot] = str_duplicate( str ) ;
if ( !DictPath[DictTot++] ) {
fprintf( stderr, "Ugh, we're out of memory!\n" ) ;
exit(1) ;
}
} else {
fprintf( stderr,
"No dictionary path given for -d.\n" ) ;
USAGE ;
return( FALSE ) ;
}
break ;
case 's': /* allowed single letter words */
if ( ++num_arg < argc ) {
sscanf( argv[num_arg], "%s", OneLetter ) ;
} else {
fprintf( stderr,
"No single letter words given for -s.\n" ) ;
USAGE ;
return( FALSE ) ;
}
break ;
case 'm': /* mapping of entire alphabet */
if ( ++num_arg < argc ) {
sscanf( argv[num_arg], "%s", str ) ;
if ( strlen(str) != 26 ) {
fprintf( stderr, "Must input all 26 digits\n" ) ;
USAGE ;
return( FALSE ) ;
}
for ( i = 0 ; i < 26 ; i++ ) {
if ( (str[i] >= '0') && (str[i] <= '9') ) {
Letter2Numeral[i] = str[i] - '0' ;
} else {
Letter2Numeral[i] = NO_NUMBER ;
}
}
if ( Verbose ) {
fprintf( stderr, "here's your banana: )\n" ) ;
}
} else {
fprintf( stderr, "No digit map given for -m.\n" ) ;
USAGE ;
return( FALSE ) ;
}
break ;
case 'r': /* output concatenation */
RollOwn = TRUE ;
break ;
case 'c': /* output concatenation */
Concat = 1 ;
break ;
case 'C': /* output spacing & concatenation */
Concat = 2 ;
break ;
case 'v': /* verbose output */
Verbose = TRUE ;
break ;
default:
fprintf( stderr, "No such option `-%c'.\n",
argv[num_arg][1] ) ;
USAGE ;
return( FALSE ) ;
}
} else {
/* not an argument, so pass it on */
nargv[(*nargc)++] = argv[num_arg] ;
}
}
return( TRUE ) ;
}
/* strdup for the masses, since strdup is not standard */
char *str_duplicate( s )
char *s ;
{
char *ps ;
if ( ps = malloc( strlen( s ) + 1 ) ) {
strcpy( ps, s ) ;
}
return( ps ) ;
}
@EOF
chmod 644 phonewrd.c
exit 0
Technical Details
Message-ID:
<1993May27.161051.12563@eye.com>Path:
arc1-ca.pugleaf.net!wupost!cs.utexas.edu!utnut!torn!nott!bnrgate!bnr.co.uk!pipex!sunic!psinntp!psinntp!eye!erichShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!wupost!cs.utexas.edu!utnut!torn!nott!bnrgate!bnr.co.uk!pipex!sunic!psinntp!psinntp!eye!erich From: erich@eye.com (Eric Haines) Newsgroups: alt.dcom.telecom,alt.sources Subject: phonewrd - phone # to words and phrases, now using GNU dictionary Message-ID: <1993May27.161051.12563@eye.com> Date: Thu, 27 May 93 20:10:51 GMT Sender: erich@eye.com (Eric Haines) Organization: 3D/EYE, Inc. Ithaca, NY Lines: 1731