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

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