#ifdef	ournix
	/* printf("XX %d\n",__LINE__); */
#include "ournix.h"
#endif
	char sccsID[] =
 "@(#) phone.c V1.11 Copyright Julian H. Stacey, Munich, 1997 01 02 - 2009.\n";

/* FUNCTION : Filter phone book input to output for estic, isdnd,
		or gnokii phone table formats
		LATER allow multiple work phone numbers per person.
		LATER extend to sort phone book entries by criteria,
		such as alphabetic by first name.

  There's no call to free() 'cos I want to later add a sort command.
  JJLATER maybe allow for '*' '#' 'R' as dial keys.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>	/* for isalpha */

#define strequ(a,b)	(!strcmp(a,b))
#define strnequ(a,b,n)	(!strncmp(a,b,n))

typedef char	FLAG ;

char	**ARGV ;
FLAG	opt_isdn_and_estic =	(FLAG)0 ; /* produce lookup table for isdn & estic */
FLAG	opt_mobile =		(FLAG)0 ; /* produce lookup table for gnokii */
FLAG	opt_comma =		(FLAG)0 ; /* if set, & if opt_mobile also set,
					 convert comma in names to ampersand */
FLAG	opt_new_gnokii =
#if /*{*/ ( __FreeBSD__ == 4 )	/* { Assume FreeBSD-4.11 with Gnokii-6.4  */
				(FLAG)0 ;
#else				/* }{ Assume FreeBSD-6.2 with Gnokii-6.14 */
				(FLAG)1 ;
#endif				/*}*/
FLAG	opt_dflt_exclude =	(FLAG)0 ;
	/* if opt_dflt_exclude is set, exclude all entries lacking "ie:+" */
FLAG	opt_estic =		(FLAG)0 ;
FLAG	opt_sort =		(FLAG)0 ;
FLAG	opt_zap =		(FLAG)0 ;
FLAG	opt_capital =		(FLAG)0 ;
FILE	*fp_in ;
long	line_count ;
char	*file_name ;
char	seperator[] =	"][" ;
size_t	seperator_ln ;

	/* My full international number is (last bit faked) "+49.89.123456" */
#define MY_COUNTRY	"49"	/* Default international number */
#define MY_TOWN		"89"	/* Default Town */
#define PREFIX_INTERNATIONAL "00" /* Replace + with 00 for countries */
#define PREFIX_NATIONAL	"0"	/* Dial 0 to get out of town */
char my_country[20]		; /* typically 49 */
char my_town[20]		; /* typically 89 */
char prefix_international[20]	; /* typically 00 */
char prefix_national[20]	; /* typically 0  */

FLAG num_local = (FLAG)1 ;	/* output local within-same-town variant of
				   number, if within your town */
FLAG num_national = (FLAG)1 ;	/* output within-same-nation national variant
				   of number, if within your country */
FLAG num_international = (FLAG)1 ;	/* output full international number */
FLAG num_one = (FLAG)0 ;	/* just one number, the shortest */
FLAG field_printed ;

char int_prefix_country[20] ;	/* typically 0049 */
char nat_prefix_town[20] ;	/* typically 089  */
unsigned ln_nat_prefix_town,	ln_int_prefix_country ;
unsigned ln_prefix_national,	ln_prefix_international ;

#define SIM_MAX	100		/* Maximum number of names in a SIM card */
unsigned sim_max = SIM_MAX ;

/* Define Maximum names in phone internal memory. */
#if defined NOKIA_6110	/*{{*/
#define PHONE_MAX 50		/* Erik S.: GSM spec requires > 50.  */
#elif defined NOKIA_5110	/*}{*/
#define PHONE_MAX  0		/* xgnokii */
#elif defined NOKIA_6210	/*}{*/
#define PHONE_MAX  500		/* Pawel Kot <pkot@linuxnews._ERASE_.pl> */
#elif defined SONY_CMD_J70 /*}{*/
#define PHONE_MAX 500
#elif defined SONY_PTX_520 /*}{*/
#define PHONE_MAX 500
#else
#define PHONE_MAX 50		/* Be conservative, (see eg Nokia above) */
#endif	/*}}*/

/* Define maximum length of name to be stored for mobile phones */
#define	NAME_WIDTH_MAX	64
#define	NAME_WIDTH_MIN	3	/* Nothing special about 3, but program not
				 * written for daft values example <=2,
				 * & probably would crash.
				 */
#ifdef NOKIA_6110	/*{{*/
#define	NAME_WIDTH	14
#else	/*}{ (Sony 13) */
#define	NAME_WIDTH	14
#endif	/*}}*/
/* My new nokia, when set to large font mode shows just part of name, eg
 *	Original
 *				"Abcde + Abcd12" 
 *	Should display as 
 *				"Abcde + Abcd12 #" 
 *	But gets displayed as 
 *				"Abcde + Abcd..." 
 */
#undef	NAME_WIDTH
#define	NAME_WIDTH	12
unsigned name_width = NAME_WIDTH ;

unsigned	phone_max = PHONE_MAX ;

#define LINE_LN 1024
char	line_buf[LINE_LN] ;

#define HOME_INDICATOR		"#"	/* Hash, as in 4 walls,
					 * Better than 'H' to distinguish
					 * from 'W' & 'M' in poor light.
					 */
#ifdef OLD	/*{ gnokii running non FreeBSD-4.7 used to be OK with these
	    but on 4.9 Dollar & and Yen (but not hash) are getting lost, not
	    by this program, but by gnokii wrinting to 6110,
	    they show OK in the gnokii window, but after writing to
	    Nokia 6110 they are no longer visible
	    until/if I fix that, I use boring letters.

	 */
#define WORK_INDICATOR		"$"	/* Dollar, as in working for money */
#define MOBILE_INDICATOR	"\xa5"	/* Yen symbol, looks like Aerial */
#else	/*}{ So now we use boring letters */
#define WORK_INDICATOR		"W"
#define MOBILE_INDICATOR	"Y"	/* Aerial shape, better than M for
					 * Mobile, as horizontal of M
					 * blurs easier into previous
					 * letter.  + not all call
					 * it mobile, eg Americans
					 * "Cell" & Germans "Handy".
					 */
#endif	/*}*/

#include "person.h"

int person_ln ;

struct person *first_person, *cur_person ;

	void
