home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_10_09 / schum2.cpp < prev    next >
C/C++ Source or Header  |  1992-06-24  |  7KB  |  346 lines

  1. /*
  2.  
  3.                 Listing 2
  4.  
  5.  outlist.cpp--Print out a "calling tree."
  6.  
  7.   Compiler: Borland C++ 2.0.
  8.   Library:    SoftC version 2.1f or 3.0.
  9.  
  10.   17 March 1992, by Mark W. Schumann
  11.   Usenet: mark@whizbang.ncoast.org
  12.  
  13.   Compile (Borland) with:
  14.  
  15.       bcc -ms -lm outlist.cpp scdbp20s.lib
  16.  
  17.   This program uses a C++ string class originally
  18.   developed by John Bernstein (CIS 70244,1237).
  19.  
  20.   You can probably substitute any of the usual
  21.   C++ implementations of strings without too
  22.   much trouble.
  23.  
  24.  -------------------------------------------------
  25.  
  26.  OUTLIST-- Print out a "calling tree."
  27.  Copyright (C) 1992 by Mark W. Schumann
  28.  
  29.  This program is distributed in the hope that
  30.  it will be useful, but WITHOUT ANY WARRANTY;
  31.  without even the implied warranty of
  32.  MERCHANTABILITY or FITNESS FOR A PARTICULAR
  33.  PURPOSE.
  34.  
  35. */
  36.  
  37. #include <softc.h>
  38. #include <sc_base.h>
  39.  
  40. #include <ctype.h>
  41. #include <dir.h>
  42. #include <iostream.h>
  43. #include <string.h>
  44.  
  45. #include "oostring.h"   // Bernstein's class header.
  46.  
  47. int dbf    = -1;             // Handle of CALLTREE.DBF.
  48. int ntx1 = -1;             //      ...of MEMBER.NTX.
  49. int ntx2 = -1;             //      ...of CALLEDBY.NTX.
  50.  
  51. SC_DBFRINFO rinfo;
  52. SC_FIELD *finfo = NULL;
  53.  
  54. int f_member;                // Field handles for MEMBER,
  55. int f_calledby;            //  CALLEDBY, PHONE, and NAME
  56. int f_phone;                //  fields in CALLTREE file.
  57. int f_name;
  58.  
  59. // Given member/level, print callees.
  60. int printtree (char *, int);
  61.  
  62. // Short-compare of strings.
  63. int sstrcmp (char const *, char const *);
  64.  
  65. // Does file exist?
  66. int file (char const *);
  67.  
  68. // Check for SoftC error and get out.
  69. void errcheck (char const *);
  70.  
  71. // Deallocation and file closes.
  72. void cleanup (void);
  73.  
  74. // Return .TRUE. if null string.
  75. int nil (const char *);
  76.  
  77. // Return .TRUE. if all whitespace.
  78. int empty (const char *);
  79.  
  80.  
  81. //
  82. //  Open CALLTREE with MEMBER and CALLEDBY indexes.
  83. //  Then just call printlist() with the
  84. //  command-line arg.
  85. //
  86.  
  87. int main (int argc, char *argv[])
  88.  
  89. {
  90.  
  91. int flong;
  92.  
  93.     atexit (cleanup);
  94.  
  95.     scdinit (20, 0);
  96.  
  97.     scddopenx (&dbf, "CALLTREE.DBF", SC_RDONLY);
  98.     errcheck ("Opening CALLTREE.DBF");
  99.     scddrinfo (dbf, &rinfo);
  100.     finfo = new SC_FIELD [rinfo.numflds];
  101.     scddfinfo (dbf, &flong, finfo);
  102.     scddfnam2no (dbf, &f_member,     "MEMBER");
  103.     scddfnam2no (dbf, &f_calledby, "CALLEDBY");
  104.     scddfnam2no (dbf, &f_phone,     "PHONE");
  105.     scddfnam2no (dbf, &f_name,      "NAME");
  106.  
  107.     if (!file ("MEMBER.NTX")) {
  108.  
  109.     long lRec;
  110.     char buffer[7];
  111.  
  112.         scdccreate ("MEMBER.NTX", SC_CKEY | SC_UNIQUE,
  113.          "MEMBER", 3, 0);
  114.         scdcopenx (&ntx1, "MEMBER.NTX",
  115.          SC_RDWR | SC_EXCLUDE | SC_BUFFER);
  116.         cout << "Indexing on MEMBER...\n";
  117.  
  118.         for (lRec = 1L; ; lRec++) {
  119.             if (scddrget (dbf, lRec) == SC_SKFAIL) {
  120.                 sceclr();
  121.                 break;
  122.                 }
  123.             errcheck ("Indexing on MEMBER.");
  124.             scddfgets (dbf, 0, buffer);
  125.             scdckadd (ntx1, buffer, lRec);
  126.             cout << '\r' << lRec << " records indexed";
  127.             }
  128.  
  129.         cout << '\n';
  130.         scdcclose (ntx1);
  131.         }
  132.  
  133.     scdcopenx (&ntx1, "MEMBER.NTX", SC_RDONLY);
  134.     errcheck ("Opening MEMBER.NTX");
  135.  
  136.  
  137.     if (!file ("CALLEDBY.NTX")) {
  138.  
  139.     long lRec;
  140.     char buffer[7];
  141.  
  142.         scdccreate ("CALLEDBY.NTX",
  143.          SC_CKEY | SC_UNIQUE,
  144.          "CALLEDBY+MEMBER", 6, 0);
  145.  
  146.         scdcopenx (&ntx2, "CALLEDBY.NTX",
  147.          SC_RDWR | SC_EXCLUDE | SC_BUFFER);
  148.  
  149.         cout << "Indexing on CALLEDBY+MEMBER...\n";
  150.  
  151.         for (lRec = 1L; ; lRec++) {
  152.             if (scddrget (dbf, lRec) == SC_SKFAIL) {
  153.                 sceclr();
  154.                 break;
  155.                 }
  156.             errcheck ("Indexing on CALLEDBY+MEMBER.");
  157.             scddfgets (dbf, f_calledby, buffer);
  158.             scddfgets (dbf, f_member,
  159.              buffer + finfo[f_calledby].len);
  160.             scdckadd (ntx2, buffer, lRec);
  161.             cout << '\r' << lRec << " records indexed";
  162.             }
  163.  
  164.         cout << '\n';
  165.         scdcclose (ntx2);
  166.         }
  167.  
  168.     scdcopenx (&ntx2, "CALLEDBY.NTX", SC_RDONLY);
  169.     errcheck ("Opening CALLEDBY.NTX");
  170.     printtree (argc > 1 ? argv[1] : "", 0);
  171.  
  172.     }
  173.  
  174.  
  175. //
  176. // printtree (char *cpFr, int npLv);
  177. //
  178. // Recursively print out all people called by "cpFr."
  179. //
  180. // Parameters:
  181. //
  182. //   cpFr     ASCIIZ string indicating caller's number.
  183. //   npLv     Indicates "level" of output.
  184. //
  185.  
  186. int printtree (char *cpFr, int npLv)
  187.  
  188. {
  189.  
  190. char member[4];      // Assume DBF:  MEMBER   C  3
  191. char calledby[4];    //              CALLEDBY C  3
  192. char phone[8];       //              PHONE    C  7
  193. char name[31];       //              NAME     C 30
  194.  
  195. char keybuffer[50];    // Buffer for key values, natch.
  196. long nRec;                // Current record number.
  197. int nScCd;                // SoftC error code.
  198. register int i;
  199.  
  200.     sceclr();
  201.  
  202.     strcpy (keybuffer, cpFr);
  203.  
  204.     nScCd = scdckfind (
  205.      ntx2,
  206.      (void *) keybuffer,
  207.      &nRec,
  208.      SC_FIRST);
  209.  
  210.     // The index now points to the first matching
  211.     // record, if any.  Now read in sequence until
  212.     // there is a non-matching record.  Exit on
  213.     // error (code < 0) or end-of-file (code == SC_END).
  214.  
  215.     while (nScCd >= 0 && nScCd != SC_END) {
  216.  
  217.         // Get a record and ensure a match.
  218.         scddrget (dbf, nRec);
  219.         scddfgets (dbf, f_calledby, calledby);
  220.  
  221.         if (nil (cpFr) ? !empty (calledby)
  222.          : sstrcmp (calledby, cpFr))
  223.                 break;
  224.  
  225.       // Break record into fields.
  226.         scddfgets (dbf, f_member, member);
  227.         scddfgets (dbf, f_name,   name);
  228.         scddfgets (dbf, f_phone,  phone);
  229.  
  230.         for (i = 0; i < npLv; i++) cout << '\t';
  231.  
  232.         cout << trim (name);
  233.  
  234.         if (!empty (phone))
  235.             cout << " (" + substr (phone, 0, 3) + ;
  236.              "-" + substr (phone, 3) + ")";
  237.         cout << '\n';
  238.  
  239.         // This recursive call changes the index
  240.         //  pointer information:
  241.         printtree (member, npLv + 1);
  242.  
  243.         // Now to fix index pointer:
  244.         nScCd = scdckfind (
  245.          ntx2,
  246.          (void *) keybuffer,
  247.          &nRec,
  248.          SC_EXACT);
  249.  
  250.         // And go to the next record.  This
  251.         // won't work in the case of duplicate
  252.         // keys, by the way.
  253.         if (nScCd >= 0)
  254.             nScCd = scdcknext (
  255.              ntx2,
  256.              (void *) keybuffer,
  257.              &nRec);
  258.  
  259.         }
  260.  
  261.     errcheck ("Printing call list");
  262.     return nScCd;
  263.  
  264.     }
  265.  
  266.  
  267. //---------- Minor support functions ----------//
  268.  
  269. int sstrcmp (char const *a, char const *b)
  270.  
  271. {
  272.  
  273. register int i;
  274.  
  275.     for (i = 0; a[i] && b[i]; i++)
  276.         if (a[i] != b[i]) return (a[i] - b[i]);
  277.  
  278.     return 0;
  279.  
  280.     }
  281.  
  282. int file (const char *cName)
  283.  
  284. {
  285.  
  286. struct ffblk ff;
  287.  
  288.     return (!findfirst (cName, &ff, 0));
  289.  
  290.     }
  291.  
  292. void errcheck (char const *cText)
  293.  
  294. {
  295.  
  296.     if (sc_code < 0) {
  297.         cout << "SoftC error " << sc_code << '\n';
  298.         cout << scemsg() << '\n';
  299.         cout << cText;
  300.         exit (-1);
  301.         }
  302.     }
  303.  
  304. void cleanup (void)
  305.  
  306. {
  307.  
  308.     scddclose (dbf);
  309.     scdcclose (ntx1);
  310.     scdcclose (ntx2);
  311.  
  312.     if (finfo != NULL)
  313.         delete finfo;
  314.  
  315.     scdterm();
  316.  
  317.     }
  318.  
  319. int nil (const char *s)
  320.  
  321. {
  322.  
  323.     return (s[0] == '\0');
  324.  
  325.     }
  326.  
  327. int empty (const char *s)
  328.  
  329. {
  330.  
  331. register int i;
  332.  
  333.     for (i = 0; s[i]; i++)
  334.         if (!isspace (s[i])) return 0;
  335.  
  336.     return 1;
  337.  
  338.     }
  339.  
  340. -- 
  341. Mark W. Schumann/3111 Mapledale Avenue/Cleveland, Ohio 44109-2447 USA
  342. Domain: mark@whizbang.wariat.org                      CIS: 73750,3527
  343. "Now when I tell people I'm Slovak, they won't think I'm Czech."
  344. --My wife Judy (Mravetz) Schumann remarking upon the Czech/Slovak split
  345.  
  346.