home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume33 / mbase / part04 < prev    next >
Text File  |  1992-11-24  |  56KB  |  1,957 lines

  1. Newsgroups: comp.sources.misc
  2. From: richid@owlnet.rice.edu (Richard Parvin Jernigan)
  3. Subject:  v33i122:  mbase - MetalBase 5.0, Portable database engine, Part04/08
  4. Message-ID: <1992Nov23.232459.7422@sparky.imd.sterling.com>
  5. X-Md4-Signature: 87d6cd42d8825598a91064150903ec07
  6. Date: Mon, 23 Nov 1992 23:24:59 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 122
  11. Archive-name: mbase/part04
  12. Environment: AMIGA, MS-DOS, HP-UX, XENIX, UNIX, ULTRIX, SGI, SU, Curses
  13. Supersedes: mbase: Volume 28, Issue 40-44
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then feed it
  17. # into a shell via "sh file" or similar.  To overwrite existing files,
  18. # type "sh file -c".
  19. # Contents:  sample/bench.s src/form.c src/lock.c src/mbase.c
  20. #   src/mbase.h
  21. # Wrapped by kent@sparky on Mon Nov 23 16:33:13 1992
  22. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  23. echo If this archive is complete, you will see the following message:
  24. echo '          "shar: End of archive 4 (of 8)."'
  25. if test -f 'sample/bench.s' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'sample/bench.s'\"
  27. else
  28.   echo shar: Extracting \"'sample/bench.s'\" \(67 characters\)
  29.   sed "s/^X//" >'sample/bench.s' <<'END_OF_FILE'
  30. Xrelation bench
  31. X
  32. Xfield num type serial;
  33. X
  34. Xindex ix_num on num;
  35. X
  36. Xend
  37. X
  38. END_OF_FILE
  39.   if test 67 -ne `wc -c <'sample/bench.s'`; then
  40.     echo shar: \"'sample/bench.s'\" unpacked with wrong size!
  41.   fi
  42.   # end of 'sample/bench.s'
  43. fi
  44. if test -f 'src/form.c' -a "${1}" != "-c" ; then 
  45.   echo shar: Will not clobber existing file \"'src/form.c'\"
  46. else
  47.   echo shar: Extracting \"'src/form.c'\" \(12334 characters\)
  48.   sed "s/^X//" >'src/form.c' <<'END_OF_FILE'
  49. X/*
  50. X * METALBASE 5.0
  51. X *
  52. X * Released October 1st, 1992 by Huan-Ti [ richid@owlnet.rice.edu ]
  53. X *                                       [ t-richj@microsoft.com ]
  54. X *
  55. X * Special thanks go to Adrian Corston (adrian@internode.com.au) for his
  56. X * suggestions and code.  While this code is of my penning, the idea and
  57. X * style of implementation for this are direct ports from his own
  58. X * excellent work.
  59. X *
  60. X */
  61. X
  62. X#include "mbase.h"
  63. X
  64. X#ifndef MAXnREL
  65. X#define MAXnREL 20    /* Max # of relations in any given DE form */
  66. X#endif
  67. X#ifndef MAXnFLD
  68. X#define MAXnFLD 40    /* Max # of fields in any given DE form    */
  69. X#endif
  70. X
  71. X/*
  72. X * Definitions
  73. X *
  74. X */
  75. X
  76. X#define LPARQ "("
  77. X#define LBRCQ "{"   /* These are pulled out   */
  78. X#define LBKT  '['   /* so that vi's ()/[]/{}  */
  79. X#define LBRC  '{'   /* matchin works properly */
  80. X#define RBRC  '}'   /* in moving through the  */
  81. X#define RBKT  ']'   /* code.                  */
  82. X#define RBRCQ "}"
  83. X#define RPARQ ")"
  84. X
  85. X#define usage() fprintf (stderr, "form: format: %sform [formname]%s",SNGCR,SNGCR)
  86. X
  87. X#define comment() skip(form,";"); while(skip(form,"#")) goeol(form,NULL);
  88. X#define nocolon()                 while(skip(form,"#")) goeol(form,NULL);
  89. X
  90. X#define fieldopt(x) (*(options[x]))
  91. X#define fieldmode(x) (*(modes[x]))
  92. X
  93. X/*
  94. X * Prototypes
  95. X *
  96. X */
  97. X
  98. X#ifdef LONGARGS
  99. X   void  main         (int, char **);
  100. X   void  parse_args   (int, char **);
  101. X   void  check_data   (int);
  102. X   void  check_defin  (int);
  103. X   void  check_screen (int);
  104. X   void  check_fields (int);
  105. X   void  check_modes  (int);
  106. X   void  id_field     (char *, char *);
  107. X   extern void  writeit      (void);
  108. X#else
  109. X   void  main();
  110. X   void  parse_args();
  111. X   void  check_data();
  112. X   void  check_defin();
  113. X   void  check_screen();
  114. X   void  check_fields();
  115. X   void  check_modes();
  116. X   void  id_field();
  117. X   extern void  writeit();
  118. X#endif
  119. X
  120. Xtypedef relation *relptr;
  121. Xtypedef char      optlist[10][40];
  122. Xtypedef int       modelist[20];
  123. X
  124. X/*
  125. X * Global Variables
  126. X *
  127. X */
  128. X
  129. Xchar      formname[30];
  130. Xint       form;
  131. X
  132. Xftype     gen_type;
  133. Xint       gen_len;
  134. X
  135. Xchar      defins[26][50];
  136. Xchar      displ[25][140];
  137. Xint       num_l, pos_y, pos_x, num_f, num_m;
  138. Xfield     fld[MAXnFLD];
  139. Xint       lens[MAXnFLD];
  140. Xoptlist  *options[MAXnFLD];
  141. Xmodelist *modes[MAXnFLD];
  142. X
  143. Xint       num_r;
  144. Xrelptr    rel[MAXnREL];
  145. X
  146. X/*
  147. X * Main code
  148. X *
  149. X */
  150. X
  151. Xvoid
  152. Xmain  (argc, argv)
  153. Xint    argc;
  154. Xchar **argv;
  155. X{
  156. X   parse_args   (argc, argv);
  157. X
  158. X   check_data   (form);
  159. X   check_defin  (form);
  160. X   check_screen (form);
  161. X   check_fields (form);
  162. X   check_modes  (form);
  163. X
  164. X   close   (form);
  165. X   mb_die  ();  /* Close all open relations */
  166. X
  167. X   writeit ();
  168. X   exit (0);
  169. X}
  170. X
  171. X/*
  172. X * Utilities
  173. X *
  174. X */
  175. X
  176. Xvoid
  177. Xparse_args (agc, agv)
  178. Xint         agc;
  179. Xchar           **agv;
  180. X{
  181. X   while (agc > 1 && agv[1][0] == '-')
  182. X    {
  183. X      switch (agv[1][1])
  184. X       { default:   fprintf (stderr, "unrecognized option '%s'\n", agv[1]);
  185. X                    usage   ();
  186. X                    exit    (1);
  187. X                   break;
  188. X       }
  189. X
  190. X      agc--;  agv++;
  191. X    }
  192. X
  193. X   if (agc != 2)
  194. X    { usage ();
  195. X      exit  (1);
  196. X    }
  197. X
  198. X   strcpy (formname, agv[1]);
  199. X   if (strcmp (&formname[strlen(formname)-4], ".frm"))
  200. X      strcat (formname, ".frm");
  201. X   if ((form = openx (formname, O_RDONLY)) < 0)
  202. X    { fprintf (stderr, "cannot open form '%s'\n", formname);
  203. X      exit    (2);
  204. X    }
  205. X}
  206. X
  207. Xvoid
  208. Xcheck_data (form)
  209. Xint         form;
  210. X{
  211. X   char  temp[80];
  212. X
  213. X   comment();
  214. X   num_r = 0;
  215. X   if (skip(form,"data") || skip(form,"relations") || skip(form,"relation"))
  216. X    {
  217. X      while (! skip (form, ";"))
  218. X       {
  219. X         if (num_r == MAXnREL)
  220. X          { fprintf (stderr, "Too many relations--see trouble.dox%s", SNGCR);
  221. X            close   (form);
  222. X            mb_exit (4);
  223. X          }
  224. X
  225. X         strcpy (temp, getword(form));
  226. X         skip (form, ","); nocolon();
  227. X
  228. X         if (! strcmp (&temp[strlen(temp)-4], ".rel"))
  229. X            temp[strlen(temp)-4] = 0;
  230. X
  231. X         if ((rel[num_r] = mb_inc (temp, 0)) == RNULL)
  232. X          { fprintf (stderr, "Cannot open relation '%s' : %s\n",temp,mb_error);
  233. X            close   (form);
  234. X            mb_exit (4);
  235. X          }
  236. X         num_r++;
  237. X       }
  238. X      if (num_r == 0)
  239. X       { fprintf (stderr,"Data keyword implies at least one relation%s",SNGCR);
  240. X         close   (form);
  241. X         mb_exit (5);
  242. X       }
  243. X    }
  244. X}
  245. X
  246. Xvoid
  247. Xcheck_defin (form)
  248. Xint          form;
  249. X{
  250. X   int   i;
  251. X   char  temp[80], t2[80];
  252. X
  253. X   for (i = 0; i < 26; i++)  defins[i][0] = 0;
  254. X
  255. X   while (skip (form, "define"))
  256. X    {
  257. X      strcpy (temp, getword (form));
  258. X      strcpy (t2,   getword (form));
  259. X
  260. X      if (strlen (temp) != 1 || t2[0] == 0)
  261. X       { fprintf (stderr, "DEFINE (%s:%s) syntax error%s", temp, t2, SNGCR);
  262. X         close   (form);
  263. X         mb_exit (6);
  264. X       }
  265. X      if (defins[(i = tolower(temp[0])-'a')][0] != 0)
  266. X       { fprintf (stderr, "Multiple references to DEFINE %c%s",temp[0],SNGCR);
  267. X         close   (form);
  268. X         mb_exit (6);
  269. X       }
  270. X
  271. X      strcpy  (defins[i], t2);
  272. X      comment ();
  273. X    }
  274. X}
  275. X
  276. Xvoid
  277. Xcheck_screen (form)
  278. Xint           form;
  279. X{
  280. X   int   i, j, k;
  281. X   char  temp[80], c;
  282. X
  283. X   pos_y = pos_x = 0;
  284. X
  285. X   if (! skip (form, "screen"))
  286. X    { fprintf (stderr, "Screen{} segment must follow Data and Define%s",SNGCR);
  287. X      close   (form);
  288. X      mb_exit (7);
  289. X    }
  290. X   if (! skip (form, LBRCQ))
  291. X    {
  292. X      pos_y = atoi (getword (form));
  293. X
  294. X      if (! skip (form, LBRCQ))
  295. X       {
  296. X         pos_x = atoi (getword (form));
  297. X
  298. X         if (! skip (form, LBRCQ))
  299. X          { fprintf (stderr, "Left brace must follow SCREEN keyword%s",SNGCR);
  300. X            close   (form);
  301. X            mb_exit (7);
  302. X          }
  303. X       }
  304. X    }
  305. X   goeol (form, NULL);
  306. X
  307. X   num_f = 0;
  308. X
  309. X   for (num_l = 0; num_l < 24; num_l++)
  310. X    {
  311. X      goeol (form, displ[num_l]);
  312. X      if (displ[num_l][0] == RBRC)  break;
  313. X
  314. X      for (;;)
  315. X       {
  316. X         for (i = 0; displ[num_l][i] != 0; i++)
  317. X            if (displ[num_l][i] == LBKT || displ[num_l][i] == LBRC)
  318. X               break;
  319. X         if (displ[num_l][i] == 0)
  320. X            break;
  321. X
  322. X         for (j = i+1; displ[num_l][j] != 0; j++)
  323. X            if ((displ[num_l][j] == RBKT && displ[num_l][i] == LBKT) ||
  324. X                (displ[num_l][j] == RBRC && displ[num_l][i] == LBRC))
  325. X               break;
  326. X            else
  327. X               temp[j-i-1] = displ[num_l][j];
  328. X         temp[j-i-1] = 0;
  329. X         if (displ[num_l][j] == 0)
  330. X            break;
  331. X
  332. X         if (num_f == MAXnFLD)
  333. X          { fprintf (stderr, "Too many fields--see trouble.dox%s", SNGCR);
  334. X            close   (form);
  335. X            mb_exit (8);
  336. X          }
  337. X
  338. X         for (k = 0; k < j-i-1; k++)
  339. X            if (temp[k] == ' ' || temp[k] == '\t')
  340. X               break;
  341. X         temp[k] = 0;
  342. X         if (k == 1)
  343. X          {
  344. X            k = (toupper (temp[0]) - 'A');
  345. X            if (defins[k][0] == 0)
  346. X             {
  347. X               fprintf (stderr, "Field %c undefined%s", temp[0], SNGCR);
  348. X               close   (form);
  349. X               mb_exit (8);
  350. X             }
  351. X            strcpy (temp, defins[k]);
  352. X          }
  353. X
  354. X         gen_len = j-i;
  355. X         id_field (fld[num_f].name, temp);
  356. X         fld[num_f].type  = gen_type;
  357. X         fld[num_f].y     = num_l;
  358. X         fld[num_f].x     = i + ((c = displ[num_l][i]) == LBKT);
  359. X         fld[num_f].len   = j-i-1;
  360. X         lens[num_f]      = gen_len;
  361. X
  362. X         num_f++;
  363. X
  364. X         for (k = i; i <= j; i++)
  365. X            displ[num_l][i] = ' ';
  366. X         if (c == LBRC)
  367. X          {
  368. X            for (i = k; displ[num_l][i+1] != 0; i++)
  369. X               displ[num_l][i] = displ[num_l][i+1];
  370. X            displ[num_l][i] = 0;
  371. X            i = j-1;
  372. X            for ( ; displ[num_l][i+1] != 0; i++)
  373. X               displ[num_l][i] = displ[num_l][i+1];
  374. X            displ[num_l][i] = 0;
  375. X          }
  376. X       }
  377. X    }
  378. X   comment();
  379. X}
  380. X
  381. Xvoid
  382. Xcheck_fields (form)
  383. Xint           form;
  384. X{
  385. X   char   temp[80];
  386. X   int    i, j, t;
  387. X
  388. X   for (i = 0; i < MAXnFLD; i++)
  389. X      options[i] = (optlist *)0;
  390. X
  391. X   while (skip (form, "field"))
  392. X    {
  393. X      id_field (temp, getword(form));
  394. X
  395. X      for (i = 0; i < num_f; i++)
  396. X         if (! strcmp (fld[i].name, temp))  break;
  397. X      if (i == num_f)
  398. X       { fprintf (stderr, "FIELD variable '%s' unused%s", temp, SNGCR);
  399. X         close   (form);
  400. X         mb_exit (9);
  401. X       }
  402. X
  403. X      skip (form, "type");
  404. X
  405. X       /*
  406. X        * Field credit type choice ("Yy" "Nn" "?");
  407. X        * Field temp   type link to credit ("Yes" "No" "Maybe");
  408. X        * Field other  type money;
  409. X        *
  410. X        */
  411. X
  412. X      strcpy (temp, getword (form));
  413. X
  414. X      if (! strcmp (temp, "choice") || ! strcmp (temp, "link"))
  415. X       {
  416. X         t = 0;
  417. X         if (!strcmp (temp, "link"))
  418. X          {
  419. X            skip (form, "to");
  420. X            id_field (temp, getword(form));
  421. X            t = 1;
  422. X          }
  423. X
  424. X         if (! skip (form, LPARQ))
  425. X          { fprintf (stderr, "(...) must surround options in FIELD%s", SNGCR);
  426. X            close   (form);
  427. X            mb_exit (9);
  428. X          }
  429. X
  430. X         if ((options[i] = New (optlist)) == (optlist *)0)
  431. X          { fprintf (stderr, "fatal error: out of memory%s", SNGCR);
  432. X            close   (form);
  433. X            mb_exit (9);
  434. X          }
  435. X
  436. X         fieldopt(i)[0][0] = 0;  /* Link-To field name */
  437. X         if (t == 1)
  438. X            strcpy (fieldopt(i)[0], temp);  /* Link-To field name */
  439. X
  440. X         for (j = 1; !skip (form, RPARQ); j++)
  441. X          {
  442. X            if (j == 10)  break;
  443. X            strcpy (fieldopt(i)[j], getword(form));
  444. X          }
  445. X         if (j != 10)  fieldopt(i)[j][0] = 0;
  446. X
  447. X         fld[i].option = t+1;  /* t: 0 == choice, 1 == link */
  448. X
  449. X         comment();
  450. X         continue;
  451. X       }
  452. X
  453. X      if (! strcmp (temp, "char"))       fld[i].type = T_CHAR;
  454. X      if (! strcmp (temp, "string"))     fld[i].type = T_CHAR;
  455. X      if (! strcmp (temp, "character"))  fld[i].type = T_CHAR;
  456. X      if (! strcmp (temp, "short"))      fld[i].type = T_SHORT;
  457. X      if (! strcmp (temp, "ushort"))     fld[i].type = T_USHORT;
  458. X      if (! strcmp (temp, "long"))       fld[i].type = T_LONG;
  459. X      if (! strcmp (temp, "ulong"))      fld[i].type = T_ULONG;
  460. X      if (! strcmp (temp, "float"))      fld[i].type = T_FLOAT;
  461. X      if (! strcmp (temp, "double"))     fld[i].type = T_DOUBLE;
  462. X      if (! strcmp (temp, "money"))      fld[i].type = T_MONEY;
  463. X      if (! strcmp (temp, "time"))       fld[i].type = T_TIME;
  464. X      if (! strcmp (temp, "date"))       fld[i].type = T_DATE;
  465. X      if (! strcmp (temp, "serial"))     fld[i].type = T_SERIAL;
  466. X      if (! strcmp (temp, "phone"))      fld[i].type = T_PHONE;
  467. X
  468. X      comment ();
  469. X    }
  470. X}
  471. X
  472. Xvoid
  473. Xcheck_modes  (form)
  474. Xint           form;
  475. X{
  476. X   char   temp[80];
  477. X   int    i, j, k;
  478. X
  479. X   for (i = 0; i < MAXnFLD; i++)
  480. X      modes[i] = (modelist *)0;
  481. X   for (i = 0; i < num_f; i++)
  482. X      if ((modes[i] = New (modelist)) == (modelist *)0)
  483. X       { fprintf (stderr, "fatal error: out of memory%s", SNGCR);
  484. X         close   (form);
  485. X         mb_exit (9);
  486. X       }
  487. X
  488. X   num_m = 0;
  489. X
  490. X   while (skip (form, "mode"))
  491. X    {
  492. X      if ((i = atoi (getword (form))) < 1) { goeol (form, NULL);  continue; };
  493. X
  494. X      strcpy (temp, getword (form));
  495. X      k = FM_INOUT;
  496. X      if (! strcmp (temp, "in"))   k = FM_IN;
  497. X      if (! strcmp (temp, "out"))  k = FM_OUT;
  498. X
  499. X      for (j = 0; j < num_f; j++)
  500. X         fieldmode(j)[i-1] = k;
  501. X
  502. X      while (! skip (form, ";"))
  503. X       {
  504. X         id_field (temp, getword (form));
  505. X
  506. X         for (j = 0; j < num_f; j++)
  507. X            if (! strcmp (fld[j].name, temp))  break;
  508. X         if (j == num_f)
  509. X          { fprintf (stderr, "MODE variable '%s' unused%s", temp, SNGCR);
  510. X            close   (form);
  511. X            mb_exit (9);
  512. X          }
  513. X
  514. X         k = FM_INOUT;
  515. X         strcpy (temp, getword (form));
  516. X         if (! strcmp (temp, "in"))   k = FM_IN;
  517. X         if (! strcmp (temp, "out"))  k = FM_OUT;
  518. X         fieldmode(j)[i-1] = k;
  519. X
  520. X         skip (form, ",");
  521. X       }
  522. X
  523. X      num_m ++;
  524. X      nocolon ();
  525. X    }
  526. X
  527. X   if (! skip (form, "end"))
  528. X    { fprintf (stderr, "unexpected keyword: END%s", SNGCR);
  529. X      close   (form);
  530. X      mb_exit (9);
  531. X    }
  532. X}
  533. X
  534. Xvoid
  535. Xid_field (buf, str)
  536. Xchar     *buf,*str;
  537. X{
  538. X   int  i, j;
  539. X
  540. X   strcpy (buf, str);
  541. X   gen_type = T_CHAR;
  542. X
  543. X   if (strchr (str, '.') == NULL)
  544. X      for (i = 0; i < num_r; i++)
  545. X       {
  546. X         for (j = 0; j < rel[i]->num_f; j++)
  547. X            if (! strcmp (str, rel[i]->name[j]))
  548. X               {
  549. X               sprintf (buf, "%s.%s", rel[i]->relname, rel[i]->name[j]);
  550. X               gen_type = rel[i]->type[j];
  551. X               gen_len  = rel[i]->siz[j];
  552. X               break;
  553. X               }
  554. X         if (j != rel[i]->num_f)  break;
  555. X       }
  556. X}
  557. X
  558. END_OF_FILE
  559.   if test 12334 -ne `wc -c <'src/form.c'`; then
  560.     echo shar: \"'src/form.c'\" unpacked with wrong size!
  561.   fi
  562.   # end of 'src/form.c'
  563. fi
  564. if test -f 'src/lock.c' -a "${1}" != "-c" ; then 
  565.   echo shar: Will not clobber existing file \"'src/lock.c'\"
  566. else
  567.   echo shar: Extracting \"'src/lock.c'\" \(12967 characters\)
  568.   sed "s/^X//" >'src/lock.c' <<'END_OF_FILE'
  569. X/*
  570. X * METALBASE 5.0
  571. X *
  572. X * Released October 1st, 1992 by Huan-Ti [ richid@owlnet.rice.edu ]
  573. X *                                       [ t-richj@microsoft.com ]
  574. X */
  575. X
  576. X#define UTIL_C
  577. X#include "mbase.h"
  578. X#include "internal.h"
  579. X
  580. X#ifdef LONGARGS
  581. X   static mb_err     _set_hack  (relation *);
  582. X   static void       _clr_hack  (relation *);
  583. X   static void       _lck_pause (void);
  584. X   static int        _is_dead   (relation *, int);
  585. X   static void       _clrstrobe (relation *);
  586. X#else
  587. X   static mb_err     _set_hack();
  588. X   static void       _clr_hack();
  589. X   static void       _lck_pause();
  590. X   static int        _is_dead();
  591. X   static void       _clrstrobe();
  592. X#endif
  593. X
  594. X/*****************************************************************************
  595. X *
  596. X * LOCK TIMING
  597. X *
  598. X */
  599. X
  600. Xstatic void
  601. X_lck_pause ()  /* Around .1 second pause, to reduce disk I/O */
  602. X{
  603. X   int  i, j = 1;
  604. X   for (i = 0; i < 40000; i++)  /* UGLY!  CHANGE THIS! */
  605. X      j = 1-j;
  606. X}
  607. X
  608. X/*****************************************************************************
  609. X *
  610. X * EXCLUSIVE (RELATION-WIDE) LOCKS
  611. X *
  612. X */
  613. X
  614. Xmb_err           /* Fair warning:                                            */
  615. X_chk_elck (rel)  /* THIS ROUTINE CANNOT BE TRUSTED unless you have a         */
  616. Xrelation  *rel;  /* temporary lock placed on the relation before calling it! */
  617. X{
  618. X   ushort pid;
  619. X   if (rel->exc & 1)  baderr (MB_OKAY);  /* _we_ have the lock set */
  620. X
  621. X   lseek (rel->lckcode, lckPOS_ELOCK, 0);
  622. X   readx (rel->lckcode, &pid, 2);
  623. X   if (! pid)  baderr (MB_OKAY);     /* or no one has the lock */
  624. X
  625. X   baderr (MB_LOCKED);
  626. X}
  627. X
  628. Xmb_err
  629. Xmb_unl   (rel)
  630. Xrelation *rel;
  631. X{
  632. X   ushort pid;
  633. X   if (_identify (rel) < 0)  reterr (MB_BAD_REL,  -1);
  634. X   if (! (rel->exc & 1))     reterr (MB_OKAY, MB_OKAY); /* We didn't lock it */
  635. X
  636. X   if (_set_lck (rel) != MB_OKAY)  baderr (mb_errno);
  637. X
  638. X   lseek (rel->lckcode, lckPOS_ELOCK, 0);
  639. X   readx (rel->lckcode, &pid,      2);
  640. X
  641. X   if (pid == rel->pid)
  642. X      {
  643. X      pid = 0;
  644. X      lseek (rel->lckcode, lckPOS_ELOCK, 0);
  645. X      writx (rel->lckcode, &pid,      2);
  646. X      }
  647. X
  648. X   rel->exc &= 2;  /* Clear the exclusive-lock bit */
  649. X   lckerr (rel, MB_OKAY, MB_OKAY);
  650. X}
  651. X
  652. Xmb_err
  653. Xmb_lck   (rel)
  654. Xrelation *rel;
  655. X{
  656. X   ushort pid;
  657. X   if (_identify (rel) < 0)  reterr (MB_BAD_REL,  -1);
  658. X   if (rel->exc & 1)         baderr (MB_OKAY);  /* We've already locked it */
  659. X
  660. X   if (_set_lck (rel) != MB_OKAY)  baderr (mb_errno);
  661. X
  662. X   lseek (rel->lckcode, lckPOS_ELOCK, 0);
  663. X   readx (rel->lckcode, &pid, 2);
  664. X   if (pid != 0)  lckerr (rel, MB_LOCKED, -1);
  665. X
  666. X   lseek (rel->lckcode, lckPOS_ELOCK, 0);
  667. X   writx (rel->lckcode, &rel->pid, 2);
  668. X   rel->exc |= 1;  /* Set the exclusive-lock bit */
  669. X
  670. X   lckerr (rel, MB_OKAY, MB_OKAY);
  671. X}
  672. X
  673. X/*****************************************************************************
  674. X *
  675. X * HACK LOCKS (CONCURRENCY CONTROL)
  676. X *
  677. X */
  678. X
  679. Xstatic void
  680. X_clr_hack (rel)
  681. Xrelation  *rel;
  682. X{
  683. X   ushort *pid;
  684. X   char    pids[6];
  685. X
  686. X   lseek (rel->lckcode, lckPOS_HLOCK, 0);
  687. X   readx (rel->lckcode, pids, 6);
  688. X
  689. X   if (*(pid = (ushort *)&pids[0]) == rel->pid)  *pid = 0L;
  690. X   if (*(pid = (ushort *)&pids[2]) == rel->pid)  *pid = 0L;
  691. X   if (*(pid = (ushort *)&pids[4]) == rel->pid)  *pid = 0L;
  692. X
  693. X   lseek (rel->lckcode, lckPOS_HLOCK, 0);
  694. X   writx (rel->lckcode, pids, 6);
  695. X}
  696. X
  697. Xstatic mb_err
  698. X_set_hack (rel)
  699. Xrelation  *rel;
  700. X{
  701. X   ushort *pid;
  702. X   char    pids[6];
  703. X   int     fChange;
  704. X   mb_time timeStart;
  705. X
  706. X   timeStart = curtime();
  707. X
  708. X   for (;;)
  709. X      {
  710. X      if (elap_t (timeStart) > 5)
  711. X         {
  712. X         pids[0] = pids[1] = pids[2] = pids[3] = pids[4] = pids[5] = 0;
  713. X         lseek (rel->lckcode, lckPOS_HLOCK, 0);
  714. X         writx (rel->lckcode, pids, 6);
  715. X         timeStart = curtime();
  716. X         continue;
  717. X         }
  718. X
  719. X/*
  720. X * FIRST ITERATION:
  721. X *
  722. X */
  723. X
  724. X      fChange = 0;
  725. X      lseek (rel->lckcode, lckPOS_HLOCK, 0);
  726. X      readx (rel->lckcode, pids, 6);
  727. X
  728. X      if (*(pid = (ushort *)&pids[0]) == rel->pid) { *pid = 0; fChange |= 1; }
  729. X      if (*pid != 0)  fChange |= 2;
  730. X      if (*(pid = (ushort *)&pids[2]) == rel->pid) { *pid = 0; fChange |= 1; }
  731. X      if (*pid != 0)  fChange |= 2;
  732. X      if (*(pid = (ushort *)&pids[4]) == rel->pid) { *pid = 0; fChange |= 1; }
  733. X      if (*pid != 0)  fChange |= 2;
  734. X
  735. X      if (! (fChange & 2))
  736. X         {
  737. X         *pid = rel->pid;  fChange |= 1;
  738. X         }
  739. X
  740. X      if (fChange & 1)
  741. X         {
  742. X         lseek (rel->lckcode, lckPOS_HLOCK, 0);
  743. X         writx (rel->lckcode, pids, 6);
  744. X         }
  745. X
  746. X      if (fChange & 2)
  747. X         {
  748. X         continue;
  749. X         }
  750. X
  751. X/*
  752. X * SECOND ITERATION:
  753. X *
  754. X */
  755. X
  756. X      lseek (rel->lckcode, lckPOS_HLOCK, 0);
  757. X      readx (rel->lckcode, pids, 6);
  758. X
  759. X      if (*(pid = (ushort *)&pids[0]) != 0)          continue; /* NOTE ORDER */
  760. X      if (*(pid = (ushort *)&pids[4]) != rel->pid)   continue; /* NOTE ORDER */
  761. X      if (*(pid = (ushort *)&pids[2]) != 0)          continue; /* NOTE ORDER */
  762. X
  763. X      *pid = rel->pid;
  764. X
  765. X      lseek (rel->lckcode, lckPOS_HLOCK, 0);
  766. X      writx (rel->lckcode, pids, 6);
  767. X
  768. X/*
  769. X * THIRD ITERATION:
  770. X *
  771. X */
  772. X
  773. X      lseek (rel->lckcode, lckPOS_HLOCK, 0);
  774. X      readx (rel->lckcode, pids, 6);
  775. X
  776. X      if (*(pid = (ushort *)&pids[4]) != rel->pid)   continue; /* NOTE ORDER */
  777. X      if (*(pid = (ushort *)&pids[2]) != rel->pid)   continue; /* NOTE ORDER */
  778. X      if (*(pid = (ushort *)&pids[0]) != 0)          continue; /* NOTE ORDER */
  779. X
  780. X      *pid = rel->pid;
  781. X
  782. X      lseek (rel->lckcode, lckPOS_HLOCK, 0);
  783. X      writx (rel->lckcode, pids, 6);
  784. X
  785. X/*
  786. X * FINAL CHECK:
  787. X *
  788. X */
  789. X
  790. X      lseek (rel->lckcode, lckPOS_HLOCK, 0);
  791. X      readx (rel->lckcode, pids, 6);
  792. X
  793. X      if (*(pid = (ushort *)&pids[4]) != rel->pid)   continue; /* NOTE ORDER */
  794. X      if (*(pid = (ushort *)&pids[2]) != rel->pid)   continue; /* NOTE ORDER */
  795. X      if (*(pid = (ushort *)&pids[0]) != rel->pid)   continue; /* NOTE ORDER */
  796. X
  797. X      break;
  798. X      }
  799. X
  800. X   return MB_OKAY;
  801. X}
  802. X
  803. X/*****************************************************************************
  804. X *
  805. X * TEMPORARY LOCKS/ QUEUEING
  806. X *
  807. X */
  808. X
  809. Xmb_err
  810. X_set_lck (rel)
  811. Xrelation *rel;
  812. X{
  813. X   char    pids[60];
  814. X   ushort *pid, tpid;
  815. X   int     i, j;
  816. X
  817. X/*
  818. X * FLOW FOR GETTING   ( example queue:  12  13  14  00  19  22  00  00  00... )
  819. X * INTO THE QUEUE:    (           pos:   0   1   2   3   4   5   6   7   8... )
  820. X *
  821. X *     set hacklock  -- This guarantees that only one process will try to get
  822. X *                      into the queue at once--avoids race conditions.
  823. X *
  824. X * WAIT:
  825. X *     pos = the first zero in the right-hand set of contiguous zeroes
  826. X *           (position 6 in the example above)
  827. X *     look for a queuehole (position 3 above): -- if we were to just set
  828. X *        a lock when the queue has a hole in it, we'd possibly escalate
  829. X *        the length of the queue, whereas if we wait a few seconds, it'll
  830. X *        shrink itself (when process 19 wakes up and moves itself).
  831. X *     if queuehole
  832. X *        check strobe for our blocking process (pos 5, pid 22 in this case)
  833. X *        if strobe hasn't changed and elapsed time > 3 seconds
  834. X *           pos -= 1      -- move over the dead process and erase its hold on
  835. X *           write PID, 0  -- the queue--try again and we'll start here.
  836. X *        else
  837. X *           pause         -- let other processes work without extra I/O
  838. X *        goto WAIT        -- go check the queue for a hole again.
  839. X *     if the queue's full (pos == 30 -- no free slots), return MB_BUSY
  840. X *
  841. X *     clear hacklock      -- we're assured this position in the queue now
  842. X *
  843. X */
  844. X
  845. X   if (rel->exc & 2)  baderr (MB_OKAY);
  846. X
  847. X   if (_set_hack (rel))   baderr (mb_errno);
  848. X
  849. X   _clrstrobe (rel);
  850. X
  851. Xlockwait:
  852. X
  853. X   lseek (rel->lckcode, lckPOS_QUEUE, 0);
  854. X   readx (rel->lckcode, pids, 60);
  855. X
  856. X   for (i = 29; i >= 0; i--)
  857. X      if (*(pid = (ushort *)&pids[i*2]) != 0)
  858. X         break;
  859. X   i++;           /* "i" now == first available zero. */
  860. X
  861. X   if (i != 0)    /* Check for a queuehole before taking the slot. */
  862. X      {
  863. X      for (j = i-1; j >= 0; j--)
  864. X         if (*(pid = (ushort *)&pids[j*2]) == 0)
  865. X            break;
  866. X
  867. X      if (j != -1)  /* If this != -1, there's a 0 right here in the queue */
  868. X         {
  869. X         if (! _is_dead (rel, i-1))  /* If it's not dead, we expect it's     */
  870. X            {                   /* checking the guy before it, and so on--   */
  871. X            _lck_pause ();      /* and that eventually, someone will see the */
  872. X            _lck_pause ();      /* queuehole exists and will try to get it   */
  873. X            }                   /* filled.                                   */
  874. X         else
  875. X            {
  876. X            i--;       /* If it IS dead, though, move over it and try again. */
  877. X            tpid = 0;
  878. X            lseek (rel->lckcode, lckPOS_QUEUE +2*i, 0);
  879. X            writx (rel->lckcode, &tpid, 2);
  880. X            }
  881. X         goto lockwait; /* Look, GOTO was useful here, all right?  Sheesh... */
  882. X         }
  883. X      }
  884. X   if (i == 30)
  885. X      {
  886. X      _clr_hack (rel);
  887. X      baderr (MB_BUSY);
  888. X      }
  889. X
  890. X   lseek (rel->lckcode, lckPOS_QUEUE +2*i, 0);
  891. X   writx (rel->lckcode, &rel->pid, 2);
  892. X
  893. X   _clr_hack (rel);
  894. X
  895. X/*
  896. X * FLOW FOR WORKING OUR    ( example queue:   15  13  12  92  34  16  00... )
  897. X * WAY UP THE QUEUE:       (           pos:    0   1   2   3   4   5   6... )
  898. X *
  899. X * (we're in slot #4, PID==34, in the example above):
  900. X *
  901. X * WAIT:
  902. X *   If we're in slot 0, goto DONE
  903. X *   Otherwise,
  904. X *      Read pos OurPos-1 (#3)--check pid (92)
  905. X *      If PID==0,                     -- The process that WAS there has moved,
  906. X *      OR PID is dead                 -- or hasn't strobed in 3 seconds,
  907. X *         Write our PID in that slot  -- move up over it.  This way, free
  908. X *         Write zero in our last slot -- slots bubble upwards...
  909. X *         Goto WAIT
  910. X *      Strobe our position
  911. X *      Goto WAIT
  912. X *
  913. X * DONE:
  914. X *   We're finished, and a temporary lock is in place.  Make sure to strobe
  915. X *   every second during operations, or you'll lose your lock.
  916. X *
  917. X */
  918. X
  919. X   _clrstrobe (rel);
  920. X
  921. X   for (j = 0; i > 0; j++)
  922. X      {
  923. X      lseek (rel->lckcode, lckPOS_QUEUE +2*(i-1), 0);
  924. X      readx (rel->lckcode, &tpid, 2);
  925. X      if (tpid == 0 || _is_dead (rel, i-1))
  926. X         {
  927. X         i--;
  928. X         tpid = 0;
  929. X         lseek (rel->lckcode, lckPOS_QUEUE +2*i, 0);
  930. X         writx (rel->lckcode, &rel->pid, 2);
  931. X         writx (rel->lckcode, &tpid,     2);
  932. X         continue;
  933. X         }
  934. X
  935. X      _strobe (rel, i);  /* Don't let anyone think we're dead, but let */
  936. X      _lck_pause ();     /* other processes think for a second without */
  937. X      continue;          /* tons of I/O slowing everything down.       */
  938. X      }
  939. X
  940. X   rel->exc |= 2;
  941. X
  942. X   baderr (MB_OKAY);
  943. X}
  944. X
  945. Xmb_err
  946. X_clr_lck (rel)
  947. Xrelation *rel;
  948. X{
  949. X   ushort tpid = 0;
  950. X
  951. X   if (! (rel->exc & 2))  baderr (MB_OKAY);
  952. X
  953. X   rel->exc &= 1;  /* Clear the temp lock bit */
  954. X
  955. X   lseek (rel->lckcode, lckPOS_QUEUE, 0);
  956. X   writx (rel->lckcode, &tpid, 2);
  957. X
  958. X   return MB_OKAY;
  959. X}
  960. X
  961. Xstatic int
  962. X_is_dead (rel, pos)
  963. Xrelation *rel;
  964. Xint            pos;
  965. X{
  966. X   char    newstrobe[30];   /* Values just read from lockfile         */
  967. X   mb_time cur;             /* Current time (reduces curtime() calls) */
  968. X   int     i;
  969. X
  970. X   cur = curtime();
  971. X
  972. X/*
  973. X * If you have lots of frequently-dying processes, you may want to change the
  974. X * thing below to "#if 0"--that way, you can detect ALL processes dying in
  975. X * exactly three seconds instead of three sec per process--does a bit more
  976. X * I/O, though.
  977. X *
  978. X */
  979. X
  980. X#if 1
  981. X   i = pos;
  982. X
  983. X   lseek (rel->lckcode, lckPOS_STROBE +2*i, 0);    /* Get just this one */
  984. X   readx (rel->lckcode, &newstrobe[i], 1);         /* position's strobe */
  985. X#else
  986. X   lseek (rel->lckcode, lckPOS_STROBE, 0);  /* First, we read all thirty */
  987. X   readx (rel->lckcode, newstrobe, 30);     /* strobes into an array.    */
  988. X
  989. X   for (i = 0; i < 30; i++)                /* For each strobe, check if the  */
  990. X#endif
  991. X      if (rel->strobe[i] != newstrobe[i])  /* value's changed--if so, update */
  992. X         rel->times[i] = cur;              /* times[] array to current time. */
  993. X
  994. X/*
  995. X * Note: elap_t() will fail at midnight--it'll return a BIG negative number,
  996. X *       which won't pass the IsItDead test below.  So it may take 6 seconds
  997. X *       to detect if a process is dead, if successive checks occur right then.
  998. X *
  999. X * Now why 10 seconds?
  1000. X *    1-second granularity means two seconds are minimum.
  1001. X *    Previous value == current value adds two seconds for trigger (strobing
  1002. X *       process won't change it, even if it expects to--and won't try again
  1003. X *       for 1 sec, plus granularity safeguard).
  1004. X *    6-second safeguard (just to be SURE, 'cause it's a Bad Thing to be
  1005. X *       trigger happy, and a one-time timeout isn't worth fussing over).
  1006. X *
  1007. X */
  1008. X
  1009. X   return (elap_t (rel->times[pos]) > 10);  /* If not changed yet, dead. */
  1010. X}
  1011. X
  1012. Xvoid
  1013. X_strobe  (rel, pos)
  1014. Xrelation *rel;
  1015. Xint            pos;
  1016. X{
  1017. X   if (elap_t (rel->times[pos]) >= 1)
  1018. X      {
  1019. X      lseek (rel->lckcode, lckPOS_STROBE +pos, 0);
  1020. X      rel->strobe[pos] = (char)( ((int)rel->strobe[pos] +1) % 255 );
  1021. X      writx (rel->lckcode, &rel->strobe[pos], 1);
  1022. X      rel->times[pos] = curtime();
  1023. X      }
  1024. X}
  1025. X
  1026. Xstatic void
  1027. X_clrstrobe (rel)
  1028. Xrelation   *rel;
  1029. X{
  1030. X   int     i;
  1031. X   mb_time cur;
  1032. X   cur = curtime();
  1033. X   for (i = 0; i < 30; i++)
  1034. X      rel->times[i] = curtime();
  1035. X}
  1036. X
  1037. END_OF_FILE
  1038.   if test 12967 -ne `wc -c <'src/lock.c'`; then
  1039.     echo shar: \"'src/lock.c'\" unpacked with wrong size!
  1040.   fi
  1041.   # end of 'src/lock.c'
  1042. fi
  1043. if test -f 'src/mbase.c' -a "${1}" != "-c" ; then 
  1044.   echo shar: Will not clobber existing file \"'src/mbase.c'\"
  1045. else
  1046.   echo shar: Extracting \"'src/mbase.c'\" \(12702 characters\)
  1047.   sed "s/^X//" >'src/mbase.c' <<'END_OF_FILE'
  1048. X/*   ********************************************************************   *
  1049. X  ***                                                   unix compatible! ***
  1050. X *    MetalBase 5.0.....................................................    *
  1051. X *                                                                          *
  1052. X *    Simultaneous multi-user use of multiple relations!                    *
  1053. X *    Users may have many relations open at once, even the same one!        *
  1054. X *    Environmentally safe--no chloroflourocarbons to destroy the ozone!    *
  1055. X *    Loads of wonderful utilities, like data entry and report writing!     *
  1056. X *    Unlimited indicies per relation/Up to 999 fields per composite index! *
  1057. X *    Up to 4.2 billion records per relation (that's a lot, friend...)      *
  1058. X *    Bizarre intermittent bugs (NOT), just like the expensive programs!    *
  1059. X *    Portable to most any small-scale platform you can think of!           *
  1060. X *    And, unless they're weird, your kids will eat it.                     *
  1061. X *                                                               /\         *
  1062. X *    Released October 1st, 1992 by Huan-Ti                  rj /  \        *
  1063. X *                                                             /    \       *
  1064. X *   "Ye hath mushrooms for $1.99 a pound.  Ye art             \    /       *
  1065. X *    truly a Calvinist."                                       \  / tp     *
  1066. X *                       -- II Calvin 7:1                        \/         *
  1067. X *                                                                          *
  1068. X *          206/881-2624 <-----= May 26, 1996 =-----> 615/494-0445          *
  1069. X  ***       t-richj@microsoft.com / / virtual!root@owlnet.rice.edu       ***
  1070. X *   ********************************************************************   */
  1071. X
  1072. X#define MBASE_C
  1073. X#include "mbase.h"
  1074. X#include "internal.h"
  1075. X
  1076. Xint       _started = 0;
  1077. Xint       _really  = 1;
  1078. Xrelation *_list [MAX_REL];
  1079. X
  1080. X#ifndef MSDOS
  1081. X#ifdef LONGARGS
  1082. X   extern char *getenv (char _FAR_ *);
  1083. X#else
  1084. X   extern char *getenv();
  1085. X#endif
  1086. X#endif
  1087. X
  1088. Xrelation *
  1089. Xmb_open (filename, key, useold)
  1090. Xchar    *filename;
  1091. Xint                key, useold;
  1092. X{
  1093. X   relation     *rel;
  1094. X   int           i, rc, fZero = 0;
  1095. X   char          buf[256], *pch;
  1096. X   long          fld, idx, tlong;
  1097. X   short         tshort;
  1098. X
  1099. X   _really = 0;
  1100. X   if (mb_test (filename, useold) != MB_OKAY)
  1101. X    { if (_really != 0)
  1102. X       { if (_really < 0)  close (0-_really);
  1103. X         else              close (_really);
  1104. X       }
  1105. X      _really = 1;
  1106. X      relerr (mb_errno, RNULL);
  1107. X    }
  1108. X   if ((rel = New (relation)) == RNULL)
  1109. X    { if (_really != 0)
  1110. X       { if (_really < 0)  close (0-_really);
  1111. X         else              close (_really);
  1112. X       }
  1113. X      _really = 1;
  1114. X      relerr (MB_NO_MEMORY, RNULL);
  1115. X    }
  1116. X
  1117. X   rel->rdonly = (_really < 0) ? 1 : 0;
  1118. X   if (_really < 0)  _really = 0-_really;
  1119. X   rel->relcode = rc = _really;  _really = 1;
  1120. X
  1121. X   lseek (rel->relcode, 0L, 0);
  1122. X   readx (rel->relcode, buf, 1);
  1123. X
  1124. X   rel->pos = 0L;
  1125. X   rel->exc = 0;
  1126. X   rel->pid = getpid();
  1127. X   rel->ver = (int)buf[0];
  1128. X
  1129. X   for (i=0; i<MAX_REL; i++)
  1130. X      if (_list[i] == RNULL)
  1131. X         break;
  1132. X   _list[i] = rel;        /* Assign it so mb_rmv()/mb_die() can find it */
  1133. X
  1134. X   if ((pch = strrchr (filename, DIRSEP)) == NULL)
  1135. X      pch = filename;
  1136. X   else
  1137. X      pch++;
  1138. X   strcpy (buf, pch);
  1139. X
  1140. X   if ((pch = strrchr (buf, '.')) != NULL)
  1141. X      *pch = 0;
  1142. X   strcpy (rel->relname, buf);
  1143. X
  1144. X   lseek (rel->relcode, POS_FIELDPTR(rel->ver), 0);
  1145. X
  1146. X   readx (rc, &fld,        4);
  1147. X   readx (rc, &idx,        4);
  1148. X   readx (rc, &rel->recz,  4);
  1149. X   readx (rc, &tlong,      4);
  1150. X   readx (rc, &tlong,      4);
  1151. X   readx (rc, &tshort,     2);  rel->num_f = tshort;
  1152. X   readx (rc, &tshort,     2);  rel->num_i = tshort;
  1153. X
  1154. X   _divine_mask (rel, key);
  1155. X
  1156. X   if (rel->ver == verCURRENT && ! rel->rdonly)
  1157. X      {
  1158. X      if ((pch = getenv ("TMP")) != NULL ||
  1159. X          (pch = getenv ("TEMP")) != NULL)
  1160. X         {
  1161. X         strcpy (buf, pch);  /* If they define a directory, use it. */
  1162. X         }
  1163. X      else                   /* Otherwise, try to guess a default directory. */
  1164. X         {
  1165. X#ifdef UNIX
  1166. X         strcpy (buf, "/tmp");
  1167. X#endif
  1168. X         }
  1169. X      if (! buf[0])
  1170. X         {
  1171. X         close (rel->relcode);
  1172. X         free (rel);
  1173. X         relerr (MB_TMPDIR, RNULL);
  1174. X         }
  1175. X      if (buf[(i = strlen(buf))-1] != DIRSEP)
  1176. X         {
  1177. X         buf[i] = DIRSEP;
  1178. X         buf[i+1] = 0;
  1179. X         }
  1180. X      strcat (buf, rel->relname);
  1181. X      strcat (buf, ".lck");
  1182. X
  1183. X      if (access (buf, 0) == -1)
  1184. X         if ((rel->lckcode = creatx (buf)) > 0)
  1185. X            {
  1186. X            close (rel->lckcode);
  1187. X            fZero = 1;
  1188. X            rel->lckcode = -1;
  1189. X            }
  1190. X
  1191. X      rel->lckcode = openx (buf, OPENMODE);
  1192. X
  1193. X      if (rel->lckcode <= 0)
  1194. X         {
  1195. X         close (rel->relcode);
  1196. X         free (rel);
  1197. X         relerr (MB_TMPERR, RNULL);
  1198. X         }
  1199. X
  1200. X      if (fZero)
  1201. X         {
  1202. X         modex (buf, 0666);              /* The 100 bytes consist of:    */
  1203. X         for (i = 0; i < 100; i++)       /*   2 : Number of users in rel */
  1204. X            buf[i] = 0;                  /*   2 : Exclustive lock        */
  1205. X         lseek (rel->lckcode, 0L, 0);    /*   6 : 3 Hacklock positions   */
  1206. X         writx (rel->lckcode, buf, 100); /*  60 : 30 Queue positions     */
  1207. X         }                               /*  30 : 30 Strobe positions    */
  1208. X
  1209. X/*
  1210. X * Lock file has been created; keep going.
  1211. X *
  1212. X */
  1213. X
  1214. X      if (_set_lck (rel) || _chk_elck (rel))
  1215. X         {
  1216. X         if (rel->exc & 2)
  1217. X            _clr_lck (rel);
  1218. X         close (rel->relcode);
  1219. X         free (rel);
  1220. X         relerr (mb_errno, RNULL);
  1221. X         }
  1222. X      }
  1223. X
  1224. X   return _fill_info (rel, fld, idx);
  1225. X}
  1226. X
  1227. Xmb_err
  1228. Xmb_test (filename, useold)
  1229. Xchar    *filename;
  1230. Xint                useold;
  1231. X{
  1232. X   int     i, rc, rdonly = 0;
  1233. X   int     ver;
  1234. X   char    buffer[256];
  1235. X
  1236. X   if (_started == 0)
  1237. X      {
  1238. X      _started = 1;
  1239. X      for (_started=1, i=0; i<MAX_REL; i++)  /* Initialize list */
  1240. X         _list[i] = RNULL;                   /* (oh boy fun!)   */
  1241. X      }
  1242. X
  1243. X   for (i=0; i<MAX_REL; i++)
  1244. X      if (_list[i] == RNULL)  break;
  1245. X
  1246. X   if (i == MAX_REL)
  1247. X      {
  1248. X      _really = 0;
  1249. X      reterr (MB_NO_ROOM, -1);
  1250. X      }
  1251. X
  1252. X   strcpy (buffer, filename);
  1253. X   if (strcmp (&buffer[strlen(buffer)-4], ".rel"))
  1254. X      strcat (buffer, ".rel");
  1255. X
  1256. X   if ((rc = openx (buffer, OPENMODE)) == -1)
  1257. X      {
  1258. X      if ((rc = openx (buffer, READMODE)) == -1)
  1259. X         {
  1260. X         if (_really)  close (rc);
  1261. X         else         _really = 0;
  1262. X         reterr (MB_NO_OPEN, -1);                    /* Can we open it? */
  1263. X         }
  1264. X      rdonly = 1;
  1265. X      }
  1266. X   if (readx (rc, buffer, 2) != 2)
  1267. X      {
  1268. X      if (_really)  close (rc);  else _really = 0;
  1269. X      reterr (MB_NO_READ, -1);                    /* Can we read it? */
  1270. X      }
  1271. X
  1272. X   ver = (int)buffer[0];
  1273. X
  1274. X   if (useold   && (ver < 40 || ver > verCURRENT))
  1275. X      ver = 0;
  1276. X   if (! useold && ver != verCURRENT)
  1277. X      ver = 0;
  1278. X
  1279. X   if (!ver)
  1280. X      {
  1281. X      if (_really)  close (rc); else _really = 0;
  1282. X      reterr (MB_FORMAT, -1);             /* Is it a 5.0 relation? */
  1283. X      }
  1284. X
  1285. X#ifndef UNIX_LOCKS
  1286. X   if (ver == verCURRENT && !rdonly && ((int)((uchar)buffer[1]) == 255))
  1287. X      {
  1288. X      if (_really)  close (rc);  else _really = 0;
  1289. X      reterr (MB_BUSY, -1);                   /* Are there 255 users already? */
  1290. X      }
  1291. X#endif
  1292. X
  1293. X   if (_really)  close (rc);
  1294. X   else          _really = (rdonly) ? 0-rc : rc;    /* - == readonly */
  1295. X
  1296. X   reterr (MB_OKAY, MB_OKAY);
  1297. X}
  1298. X
  1299. Xmb_err
  1300. Xmb_add   (rel, rec)
  1301. Xrelation *rel;
  1302. Xdataptr        rec;
  1303. X{
  1304. X   int     i;
  1305. X   long    rcd;
  1306. X   int     err;
  1307. X
  1308. X   if (_identify (rel) < 0)            reterr (MB_BAD_REL,  -1);
  1309. X   if (rel->rdonly)                    reterr (MB_NO_WRITE, -1);
  1310. X
  1311. X   if (_format (rel, rec, 1))          reterr (mb_errno,    -1);
  1312. X   if (_set_lck (rel))                 reterr (mb_errno,    -1);
  1313. X   if (_chk_elck (rel))                lckerr (rel, MB_LOCKED, -1);
  1314. X
  1315. X   _crypt (rel, rec);
  1316. X   for (i=0; i<rel->num_i; i++)
  1317. X      if (_check_dup (rel, rec, i, 0L))  lckerr (rel, mb_errno, -1);
  1318. X
  1319. X   _format (rel, rec, 2);
  1320. X
  1321. X   if (! (rcd = _append (rel, rec)))  lckerr (rel, MB_NO_WRITE, -1);
  1322. X   if (_link (rel, rcd))              lckerr (rel, MB_CORRUPT,  -1);
  1323. X
  1324. X   rel->pos = rcd;
  1325. X
  1326. X   _crypt (rel, rec);
  1327. X   err = MB_OKAY;
  1328. X
  1329. X   lckerr (rel, MB_OKAY, MB_OKAY);
  1330. X}
  1331. X
  1332. Xmb_err
  1333. Xmb_upd   (rel, rec)
  1334. Xrelation *rel;
  1335. Xdataptr        rec;
  1336. X{
  1337. X   int     i;
  1338. X   long    rcd;
  1339. X
  1340. X   if (_identify (rel) < 0)            reterr (MB_BAD_REL, -1);
  1341. X   if ((rcd = rel->pos) == 0L)         reterr (MB_NO_CURR, -1);
  1342. X   if (_format (rel, rec, 1))          reterr (mb_errno,   -1);
  1343. X   if (rel->rdonly)                    reterr (MB_NO_WRITE,-1);
  1344. X   if (_chk_elck (rel))                reterr (MB_LOCKED,  -1);
  1345. X
  1346. X   if (rel->iser < rel->num_f)
  1347. X      {
  1348. X      if (*(long *)((char *)rec + rel->start[rel->iser]) != rel->serial)
  1349. X         reterr (MB_BAD_SERIAL, -1);
  1350. X      }
  1351. X   _crypt (rel, rec);
  1352. X   for (i=0; i<rel->num_i; i++)
  1353. X      if (_check_dup (rel, rec, i, rcd)) reterr (mb_errno, -1);
  1354. X   if (_set_lck (rel))                   reterr (mb_errno, -1);
  1355. X
  1356. X   if (_delete (rel, rel->pos) <= 0L)
  1357. X      if (mb_errno != MB_OKAY)         lckerr (rel, mb_errno, -1);
  1358. X
  1359. X   GO_RECID (rel, rel->pos);
  1360. X   writx (rel->relcode, rec, rel->rec_len);
  1361. X
  1362. X   if (_link (rel, rel->pos))          lckerr (rel, MB_CORRUPT,  -1);
  1363. X
  1364. X   _crypt (rel, rec);
  1365. X   lckerr (rel, MB_OKAY, MB_OKAY);
  1366. X}
  1367. X
  1368. Xmb_err
  1369. Xmb_del   (rel)
  1370. Xrelation *rel;
  1371. X{
  1372. X   if (_identify (rel) < 0)    reterr (MB_BAD_REL, -1);
  1373. X   if (rel->pos == 0L)         reterr (MB_NO_CURR, -1);
  1374. X   if (_chk_elck (rel))        reterr (MB_LOCKED,  -1);
  1375. X   if (rel->rdonly)            reterr (MB_NO_WRITE,-1);
  1376. X   if (_set_lck (rel))         reterr (mb_errno,   -1);
  1377. X
  1378. X   if (_delete (rel, rel->pos) <= 0L)
  1379. X      if (mb_errno != MB_OKAY)  lckerr (rel, mb_errno, -1);
  1380. X
  1381. X   _remove (rel, rel->pos);
  1382. X
  1383. X   rel->pos = 0L;
  1384. X
  1385. X   lckerr (rel, MB_OKAY, MB_OKAY);
  1386. X}
  1387. X
  1388. Xmb_err
  1389. Xmb_rmv   (rel)
  1390. Xrelation *rel;
  1391. X{
  1392. X   int  i;
  1393. X
  1394. X   if ((i = _identify (rel)) == -1)  reterr (MB_BAD_REL, -1);
  1395. X   _list[i] = RNULL;
  1396. X   _close_proc (rel);
  1397. X   baderr (MB_OKAY);
  1398. X}
  1399. X
  1400. Xvoid
  1401. Xmb_exit (x)
  1402. Xint      x;
  1403. X{
  1404. X   mb_die ();
  1405. X   exit   (x);
  1406. X}
  1407. X
  1408. Xvoid
  1409. Xmb_die ()
  1410. X{
  1411. X   int  i;
  1412. X   if (_started)
  1413. X      for (i=0; i<MAX_REL; i++)
  1414. X         if (_list[i] != RNULL)
  1415. X          { _close_proc (_list[i]);
  1416. X            _list[i] = RNULL;
  1417. X          }
  1418. X   _seterr (MB_OKAY);
  1419. X}
  1420. X
  1421. Xlong
  1422. Xmb_num   (rel)
  1423. Xrelation *rel;
  1424. X{
  1425. X   long    x;
  1426. X   if (_identify (rel) < 0)  longerr (MB_BAD_REL, -1);
  1427. X   if (lseek (rel->relcode, POS_NUMREC, 0) != POS_NUMREC)
  1428. X      longerr (MB_FORMAT, -1);
  1429. X   readx (rel->relcode, &x, 4);
  1430. X   longerr (MB_OKAY, x);
  1431. X}
  1432. X
  1433. Xint
  1434. Xstrtokey (str)
  1435. Xchar     *str;
  1436. X{
  1437. X   char *a;
  1438. X   int   x;
  1439. X   for (x=0, a=str; a && *a; a++)
  1440. X      x = (x + (int)*a) % 240 + 15;
  1441. X   return x;
  1442. X}
  1443. X
  1444. Xvoid
  1445. Xstrzcpy (new, old, num)
  1446. Xchar    *new,*old;
  1447. Xint                num;
  1448. X{
  1449. X   int  i;
  1450. X   char         *a,*b;
  1451. X
  1452. X   if (!new || !old)  return;
  1453. X   for (a=new,b=old,i=0; i<num && *b; a++,b++,i++)
  1454. X      *a = *b;
  1455. X   *a = 0;
  1456. X}
  1457. X
  1458. Xmb_err
  1459. Xmb_sel   (rel, idx, buf, act, comp)
  1460. Xrelation *rel;
  1461. Xint            idx;
  1462. Xmb_action                act;
  1463. Xdataptr             buf,      comp;
  1464. X{
  1465. X   dataptr rec;
  1466. X   long    off, top;
  1467. X
  1468. X   _free_cache ();
  1469. X
  1470. X   if (_identify (rel) < 0)                            baderr (MB_BAD_REL);
  1471. X   if (act != CURR && (idx < 0 || idx >= rel->num_i))  baderr (MB_BAD_IDX);
  1472. X   if (_chk_elck (rel))                                baderr (MB_LOCKED);
  1473. X   if (_set_lck (rel))                                 baderr (mb_errno);
  1474. X
  1475. X   rec = (comp == NULL) ? buf : comp;
  1476. X   if (rec != NULL)  _crypt (rel, rec);
  1477. X
  1478. X   if (rel->pos == 0L)
  1479. X      {
  1480. X      if (act == NEXT)  act = FRST;
  1481. X      if (act == PREV)  act = LAST;
  1482. X      }
  1483. X
  1484. X   switch (act)
  1485. X      {
  1486. X      case FRST:
  1487. X      case LAST:  off = _find_ends (rel, idx, (act == FRST) ? -1 : 1);
  1488. X                 break;
  1489. X      case CURR:  off = rel->pos;
  1490. X                 break;
  1491. X      case NEXT:
  1492. X      case PREV:  off = _find_seq (rel, 0L, rel->pos, idx, (act == NEXT)?1:-1);
  1493. X                 break;
  1494. X      case GTEQ:
  1495. X      case GTHN:
  1496. X      case LTEQ:
  1497. X      case LTHN:
  1498. X      case EQUL:  GO_TOP (rel, idx);  readx (rel->relcode, &top, 4);
  1499. X                  off = _search (rel, top, idx, act, rec);
  1500. X                 break;
  1501. X      default  :  baderr (MB_UNKNOWN);
  1502. X                 break;
  1503. X      }
  1504. X
  1505. X   if (off == 0L)
  1506. X      {
  1507. X      _seterr (MB_NO_SUCH);
  1508. X      }
  1509. X   else
  1510. X      {
  1511. X      _seterr (MB_OKAY);
  1512. X      rel->pos = off;
  1513. X      }
  1514. X
  1515. X   _crypt  (rel, rec);           /* Reverse-encrypt the comparison buffer */
  1516. X   _memrec (rel, rel->pos, buf); /* Read in the output buffer, encrypted  */
  1517. X   _crypt  (rel, buf);           /* Decrypt the output buffer             */
  1518. X
  1519. X   if (rel->pos && rel->iser < rel->num_f)
  1520. X      {
  1521. X      rel->serial = *(long *)((char *)buf + rel->start[rel->iser]);
  1522. X      }
  1523. X
  1524. X   _clr_lck (rel);
  1525. X
  1526. X   return mb_errno;
  1527. X}
  1528. X
  1529. END_OF_FILE
  1530.   if test 12702 -ne `wc -c <'src/mbase.c'`; then
  1531.     echo shar: \"'src/mbase.c'\" unpacked with wrong size!
  1532.   fi
  1533.   # end of 'src/mbase.c'
  1534. fi
  1535. if test -f 'src/mbase.h' -a "${1}" != "-c" ; then 
  1536.   echo shar: Will not clobber existing file \"'src/mbase.h'\"
  1537. else
  1538.   echo shar: Extracting \"'src/mbase.h'\" \(12825 characters\)
  1539.   sed "s/^X//" >'src/mbase.h' <<'END_OF_FILE'
  1540. X/*
  1541. X * METALBASE 5.0
  1542. X *
  1543. X * Released October 1st, 1992 by Huan-Ti [ richid@owlnet.rice.edu ]
  1544. X *                                       [ t-richj@microsoft.com ]
  1545. X */
  1546. X
  1547. X#ifndef MBASE_H
  1548. X#define MBASE_H
  1549. X
  1550. X#include <stdinc.h>
  1551. X#include <curses.h>
  1552. X
  1553. X#define verCURRENT 50  /* Signature for 5.0 relations */
  1554. X
  1555. Xextern WINDOW *win;
  1556. X
  1557. X#ifdef MSDOS       /*                                                     */
  1558. X#ifdef KEY_RIGHT   /* If this is defined in curses.h, the curses package  */
  1559. X#define USE_CURKEY /* supports keypad mode, and can trap our keys itself. */
  1560. X#endif             /* Otherwise, we have to use our own esc-sequences. /  */
  1561. X#endif             /*                                                     */
  1562. X
  1563. X/*
  1564. X * USER-DEFINABLE DEFINITIONS -----------------------------------------------
  1565. X *
  1566. X */
  1567. X
  1568. X#ifndef MAX_REL
  1569. X#define MAX_REL  100      /* Max relations open at once for any given user */
  1570. X#endif
  1571. X#ifndef MAX_FLD
  1572. X#define MAX_FLD   40      /* Maximum number of fields in a relation        */
  1573. X#endif
  1574. X#ifndef MAX_IDX
  1575. X#define MAX_IDX   20      /* Maximum number of indices in a relation       */
  1576. X#endif
  1577. X#ifndef MAX_CACHE
  1578. X#define MAX_CACHE 500     /* Maximum # of records to cache before flushing */
  1579. X#endif
  1580. X
  1581. X/*
  1582. X * ERROR CODES --------------------------------------------------------------
  1583. X *
  1584. X */
  1585. X
  1586. Xtypedef enum
  1587. X   {
  1588. X   MB_OKAY = 0,
  1589. X   MB_NO_ROOM,    /* MAX_REL is #defined to be too small   */
  1590. X   MB_NO_MEMORY,  /* Not enough memory for requested task  */
  1591. X   MB_NO_OPEN,    /* Cannot open given filename            */
  1592. X   MB_NO_READ,    /* Cannot read given filename            */
  1593. X   MB_FORMAT,     /* Relation is not in MB 4.0+ format     */
  1594. X   MB_LOCKED,     /* Relation is locked by another user    */
  1595. X   MB_BUSY,       /* Relation has too many users at once   */
  1596. X   MB_BAD_REL,    /* Function passed bad relation struct   */
  1597. X   MB_NO_WRITE,   /* Cannot write given filename           */
  1598. X   MB_TIMEOUT,    /* Temporary lock has not been removed   */
  1599. X   MB_BAD_REC,    /* A null rec pointer has been received  */
  1600. X   MB_CORRUPT,    /* A corrupt index has been detected     */
  1601. X   MB_BAD_DUP,    /* Addition would violate a nodups idx   */
  1602. X   MB_NO_CURR,    /* Current record required for operation */
  1603. X   MB_BAD_IDX,    /* A bad index number has been received  */
  1604. X   MB_NO_SUCH,    /* The specified record can't be found   */
  1605. X   MB_UNKNOWN,    /* Search command invalid                */
  1606. X   MB_NO_FIELDS,  /* The new relation has no fields        */
  1607. X   MB_NO_INDICES, /* The new relation has no indices       */
  1608. X   MB_BAD_INDEX,  /* A proposed new index has no fields    */
  1609. X   MB_DISKFULL,   /* There is not enough free space left   */
  1610. X   MB_BAD_SERIAL, /* Serial #'s for records can't change   */
  1611. X   MB_TMPDIR,     /* You must define a TMP directory       */
  1612. X   MB_TMPERR,     /* Cannot work with TMP directory        */
  1613. X   } mb_err;
  1614. X
  1615. X/*
  1616. X * SEARCH CRITERIA ----------------------------------------------------------
  1617. X *
  1618. X */
  1619. X
  1620. Xtypedef enum
  1621. X   {
  1622. X   FRST = 0,
  1623. X   LAST,
  1624. X   CURR,
  1625. X   NEXT,
  1626. X   PREV,
  1627. X   GTEQ,
  1628. X   GTHN,
  1629. X   LTEQ,
  1630. X   LTHN,
  1631. X   EQUL
  1632. X   } mb_action;
  1633. X
  1634. Xtypedef enum
  1635. X   {
  1636. X   T_CHAR = 0,  /*  0 -- length ? (char [])         */
  1637. X   T_SHORT,     /*  1 -- length 2 (short)           */
  1638. X   T_USHORT,    /*  2 -- length 2 (unsigned short)  */
  1639. X   T_LONG,      /*  3 -- length 4 (long)            */
  1640. X   T_ULONG,     /*  4 -- length 4 (unsigned long)   */
  1641. X   T_FLOAT,     /*  5 -- length 4 (float)           */
  1642. X   T_DOUBLE,    /*  6 -- length 8 (double)          */
  1643. X   T_MONEY,     /*  7 -- length 8 (double)          */
  1644. X   T_TIME,      /*  8 -- length 4 (long)            */
  1645. X   T_DATE,      /*  9 -- length 4 (long)            */
  1646. X   T_SERIAL,    /* 10 -- length 4 (long)            */
  1647. X   T_PHONE      /* 11 -- lenght 20 (char [])        */
  1648. X   } ftype;
  1649. X
  1650. X#define FIRST    FRST
  1651. X#define CURRENT  CURR
  1652. X#define PREVIOUS PREV
  1653. X#define GTHAN    GTHN
  1654. X#define LTHAN    LTHN
  1655. X#define EQUAL    EQUL
  1656. X
  1657. X#define AR_UP    (char)129  /* Arrows for input.c */
  1658. X#define AR_DOWN  (char)130
  1659. X#define AR_LEFT  (char)131
  1660. X#define AR_RIGHT (char)132
  1661. X#define AR_INS   (char)133  /* Insert, Delete, Home, End, PgUp, PgDn */
  1662. X#define AR_DEL   (char)134
  1663. X#define AR_HOME  (char)135
  1664. X#define AR_END   (char)136
  1665. X#define AR_PGUP  (char)137
  1666. X#define AR_PGDN  (char)138
  1667. X
  1668. X/*
  1669. X * TIME/DATE/PHONE STRUCTURES -----------------------------------------------
  1670. X *
  1671. X */
  1672. X
  1673. Xtypedef long mb_time;
  1674. Xtypedef long mb_date;
  1675. Xtypedef char mb_phone[20];
  1676. X
  1677. X/*
  1678. X * RELATION STRUCTURE -------------------------------------------------------
  1679. X *
  1680. X */
  1681. X
  1682. Xtypedef struct
  1683. X   {
  1684. X   int    relcode;                       /* File handle for relation     */
  1685. X   int    lckcode;                       /* Handle for lockfile          */
  1686. X   int    num_i, num_f, rec_len;
  1687. X   long   recz,  pos,   hack;
  1688. X   long   serial;                        /* Serial value last queried    */
  1689. X   int    iser;                          /* Serial field index, or num_f */
  1690. X
  1691. X   char   relname[30];                   /* Relation name--no path       */
  1692. X
  1693. X   int    start[MAX_FLD], siz[MAX_FLD];  /* Byte-wise info for fields    */
  1694. X   ftype  type[MAX_FLD];                 /* Field types                  */
  1695. X   char   name[MAX_FLD][21];             /* Field names                  */
  1696. X
  1697. X   int    itype[MAX_IDX];                /* Dups/Nodups                  */
  1698. X   char   idxs[MAX_IDX][100];            /* Index fields                 */
  1699. X   char   iname[MAX_IDX][21];            /* Index name                   */
  1700. X
  1701. X   char   mask;                          /* Encryption mask              */
  1702. X   ushort pid;                           /* This Process ID              */
  1703. X   int    rdonly;                        /* True if we can't write       */
  1704. X   int    exc;                           /* True if we've locked it      */
  1705. X   int    ver;                           /* Version number               */
  1706. X
  1707. X   char    strobe[30];      /* Last read strobe value for each strobe */
  1708. X   mb_time times[30];       /* Time strobe value last changed         */
  1709. X   } relation;
  1710. X
  1711. X#define RNULL (relation *)0
  1712. X
  1713. X/*
  1714. X * DEFINITIONS --------------------------------------------------------------
  1715. X *
  1716. X */
  1717. X
  1718. X#ifndef UTIL_C
  1719. X#define mb_inc(a,b) mb_open(a,b,0)
  1720. X#define mb_old(a,b) mb_open(a,b,1)
  1721. X#define mb_tst(a)   mb_test(a,0)
  1722. X
  1723. X#define MB_IncludeRelation   mb_inc
  1724. X#define MB_TestInclude       mb_tst
  1725. X#define MB_RemoveRelation    mb_rmv
  1726. X#define MB_CloseAllRelations mb_die
  1727. X#define MB_NumberOfRecords   mb_num
  1728. X#define MB_ResetNumUsers     mb_rst
  1729. X#define MB_AddRecord         mb_add
  1730. X#define MB_DeleteRecord      mb_del
  1731. X#define MB_DebugRelation     mb_dbg
  1732. X#define MB_UpdateRecord      mb_upd
  1733. X#define MB_SelectRecord      mb_sel
  1734. X#define MB_LockRelation      mb_lck
  1735. X#define MB_UnlockRelation    mb_unl
  1736. X#define MB_FormatDate        fmt_date
  1737. X#define MB_FormatTime        fmt_time
  1738. X#define MB_FormatPhone       fmt_phone
  1739. X#define MB_ScanDate          scn_date
  1740. X#define MB_ScanTime          scn_time
  1741. X#define MB_ScanPhone         scn_phone
  1742. X#endif
  1743. X
  1744. X#define curtime()     tmtotime((struct tm *)0)
  1745. X#define curdate()     tmtodate((struct tm *)0)
  1746. X#define curdatetime() datetimetotm((mb_date)0,(mb_time)0)
  1747. X#define iswhite(x)    (x==' ' ||x=='\n' ||x=='\r' ||x=='\t')
  1748. X#define istoken(x)    (x==',' ||x==':'  ||x==';'  ||x=='#' ||x=='(' || x==')')
  1749. X#define putback(f)    lseek(f,_lpos,0)
  1750. X
  1751. X/*
  1752. X * GLOBAL VARIABLES ---------------------------------------------------------
  1753. X *
  1754. X */
  1755. X
  1756. X#ifdef INPUT_C
  1757. X   char      quit_chars[20] = "";
  1758. X   WINDOW   *win = (WINDOW *)0;
  1759. X#else
  1760. X   extern WINDOW *win;
  1761. X   extern char    quit_chars[20];
  1762. X#endif
  1763. X
  1764. X#ifdef MBASE_C
  1765. X   char     *mb_error = "";
  1766. X   mb_err    mb_errno = MB_OKAY;
  1767. X#else
  1768. X   extern char     *mb_error;
  1769. X   extern mb_err    mb_errno;
  1770. X#endif
  1771. X
  1772. X/*
  1773. X * DATA ENTRY STRUCTURES ----------------------------------------------------
  1774. X *
  1775. X */
  1776. X
  1777. X#define FM_IN    1
  1778. X#define FM_OUT   2
  1779. X#define FM_INOUT (FM_IN|FM_OUT)
  1780. X#define fm_refrnum(f,n) fm_refresh(f,&(form->fields[n]))
  1781. X
  1782. Xtypedef int (*int_fn)();
  1783. X
  1784. Xtypedef struct
  1785. X { int      y,    x,     len;
  1786. X   ftype    type;
  1787. X   int      inout, option;
  1788. X   int     *mode;
  1789. X   dataptr  buffer;
  1790. X   char     name[40];
  1791. X   charptr *opt_arr; } field;
  1792. X
  1793. Xtypedef struct
  1794. X { int      curmode;
  1795. X   int      key;          /* Return code from input() */
  1796. X   int      curfield;
  1797. X   int      nextfield;
  1798. X   int      numfields;
  1799. X   int      nummodes;
  1800. X   int_fn   valid_fn;
  1801. X   int      numlines, y, x;
  1802. X   field   *fields;
  1803. X   charptr *_scrn;       } de_form;
  1804. X
  1805. X/*
  1806. X * FUNCTION PROTOTYPES ------------------------------------------------------
  1807. X *
  1808. X */
  1809. X
  1810. X#ifdef LONGARGS
  1811. X
  1812. X#ifndef UTIL_C
  1813. X   extern relation *mb_open  (char     *, int, int);
  1814. X   extern mb_err    mb_test  (char     *, int);
  1815. X   extern mb_err    mb_rmv   (relation *);
  1816. X   extern void      mb_die   (void);
  1817. X   extern long      mb_num   (relation *);
  1818. X   extern mb_err    mb_rst   (relation *, int);
  1819. X   extern mb_err    mb_add   (relation *, dataptr);
  1820. X   extern mb_err    mb_upd   (relation *, dataptr);
  1821. X   extern mb_err    mb_del   (relation *);
  1822. X   extern void      mb_dbg   (relation *);
  1823. X   extern mb_err    mb_sel   (relation *, int, dataptr, mb_action, dataptr);
  1824. X   extern int       compare  (relation *, char *, char *, int);
  1825. X   extern int       idxnum   (relation *, char *);
  1826. X   extern void      mb_exit  (int);
  1827. X   extern int       strtokey (char *);
  1828. X   extern mb_err    mb_lck   (relation *);
  1829. X#endif
  1830. X
  1831. X   extern mb_err   _chk_elck (relation *);
  1832. X   extern mb_err    mb_unl   (relation *);
  1833. X   extern void      strzcpy  (char *,     char *, int);
  1834. X
  1835. X#ifndef MBASE_C
  1836. X   extern long       elap_t       (mb_time);
  1837. X   extern mb_time    tmtotime     (struct tm *);
  1838. X   extern mb_date    tmtodate     (struct tm *);
  1839. X   extern struct tm *datetimetotm (mb_date,     mb_time);
  1840. X   extern char      *fmt_date     (mb_date,     int);
  1841. X   extern char      *fmt_time     (mb_time,     int);
  1842. X   extern char      *fmt_phone    (long, long, long, long, int);
  1843. X   extern void       scn_phone    (long *, long *, long *, long *, char *);
  1844. X   extern mb_date    scn_date     (char      *);
  1845. X   extern mb_time    scn_time     (char      *);
  1846. X   extern mb_time    add_time     (char      *);
  1847. X   extern char      input    (dataptr,    int,    int);
  1848. X   extern char      getarr   (void);
  1849. X   extern void      display  (dataptr,    int,    int);
  1850. X   extern void      init_curses(void);
  1851. X   extern int       skip     (int,        char *);
  1852. X   extern void      goeol    (int,        char *);
  1853. X   extern char     *getword  (int);
  1854. X   extern int       fm_fldnum  (de_form  *,  char     *);
  1855. X   extern void      reltoform  (relation *,  de_form  *,  dataptr);
  1856. X   extern void      formtorel  (de_form  *,  relation *,  dataptr);
  1857. X   extern void      fm_refresh (de_form  *,  field    *);
  1858. X   extern void      fm_refrall (de_form  *);
  1859. X   extern void      fm_zero    (de_form  *);
  1860. X   extern int       do_form    (de_form  *);
  1861. X   extern dataptr   fm_data    (de_form  *,  char     *);
  1862. X   extern void      fm_mode    (de_form *,   int);
  1863. X   extern relation *mb_new      (void);
  1864. X   extern mb_err    mb_addindex (relation *, char *, int,   char *);
  1865. X   extern mb_err    mb_addfield (relation *, char *, ftype, long);
  1866. X   extern mb_err    mb_create   (relation *, char *, int);
  1867. X   extern int       mb_getname  (relation *, char *, int);
  1868. X#endif
  1869. X
  1870. X#else  /* ifndef LONGARGS */
  1871. X
  1872. X#ifndef UTIL_C
  1873. X   extern relation *mb_open();
  1874. X   extern mb_err    mb_test();
  1875. X   extern mb_err    mb_rmv();
  1876. X   extern void      mb_die();
  1877. X   extern long      mb_num();
  1878. X   extern mb_err    mb_rst();
  1879. X   extern mb_err    mb_add();
  1880. X   extern mb_err    mb_upd();
  1881. X   extern mb_err    mb_del();
  1882. X   extern void      mb_dbg();
  1883. X   extern mb_err    mb_sel();
  1884. X   extern int       compare();
  1885. X   extern int       idxnum();
  1886. X   extern void      mb_exit();
  1887. X   extern int       strtokey();
  1888. X   extern mb_err    mb_lck();
  1889. X#endif
  1890. X
  1891. X   extern mb_err   _chk_elck();
  1892. X   extern mb_err    mb_unl();
  1893. X   extern void      strzcpy();
  1894. X
  1895. X#ifndef MBASE_C
  1896. X   extern long       elap_t();
  1897. X   extern mb_time    tmtotime();
  1898. X   extern mb_date    tmtodate();
  1899. X   extern struct tm *datetimetotm();
  1900. X   extern char      *fmt_date();
  1901. X   extern char      *fmt_time();
  1902. X   extern char      *fmt_phone();
  1903. X   extern void       scn_phone();
  1904. X   extern mb_date    scn_date();
  1905. X   extern mb_time    scn_time();
  1906. X   extern mb_time    add_time();
  1907. X   extern char      input();
  1908. X   extern char      getarr();
  1909. X   extern void      display();
  1910. X   extern void      init_curses();
  1911. X   extern int       skip();
  1912. X   extern void      goeol();
  1913. X   extern char     *getword();
  1914. X   extern int       fm_fldnum();
  1915. X   extern void      reltoform();
  1916. X   extern void      formtorel();
  1917. X   extern void      fm_refresh();
  1918. X   extern void      fm_refrall();
  1919. X   extern void      fm_zero();
  1920. X   extern int       do_form();
  1921. X   extern dataptr   fm_data();
  1922. X   extern void      fm_mode();
  1923. X   extern relation *mb_new();
  1924. X   extern mb_err    mb_addindex();
  1925. X   extern mb_err    mb_addfield();
  1926. X   extern mb_err    mb_create();
  1927. X   extern int       mb_getname();
  1928. X#endif
  1929. X
  1930. X#endif  /* LONGARGS */
  1931. X
  1932. X#endif  /* MBASE_H */
  1933. X
  1934. END_OF_FILE
  1935.   if test 12825 -ne `wc -c <'src/mbase.h'`; then
  1936.     echo shar: \"'src/mbase.h'\" unpacked with wrong size!
  1937.   fi
  1938.   # end of 'src/mbase.h'
  1939. fi
  1940. echo shar: End of archive 4 \(of 8\).
  1941. cp /dev/null ark4isdone
  1942. MISSING=""
  1943. for I in 1 2 3 4 5 6 7 8 ; do
  1944.     if test ! -f ark${I}isdone ; then
  1945.     MISSING="${MISSING} ${I}"
  1946.     fi
  1947. done
  1948. if test "${MISSING}" = "" ; then
  1949.     echo You have unpacked all 8 archives.
  1950.     rm -f ark[1-9]isdone
  1951. else
  1952.     echo You still must unpack the following archives:
  1953.     echo "        " ${MISSING}
  1954. fi
  1955. exit 0
  1956. exit 0 # Just in case...
  1957.