init_person(tmp_person)
	struct person *tmp_person ;
	{
	tmp_person->psn_next = (struct person *)0 ;

	  tmp_person->psn_fn = tmp_person->psn_sn = tmp_person->psn_bn
	= tmp_person->psn_de = tmp_person->psn_co = tmp_person->psn_ah
	= tmp_person->psn_aw = tmp_person->psn_th = tmp_person->psn_tw
	= tmp_person->psn_tm = tmp_person->psn_tn = tmp_person->psn_fh
	= tmp_person->psn_fw = tmp_person->psn_fm = tmp_person->psn_mh
	= tmp_person->psn_mw = tmp_person->psn_mm = tmp_person->psn_ih
	= tmp_person->psn_iw = tmp_person->psn_im = tmp_person->psn_ie
	= tmp_person->psn_cg = tmp_person->psn_tx = tmp_person->psn_eh
	= tmp_person->psn_ew = tmp_person->psn_wh = tmp_person->psn_ww
	= tmp_person->psn_sk = tmp_person->psn_cy = tmp_person->psn_ws
	= tmp_person->psn_sm = tmp_person->psn_ca = tmp_person->psn_oc
	= tmp_person->psn_na = tmp_person->psn_bo = tmp_person->psn_te
	= tmp_person->psn_fr = tmp_person->psn_ac = tmp_person->psn_xs
	= tmp_person->psn_xr = tmp_person->psn_ld = tmp_person->psn_bd
	= tmp_person->psn_bg = tmp_person->psn_jo = tmp_person->psn_cz
	= (char *)0 ;

	}

	void
print_keys()
	{
	char *p =
 "fn:sn:bn:co:ah:aw:th:tw:tm:tn:fh:fw:fm:mh:mw:mm:ih:iw:im:ie:cg:tx:eh:ew:wp:wb:sk:cy:ws:sm:ca:oc:na:bo:te:fr:ac:xs:xr:ld:bd:bg:jo:cz";
	while (*p != '\0' )
		{
		if (*p == ':' ) (void)fputc((int)',', stderr) ;
		else (void)fputc((int)*p, stderr);
		p++;
		}
	(void)fputc((int)'\n', stderr);
	}

/* Returns pointer to address of required field. */
/* LATER: see if enum is supported by MSC V4, & if so shrink field_p etc */
	char **
field_p(field,tmp_person)
	char		*field ;
	struct person	*tmp_person;
	{
#define DEFL_ENTRY	"cz"
	if (strequ(DEFL_ENTRY,field)) return( &(tmp_person->psn_cz) );
		/* do above 1st for speed*/

	if (strequ("fn",field)) return( &(tmp_person->psn_fn) );
	if (strequ("sn",field)) return( &(tmp_person->psn_sn) );
	if (strequ("bn",field)) return( &(tmp_person->psn_bn) );
	if (strequ("de",field)) return( &(tmp_person->psn_de) );
	if (strequ("co",field)) return( &(tmp_person->psn_co) );
	if (strequ("ah",field)) return( &(tmp_person->psn_ah) );
	if (strequ("aw",field)) return( &(tmp_person->psn_aw) );
	if (strequ("th",field)) return( &(tmp_person->psn_th) );
	if (strequ("tw",field)) return( &(tmp_person->psn_tw) );
	if (strequ("tm",field)) return( &(tmp_person->psn_tm) );
	if (strequ("tn",field)) return( &(tmp_person->psn_tn) );
	if (strequ("fh",field)) return( &(tmp_person->psn_fh) );
	if (strequ("fw",field)) return( &(tmp_person->psn_fw) );
	if (strequ("fm",field)) return( &(tmp_person->psn_fm) );
	if (strequ("mh",field)) return( &(tmp_person->psn_mh) );
	if (strequ("mw",field)) return( &(tmp_person->psn_mw) );
	if (strequ("mm",field)) return( &(tmp_person->psn_mm) );
	if (strequ("ih",field)) return( &(tmp_person->psn_ih) );
	if (strequ("iw",field)) return( &(tmp_person->psn_iw) );
	if (strequ("im",field)) return( &(tmp_person->psn_im) );
	if (strequ("ie",field)) return( &(tmp_person->psn_ie) );
	if (strequ("cg",field)) return( &(tmp_person->psn_cg) );
	if (strequ("tx",field)) return( &(tmp_person->psn_tx) );
	if (strequ("eh",field)) return( &(tmp_person->psn_eh) );
	if (strequ("ew",field)) return( &(tmp_person->psn_ew) );
	if (strequ("wh",field)) return( &(tmp_person->psn_wh) );
	if (strequ("ww",field)) return( &(tmp_person->psn_ww) );
	if (strequ("sk",field)) return( &(tmp_person->psn_sk) );
	if (strequ("cy",field)) return( &(tmp_person->psn_cy) );
	if (strequ("ws",field)) return( &(tmp_person->psn_ws) );
	if (strequ("sm",field)) return( &(tmp_person->psn_sm) );
	if (strequ("ca",field)) return( &(tmp_person->psn_ca) );
	if (strequ("oc",field)) return( &(tmp_person->psn_oc) );
	if (strequ("na",field)) return( &(tmp_person->psn_na) );
	if (strequ("bo",field)) return( &(tmp_person->psn_bo) );
	if (strequ("te",field)) return( &(tmp_person->psn_te) );
	if (strequ("fr",field)) return( &(tmp_person->psn_fr) );
	if (strequ("ac",field)) return( &(tmp_person->psn_ac) );
	if (strequ("xs",field)) return( &(tmp_person->psn_xs) );
	if (strequ("xr",field)) return( &(tmp_person->psn_xr) );
	if (strequ("ld",field)) return( &(tmp_person->psn_ld) );
	if (strequ("bd",field)) return( &(tmp_person->psn_bd) );
	if (strequ("bg",field)) return( &(tmp_person->psn_bg) );
	if (strequ("jo",field)) return( &(tmp_person->psn_jo) );

	fprintf(stderr,
		"%s Warning: File %s, Line %ld, Field \"%s\" unrecognised, treating as comment.\n",
		*ARGV, file_name, line_count, field) ;
	return( &(tmp_person->psn_cz) );
	}

	int
get_line()	/* return 0 if fail, as on EOF */
	{
	register int	this_ch, count = LINE_LN ;
	char	*line_ptr = line_buf, ch ;

	line_buf[0] = '\0' ;
	line_count++ ;
	while((this_ch = getc(fp_in)) != EOF)
		{
		ch = (char)this_ch ;
		if (ch == '\n')
			{
			*line_ptr = '\0' ;
			return( line_ptr - line_buf) ;
			}
		*line_ptr++ = ch ;
		if (--count <= 0)
			{
			*--line_ptr = '\0' ; /* The -- loses the ch,
						but need it to avoid writing
						beyond array. */
			fprintf(stderr,
	"%s %s: File %s, Line %ld >= %d chars, too long, break inserted\n",
				*ARGV,
#define SAFER 1	/* undef for old behaviour */
#ifdef SAFER
				"Error",
#else
				"Warning",
#endif
				file_name, line_count, LINE_LN) ;
#ifdef SAFER
			exit(-1);
#else
			return(LINE_LN-1) ;
#endif
			}
		} /* loop for next char */
	if (line_ptr>line_buf)
		/* flush any last line lacking a \n */
		return(line_ptr - line_buf) ;
	else return(EOF);
	}

