flak@slovax.UUCP (Dan Flak) (01/19/88)
Last week, I presented a problem to track a family tree: The schema looks like: database people file family field name type character 20 index primary field parent type character 20 index dups. end Rules of the game: (1) The first record is "seeded" into the database. (2) All subsequent entries for the "parent" field must be validated from the "name" field. (That is, all future generations can only come from people who already exist). The challenge: Write an ACE or C program using the Informix Applications Language Library (ALL) which will accept as its first argument the name of any ancestor, and produce a list of all descendants for as many generations as are loaded in the database. As some of you have pointed out, and I am inclined to agree, ACE can handle a fixed number of generations, but can't handle an indefinate number. Below is my "hack" in C. Cut away at the dotted lines (don't forget to remove the .signature), save into a <filename>. Unpack using "sh <filename>", and then do a "make demo". #-------------------- cut here ------------------ #! /bin/sh echo shar: extracting Makefile if test -f 'Makefile' ; then echo shar: will not overwrite Makefile else cat > Makefile << '@EOF Makefile' demo: family family.dat family.f.frm echo "Welcome to John's family" ./family "JOHN (0)" touch demo family: family.c cc -o family family.c -ldb family.dat: family.s family.dlf dbbuild family.s dbstatus people < load.cmd family.f.frm: family.f formbuild family.f @EOF Makefile if test 298 -ne "`wc -c < Makefile`"; then echo shar: checksum error - number of characters should be 298 fi fi chmod 666 Makefile echo shar: extracting README if test -f 'README' ; then echo shar: will not overwrite README else cat > README << '@EOF README' The family program was set up to meet the following challenge. The schema looks like: database people file family field name type character 20 index primary field parent type character 20 index dups. end Rules of the game: (1) The first record is "seeded" into the database. (2) All subsequent entries for the "parent" field must be validated from the "name" field. (That is, all future generations can only come from people who already exist). The challenge: Write a C program using the Informix Applications Language Library (ALL) which will accept as its first argument the name of any ancestor, and produce a list of all descendants for as many generations as are loaded in the database. The family tree (file "tree") is provided to produce a better picture of what's happening. I've included parenthesized numbers as part of the 20 character name. The parenthesis serve two purposes: (1) They keep the name unique (e.g. MARY (2) vs MARY (6)) (2) They also indicate the generation of the person. @EOF README if test 1058 -ne "`wc -c < README`"; then echo shar: checksum error - number of characters should be 1058 fi fi chmod 666 README echo shar: extracting family.c if test -f 'family.c' ; then echo shar: will not overwrite family.c else cat > family.c << '@EOF family.c' /*+ * File: family.c * Description: * Get all the descendants of a specified ancestor. * * Audit Trail: * Program by Dan Flak - 14 Jan 88 * -*/ #ifdef VERSION static char *SCCS = "%Z% %M%:%I% %G% %U%"; #endif /* #includes */ #include <dbio.h> /* #defines */ #define MAXCHILD 100 /* Allowable number of descendants */ /* external variables */ /* referenced external functions */ /* internal functions */ int getchild(); /* global variables */ char ancestor[21]; /* root level for family tree */ char offspring[MAXCHILD][21]; /* array of descendant names */ int numrecs = 0; /* number of members in the tree */ struct dbview family_view [] = /* The dbview for the family file */ { {"name"}, /* Person's name */ {"parent"} /* Person's parent's name */ }; int family_view_num = 2; struct { char name[21]; char parent[21]; } family_buf; /* static variables */ /*< * Function: main (argc, argv) * Description: * Get the first generation of children. * * Arguments: * argv[1] = Ancestor's name * * Returns: * None. * * Side Effects: * None. * * Calls: * Standard Informix ALL Calls. * * PDL: * Open database, set up files, and get the first generation of * children. Call getchild as long as offspring can be found. * >*/ main (argc, argv) int argc; char *argv[]; { int cc, val, len; /* Informix return values */ int i; /* Counter */ sprintf (ancestor,"%-20.20s",argv[1]); /* Put ancestor's name into the * * correct format */ /* Note, a really "good" C programmer would do error checking on cc */ /* Invoking ALL calls to set up database */ cc = dbselect (DBOPEN, "people"); cc = dbselect (FILEOPEN, "family"); cc = dbstructview ("family", family_view, family_view_num); cc = dbselfield ("family", "parent", ACCKEYED); getchild (ancestor); /* get the first generation of * * children */ for (i = 0; i < numrecs; i++) /* get successive generations */ { getchild (offspring[i]); } cc = dbselect (FILECLOSE, "family"); cc = dbselect (DBCLOSE, "people"); for (i = 0; i < numrecs; i++) { printf ("%s\n",offspring[i]); } } /*< * Function: getchild (pname) * Description: * Get the immediate children of the specified parent. * * Arguments: * pname = parent name * * Returns: * None. * * Side Effects: * The global variable, numrecs, is incremented for each child found. * * Calls: * dbfind * * PDL: * Find first child of parent, step through records while still finding * children for that parent. * >*/ int getchild (pname) char *pname; { int cc, val, len; /* Informix return values */ cc = dbfind ("family", COMPARISON, pname, &len, &family_buf); /* Find the first child belonging * * to the parent */ while (cc == 0) /* Find subsequent children */ { /* Fill the array and increment * * the total number of children * * found */ strcpy (offspring[numrecs], family_buf.name); numrecs++; /* Find the next child, and see if * * it still has the same parent */ cc = dbfind ("family", NEXT, &val, &len, &family_buf); if (cc == 0) { cc = strcmp (family_buf.parent, pname); } } } @EOF family.c if test 4015 -ne "`wc -c < family.c`"; then echo shar: checksum error - number of characters should be 4015 fi fi chmod 666 family.c echo shar: extracting family.dlf if test -f 'family.dlf' ; then echo shar: will not overwrite family.dlf else cat > family.dlf << '@EOF family.dlf' JOHN (0) | | JOHN JR (1) |JOHN (0) | MARY (1) |JOHN (0) | SALLY (1) |JOHN (0) | JOHN III (2) |JOHN JR (1) | MARY (2) |JOHN JR (1) | HAL (2) |MARY (1) | CAL (2) |MARY (1) | JOHN IV (3) |JOHN III (2) | JANE (3) |JOHN III (2) | JOE (3) |MARY (2) | WILLIE (3) |MARY (2) | JOHN V (4) |JOHN IV (3) | HARRY (4) |JANE (3) | JOHN VI (5) |JOHN V (4) | JOHN VII (6) |JOHN VI (5) | MARY (6) |JOHN VI (5) | SUSAN (3) |CAL (2) | @EOF family.dlf if test 558 -ne "`wc -c < family.dlf`"; then echo shar: checksum error - number of characters should be 558 fi fi chmod 666 family.dlf echo shar: extracting family.f if test -f 'family.f' ; then echo shar: will not overwrite family.f else cat > family.f << '@EOF family.f' database people screen { Name [a ] Parent [b ] } end attributes a= name, upshift; b = parent, upshift, lookup from *name; end @EOF family.f if test 174 -ne "`wc -c < family.f`"; then echo shar: checksum error - number of characters should be 174 fi fi chmod 666 family.f echo shar: extracting family.s if test -f 'family.s' ; then echo shar: will not overwrite family.s else cat > family.s << '@EOF family.s' database people file family field name type character 20 index primary field parent type character 20 index dups end @EOF family.s if test 122 -ne "`wc -c < family.s`"; then echo shar: checksum error - number of characters should be 122 fi fi chmod 666 family.s echo shar: extracting load.cmd if test -f 'load.cmd' ; then echo shar: will not overwrite load.cmd else cat > load.cmd << '@EOF load.cmd' load ascii family from "family.dlf" bye @EOF load.cmd if test 40 -ne "`wc -c < load.cmd`"; then echo shar: checksum error - number of characters should be 40 fi fi chmod 666 load.cmd echo shar: extracting tree if test -f 'tree' ; then echo shar: will not overwrite tree else cat > tree << '@EOF tree' JOHN (0) | ----------------------------------------- | | | JOHN JR (1) SALLY (1) MARY (1) | | ----------------------------- ------------ | | | | JOHN III (2) MARY (2) CAL (2) HAL (2) | | | -------------- -------------- | | | | | | JOHN IV (3) JANE (3) JOE (3) WILLIE (3) SUSAN (3) | JOHN V (4) | JOHN VI (5) | _______________ | | JOHN VII (6) MARY (6) @EOF tree if test 958 -ne "`wc -c < tree`"; then echo shar: checksum error - number of characters should be 958 fi fi chmod 666 tree -- {hplsla,uw-beaver}!tikal!slovax!flak Dan Flak-R & D Associates,3625 Perkins Lane SW,Tacoma,Wa 98499,206-581-1322