home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume33 / mbase / part01 < prev    next >
Encoding:
Text File  |  1992-11-23  |  54.2 KB  |  1,323 lines

  1. Newsgroups: comp.sources.misc
  2. From: richid@owlnet.rice.edu (Richard Parvin Jernigan)
  3. Subject:  v33i119:  mbase - MetalBase 5.0, Portable database engine, Part01/08
  4. Message-ID: <csm-v33i119=mbase.165613@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: 4e160b28912fbbc8564f40f7508addad
  6. Date: Mon, 23 Nov 1992 22:57:13 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: richid@owlnet.rice.edu (Richard Parvin Jernigan)
  10. Posting-number: Volume 33, Issue 119
  11. Archive-name: mbase/part01
  12. Environment: AMIGA, MS-DOS, HP-UX, XENIX, UNIX, ULTRIX, SGI, SU, Curses
  13. Supersedes: mbase: Volume 28, Issue 40-44
  14.  
  15. [ This version of mbase has been released as donateware.  Donate if you wish ]
  16. [ but you are not required to.  See the file readme.too for more specifics.  ]
  17. [ For archiving purposes, I do not consider this shareware.      -Kent+      ]
  18.  
  19. MetalBase 5.0 is a simple database engine, designed to be portable between
  20. almost any platform; Unix, MS-DOS, HP, Mac PW, NeXT, sgi, and many more, small-
  21. model and up.  This latest release has more field types, three-phase locking
  22. to ensure multi-user access without any system-based IPC, and internal caching
  23. to provide twice the speed and up for rebalancing indices.  A conversion
  24. utility for MetalBase 4.0 and 4.1a relations is provided.  Other features
  25. include run-time encryption on all platforms, creation of relations on-the-fly
  26. and a flexible report writer.
  27.  
  28. Richid
  29. -------------------------------------------------------------------------------
  30. #! /bin/sh
  31. # This is a shell archive.  Remove anything before this line, then feed it
  32. # into a shell via "sh file" or similar.  To overwrite existing files,
  33. # type "sh file -c".
  34. # Contents:  advert dox dox/mbase.dox sample src src/util1.c
  35. # Wrapped by kent@sparky on Mon Nov 23 16:33:11 1992
  36. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  37. echo If this archive is complete, you will see the following message:
  38. echo '          "shar: End of archive 1 (of 8)."'
  39. if test -f 'advert' -a "${1}" != "-c" ; then 
  40.   echo shar: Will not clobber existing file \"'advert'\"
  41. else
  42.   echo shar: Extracting \"'advert'\" \(1397 characters\)
  43.   sed "s/^X//" >'advert' <<'END_OF_FILE'
  44. XAdvertisement :)                                                  MetalBase 5.0
  45. X-------------------------------------------------------------------------------
  46. X
  47. XI'm looking for either of two things:
  48. X
  49. X   - An internet newsfeed (ANY feed, stable or not) local to central Iowa,
  50. X     around Ames/Des Moines preferably.
  51. X
  52. X   - A job located somewhere in Iowa, again, preferably near Des Moines.  I
  53. X     know, I know--"Iowa???"  That's what everyone says.  But my SO is starting
  54. X     school at Grinnell this fall, and I wanna be around for it.
  55. X
  56. X     Microsoft's being nice to me, but my internship will be over around
  57. X     January of 1993; and 'cause of regulations, they can't hire an intern
  58. X     again until X months after the last internship ended.  So I've gotta find
  59. X     somebody else instead...
  60. X
  61. X     If your company is in need of a very experienced Unix/MSDOS/VMS
  62. X     C/C++/Pascal/FORTRAN/680x0/80x86/6502 programmer, let me know and I'll
  63. X     float you a resume.  I'm unsure of my internet connection for a while, so
  64. X     contact me through:
  65. X           Richard P Jernigan IV
  66. X           PO Box 827
  67. X           Norris, TN  37828
  68. X             615-494-0445
  69. X     Okay.  So what are the odds I'll get a response to that?  :)
  70. X
  71. XPostScript:  I actually DID get a response!  Didn't take 'em up 'cause
  72. X             I'm doin that summer thang at Microsoft.  But as I said, that's
  73. X             almost over.
  74. X
  75. END_OF_FILE
  76.   if test 1397 -ne `wc -c <'advert'`; then
  77.     echo shar: \"'advert'\" unpacked with wrong size!
  78.   fi
  79.   # end of 'advert'
  80. fi
  81. if test ! -d 'dox' ; then
  82.     echo shar: Creating directory \"'dox'\"
  83.     mkdir 'dox'
  84. fi
  85. if test -f 'dox/mbase.dox' -a "${1}" != "-c" ; then 
  86.   echo shar: Will not clobber existing file \"'dox/mbase.dox'\"
  87. else
  88.   echo shar: Extracting \"'dox/mbase.dox'\" \(33032 characters\)
  89.   sed "s/^X//" >'dox/mbase.dox' <<'END_OF_FILE'
  90. X    /\
  91. X   /  \
  92. X../    \....METALBASE Version 5.0..............................................
  93. X /      \
  94. X/        \  Written From October 1990 by Huan-Ti
  95. X\        /
  96. X \      /   Revision 3.1 released December 10th 1990
  97. X  \    /    Revision 3.2 released December 10th 1991
  98. X   \  /     Revision 4.0 released Febuary 14th 1992
  99. X    \/      Revision 4.1 released April 1st 1992
  100. X            Revision 4.1a released May 10th 1992
  101. X            Revision 5.0 released October 1st 1992
  102. X
  103. X
  104. X
  105. X
  106. X
  107. X
  108. X       "And Calvin ate.  And Food Lion went out of business.  Amen."
  109. X
  110. X                                                   --1st Calvin 4:8
  111. X
  112. X
  113. XWHY_METALBASE_?________________________________________________________________
  114. X
  115. X    The Amiga 500 multi-tasks.  Wow.  It has great graphics.  Yeah.  Phenomenal
  116. Xsound.  Yippee.  It costs $500.  I bought one.
  117. X    A DBase package costs more than the computer.  So does Paradox.  And
  118. XInformix.  And almost every other database package on the market.  I didn't
  119. Xbuy one.
  120. X    But I needed a database for my system--anybody who's ever worked with a
  121. Xdatabase knows they're addictive; code that's written without a flexible
  122. Xdatabase backing it up lacks something.  And DBase wants $600 to put that
  123. Xsomething back into programs.  No thanks.
  124. X    That's why MetalBase was written... its forerunners (versions 1.0 and
  125. X2.0, not available) were designed by the same author with the Amiga line's
  126. Xneeds specifically in mind:  relatively slow floppy drives (Compared to hard
  127. Xdrives), so sparse read-head maneuvering was essential.  Relatively small
  128. Xmemory, when compared with the amounts of memory required by most C compilers
  129. X(Lattice needs roughly 300k just to run, for example), so the code had to be
  130. Xconsise, pure, and use few variables.  Expansion was always available; hard
  131. Xdrives, huge memory capacities, extra processors, ram drives -- so the system
  132. Xhad to be readily expandible and flexible enough to meet the requirements of
  133. Xboth a 512k, 1-drive machine and a 32-megabyte, 200-meg hard drive-driven
  134. Xsetup.  And they were.
  135. X    The problem was, Amigas can multi-task.  So what is the rest of the
  136. Xcomputer doing while a database runs around looking up records on one drive?
  137. XNothing.  Why not let it look up records on another drive?  Fine... that works.
  138. XWhat about on the same drive... using, say, a ram disk, so there are no real
  139. Xread-heads to worry about positioning?  That would mean each relation would
  140. Xhave to support multi-user access... a requirement around which MetalBase
  141. Xversions 3.0 and up focus.  Not only can any given terminal access many files
  142. Xat once, but on multi-terminal systems, each terminal can work simultaneously
  143. Xon any given file.  Terminals can each use as many relations as a system will
  144. Xallow, and each relation can be used by some sixty-four users at once.  The
  145. Xcode used to create MetalBase 3.X and up is completely compatible with the
  146. XUnix operating system and all of its derivatives, so its inherent multi-user
  147. Xability places it in firm working footing on the most advanced systems on the
  148. Xmarket.
  149. X    But the IBM users complained.  And the unix users complained.  And lo,
  150. Xeven the Amiga people complained--the code didn't work all the time, and
  151. Xwas generally crude.  So MetalBase 4.0 solved these troubles and more--a
  152. Xcomplete rewrite of the engine has provided even faster and more efficient
  153. Xalgorithms, which keep MetalBase indices in AVL balance at all times.  More
  154. Xconvenient functions and operations (such as build's ability to create header
  155. Xfiles for your code which reflect a schema's structure) have been added,
  156. Xalong with several utility programs for maintaining your database.
  157. X    Relations are designed by a user to match his/her exact requirements,
  158. Xindices placed as needed on single or composite fields, and records can be
  159. Xadded, retrieved, changed, and deleted as any C programmer so desires.  The
  160. Xinterface is as simple as possible, very fast in execution, and provides a wide
  161. Xrange of error types for exact specification of problems.  A user on any
  162. Xterminal can choose to lock out other users from any number of relations, so
  163. Xsweeping changes in data will not be read by others before they can take
  164. Xplace.  Automatic temporary locks are placed on a relation which is about
  165. Xto undergo a deletion or addition, strategically delaying other users' access
  166. Xto files for less than seconds, so that no data will be read until all indices
  167. Xhave been updated correctly.  This process is entirely system-driven; users
  168. Xnever need worry about it at all.  If one user is adding a record to a
  169. Xrelation, any terminal requesting a record lookup will simply wait until the
  170. Xaddition is complete before proceeding.  As records are deleted and added
  171. Xthrough normal use, the algorithms used to update indices automatically keep
  172. Xthem at top operating speeds, so any given relation's number of records can
  173. Xgrow exponentially while causing only a linear increase in look-up time.  Any
  174. Xrelation can contain over four billion records (Nearly four billion more than
  175. Xmost systems will ever need), and each record's length can be as large as its
  176. Xsystem's memory can handle.  In perspective, MetalBase is infinitely
  177. Xexpandible, while requiring very little of the system on which it operates.
  178. X
  179. X[ The actual number of records allowable is 4,294,967,296... if you were to
  180. X  add one record a second, it would take over 136 years to reach this limit ]
  181. X
  182. XRELATION_DESIGN________________________________________________________________
  183. X
  184. X        A sample relation.  Data      Field # ->  1    2   3    4       5
  185. X        is read by selecting one     Record #   _____ ___ ____ ___ ___________
  186. X        record from the others by          1   |_____|___|____|___|___________|
  187. X        various criteria, and              2   |_____|___|____|___|___________|
  188. X        returning it to the user.          3   |Smith| 12| 114| A2|Houston, TX|
  189. X        Record 3 (In this example--        4   |-----|---|----|---|-----------|
  190. X        actual MetalBase records need
  191. X        no such numbering system), if returned, would be placed in a structure
  192. X        containing Smith,12,114,A2, and Houston,TX in the appropriate elements.
  193. X
  194. X    A relation is a collection of records, each record consisting of the same
  195. Xnumber of fields--blocks of data whose individual lengths remain constant from
  196. Xrecord to record.  Each field need not have the same length as the others in
  197. Xany given record, but from record to record, a field's length will remain the
  198. Xsame. The data the fields contain is, of course, the main purpose of a
  199. Xdatabase--when thousands of records exist, a system without a database would
  200. Xneed vast amounts of time to find any given record.  Databases decrease
  201. Xdramatically record retrieval time, while requiring as little additional time
  202. Xto add new and change old records as possible.
  203. X    The key to a database is its indices--pointers arranged in such a fashion
  204. Xas to show the system where to look for the record for which it is searching.
  205. XThe more of these collections of pointers, or indices, a database has, the
  206. Xgreater the number of different fields a system can search through in order to
  207. Xfind a record meeting certain criteria for a field (Or fields... a single index
  208. Xcan be used to first sort records by one field, and also sort duplicates with
  209. Xrespect to a second field, etc.  MetalBase allows these composite indices to
  210. Xkey off of as many as 999 different fields).  However, databases require time
  211. Xto update each index every time you add, delete, or change a field which has an
  212. Xindex placed upon it.  So although retrieval criteria possibilites are expanded
  213. Xby using many indices, the amount of time required to change the existing
  214. Xrecords in a database will also increase.  For this reason, the number of
  215. Xindices a relation will have should be considered carefully--use what is
  216. Xneeded, but no more.
  217. X
  218. X    Relations are built from schema files, which decribe the relation in a
  219. Xmore human-friendly syntax.  See build.dox for a more complete description of
  220. Xthis process.
  221. X
  222. XIMPLEMENTAION__________________________________________________________________
  223. X
  224. X    A sample program implementing MetalBase follows:
  225. X
  226. X     #include <mbase.h>
  227. X     #include "equipment.h"
  228. X
  229. X     main ()
  230. X     {
  231. X        relation *rel;
  232. X
  233. X        if ((rel = mb_inc ("/usr/joe/equipment", strtokey("key"))) == RNULL) {
  234. X           printf ("Can't open database - %s.\n", mb_error);
  235. X           mb_exit (1);
  236. X        }
  237. X
  238. X        equipment_rec.price_code = 114.20;       /* Set up initial values */
  239. X        strcpy (equipment_rec.part_numb, "117"); /* to search for...      */
  240. X
  241. X        if (mb_sel (rel, 0, &equipment_rec, EQUAL, NULL) != 0) {
  242. X           printf  ("%s.\n", mb_error);
  243. X           mb_exit (1);
  244. X        }
  245. X
  246. X        /* Now that we've found a record, change it to something else... */
  247. X
  248. X        equipment_rec.num_purch = 14;
  249. X        strcpy (equipment_rec.customer,  "Su");
  250. X        strcpy (equipment_rec.part_numb, "112");
  251. X        strcpy (equipment_rec.shop_addr, "Dallas, TX");
  252. X        equipment_rec.price_code = 12;
  253. X
  254. X        mb_upd (rel, &equipment_rec);  /* Update the current selection */
  255. X
  256. X        mb_rmv (rel); // Unnecessary before mb_exit(), but good practice.
  257. X        mb_exit (0);  // Always a good idea to use mb_exit() with MetalBase.
  258. X     }
  259. X
  260. X    Manipulation of relations using MetalBase is simple... by including the
  261. XMetalBase header file in your programs and compiling using the option "-lmb"
  262. X(Or "library ..., mbase.lib;", depending on your compiler), you add extra
  263. Xcommands to C.  A summary of these follows:
  264. X
  265. X - mb_inc (filename, int) -- this command includes a relation on your desktop,
  266. X        so that it becomes accessable.  Any relation you wish to work with
  267. X        must be included using this call.  If mb_inc returns RNULL ( defined
  268. X        as (relation *)0 ), an error has occurred (The most likely one is that
  269. X        the relation cannot be found under the given directory--mb_errno will
  270. X        be set to an error number, and mb_error (global char*) will contain
  271. X        text regarding the problem).  Note that "filename" does NOT include the
  272. X        ".rel" suffix.  BUILD, in analog, does not require that you include the
  273. X        ".s" suffix on the name of the schema you are working with, but the
  274. X        schema file itself must end in ".s", as relations must end in ".rel",
  275. X        forms in ".frm" and reports in ".rpt".
  276. X
  277. X        The integer passed in is the encryption key for the relation--see the
  278. X        section on encryption for more information.  Note that MetalBase 3.0,
  279. X        as it does not support encryption, does not require this integer; all
  280. X        versions 3.1 and up do.  Sorry for the inconvenience.
  281. X
  282. X        I also STRONGLY recommend the use of the function strtokey() to
  283. X        obtain this integer from an ascii string... all utility programs
  284. X        shipped with MetalBase ask for "Encryption Key"s, and they expect
  285. X        a string to hash up with strtokey().  So if you use encryption but
  286. X        not this method of getting the integer, you're SOL when trying to
  287. X        use vr or report.  In fact, I encourage this so strongly that, in
  288. X        future releases, I may replace the integer argument with a string
  289. X        argument and do away with strtokey() entirely.
  290. X
  291. X - mb_tst (filename) -- This function goes through all the steps needed to
  292. X        make sure a given relation can be opened, but doesn't open it (thus
  293. X        it doesn't need an encryption key).  vr uses this one to make sure
  294. X        it can open a relation before asking for a key; that's pretty much
  295. X        its only use.
  296. X
  297. X - mb_sel (file, index, buffer, action, comparison_buffer) -- this command
  298. X        searches a given relation for the record you desire, described by
  299. X        "action" and "comparison_value".  "file" is a pointer to the structure
  300. X        returned by mb_inc... this structure is used in all other functions to
  301. X        indicate which relation you intend to work with.  "index" is the index
  302. X        number by which you wish to search... numbered sequentially by the
  303. X        order in which they were defined in the schema, starting with the
  304. X        number 0.  To save trouble when changing schema, it is recommended you
  305. X        use the routine idxnum() to look up an index number by name.  "buffer"
  306. X        is merely a structure (like &equipment_rec above) into which MetalBase
  307. X        can return the record, when found.  A list of valid actions follows:
  308. X           FIRST (or FRST) -- searches for the first record alphabetically.
  309. X           LAST -- similarly, seeks the last record alphabetically.
  310. X           NEXT -- searches for the next sequential record alphabetically.
  311. X           PREVIOUS (PREV) -- as NEXT, searches for the previous record.
  312. X           EQUAL (EQUL) -- seeks a record containing fields exactly those in
  313. X                "comparison_buffer".  If the index used allows duplicates and
  314. X                some exist, EQUAL returns the first of these: all duplicates
  315. X                can be found by subsequent "NEXT" searches.  Note that the
  316. X                comparison_buffer and the return buffer need not be the same
  317. X                space, although they may.
  318. X           GTEQ -- EQUAL returns a NOT_FOUND error if a record cannot be found
  319. X                to precisely match the comparison.  GTEQ acts as EQUAL in all
  320. X                respects but this;  GTEQ will find the record greater
  321. X                alphabetically, or precisely equal to (if one exists), the
  322. X                comparison.  In the event that duplicates of the record exist
  323. X                ("Duplicate" being defined logically as a record whose fields
  324. X                used by the current index are precisely equal to another such
  325. X                record's fields for the same index), GTEQ returns the first
  326. X                of these: all duplicates can be found by subsequent "NEXT"
  327. X                searches.
  328. X           GTHAN (GTHN) -- Acts as GTEQ, except GTHAN will ignore precise
  329. X                matches.  Useful if you wish to begin searching names, say,
  330. X                after the "Smith"'s.  Another way to accomplish this would be
  331. X                to use LTEQ + "Smith", followed by a NEXT...
  332. X           LTEQ -- Searches for a record less alphabetically, or equal to (if
  333. X                one exists), the comparison.  In the event that duplicates of
  334. X                the record about to be returned exist, LTEQ returns the last of
  335. X                these: all duplicates can be found by subsequent "PREVIOUS"
  336. X                searches.
  337. X           LTHN (LTHAN) -- Similar to LTEQ in all but one regard: LTHAN will
  338. X                not return a precise duplicate, instead searching to its
  339. X                left for the record before it.
  340. X           CURR (CURRENT) -- After a record is found by a search, MetalBase
  341. X                remembers the location of the record.  Searching with the
  342. X                action CURRENT re-reads this most recent record, and returns
  343. X                it in its entirety.  As with FIRST, LAST, NEXT and PREVIOUS,
  344. X                the value of "comparison_value" is irrelevant in CURRENT --
  345. X                however, CURRENT is also oblivious to index used (As no
  346. X                actual searching takes place... MetalBase merely recalls a
  347. X                known record).
  348. X        Please note that the above-described action names merely stand for
  349. X        integers, and MetalBase will not understand if you use quotes around
  350. X        the names.  These actions must also be written in upper-case.
  351. X        "comparison_buffer" is a structure identical to "buffer", but any
  352. X        data in any of the fields is used for comparison when searching for
  353. X        EQUAL, GTEQ, LTEQ, GTHAN or LTHAN.  There are three ways to use that--
  354. X        give it a new record...
  355. X            sample_str   sample_rec, target_rec;
  356. X            target_rec.num = 15;
  357. X            mb_sel (rel, idxnum("ix_num"), &sample_rec, EQUAL, &target_rec)
  358. X        or, the same one twice...
  359. X            sample_str   sample_rec;
  360. X            sample_rec.num = 15;
  361. X            mb_sel (rel, idxnum("ix_num"), &sample_rec, EQUAL, &sample_rec)
  362. X        or, what I do most, pass in NULL as the comparison (works just like
  363. X        the one above):
  364. X            sample_str   sample_rec;
  365. X            sample_rec.num = 15;
  366. X            mb_sel (rel, idxnum("ix_num"), &sample_rec, EQUAL, NULL)
  367. X        All three of these would have the same effect.
  368. X
  369. X - mb_upd (file, new_rec) -- After a record is found, it may be updated
  370. X        through mb_upd.  MetalBase simply replaces the old record's fields with
  371. X        those indicated in "new_rec".  This process usually requires more time
  372. X        than any other, as the record must be disconnected from each index in
  373. X        turn, changed, and reconnected.  Occasionally, changing a record will
  374. X        not change certain indices--when this occurs, the index is simply
  375. X        skipped.  An update, like an add, will be aborted if the changes would
  376. X        violate a no-duplicates-allowed index.
  377. X
  378. X - mb_del (file) -- After a record is found, it may be removed completely by
  379. X        use of mb_del.  Once a record is deleted thus, it CANNOT be retrieved.
  380. X        Pre-5.0 versions of MetalBase used a second argument for tracking the
  381. X        current pointer; this code was broken and I removed it.  :)  So now
  382. X        there's no second argument--again, sorry for changing things on ya.
  383. X
  384. X - mb_add (file, new_rec) -- This command adds a new record to a relation.  If
  385. X        adding the record described by "new_rec" would violate a non-duplicate
  386. X        index, the addition to the relation will be aborted and an error
  387. X        returned (See the section on Errors, below).
  388. X
  389. X - mb_lck (file) -- If, as an example, a program reads a record from a relation
  390. X        used by many terminals simulaneously, waits for a user to enter a new
  391. X        value for one of its fields, and updates the record, it could prove
  392. X        disastrous if the record was read by one terminal, then another...
  393. X        updated on one & re-written, and re-updated by the second terminal.  To
  394. X        prevent this type of scenario, mb_lck, when used, excludes other users
  395. X        from reading or writing to a relation.  Every operation they try
  396. X        (including mb_inc()) will return MB_LOCKED until the process which
  397. X        called mb_lck() calls mb_unl().
  398. X
  399. X - mb_unl (file) -- Removes a lock placed on a relation by mv_lck.
  400. X
  401. X - mb_rmv (file) -- This command removes a relation from your desktop.  If the
  402. X        file has been locked previously (via mb_lck), the lock is removed.
  403. X
  404. X - mb_die () -- This command removes all open relations from your desktop, as
  405. X        if you'd called each one in turn with mb_rmv(file).
  406. X
  407. X - mb_exit (ret_code) -- Calls mb_die(), followed by exit(ret_code).
  408. X
  409. X - mb_num (file) -- Returns the number of records in a relation.  Wheeee...
  410. X
  411. X
  412. XERRORS_________________________________________________________________________
  413. X
  414. XIn addition, see the separate documentation on troubleshooting, under the name
  415. Xtrouble.dox.  There's not much, but I tried...
  416. X
  417. XBuild / Errors :
  418. X
  419. X      Cannot open <file.s>............The schema indicated to Build cannot
  420. X                                        be found.
  421. X      File <file.s> holds no schema...The schema indicated cannot be used
  422. X        definition                      as a definition of a relation.  The
  423. X                                        most likely cause is that the file is
  424. X                                        empty.
  425. X      Field <field> declared after....All fields must be declared before any
  426. X        indices                        indices are declared.
  427. X      Field <field> declared twice....Field names must be unique.  Spaces are
  428. X                                        not allowed in field names.
  429. X      No fields declared before.......A relation must contain fields, and these
  430. X        end reached                     must be declared before any indices.
  431. X      Incorrect syntax................The definition of a field's length has
  432. X                                        been entered incorrectly.
  433. X      Field <field> undefined.........An index has been placed on a non-
  434. X                                        existant field.  Check spelling.
  435. X      No fields declared before end...The schema definition is incomplete: it
  436. X        reached                         must contain at least one field and
  437. X                                        one index.
  438. X      No indices declared before.....See the above error description.
  439. X        end reached
  440. X      Identifier <?> not recognized...The only valid words for the beginning
  441. X                                        of a line are "relation" or a relation-
  442. X                                        name (as the first line), "field",
  443. X                                        "index", and (optionally) "end".
  444. X      Cannot open relation............The file <file.rel> cannot be written...
  445. X                                        possible causes are a media error or
  446. X                                        write-protection on the file.
  447. X      Relation is busy................Relations cannot be re-built until it is
  448. X                                        not being worked with by any users.
  449. X      The file about to be created....If you build a relation where a relation
  450. X        already exists                  of the same name already exists, any
  451. X                                        data in the existing relation will be
  452. X                                        erased in favor of the new, empty
  453. X                                        relation.
  454. X
  455. XMetalBase / Errors :
  456. X
  457. XMetalBase routines either return necessary information (such as, mb_inc()
  458. Xreturns a relation-pointer, and mb_num() the number of records in a relation),
  459. Xor 0 to indicate success.  The global variable mb_errno will be set to MB_OKAY
  460. X(0) on success, and another error number (in the 1000's) on failure; the
  461. Xvariable mb_error is a character string which will always describe the most
  462. Xrecent error.  Possible errors are:
  463. X
  464. X        0..MB_OKAY............This is the generic no-problem return code.  All
  465. X                                functions except mb_inc should return 0 if
  466. X                                they have been able to function properly.
  467. X     1001..MB_NO_ROOM.........Too many relations are open at once -- mb_inc
  468. X                                cannot allocate enough space for the new
  469. X                                relation.  This error can be prevented by
  470. X                                re-defining MAX_REL, as with build's warning
  471. X                                messages, to a value greater than its default
  472. X                                of 5.  In addition, having many files open at
  473. X                                once may require that you warn <stdio.h>
  474. X                                (or config.sys, if you're using MSDOS)...
  475. X                                consult your system manuals.
  476. X     1002..MB_NO_MEMORY.......A malloc() has failed, and the task must be
  477. X                                aborted.  This is a bad, bad thing to happen.
  478. X                                How d'ya fix it?  Well, that's hard to say...
  479. X                                look around and make sure you're free()'ing any
  480. X                                memory you malloc().
  481. X     1003..MB_NO_OPEN.........The file "file.rel", where "file" is the name
  482. X                                passed to mb_inc, cannot be opened.  In all
  483. X                                probability, it does not exist.
  484. X     1004..MB_NO_READ.........The file <file.rel> cannot be read.  This error
  485. X                                is returned only from mb_inc, and is probably
  486. X                                caused by read-protection placed on the file.
  487. X     1005..MB_FORMAT..........This is the generic this-shouldn't-have-happened
  488. X                                error.  Check out trouble.dox for a quick
  489. X                                explanation of what could cause it.
  490. X     1006..MB_LOCKED..........This error is returned if another user has
  491. X                                locked the relation you're trying to access...
  492. X                                wait until they haven't, and you'll be fine.
  493. X     1007..MB_BUSY............Only a certain number of users is allowed to
  494. X                                access a relation at any given time.  The
  495. X                                limits are:
  496. X                                        MetalBase 3.1, 3.2.........120
  497. X                                        MetalBase 4.0...............63
  498. X                                        MetalBase 4.1, 4.1a, 5.0...255
  499. X     1008..MB_BAD_REL.........This essentially means that the relation* you
  500. X                                passed to a function was not returned by
  501. X                                a call to mb_inc()... it's an invalid pointer.
  502. X     1009..MB_NO_WRITE........This error is produced when the relation you've
  503. X                                opened can't be written to... perhaps you don't
  504. X                                have permission.
  505. X     1010..MB_TIMEOUT.........A user has stopped a program during a record
  506. X                                addition, deletion, or update.  These functions
  507. X                                place temporary locks on a file, which are
  508. X                                removed at the end of their respective
  509. X                                procedures.  Normally other functions will
  510. X                                simply wait for the file to be unlocked, but if
  511. X                                the wait time becomes excessive, this error is
  512. X                                returned and the function aborted.  Try the
  513. X                                function again, and if you recieve this error
  514. X                                a second time, see the section on Utilites to
  515. X                                remove the lock manually.
  516. X
  517. X                                Note that this error is no longer used, as of
  518. X                                revision 4.1.
  519. X     1011..MB_BAD_REC.........A null pointer to a record has been received.
  520. X                                So essentially, you've given NULL instead
  521. X                                of &rec.  Stupid thing to do.  :(
  522. X     1012..MB_CORRUPT.........This relation has an error on an index.  See the
  523. X                                section on Utilites to repair it.  Try to find
  524. X                                which index you were working with at the time
  525. X                                of the error, in order to speed repair.
  526. X     1013..MB_BAD_DUP.........The record that has been offered for addition/
  527. X                                update would violate an index that has been
  528. X                                declared not to allow duplicates.
  529. X     1014..MB_NO_CURR.........In order to perform a delete or an update,
  530. X                                you must have already issued mb_sel() to
  531. X                                determine which record you wish to modify.
  532. X                                This error indicates you have not done so.
  533. X     1015..MB_BAD_IDX.........A bad index number has been passed to mb_sel.
  534. X                                Valid numbers range 0 through the number of
  535. X                                indices in a relation, minus 1.
  536. X     1016..MB_NO_SUCH.........Generic code returned when the record described
  537. X                                cannot be found in the relation searched.  If
  538. X                                you feel it should have been found, check the
  539. X                                index number, action, and comparison value used
  540. X                                in the search.
  541. X     1017..MB_UNKNOWN.........A very unlikely error, receipt of this code
  542. X                                indicates you have passed a number greater than
  543. X                                12 or less than 0 to mb_sel as an action.
  544. X     1018..MB_NO_FIELDS.......You're trying to create a new relation without
  545. X                                specifying any fields for it.  Stupid you.
  546. X     1019..MB_NO_INDICES......You're trying to create a new relation without
  547. X                                specifying any inidces for it.
  548. X     1020..MB_BAD_INDEX.......An index you're trying to create has no fields.
  549. X                                Remember that the format for indices being
  550. X                                created is "nnn,nnn,nnn" --no whitespace
  551. X                                allowed without using BUILD.
  552. X     1021..MB_DISKFULL........This will only happen on mb_add() or when using
  553. X                                mbconv, the 4.0+ => 5.0 conversion utility,
  554. X                                and is returned whenever there isn't enough
  555. X                                free space on the drive to perform the
  556. X                                requested operation.
  557. X     1022..MB_BAD_SERIAL......This will only happen on mb_upd(), if you've
  558. X                                changed the serial number of the record
  559. X                                you're trying to update.  You can't.  It won't
  560. X                                let you.
  561. X     1023..MB_TMPDIR..........On some systems, MetalBase requires that you
  562. X                                have the environment variable "TMP" set to
  563. X                                an appropriate directory for temporary files;
  564. X                                for example, "TMP=/tmp; export TMP" or
  565. X                                "set TMP=C:\TMP".  If you prefer, you can
  566. X                                use the variable "TEMP" instead.
  567. X     1024..MB_TMPERR..........MetalBase cannot work with the directory you've
  568. X                                defined as per error #1023 (see TROUBLE.DOX).
  569. X
  570. XUTILITIES______________________________________________________________________
  571. X
  572. X    Five utilities have been released with this package; one, called blast,
  573. Xremoves user- and system-placed locks on a relation and sets the number of
  574. Xusers the relation thinks are using it to zero.  Impromper closing of a
  575. Xrelation (ie, not closing one) will cause the number of users to build up
  576. Xuntil it cannot be used any longer.
  577. X
  578. X    The second utility included is called vr, for View Relation.  Please see
  579. Xthe separate documentation under ../dox/vr.dox for its description and
  580. Xinstructions for its use.
  581. X
  582. X    The third utility is called report... it generates reports of a relation's
  583. Xcontents.  There is sparse documentation under ../dox/report.dox; it might
  584. Xhelp, it might not.  Play with it and it'll work--honest.  :)
  585. X
  586. X    The fourth, and newest utility, is called mbconv--it converts pre-5.0
  587. XMetalBase relations to 5.0 syntax.  Note that the process is safe but
  588. Xirreversable; and your schema files may need semicolons added just to be
  589. Xcomplete.
  590. X
  591. X    And, the final utility is called "form"--it compiles data-entry templates
  592. Xinto .h files your programs include for data-entry.  There's practically
  593. Xno documentation; just the one example under ../sample.  Good luck to you.
  594. X
  595. X    Other supporting utilities to MetalBase have not been released with this
  596. Xpackage, primarily because I have not bothered to write them yet.  See the
  597. XReadMe.Too file up one directory to see how to register yourself with me, as
  598. XI'll write any of the following upon request once you're registered (and
  599. Xmaybe before, if I have time).
  600. X
  601. X    Future utilities:
  602. X
  603. X       * Repair of bad indices and recover of unreclaimed space from
  604. X         previous deletes
  605. X
  606. X       * Utility to change a relation's schema without destroying its
  607. X         contents (oh boy...)
  608. X
  609. X       * Relation import/export from standard, Emailable text files.
  610. X
  611. X
  612. XENCRYPTION______________________________________________________________________
  613. X
  614. X    MetalBase 3.1 and up (not 3.0) automatically encrypt all files unless
  615. Xtold otherwise.  When a relation is opened (using mb_inc()), an integer
  616. Xencryption-key is passed in to MetalBase.  Any records which are added to that
  617. Xrelation are encrypted using this key, and any records which are retrieved are
  618. Xdecrypted similarly before they are returned.  In this way, any information
  619. Xwhich is physically stored is encrypted beyond recognition.  As long as this
  620. Xinteger key is the same every time the relation is opened, the encryption is
  621. Xtotally user-transparent: records are passed to mb_inc and mb_upd in normal
  622. Xtext, and are retrieved in normal text, but are stored garbled.  If the key
  623. Xchanges, however, the records retreived in the second session will be decrypted
  624. Xunder the new key, whereas they were encrypted under the former... and the
  625. Xoutput will be meaningless, for numbers and strings alike.
  626. X
  627. X    Note that the encryption is apparently working for ALL supported machines
  628. Xnow--however, this has always been the hardest part to port between machines.
  629. XIf necessary (or if you simply want to), compile mbase.c (and vr.c/sample.c/
  630. Xwhatever) with -DNOENCRYPT, and it'll be turned off.
  631. X
  632. X    For a more thorough explanation of MetalBase's encryption process, see the
  633. Xseparate documentation crypt.dox.
  634. X
  635. X--
  636. X            ___
  637. X         .-','                                        /\
  638. X        /  (_______.------------------.              /  \ Huan-Ti
  639. X       (    _______|))))))))))))))))))|              \  /
  640. X        )__(       `------------------'               \/
  641. X       `----'                                richid@owlnet.rice.edu
  642. X
  643. END_OF_FILE
  644.   if test 33032 -ne `wc -c <'dox/mbase.dox'`; then
  645.     echo shar: \"'dox/mbase.dox'\" unpacked with wrong size!
  646.   fi
  647.   # end of 'dox/mbase.dox'
  648. fi
  649. if test ! -d 'sample' ; then
  650.     echo shar: Creating directory \"'sample'\"
  651.     mkdir 'sample'
  652. fi
  653. if test ! -d 'src' ; then
  654.     echo shar: Creating directory \"'src'\"
  655.     mkdir 'src'
  656. fi
  657. if test -f 'src/util1.c' -a "${1}" != "-c" ; then 
  658.   echo shar: Will not clobber existing file \"'src/util1.c'\"
  659. else
  660.   echo shar: Extracting \"'src/util1.c'\" \(16120 characters\)
  661.   sed "s/^X//" >'src/util1.c' <<'END_OF_FILE'
  662. X/*
  663. X * METALBASE 5.0
  664. X *
  665. X * Released October 1st, 1992 by Huan-Ti [ richid@owlnet.rice.edu ]
  666. X *                                       [ t-richj@microsoft.com ]
  667. X */
  668. X
  669. X#define UTIL_C
  670. X#include "mbase.h"
  671. X#include "internal.h"
  672. X
  673. Xextern int       _started;
  674. Xextern relation *_list[MAX_REL];
  675. X
  676. X/****************************************************************************/
  677. X
  678. X#ifdef LONGARGS
  679. X   static void  _dec_user (relation *);
  680. X#else
  681. X   static void  _dec_user();
  682. X#endif
  683. X
  684. Xvoid
  685. X_seterr (err)
  686. Xmb_err   err;
  687. X{
  688. X   switch (mb_errno = err)
  689. X      {
  690. X      case MB_OKAY:     mb_error="No error";                             break;
  691. X      case MB_NO_ROOM:  mb_error="MAX_REL is #defined to be too small";  break;
  692. X      case MB_NO_MEMORY:mb_error="Not enough memory for requested task"; break;
  693. X      case MB_NO_OPEN:  mb_error="Cannot open given filename";           break;
  694. X      case MB_NO_READ:  mb_error="Cannot read given filename";           break;
  695. X      case MB_FORMAT:   mb_error="Relation is not in MB 5.0 format";     break;
  696. X      case MB_LOCKED:   mb_error="Relation is locked by another user";   break;
  697. X      case MB_BUSY:     mb_error="Relation is too busy";                 break;
  698. X      case MB_BAD_REL:  mb_error="Function passed bad relation struct";  break;
  699. X      case MB_NO_WRITE: mb_error="Cannot write given to relation";       break;
  700. X      case MB_TIMEOUT:  mb_error="Temporary lock has not been removed";  break;
  701. X      case MB_BAD_REC:  mb_error="A null rec pointer has been received"; break;
  702. X      case MB_CORRUPT:  mb_error="A corrupt index has been detected";    break;
  703. X      case MB_BAD_DUP:  mb_error="Addition would violate a nodups idx";  break;
  704. X      case MB_NO_CURR:  mb_error="Current record required for operation";break;
  705. X      case MB_BAD_IDX:  mb_error="A bad index number has been received"; break;
  706. X      case MB_NO_SUCH:  mb_error="The specified record can't be found";  break;
  707. X      case MB_UNKNOWN:  mb_error="Search command invalid";               break;
  708. X      case MB_NO_FIELDS:  mb_error="The new relation has no fields";     break;
  709. X      case MB_NO_INDICES: mb_error="The new relation has no indices";    break;
  710. X      case MB_BAD_INDEX:  mb_error="The new index has no fields";        break;
  711. X      case MB_DISKFULL: mb_error="There is not enough free space left";  break;
  712. X      case MB_BAD_SERIAL: mb_error="The record's serial number changed"; break;
  713. X      case MB_TMPDIR:   mb_error="You must define a TMP directory";      break;
  714. X      case MB_TMPERR:   mb_error="Cannot work with TMP directory";       break;
  715. X      default:          mb_error="Undefined error--rebuild and pray";    break;
  716. X      }
  717. X}
  718. X
  719. Xrelation *
  720. X_fill_info (rel, fld, idx)
  721. Xrelation   *rel;
  722. Xlong             fld, idx;
  723. X{
  724. X   register int  i, j;
  725. X   int           s, e;
  726. X   char          temp[4], buf[128];
  727. X   short         tshort;
  728. X#ifdef STRUCT_4
  729. X   int           done = 0;
  730. X#endif
  731. X
  732. X   rel->iser = rel->num_f;  /* Until we find otherwise */
  733. X
  734. X   for (i=rel->rec_len=0; i<rel->num_f; i++)
  735. X      {
  736. X      if (lseek (rel->relcode, fld, 0) != fld)
  737. X         {
  738. X         _clr_lck (rel);  free (rel);
  739. X         relerr (MB_FORMAT, RNULL);
  740. X         }
  741. X
  742. X      readx (rel->relcode,  buf,    1);  rel->type[i] = (ftype)buf[0];
  743. X      readx (rel->relcode, &tshort, 2);
  744. X      switch (rel->type[i])
  745. X         {
  746. X         case T_SHORT:
  747. X         case T_USHORT:  rel->siz[i] =  2; /* sizeof(short)  */   break;
  748. X         case T_FLOAT:   rel->siz[i] =  4; /* sizeof(float)  */   break;
  749. X         case T_DOUBLE:
  750. X         case T_MONEY:   rel->siz[i] =  8; /* sizeof(double) */   break;
  751. X         case T_TIME:
  752. X         case T_LONG:
  753. X         case T_ULONG:   rel->siz[i] =  4; /* sizeof(long)   */   break;
  754. X         case T_DATE:    rel->siz[i] =  4; /* sizeof(long)   */   break;
  755. X         case T_PHONE:   rel->siz[i] = 20; /* char[20]       */   break;
  756. X         case T_SERIAL:  rel->siz[i] =  4; /* sizeof(long)   */
  757. X                         rel->iser = i;
  758. X                        break;
  759. X         default:  rel->siz[i] = (int)tshort;              break;
  760. X         }
  761. X
  762. X#ifdef STRUCT_1
  763. X      if (rel->type[i] != T_CHAR && rel->type[i] != T_PHONE)
  764. X         {
  765. X         if (rel->siz[i] == 8)       rel->rec_len = round8(rel->rec_len);
  766. X         else if (rel->siz[i] == 4)  rel->rec_len = round4(rel->rec_len);
  767. X         else                        rel->rec_len = round2(rel->rec_len);
  768. X         }
  769. X#endif
  770. X
  771. X#ifdef STRUCT_3
  772. X      if (rel->type[i] != T_CHAR && rel->type[i] != T_PHONE)
  773. X         {
  774. X         if (rel->siz[i] == 2)  rel->rec_len = round2(rel->rec_len);
  775. X         else                   rel->rec_len = round4(rel->rec_len);
  776. X         }
  777. X#endif
  778. X
  779. X#ifdef STRUCT_4
  780. X      if (rel->type[i] != T_CHAR && rel->type[i] != T_PHONE)
  781. X         {
  782. X         done=1;
  783. X         rel->rec_len = round2(rel->rec_len);
  784. X         }
  785. X#endif
  786. X
  787. X      rel->start[i] = rel->rec_len;
  788. X      rel->rec_len += rel->siz[i];
  789. X
  790. X      readx (rel->relcode, buf, 20);
  791. X
  792. X      for (j=0; buf[j]!='|'; j++)
  793. X         ;
  794. X      fld += (long)j+4;  /* Advance to next field */
  795. X
  796. X      buf[j] = 0;  strcpy (rel->name[i], buf);
  797. X      }
  798. X
  799. X#ifdef STRUCT_1
  800. X   rel->rec_len = round8(rel->rec_len);
  801. X#endif
  802. X
  803. X#ifdef STRUCT_3
  804. X   rel->rec_len = round4(rel->rec_len);
  805. X#endif
  806. X
  807. X#ifdef STRUCT_4
  808. X   if (done)
  809. X      rel->rec_len = round2(rel->rec_len);
  810. X#endif
  811. X
  812. X   if (lseek (rel->relcode, idx, 0) != idx)
  813. X      {
  814. X      _clr_lck (rel);
  815. X      free (rel);
  816. X      relerr (MB_FORMAT, RNULL);
  817. X      }
  818. X
  819. X   for (i=0; i<rel->num_i; i++)
  820. X      { 
  821. X      readx (rel->relcode, buf,  1);  e=(int)buf[0];  /* Dups/NoDups */
  822. X      readx (rel->relcode, buf,  1);  s=(int)buf[0];  /* Num/Fields  */
  823. X      readx (rel->relcode, buf, 20);
  824. X
  825. X      for (j=0; buf[j]!=':'; j++)
  826. X         ;
  827. X
  828. X      idx += (long)j + 3L;
  829. X      lseek (rel->relcode, idx, 0); /* Advance to index' fields */
  830. X
  831. X      buf[j] = 0;
  832. X      strcpy (rel->iname[i], buf);
  833. X      rel->itype[i]=e;  sprintf (rel->idxs[i], "%03d", s);
  834. X
  835. X      for (j=0; j<s; j++)
  836. X         {
  837. X         readx (rel->relcode, &tshort, 2);
  838. X         sprintf (temp, "%03d", tshort);
  839. X         strcat (rel->idxs[i], temp);
  840. X         }
  841. X
  842. X      idx = lseek (rel->relcode, 0L, 1);    /* Get current position */
  843. X      }
  844. X
  845. X   rel->hack = idx;  /* Current position == reserved segment */
  846. X
  847. X   if (rel->ver == verCURRENT && ! rel->rdonly)
  848. X      {
  849. X      lseek (rel->lckcode, lckPOS_USERS, 0);
  850. X      readx (rel->lckcode, buf, 1);
  851. X      buf[0] = (char)((unsigned int)buf[0] +1);   /* Increment the   */
  852. X      lseek (rel->lckcode, lckPOS_USERS, 0);      /* number of users */
  853. X      writx (rel->lckcode, buf, 1);
  854. X
  855. X      _clr_lck (rel);
  856. X      }
  857. X
  858. X   relerr (MB_OKAY, rel);
  859. X}
  860. X
  861. Xvoid
  862. X_close_proc (rel)
  863. Xrelation    *rel;
  864. X{
  865. X   if (rel->ver == verCURRENT)
  866. X      {
  867. X      (void)mb_unl (rel);
  868. X      _dec_user (rel);
  869. X      }
  870. X
  871. X   close (rel->relcode);
  872. X   free  (rel);
  873. X}
  874. X
  875. Xvoid
  876. X_divine_mask (rel, key)
  877. Xrelation     *rel;
  878. Xint                key;
  879. X{
  880. X   rel->mask = (char)(
  881. X      ((key & (int)0x04) << 5) |  /* 00000100 -> 10000000 */
  882. X      ((key & (int)0x30) << 1) |  /* 00110000 -> 01100000 */
  883. X      ((key & (int)0x80) >> 3) |  /* 10000000 -> 00010000 */
  884. X      ((key & (int)0x03) << 2) |  /* 00000011 -> 00001100 */
  885. X      ((key & (int)0x40) >> 5) |  /* 01000000 -> 00000010 */
  886. X      ((key & (int)0x08) >> 3));  /* 00001000 -> 00000001 */
  887. X}
  888. X
  889. Xint
  890. X_identify (rel)
  891. Xrelation  *rel;
  892. X{
  893. X   register int  i;
  894. X   if (rel == RNULL || !_started)  return -1;
  895. X   for (i=0; i<MAX_REL; i++)
  896. X      if (_list[i] == rel)  break;
  897. X   if (i == MAX_REL)   return -1;
  898. X   if (rel->ver != verCURRENT)  return -2;
  899. X   return i;
  900. X}
  901. X
  902. Xmb_err
  903. X_format  (rel, rec, stage)
  904. Xrelation *rel;
  905. Xdataptr        rec;
  906. Xint                 stage;
  907. X{
  908. X   register int  i;
  909. X   double        tdbl;
  910. X   long          nexts, tlong;
  911. X   int           a;
  912. X   long          ac,pre,num,ext;
  913. X   char         *pch, temp[25];
  914. X
  915. X   if (! rec)  baderr (MB_BAD_REC);
  916. X
  917. X   if (stage == 2)
  918. X    { GO_NEXTS (rel);
  919. X      readx    (rel->relcode, &nexts, 4);
  920. X    }
  921. X
  922. X   for (i=a=0; i<rel->num_f; i++)
  923. X      {
  924. X      if (stage == 1)
  925. X         {
  926. X         if (rel->type[i] == T_PHONE)
  927. X            {
  928. X            pch = (char *)rec + rel->start[i];
  929. X            scn_phone (&ac,&pre,&num,&ext, pch);
  930. X            strcpy (temp, fmt_phone (ac,pre,num,ext, -1));
  931. X            strncpy (pch, temp, 20);
  932. X            }
  933. X         if (rel->type[i] == T_MONEY)
  934. X            {
  935. X            tdbl = *(double *)((char *)rec+rel->start[i]);
  936. X            tlong = (long)(tdbl * 100.0);  tdbl = (double)tlong / 100.0;
  937. X            *(double *)((char *)rec+rel->start[i]) = tdbl;
  938. X            }
  939. X         }
  940. X      else
  941. X         {
  942. X         if (rel->type[i] == T_SERIAL)
  943. X            {
  944. X            *(long *)((char *)rec+rel->start[i]) = nexts;
  945. X            rel->serial = nexts;
  946. X            _cryptf ((dataptr)((char *)rec+rel->start[i]), 4, rel->mask);
  947. X            a = 1;
  948. X            }
  949. X         }
  950. X      }
  951. X
  952. X   if (a)
  953. X      {
  954. X      GO_NEXTS (rel);  nexts++;
  955. X      writx    (rel->relcode, &nexts, 4);
  956. X      }
  957. X
  958. X   return MB_OKAY;
  959. X}
  960. X
  961. Xvoid
  962. X_crypt   (rel, rec)
  963. Xrelation *rel;
  964. Xdataptr        rec;
  965. X{
  966. X#ifndef NOENCRYPT
  967. X   register int  i;
  968. X
  969. X   if (rel->mask)
  970. X      for (i=0; i<rel->num_f; i++)
  971. X         _cryptf ((char *)rec+rel->start[i], rel->siz[i], rel->mask);
  972. X#else
  973. X   ;  /* Some compilers complain about null-functions */
  974. X#endif
  975. X}
  976. X
  977. Xvoid
  978. X_cryptf (rec, siz, mask)
  979. Xdataptr  rec;
  980. Xint           siz, mask;
  981. X{
  982. X#ifndef NOENCRYPT
  983. X   register int    i;
  984. X   register char  *c;
  985. X
  986. X   if (mask != 0)
  987. X      for (i=0,c=rec; i<siz; i++,c++)
  988. X       { *c ^= mask;
  989. X         mask  = (mask + 1) & (int)0xFF;
  990. X       }
  991. X#else
  992. X   ;  /* Some compilers complain about null-functions */
  993. X#endif
  994. X}
  995. X
  996. Xmb_err
  997. X_check_dup (rel, rec, idx, ign)
  998. Xrelation   *rel;
  999. Xdataptr          rec;
  1000. Xint                   idx;
  1001. Xlong                       ign;
  1002. X{
  1003. X   dataptr  mem;
  1004. X   long     pos;
  1005. X   int      dir;
  1006. X
  1007. X   if (rel->itype[idx] == 1)  reterr (MB_OKAY, 0);
  1008. X
  1009. X   GO_TOP (rel, idx);
  1010. X   readx (rel->relcode, &pos, 4);
  1011. X   if (pos==0L)
  1012. X      reterr (MB_OKAY, 0);
  1013. X
  1014. X   if ((mem = (dataptr)malloc (1+ rel->rec_len)) == NULL)
  1015. X      reterr (MB_NO_MEMORY, -1);
  1016. X
  1017. X   for (;;)
  1018. X      {
  1019. X      dir = _compare (rel, rec, _memrec(rel,pos,mem), idx);
  1020. X
  1021. X      if (dir == 0)
  1022. X         {
  1023. X         if (pos == ign)  break;  /* If we're about to change the rec, okay */
  1024. X         free (mem);
  1025. X
  1026. X         reterr (MB_BAD_DUP, -1);
  1027. X         }
  1028. X
  1029. X      GO_POINT (rel, pos, idx, dir);
  1030. X      readx (rel->relcode, &pos, 4);
  1031. X
  1032. X      if (pos == 0L)  break;
  1033. X      }
  1034. X   free (mem);
  1035. X
  1036. X   reterr (MB_OKAY, MB_OKAY);
  1037. X}
  1038. X
  1039. Xlong
  1040. X_append  (rel, rec)
  1041. Xrelation *rel;
  1042. Xdataptr        rec;
  1043. X{
  1044. X   long           rcd, temp;
  1045. X   register int   i;
  1046. X   char           buf[2];
  1047. X
  1048. X   lseek (rel->relcode, POS_NUMREC, 0);
  1049. X   readx (rel->relcode, &rcd, 4);  rcd++;
  1050. X   lseek (rel->relcode, POS_NUMREC, 0);
  1051. X   writx (rel->relcode, &rcd, 4);
  1052. X
  1053. X   GO_START (rel, rcd);
  1054. X
  1055. X   for (i=0,temp=0L,buf[0]=BAL_EV; i<rel->num_i; i++)
  1056. X      {
  1057. X      writx (rel->relcode, &temp, 4);
  1058. X      writx (rel->relcode, &temp, 4);
  1059. X      writx (rel->relcode, &temp, 4);
  1060. X      writx (rel->relcode, buf,   1);
  1061. X      }
  1062. X   writx (rel->relcode, rec, rel->rec_len);
  1063. X
  1064. X   return rcd;
  1065. X}
  1066. X
  1067. Xvoid
  1068. X_remove  (rel, bad)
  1069. Xrelation *rel;
  1070. Xlong           bad;
  1071. X{
  1072. X   int      i,   dir;
  1073. X   long     rep, tmp;
  1074. X   char     temp[5];
  1075. X   dataptr  buf;
  1076. X
  1077. X   lseek (rel->relcode, POS_NUMREC, 0);
  1078. X   readx (rel->relcode, &rep, 4);  rep--;
  1079. X   lseek (rel->relcode, POS_NUMREC, 0);
  1080. X   writx (rel->relcode, &rep, 4);  rep++;  /* Find replacement record */
  1081. X
  1082. X   if (rep == bad)  return;
  1083. X
  1084. X   if ((buf=(dataptr)malloc (rel->rec_len +13*rel->num_i +1)) == NULL)  return;
  1085. X
  1086. X   GO_START (rel, rep);
  1087. X   readx    (rel->relcode, buf, rel->rec_len +13*rel->num_i);
  1088. X   GO_START (rel, bad);
  1089. X   writx    (rel->relcode, buf, rel->rec_len +13*rel->num_i);
  1090. X
  1091. X   for (i = 0; i < rel->num_i; i++)
  1092. X      {
  1093. X      GO_POINT (rel, rep, i, 0);
  1094. X      readx (rel->relcode, &tmp, 4);
  1095. X      GO_BAL   (rel, rep, i);
  1096. X      readx (rel->relcode, temp, 1);  dir = (temp[0] & PARDIR);
  1097. X
  1098. X      if (tmp == 0L)
  1099. X         GO_TOP (rel, i);
  1100. X      else
  1101. X         GO_POINT (rel, tmp, i, (dir ? 1 : -1));
  1102. X      writx (rel->relcode, &bad, 4);
  1103. X
  1104. X      GO_POINT (rel, rep, i, -1);
  1105. X      readx (rel->relcode, &tmp, 4);
  1106. X      if (tmp != 0L)
  1107. X         {
  1108. X         GO_POINT (rel, tmp, i, 0);
  1109. X         writx (rel->relcode, &bad, 4);
  1110. X         }
  1111. X
  1112. X      GO_POINT (rel, rep, i, 1);
  1113. X      readx (rel->relcode, &tmp, 4);
  1114. X      if (tmp != 0L)
  1115. X         {
  1116. X         GO_POINT (rel, tmp, i, 0);
  1117. X         writx (rel->relcode, &bad, 4);
  1118. X         }
  1119. X      }
  1120. X
  1121. X   free (buf);
  1122. X}
  1123. X
  1124. Xmb_err
  1125. X_link    (rel, rcd)   /* CACHED */
  1126. Xrelation *rel;
  1127. Xlong           rcd;
  1128. X{
  1129. X   register int  i;
  1130. X
  1131. X   _free_cache ();
  1132. X
  1133. X   for (i=0; i<rel->num_i; i++)
  1134. X      {
  1135. X      _drop (rel, rcd, i, 0L);
  1136. X      if (_check (rel, rcd, 0L, i))
  1137. X         {
  1138. X         _flush_cache (rel, i);
  1139. X         return mb_errno;
  1140. X         }
  1141. X      _flush_cache (rel, i);
  1142. X      }
  1143. X   return MB_OKAY;
  1144. X}
  1145. X
  1146. Xvoid
  1147. X_drop    (rel, rcd, idx, top)  /* CACHED */
  1148. Xrelation *rel;
  1149. Xlong           rcd,      top;
  1150. Xint                 idx;
  1151. X{
  1152. X   long     pos, par;
  1153. X   int      dir;
  1154. X   char     temp[5];
  1155. X   dataptr  a, b;
  1156. X   cache   *ptr;
  1157. X
  1158. X   ptr = _read_cache (rel, top, idx);
  1159. X   if (top == 0L)
  1160. X      {
  1161. X      pos = ptr->num;
  1162. X      par = 0L;
  1163. X      }
  1164. X   else
  1165. X      {
  1166. X      par = ptr->parent;
  1167. X      pos = top;
  1168. X      }
  1169. X
  1170. X   a = (dataptr)malloc (1+ rel->rec_len);
  1171. X   b = (dataptr)malloc (1+ rel->rec_len);
  1172. X
  1173. X   for ( ; pos != 0L; )
  1174. X      {
  1175. X      ptr = _read_cache (rel, pos, idx);
  1176. X      temp[0] = ptr->parbal;
  1177. X
  1178. X      dir = _compare (rel, _memrec(rel,rcd,a), b=_memrec(rel,pos,b), idx );
  1179. X/*
  1180. X * POSSIBLE ERROR POINT -- _memrec is being used twice in one
  1181. X * function call.  If it's going to be a problem, it'll show up after
  1182. X * the second add, delete or update.... if it doesn't, this isn't
  1183. X * the cause of your trouble.
  1184. X *
  1185. X */
  1186. X
  1187. X      if (dir == 0)
  1188. X         {
  1189. X         dir = ((temp[0] & BAL) == BAL_RT || (temp[0] & BAL) == BAL_FR) ? -1:1;
  1190. X         }
  1191. X      temp[0] += dir;
  1192. X
  1193. X      _change_cache (ptr, parbal, temp[0]);
  1194. X
  1195. X      par = pos;
  1196. X      pos = _cache_field (ptr, dir);
  1197. X      }
  1198. X
  1199. X   free (a);  free (b);
  1200. X
  1201. X   if (par == 0L)
  1202. X      {
  1203. X      ptr = _read_cache (rel, 0L, idx);
  1204. X      _change_cache (ptr, num, rcd);
  1205. X      }
  1206. X   else
  1207. X      {
  1208. X      temp[0] = (char)(((dir==1) ? PARDIR:0) | BAL_EV);
  1209. X
  1210. X      ptr = _read_cache (rel, rcd, idx);
  1211. X      _change_cache (ptr, parbal, temp[0]);
  1212. X
  1213. X      ptr = _read_cache (rel, par, idx);
  1214. X      if (dir == -1)      _changeqcache (ptr, left, rcd);
  1215. X      else if (dir == 0)  _changeqcache (ptr, parent, rcd);
  1216. X      else                _changeqcache (ptr, right, rcd);
  1217. X      ptr->changed = 1;
  1218. X      }
  1219. X
  1220. X   ptr = _read_cache (rel, rcd, idx);
  1221. X   _change_cache (ptr, parent, par);
  1222. X}
  1223. X
  1224. Xmb_err
  1225. X_check   (rel, st, ed, idx)  /* CACHED */
  1226. Xrelation *rel;
  1227. Xlong           st, ed;
  1228. Xint                    idx;
  1229. X{
  1230. X   long   pos, tmp;
  1231. X   cache *ptr;
  1232. X
  1233. X   for (pos = st; pos != ed; )
  1234. X      {
  1235. X      if (pos == 0L)  break;
  1236. X
  1237. X      ptr = _read_cache (rel, pos, idx);
  1238. X      tmp = ptr->parent;
  1239. X
  1240. X      if (! BALANCED ( (ptr->parbal & BAL) ))
  1241. X         if (_balance (rel, pos, idx, (int)(ptr->parbal & BAL)))
  1242. X            return mb_errno;
  1243. X      pos = tmp;
  1244. X      }
  1245. X
  1246. X   return MB_OKAY;
  1247. X}
  1248. X
  1249. X/****************************************************************************/
  1250. X
  1251. Xint
  1252. Xcompare  (rel, ptra, ptrb, idx)  /* -1 == ptra < ptrb */
  1253. Xrelation *rel;
  1254. Xdataptr        ptra, ptrb;
  1255. Xint                        idx;
  1256. X{
  1257. X   int  i;
  1258. X   if (_identify (rel) < 0)           interr (MB_BAD_REL, -1);
  1259. X   if (idx < 0 || idx >= rel->num_i)  interr (MB_BAD_IDX, -1);
  1260. X   if (ptra == ptrb)                  interr (MB_OKAY,     0);
  1261. X
  1262. X   _crypt (rel, ptra);
  1263. X   _crypt (rel, ptrb);
  1264. X   i = _compare (rel, ptra, ptrb, idx);
  1265. X   _crypt (rel, ptra);
  1266. X   _crypt (rel, ptrb);
  1267. X   interr (MB_OKAY, i);
  1268. X}
  1269. X
  1270. Xint
  1271. Xidxnum   (rel, name)
  1272. Xrelation *rel;
  1273. Xchar          *name;
  1274. X{
  1275. X   int  i;
  1276. X
  1277. X   if (_identify (rel) < 0)  interr (MB_BAD_REL, -1);
  1278. X
  1279. X   for (i = 0; i < rel->num_i; i++)
  1280. X      if (! strcmp (name, rel->iname[i]))
  1281. X         break;
  1282. X   if (i == rel->num_i)  interr (MB_BAD_IDX, -1);
  1283. X
  1284. X   interr (MB_OKAY, i);
  1285. X}
  1286. X
  1287. Xstatic void
  1288. X_dec_user (rel)
  1289. Xrelation  *rel;
  1290. X{
  1291. X   char  buf[2];
  1292. X
  1293. X   lseek (rel->lckcode, lckPOS_USERS, 0);
  1294. X   readx (rel->lckcode, buf, 1);
  1295. X   buf[0] = (char)((unsigned int)buf[0] -1);
  1296. X   if ((uchar)buf[0] > 254)  buf[0] = 0;
  1297. X   lseek (rel->lckcode, lckPOS_USERS, 0);  writx (rel->lckcode, buf, 1);
  1298. X}
  1299. X
  1300. END_OF_FILE
  1301.   if test 16120 -ne `wc -c <'src/util1.c'`; then
  1302.     echo shar: \"'src/util1.c'\" unpacked with wrong size!
  1303.   fi
  1304.   # end of 'src/util1.c'
  1305. fi
  1306. echo shar: End of archive 1 \(of 8\).
  1307. cp /dev/null ark1isdone
  1308. MISSING=""
  1309. for I in 1 2 3 4 5 6 7 8 ; do
  1310.     if test ! -f ark${I}isdone ; then
  1311.     MISSING="${MISSING} ${I}"
  1312.     fi
  1313. done
  1314. if test "${MISSING}" = "" ; then
  1315.     echo You have unpacked all 8 archives.
  1316.     rm -f ark[1-9]isdone
  1317. else
  1318.     echo You still must unpack the following archives:
  1319.     echo "        " ${MISSING}
  1320. fi
  1321. exit 0
  1322. exit 0 # Just in case...
  1323.