/* Append to an entry in a person structure */
	void
ent_append( to , from)
	char **to, *from ;
	{
	char *new ; int len ;
	if ((new = realloc( *to,
		(len=strlen(*to)) + 1 + 1 + strlen(from) + 1 ) )
			/* 1st str + \n + space + 2nd str + \0 */
		==(void *)0)
		{perror("ent_append"); exit(EXIT_FAILURE); }
	if ((*from == ' ') || (*from == '\t')) sprintf(new+len,"\n%s", from);
	else
		/* prepend a space on continuation line */
		sprintf(new+len,"\n %s", from);
	*to = new ; /* I guess *to = new is normally un-necessary,
			but reading FreeBSD man malloc re. env. var.
			MALLOC_OPTIONS:
			R ``realloc'' always reallocate when realloc()
			is called, even if the initial allocation
			was big enough.
			This can substantially aid in compacting memory.
			*/
	}

/* Gets an entry such as "sn:stacey" (which may have trailing data on
 * subsequent indented lines).
 *	Return EOF on EOF if no preceeding data.
 *	Return 0 if a person seperator is encountered.
 *	Return 1 if a record is obtained (& don't exit till the whole
 *		of the multi line record is obtained.
 */
	int
get_entry(tmp_person)
	struct person *tmp_person;
	{
	char field[3];
	char *data, **ptr, *start;
	int	len ;

	/* On new files input buffer will be empty, but in normal use
	   the read-ahead (necessary to determine if the previous record
	   is terminated) will have already pre-loaded the buffer */
	if (line_buf[0]=='\0')
		{ /* load input buffer */
		while ((len=get_line()) == 0 ) ; /* discard blank lines */
		if (len == EOF) return(EOF);
		}
	/* detect inter person seperator */
	if (strnequ(seperator,line_buf,seperator_ln))
		{ line_buf[0] = '\0' ; return(0) ; }
	if (isalpha(line_buf[0]) && isalpha(line_buf[1]) &&
		(line_buf[2]==':'))
		{ /* new field specifier */
		field[0]=line_buf[0]; field[1]=line_buf[1];field[2]='\0';
		start=line_buf + 3;
		}
	else	{ /* unspecified data */
		strcpy(field,DEFL_ENTRY);
		start=line_buf ;
		fprintf(stderr,
			"%s Warning: File %s, Line %ld, Data \"%s\"\n",
			*ARGV, file_name, line_count, line_buf) ;
		}
	ptr = field_p(field,tmp_person) ;
	if (*ptr == (char *)0)
		{
		if ((data = malloc(strlen(start)+1))==(void *)0)
			{perror("get_entry 1"); exit(EXIT_FAILURE); }
		*ptr = data ;
		strcpy(data,start);
		}
	else	{ /* Entry used previously, so append */
		fprintf(stderr,
			"Warning file: %s, line: %ld, field: %s, appending \"%s\" to \"%s\"\n",
			file_name, line_count, field,  start, *ptr);
		ent_append( ptr , start);
		}
	/* append cascade indented entry extensions */
	while (((len=get_line()) != 0 ) && ( len != EOF ) &&
		((line_buf[0] ==' ') || (line_buf[0] =='\t')))
		/* if we happen to get an EOF now, leave it till
			next get_entry() invocation. */
		ent_append( ptr , line_buf);
	return(1);
	}

	int
get_person()
	{
	struct person *new_person ;
	int	rslt ;
	if ((new_person = malloc(sizeof(struct person)))==(void *)0)
			{perror("get_person"); exit(EXIT_FAILURE); }
	init_person(new_person);
	if (first_person == (struct person *)0)
		cur_person= first_person = new_person ;
	else	{
		cur_person->psn_next = new_person ;
		cur_person = new_person ;
		}
	while((rslt=get_entry(cur_person)) && (rslt != EOF)) ;
	return(rslt);
	}


/* Receive an empty string & fill it with an incrementing record number */
	char *
get_index(phone_index)
	char *phone_index;
	{
	static int sim_count=1 ;
	/* xgnokii starts numbering both at 1 not 0 */
	static int phone_count=1 ;

	if (phone_count == phone_max + 1 )
		fprintf(stderr,
		"Warning: You exceed assumed maximum memory of phone\n");
		/* do not abort, that's the phones job later */
	sprintf(phone_index,"%s;%d;",
		( sim_count <= sim_max ) ?
			((opt_new_gnokii == (FLAG)0 ) ? "A" : "SM" )
			:
			((opt_new_gnokii == (FLAG)0 ) ? "B" : "ME")
			,
		( sim_count <= sim_max ) ?	sim_count++ :  phone_count++
		) ;
	return(phone_index);
	}

	int
get_call_group(call_group,name)
	char *call_group;
	char *name;
	{
	char *p;
	if ((p=call_group)==(char *)0) return(5) ;
	if (*p=='\0') return(5) ;
	while (*p != '\0') { *p = tolower(*p); p++ ; }
	p = call_group ;
	if (strequ("family",p)) return(0);
	if (strequ("urgent",p)) return(1);
	if (strequ("social",p)) return(2);
	if (strequ("business",p)) return(3);
	if (strequ("club",p)) return(4);
	if (strequ("default",p)) return(5);
	if (strequ("no group",p)) return(5);
	fprintf(stderr,"Unrecognised call group \"%s\" for name \"%s\"\n",
		p,name);
	return(5);
	}

	void
get_file()
	{

	line_count = 0L ;
	line_buf[0] = '\0' ;
	cur_person = first_person = (struct person *)0 ;
	while( get_person() != EOF ) ;
	}

	int
isphone(char *str)
	{
	char *ptr ;
	for (ptr = str ;
		(isdigit((int)*ptr) || (*ptr == '.') || (*ptr == '+') ) ;
		ptr++ ) ;
	if (*ptr == '\0' ) return 1 ;
	fprintf(stderr, "Error, bad phone number: \"%s\"\n", str);
	return 0 ;
	}

#define	NAME_LN	100 /* Maximum output for fn: sn: or bn: record */
		/* in fact all of estic gnokii & isdn want much shorter names */
