source for mkpath
utzoo!decvax!duke!unc!mcnc!ikonas!mcm
utzoo!decvax!duke!unc!mcnc!ikonas!mcm
Tue Mar 1 12:29:22 AEST 1983
/*
* Mkpath creates UUCP routing information from the Usenet directory
* Mark and Karen Horton send down the Usenet. The map input should
* look something like :
*
* Name: name-of-site
* (extra fields)
* Usenet: connected sites
* (any extra connected sites)
* UUCP: connected sites
* (any extra connected sites)
* Name:
*
* The Usenet: and UUCP: fields must not have any other fields between
* them. Blank lines can be used to separate fields. The connected sites
* can be separated by any number of blanks, tabs, commas, or new-lines.
*
* Usage: mkpath [-lsite][-2][-dsite][-dsite1!site2][-asite1!site2] map-file(s)
*
* -lsite creates paths starting at "site". If not supplied,
* the system name from the <whoami.h> file is used.
*
* -2 forces all routes to be two-way.
*
* -dsite removes "site" from the list; -dsite1!site2 removes the connection
* from "site1" to "site2".
*
* -asite1!site2 adds the connection from "site1" to "site2". If the -2
* option is used, it adds the connection from "site2" to "site1" as well.
*
* The output goes to stdout.
*
* Version 3.0 2/12/83
* Version 3.1 2/21/83 added -a option
* Version 3.2 2/23/83 made storage for -a,-d options dynamic
*
* Written by Mike Mitchell decvax!duke!mcnc!ikonas!mcm
*
*/
#include <stdio.h>
#include <ctype.h>
#include <whoami.h>
FILE *map; /* map input file */
struct site { /* structure for all needed info on a site */
char *name; /* name of site */
struct site *route; /* route to take to get there */
struct path *conn; /* who the site is connected to */
struct site *nxtsite; /* pointer to next site in list */
};
struct path { /* structure for connection & routing info */
struct site *siteptr; /* pointer to site data */
struct path *nxtpath; /* pointer to next hop in route */
};
struct site *Begsite; /* pointer to the start of site data */
struct site *Strsite; /* pointer to starting point's site data */
char *SYSNAME = sysname; /* system name from whoami.h */
main(argc, argv)
int argc;
char **argv;
{
int i, dno, ano, twoflg, upcase(), getcon();
register struct site *curptr; /* current site */
register struct path *conptr; /* pointer to connections */
struct site *search(), *getsite();
struct site *sptr;
struct path *twoptr, *lnkptr;
struct path *ptalloc();
char buf[BUFSIZ], tmp[BUFSIZ], *fgets();
char **dsites, **asites, *stnam, *cp, *index();
char **calloc();
FILE *fopen();
if (argc < 2) {
fprintf(stderr,
"Usage: %s [-lsite][-dsite][-dsite!site][-asite!site] mapfile...\n",
argv[0]);
exit(1);
}
Begsite = NULL;
i = 0;
argc--;
dno = 0;
ano = 0;
twoflg = 0;
stnam = SYSNAME;
/*
* scan for options we can take care of now. Allocate space for -a and -d
* options.
*/
while(i++ < argc) {
if (argv[i][0] == '-') {
switch(argv[i][1]) {
case 'l': stnam = &argv[i][2];
break;
case '2': twoflg = 1;
break;
case 'd': dno++;
break;
case 'a': ano++;
break;
default: fprintf(stderr, "Bad option %s\n",
argv[i]);
exit(1);
}
}
}
if (dno != 0) {
if ((dsites = calloc(dno, sizeof(char *))) == NULL) {
fprintf(stderr, "Can't get mem for -d options");
exit(4);
}
}
if (ano != 0) {
if ((asites = calloc(ano, sizeof(char *))) == NULL) {
fprintf(stderr, "Can't get mem for -a options");
exit(4);
}
}
ano = 0;
dno = 0;
i = 0;
/*
* Loop through the map data files, building the site & connection data
*/
while(i++ < argc) {
if (argv[i][0] == '-') {
switch(argv[i][1]) {
case 'd': dsites[dno++] = &argv[i][2];
break;
case 'a': asites[ano++] = &argv[i][2];
break;
}
continue;
}
map = fopen(argv[i], "r");
if (map == NULL) {
fprintf(stderr, "Cannot open %s for map input\n",
argv[i]);
exit(2);
}
while(fgets(buf, BUFSIZ, map) != NULL) {
/*
* look for a "Name:" field
*/
if ((upcase(buf))&&(strncmp(buf,"NAME:",5)==0)) {
/*
* find out if the current site is in our list. If not, add it to the
* list.
*/
if (sscanf(buf, "NAME: %s", tmp)!=1)
continue;
curptr = getsite(tmp);
buf[0] = '\0';
/*
* now grab the first connected site name, if any.
*/
if (getcon(buf, tmp, 1)) {
/*
* allocate space for the path structure, then check to see if the
* connection is a "known" site. If it isn't, add it to our list
* of "known" sites. Make the recently allocated path structure
* point to the site, and link it in with the rest of the connection
* info.
*/
curptr->conn = ptalloc();
conptr = curptr->conn;
conptr->siteptr=getsite(tmp);
/*
* now get the rest of the connected site names
*/
while(getcon(buf, tmp, 0)) {
conptr->nxtpath = ptalloc();
conptr = conptr->nxtpath;
conptr->siteptr = getsite(tmp);
}
}
}
}
fclose(map);
}
/*
* add any connections specified on the command line
*/
while(ano--) {
if ((cp=index(asites[ano],'!')) == NULL) {
fprintf(stderr,
"Warning: -a%s is an invalid -a command.\n",
asites[ano]);
continue;
}
*cp++ = '\0';
curptr = getsite(asites[ano]);
sptr = getsite(cp);
/*
* go through connection list for site1, and make sure site2 is not already
* connected.
*/
conptr = curptr->conn;
while(conptr != NULL) {
if (conptr->siteptr->name == sptr->name)
break;
conptr = conptr->nxtpath;
}
if (conptr == NULL) {
/*
* add the site into the connection list.
*/
conptr = curptr->conn;
curptr->conn = ptalloc();
curptr->conn->nxtpath = conptr;
curptr->conn->siteptr = sptr;
}
}
/*
* go through the list and make sure the connections are two way.
*/
if (twoflg) {
curptr = Begsite;
while(curptr != NULL) {
twoptr = curptr->conn;
/*
* loop through each site's connection list
*/ while(twoptr != NULL) {
conptr = twoptr->siteptr->conn;
/*
* loop through the connection's connections, looking for the current
* site. Add the site to the connection's connections if it is not
* found.
*/
while((conptr != NULL) && (conptr->siteptr != curptr))
conptr = conptr->nxtpath;
if (conptr == NULL) {
lnkptr = ptalloc();
lnkptr->siteptr = curptr;
lnkptr->nxtpath = twoptr->siteptr->conn;
twoptr->siteptr->conn = lnkptr;
}
twoptr = twoptr->nxtpath;
}
curptr = curptr->nxtsite;
}
}
/*
* now handle the -d options.
*/
while( dno-- ) {
/*
* if a '!' is not in the argument, remove the site name.
*/
if ((cp=index(dsites[dno], '!')) == NULL) {
curptr = search(dsites[dno]);
if (curptr == NULL) {
fprintf(stderr,
"Warning: site %s already removed\n",
dsites[dno]);
continue;
}
remsite(curptr); /* remove the site */
}
/*
* otherwise, remove the connection from the first site to the second site
*/
else {
*cp++ = '\0';
curptr = search(dsites[dno]);
sptr = search(cp);
if (curptr == NULL || sptr == NULL ) {
fprintf(stderr,
"Warning: connection %s!%s non-existent\n",
dsites[dno], cp);
continue;
}
rempath(curptr, sptr); /* remove the connection */
}
}
/*
* look for the starting point
*/
Strsite = search(stnam);
if (Strsite == NULL) {
fprintf(stderr, "cannot find site %s\n", stnam);
exit(3);
}
/*
* The hard part -- create the UUCP route for every site. Paths() is
* a recursive routine that wanders through the connection info
* looking for the best way to get somewhere.
*/
paths(Strsite);
/*
* now that paths has finished, output the routing information.
* All we have to do is traverse the "route" pointers!
*/
curptr = Begsite;
while(curptr != NULL) {
if (curptr->route != NULL) {
printf("%s\t", curptr->name);
proute(curptr);
printf("%%s\n");
}
curptr = curptr->nxtsite;
}
}
/*
* search() searches the "known" sites, looking for the site name
* passed to it. If it finds it, it returns the site pointer to
* it. Otherwise, it returns NULL.
*/
struct site *search(nam)
register char *nam;
{
register struct site *sp;
sp = Begsite;
while(sp != NULL) {
if (strcmp(sp->name, nam) == 0)
return(sp);
sp = sp->nxtsite;
}
return(NULL);
}
/*
* getsite() searchs the site list for a given site. If the site is not
* found, it adds the site name passed to it to the list of "known"
* sites. It allocates the site structure & space for the name,
* copies the name, and links everything in. It returns a pointer to
* the site structure.
*/
struct site *getsite(nam)
register char *nam;
{
char *malloc(), *calloc();
register char *cp;
register struct site *sp;
struct site *search();
cp = nam; /* remove any junk from the name */
while (*cp) {
if (isspace(*cp) || *cp == ',') {
*cp = '\0';
break;
}
cp++;
}
if ((sp = search(nam)) != NULL)
return(sp);
sp = (struct site *)calloc(1, sizeof(struct site));
if (sp == NULL) {
fprintf(stderr, "Cannot get mem for new site!\n");
exit(4);
}
cp = malloc(strlen(nam) + 1);
if (cp == NULL) {
fprintf(stderr, "Cannot get mem for name!\n");
exit(4);
}
strcpy(cp, nam);
sp->name = cp;
sp->nxtsite = Begsite;
Begsite = sp;
sp->route = NULL;
sp->conn = NULL;
return(sp);
}
/*
* getcon() grabs a site name from the "Usenet:" field or the "UUCP:"
* field. If the buffer passed is empty, it reads from the map file.
* if it reads a "Name:" field, it returns false. If it reads a line
* with a colon in it and the passed flag is false, it returns false.
* It reads until there is something on the line that is not a blank,
* tab, comma, or a newline. Once there is something useful in the
* buffer, it removes the first "word" terminated by a blank, tab, comma,
* or newline and returns true.
*/
getcon(buf, name, flag)
char *buf;
register char *name;
int flag;
{
long ftell(), pos;
register char *cp0, *cp1;
char *fgets(), *wrdpos();
cp0 = buf;
cp1 = wrdpos(cp0);
pos = ftell(map);
/*
* read until there is some useful data in buf
*/
while((cp1==NULL)&&((cp0=fgets(buf,BUFSIZ,map))!=NULL)) {
/*
* if there is a colon on this line, see if its a "Name:" field, "Usenet:"
* field, or a "UUCP:" field.
*/
if (upcase(cp0)) {
if (strncmp(cp0, "NAME:", 5) == 0) {
fseek(map, pos, 0);
return(0);
}
if (strncmp(cp0, "USENET:", 7) == 0)
cp0 += 7;
else if (strncmp(cp0, "UUCP:", 5) == 0)
cp0 += 5;
else if (!flag) {
fseek(map, pos, 0);
return(0);
}
else *cp0 = '\0';
}
else if (flag) *cp0 = '\0';
pos = ftell(map);
cp1 = wrdpos(cp0);
}
if (cp0 == NULL) {
fseek(map, pos, 0);
return(0);
}
/*
* now that there is some data, we copy the first "word" into name, and
* remove the "word" from buf, returning true.
*/
while((*cp1) && (!isspace(*cp1)) && (*cp1 != ','))
*name++ = *cp1++;
*name = '\0';
cp1 = wrdpos(cp1);
if (cp1 == NULL)
*buf = '\0';
else strcpy(buf, cp1);
return(1);
}
/*
* ptalloc() allocates a path structure.
*/
struct path *ptalloc()
{
char *calloc();
register struct path *ptr;
ptr = (struct path *)calloc(1, sizeof(struct path));
if (ptr == NULL) {
fprintf(stderr, "Cannot allocate memory for path\n");
exit(4);
}
ptr->siteptr = NULL;
ptr->nxtpath = NULL;
return(ptr);
}
/*
* paths() does all the dirty work. For each site in the connection list,
* it checks the hop count of the stored route and the current route.
* if the current route is shorter or there is no stored route, it
* and assigns the current route as the stored route.
* it then calls itself with the current site's connection list.
*/
paths(sptr)
struct site *sptr;
{
register struct path *pptr;
register struct site *conptr;
int scnt, hopcnt();
register int cnt;
/*
* loop through all the connections
*/
#ifdef DEBUG
/*DBG*/ printf("\npaths: at site %s\n", sptr->name);
#endif
scnt = hopcnt(sptr);
pptr = sptr->conn;
while(pptr != NULL) {
conptr = pptr->siteptr;
if (conptr != Strsite) {
cnt = hopcnt(conptr->route);
/*
* if there is no stored route or if the stored route is longer than
* the current route, replace it.
*/
if ((cnt == 0) || (cnt >= scnt)) {
#ifdef DEBUG
/*DBG*/ printf("changing path for %s.\nOld: ",conptr->name);
/*DBG*/ proute(conptr->route);
/*DBG*/ printf("\nNew: ");
/*DBG*/ proute(sptr);
/*DBG*/ printf("\n");
#endif
conptr->route = sptr;
/*
* final step, call paths() with this site's list of connections
*/
paths(conptr);
#ifdef DEBUG
/*DBG*/ printf("back from paths, now in %s\n", sptr->name);
#endif
}
}
pptr = pptr->nxtpath;
}
}
/*
* upcase() first scans to see if there is a colon in the buffer passed
* to it. If not, it returns false. Otherwise, it converts everything
* in the buffer up to the colon to uppercase and returns true.
*/
upcase(buf)
register char *buf;
{
register char *cp;
char *index();
cp = index(buf, ':');
if (cp == NULL)
return(0);
while(buf != cp) {
if (islower(*buf))
*buf = toupper(*buf);
buf++;
}
return(1);
}
/*
* wrdpos() returns a pointer to the first character that is not a
* blank, tab, comma, or newline. If it can't find one, it returns
* NULL.
*/
char *wrdpos(buf)
register char *buf;
{
while((*buf) && (isspace(*buf)||(*buf==',')))
buf++;
if (*buf)
return(buf);
return(NULL);
}
/*
* hopcnt() returns the number of site structures in the routing list its
* argument points to.
*/
hopcnt(sptr)
register struct site *sptr;
{
register int cnt;
cnt = 0;
while(sptr != NULL) {
cnt++;
sptr = sptr->route;
}
return(cnt);
}
/*
* proute() prints out the way to get to the passed site. It calls itself
* with a pointer to the next site in the route, then prints the current
* site name.
*/
proute(sptr)
register struct site *sptr;
{
if (sptr == NULL || sptr->route == NULL)
return;
proute(sptr->route);
printf("%s!", sptr->name);
}
/*
* rempath removes the connection from its first argument to its
* second argument.
*/
rempath(sptr, cptr)
register struct site *sptr, *cptr;
{
register struct path *pptr;
struct path *pptr0;
pptr = sptr->conn;
/*
* loop through connections
*/
while( pptr != NULL) {
if (pptr->siteptr == cptr) {
/*
* found the connection, now must remove it.
*/
if (pptr == sptr->conn) {
sptr->conn = pptr->nxtpath;
free(pptr);
pptr = sptr->conn;
}
else {
pptr0->nxtpath = pptr->nxtpath;
free(pptr);
pptr = pptr0->nxtpath;
}
}
else {
pptr0 = pptr;
pptr = pptr->nxtpath;
}
}
}
/*
* remsite removes a site from the data base.
*/
remsite(sptr)
register struct site *sptr;
{
register struct site *sitep, *sitep0;
struct path *pptr, *pptr0;
sitep = Begsite;
/*
* search the site list for the one we want.
*/
while( sitep != NULL) {
if (sitep == sptr) {
/*
* we found it. Now free up the name and the connection list.
*/
free(sptr->name);
pptr = sptr->conn;
while(pptr != NULL) {
pptr0 = pptr->nxtpath;
free(pptr);
pptr = pptr0;
}
/*
* now link the data around the site.
*/
if (sitep == Begsite) {
Begsite = sitep->nxtsite;
free(sitep);
sitep = Begsite;
}
else {
sitep0->nxtsite = sitep->nxtsite;
free(sitep);
sitep = sitep0->nxtsite;
}
}
else {
/*
* remove any connections between the current site & the one we are removing
*/
rempath(sitep, sptr);
sitep0 = sitep;
sitep = sitep->nxtsite;
}
}
}
More information about the Comp.sources.unix
mailing list