home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / s / sd-27.zip / sdinit.c < prev    next >
C/C++ Source or Header  |  1992-11-15  |  40KB  |  1,054 lines

  1. /* SD -- square dance caller's helper.
  2.  
  3.     Copyright (C) 1990, 1991, 1992  William B. Ackerman.
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 1, or (at your option)
  8.     any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19.     This is for version 27. */
  20.  
  21. /* This defines the following functions:
  22.    initialize_menus
  23. */
  24.  
  25. #include <string.h>
  26. #include "sd.h"
  27.  
  28. /* Global to this file. */
  29.  
  30. /* These two get temporarily allocated.  They persist through the entire initialization. */
  31. static callspec_block **global_temp_call_list;
  32. static char **global_temp_call_name_list;
  33. static int global_callcount;     /* Index into the above. */
  34.  
  35. /* This contains the menu-presentable (e.g. "@" escapes turned into "<ANYONE>", etc.)
  36.    text corresponding to "main_call_lists[call_list_any]", that is, the alphabetized
  37.    universal menu.  It persists through the entire initialization. */
  38. static char **global_main_call_name_list;
  39.  
  40. #define SB (ID2_SIDE|ID2_BOY)
  41. #define HB (ID2_HEAD|ID2_BOY)
  42. #define SG (ID2_SIDE|ID2_GIRL)
  43. #define HG (ID2_HEAD|ID2_GIRL)
  44. #define WEST(x) (d_west|(x)<<6)
  45. #define EAST(x) (d_east|(x)<<6)
  46. #define NORT(x) (d_north|(x)<<6)
  47. #define SOUT(x) (d_south|(x)<<6)
  48.  
  49. /* In all of these setups in which people are facing, they are normal couples.  This makes initialization of things like star thru,
  50.    ladies chain, and curlique work. */
  51. static setup test_setup_1x8  = {s1x8, 0, {{NORT(6), SB}, {SOUT(5), HG}, {SOUT(4), HB}, {NORT(7), SG}, {SOUT(2), SB}, {NORT(1), HG}, {NORT(0), HB}, {SOUT(3), SG}}, 0};
  52. static setup test_setup_l1x8 = {s1x8, 0, {{SOUT(6), SB}, {NORT(5), HG}, {NORT(4), HB}, {SOUT(7), SG}, {NORT(2), SB}, {SOUT(1), HG}, {SOUT(0), HB}, {NORT(3), SG}}, 0};
  53. static setup test_setup_dpt  = {s2x4, 0, {{EAST(6), SB}, {EAST(4), HB}, {WEST(5), HG}, {WEST(7), SG}, {WEST(2), SB}, {WEST(0), HB}, {EAST(1), HG}, {EAST(3), SG}}, 0};
  54. static setup test_setup_cdpt = {s2x4, 0, {{WEST(7), SG}, {WEST(5), HG}, {EAST(4), HB}, {EAST(6), SB}, {EAST(3), SG}, {EAST(1), HG}, {WEST(0), HB}, {WEST(2), SB}}, 0};
  55. static setup test_setup_rcol = {s2x4, 0, {{EAST(6), SB}, {EAST(5), HG}, {EAST(4), HB}, {EAST(7), SG}, {WEST(2), SB}, {WEST(1), HG}, {WEST(0), HB}, {WEST(3), SG}}, 0};
  56. static setup test_setup_lcol = {s2x4, 0, {{WEST(6), SB}, {WEST(5), HG}, {WEST(4), HB}, {WEST(7), SG}, {EAST(2), SB}, {EAST(1), HG}, {EAST(0), HB}, {EAST(3), SG}}, 0};
  57. static setup test_setup_8ch  = {s2x4, 0, {{EAST(6), SB}, {WEST(5), HG}, {EAST(4), HB}, {WEST(7), SG}, {WEST(2), SB}, {EAST(1), HG}, {WEST(0), HB}, {EAST(3), SG}}, 0};
  58. static setup test_setup_tby  = {s2x4, 0, {{WEST(5), HG}, {EAST(6), SB}, {WEST(7), SG}, {EAST(4), HB}, {EAST(1), HG}, {WEST(2), SB}, {EAST(3), SG}, {WEST(0), HB}}, 0};
  59. static setup test_setup_lin  = {s2x4, 0, {{SOUT(5), HG}, {SOUT(6), SB}, {SOUT(7), SG}, {SOUT(4), HB}, {NORT(1), HG}, {NORT(2), SB}, {NORT(3), SG}, {NORT(0), HB}}, 0};
  60. static setup test_setup_lout = {s2x4, 0, {{NORT(6), SB}, {NORT(5), HG}, {NORT(4), HB}, {NORT(7), SG}, {SOUT(2), SB}, {SOUT(1), HG}, {SOUT(0), HB}, {SOUT(3), SG}}, 0};
  61. static setup test_setup_rwv  = {s2x4, 0, {{NORT(6), SB}, {SOUT(5), HG}, {NORT(4), HB}, {SOUT(7), SG}, {SOUT(2), SB}, {NORT(1), HG}, {SOUT(0), HB}, {NORT(3), SG}}, 0};
  62. static setup test_setup_lwv  = {s2x4, 0, {{SOUT(6), SB}, {NORT(5), HG}, {SOUT(4), HB}, {NORT(7), SG}, {NORT(2), SB}, {SOUT(1), HG}, {NORT(0), HB}, {SOUT(3), SG}}, 0};
  63. static setup test_setup_r2fl = {s2x4, 0, {{NORT(6), SB}, {NORT(5), HG}, {SOUT(4), HB}, {SOUT(7), SG}, {SOUT(2), SB}, {SOUT(1), HG}, {NORT(0), HB}, {NORT(3), SG}}, 0};
  64. static setup test_setup_l2fl = {s2x4, 0, {{SOUT(6), SB}, {SOUT(5), HG}, {NORT(4), HB}, {NORT(7), SG}, {NORT(2), SB}, {NORT(1), HG}, {SOUT(0), HB}, {SOUT(3), SG}}, 0};
  65.  
  66.  
  67.  
  68.  
  69.  
  70. /* This cleans up the text of the alphabetized main call list in
  71.    "main_call_lists[call_list_any]", putting the menu-presentable form
  72.    into global_main_call_name_list, from which various subsets will be picked out
  73.    for the menus.  It simply re-uses the stored string where it can, and allocates
  74.    fresh memory if a substitution took place. */
  75.  
  76. static void create_call_name_list(void)
  77. {
  78.    int i, j;
  79.    char *name_ptr;
  80.    long_boolean atsign;
  81.    char c;
  82.    int namelength;
  83.  
  84.    for (i=0; i<number_of_calls[call_list_any]; i++) {
  85.       name_ptr = main_call_lists[call_list_any][i]->name;
  86.       atsign = FALSE;
  87.  
  88.       /* See if the name has an 'at' sign, in which case we have to modify it to
  89.          get the actual menu text. */
  90.  
  91.       namelength = 0;
  92.       for (;;) {
  93.          c = name_ptr[namelength];
  94.          if (!c) break;
  95.          else if (c == '@') atsign = TRUE;
  96.          namelength++;
  97.       }
  98.  
  99.       if (atsign) {
  100.          char tempname[200];
  101.          char *temp_ptr;
  102.          int templength;
  103.  
  104.          temp_ptr = tempname;
  105.          templength = 0;
  106.  
  107.          for (j = 0; j < namelength; j++) {
  108.             c = name_ptr[j];
  109.  
  110.             if (c == '@') {
  111.                j++;
  112.                c = name_ptr[j];
  113.                if (c == '0') {
  114.                   char *p;
  115.  
  116.                   p = temp_ptr+templength;
  117.                   string_copy(&p, "<ANYTHING>");
  118.                   templength = p - temp_ptr;
  119.                }
  120.                else if (c == '6' || c == 'k') {
  121.                   char *p;
  122.  
  123.                   p = temp_ptr+templength;
  124.                   string_copy(&p, "<ANYONE>");
  125.                   templength = p - temp_ptr;
  126.                }
  127.                else if (c == '9') {
  128.                   char *p;
  129.  
  130.                   p = temp_ptr+templength;
  131.                   string_copy(&p, "<N>");
  132.                   templength = p - temp_ptr;
  133.                }
  134.                else if (c == 'a' || c == 'b') {
  135.                   char *p;
  136.  
  137.                   p = temp_ptr+templength;
  138.                   string_copy(&p, "<N/4>");
  139.                   templength = p - temp_ptr;
  140.                }
  141.                else if (c == '7' || c == 'j') {
  142.                   /* Skip over @7...@8 and @j...@l stuff. */
  143.                   while (name_ptr[j] != '@') j++;
  144.                   j++;
  145.                }
  146.             }
  147.             else if (c != ' ' || templength == 0 || temp_ptr[templength-1] != ' ')
  148.                temp_ptr[templength++] = c;
  149.          }
  150.  
  151.          tempname[templength] = '\0';
  152.          /* Must copy the text into some fresh memory, being careful about overflow. */
  153.          name_ptr = get_mem(templength+1);
  154.          for (j=0; j<=templength; j++) name_ptr[j] = tempname[j];
  155.       }
  156.  
  157.       global_main_call_name_list[i] = name_ptr;
  158.    }
  159. }
  160.  
  161.  
  162. static void create_menu(call_list_kind cl, char *call_name_list[])
  163. {
  164.    int i;
  165.  
  166.    for (i=0; i<number_of_calls[cl]; i++) {
  167.       uims_add_call_to_menu(cl, i, call_name_list[i]);
  168.    }
  169.    uims_finish_call_menu(cl, menu_names[cl]);
  170. }
  171.  
  172.  
  173. /* These variables are actually local to test_starting_setup, but they are
  174.    expected to be preserved across the longjmp, so they must be static. */
  175. static parse_block *parse_mark;
  176. static int call_index;
  177.  
  178.  
  179. static void test_starting_setup(call_list_kind cl, setup test_setup)
  180. {
  181.    callspec_block *test_call;
  182.    real_jmp_buf my_longjmp_buffer;
  183.    int i;
  184.  
  185.    call_index = -1;
  186.    global_callcount = 0;
  187.    /* Mark the parse block allocation, so that we throw away the garbage
  188.       created by failing attempts. */
  189.    parse_mark = mark_parse_blocks();
  190.  
  191.    /* Create a special error handler. */
  192.  
  193.    longjmp_ptr = &my_longjmp_buffer;          /* point the global pointer at it. */
  194.    if (setjmp(my_longjmp_buffer.the_buf)) {
  195.  
  196.       /* A call failed.  A bad choice of selector may be the cause. */
  197.  
  198.       if (selector_used) {
  199.          /* This call used a selector and didn't like it.  Try again with
  200.             a different selector, until we run out of ideas. */
  201.          switch (selector_for_initialize) {
  202.             case selector_beaux:
  203.                selector_for_initialize = selector_all;
  204.                goto try_another_selector;
  205.             case selector_all:
  206.                selector_for_initialize = selector_none;
  207.                goto try_another_selector;
  208.          }
  209.       }
  210.       /* Otherwise fall through and go on to the next call. */
  211.    }
  212.  
  213.   try_again:
  214.    /* Throw away garbage. */
  215.    release_parse_blocks_to_mark(parse_mark);
  216.    call_index++;
  217.    if (call_index >= number_of_calls[call_list_any]) goto finished;
  218.    test_call = main_call_lists[call_list_any][call_index];
  219.  
  220.    /* Set the selector (for "so-and-so advance to a column", etc) to "beaux".
  221.       This seems to make most calls work -- note that "everyone run" and
  222.       "no one advance to a column" are illegal.  If this doesn't work, we will
  223.       try a few others before giving up. */
  224.    selector_for_initialize = selector_beaux;
  225.  
  226.    try_another_selector:
  227.  
  228.    /* Do the call.  An error will signal and go to try_again. */
  229.  
  230.    selector_used = FALSE;
  231.  
  232.    history_ptr = 1;
  233.    initialize_parse();
  234.  
  235.    /* If the call has the "rolldefine" schema, we accept it, since the test setups
  236.       are all in the "roll unsupported" state. */
  237.  
  238.    if (test_call->schema == schema_roll) goto accept;
  239.  
  240.    (void) deposit_call(test_call);
  241.    history[history_ptr].state = test_setup;
  242.    history[history_ptr+1].warnings.bits[0] = 0;
  243.    history[history_ptr+1].warnings.bits[1] = 0;
  244.    toplevelmove();
  245.  
  246.    /* It seems to have worked, save it.  We don't care about warnings here. */
  247.  
  248.   accept:
  249.    global_temp_call_list[global_callcount] = test_call;
  250.    global_temp_call_name_list[global_callcount] = global_main_call_name_list[call_index];
  251.    global_callcount++;
  252.    goto try_again;
  253.  
  254.   finished:
  255.  
  256.    /* Restore the global error handler. */
  257.  
  258.    longjmp_ptr = &longjmp_buffer;
  259.  
  260.    /* Create the call list itself. */
  261.  
  262.    number_of_calls[cl] = global_callcount;
  263.    main_call_lists[cl] = (callspec_block **) get_mem(global_callcount * sizeof(callspec_block *));
  264.    for (i=0; i < global_callcount; i++) {
  265.       main_call_lists[cl][i] = global_temp_call_list[i];
  266.    }
  267.  
  268.    /* Create the menu for it. */
  269.  
  270.    create_menu(cl, global_temp_call_name_list);
  271. }
  272.  
  273.  
  274. /* Definition: a region of the array "a" is said to have the "heap" property
  275.    (or "be a heap") if:
  276.       Whenever a[i] and a[2i+1] are both in the region, a[i] >= a[2i+1], and
  277.       Whenever a[i] and a[2i+2] are both in the region, a[i] >= a[2i+2].
  278.  
  279.    Two special properties are noteworthy:
  280.       1: If hi <= 2*lo, the region from lo to hi inclusive is automatically a heap,
  281.          since there are no such pairs lying in the region.
  282.       2: If the region that is a heap is [0..hi], a[0] is greater than or equal to
  283.          every other element of the region.  Why?  Because a[0] >= a[1..2],
  284.          and a[1] >= a[3..4] while a[2] >= a[5..6], so a[1] and a[2]
  285.          are collectively >= a[3..6], which are >= a[7..14], etc. */
  286.  
  287.          /* Heapify causes the region between lo-1 and hi-1, inclusive, to be a heap, given that the
  288.             region from lo to hi-1 was already a heap.  It works as follows:  when we declare
  289.             "lo-1" to be part of the region, the only way it can fail to be a heap is if a[lo-1]
  290.             is too small -- it might be less than a[2*lo-1] or a[2*lo].  If this is the case,
  291.             we swap it with the larger of a[2*lo-1] and a[2*lo-1].  Now whatever we swapped it
  292.             with got smaller, so it might fail to meet the heap property with respect to the
  293.             elements farther down the line, so we repeat the process until we are off the end
  294.             of the region. */
  295.  
  296.  
  297. /* This pointer to a call array is used by the heapsort routine. */
  298.  
  299. static callspec_block **the_array;
  300.  
  301.  
  302. static long_boolean callcompare(callspec_block *x, callspec_block *y)
  303. {
  304.    char *m, *n;
  305.  
  306.    m = x->name;
  307.    n = y->name;
  308.    for (;;) {
  309.       if (*m == '@') {
  310.          /* Skip over @7...@8 and @j...@l stuff. */
  311.          if (m[1] == '7' || m[1] == 'j') {
  312.             while (*++m != '@');
  313.          }
  314.          m += 2;   
  315.       }
  316.       else if (*n == '@') {
  317.          if (n[1] == '7' || n[1] == 'j') {
  318.             while (*++n != '@');
  319.          }
  320.          n += 2;
  321.       }
  322.       /* We need to ignore blanks too, otherwise "@6 run" will come out at the beginning of the list instead of under "r". */
  323.       else if (*m == ' ') m++;
  324.       else if (*n == ' ') n++;
  325.       else if (!*m) return(TRUE);
  326.       else if (!*n) return(FALSE);
  327.       else if (*m < *n) return(TRUE);
  328.       else if (*m > *n) return(FALSE);
  329.       else
  330.          { m++; n++; }
  331.    }
  332. }
  333.  
  334. static void heapify(int lo, int hi)
  335. {
  336.    int j = lo-1;
  337.  
  338.    for (;;) {
  339.       callspec_block *temp;
  340.       int k = j*2+1;
  341.  
  342.       if (k+1 > hi) return;
  343.       if (k+1 < hi) {
  344.          if (callcompare(the_array[k], the_array[k+1])) k++;
  345.       }
  346.       if (callcompare(the_array[k], the_array[j])) return;
  347.       temp = the_array[j];
  348.       the_array[j] = the_array[k];
  349.       the_array[k] = temp;
  350.       j = k;
  351.    }
  352. }
  353.  
  354.  
  355.  
  356. static void heapsort(int n)
  357. {
  358.    int i;
  359.  
  360.    /* First, turn the whole array into a heap, building downward from the top, since adding
  361.       one more item at the bottom is what heapify is good at.  We don't start calling heapify
  362.       until the low limit is n/2, since heapify wouldn't have anything to do until then. */
  363.  
  364.    for (i=n/2; i>0; i--) heapify(i, n);
  365.  
  366.    /* Now we use the property that a[0] has the largest element.  We pull that out and move it
  367.       to the end.  We declare that item to no longer be part of the region we are interested in.
  368.       Since we have changed a[0], we call heapify to repair the damage, on the smaller region.
  369.       We repeat this, pulling out the largest element of the remaining heap (which is always
  370.       element 0), and letting the heap shrink down to nothing. */
  371.  
  372.    for (i=n; i>1; i--) {
  373.       callspec_block *temp;
  374.  
  375.       temp = the_array[0];
  376.       the_array[0] = the_array[i-1];
  377.       the_array[i-1] = temp;
  378.       heapify(1, i-1);
  379.    }
  380. }
  381.  
  382.  
  383. static void create_misc_call_lists(void)
  384. {
  385.    int j;
  386.    long_boolean accept_it;
  387.    int i, callcount;
  388.  
  389.    /* GCOL */
  390.  
  391.    callcount = 0;
  392.  
  393.    for (j=0; j<number_of_calls[call_list_any]; j++) {
  394.       accept_it = FALSE;
  395.       if (main_call_lists[call_list_any][j]->schema != schema_by_array) accept_it = TRUE;
  396.       else if (main_call_lists[call_list_any][j]->callflags & cflag__step_to_wave) {
  397.          if (  assoc(b_4x2, (setup *) 0, main_call_lists[call_list_any][j]->stuff.arr.def_list->callarray_list) ||
  398.                assoc(b_4x1, (setup *) 0, main_call_lists[call_list_any][j]->stuff.arr.def_list->callarray_list) ||
  399.                assoc(b_2x2, (setup *) 0, main_call_lists[call_list_any][j]->stuff.arr.def_list->callarray_list) ||
  400.                assoc(b_2x1, (setup *) 0, main_call_lists[call_list_any][j]->stuff.arr.def_list->callarray_list))
  401.             accept_it = TRUE;
  402.       }
  403.       else {
  404.          if (  assoc(b_8x1, (setup *) 0, main_call_lists[call_list_any][j]->stuff.arr.def_list->callarray_list) ||
  405.                assoc(b_4x1, (setup *) 0, main_call_lists[call_list_any][j]->stuff.arr.def_list->callarray_list) ||
  406.                assoc(b_2x1, (setup *) 0, main_call_lists[call_list_any][j]->stuff.arr.def_list->callarray_list))
  407.             accept_it = TRUE;
  408.       }
  409.  
  410.       if (accept_it) {
  411.          global_temp_call_list[callcount] = main_call_lists[call_list_any][j];
  412.          global_temp_call_name_list[callcount] = global_main_call_name_list[j];
  413.          callcount++;
  414.       }
  415.    }
  416.  
  417.    /* Create the call list itself. */
  418.  
  419.    number_of_calls[call_list_gcol] = callcount;
  420.    main_call_lists[call_list_gcol] = (callspec_block **) get_mem(callcount * sizeof(callspec_block *));
  421.    for (i=0; i < callcount; i++) {
  422.       main_call_lists[call_list_gcol][i] = global_temp_call_list[i];
  423.    }
  424.  
  425.    /* Create the menu for it. */
  426.  
  427.    create_menu(call_list_gcol, global_temp_call_name_list);
  428.  
  429.    /* QTAG */
  430.  
  431.    callcount = 0;
  432.  
  433.    for (j=0; j<number_of_calls[call_list_any]; j++) {
  434.       accept_it = FALSE;
  435.       if (main_call_lists[call_list_any][j]->schema != schema_by_array) accept_it = TRUE;
  436.       else if (main_call_lists[call_list_any][j]->callflags & cflag__rear_back_from_qtag) {
  437.          if (  assoc(b_4x2, (setup *) 0, main_call_lists[call_list_any][j]->stuff.arr.def_list->callarray_list) ||
  438.                assoc(b_4x1, (setup *) 0, main_call_lists[call_list_any][j]->stuff.arr.def_list->callarray_list))
  439.             accept_it = TRUE;
  440.       }
  441.       else {
  442.          if (assoc(b_qtag, (setup *) 0, main_call_lists[call_list_any][j]->stuff.arr.def_list->callarray_list) ||
  443.                assoc(b_pqtag, (setup *) 0, main_call_lists[call_list_any][j]->stuff.arr.def_list->callarray_list) ||
  444.                assoc(b_dmd, (setup *) 0, main_call_lists[call_list_any][j]->stuff.arr.def_list->callarray_list) ||
  445.                assoc(b_pmd, (setup *) 0, main_call_lists[call_list_any][j]->stuff.arr.def_list->callarray_list) ||
  446.                assoc(b_1x2, (setup *) 0, main_call_lists[call_list_any][j]->stuff.arr.def_list->callarray_list) ||
  447.                assoc(b_2x1, (setup *) 0, main_call_lists[call_list_any][j]->stuff.arr.def_list->callarray_list))
  448.             accept_it = TRUE;
  449.       }
  450.  
  451.       if (accept_it) {
  452.          global_temp_call_list[callcount] = main_call_lists[call_list_any][j];
  453.          global_temp_call_name_list[callcount] = global_main_call_name_list[j];
  454.          callcount++;
  455.       }
  456.    }
  457.  
  458.    /* Create the call list itself. */
  459.  
  460.    number_of_calls[call_list_qtag] = callcount;
  461.    main_call_lists[call_list_qtag] = (callspec_block **) get_mem(callcount * sizeof(callspec_block *));
  462.    for (i=0; i < callcount; i++) {
  463.       main_call_lists[call_list_qtag][i] = global_temp_call_list[i];
  464.    }
  465.  
  466.    /* Create the menu for it. */
  467.  
  468.    create_menu(call_list_qtag, global_temp_call_name_list);
  469. }
  470.  
  471.  
  472. /* These are used by the database reading stuff. */
  473.  
  474. static int last_datum, last_12;
  475. static callspec_block *call_root;
  476. static callarray *tp;
  477. /* This shows the highest index we have seen so far.  It must never exceed max_base_calls-1. */
  478. static int highest_base_call;
  479.  
  480.  
  481. static void read_halfword(void)
  482. {
  483.    last_datum = read_from_database();
  484.    last_12 = last_datum & 0xFFF;
  485. }
  486.  
  487.  
  488. static void read_fullword(void)
  489. {
  490.    int t = read_from_database();
  491.    last_datum = t << 16 | read_from_database();
  492. }
  493.  
  494.  
  495.  
  496. /* Found an error while reading CALL out of the database.
  497.    Print an error message and quit.
  498.    Should take the call as an argument, but since this entire file uses global variables,
  499.    we will, too. */
  500.  
  501. static void database_error(char *message)
  502. {
  503.     print_line(message);
  504.     if (call_root && call_root->name) {
  505.     print_line("  While reading this call from the database:");
  506.     print_line(call_root->name);
  507.     }
  508.     exit_program(1);
  509. }
  510.  
  511.  
  512. static void read_level_3_groups(calldef_block *where_to_put)
  513. {
  514.    int j, char_count;
  515.    callarray *current_call_block;
  516.  
  517.    read_halfword();
  518.  
  519.    if ((last_datum & 0xE000) != 0x6000) {
  520.       database_error("database phase error 3");
  521.    }
  522.  
  523.    current_call_block = 0;
  524.  
  525.    while ((last_datum & 0xE000) == 0x6000) {
  526.       begin_kind this_start_setup;
  527.       search_qualifier this_qualifier;
  528.       call_restriction this_restriction;
  529.       setup_kind end_setup;
  530.       setup_kind end_setup_out;
  531.       int this_start_size;
  532.       unsigned int these_flags;
  533.       int extra;
  534.  
  535.       these_flags = last_12;
  536.  
  537.       read_halfword();       /* Get qualifier and start setup. */
  538.       this_qualifier = (search_qualifier) ((last_datum & 0xFF00) >> 8);
  539.       this_start_setup = (begin_kind) (last_datum & 0xFF);
  540.       this_start_size = begin_sizes[this_start_setup];
  541.  
  542.       read_halfword();       /* Get restriction and end setup. */
  543.       this_restriction = (call_restriction) ((last_datum & 0xFF00) >> 8);
  544.       end_setup = (setup_kind) (last_datum & 0xFF);
  545.  
  546.       if (these_flags & CAF__CONCEND) {      /* See if "concendsetup" was used. */
  547.          read_halfword();       /* Get outer setup and outer rotation. */
  548.          end_setup_out = (setup_kind) (last_datum & 0xFF);
  549.       }
  550.  
  551.       if (these_flags & CAF__PREDS) {
  552.          read_halfword();    /* Get error message count. */
  553.          char_count = last_datum & 0xFF;
  554.          /* We will naturally get 4 items in the "stuff.prd.errmsg" field; we are responsible all for the others. */
  555.          /* We subtract 3 because 4 chars are already present, but we need one extra for the pad. */
  556.          extra = (char_count-3) * sizeof(char);
  557.       }
  558.       else {
  559.          /* We will naturally get 4 items in the "stuff.def" field; we are responsible all for the others. */
  560.          extra = (this_start_size-4) * sizeof(unsigned short int);
  561.       }
  562.  
  563.       tp = (callarray *) get_mem(sizeof(callarray) + extra);
  564.       tp->next = 0;
  565.  
  566.       if (!current_call_block)
  567.          where_to_put->callarray_list = tp;   /* First time. */
  568.       else {
  569.          current_call_block->next = tp;       /* Subsequent times. */
  570.       }
  571.  
  572.       current_call_block = tp;
  573.  
  574.       tp->callarray_flags = these_flags;
  575.       tp->qualifier = this_qualifier;
  576.       tp->start_setup = this_start_setup;
  577.       tp->restriction = this_restriction;
  578.  
  579.       if (these_flags & CAF__CONCEND) {      /* See if "concendsetup" was used. */
  580.          tp->end_setup = s_normal_concentric;
  581.          tp->end_setup_in = end_setup;
  582.          tp->end_setup_out = end_setup_out;
  583.       }
  584.       else {
  585.          tp->end_setup = end_setup;
  586.       }
  587.  
  588.       if (these_flags & CAF__PREDS) {
  589.          predptr_pair *temp_predlist;
  590.          predptr_pair *this_predlist = (predptr_pair *) 0;
  591.  
  592.          /* Read error message text. */
  593.  
  594.          for (j=1; j <= ((char_count+1) >> 1); j++) {
  595.             read_halfword();
  596.             tp->stuff.prd.errmsg[(j << 1)-2] = (last_datum >> 8) & 0xFF;
  597.             if ((j << 1) != char_count+1) tp->stuff.prd.errmsg[(j << 1)-1] = last_datum & 0xFF;
  598.          }
  599.  
  600.          tp->stuff.prd.errmsg[char_count] = '\0';
  601.  
  602.          read_halfword();
  603.  
  604.          /* Demand level 4 group. */
  605.          if (last_datum != 0x8000) {
  606.             database_error("database phase error 4");
  607.          }
  608.  
  609.          while ((last_datum & 0xE000) == 0x8000) {
  610.             read_halfword();       /* Read predicate indicator. */
  611.             /* "predptr_pair" will get us 4 items in the "arr" field; we are responsible all for the others. */
  612.             temp_predlist = (predptr_pair *) get_mem(sizeof(predptr_pair) +
  613.                     (this_start_size-4) * sizeof(unsigned short));
  614.             temp_predlist->pred = pred_table[last_datum];
  615.             /* If this call uses a predicate that takes a selector, flag the call so that
  616.                we will query the user for that selector. */
  617.             if (last_datum < SELECTOR_PREDS)
  618.                call_root->callflags |= cflag__requires_selector;
  619.             for (j=0; j < this_start_size; j++) {
  620.                read_halfword();
  621.                temp_predlist->arr[j] = last_datum;
  622.             }
  623.  
  624.             temp_predlist->next = this_predlist;
  625.             this_predlist = temp_predlist;
  626.             read_halfword();    /* Get next level 4 header, or whatever. */
  627.          }
  628.  
  629.          /* need to reverse stuff in "this_predlist" */
  630.          temp_predlist = 0;
  631.          while (this_predlist) {
  632.             predptr_pair *revptr = this_predlist;
  633.             this_predlist = this_predlist->next;
  634.             revptr->next = temp_predlist;
  635.             temp_predlist = revptr;
  636.          }
  637.  
  638.          tp->stuff.prd.predlist = temp_predlist;
  639.       }
  640.       else {
  641.          for (j=0; j < this_start_size; j++) {
  642.             read_halfword();
  643.             tp->stuff.def[j] = last_datum;
  644.          }
  645.          read_halfword();
  646.       }
  647.    }
  648. }
  649.  
  650.  
  651. static void check_tag(int tag)
  652. {
  653.    if (tag >= max_base_calls)
  654.       database_error("Too many tagged calls -- mkcalls made an error.");
  655.    if (tag > highest_base_call) highest_base_call = tag;
  656. }
  657.  
  658.  
  659. /* This fills the permanent array "main_call_lists[call_list_any]" with the stuff
  660.       read in from the database, including name pointer fields containing the original text
  661.       with "@" escapes.  It also sets "number_of_calls[call_list_any]" to the size thereof.
  662.          It does this only for calls that are legal at this level.  If we are just
  663.          writing a call list, a call is legal only if its level is exactly the level
  664.          specified when the program was invoked, rather than the usual case of including
  665.          any call whose level is at or below the specified level.  If we are doing a
  666.          "write full" we do the usual action.
  667.    It also fills in the "base_calls" array with tagged calls, independent of level. */
  668.  
  669. static void build_database(call_list_mode_t call_list_mode)
  670. {
  671.    int i, j, char_count;
  672.    calldef_schema call_schema;
  673.    int local_callcount;
  674.    char *np, c;
  675.    int savetag, saveflags;
  676.    level savelevel;
  677.    callspec_block **local_call_list;
  678.  
  679.    open_database();    /* This sets up the values of abs_max_calls and max_base_calls. */
  680.  
  681.    /* This list will be permanent. */
  682.    base_calls = (callspec_block **) get_mem(max_base_calls * sizeof(callspec_block *));
  683.  
  684.    /* These three will be temporary.  The first two last through the entire initialization
  685.       process.  The last one only in this procedure. */
  686.    global_temp_call_list = (callspec_block **) get_mem(abs_max_calls * sizeof(callspec_block *));
  687.    global_temp_call_name_list = (char **) get_mem(abs_max_calls * sizeof(char *));
  688.    local_call_list = (callspec_block **) get_mem(abs_max_calls * sizeof(callspec_block *));
  689.  
  690.    /* Clear the tag list.  Calls will fill this in as they announce themselves. */
  691.    for (i=0; i < max_base_calls; i++) base_calls[i] = 0;
  692.  
  693.    highest_base_call = 0;
  694.  
  695.    read_halfword();
  696.  
  697.    local_callcount = 0;
  698.  
  699.    for (;;) {
  700.       if ((last_datum & 0xE000) == 0) break;
  701.  
  702.       if ((last_datum & 0xE000) != 0x2000) {
  703.          database_error("database phase error 1");
  704.       }
  705.  
  706.       savetag = last_12;     /* Get tag, if any. */
  707.  
  708.       read_halfword();       /* Get level. */
  709.       savelevel = (level) last_datum;
  710.  
  711.       read_fullword();       /* Get boolean flags. */
  712.       saveflags = last_datum;
  713.  
  714.       read_halfword();       /* Get char count and schema. */
  715.       call_schema = (calldef_schema) (last_datum & 0xFF);
  716.       char_count = (last_datum >> 8) & 0xFF;
  717.  
  718.       /* **** We should only allocate the call root if we are going to use this call,
  719.          either because it is tagged or because it is legal at this level!!!! */
  720.  
  721.       /* Now that we know how long the name is, create the block and fill in the saved stuff. */
  722.       /* We subtract 3 because 4 chars are already present, but we need one extra for the pad. */
  723.  
  724.       call_root = (callspec_block *) get_mem(sizeof(callspec_block) + char_count - 3);
  725.       np = call_root->name;
  726.  
  727.       if (savetag) {
  728.          check_tag(savetag);
  729.          base_calls[savetag] = call_root;
  730.       }
  731.  
  732.       if (savelevel == calling_level || (call_list_mode != call_list_mode_writing && savelevel < calling_level)) {
  733.          if (local_callcount >= abs_max_calls)
  734.             database_error("Too many base calls -- mkcalls made an error.");
  735.          local_call_list[local_callcount++] = call_root;
  736.       }
  737.  
  738.       call_root->age = 0;
  739.       call_root->callflags = saveflags;
  740.       /* If we are operating at the "all" level, make fractions visible everywhere, to aid in debugging. */
  741.       if (calling_level == l_dontshow) call_root->callflags |= cflag__visible_fractions | cflag__first_part_visible;
  742.  
  743.       /* Now read in the name itself. */
  744.  
  745.       for (j=2; j <= char_count+1; j += 2) {
  746.          read_halfword();
  747.  
  748.          *np++ = (last_datum >> 8) & 0xFF;
  749.          if (j != char_count+1)
  750.             *np++ = last_datum & 0xFF;
  751.       }
  752.  
  753.       *np = '\0';
  754.  
  755.       /* Scan the name for "@6" or "@e", fill in "needselector" or
  756.          "left_changes_name" flag if found. */
  757.  
  758.       np = call_root->name;
  759.  
  760.       while (c = *np++) {
  761.          if (c == '@') {
  762.             if ((c = *np++) == '6' || c == 'k') call_root->callflags |= cflag__requires_selector;
  763.          }
  764.       }
  765.  
  766.       read_halfword();       /* Get next thing, whatever that is. */
  767.  
  768.       call_root->schema = call_schema;
  769.  
  770.       switch (call_schema) {
  771.          case schema_nothing:
  772.             continue;
  773.          case schema_matrix:
  774.             {
  775.                int left_half = last_datum;
  776.                read_halfword();
  777.                call_root->stuff.matrix.flags = ((left_half & 0xFFFF) << 16) | (last_datum & 0xFFFF);
  778.                read_halfword();
  779.  
  780.                for (j=0; j < 2; j++) {
  781.                   call_root->stuff.matrix.stuff[j] = last_datum & 0xFFFF;
  782.                   read_halfword();
  783.                }
  784.  
  785.                call_root->callflags |= cflag__requires_selector;
  786.                continue;
  787.             }
  788.          case schema_partner_matrix:
  789.             {
  790.                int left_half = last_datum;
  791.                read_halfword();
  792.                call_root->stuff.matrix.flags = ((left_half & 0xFFFF) << 16) | (last_datum & 0xFFFF);
  793.                read_halfword();
  794.  
  795.                for (j=0; j < 8; j++) {
  796.                   call_root->stuff.matrix.stuff[j] = last_datum & 0xFFFF;
  797.                   read_halfword();
  798.                }
  799.  
  800.                continue;
  801.             }
  802.          case schema_roll:
  803.             continue;
  804.       }
  805.  
  806.       switch (call_schema) {
  807.          case schema_by_array:
  808.             {
  809.                calldef_block *zz, *yy;
  810.    
  811.                /* Demand a level 2 group. */
  812.                if ((last_datum) != 0x4000) {
  813.                   database_error("database phase error 2");
  814.                }
  815.    
  816.                zz = (calldef_block *) get_mem(sizeof(calldef_block));
  817.                zz->next = 0;
  818.                zz->modifier_set = 0;
  819.                zz->modifier_level = l_mainstream;
  820.                call_root->stuff.arr.def_list = zz;
  821.    
  822.                read_level_3_groups(zz);
  823.    
  824.                /* Check for more level 2 groups. */
  825.    
  826.                while ((last_datum & 0xE000) == 0x4000) {
  827.                   yy = (calldef_block *) get_mem(sizeof(calldef_block));
  828.                   zz->next = yy;
  829.                   zz = yy;
  830.                   zz->modifier_level = (level) (last_datum & 0xFF);
  831.                   zz->next = 0;
  832.                   /* We make use of the fact that HERITABLE_FLAG_MASK, which has all the
  833.                      bits we could read in, lies only in the left half.  This was tested
  834.                      by some compile-time code near the start of this file. */
  835.                   read_halfword();
  836.                   zz->modifier_set = last_datum << 16;
  837.    
  838.                   read_level_3_groups(zz);
  839.                }
  840.             }
  841.             break;
  842.          case schema_sequential:
  843.          case schema_split_sequential:
  844.             {
  845.                int next_definition_index = 0;
  846.  
  847.                /* Demand a level 2 group. */
  848.                if ((last_datum & 0xE000) != 0x4000) {
  849.                   database_error("database phase error 6");
  850.                }
  851.  
  852.                while ((last_datum & 0xE000) == 0x4000) {
  853.                   if (next_definition_index >= SEQDEF_MAX) {
  854.                      database_error("database error: too many sequential parts");
  855.                   }
  856.                   check_tag(last_12);
  857.                   call_root->stuff.def.defarray[next_definition_index].call_id = last_12;
  858.                   read_fullword();
  859.                   call_root->stuff.def.defarray[next_definition_index++].modifiers = (defmodset) last_datum;
  860.                   call_root->stuff.def.defarray[next_definition_index].call_id = 0;
  861.                   read_halfword();
  862.                }
  863.             }
  864.             break;
  865.          default:          /* These are all the variations of concentric. */
  866.             /* Demand a level 2 group. */
  867.             if ((last_datum & 0xE000) != 0x4000) {
  868.                database_error("database phase error 7");
  869.             }
  870.  
  871.             check_tag(last_12);
  872.             call_root->stuff.conc.innerdef.call_id = last_12;
  873.             read_fullword();
  874.             call_root->stuff.conc.innerdef.modifiers = (defmodset) last_datum;
  875.             read_halfword();
  876.             check_tag(last_12);
  877.             call_root->stuff.conc.outerdef.call_id = last_12;
  878.             read_fullword();
  879.             call_root->stuff.conc.outerdef.modifiers = (defmodset) last_datum;
  880.             read_halfword();
  881.             break;
  882.       }
  883.    }
  884.  
  885.    number_of_calls[call_list_any] = local_callcount;
  886.    main_call_lists[call_list_any] = (callspec_block **) get_mem(local_callcount * sizeof(callspec_block *));
  887.    for (i=0; i < local_callcount; i++) {
  888.       main_call_lists[call_list_any][i] = local_call_list[i];
  889.    }
  890.    free_mem(local_call_list);
  891.  
  892.    for (i=1; i <= highest_base_call; i++) {
  893.       if (!base_calls[i]) {
  894.          print_id_error(i);
  895.          exit_program(1);
  896.       }
  897.    }
  898.  
  899.    close_database();
  900. }
  901.  
  902.  
  903.  
  904. extern void initialize_menus(call_list_mode_t call_list_mode)
  905. {
  906.    /* Test that the necessary constants are in step with each other.
  907.       This "if" should never get executed.  We expect compilers to optimize
  908.       it away, and perhaps print a warning about it. */
  909.    
  910.    if (cflag__diamond_is_inherited        != dfm_inherit_diamond ||
  911.          cflag__reverse_means_mirror      != dfm_inherit_reverse ||
  912.          cflag__left_means_mirror         != dfm_inherit_left ||
  913.          cflag__funny_is_inherited        != dfm_inherit_funny ||
  914.          cflag__intlk_is_inherited        != dfm_inherit_intlk ||
  915.          cflag__magic_is_inherited        != dfm_inherit_magic ||
  916.          cflag__grand_is_inherited        != dfm_inherit_grand ||
  917.          cflag__12_matrix_is_inherited    != dfm_inherit_12_matrix ||
  918.          cflag__cross_is_inherited        != dfm_inherit_cross ||
  919.          cflag__single_is_inherited       != dfm_inherit_single ||
  920.          cflag__diamond_is_inherited      != FINAL__DIAMOND ||
  921.          cflag__reverse_means_mirror      != FINAL__REVERSE ||
  922.          cflag__left_means_mirror         != FINAL__LEFT ||
  923.          cflag__funny_is_inherited        != FINAL__FUNNY ||
  924.          cflag__intlk_is_inherited        != FINAL__INTERLOCKED ||
  925.          cflag__magic_is_inherited        != FINAL__MAGIC ||
  926.          cflag__grand_is_inherited        != FINAL__GRAND ||
  927.          cflag__12_matrix_is_inherited    != FINAL__12_MATRIX ||
  928.          cflag__cross_is_inherited        != FINAL__CROSS ||
  929.          cflag__single_is_inherited       != FINAL__SINGLE ||
  930.    
  931.    /* Also test that the constants ROLL_BIT and DBROLL_BIT are in the right
  932.       relationship, with ROLL_BIT >= DBROLL_BIT, that is, the roll bits
  933.       in a person record are to the left of the roll bits in the binary database.
  934.       This is because of expressions "ROLL_BIT/DBROLL_BIT" in sdbasic.c to
  935.       align stuff from the binary database into the person record. */
  936.  
  937.          ROLL_BIT < DBROLL_BIT ||
  938.  
  939.    /* Also test that HERITABLE_FLAG_MASK lies only in the left half.
  940.       This will be necessary in the code below which reads in the
  941.       "modifier_set" field from the database. */
  942.    
  943.          (HERITABLE_FLAG_MASK & 0x0000FFFF)) {
  944.       init_error("constants not consistent");
  945.  
  946.       final_exit(1);
  947.    }
  948.  
  949.    /* Read in the calls database, then start the user interface package,
  950.       whatever that might be, and finally create all the call menus.
  951.       If we are writing a call list, we do all this differently.
  952.       The user interface is never actually started, and we exit
  953.       from the program after writing the list. */
  954.  
  955.    build_database(call_list_mode);
  956.  
  957.    the_array = main_call_lists[call_list_any];
  958.    heapsort(number_of_calls[call_list_any]);
  959.  
  960.    /* Now the permanent array "main_call_lists[call_list_any]" has all the legal calls,
  961.          including name pointer fields containing the original text with "@" escapes,
  962.          sorted alphabetically.
  963.       The remaining tasks are to make the subcall lists for other setups (e.g.
  964.          those calls legal from columns), and clean up the names that we will actually
  965.          display in the menus (no "@" signs) and initialize the menus with the
  966.          cleaned-up and subsetted text. */
  967.  
  968.    global_main_call_name_list = (char **) get_mem(abs_max_calls * sizeof(char *));
  969.    create_call_name_list();
  970.  
  971.    /* Now temporary array "global_main_call_name_list" has the menu-presentable
  972.       form of the text corresponding to "main_call_lists[call_list_any]". */
  973.  
  974.    /* Do special stuff if we are reading or writing a call list file. */
  975.  
  976.    if (call_list_mode != call_list_mode_none) {
  977.       if (call_list_mode == call_list_mode_abridging) {
  978.          char abridge_call[100];
  979.          int i, j;
  980.    
  981.          while (read_from_call_list_file(abridge_call, 99)) {
  982.             /* Remove the newline character. */
  983.             abridge_call[strlen(abridge_call)-1] = '\0';
  984.             /* Search through the call name list for this call.
  985.                Why don't we use a more efficient search, based on the fact
  986.                that the call list has been alphabetized?  Because it was
  987.                alphabetized before the '@' escapes were expanded.  It
  988.                is no longer in alphabetical order. */
  989.             for (i=0; i<number_of_calls[call_list_any]; i++) {
  990.                if (!strcmp(abridge_call, global_main_call_name_list[i])) {
  991.                   /* Delete this call and move all subsequent calls down one position. */
  992.                   for (j=i+1; j<number_of_calls[call_list_any]; j++) {
  993.                      global_main_call_name_list[j-1] = global_main_call_name_list[j];
  994.                      main_call_lists[call_list_any][j-1] = main_call_lists[call_list_any][j];
  995.                   }
  996.                   number_of_calls[call_list_any]--;
  997.                   break;
  998.                }
  999.             }
  1000.          }
  1001.       }
  1002.       else {      /* Writing a list of some kind. */
  1003.          int i;
  1004.          for (i=0; i<number_of_calls[call_list_any]; i++) {
  1005.             write_to_call_list_file(global_main_call_name_list[i]);
  1006.          }
  1007.       }
  1008.  
  1009.       /* Close the file. */
  1010.       if (close_call_list_file())
  1011.          exit_program(1);
  1012.  
  1013.       if (call_list_mode != call_list_mode_abridging)
  1014.          return;   /* That's all! */
  1015.    }
  1016.  
  1017.    /* Now the array "main_call_lists[call_list_any]" and "global_main_call_name_list"
  1018.          have the stuff for the calls that we will actually use.
  1019.       The remaining tasks are to make the subcall lists for other setups (e.g.
  1020.          those calls legal from columns), and initialize the menus with the
  1021.          subsetted text. */
  1022.  
  1023.    uims_preinitialize();
  1024.  
  1025.    /* This is the universal menu. */
  1026.    create_menu(call_list_any, global_main_call_name_list);
  1027.  
  1028.    /* Create the special call menus for restricted setups. */
  1029.  
  1030.    test_starting_setup(call_list_1x8, test_setup_1x8);           /* RH grand wave */
  1031.    test_starting_setup(call_list_l1x8, test_setup_l1x8);         /* LH grand wave */
  1032.    test_starting_setup(call_list_dpt, test_setup_dpt);           /* DPT */
  1033.    test_starting_setup(call_list_cdpt, test_setup_cdpt);         /* completed DPT */
  1034.    test_starting_setup(call_list_rcol, test_setup_rcol);         /* RCOL */
  1035.    test_starting_setup(call_list_lcol, test_setup_lcol);         /* LCOL */
  1036.    test_starting_setup(call_list_8ch, test_setup_8ch);           /* 8CH */
  1037.    test_starting_setup(call_list_tby, test_setup_tby);           /* TBY */
  1038.    test_starting_setup(call_list_lin, test_setup_lin);           /* LIN */
  1039.    test_starting_setup(call_list_lout, test_setup_lout);         /* LOUT */
  1040.    test_starting_setup(call_list_rwv, test_setup_rwv);           /* RWV */
  1041.    test_starting_setup(call_list_lwv, test_setup_lwv);           /* LWV */
  1042.    test_starting_setup(call_list_r2fl, test_setup_r2fl);         /* R2FL */
  1043.    test_starting_setup(call_list_l2fl, test_setup_l2fl);         /* L2FL */
  1044.  
  1045.    create_misc_call_lists();
  1046.  
  1047.    /* This was just temporary, for copying into menus. */
  1048.    free_mem(global_main_call_name_list);
  1049.  
  1050.    /* These were global to the initialization, but they go away also. */
  1051.    free_mem(global_temp_call_list);
  1052.    free_mem(global_temp_call_name_list);
  1053. }
  1054.