#define NAME_BIG (3 * NAME_LN + 3)	/* 3 is 2 seperators + null */

/* Print a pair of numbers & names as part of a lookup list */
	int
put_pair(phone, name, location, call_group)
	char *phone, *name, *location, *call_group ;
	{
	char name_int[NAME_BIG];	/* internal copy as external name
						is passed to us several
						times & we dont want to
						succesively append
						all of
							MOBILE_INDICATOR
							WORK_INDICATOR
							HOME_INDICATOR
					*/
	char phone_index[20] ;
#define BUFF	200		/* LATER formalise */
	char buf1[BUFF], buf2[BUFF] ;
	char *p1, *p2 ;
	FLAG	num_done = (FLAG)0 ;

	/* JJLATER Checking is in the wrong place !
	   Checking should be moved from output procedure to input !
	 */
	/* skip incomplete records, comments beginning with a space etc */
	if (	(phone == (char *)0)	|| (*phone == '\0' )	||
		(name == (char *)0)	|| (*name == '\0' )	)
		return -1 ;
	if (*phone == '#') return -1 ; /* hashed out entry, ignore */
	if (isspace((int)*phone))
		{
		/* JJLATER add code to be lenient & eat the space */
		fprintf(stderr, "Warning: bad entry: \"%s:%s\" \"%s\"\n",
			(location == (char *)0) ? "" : location ,
			(phone == (char *)0) ? "" : phone ,
			(name == (char *)0) ? "" : name ) ;
		return -1 ;
		}
#if 1	/*{{*/
	if ((p1=strchr(phone,(int)'\n')) != (char *)0)
		/* unexpected \n, but accept it */ *p1 = '\0' ;
	p1 = phone ;
	if ( *p1 == '+') p1++ ;
	while ( (isdigit ((int)*p1)) || ( *p1 == '.') ) p1++ ;
	if ( *p1 == '\0' ) goto stripped;	/* ideal, no trailing junk */
	/* Trailing junk exists beyond number */
	p2 = p1 ;
	if ( *p2 == '#' ) { *p2 = '\0' ; goto stripped; }
	/* strip white before comment delimiter */
	while (isblank ((int)*p2)) p2++ ;
	if ( *p2 == '\0' ) goto stripped;
	if ( *p2 == '#' ) { *p1 = '\0' ; goto stripped; }
	fprintf(stderr,
		"Warning: bad entry: \"%s:%s\" \"%s\"\n",
		(location == (char *)0) ? "" : location ,
		(phone == (char *)0) ? "" : phone ,
		(name == (char *)0) ? "" : name ) ;
	if (isdigit((int)(*p2)))
		/* Bad format "+49.1234 567890" */
		fprintf(stderr, "Warning: discarded numeric %s\n", p2);
	*p1 = '\0' ;
stripped:

#else /* }{ old code removed between 2004 May 13 & 2006 Sep 25 */

	/* Remove any trailing comment text notes beyond phone number */
	if ((p1=strchr(phone,(int)'\t'))!=(char *)0) *p1 = '\0' ;
	if ((p1=strchr(phone,(int)'\n'))!=(char *)0)
		/* unexpected */ *p1 = '\0' ;
	if ((p1=strchr(phone,(int)' '))!=(char *)0)
		{
		if (isdigit(*(p1 + 1)))
			/* Detected bad format "+49.1234 567890" */
			fprintf(stderr,
				"Warning: truncating number with a space: %s\n",
				phone);
		*p1 = '\0' ;
		}
#endif	/*}}*/

	if (*phone == '\0') return -1 ;

	if (!isphone(phone)) return -1 ;

	strcpy(name_int,name);

	/* Capitalise at least First Character of each space seperated name */
	if (islower(name_int[0])) name_int[0] = toupper(name_int[0]) ;
	for(p1 = name_int; *p1 != '\0' ; p1++ )
		{
		if (opt_capital == (FLAG)0)
			{
			if ((*p1 == ' ') && islower(*(p1+1)))
				*(p1+1) = toupper(*(p1+1));
			}
		else	/* Capitalise all */ *(p1+1) = toupper(*(p1+1));
		}

	/* Remove all '.' & ',' & '-' & 'x' (x for extension maybe) */
	for(p1 = phone, p2 = buf2 ; *p1 != '\0' ; p1++ )
		if ((*p1 != '.') && (*p1 != ',') &&
			( *p1 != '-') && (*p1 != 'x') )
			*p2++ = *p1 ;
	*p2 = '\0' ;

	if (opt_zap && (strlen(buf2) < 6 ))
		{ /* Remove unlikely short numbers */
		return -1 ;
		}
	else if (*buf2 == '\0') return -1 ;

	/* Reduce the number that may be in a local or full international
	   form, to it's mininal form, IE if we are in the same
	   country or town, discard any redundant prefixes */

	if (buf2[0] == '+')
		{ /* Convert "+" to "00" */
		/* International */
		strcpy(buf1,prefix_international);
		strcat(buf1,buf2 + 1);
		}
	else strcpy(buf1,buf2);
	if (strnequ(buf1,int_prefix_country,ln_int_prefix_country))
		{ /* Convert "0049" to "0" */
		strcpy(buf2,prefix_national);
		strcat(buf2,buf1 + ln_int_prefix_country);
		}
	else strcpy(buf2,buf1);
	if (strnequ(buf2,nat_prefix_town,ln_nat_prefix_town))
		{ /* Convert "089" to "" */
		strcpy(buf1,buf2 + ln_nat_prefix_town); }
	else strcpy(buf1,buf2) ;

	/* buf1 now contains shortest version of number, having removed
	   any town & national prefixes that we are situated in */

	if (strlen(buf1) < 3)
		/* 112		Emergency operator (Fire Police Ambulance) */
		/* 140		Alpin Notruf */
		/* 6360		Siemens Perlach */
		/* 19202	City Ambulanz */
		fprintf(stderr,
		"Warning: suspect short number: \"%s\" \"%s\" \"%s\"\n",
		buf1 , name_int , location ) ;

	if (opt_mobile)
		{
		/* Append a location symbol to names:
		 *	$	: Work		: Hint Dollar Money
		 *	#	: Home		: Hint `Own 4 walls'
		 *	Yen	: Mobile	: Hint: Looks like Antenna
		 */

		if (strequ(location,"TH") || strequ(location,"TW") ||
			strequ(location,"TM") || strequ(location,"TN") )
			name_int[name_width -1] ='\0' ;
		if (strequ(location,"TH")|| strequ(location,"TW")||
			strequ(location,"TM")
			/* but not || strequ(location,"TN")
			 * which is a phone number of unknown type,
			 * might be coming from eg phone_merge
			 */
			)
			{
					/* force at least 1 space
					for HOME_INDICATOR, WORK_INDICATOR,
					or MOBILE_INDICATOR */
			if (strlen(name_int) < name_width - 1)
						 strcat(name_int," ") ;
			if strequ(location,"TH") strcat(name_int,
				HOME_INDICATOR ) ;
			else if strequ(location,"TW") strcat(name_int,
				WORK_INDICATOR ) ;
			else if strequ(location,"TM") strcat(name_int,
				MOBILE_INDICATOR ) ;
			}
		}
	/*
	 * Some public phone exchanges 
	 * (local [switching] offices in American parlance)
	 * allow one to dial either the full number including all the
	 * international &/or town codes, or the local short form if
	 * you are in that town.
	 * (My Munich exchange will allow me to dial myself within the
	 * 89 city using 089123456, but will not allow me to dial my
	 * international self within the 49 nation using 004989 ).
	 * As people now rove the world with laptops, making calls via
	 * modem & mobile phone, & in case multiple phone logs are merged,
	 * we allow more than one number in isdn & istec lists so,
	 *  Input:
	 * 		th:+49.89.123456
	 * 	or
	 * 		th:123456
	 * 	etc
	 *  Output:
	 * 	123456		Julian
	 * 	089123456       Julian
	 * 	004989123456    Julian
	 * But as Nokia mobile in Germany via Deutsch Telekom accepts
	 * full +4989123456 syntax, that's what's best to use, & no point
	 * storing duplicates.
	 * Isdnd reports if I call myself: "Call from 89123456 to 123456"
	 * Problem with emergency numbers such as 112 & 0800 !
	 */

	/* Names should not contain a comma, as xgnokii then fails to
         * to do a text to number conversion when parsing a comma
         * seperated list of text names of multiple people to SMS
         * with a single message.
         * But some people may Like commas in names, so just warn by default.
         */

	if (opt_mobile)
		{
		char *s_comma ;
		for (s_comma = name_int ;
			(s_comma=strchr(s_comma, (int)',' )) != (char *)0 ;
			)
			{
			fprintf(stderr,
		"%s Warning: %s %s Comma to Ampersand: %s\n",
				(ARGV == (char **)0) ? "\0" : *ARGV,
				(file_name == (char *)0 ) ? "\0" : file_name ,
				(opt_comma) ? "Converting" :
					"Consider using '-,' option to convert",
				name_int);
		/* JJLATER reporting line number too would be useful,
			so this code should be moved to input test */
			if (opt_comma) *s_comma++ = '&' ;
			else break ;
			}
		}

	/* Print local town format if wanted & in this town */
	if (num_local &&
		! (strnequ(buf1,prefix_international,ln_prefix_international) ||
		   strnequ(buf1,prefix_national,ln_prefix_national)))
		{
		if (opt_isdn_and_estic)
			{
			if (!opt_estic)
				printf("%-30s\t\"%s %s\"\n",buf1,
					location, name_int);
				/* full name may run off screen,
					 so put location first */
			else	/* Estic allows 16 chars in a name,
					EG: "John Smith H" */
				printf(	"%-30s\t\"%.13s %s\"\n",buf1,
					name_int,location);
				/* put person's (short) name before location */
			num_done = (FLAG)1 ;
			}
		else if (opt_mobile)
			{
		/* Mobiles mostly need national or international numbers,
		   not local, as they dont make any assumption which town
		   they are in for normal numbers, unlike terrestial phones;
		   however some few local numbers such as "112"=Emergency
		   need to be left unchanged, so we cant just turn off
		   all local numbers with a
			num_local = (FLAG)0 ;
		   */
			if (
	strequ(buf1,/* Debitel: Auskunft */		"11880") ||
	strequ(buf1,/* Debitel: Hotline */		"22210") ||
	strequ(buf1,/* Debitel: Minutes et More */	"2555") ||
	strequ(buf1,/* German:  Notruf */		"112" ) ||
	strequ(buf1,/* German:  Notruf Alpin */		"140" ) ||
	strequ(buf1,/* German:  Polizei */		"110" ) ||
	strequ(buf1,/* T-Mobil: Auskunft/Vermittlung */	"2555") ||
	strequ(buf1,/* T-Mobil: Konto Audio */		"2000") ||
	strequ(buf1,/* T-Mobil: MobilboxAbfrage */	"3311") ||
	strequ(buf1,/* T-Mobil: PannenService */	"2424") ||
	strequ(buf1,/* T-Mobil: SMS-Operator */		"2522") ||
	strequ(buf1,/* T-Mobil: StauInfo Tegaron */	"2211") ||
	strequ(buf1,/* T-Mobil: T-D1 Service Manager */	"2020") ||
	strequ(buf1,/* T-Mobil: TravelService */	"2525") ||
	strequ(buf1,/* T-Mobil: Verkehrs Info */	"2526") ||
	strequ(buf1,/* T-Mobil: Vermittlung */		"2555") ||
	strequ(buf1,/* T-Mobil: Xtra Service 60 */	"2202") ||

		0 /* blank line above allows a sort with editor */
			)
			/* A nasty ad hoc table till do it a better way.
			   Perhaps later by defining anything begining with a
			   "-" EG "-112" does not get expanded to +4989112
			 */
				{
				printf("%s;%s;%s%d%s\n",
					name_int, buf1,
					get_index(phone_index),
					get_call_group(call_group,name_int) ,
					(opt_new_gnokii==(FLAG)0 ) ? ";" : ""
					) ;
				num_done = (FLAG)1 ;
				}
			}
		}
	/* Print national format if wanted & in this nation */
	if (num_national && !(num_done && num_one) &&
		! strnequ(buf1,prefix_international,ln_prefix_international) )
		{
		buf2[0] = '\0' ;
		if (!strnequ(buf1,prefix_national,ln_prefix_national))
			/* if buf1 is local number */
			strcpy(buf2,nat_prefix_town);
		strcat(buf2,buf1);
		if (opt_isdn_and_estic)
			{	/* not single gnokii, so print now,
				 as may want both */
			if (!opt_estic)
				/* full name may run off screen,
					 so put location first */
				printf("%-30s\t\"%s %s\"\n",buf2,
					location, name_int);
			else
				/* Estic allows 16 chars in a name,
				   put person's (short) name before
				   location */
				printf("%-30s\t\"%.13s %s\"\n",buf2,
					name_int,location);
			num_done = (FLAG)1 ;
			}
		else if (opt_mobile)
			{
			printf("%s;%s;%s%d%s\n",
					name_int, buf2,
					get_index(phone_index),
					get_call_group(call_group,name_int),
					(opt_new_gnokii==(FLAG)0 ) ? ";" : ""
					 ) ;
			num_done = (FLAG)1 ;
			}
		}
	/* Print international format if wanted */
	if (num_international && !(num_done && num_one))
		{
		if (strnequ(buf1,prefix_international,ln_prefix_international) )
			/* buf1 is international */
			strcpy(buf2,buf1);
		else if strnequ(buf1,prefix_national,ln_prefix_national)
			{ /* buf1 is national */
			strcpy(buf2,int_prefix_country);
			strcat(buf2,buf1 + ln_prefix_national);
			}
		else	{ /* buf1 is local */
			strcpy(buf2,int_prefix_country);
			strcat(buf2,my_town);
			strcat(buf2,buf1);
			}
		/* now print */
		if (opt_isdn_and_estic)
			{
			if (opt_estic)
				/* Estic allows 16 chars in a name,
				   put person's (short) name before
				   location */
				printf("%-30s\t\"%.13s %s\"\n",buf2,
					name_int,location);
			else
				/* full name may run off screen,
					 so put location first */
				printf("%-30s\t\"%s %s\"\n",buf2,
					location, name_int);
			num_done = (FLAG)1 ;
			}
		else if (opt_mobile)
			{
			/* Convert "00" back to "+" */
			strcpy(buf1,"+");
			strcat(buf1,buf2 + ln_prefix_international);
			printf("%s;%s;%s%d%s\n", name_int, buf1,
				get_index(phone_index),
				get_call_group(call_group,name_int) ,
				(opt_new_gnokii==(FLAG)0 ) ? ";" : ""
				) ;
			num_done = (FLAG)1 ;
			}
		}
	return 0 ;
	}

	/* Trim any hashed trailing comments, then trim trailing white space */
	void
