home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / comp / sources / misc / 4126 < prev    next >
Encoding:
Text File  |  1992-11-23  |  55.6 KB  |  1,648 lines

  1. Newsgroups: comp.sources.misc
  2. Path: sparky!kent
  3. From: richid@owlnet.rice.edu (Richard Parvin Jernigan)
  4. Subject:  v33i125:  mbase - MetalBase 5.0, Portable database engine, Part07/08
  5. Message-ID: <1992Nov23.233051.9685@sparky.imd.sterling.com>
  6. Followup-To: comp.sources.d
  7. X-Md4-Signature: 1aa82636e6b6f8f67fc49580123863d2
  8. Sender: kent@sparky.imd.sterling.com (Kent Landfield)
  9. Organization: Sterling Software
  10. References: <csm-v33i119=mbase.165613@sparky.IMD.Sterling.COM>
  11. Date: Mon, 23 Nov 1992 23:30:51 GMT
  12. Approved: kent@sparky.imd.sterling.com
  13. Lines: 1633
  14.  
  15. Submitted-by: richid@owlnet.rice.edu (Richard Parvin Jernigan)
  16. Posting-number: Volume 33, Issue 125
  17. Archive-name: mbase/part07
  18. Environment: AMIGA, MS-DOS, HP-UX, XENIX, UNIX, ULTRIX, SGI, SU, Curses
  19. Supersedes: mbase: Volume 28, Issue 40-44
  20.  
  21. #! /bin/sh
  22. # This is a shell archive.  Remove anything before this line, then feed it
  23. # into a shell via "sh file" or similar.  To overwrite existing files,
  24. # type "sh file -c".
  25. # Contents:  dox/crypt.dox dox/flow.dox dox/format.dox dox/struct.dox
  26. #   dox/time.dox sample/bench.c sample/readme sample/sample.frm
  27. #   sample/sample.s src/blast.c src/cache.c src/makefile
  28. #   src/makefile.dos src/parse.c src/struct.c
  29. # Wrapped by kent@sparky on Mon Nov 23 16:33:15 1992
  30. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  31. echo If this archive is complete, you will see the following message:
  32. echo '          "shar: End of archive 7 (of 8)."'
  33. if test -f 'dox/crypt.dox' -a "${1}" != "-c" ; then 
  34.   echo shar: Will not clobber existing file \"'dox/crypt.dox'\"
  35. else
  36.   echo shar: Extracting \"'dox/crypt.dox'\" \(3346 characters\)
  37.   sed "s/^X//" >'dox/crypt.dox' <<'END_OF_FILE'
  38. XEncryption Method                                                 MetalBase 5.0
  39. X-------------------------------------------------------------------------------
  40. X
  41. X  -- Note: This information is provided for your information alone, and --
  42. X  -- is sufficient to crack the (rather simple) encryption method.  If  --
  43. X  --  you are going to be encrypting sensitive data, please delete or   --
  44. X  --               change the permissions on this file.                 --
  45. X
  46. XNote that the encryption is apparently working for ALL supported machines
  47. Xnow--however, this has always been the hardest part to port between machines.
  48. XIf necessary (or if you simply want to), compile mbase.c (and vr.c/sample.c/
  49. Xwhatever) with -DNOENCRYPT, and it'll be turned off.
  50. X
  51. X-------------------------------------------------------------------------------
  52. X
  53. XIf the user has specifed a nonzero key when calling mb_inc(), the following
  54. Xencryption operations take place at any necessary time before the next call
  55. Xto mb_rmv():
  56. X o  All records to be written are encrypted on a field-by-field basis
  57. X o  Records being read for return to the user are decrypted
  58. X o  Records being compared during an internal search are decrypted as needed
  59. X
  60. XIn this way, as long as mb_inc() is always called with the same key, programs
  61. Xwill never see any effect of encryption--records passed to MetalBase routines
  62. Xare not encrypted by the user, and records returned from these routines are
  63. Xalready decrypted.  However, the relation's data will be unintelligible if
  64. Xviewed using either an external file display utility or MetalBase routines
  65. Xwhich have not passed the proper key to mb_inc().
  66. X
  67. XThe key used for encryption is passed as an integer argument to mb_inc(),
  68. Xalong with the relation name which is to be opened.  If this key is 0, no
  69. Xencryption will take place for that session (note that already-encrypted
  70. Xinformation will not be decrypted without the proper key--passing 0 is simply
  71. Xan alternative to encrypting the relation in the first place).  To facilitate
  72. Xmatters, MetalBase 4.0 and up include the routine strtokey() to convert a text
  73. Xstring to a key for mb_inc().
  74. X
  75. XEncryption is performed as follows:
  76. X o During mb_inc(), the key passed in is converted to an 8-bit mask by
  77. X     shuffling the bits around:
  78. X        Bits 12345678  become bits  63417825
  79. X   Okay, so it's not really useful.  So it places limits on portability, and
  80. X   is generally ugly.  But hey--I always wanted an excuse to do some good
  81. X   bit-shuffling...
  82. X
  83. X o When a record is encrypted or decrypted, each field is handled
  84. X     individually.  This is because MB 4.0 originally used a memoried
  85. X     encryption method; i.e., a byte's mask was dependent on that of the byte
  86. X     before it.  Portability problems with uchars made a change to it before
  87. X     the original 4.0 release, but the style is still the same.  In the
  88. X     interests of speed, it is necessary to decrypt only indexed fields
  89. X     during an internal search; thus, each field must be a starting point for
  90. X     the algorithm.
  91. X   To encrypt a field consisting of N bytes (be they for longs, strings,
  92. X     or whatever):
  93. X
  94. X     mask = relation.mask; (set by MetalBase during mb_inc())
  95. X
  96. X     if (mask)
  97. X        for (i=0; i<N; i++)
  98. X         {
  99. X           byte[i] ^= mask;
  100. X           mask     = (mask+1) & (int)0xFF;
  101. X         }
  102. X
  103. X   Decryption uses the exact same routine.
  104. X
  105. END_OF_FILE
  106.   if test 3346 -ne `wc -c <'dox/crypt.dox'`; then
  107.     echo shar: \"'dox/crypt.dox'\" unpacked with wrong size!
  108.   fi
  109.   # end of 'dox/crypt.dox'
  110. fi
  111. if test -f 'dox/flow.dox' -a "${1}" != "-c" ; then 
  112.   echo shar: Will not clobber existing file \"'dox/flow.dox'\"
  113. else
  114.   echo shar: Extracting \"'dox/flow.dox'\" \(4341 characters\)
  115.   sed "s/^X//" >'dox/flow.dox' <<'END_OF_FILE'
  116. XAVL-Balanced Binary Tree Processes                                MetalBase 5.0
  117. X-------------------------------------------------------------------------------
  118. X
  119. XMetalBase 3.2 used straight, unbalanced binary-trees to keep track of data.
  120. X4.0 and up have migrated to AVL-balancing; the routines for keeping a tree
  121. Xin balance, and rebalancing it when needed, are below.  I developed these
  122. Xby hand, just from common sense; if there's a flaw, it hasn't shown up after
  123. Xhundreds of thousands of uses.
  124. X
  125. XAVL balancing means that, at any node in a tree, the number of records to
  126. Xthe left of a node is almost exactly equal to the number on the right; to
  127. Xmake it, work, they can be off by 1.  So the following are balanced:
  128. X
  129. X                     ___5___           ___4___
  130. X                   _2_     _8_       _2_     _6_
  131. X                  1   4   7         1   3   5   7
  132. X
  133. XAnd the following aren't (the first is too heavy to the left at 5, the second
  134. Xis too heavy to the right at 4):
  135. X
  136. X                     ___5___           ___4___
  137. X                   _2_      8                 6_
  138. X                  1   4                          7
  139. X
  140. XThis kind of balancing ensures, in effect, that only the last two levels of
  141. Xthe tree can ever have any empty nodes... so a tree will always stay as shallow
  142. Xas possible, providing the following speeds for algorithms:
  143. X
  144. X                                Worst-Case      Best-Case
  145. X                                ------------    ---------
  146. X               SEARCH...........O(ln(n))........O(1)
  147. X               ADD..............O(n * ln (n))...O(ln (n))
  148. X               UPDATE...........O(n * ln (n))...O(ln (n))
  149. X               DELETE...........O(n * ln (n))...O(ln (n))
  150. X
  151. XI'm particularly interested in getting a better rebalancing routine; mine is
  152. Xthe elegant solution, but I can't believe it's the only, or the fastest.  If
  153. Xyou have any ideas, lemme know.
  154. X
  155. X-------------------------------------------------------------------------------
  156. X
  157. X        Note that some names have changed [to protect the innocent?]  :)
  158. X
  159. X          (*) indicates a procedure must be called once for each index
  160. X
  161. X-------------------------------------------------------------------------------
  162. X
  163. Xupdate (rcd) :
  164. X*  del_preserve (rcd, <index>)
  165. X   change records instance on disk
  166. X*  link (rcd, <index>)
  167. X
  168. Xdelete (rcd) :
  169. X*  del_preserve (rcd, <index>)
  170. X   remove (rcd)
  171. X
  172. Xadd (data) :
  173. X   rcd = append (data)
  174. X*  link (rcd, <index>)
  175. X
  176. Xlink (rcd) :
  177. X*| drop (rcd, <index>)            (these are called, one after the other,
  178. X*| check (rcd, top, <index>)       for each index in the relation)
  179. X
  180. Xdrop (pos, index) :
  181. X   for (loc = top; ; )
  182. X    { dir = compare (rec (loc), rec(pos), index)  -- (-1,0,1)
  183. X      loc->balance += dir;
  184. X      if ( loc->child[dir] == 0 )
  185. X       { loc->child[dir] = rec
  186. X         rec->parent = loc
  187. X         break
  188. X       }
  189. X    }
  190. X
  191. Xcheck (st, ed, index) :
  192. X   for (loc = st; ; loc=loc->parent)
  193. X    { if ( rec (loc) ->unbalanced(index) )
  194. X         balance (loc, index)
  195. X      if (loc == ed)  break;
  196. X    };
  197. X
  198. Xunlink (loc, index) :
  199. X   ch=loc->left || loc->right
  200. X   if (loc->pardir)  loc->parent->right = ch;
  201. X   else              loc->parent->left  = ch;
  202. X   if (ch)  ch->parent = loc->parent, ch->pardir = loc->pardir;
  203. X                     /* DO NOT re-read loc */
  204. X   for (dir=loc->pardir,tmp=loc->parent;tmp!=0;dir=tmp->pardir,tmp=tmp->parent)
  205. X      tmp->balance -= (dir == 1) ? 1 : -1;
  206. X
  207. Xbalance (loc, index) :
  208. X   if (! rep = find_seq (loc, rec(loc)->balance) )  ERROR!!! -- bal>0?Next:Prev
  209. X   rp=rep->parent
  210. X   unlink (rep, index)
  211. X   replace (loc, rep, index) -- Replace LOC with REP
  212. X   drop (loc, index)
  213. X   if (rp != loc)  check (rp, rep)
  214. X                    /* re-read loc */
  215. X   check (loc->parent, rep)
  216. X
  217. Xdelete_preserve (bad) :
  218. X   bp = bad->parent
  219. X   if (bad->balance != 0)
  220. X      rep = find_seq (bad, bad->balance)  --bal>0?Next:Prev
  221. X   else
  222. X      if (! rep = find_seq (bad, toggle (lastmove)))
  223. X         rep = find_seq (bad, toggle (lastmove))
  224. X   if (! rep)
  225. X      unlink (bad)
  226. X   else
  227. X    { rp= rep->parent;
  228. X      unlink (rep)
  229. X      replace (bad, rep)
  230. X      if (rp != bad)  check (rp, bp)
  231. X    }
  232. X   check (bp, top)
  233. X
  234. Xreplace (old, new) :
  235. X   new->left_c = old->left_c;
  236. X   new->right_ = old->right_;
  237. X   new->parent = old->parent;  par=new->parent;
  238. X   new->pardir = old->pardir;
  239. X   par->[pardir]_c = new;
  240. X   new->left_c->parent = new;
  241. X   new->right_c->parent = new;
  242. X
  243. END_OF_FILE
  244.   if test 4341 -ne `wc -c <'dox/flow.dox'`; then
  245.     echo shar: \"'dox/flow.dox'\" unpacked with wrong size!
  246.   fi
  247.   # end of 'dox/flow.dox'
  248. fi
  249. if test -f 'dox/format.dox' -a "${1}" != "-c" ; then 
  250.   echo shar: Will not clobber existing file \"'dox/format.dox'\"
  251. else
  252.   echo shar: Extracting \"'dox/format.dox'\" \(4400 characters\)
  253.   sed "s/^X//" >'dox/format.dox' <<'END_OF_FILE'
  254. XRelation Format                                                   MetalBase 5.0
  255. X-------------------------------------------------------------------------------
  256. X
  257. X              Number   Enum Name    Storage    Typedef From
  258. X              ------  -----------  ---------  --------------
  259. X                 0.....T_CHAR.......char []....
  260. X                 1.....T_SHORT......short......
  261. X                 2.....T_USHORT.....ushort.....unsigned short
  262. X                 3.....T_LONG.......long.......
  263. X                 4.....T_ULONG......ulong......unsigned long
  264. X                 5.....T_FLOAT......float......
  265. X                 6.....T_DOUBLE.....double.....
  266. X                 7.....T_MONEY......double.....
  267. X                 8.....T_TIME.......mb_time....long
  268. X                 9.....T_DATE.......mb_date....long
  269. X                10.....T_SERIAL.....long.......
  270. X                11.....T_PHONE......mb_phone...char[20]
  271. X
  272. X
  273. XFIELD DESCRIPTIONS ------------------------------------------------------------
  274. X
  275. X
  276. XBits in time field:
  277. X   00000000 hhhhhmmm mmmsssss suuuuuuu --h=hour,m=min,s=sec,u=microseconds
  278. X
  279. XBits in date field:
  280. X   00000000 00yyyyyy yyyyyyym mmmddddd --y=year,m=month,d=day
  281. X
  282. XMoney:
  283. X   Money is treated exactly as double, but is rounded to 2 decimal places
  284. X   before being written.
  285. X
  286. XSerial:
  287. X   Serial fields are automatically filled before an 'add' instruction (not
  288. X   before updates), by the system--the number starts with 0 (unless specified
  289. X   otherwise in the schema) and increments on each successive add.  It never
  290. X   decrements (even if a record is deleted), nor is the same number ever used
  291. X   twice.
  292. X
  293. XPhone:
  294. X   Phone number fields are stored as pure text; there's only a special field
  295. X   because scn_phone() and fmt_phone() are there, and it's awfully convenient.
  296. X
  297. X
  298. XRELATION FORMAT ---------------------------------------------------------------
  299. X
  300. X
  301. XPos  #/Bytes   Description
  302. X
  303. X  0   1.......(char)50 : 5.0 signature
  304. X  1   1.......Unused in MB 5.0 (was number of users on the system, 0 == none)
  305. X  2   2.......Unused in MB 5.0 (was PID of temporary lock, 0 == none)
  306. X  4   2.......Unused in MB 5.0 (was PID of exclusive lock, 0 == none)
  307. X  6   4.......Pointer to fields' decriptions  => :A
  308. X 10   4.......Pointer to indices' decriptions => :B
  309. X 14   4.......Pointer to record 0             => :C
  310. X 18   4.......Number of records
  311. X 22   4.......Next serial field value
  312. X 26   2.......Number of fields
  313. X 28   2.......Number of indices
  314. X 30   4*I.....Pointers to index-heading records (top rcd in each tree)
  315. X A:   var*F...Fields' descriptions:
  316. X                 byte    0 : Type (0-10, as listed above)
  317. X                 bytes 1-2 : Size (short/ used only for char fields)
  318. X                 bytes 3-? : Name (max len = 20, terminated by '|')
  319. X B:   var*I...Indices' descriptions:
  320. X                 byte    0 : Type (0-1, 0==nodups, 1==dups)
  321. X                 bytes   1 : Number of fields in this index
  322. X                 bytes 2-? : Name (max len = 20, terminated by ':')
  323. X                       --- : Each field's sequential # (as short, 0-based)
  324. X      1.......Separator ('\n')
  325. X
  326. X ?:   128.....Unused in 5.0 (reserved space for later MB versions)
  327. X                (at runtime, this position is pointed to by {rel->hack})
  328. X
  329. X C:   var*R...Records:
  330. X                 13 bytes for each index: Index information
  331. X                    Bytes  0-3 : Left-child (record #)
  332. X                    Bytes  4-7 : Right-child (record #)
  333. X                    Bytes 8-11 : Parent (record #)
  334. X                    Byte    12 : Balance (';'=-2 '<'=-1 '='=0 '>'=1 '?'=2)
  335. X                 recsize bytes: Record information (no field separators)
  336. X                 1 byte separator ('\n')
  337. X
  338. X
  339. XLOCKFILE FORMAT ---------------------------------------------------------------
  340. X
  341. X
  342. XThere is exactly one lockfile for each relation, kept in a common temporary
  343. Xdirectory.  You can delete the lockfile at any time, as long as you're sure
  344. Xthere is no one using the relation at the time (this would be a Bad Thing to
  345. Xdelete if the relation is in use).  Deleting the lockfile will erase any
  346. Xremaining exclusive lock, and reset the number of users on the relation to
  347. Xzero.
  348. X
  349. XPos  #/Bytes   Description
  350. X
  351. X  0   2.......Number of users on relation, 0 == none
  352. X  2   2.......PID of exclusive lock, 0 == none
  353. X  4   6.......Three hacklock PIDs (see lock.dox)
  354. X 10  60.......Thirty temporary-lock queue positions (see lock.dox)
  355. X 70  30.......Thirty temporary-lock strobes (see lock.dox)
  356. X
  357. END_OF_FILE
  358.   if test 4400 -ne `wc -c <'dox/format.dox'`; then
  359.     echo shar: \"'dox/format.dox'\" unpacked with wrong size!
  360.   fi
  361.   # end of 'dox/format.dox'
  362. fi
  363. if test -f 'dox/struct.dox' -a "${1}" != "-c" ; then 
  364.   echo shar: Will not clobber existing file \"'dox/struct.dox'\"
  365. else
  366.   echo shar: Extracting \"'dox/struct.dox'\" \(2763 characters\)
  367.   sed "s/^X//" >'dox/struct.dox' <<'END_OF_FILE'
  368. XC-Structure Interface                                             MetalBase 5.0
  369. X-------------------------------------------------------------------------------
  370. X
  371. XMetalBase 4.0 and up read and write database information directly from C
  372. Xstructures, using the following assumptions:
  373. X
  374. X            sizeof(long)   = sizeof(ulong)  = 4 bytes
  375. X            sizeof(short)  = sizeof(ushort) = 2 bytes
  376. X            sizeof(float)  = 4 bytes
  377. X            sizeof(double) = 8 bytes
  378. X
  379. XIf any of the above are not valid for your system, MetalBase 5.0 will not work
  380. Xproperly; however, this is the defacto standard, and should produce little
  381. Xdifficulty in porting.  So far, I have yet to receive even one complaint that
  382. Xthis assumption has limited a user's use of this package (one Mac user had
  383. Xto change the defaults for his compiler from a 12-byte double to an 8-byte,
  384. Xbut it worked fine after that).
  385. X
  386. XThe main problem between machines is therefore not type sizes, but byte-
  387. Xaligning in C structures.  At first, one would expect that the following:
  388. X   struct
  389. X    { char   A[3];
  390. X      long   B;
  391. X      char   C[5];
  392. X      char   D[5];
  393. X      double E;
  394. X      char   F[2];
  395. X    }
  396. Xwould appear like this in memory:
  397. X      AAABBBBCCCCCDDDDDEEEEEEEEFF
  398. XUnfortunately, this is not the case for most systems.  On this machine
  399. X(Sun4 SunOs/cc), structures are aligned comme ca:
  400. X      AAAxBBBBCCCCCDDDDDxxxxxxEEEEEEEEFFxxxxxx
  401. XWhile Xenix 2.3.2 would align them as:
  402. X      AAAxBBBBCCCCCDDDDDxxEEEEEEEEFF
  403. XWhy?  Because, for the Sun, each field is aligned on 4- or 8- byte boundaries,
  404. Xdepending on size; shorts, longs and floats to 4-byte boundaries, and doubles
  405. Xto 8-byte ones.  Essentially, the algorithm is:
  406. X
  407. X      start_pos = &base_of_structure;
  408. X      for (each field)
  409. X       { if (type != char)
  410. X            if (sizeof (type) < 8)  align_to_4_byte_boundary (start_pos);
  411. X            else                    align_to_8_byte_boundary (start_pos);
  412. X         add_field
  413. X       }
  414. X      align_to_8_byte_boundary
  415. X
  416. XThe last alignment is to obtain the structure size.
  417. X
  418. XAll this crap was discovered through trial and error (yick!)  If anyone
  419. Xencounters a structure which does not seem to meet the standards shown
  420. Xby struct.c, please contact me (virtual!richid@owlnet.rice.edu) and describe
  421. Xthe structure and your machine type.  If you decide to make any necessary
  422. Xmodifications yourself, you'll find the above algorithm (in essentially that
  423. Xform) in the routine _fill_info() [mbase.c]--but let me know if you get it
  424. Xworking, so I can add machine-dependency to the code with #defines.
  425. X
  426. XCurrently, there are 4 different version supported, as shown by "make struct".
  427. XIn general, these conform to Sun, Coherent/Zortec, Xenix, and Mac/Microsoft C
  428. Xrespectively (definitely not an exhaustive list of compatibility there).
  429. X
  430. END_OF_FILE
  431.   if test 2763 -ne `wc -c <'dox/struct.dox'`; then
  432.     echo shar: \"'dox/struct.dox'\" unpacked with wrong size!
  433.   fi
  434.   # end of 'dox/struct.dox'
  435. fi
  436. if test -f 'dox/time.dox' -a "${1}" != "-c" ; then 
  437.   echo shar: Will not clobber existing file \"'dox/time.dox'\"
  438. else
  439.   echo shar: Extracting \"'dox/time.dox'\" \(3925 characters\)
  440.   sed "s/^X//" >'dox/time.dox' <<'END_OF_FILE'
  441. XTime/Date Functions                                               MetalBase 5.0
  442. X-------------------------------------------------------------------------------
  443. X
  444. XMetalBase handles time and date rather cleanly.  Two new types have been
  445. Xdefined, mb_time and mb_date ... each is actually a parsed-out long, so they
  446. Xmay be passed and returned by value as well as by reference.  There are several
  447. Xfunctions available for use with date and time fields (note that {struct tm *}
  448. Xis a system-supplied structure, and many many many functions are available for
  449. Xits use, completely independant of MetalBase):
  450. X
  451. X   mb_date tmtodate (struct tm *)
  452. X      If the argument passed is a valid {struct tm*} pointer, its information
  453. X      is converted to mb_date format, and the new variable returned.  If the
  454. X      pointer is NULL, the current date is returned.
  455. X
  456. X   mb_time tmtotime (struct tm *)
  457. X      If the argument passed is a valid {struct tm*} pointer, its information
  458. X      is converted to mb_time format, and the new variable returned.  If the
  459. X      pointer is NULL, the current time is returned.
  460. X
  461. X   struct tm *datetimetotm (mb_date, mb_time)
  462. X      If the arguments passed represent valid dates and times, a static local
  463. X      variable is filled out to conform to {struct tm*} conventions and
  464. X      returned.  If either component is zero, that component is replaced by
  465. X      the current date or time.
  466. X
  467. XNote that these functions have been #define'd to the following equivalents
  468. Xas well:
  469. X
  470. X      mb_date    curdate();
  471. X         Returns the current date (assign with "mb_date x = curdate()" or
  472. X         whatever strikes your fancy).
  473. X
  474. X      mb_time    curtime();
  475. X         Returns the current time.
  476. X
  477. X      struct tm *curdatetime();
  478. X         Returns the curent date and time in a {struct tm *} structure.
  479. X
  480. XThere are also two format functions:
  481. X
  482. X   char *fmt_date (mb_date, opt)
  483. X      The date does _not_ default to the current date if it ==0L.  This command
  484. X      returns a pointer to a static local character array, in which the date
  485. X      represented will be formated to one of the following conventions:
  486. X          opt:           format:
  487. X         default          mm/dd/yyyy
  488. X           1              mm/dd/yy
  489. X           2              yymmdd
  490. X      Note that we're approaching 2000, so I don't suggest using mm/dd/yy or
  491. X      yymmdd... just a personal peeve.  Not that my code will be around that
  492. X      long or anything, but it's only what, 8 years away?
  493. X
  494. X   char *fmt_time (mb_time, opt)
  495. X      The time does _not_ default to the current time if it ==0L.  This command
  496. X      returns a pointer to a static local character array, in which the time
  497. X      represented will be formated to one of the following conventions:
  498. X          opt:           format:
  499. X         default          hh:mm:ss   24-hour
  500. X           1              hh:mm xx   where "xx" == "am" or "pm"
  501. X           2              hh:mm      24-hour
  502. X
  503. XAnd, accordingly, there are two scanning functions:
  504. X
  505. X   mb_date scn_date (char *)
  506. X      The string must contain a date, which may be in any of the formats
  507. X      supported by fmt_date, and will be scanned appropriately into an
  508. X      mb_date structure.  Note that this function assumes the separator
  509. X      WILL BE '/' ... if you want hyphens as well, you'll have to add
  510. X      that.
  511. X
  512. X   mb_time scn_time (char *)
  513. X      The string must contain a time, which may be in any of the formats
  514. X      supported by fmt_time, and will be scanned appropriately into an
  515. X      mb_time structure.
  516. X
  517. XThere is also a function to find the number of seconds that have elapsed since
  518. Xa given mb_time:
  519. X   long   elap_t (mb_time)
  520. XIf you pass it 0L, it will return the number of seconds since midnight.
  521. X
  522. XYou can simulate a timer by doing something like this:
  523. X         mb_time  a;
  524. X         a = curtime();   /* Start timer */
  525. X         for (;;)
  526. X            printf ("It's been %ld seconds\n", elap_t(a));
  527. XRather useful at times. :)  Ha!  Times!  A pun!  Get it?  Hooo...
  528. X
  529. END_OF_FILE
  530.   if test 3925 -ne `wc -c <'dox/time.dox'`; then
  531.     echo shar: \"'dox/time.dox'\" unpacked with wrong size!
  532.   fi
  533.   # end of 'dox/time.dox'
  534. fi
  535. if test -f 'sample/bench.c' -a "${1}" != "-c" ; then 
  536.   echo shar: Will not clobber existing file \"'sample/bench.c'\"
  537. else
  538.   echo shar: Extracting \"'sample/bench.c'\" \(2552 characters\)
  539.   sed "s/^X//" >'sample/bench.c' <<'END_OF_FILE'
  540. X/*
  541. X * METALBASE 5.0
  542. X *
  543. X * Released October 1st, 1992 by Huan-Ti [ richid@owlnet.rice.edu ]
  544. X *                                       [ t-richj@microsoft.com ]
  545. X */
  546. X
  547. X#include <mbase.h>
  548. X#include "bench.h"             /* Created during "% build bench.s"  */
  549. X
  550. X#define NUM 10 /* When building chart, each '.' == how many adds? */
  551. X
  552. X#ifdef LONGARGS
  553. X   void  main (int, char **);
  554. X#else
  555. X   void  main ();
  556. X#endif
  557. X
  558. Xrelation  *rel;
  559. X
  560. Xlong   elaparr[79];
  561. X
  562. Xvoid
  563. Xmain  (argc, argv)
  564. Xint    argc;
  565. Xchar **argv;
  566. X{
  567. X   int     i, num, x, top;
  568. X   long    sec;
  569. X   mb_time start;
  570. X
  571. X/*
  572. X * First, parse the command line, and set {num}.
  573. X *
  574. X */
  575. X
  576. X   if (argc == 1)
  577. X      num = 0;
  578. X   else if (argc == 2)
  579. X      num = (int)atoi (argv[1]);
  580. X   else
  581. X      {
  582. X      fprintf (stderr, "format: bench [numberofadds]%s", SNGCR);
  583. X      mb_exit (1);
  584. X      }
  585. X   if (num < 0)
  586. X      {
  587. X      fprintf (stderr, "You gotta add at least one record, idiot.%s", SNGCR);
  588. X      mb_exit (1);
  589. X      }
  590. X
  591. X/*
  592. X * Great.  Now open the database and start it rolling...
  593. X *
  594. X */
  595. X
  596. X   if ((rel = mb_inc ("bench", 0)) == RNULL)
  597. X      {
  598. X      fprintf (stderr, "%s.%s", mb_error, SNGCR);
  599. X      mb_exit (2);
  600. X      }
  601. X
  602. X   start = curtime();
  603. X
  604. X   if (num != 0)
  605. X      {
  606. X      printf ("Number of records: %ld%s", mb_num(rel), SNGCR);
  607. X      printf ("Start time:        %s%s", fmt_time (start, 0), SNGCR);
  608. X      }
  609. X
  610. X   for (x = 0; x < 79; x++)
  611. X      {
  612. X      top = num ? num : NUM;
  613. X      for (i = 0; i < top; i++)
  614. X         {
  615. X         if ((mb_add (rel, &bench_rec)) != MB_OKAY)
  616. X            {
  617. X            printf ("ADD FAILED: %s%s", mb_error, SNGCR);
  618. X            mb_exit(3);
  619. X            }
  620. X         }
  621. X      if (! num)
  622. X         fprintf (stderr, ".");
  623. X
  624. X      sec = elap_t (start);
  625. X
  626. X      if (num != 0)  break;
  627. X
  628. X      elaparr[x] = sec;
  629. X      }
  630. X
  631. X/*
  632. X * All done.  Print the tally.
  633. X *
  634. X */
  635. X
  636. X   if (! num)  printf ("\n");
  637. X   printf ("Number of records: %ld%s", mb_num (rel), SNGCR);
  638. X   if (num)
  639. X      {
  640. X      printf ("End time:          %s%s", fmt_time (curtime(), 0), SNGCR);
  641. X
  642. X      if (i != 0)
  643. X         {
  644. X         printf ("Seconds per add:   %.2lf%s", (double)sec/(double)i, SNGCR);
  645. X         }
  646. X      }
  647. X   else if (elaparr[78] != 0)
  648. X      {
  649. X      printf ("Average seconds per add = %.2lf:\n",
  650. X              ((double)elaparr[78]/(double)(NUM*79)));
  651. X      for (x = 19; x >= 0; x--)
  652. X         {
  653. X         for (i = 0; i < 79; i++)
  654. X            {
  655. X            if ( ((elaparr[i] * 20) / elaparr[78]) >= x )
  656. X               printf ("X");
  657. X            else
  658. X               printf (" ");
  659. X            }
  660. X         printf ("\n");
  661. X         }
  662. X      }
  663. X
  664. X   mb_exit (0);
  665. X}
  666. X
  667. END_OF_FILE
  668.   if test 2552 -ne `wc -c <'sample/bench.c'`; then
  669.     echo shar: \"'sample/bench.c'\" unpacked with wrong size!
  670.   fi
  671.   # end of 'sample/bench.c'
  672. fi
  673. if test -f 'sample/readme' -a "${1}" != "-c" ; then 
  674.   echo shar: Will not clobber existing file \"'sample/readme'\"
  675. else
  676.   echo shar: Extracting \"'sample/readme'\" \(2634 characters\)
  677.   sed "s/^X//" >'sample/readme' <<'END_OF_FILE'
  678. XThe makefiles under this directory are (if it's possible) even harder to
  679. Xdeal with than in ../src --but I guarantee it's all compilable.  :)
  680. X
  681. XEventually.
  682. X
  683. XThere are two primary toys under here, sample and bench.  Sample is really
  684. Xjust there for example code; it happens to work, which is nice, but it's
  685. Xnot doing its intended job unless you look under the hood.  So have at it;
  686. Xit's ugly code (amazing how you can always look back and say, "God, I
  687. Xcan't believe I wrote THAT", isn't it?), but, as I said, it does work.
  688. X                          ^^
  689. X                          Note that I didn't put the comma inside the
  690. X                          quotes.  I think that looks really stupid; it's
  691. X                          not part of the quote.  New standard.  Anyone
  692. X                          wanna draw up a petition?
  693. X
  694. XBench is a benchmark utility.  Run it without any arguments and it'll proceed
  695. Xto add 790 very simple records, one after another, to bench.rel--each '.' it
  696. Xprints represents 10.  Then it'll draw a pretty graph that looks like a plot
  697. Xof any O(n * ln(n)) function (for 5.0 anyway--try it with 4.1a and it looks
  698. Xpretty!  All kindsa lumps and valleys...) and tell you what the average add
  699. Xtime is for all 790 records.  Some typical numbers, with the cache at 500
  700. X(as shipped):
  701. X
  702. X                                      Average time per add,  Multiple that
  703. X Machine   Software                   Versions 5.0 vs 4.1a   it's faster by
  704. X --------  -------------------------  ---------------------  --------------
  705. X NeXT      Non-turbo, 25Mhz            .27 sec vs  ???? sec      x ????
  706. X Sparc 1+  SunOS 4.1 (zzzooooom!!!)    .37 sec vs  1.16 sec      x 3.13
  707. X 386/25dx  Dos 5, SMARTDRV, DublDisk  1.15 sec vs  3.17 sec      x 2.75
  708. X 386/16sx  Xenix of some sort         1.27 sec vs  2.67 sec      x 2.10
  709. X
  710. XSo basically, the faster your processor, the better 5.0 beats the crap out of
  711. X4.1a... just what you'd expect, 'cause its primary change is that all tree
  712. Xbalancing is done cached.  Beware, though; 790 records at even 1 sec per add
  713. Xis just over 13 minutes; this benchmark will take a bit of time to run.  If you
  714. Xchange the cache size in the library it'll change the results a good bit; play
  715. Xwith MAX_CACHE in mbase.h and see.  Optimally you'd want MAX_CACHE to be
  716. Xexactly as big as the number of records you intend to store; more than that
  717. Xwould never be used, less than that and it flushes too often.  If you cut the
  718. Xnumber of records added by the benchmark to around 520, you may be able to see
  719. Xa bit of a peak in the plot where the cache size is...  if you have no more of
  720. Xa life than I do, you may wanna give it a whirl.  :|
  721. X
  722. END_OF_FILE
  723.   if test 2634 -ne `wc -c <'sample/readme'`; then
  724.     echo shar: \"'sample/readme'\" unpacked with wrong size!
  725.   fi
  726.   # end of 'sample/readme'
  727. fi
  728. if test -f 'sample/sample.frm' -a "${1}" != "-c" ; then 
  729.   echo shar: Will not clobber existing file \"'sample/sample.frm'\"
  730. else
  731.   echo shar: Extracting \"'sample/sample.frm'\" \(4088 characters\)
  732.   sed "s/^X//" >'sample/sample.frm' <<'END_OF_FILE'
  733. X#
  734. X# This is form sample--designed as a demonstration data-entry form.  It
  735. X# must be compiled with 'form'; sample_fm.h (built from this by form) is used
  736. X# in sample.c to control data-entry.
  737. X#
  738. X# Released October 1st, 1992 by Huan-Ti [ virtual!root@owlnet.rice.edu ]
  739. X#                                       [ t-richj@microsoft.com ]
  740. X#
  741. X
  742. XData sample;
  743. X
  744. XDefine A credit;    # These names are too long for their DE slots,
  745. XDefine B temp;      # So they're defined to something shorter.
  746. XDefine C num
  747. X
  748. X#
  749. X# Oh yeah.  I added the line below for Number Purchased on a whim... you'll
  750. X# find no mention of it in sample.c; but it works just perfectly, data moving
  751. X# from data-entry template to the relation and back without any specific
  752. X# coding at all.  Good example of some hefty flexibility here...
  753. X#
  754. X# The "4 2" below are the Y,X coordinates of the upper-left corner of this
  755. X# data-entry template on the screen.  Just thought I'd mention that.
  756. X#
  757. X
  758. XScreen 2 2
  759. X{
  760. X     +--------------------------------------------------------------+
  761. X     |                                                              |
  762. X     |  Customer Number...[custnum]   Name...[custname           ]  |
  763. X     |  Customer Phone....[phone               ]                    |
  764. X     |                                                              |
  765. X     |  Current Balance...${balance  }  Accept Credit...[A]..[B    ]  |
  766. X     |  Number Purchased..[C  ]                                     |
  767. X     |                                                              |
  768. X     |  Date Entered......[date_en   ]  Time...[time_en ]           |
  769. X     |                                                              |
  770. X     +--------------------------------------------------------------+
  771. X
  772. X            Ctrl-U          -  Undo (in this field only)
  773. X            Ctrl-Q, Ctrl-C  -  Abort a change
  774. X            Ctrl-A, Ctrl-D  -  Accept transaction; Delete this record
  775. X            Ctrl-N, Ctrl-P  -  Find next record; Find previous record
  776. X
  777. X      Type CTRL-Q (to leave edit mode), then "new" as a customer name
  778. X            to add a new record.
  779. X}
  780. X
  781. X#
  782. X# Note the screwed-up right side on the template above.  The braces
  783. X# surrounding "balance" will be actually -removed- from the display, while
  784. X# the brackets around the others are simply spaced over.  So the template
  785. X# looks perfectly rectangular during data-entry.
  786. X#
  787. X# I only used braces because I wanted the number for the customer's balance
  788. X# to buck right up against the dollar sign.  I know--picky picky...
  789. X#
  790. X
  791. XField credit type choice ("Yy" "Nn" "?");
  792. XField temp   type link to credit ("Yes" "No" "Maybe");
  793. X
  794. X#
  795. X# Ah.  The two lines above create a choice-and-link pair... something I
  796. X# noticed I'd been writing a lot of hard-coded a while back, and decided to
  797. X# support.  Without the "Field temp type link to credit..." thing, the
  798. X# field "sample.credit" would continue to work as you'd expect from a choice
  799. X# field--it only allows characters from the set "YyNn?" in it.  But, add the
  800. X# link to credit, and field "temp" is filled in automatically depending on
  801. X# what "sample.credit" is:  "Yy" maps to "Yes", "Nn" to "No", and "?" to
  802. X# "Maybe".
  803. X#
  804. X# Note that, an alternate setup (if the relation had sample.credit defined
  805. X# to have a few more characters) might be:
  806. X#
  807. X# Field temp   type choice ("Yy" "Nn" "?");
  808. X# Field credit type link to temp ("Yes" "No" "Maybe");
  809. X#
  810. X#    Accept Credit?....[temp]..[credit ]
  811. X#
  812. X# That way, the Yes/No/Maybe is stored in the relation, instead of Y/N/?.
  813. X# Nifty, eh?  Links can only be made to choice fields, and choices need not
  814. X# have links.  A field can't be both a link and a choice, nor can a single
  815. X# field be a link to more than one choice field... but a choice field can
  816. X# have multiple links.  Confused yet?  Play with it.
  817. X#
  818. X
  819. XMode 1 inout  custnum out,   temp out, date_en out, time_en  out; # Add
  820. XMode 2 out    custnum inout, custname inout;                      # Query
  821. XMode 3 inout                 temp out, date_en out, time_en  out; # Update
  822. X
  823. X#
  824. X# Mode 1 is for adding new records,
  825. X# Mode 2 is for finding old records,
  826. X# Mode 3 is for updating existing records.
  827. X#
  828. X
  829. XEnd
  830. X
  831. END_OF_FILE
  832.   if test 4088 -ne `wc -c <'sample/sample.frm'`; then
  833.     echo shar: \"'sample/sample.frm'\" unpacked with wrong size!
  834.   fi
  835.   # end of 'sample/sample.frm'
  836. fi
  837. if test -f 'sample/sample.s' -a "${1}" != "-c" ; then 
  838.   echo shar: Will not clobber existing file \"'sample/sample.s'\"
  839. else
  840.   echo shar: Extracting \"'sample/sample.s'\" \(1571 characters\)
  841.   sed "s/^X//" >'sample/sample.s' <<'END_OF_FILE'
  842. Xrelation sample
  843. X
  844. X#
  845. X#  Each customer at a store, for example, has one record in this relation--the
  846. X#  record contains their name and a customer code (assigned by the system, with
  847. X#  the first customer being 100), their balance and number of purchases made,
  848. X#  the date and time the record was established, and a 3-character string that
  849. X#  describes whether or not they're allowed credit at the store.
  850. X#
  851. X
  852. Xfield custname type string length 30; # A fairly short name field, but hey...
  853. Xfield custnum  type serial start 100; # Assigned automatically (from 100)
  854. Xfield balance  type money;            # Standard double, to .XX resolution
  855. Xfield date_en  date;                  # Date customer entered into database
  856. Xfield time_en  type time;             # Time customer entered into database
  857. Xfield credit   char * 3;              # "y"/"n"/"?" etc.
  858. Xfield num      ushort;                # Number of purchases customer has made
  859. Xfield phone    type phone;            # Phone number of client
  860. X
  861. Xindex ix_name    on custname with duplicates;
  862. Xindex ix_number  on custnum;
  863. Xindex ix_balance on balance            with duplicates;
  864. Xindex ix_entered on date_en, time_en   with duplicates;  # DATE_EN FIRST!!!
  865. X
  866. X#
  867. X# Why date_en first?  Because a composite index, like ix_entered, will
  868. X# sort merrily along the first field you give it... as soon as it finds two
  869. X# records which have the same first field, it'll sort 'em by the second.  So
  870. X# ix_entered will sort things by date, and when the date's the same, by time..
  871. X# if you did it the other way around, it'd be a pretty stupid index.
  872. X#
  873. X
  874. Xend
  875. X
  876. END_OF_FILE
  877.   if test 1571 -ne `wc -c <'sample/sample.s'`; then
  878.     echo shar: \"'sample/sample.s'\" unpacked with wrong size!
  879.   fi
  880.   # end of 'sample/sample.s'
  881. fi
  882. if test -f 'src/blast.c' -a "${1}" != "-c" ; then 
  883.   echo shar: Will not clobber existing file \"'src/blast.c'\"
  884. else
  885.   echo shar: Extracting \"'src/blast.c'\" \(2299 characters\)
  886.   sed "s/^X//" >'src/blast.c' <<'END_OF_FILE'
  887. X/*
  888. X * METALBASE 5.0
  889. X *
  890. X * Released October 1st, 1992 by Huan-Ti [ richid@owlnet.rice.edu ]
  891. X *                                       [ t-richj@microsoft.com ]
  892. X */
  893. X
  894. X#include "stdinc.h"
  895. X
  896. X#ifndef MSDOS
  897. X#ifdef LONGARGS
  898. X   extern char *getenv (char _FAR_ *);
  899. X#else
  900. X   extern char *getenv();
  901. X#endif
  902. X#endif
  903. X
  904. Xvoid
  905. Xmain  (argc, argv)
  906. Xint    argc;
  907. Xchar **argv;
  908. X{
  909. X   char  buf[128], name[128], *pch;
  910. X   int   i;
  911. X
  912. X   if (argc == 1)
  913. X      {
  914. X      fprintf (stderr, "format: blast relation [relation]*\n");
  915. X      exit (1);
  916. X      }
  917. X
  918. X   for (--argc, argv++; argc; argc--, argv++)
  919. X      {
  920. X      if ((*argv)[0] == '-')
  921. X         {
  922. X         fprintf (stderr, "blast: unrecognized switch -%c\n", (*argv)[1]);
  923. X         exit (2);
  924. X         }
  925. X
  926. X      if (access (*argv, 0) == -1)
  927. X         {
  928. X         fprintf (stderr, "blast: cannot find relation %s\n", *argv);
  929. X         continue;
  930. X         }
  931. X
  932. X/*
  933. X * First, get the basename for the relation (take off the path and/or
  934. X * extension)--put it in buf:
  935. X *
  936. X */
  937. X
  938. X      name[0] = 0;
  939. X
  940. X      if ((pch = strrchr (*argv, DIRSEP)) == NULL)
  941. X         pch = *argv;
  942. X      else
  943. X         pch++;
  944. X      strcpy (buf, pch);
  945. X
  946. X      if (! strcmp (buf, ".rel") || ! strcmp (buf, ".REL"))
  947. X         {
  948. X         *(strrchr (buf, '.')) = 0;
  949. X         }
  950. X
  951. X/*
  952. X * Great.  Now get the temporary directory where the lockfile will be...
  953. X *
  954. X */
  955. X
  956. X      if ((pch = getenv ("TMP")) != NULL || (pch = getenv ("TEMP")) != NULL)
  957. X         {
  958. X         strcpy (name, pch);  /* If they define a directory, use it. */
  959. X         }
  960. X      else                   /* Otherwise, try to guess a default directory. */
  961. X         {
  962. X#ifdef UNIX
  963. X         strcpy (name, "/tmp");
  964. X#endif
  965. X         }
  966. X      if (! name[0])
  967. X         {
  968. X         fputs ("blast: you must have a TMP directory defined.\n", stderr);
  969. X         exit (3);
  970. X         }
  971. X      if (name[(i = strlen(name))-1] != DIRSEP)
  972. X         {
  973. X         name[i] = DIRSEP;
  974. X         name[i+1] = 0;
  975. X         }
  976. X
  977. X/*
  978. X * And attach the filename + .LCK to get a lockfile name.  Then delete the
  979. X * stupid thing.
  980. X *
  981. X */
  982. X
  983. X      strcat (name, buf);
  984. X      strcat (name, ".lck");
  985. X
  986. X      if (access (name, 0) == -1)
  987. X         {
  988. X         fprintf (stderr, "blast: %s was not locked\n", *argv);
  989. X         continue;
  990. X         }
  991. X
  992. X      unlink (name);
  993. X
  994. X      fprintf (stderr, "%s blasted successfully\n", *argv);
  995. X      }
  996. X}
  997. X
  998. END_OF_FILE
  999.   if test 2299 -ne `wc -c <'src/blast.c'`; then
  1000.     echo shar: \"'src/blast.c'\" unpacked with wrong size!
  1001.   fi
  1002.   # end of 'src/blast.c'
  1003. fi
  1004. if test -f 'src/cache.c' -a "${1}" != "-c" ; then 
  1005.   echo shar: Will not clobber existing file \"'src/cache.c'\"
  1006. else
  1007.   echo shar: Extracting \"'src/cache.c'\" \(2960 characters\)
  1008.   sed "s/^X//" >'src/cache.c' <<'END_OF_FILE'
  1009. X/*
  1010. X * METALBASE 5.0
  1011. X *
  1012. X * Released October 1st, 1992 by Huan-Ti [ richid@owlnet.rice.edu ]
  1013. X *                                       [ t-richj@microsoft.com ]
  1014. X */
  1015. X
  1016. X#define UTIL_C
  1017. X#include "mbase.h"
  1018. X#include "internal.h"
  1019. X
  1020. Xcache  mb_cache[MAX_CACHE];
  1021. Xcache  mb_ctop;
  1022. Xint    ncache = 0;
  1023. Xcache *mb_clast = NULL;
  1024. Xlong   mb_nlast = 0L;
  1025. X
  1026. Xcache *mb_hash[MAX_CACHE];  /* Attempted */
  1027. X
  1028. X/****************************************************************************/
  1029. X
  1030. Xcache *
  1031. X_read_cache (rel, rcd, idx)
  1032. Xrelation    *rel;
  1033. Xlong              rcd;
  1034. Xint                    idx;
  1035. X{
  1036. X   cache *ptr, *end;
  1037. X   long   n;
  1038. X
  1039. X   end = &mb_cache[ncache];  /* Can't check when ptr==end */
  1040. X
  1041. X   if (mb_nlast == rcd && mb_clast != NULL)  /* Now in practice, we seem to */
  1042. X      {                                      /* query the same one twice    */
  1043. X      return mb_clast;                       /* in a row a lot, so here's   */
  1044. X      }                                      /* a hack to optimize for it.  */
  1045. X
  1046. X   mb_nlast = rcd;
  1047. X
  1048. X   if (rcd == 0L)
  1049. X      {
  1050. X      if (mb_ctop.num != 0L)
  1051. X         {
  1052. X         return (mb_clast = &mb_ctop);
  1053. X         }
  1054. X
  1055. X      GO_TOP (rel, idx);
  1056. X      readx  (rel->relcode, &(mb_ctop.num), 4);
  1057. X      mb_ctop.changed = 0;
  1058. X      return (mb_clast = &mb_ctop);
  1059. X      }
  1060. X
  1061. X   if ((ptr = mb_hash[ n=(rcd % MAX_CACHE) ]) != NULL && ptr->num == rcd)
  1062. X      {
  1063. X      return (mb_clast = ptr);
  1064. X      }
  1065. X
  1066. X   for (ptr = mb_cache; ptr < end; ptr++)
  1067. X      if (ptr->num == rcd)
  1068. X         {
  1069. X         return (mb_clast = mb_hash[n] = ptr);
  1070. X         }
  1071. X
  1072. X   ptr = _new_cache (rel, idx);
  1073. X
  1074. X   GO_INDEX (rel, rcd, idx);
  1075. X   readx (rel->relcode, &(ptr->left),   4);
  1076. X   readx (rel->relcode, &(ptr->right),  4);
  1077. X   readx (rel->relcode, &(ptr->parent), 4);
  1078. X   readx (rel->relcode, &(ptr->parbal), 1);
  1079. X
  1080. X   ptr->num     = rcd;
  1081. X   ptr->changed = 0;
  1082. X
  1083. X   return (mb_clast = mb_hash[n] = ptr);
  1084. X}
  1085. X
  1086. Xvoid
  1087. X_flush_cache (rel, idx)
  1088. Xrelation     *rel;
  1089. Xint                idx;
  1090. X{
  1091. X   cache *ptr, *end;
  1092. X
  1093. X   if (mb_ctop.changed)
  1094. X      {
  1095. X      GO_TOP (rel, idx);
  1096. X      writx  (rel->relcode, &(mb_ctop.num), 4);
  1097. X      }
  1098. X
  1099. X   end = &mb_cache[ncache];  /* Can't check when ptr==end */
  1100. X
  1101. X   for (ptr = mb_cache; ptr < end; ptr++)
  1102. X      if (ptr->changed)
  1103. X         {
  1104. X         GO_INDEX (rel, ptr->num, idx);
  1105. X         writx (rel->relcode, &(ptr->left),   4);
  1106. X         writx (rel->relcode, &(ptr->right),  4);
  1107. X         writx (rel->relcode, &(ptr->parent), 4);
  1108. X         writx (rel->relcode, &(ptr->parbal), 1);
  1109. X         }
  1110. X
  1111. X   _free_cache ();
  1112. X}
  1113. X
  1114. Xcache *
  1115. X_new_cache (rel, idx)
  1116. Xrelation   *rel;
  1117. Xint              idx;
  1118. X{
  1119. X   if (ncache >= MAX_CACHE) /* If this happens, expand cache for performance */
  1120. X      {
  1121. X      _flush_cache (rel, idx);
  1122. X      }
  1123. X   ncache ++;
  1124. X
  1125. X   return &mb_cache[ncache-1];
  1126. X}
  1127. X
  1128. Xvoid
  1129. X_free_cache ()
  1130. X{
  1131. X   register int  i;
  1132. X   mb_clast = NULL;  /* If we free the cache, it invalidates all cache*'s. */
  1133. X   ncache = 0;
  1134. X   for (i = 0; i < MAX_CACHE; i++)
  1135. X      mb_hash[i] = NULL;
  1136. X   mb_ctop.num = 0L;
  1137. X   mb_ctop.changed = 0;
  1138. X}
  1139. X
  1140. END_OF_FILE
  1141.   if test 2960 -ne `wc -c <'src/cache.c'`; then
  1142.     echo shar: \"'src/cache.c'\" unpacked with wrong size!
  1143.   fi
  1144.   # end of 'src/cache.c'
  1145. fi
  1146. if test -f 'src/makefile' -a "${1}" != "-c" ; then 
  1147.   echo shar: Will not clobber existing file \"'src/makefile'\"
  1148. else
  1149.   echo shar: Extracting \"'src/makefile'\" \(4498 characters\)
  1150.   sed "s/^X//" >'src/makefile' <<'END_OF_FILE'
  1151. X#
  1152. X#  METALBASE 5.0
  1153. X#
  1154. X#  Released October 1st, 1992 by Huan-Ti [ richid@owlnet.rice.edu ]
  1155. X#                                        [ t-richj@microsoft.com ]
  1156. X#
  1157. X#  Generic Makefile for 5.0 Library and Utilities
  1158. X#
  1159. X###############################################################################
  1160. X#
  1161. X# CFLAGS=
  1162. X#    -DSTRUCT_1      -- Read lower for an explanation of these, and how to
  1163. X#    -DSTRUCT_2      --    determine which is appropriate for your system.
  1164. X#    -DSTRUCT_3
  1165. X#    -DSTRUCT_4
  1166. X#    -DLONGARGS      -- To produce ansi-style prototypes ("void fn(int)")
  1167. X#    -DNOSYNC        -- Removes calls to sync() and fsync(), and in-line _asm
  1168. X#    -DNOVOIDPTR     -- To use char* instead of void* (automatic for COHERENT)
  1169. X#    -DNOENCRYPT     -- To remove encryption crap from library and utilities
  1170. X#    -DNEED_USHORT   -- If your compiler doesn't have ushort yet (COH again)
  1171. X#    -DNEED_ULONG    -- If your compiler doesn't have ulong yet (most don't)
  1172. X#    -DUNIX_LOCKS    -- To enable Unix-style locking
  1173. X#    -DSIG_TYPE=void -- void or int; needed only if you define UNIX_LOCKS
  1174. X#    -DVI_EMU        -- To add vi emulation to input.c
  1175. X#    -DMSDOS         -- MS-DOS users should define this if their CC doesn't.
  1176. X#
  1177. X# EXEDIR=            -- Directory where executables should go
  1178. X# INCDIR=            -- Directory where include files should go
  1179. X# LIBDIR=            -- Directory where libmb.a / mbase.lib should go
  1180. X#
  1181. X# LDOPTS=-f          -- To include floating point stuff for printf()
  1182. X#
  1183. X###############################################################################
  1184. X#
  1185. X# All users: Update the flags just below here FIRST (don't worry about
  1186. X#            setting -DSTRUCT_?); then just type "make".  It will compile and
  1187. X#            run struct/struct.exe, which will tell you how to determine how
  1188. X#            -DSTRUCT_? should be set for your system.  Update this in the
  1189. X#            Makefile and type "make install".  You may delete struct/
  1190. X#            struct.exe after you've used it.
  1191. X#
  1192. X# DOS users: Try adding -DMSDOS to CFLAGS=; if you get a compiler error,
  1193. X#            take it back out.  The code expects MSDOS to be defined for all
  1194. X#            DOS compilers--most already set it, but some may not.
  1195. X#
  1196. X# Unix users: set -DUNIX_LOCKS to use flock() for file locking; otherwise,
  1197. X#             MetalBase's inherent system will be used (which MAY cause
  1198. X#             problems with code which does not exit properly, but which is
  1199. X#             operationally identical).
  1200. X#
  1201. X###############################################################################
  1202. X
  1203. XEXEDIR=/usr/bin
  1204. XINCDIR=/usr/include
  1205. XLIBDIR=/usr/lib
  1206. XOBJ=.o
  1207. XEXE=
  1208. XLIB=libmb.a
  1209. XCURSES=-lcurses -lterm
  1210. XCOPY=cp
  1211. XCC=cc
  1212. XLDOPTS=-f
  1213. X
  1214. XCFLAGS=-DSTRUCT_2 -DNEED_ULONG -ML -I$(INCDIR)
  1215. X
  1216. X###############################################################################
  1217. X
  1218. XBLAST   = $(EXEDIR)/blast$(EXE)
  1219. XBUILD   = $(EXEDIR)/build$(EXE)
  1220. XFORM    = $(EXEDIR)/form$(EXE)
  1221. XMBCONV  = $(EXEDIR)/mbconv$(EXE)
  1222. XREPORT  = $(EXEDIR)/report$(EXE)
  1223. XVR      = $(EXEDIR)/vr$(EXE)
  1224. XLIBRARY = $(LIBDIR)/libmb.a
  1225. X
  1226. XHEADERS=$(INCDIR)/stdinc.h $(INCDIR)/mbase.h
  1227. XTARGETS=$(BLAST) $(BUILD) $(FORM) $(MBCONV) $(REPORT) $(SAMPLE) $(VR)
  1228. X
  1229. X###############################################################################
  1230. X
  1231. XARCHIVE = ar rv $(LIBRARY)
  1232. XRANLIB  = ranlib $(LIBRARY)
  1233. X
  1234. X###############################################################################
  1235. X
  1236. Xstruct$(EXE) : struct$(OBJ)
  1237. X    $(CC) -o $@ struct$(OBJ)
  1238. X    @./struct
  1239. X    @echo Now update the Makefile and make install
  1240. X
  1241. Xinstall : all
  1242. X    @mailscr
  1243. X
  1244. Xall : $(HEADERS) $(TARGETS)
  1245. X    
  1246. X
  1247. X$(INCDIR)/mbase.h : mbase.h
  1248. X    $(COPY) mbase.h $(INCDIR)
  1249. X
  1250. X$(INCDIR)/stdinc.h : stdinc.h
  1251. X    $(COPY) stdinc.h $(INCDIR)
  1252. X
  1253. X###############################################################################
  1254. X
  1255. X$(BLAST)   : blast$(OBJ)
  1256. X    $(CC) -o $@ blast$(OBJ)
  1257. X
  1258. X$(BUILD)   : build$(OBJ) $(LIBRARY)
  1259. X    $(CC) $(LDOPTS) -o $@ build$(OBJ) $(LIBRARY)
  1260. X
  1261. X$(FORM)    : form$(OBJ) form_wr$(OBJ) $(LIBRARY)
  1262. X    $(CC) $(LDOPTS) -o $@ form$(OBJ) form_wr$(OBJ) $(LIBRARY)
  1263. X
  1264. X$(MBCONV)  : mbconv$(OBJ) $(LIBRARY)
  1265. X    $(CC) $(LDOPTS) -o $@ mbconv$(OBJ) $(LIBRARY)
  1266. X
  1267. X$(REPORT)  : report$(OBJ) $(LIBRARY)
  1268. X    $(CC) $(LDOPTS) -o $@ report$(OBJ) $(LIBRARY)
  1269. X
  1270. X$(VR)      : vr$(OBJ) $(LIBRARY)
  1271. X    $(CC) $(LDOPTS) -o $@ vr$(OBJ) $(LIBRARY) $(CURSES)
  1272. X
  1273. X$(LIBRARY) : entry$(OBJ) lock$(OBJ) input$(OBJ) mbase$(OBJ) parse$(OBJ) timedate$(OBJ) util1$(OBJ) util2$(OBJ) cache$(OBJ) create$(OBJ)
  1274. X    $(ARCHIVE) entry$(OBJ) lock$(OBJ) input$(OBJ) mbase$(OBJ) parse$(OBJ) timedate$(OBJ) util1$(OBJ) util2$(OBJ) cache$(OBJ) create$(OBJ)
  1275. X    $(RANLIB)
  1276. X
  1277. END_OF_FILE
  1278.   if test 4498 -ne `wc -c <'src/makefile'`; then
  1279.     echo shar: \"'src/makefile'\" unpacked with wrong size!
  1280.   fi
  1281.   # end of 'src/makefile'
  1282. fi
  1283. if test -f 'src/makefile.dos' -a "${1}" != "-c" ; then 
  1284.   echo shar: Will not clobber existing file \"'src/makefile.dos'\"
  1285. else
  1286.   echo shar: Extracting \"'src/makefile.dos'\" \(3856 characters\)
  1287.   sed "s/^X//" >'src/makefile.dos' <<'END_OF_FILE'
  1288. X#
  1289. X#  METALBASE 5.0
  1290. X#
  1291. X#  Released October 1st, 1992 by Huan-Ti [ richid@owlnet.rice.edu ]
  1292. X#                                        [ t-richj@microsoft.com ]
  1293. X#
  1294. X#  Microsoft C6 makefile (for use with NMAKE) for 5.0 library and utilities
  1295. X#
  1296. X###############################################################################
  1297. X#
  1298. X# CFLAGS=
  1299. X#    -DSTRUCT_1      -- Read lower for an explanation of these, and how to
  1300. X#    -DSTRUCT_2      --    determine which is appropriate for your system.
  1301. X#    -DSTRUCT_3
  1302. X#    -DSTRUCT_4
  1303. X#    -DLONGARGS      -- To produce ansi-style prototypes ("void fn(int)")
  1304. X#    -DNOVOIDPTR     -- To use char* instead of void* (automatic for COHERENT)
  1305. X#    -DNOENCRYPT     -- To remove encryption crap from library and utilities
  1306. X#    -DNEED_USHORT   -- If your compiler doesn't have ushort yet (COH again)
  1307. X#    -DNEED_ULONG    -- If your compiler doesn't have ulong yet (most don't)
  1308. X#    -DUNIX_LOCKS    -- To enable Unix-style locking
  1309. X#    -DSIG_TYPE=void -- void or int; needed only if you define UNIX_LOCKS
  1310. X#    -DVI_EMU        -- To add vi emulation to input.c
  1311. X#    -DMSDOS         -- MS-DOS users should define this if their CC doesn't.
  1312. X#
  1313. X# LDOPTS=-f          -- To include floating point stuff for printf()
  1314. X#
  1315. X###############################################################################
  1316. X#
  1317. X# All users: Update the flags just below here FIRST (don't worry about
  1318. X#            setting -DSTRUCT_?); then just type "make".  It will compile and
  1319. X#            run struct/struct.exe, which will tell you how to determine how
  1320. X#            -DSTRUCT_? should be set for your system.  Update this in the
  1321. X#            Makefile and type "make install".  You may delete struct/
  1322. X#            struct.exe after you've used it.
  1323. X#
  1324. X# DOS users: Try adding -DMSDOS to CFLAGS=; if you get a compiler error,
  1325. X#            take it back out.  The code expects MSDOS to be defined for all
  1326. X#            DOS compilers--most already set it, but some may not.
  1327. X#
  1328. X# NOTE: This makefile is set up to use \INCLUDE, \LIB and \UTIL... change the
  1329. X#       names in here or create those directories, as you see fit.
  1330. X#
  1331. X###############################################################################
  1332. X
  1333. XCFLAGS = -nologo -c -W3 -AL -DSTRUCT_4 -DNEED_USHORT -DNEED_ULONG
  1334. X
  1335. XCC     = CL $(CFLAGS)
  1336. X
  1337. X.C.OBJ:
  1338. X    $(CC) $*.c
  1339. X
  1340. X###############################################################################
  1341. X
  1342. Xstruct.exe : struct.obj
  1343. X    @link /nologo struct.obj, struct.exe;
  1344. X    @.\struct
  1345. X    @echo Now update the Makefile and 'make install'
  1346. X
  1347. Xall : \INCLUDE\stdinc.h \INCLUDE\mbase.h blast.exe build.exe form.exe \
  1348. X      mbconv.exe report.exe vr.exe
  1349. X    
  1350. X
  1351. Xinstall : final
  1352. X    @echo MetalBase 5.0 has been installed.
  1353. X
  1354. X###############################################################################
  1355. X
  1356. X\INCLUDE\mbase.h : mbase.h
  1357. X    copy mbase.h \INCLUDE
  1358. X
  1359. X\INCLUDE\stdinc.h : stdinc.h
  1360. X    copy stdinc.h \INCLUDE
  1361. X
  1362. X\LIB\mbase.lib : mbase.lib
  1363. X    copy mbase.lib \LIB
  1364. X
  1365. Xfinal : all
  1366. X    copy *.exe \UTIL
  1367. X
  1368. X###############################################################################
  1369. X
  1370. Xblast.exe   : blast.obj
  1371. X    link/nologo blast.obj, blast.exe;
  1372. X
  1373. Xbuild.exe   : build.obj \LIB\mbase.lib
  1374. X    link/nologo build.obj, build.exe,, mbase.lib;
  1375. X
  1376. Xform.exe    : form.obj form_wr.obj \LIB\mbase.lib
  1377. X    link/nologo form.obj form_wr.obj, form.exe,, mbase.lib;
  1378. X
  1379. Xmbconv.exe  : mbconv.obj \LIB\mbase.lib
  1380. X    link/nologo mbconv.obj, mbconv.exe,, mbase.lib;
  1381. X
  1382. Xreport.exe  : report.obj \LIB\mbase.lib
  1383. X    link/nologo report.obj, report.exe,, mbase.lib;
  1384. X
  1385. Xvr.exe      : vr.obj \LIB\mbase.lib
  1386. X    link/nologo vr.obj, vr.exe,, mbase.lib lcurses.lib;
  1387. X
  1388. Xmbase.lib : entry.obj    lock.obj  input.obj mbase.obj parse.obj \
  1389. X            timedate.obj util1.obj util2.obj cache.obj cache.obj \
  1390. X        create.obj
  1391. X    lib mbase.lib -+entry.obj  -+parse.obj -+input.obj -+mbase.obj;
  1392. X    lib mbase.lib -+util1.obj  -+cache.obj -+util2.obj -+lock.obj;
  1393. X    lib mbase.lib -+create.obj -+timedate.obj;
  1394. X
  1395. END_OF_FILE
  1396.   if test 3856 -ne `wc -c <'src/makefile.dos'`; then
  1397.     echo shar: \"'src/makefile.dos'\" unpacked with wrong size!
  1398.   fi
  1399.   # end of 'src/makefile.dos'
  1400. fi
  1401. if test -f 'src/parse.c' -a "${1}" != "-c" ; then 
  1402.   echo shar: Will not clobber existing file \"'src/parse.c'\"
  1403. else
  1404.   echo shar: Extracting \"'src/parse.c'\" \(1868 characters\)
  1405.   sed "s/^X//" >'src/parse.c' <<'END_OF_FILE'
  1406. X/*
  1407. X * METALBASE 5.0
  1408. X *
  1409. X * Released October 1st, 1992 by Huan-Ti [ richid@owlnet.rice.edu ]
  1410. X *                                       [ t-richj@microsoft.com ]
  1411. X */
  1412. X
  1413. X#define PARSE_C
  1414. X#include "mbase.h"
  1415. X
  1416. Xlong  _lpos = 0L;
  1417. Xint   quoted = 0;
  1418. X
  1419. Xint
  1420. Xskip (f, s)  /* 0 means didn't skip the word, 1 means we did. */
  1421. Xint   f;
  1422. Xchar    *s;
  1423. X{
  1424. X   int   i;
  1425. X   char  a;
  1426. X
  1427. X   i = 0;
  1428. X   _lpos = lseek (f, 0L, 1);
  1429. X
  1430. X   while (s[i] != 0)
  1431. X    {
  1432. X      if (read (f, &a, 1) != 1)  return -1;
  1433. X
  1434. X      if (i != 0 || (i==0 && !iswhite(a)))
  1435. X       { if (s[i] != tolower(a))
  1436. X          { lseek (f, -1L -(long)i, 1);
  1437. X            break;
  1438. X          }
  1439. X         else
  1440. X            i++;
  1441. X       }
  1442. X    }
  1443. X
  1444. X   return (s[i] == 0);
  1445. X}
  1446. X
  1447. Xchar *
  1448. Xgetword (fle)
  1449. Xint      fle;
  1450. X{
  1451. X   int          okay = 1, go = 0;
  1452. X   static char  buffer[256];
  1453. X   char        *ptr,   a;
  1454. X
  1455. X   while (read (fle, &a, 1) == 1)
  1456. X      if (! iswhite (a))  break;
  1457. X   _lpos = lseek (fle, 0L, 1)-1L;
  1458. X
  1459. X   quoted = 0;
  1460. X
  1461. X   for (ptr = buffer; okay; okay = read (fle, &a, 1))
  1462. X    { if (go == 1 && !quoted && istoken (a))
  1463. X       { lseek (fle, -1L, 1);  /* Backup--we don't want the token yet */
  1464. X         break;
  1465. X       }
  1466. X      if (a == '\"')
  1467. X         if (quoted)  break;
  1468. X         else
  1469. X          { quoted = 1;
  1470. X            continue;
  1471. X          }
  1472. X
  1473. X      if (quoted)  *ptr = a;
  1474. X      else
  1475. X         if (iswhite(a)) break;
  1476. X         else            *ptr = tolower(a);
  1477. X
  1478. X      ptr++; go = 1;
  1479. X      if (! quoted && istoken (a))  break;
  1480. X    }
  1481. X   *ptr = 0;
  1482. X
  1483. X   return buffer;
  1484. X}
  1485. X
  1486. Xvoid
  1487. Xgoeol (fle, str)
  1488. Xint    fle;
  1489. Xchar       *str;
  1490. X{
  1491. X   char  a, *ptr;
  1492. X   char  f;
  1493. X
  1494. X   _lpos = lseek (fle, 0L, 1);
  1495. X
  1496. X   for (ptr = str; read (fle, &a, 1) == 1; )
  1497. X    { if (a == '\n' || a == '\r')  break;
  1498. X      if (ptr != NULL)  { *ptr = a; ptr++; }
  1499. X    }
  1500. X   if (ptr != NULL)  *ptr = 0;
  1501. X
  1502. X   if (read (fle, &f, 1) == 1)
  1503. X      if ((f != '\n' && f != '\r') || f == a)
  1504. X         lseek (fle, -1L, 1);
  1505. X}
  1506. X
  1507. END_OF_FILE
  1508.   if test 1868 -ne `wc -c <'src/parse.c'`; then
  1509.     echo shar: \"'src/parse.c'\" unpacked with wrong size!
  1510.   fi
  1511.   # end of 'src/parse.c'
  1512. fi
  1513. if test -f 'src/struct.c' -a "${1}" != "-c" ; then 
  1514.   echo shar: Will not clobber existing file \"'src/struct.c'\"
  1515. else
  1516.   echo shar: Extracting \"'src/struct.c'\" \(2655 characters\)
  1517.   sed "s/^X//" >'src/struct.c' <<'END_OF_FILE'
  1518. X/*
  1519. X * METALBASE 5.0
  1520. X *
  1521. X * Released October 1st, 1992 by Huan-Ti [ richid@owlnet.rice.edu ]
  1522. X *                                       [ t-richj@microsoft.com ]
  1523. X */
  1524. X
  1525. X#ifdef MSDOS
  1526. X#include <stdio.h>
  1527. X#include <stdlib.h>
  1528. X#endif
  1529. X
  1530. Xstruct              /* MP_OPTS: -o=str */
  1531. X { char   a[13];
  1532. X   long   b;
  1533. X   char   c[7];
  1534. X   double d;
  1535. X   char   e[3];
  1536. X } test;
  1537. X
  1538. X#define STDPOS(x) x-(char*)&test
  1539. X#define CHRPOS(x) (char *)&x-(char *)&test
  1540. X
  1541. X/*
  1542. X * In general:
  1543. X *
  1544. X * STRUCT_1 -- SunOS 4, DECStation/ULTRIX
  1545. X *
  1546. X * STRUCT_2 -- COHERENT, DOS/Zortec C
  1547. X *
  1548. X * STRUCT_3 -- SunOS 3, Xenix
  1549. X *
  1550. X * STRUCT_4 -- DOS/Microsoft C, Mac Programmers' Workshop
  1551. X *
  1552. X */
  1553. X
  1554. Xint match_1 = 0;  /* Incremented 1 for each that matches */
  1555. Xint match_2 = 0;  /* Incremented 1 for each that matches */
  1556. Xint match_3 = 0;  /* Incremented 1 for each that matches */
  1557. Xint match_4 = 0;  /* Incremented 1 for each that matches */
  1558. X
  1559. Xint array[][4] =
  1560. X   { {  0,    0,    0,    0 },
  1561. X     { 16,   13,   16,   14 },
  1562. X     { 20,   17,   20,   18 },
  1563. X     { 32,   24,   28,   26 },
  1564. X     { 40,   32,   36,   34 },
  1565. X     { 48,   35,   40,   38 }  };
  1566. X
  1567. Xvoid
  1568. Xprintl (s, n, l)
  1569. Xchar   *s;
  1570. Xint        n, l;
  1571. X{
  1572. X   printf ("%-6.6s : %2d -- %2d,   %2d,   %2d,   %2d\n", s, n,
  1573. X            array[l][0], array[l][1], array[l][2], array[l][3]);
  1574. X
  1575. X   if (n == array[l][0])  match_1++;
  1576. X   if (n == array[l][1])  match_2++;
  1577. X   if (n == array[l][2])  match_3++;
  1578. X   if (n == array[l][3])  match_4++;
  1579. X}
  1580. X
  1581. Xvoid
  1582. Xmain ()
  1583. X{
  1584. X   int  n;
  1585. X
  1586. X   printf ("\n");
  1587. X   printf ("        REAL  STR1  STR2  STR3  STR4\n");
  1588. X   printf ("        ----  ----  ----  ----  ----\n");
  1589. X   printl ("test.a", STDPOS(test.a), 0);
  1590. X   printl ("test.b", CHRPOS(test.b), 1);
  1591. X   printl ("test.c", STDPOS(test.c), 2);
  1592. X   printl ("test.d", CHRPOS(test.d), 3);
  1593. X   printl ("test.e", STDPOS(test.e), 4);
  1594. X   printl ("size  ", sizeof(test),   5);
  1595. X   printf ("\n");
  1596. X
  1597. X   n = 0;
  1598. X   if (match_1 == 6)  n |= 0x01;
  1599. X   if (match_2 == 6)  n |= 0x02;
  1600. X   if (match_3 == 6)  n |= 0x04;
  1601. X   if (match_4 == 6)  n |= 0x08;
  1602. X
  1603. X   if (! n || (n != 1 && n != 2 && n != 4 && n != 8))
  1604. X      {
  1605. X      printf ("Your compiler does not match any of the expected values.\n");
  1606. X      printf ("Look in your compiler manuals for any compile-time switches\n");
  1607. X      printf ("which control structure-packing; add such a switch to\n");
  1608. X      printf ("CFLAGS in the makefile, and recompile struct.\n");
  1609. X      n = 0;
  1610. X      }
  1611. X   else
  1612. X      {
  1613. X      if (n == 4)  n = 3;
  1614. X      if (n == 8)  n = 4;
  1615. X
  1616. X      printf("For your compiler, you need to #define STRUCT_%d when\n", n);
  1617. X      printf("compiling the library... do this by setting -DSTRUCT_%d in\n",n);
  1618. X      printf("the makefile.\n");
  1619. X      }
  1620. X   printf ("\n");
  1621. X
  1622. X   exit (0);
  1623. X}
  1624. X
  1625. END_OF_FILE
  1626.   if test 2655 -ne `wc -c <'src/struct.c'`; then
  1627.     echo shar: \"'src/struct.c'\" unpacked with wrong size!
  1628.   fi
  1629.   # end of 'src/struct.c'
  1630. fi
  1631. echo shar: End of archive 7 \(of 8\).
  1632. cp /dev/null ark7isdone
  1633. MISSING=""
  1634. for I in 1 2 3 4 5 6 7 8 ; do
  1635.     if test ! -f ark${I}isdone ; then
  1636.     MISSING="${MISSING} ${I}"
  1637.     fi
  1638. done
  1639. if test "${MISSING}" = "" ; then
  1640.     echo You have unpacked all 8 archives.
  1641.     rm -f ark[1-9]isdone
  1642. else
  1643.     echo You still must unpack the following archives:
  1644.     echo "        " ${MISSING}
  1645. fi
  1646. exit 0
  1647. exit 0 # Just in case...
  1648.