[comp.sources.misc] v09i099: area code corrector

john@chinet.chi.il.us (John Mundt) (01/05/90)

Posting-number: Volume 9, Issue 99
Submitted-by: john@chinet.chi.il.us (John Mundt)
Archive-name: xchg

This little utility will adjust phone numbers in an area code that was
split in two.  Since the most recent is Chicago, the exchange numbers
are included with the -DCHICAGO option. Otherwise, it can be used for
other area codes if the different exchange numbers are placed in two
data files as explained in README.  

Compile using cc -O -s -o xchg -DCHICAGO xchg.c /lib/libPW.a

Normal usage would be 
	
	xchg -n old_phone_file new_phone_file

You use -n if you are in the new area code (708) or -o if you are
in the old area code (312).  It works on ascii files and probably
on some word processer files as well.

---------------------
John Mundt   Teachers' Aide, Inc.  P.O. Box 1666  Highland Park, IL
john@admctr.chi.il.us
------------------------------cut here----------------------------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README xchg.c
# Wrapped by john@chinet on Wed Dec 20 14:38:27 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(1915 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
Xxchg - fix area codes when one is split in two
X
XThis program came into being when area code 312 was split into two
Xwith 708 being the new one.  Lots of phone numbers had to have the
Xcorrect area codes added, and this does that.  It uses two lists of
Xnumbers which are valid for the new and old exchages, namely new.dat
Xand old.dat respectively.  (If compiled with -DCHICAGO, the two tables
Xwill be compiled right into the program and the data files are not
Xneeded.)
X
XThe proper area code is added to all numbers that were in your local
Xarea but no longer are.  Alternatively, you can add the proper area
Xcode to all numbers, regardless of where they fall now.
X
XIt recognizes a number as [^n]nnn-nnnn[^n], [^n]nnn[ )-]nnn-nnnn[^n]
Xwhere n is a digit.  With an area code, 800-555-1212, (800) 555-1212,
Xand (800)555-1212 are all recognized.  Part numbers with patterns that
Xlook like the above could fake it out.  
X
XUsage is 
X
Xxchg [ -dbno ] [ -O old.dat ] [ -N new.dat ] [infile [outfile] ]
X
XStdin input is read and output is to stdout unless file names are
Xspecified on the command line.  
X
X	-n or -o	one must be specified to tell the program
X			if you are now in the <n>ew exchange or the 
X			<o>ld one.  
X
X	-d 		put area codes in with a dash rather than using
X			parentheses: 800-555-1212, not (800) 555-1212 
X
X	-b 		put in area codes for both the new and the old
X			exchange numbers
X
X	-O		the name of the data on the old exchage
X			numbers.  The first line must have the old
X			exchange area code on it.  Then, one per line
X			are all the exchange prefixes for the
X			exchange.
X
X	-N		the name of the data on the new exchange
X			numbers.  Format as above.
X
XCompile with the following options.  Since regex() and regcmp() are
Xused, the library for same must be incuded.  This is as show below for
XAT&T's SysV3.2.  It is probably somewhere else on different systems.
X
Xcc -O -s -o xchg -DCHICAGO xchg.c /lib/libPW.a
X
END_OF_FILE
if test 1915 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'xchg.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xchg.c'\"
else
echo shar: Extracting \"'xchg.c'\" \(12418 characters\)
sed "s/^X//" >'xchg.c' <<'END_OF_FILE'
X
X/*
X * This program changes phone numbers from an exchange that has been
X * split into two new area codes.  It adds a (new) prefex in front of
X * all numbers that are outside of the current prefix.
X *
X * It assumes two files called old.dat and new.dat which hold the
X * current prefixes for the old and new area codes, respectively.
X * or if -DCHICAGO, two arrays in this source file are used for the
X * conversion from 312 to 708 area codes respectively.
X *
X * (c) 1989 by
X * John P. Mundt
X * 2737 Port Clinton Road
X * Highland Park, IL 60035
X # (708) 432-9073   <-- now you know why I wrote this :-(
X *
X * mundt@admctr.chi.il.us || john@chinet.chi.il.us
X *
X * Permission is given to use this program in any manner whatsoever as
X * long as it is not used for commercial gain.  Naturally, there are no
X * guarantees to its functionality, accuracy, correctness, insightful-
X * ness, etc.  Flames, compliments, and corrections welcome.
X *
X */
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X#include <search.h>
X
X#ifndef TRUE
X#define TRUE	1
X#define FALSE	0
X#endif
X
X#define CNULL		(char *) 0
X#define BOOLEAN		int
X#define OLDNUMS		"old.dat"
X#define NEWNUMS		"new.dat"
X
Xtypedef struct {
X	char *a_name;		/* the exchange's area code as a string */
X	char *a_file;		/* the file where the exchange numbers are kept */
X	int a_list[1000];	/* the list of valid numbers in the exchage */
X	int a_count;		/* count of how many in a_list */
X} ARRAY;
X
Xvoid exit(),
X	 do_it(),
X	 strip(),
X	 print_it(),
X	 make_space(),
X	 get_arrays();
X
Xchar *bsearch(),
X	 *Strdup();
X
Xint intcmp();
X
X#ifdef CHICAGO
Xint old_ary[] = { 312, 202, 203, 204, 207, 214, 220, 221, 222, 224, 225, 226,
X227, 229, 230, 233, 235, 236, 237, 238, 239, 241, 242, 243, 245, 247, 248,
X252, 254, 261, 262, 263, 264, 265, 266, 267, 268, 269, 271, 273, 274, 275,
X276, 277, 278, 280, 281, 282, 283, 284, 285, 286, 287, 288, 292, 294, 302,
X306, 308, 313, 315, 316, 321, 322, 324, 326, 327, 329, 332, 334, 337, 338,
X341, 342, 346, 347, 348, 353, 363, 368, 372, 374, 375, 376, 378, 379, 380,
X384, 399, 401, 404, 407, 408, 410, 413, 415, 417, 419, 421, 427, 431, 434,
X435, 436, 440, 443, 444, 445, 454, 461, 463, 465, 467, 468, 471, 472, 476,
X477, 478, 483, 486, 487, 488, 489, 493, 502, 504, 507, 508, 509, 514, 521,
X522, 523, 525, 527, 528, 533, 536, 538, 539, 542, 545, 548, 549, 550, 555,
X558, 559, 561, 565, 567, 568, 569, 580, 581, 582, 583, 585, 586, 588, 589,
X591, 592, 601, 602, 604, 606, 607, 608, 609, 613, 616, 618, 621, 622, 624,
X625, 626, 630, 631, 633, 637, 638, 641, 642, 643, 644, 645, 646, 648, 649,
X650, 651, 659, 660, 661, 663, 664, 666, 667, 670, 684, 685, 686, 693, 694,
X701, 702, 703, 704, 707, 712, 714, 715, 716, 718, 721, 722, 723, 725, 726,
X727, 728, 731, 732, 733, 734, 735, 736, 737, 738, 743, 744, 745, 750, 751,
X752, 753, 760, 761, 762, 763, 764, 765, 767, 768, 769, 770, 772, 774, 775,
X776, 777, 778, 779, 781, 782, 783, 784, 785, 786, 787, 791, 792, 793, 794,
X796, 797, 802, 804, 805, 807, 808, 812, 814, 819, 821, 822, 826, 828, 829,
X836, 838, 842, 845, 846, 847, 853, 854, 855, 856, 861, 871, 873, 874, 875,
X876, 878, 880, 881, 883, 886, 889, 890, 899, 901, 902, 903, 906, 907, 908,
X909, 914, 915, 917, 918, 919, 921, 922, 923, 924, 925, 927, 929, 930, 933,
X935, 936, 938, 939, 942, 943, 944, 947, 951, 955, 962, 973, 975, 976, 977,
X978, 984, 987, 988, 989, 992, 993, 994, 995, 996, 997, 0 
X};
X
Xint new_ary[] = { 708, 201, 205, 206, 208, 209, 210,
X213, 215, 216, 218, 223, 228, 231, 232, 234, 240, 244, 246,
X249, 250, 251, 253, 255, 256, 257, 258, 259, 260, 272, 279, 
X289, 290, 291, 293, 295, 296, 297, 298, 299, 301, 303, 304,
X305, 307, 310, 314, 317, 318, 319, 323, 325, 328, 330, 331,
X333, 335, 336, 339, 343, 344, 345, 349, 350, 351, 352, 354,
X355, 356, 357, 358, 359, 360, 361, 362, 364, 365, 366, 367,
X369, 371, 377, 381, 382, 383, 385, 386, 387, 388, 389, 390,
X391, 392, 393, 394, 395, 396, 397, 398, 402, 403, 405, 406,
X409, 412, 416, 418, 420, 422, 423, 424, 425, 426, 428, 429,
X430, 432, 433, 437, 438, 439, 441, 442, 446, 447, 448, 449,
X450, 451, 452, 453, 455, 456, 457, 458, 459, 460, 462, 464,
X466, 469, 470, 473, 474, 475, 479, 480, 481, 482, 484, 485,
X490, 491, 492, 495, 496, 497, 498, 499, 501, 503, 505, 506,
X510, 512, 513, 515, 516, 517, 518, 519, 520, 524, 526, 529,
X530, 531, 532, 534, 535, 537, 540, 541, 543, 544, 546, 547,
X551, 552, 553, 554, 555, 556, 557, 560, 562, 563, 564, 566,
X570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 584, 587,
X590, 591, 593, 594, 595, 596, 597, 598, 599, 603, 605, 612,
X614, 615, 617, 619, 620, 623, 627, 628, 629, 632, 634, 635,
X636, 639, 640, 647, 652, 653, 654, 655, 656, 657, 658, 662,
X665, 668, 669, 671, 672, 673, 674, 675, 676, 677, 678, 679,
X680, 681, 682, 683, 687, 688, 689, 690, 691, 692, 695, 696,
X697, 698, 699, 705, 706, 709, 713, 717, 719, 720, 724, 729,
X730, 739, 740, 741, 742, 746, 747, 748, 749, 754, 755, 756,
X757, 758, 759, 766, 771, 773, 780, 788, 789, 790, 795, 796,
X798, 799, 801, 803, 806, 810, 816, 817, 818, 820, 823, 824,
X825, 827, 830, 831, 832, 833, 834, 835, 837, 839, 840, 841,
X843, 844, 848, 849, 850, 851, 852, 857, 858, 859, 860, 862,
X863, 864, 865, 866, 867, 868, 869, 870, 872, 877, 879, 882,
X884, 885, 887, 888, 891, 892, 893, 894, 895, 896, 897, 898,
X904, 905, 910, 913, 916, 920, 926, 931, 932, 934, 937, 940,
X941, 945, 946, 948, 949, 952, 953, 954, 956, 957, 960, 961,
X963, 964, 965, 966, 967, 968, 969, 971, 972, 974, 976, 979,
X980, 981, 982, 983, 985, 986, 990, 991, 998, 0 };
X#endif
X
XARRAY oldx, newx;
XARRAY *presentx_ptr;			/* the exchange user is now in */
XARRAY *otherx_ptr;				/* exchange s/he ain't in */
XBOOLEAN parens;					/* do we use parentheses or dashes */
XBOOLEAN do_both;				/* put in both area codes? */
XBOOLEAN start_of_line;			/* horrible kludge */
Xchar *progname;
X
X/*
X * regular expression which locates what are considered phone numbers
X */
Xchar *_re_phone = 
X	"(([^0-9][0-9]{3}){0,1})$0([^0-9]{1,2})$1([0-9]{3}-[0-9]{4})$2[^0-9]";
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
Xextern int optind, opterr;
Xextern char *optarg;
Xint c;
Xchar buf[BUFSIZ / 2], *re_phone, *regcmp(), *regex();
X	oldx.a_file = OLDNUMS, newx.a_file = NEWNUMS;
X	do_both = FALSE;				/* only add other area code */
X	parens = TRUE;					/* format (800) rather than 800- */
X	opterr = 1;						/* lock getopt()'s ? out */
X	presentx_ptr = (ARRAY *) 0;		/* see if it is set later */
X#ifdef CHICAGO
X	while ((c = getopt(argc, argv, "bdon")) != EOF) {
X#else
X	while ((c = getopt(argc, argv, "bdonO:N:")) != EOF) {
X#endif
X		switch(c) {
X		case 'b'	:	do_both = TRUE;			break;
X		case 'o'	:	presentx_ptr = &oldx;	break;
X		case 'n'	:	presentx_ptr = &newx;	break;
X		case 'd'	:	parens = FALSE;			break;
X#ifndef CHICAGO
X		case 'O'	:	oldx.a_file = optarg;	break;
X		case 'N'	:	newx.a_file = optarg;	break;
X#endif
X		case '?'	:	out();					break;
X		}
X	}
X	if (!presentx_ptr) {			/* which exchage we are in must be known */
X		if (optind >= argc) {		/* if stdin is redirected this won't work */
X			(void)fprintf(stderr, 
X			"Option -o or -n must be set when stdin is redirected\n");
X			exit(1);
X		} else {					/* so ask which exchange we are in */
X			(void) printf("Are you located in the <o>ld or <n>ew exchange?");
X			(void) scanf("%s", buf);
X			if (*buf == 'o' || *buf == 'O')
X				presentx_ptr = &oldx;
X			else
X				presentx_ptr = &newx;
X		}
X	}
X	otherx_ptr = (presentx_ptr == &oldx) ? &newx : &oldx;
X	if (optind < argc) {		/* input file name listed */
X		if (!freopen(argv[optind], "r", stdin)) {
X			(void)fprintf(stderr, "%s cannot be opened for reading\n",
X						argv[optind]);
X			exit(1);
X		}
X		if (++optind < argc && !freopen(argv[optind], "r", stdout)) {
X			(void)fprintf(stderr, "%s cannot be opened for reading\n",
X						argv[optind]);
X			exit(1);
X		}
X	}
X	if (!(re_phone = regcmp(_re_phone, CNULL))) {
X		(void)fprintf(stderr, "%s bad regular expression\n", _re_phone);
X		exit(1);
X	}
X	get_arrays();		/* should've been a look-up table, on hindsight */
X	do_it(re_phone);	/* make the changes */
X	exit(0);
X	/* NOTREACHED */
X}
X
Xvoid do_it(re)
Xchar *re;							/* our compiled regular expression */
X{
Xchar buf[BUFSIZ * 5], area_code[5], spacer[3], number[9], *ptr, *stop;
Xregister char *start;
Xextern char *__loc1;				/* beginning of match, if any */
X	ptr = buf;						/* re matches non-number char at ends */
X	*ptr++ = ' ';					/* this is kludge to make them */
X	while (fgets(ptr, BUFSIZ * 5, stdin)) {
X		start = buf;
X		while (stop = regex(re, start, area_code, spacer, number))  {
X			if (start == buf)
X				start++;
X			if (__loc1 == buf) {	/* phone number at start of line */
X				start_of_line = TRUE;	/* so be sure not to include the */
X				start = ptr;		/* lead fudge character */
X			} else
X				start_of_line = FALSE;
X			while (start < __loc1)
X				(void)putchar(*start++);
X			put_number(area_code, number, spacer);
X			start = --stop;			/* re holds one extra character at end */
X		}							/* print residual string */
X		(void)printf("%s", (start == buf) ? ptr : start);
X	}
X}
X
Xput_number(ac, number, spacer)
Xchar *ac, *number, *spacer;
X{
Xint val;
X	val = atoi(number);
X	if (!*ac) {										/* no area code listed */
X		make_space(spacer);
X		if (bsearch((char *) &val, (char *) otherx_ptr->a_list,
X					otherx_ptr->a_count, sizeof(int *), intcmp)) {
X			print_it(otherx_ptr->a_name, number, '\0');
X		} else if (do_both == TRUE) {				/* in present exchange */
X			if (bsearch((char *) &val, (char *) presentx_ptr->a_list,
X						presentx_ptr->a_count, sizeof(int *), intcmp))
X				print_it(presentx_ptr->a_name, number, '\0');
X			else
X				print_it("???", number, '\0');
X		} else 										/* assume number is */
X			(void)printf("%s", number);				/* in current exchange */
X	} else if (!strcmp(ac + 1, presentx_ptr->a_name)/* matches old or new */
X				|| !strcmp(ac + 1, otherx_ptr->a_name)) {
X		if (bsearch((char *) &val, (char *) presentx_ptr->a_list,
X				presentx_ptr->a_count, sizeof(int *), intcmp))
X			print_it(presentx_ptr->a_name, number, *ac);
X		else if (bsearch((char *) &val, (char *) otherx_ptr->a_list,
X				otherx_ptr->a_count, sizeof(int *), intcmp))
X			print_it(otherx_ptr->a_name, number, *ac);
X		else
X			print_it("???", number, *ac);		/* a wrong! number */
X	} else 										/* different area code */
X		print_it(ac + 1, number, *ac);
X}
X
Xvoid print_it(s1, s2, c)
Xchar *s1, *s2, c;
X{
X	if (c && start_of_line==FALSE && c != '(')	/* no extra parens */
X		(void)putchar(c);
X	(void)printf(parens == TRUE ? "(%s) %s" : "%s-%s", s1, s2);
X}
X
Xintcmp(one, two)
Xint *one, *two;
X{
X	return(*one - *two);
X}
X
X#ifdef CHICAGO
Xvoid get_arrays() 
X{
XARRAY *aptr;
Xint i, *iptr;
Xregister int j;
Xchar buf[10];
X	for (j = i = 0, iptr = old_ary, aptr = &oldx; i < 2; 
X					iptr = new_ary, aptr = &newx, j = 0, i++) {
X		(void)sprintf(buf, "%03d", *iptr);
X		aptr->a_name = Strdup(buf);
X		while (aptr->a_list[j] = iptr[j + 1])
X			j++;
X		aptr->a_count = j;
X		qsort((char *) aptr->a_list, j, sizeof(int *), intcmp);
X	}
X}
X#else
Xvoid get_arrays() 
X{
XFILE *fp;
Xchar buf[BUFSIZ], *ptr;
XARRAY *aptr;
Xint i;
X	for (i = 0, aptr = &oldx; i < 2; aptr = &newx, i++) {
X		aptr->a_count = -1;
X		if (!(fp = fopen(aptr->a_file, "r"))) {
X			(void)fprintf(stderr, "Unable to open numbers file %s\n", 
X				aptr->a_file);
X			exit(1);
X		}
X		while (fgets(buf, BUFSIZ, fp)) {
X			if (isdigit(*buf)) {
X				if (++aptr->a_count == 0) {		/* get the old/new exchange */
X					for (ptr = buf; isspace(*ptr++); )
X						;						/* make a clean string */
X					strip(--ptr);
X					aptr->a_name = Strdup(ptr);
X				} else if ((aptr->a_list[aptr->a_count - 1] = atoi(buf)) < 100 
X								|| aptr->a_list[aptr->a_count] > 999) {
X					(void)fprintf(stderr, "Bad numbers in file %s\n", 
X							aptr->a_file);
X					exit(1);
X				}
X				aptr->a_list[aptr->a_count] = 0;
X			}
X		}
X		qsort((char *) aptr->a_list, (unsigned) aptr->a_count, 
X						sizeof(int *), intcmp);
X	}
X}
X#endif
X
Xout() 
X{
X	(void)fprintf(stderr, 
X		"Usage %s: [-bd] [-o -n] [input file [output file] ]\n", progname);
X	exit(1);
X}
X
Xvoid strip(s)
Xchar *s;
X{
Xregister char *ptr = s + strlen(s);
X	while (--ptr >= s && isspace(*ptr))
X		;
X	*++ptr = '\0';
X}
X
Xvoid make_space(s)
Xchar *s;
X{
X	if (*s && start_of_line == TRUE)	/* remember the kludge */
X		s++;
X	while (*s) {
X		if (*s != '(')
X			(void)putchar(*s);
X		s++;
X	}
X}
X
X/*
X * some systems don't have this, like an AT&T UNIXPC, so...
X */
Xchar *Strdup(s1)
Xchar *s1;
X{
Xchar *s2, *ptr, *malloc();
X        if (!s1)
X                return(CNULL);
X        if (ptr = s2 = malloc((unsigned) strlen(s1) + 1))
X                while (*s2++ = *s1++)
X                        ;
X        return(ptr);
X}
X
END_OF_FILE
if test 12418 -ne `wc -c <'xchg.c'`; then
    echo shar: \"'xchg.c'\" unpacked with wrong size!
fi
# end of 'xchg.c'
fi
echo shar: End of shell archive.
exit 0