hash_trim( /* const */ char *ptr0)
	{
	char *ptr1 ;
	if (( ptr0 == (char *)0) || (*ptr0 == '\0')) return ;
	/* Trim any hashed trailing comments */
	if ((ptr1 = index(ptr0, (int)'#')) != NULL ) *ptr1 = '\0' ;
	/* Trim trailing white space */
	for (ptr1 = ptr0 ;	/* warning: assignment discards `const'
					from pointer target type */

		*ptr1++ != '\0' ; ) ;
	ptr1-- ;
	while (--ptr1 >= ptr0)
		{
		if ( isspace((int)*ptr1) ) *ptr1 = '\0' ;
		break ;
		}
	}

/* For a lookup list, not for a full output,
   List all numbers {Telephone,Fax,Modem} x {Home, Work, Mobile} for a person
   Example output:
	01188		"Telefon Auskunft TW"	Phone Work
	001188		"Int. Auskunft TW"	Phone Work
	1234567		"Julian Stacey TW"	Phone Work
	2345678		"Julian Stacey FH"	Fax Home
	123456		"Fred Smith, IBM"
 */
	void
put_short(tmp_person)
	struct person *tmp_person ;
	{
	/* JJLATER add some of tmp_person->psn_de to this procedure */
	char names[NAME_BIG] ;
	char *fn, *sn, *bn, *ie, *cg ;

	fn=tmp_person->psn_fn; sn=tmp_person->psn_sn;
	bn=tmp_person->psn_bn; ie=tmp_person->psn_ie;
	cg=tmp_person->psn_cg;
	hash_trim(fn); hash_trim(sn); hash_trim(bn);
	hash_trim(ie) ; hash_trim(cg) ;
	if (	((fn == (char *)0) || (*fn == '\0')) &&
		((sn == (char *)0) || (*sn == '\0')) &&
		((bn == (char *)0) || (*bn == '\0'))
		) return ;
	if ( opt_mobile &&
		(
		((ie == (char *)0) && ( opt_dflt_exclude == (FLAG)1)) ||
		((ie != (char *)0) && strequ (ie,"-" ) )
		)
	   )
		{
#ifdef DEBUG
		fprintf(stderr,"Skipping %s%s%s\n",
			(fn != (char *)0) ? fn : "" ,
			( ((fn != (char *)0) && (*fn != '\0'))	&&
			  ((sn != (char *)0) && (*sn != '\0')) ) ? " " : "" ,
			(sn != (char *)0) ?  sn : "" ,
			( ((sn != (char *)0) && (*sn != '\0'))	&&
			  ((bn != (char *)0) && (*bn != '\0')) ) ? "," : "" ,
			(bn != (char *)0) ? bn : ""
			) ;
#endif
		return ;
		}
	sprintf(names,"%.100s%s%.100s%s%.100s",
		/* same 100 as NAME_LN */
		(fn != (char *)0) ? fn : "" ,
		( ((fn != (char *)0) && (*fn != '\0'))	&&
		  ((sn != (char *)0) && (*sn != '\0')) ) ? " " : "" ,
		(sn != (char *)0) ?  sn : "" ,
		( ((sn != (char *)0) && (*sn != '\0'))	&&
		  ((bn != (char *)0) && (*bn != '\0')) ) ? 
							" " 
		/* 27.08.2009 The preceeding  " " replaced a prior ",",
		   As option "-," now deprecates commas, so with the
		   previous comma in code, &
		   	This input:
				sn:Surnam
				bn:ABC Company
				cg:Business
				tw:+49.89.12345678.9
				ie:+
			+ this command:	
				phone -g -w 14 -, -+ -n -1 ../../job/odd/names
			Produced this warning:
				phone Warning: ../../job/odd/names Converting Comma to Ampersand: Surnam,ABC CoW
			+ this output:
				Surnam ABC CoW;+4989123456789;SM;6;3
			 */ 
							    : "" ,
		(bn != (char *)0) ? bn : ""
		) ;

	(void)put_pair(tmp_person->psn_th,names,"TH",cg);
	(void)put_pair(tmp_person->psn_tw,names,"TW",cg);
	(void)put_pair(tmp_person->psn_tm,names,"TM",cg);
	(void)put_pair(tmp_person->psn_tn,names,"TN",cg);

	if (opt_isdn_and_estic)	{ /* Only add "|| opt_mobile"
			if you need to store fax number in mobile */
		(void)put_pair(tmp_person->psn_fh,names,"FH",cg);
		(void)put_pair(tmp_person->psn_fw,names,"FW",cg);
		(void)put_pair(tmp_person->psn_fm,names,"FM",cg);
		}
	if (opt_isdn_and_estic)	{ /* Only add "|| opt_mobile"
			 if you need to store modem number in mobile */
		(void)put_pair(tmp_person->psn_mh,names,"MH",cg);
		(void)put_pair(tmp_person->psn_mw,names,"MW",cg);
		(void)put_pair(tmp_person->psn_mm,names,"MM",cg);
		}
	if (opt_isdn_and_estic)	{ /* Not useful to list isdn data connection
				numbers in mobile, so skip them
				for opt_mobile. */
		(void)put_pair(tmp_person->psn_ih,names,"IH",cg);
		(void)put_pair(tmp_person->psn_iw,names,"IW",cg);
		(void)put_pair(tmp_person->psn_im,names,"IM",cg);
		}
	}

put_field(field,content)
	char *field, *content;
	{
	if (content != (char *)0)
		{
		printf("%s:%s\n",field,content);
		field_printed = 1 ;
		}
	}

	void
put_person(pp)
	struct person *pp ;
	{
	field_printed = 0 ;

	/* LATER add upper case conversion */

	put_field("ld",pp->psn_ld);	/* Last update			*/

	/* Contact Info */

	put_field("fn",pp->psn_fn);	/* Forenames			*/
	put_field("sn",pp->psn_sn);	/* Surname			*/

	put_field("bn",pp->psn_bn);	/* Business Name		*/
	put_field("de",pp->psn_de);	/* Department Name		*/

	put_field("th",pp->psn_th);	/* Telephone home		*/
	put_field("tw",pp->psn_tw);	/* Telephone work		*/
	put_field("tm",pp->psn_tm);	/* Telephone mobile		*/
	put_field("tn",pp->psn_tn);	/* Telephone not known where	*/

	put_field("ie",pp->psn_ie);	/* Include/Exclude in own mobile */

	put_field("fh",pp->psn_fh);	/* Fax Home			*/
	put_field("fm",pp->psn_fm);	/* Fax Mobile			*/
	put_field("fw",pp->psn_fw);	/* Fax Work			*/

	put_field("mh",pp->psn_mh);	/* Modem home			*/
	put_field("mw",pp->psn_mw);	/* Modem work			*/
	put_field("mm",pp->psn_mm);	/* Modem mobile			*/

	put_field("ih",pp->psn_ih);	/* ISDN Home			*/
	put_field("iw",pp->psn_iw);	/* ISDN Work			*/
	put_field("im",pp->psn_im);	/* ISDN Mobile			*/

	put_field("eh",pp->psn_eh);	/* Email home			*/
	put_field("ew",pp->psn_ew);	/* Email work			*/

	put_field("wh",pp->psn_wh);	/* Web Home (personal)		*/
	put_field("ww",pp->psn_ww);	/* Web Work (business)		*/

	put_field("ah",pp->psn_ah);	/* Address home			*/
	put_field("aw",pp->psn_aw);	/* Address work			*/

	put_field("tx",pp->psn_tx);	/* Telex			*/

	/* Occupation/Business Info */

	put_field("oc",pp->psn_oc);	/* Occupation			*/
	put_field("jo",pp->psn_jo);	/* Jobs, last approach YYYY.MM.DD */

	put_field("cg",pp->psn_cg);	/* Call Group for incoming	*/
	put_field("co",pp->psn_co);	/* Context EG vsl ukc bg	*/

	/* Leisure Info */

	put_field("bg",pp->psn_bg);	/* Beer Garden Regular		*/
	put_field("cy",pp->psn_cy);	/* Cycle			*/
	put_field("sk",pp->psn_sk);	/* Skier			*/
	put_field("ws",pp->psn_ws);	/* Windsurfer			*/

	/* Equipment */

	put_field("bo",pp->psn_bo);	/* Boat (rubber inflatable)	*/
	put_field("ca",pp->psn_ca);	/* Car				*/
	put_field("te",pp->psn_te);	/* Tent				*/

	/* Personal Info */

	put_field("ac",pp->psn_ac);	/* Accom share			*/
	put_field("bd",pp->psn_bd);	/* Birth date			*/
	put_field("fr",pp->psn_fr);	/* Friend			*/
	put_field("na",pp->psn_na);	/* Nationality ie GB, D, F	*/
	put_field("sm",pp->psn_sm);	/* Smoker			*/
	put_field("xr",pp->psn_xr);	/* Xmas Card Received		*/
	put_field("xs",pp->psn_xs);	/* Xmas Card Sent		*/

	/* Odd Comments Last */

	put_field(DEFL_ENTRY,pp->psn_cz); /* Comment (everything else)	*/

	if ((!( opt_isdn_and_estic || opt_estic || opt_mobile ))
		&& field_printed  ) printf("%s\n",seperator);
	}

	void
put_file()
	{
	cur_person = first_person ;
	while (cur_person != (struct person *)0)
		{
		if (opt_isdn_and_estic || opt_mobile)
			{
			put_short(cur_person) ;
			}
		else	put_person(cur_person) ;
		cur_person = cur_person->psn_next ;
		}
	}

	void
sort_file()
	{
	/* struct person *low, *high, *tmp ; */
	return; /* LATER algorithm incomplete */
#if 0	/*{*/
	low = first_person ;
	while ((low != (struct person *)0) &&
		((high = low->psn_next) != (struct person *)0))
		{
		if (!(opt_isdn_and_estic || opt_mobile))
			{ /* Sort by first name.
				Perhaps later I might sort by surname then by
				forname, (so all members of a family get
				listed together), but that wouldnt be useful
				using mobile phone.
				JJLATER Maybe I should sort by
				bn: business name ?
			 */
			if (strcmp(low->psn_fn,high->psn_fn))
				{ tmp = low ; low = high ; high = tmp ; }
			}
		else
			{ /* Not much point,
				as pipe through sort will be better */
			if (strcmp(low->psn_th,high->psn_th))
				{ tmp = low ; low = high ; high = tmp ; }
			}
		low = low->psn_next ;
		}
#endif	/*}*/
	}

	void
do_file()
	{
	get_file() ;
	if (opt_sort) sort_file() ;
	put_file() ;
	}

	void
syntax()
	{
	fprintf(stderr,"Syntax: %s %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
		*ARGV,
		"[-+] ",
		"[-,] ",
		"[-1] ",
		"[-?] ",
		"[-C] ",
		"[-G 0] ",
		"[-G 1] ",
		"[-I international_prefix] ",
		"[-L] ",
		"[-N national_prefix] ",
		"[-S] ",
		"[-c country_number] ",
		"[-g] ",
		"[-i] ",
		"[-l] ",
		"[-m] ",
		"[-n] ",
		"[-p phone_records] ",
		"[-s sim_records] ",
		"[-t town_number] ",
		"[-w name_width] ",
		"[-z] ",

		"-- or File[s]"
		) ;
	fprintf(stderr,"Valid keys are: ");
	print_keys() ;
	}

	void
digit(char *str)
	{
	int dummy_int;
	if (sscanf(str,"%d",&dummy_int) != 1 )
		/* sscanf is an inadequate test */
		{
		fprintf(stderr,
			"Fatal Error, Prefix should be numeric: \"%s\"\n",
			str);
		syntax();
		exit(1);
		}
	}

	int
main(argc, argv)
	int	argc ; char	**argv ;
	{
	int	exit_code =	0 ;
	char	*p ;
	ARGV =	argv ;
#ifdef	VSL	/* { */
#include	"../../include/vsl.h"
#endif		/* } */
	strcpy(my_country,		 MY_COUNTRY );
	strcpy(my_town,			 MY_TOWN );
	strcpy(prefix_international,	 PREFIX_INTERNATIONAL );
	strcpy(prefix_national,		 PREFIX_NATIONAL );

	for (argc--, argv++ ; argc ; argv++, argc--)
		{
		if (**argv != '-') break ;
		p = *argv + 1 ;
		while(*p) switch(*p++) /* thus allow "-esz" as well as -e -s */
			{
			case '+': /* Exclude entries lacking an "ie:+". */
				opt_dflt_exclude = (FLAG)1 ;
				break ;
			case '1': /* just one number */
				num_one = (FLAG)1 ;
				break ;
			case '?' :
				syntax() ;
				exit(0) ;
				break ;
			case 'c' : /* "1" for USA, 44 for Britain etc */
				if (--argc <= 0) syntax() ;
				strcpy(my_country, *++argv);
				break ;
			case 'g': /* produce gnokii table name:number */
				opt_mobile = (FLAG)1 ;
				break ;
			case ',': /* if set, & if opt_mobile also set,
                                         convert comma in names to ampersand */
				opt_comma = (FLAG)1 ;
				break ;
			case 'G': /* produce gnokii table name:number */
				if (--argc <= 0) syntax() ;
				if ((unsigned)atoi(*++argv) == (FLAG)0)
					opt_new_gnokii = (FLAG)0 ;
				else opt_new_gnokii = (FLAG)1 ;
				opt_mobile = (FLAG)1 ;
				break ;
			case 'i': /* no international number */
				num_international = (FLAG)0 ;
				break ;
			case 'l': /* produce lookup table numbers:names */
				opt_isdn_and_estic = (FLAG)1 ;
				break ;
			case 'm': /* No local number */
				num_local = (FLAG)0 ;
				break ;
			case 'n': /* no national variant number */
				num_national = (FLAG)0 ;
				break ;
			case 'p' : /* phone memory, max number of names */
				if (--argc <= 0) syntax() ;
				phone_max = (unsigned)atoi(*++argv);
				break ;
			case 's' : /* sim memory, max. number of names */
				if (--argc <= 0) syntax() ;
				sim_max = (unsigned)atoi(*++argv);
				break ;
			case 't' : /* "89" for Munich, by default */
				if (--argc <= 0) syntax() ;
				strcpy(my_town, *++argv);
				break ;
			case 'w' : /* phone max name length */
				if (--argc <= 0) syntax() ;
				name_width = (unsigned)atoi(*++argv);
				if (( name_width > NAME_WIDTH_MAX) ||
					( name_width < NAME_WIDTH_MIN))
					{
					fprintf(stderr,
						"-w must be between %d & %d\n",
						NAME_WIDTH_MIN,
						NAME_WIDTH_MAX);
					exit(1);
					}
				break ;
			case 'z': /* zap unlikely short numbers */
				opt_zap = (FLAG)1 ;
				break ;
			case 'C' : /* Capitalise whole name for small screens */
				opt_capital = (FLAG)1 ;
				break ;
			case 'I' : /* "00" for international prefix */
				if (--argc <= 0) syntax() ;
				digit(*++argv);
				strcpy(prefix_international, *argv);
				break ;
			case 'L': /* restrict output name for estic */
				opt_isdn_and_estic = opt_estic = (FLAG)1 ;
				break ;
			case 'N' : /* "0" for national trunk prefix */
				if (--argc <= 0) syntax() ;
				digit(*++argv);
				strcpy(prefix_national, *argv);
				break ;
			case 'S': /* sort output */
				opt_sort = (FLAG)1 ;
				break ;
			default:
				fprintf(stderr, "Unknown flag %c\n", *(p-1)) ;
				syntax();
				exit(1);
				break ;
			}
		}
	if (opt_mobile) {
		if (
		     (
			( num_international == (FLAG)0 ) &&
			( num_national == (FLAG)0 )
		     ) ||
		     (
			( num_international == (FLAG)1 ) &&
			( num_national == (FLAG)1 )
		     )
		   )	{
			syntax();
			fprintf(stderr,
			"Forcing International rather than national numbers\n");
			num_international == (FLAG)1 ;
			num_national == (FLAG)0 ;
			}
		/* we do not test for num_local as some local EG "112"
			need to be allowed through &
			not swapped to "+4989112" */
		}
	if (!( num_local || num_national || num_international ))
		{
		syntax();
		fprintf(stderr, "Error, cannot use all of -i -n -m\n");
		fprintf(stderr, "Forcing International numbers\n");
		num_international == (FLAG)1 ;
		}
	if ((opt_dflt_exclude == (FLAG)1 ) && (opt_mobile == (FLAG)0 ))
		{
		syntax();
		fprintf(stderr, "Warning: -+ is meaningless without -g.\n");
		}

	seperator_ln = strlen(seperator);
	person_ln = sizeof(struct person) ;
	sprintf(int_prefix_country,"%s%s",prefix_international,my_country);
	sprintf(nat_prefix_town,"%s%s",prefix_national,my_town);
	ln_int_prefix_country = strlen(int_prefix_country);
	ln_nat_prefix_town = strlen(nat_prefix_town);
	ln_prefix_national = strlen(prefix_national);
	ln_prefix_international = strlen(prefix_international);
	if (argc == 0)
		{
		file_name = "stdin" ;
		fp_in = stdin ;
		do_file() ;
		exit(0) ;
		}
	else do {
		file_name = *argv++ ;
		fp_in = fopen(file_name, "r") ;
		if (fp_in == (FILE *)0)
			{
			fprintf(stderr, "Cannot open '%s'\n",file_name) ;
			exit_code |= EXIT_FAILURE ;
			continue ;
			}
		do_file() ;
		(void) fclose(fp_in) ;
		} while (--argc) ;
	exit(exit_code) ;
	}

