home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / games / volume13 / okbridge / part05 < prev    next >
Encoding:
Internet Message Format  |  1992-01-12  |  54.4 KB

  1. Path: uunet!zaphod.mps.ohio-state.edu!uwm.edu!ogicse!zephyr.ens.tek.com!master!saab!billr
  2. From: billr@saab.CNA.TEK.COM (Bill Randle)
  3. Newsgroups: comp.sources.games
  4. Subject: v13i020:  okbridge - computer-mediated bridge game, Part05/07
  5. Message-ID: <2279@masterCNA.TEK.COM>
  6. Date: 10 Jan 92 16:45:02 GMT
  7. Article-I.D.: masterCN.2279
  8. Sender: news@masterCNA.TEK.COM
  9. Lines: 1870
  10. Approved: billr@saab.CNA.TEK.COM
  11.  
  12. Submitted-by: mclegg@cs.UCSD.EDU (Matthew Clegg)
  13. Posting-number: Volume 13, Issue 20
  14. Archive-name: okbridge/Part05
  15. Environment: BSD-derived Unix, curses, sockets
  16.  
  17.  
  18.  
  19. #! /bin/sh
  20. # This is a shell archive.  Remove anything before this line, then unpack
  21. # it by saving it into a file and typing "sh file".  To overwrite existing
  22. # files, type "sh file -c".  You can also feed this as standard input via
  23. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  24. # will see the following message at the end:
  25. #        "End of archive 5 (of 7)."
  26. # Contents:  display.c email.c okbridge.help ps.c
  27. # Wrapped by billr@saab on Fri Jan 10 08:31:29 1992
  28. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  29. if test -f 'display.c' -a "${1}" != "-c" ; then 
  30.   echo shar: Will not clobber existing file \"'display.c'\"
  31. else
  32. echo shar: Extracting \"'display.c'\" \(17419 characters\)
  33. sed "s/^X//" >'display.c' <<'END_OF_FILE'
  34. X/* display.c -- Display functions for netbridge program.
  35. X ! 
  36. X ! Copyright (C) 1990,1991 by Matthew Clegg
  37. X ! 
  38. X ! This program may be copied and distributed freely.  Please do not
  39. X ! charge money for this program or for any program derived from it.
  40. X ! If you modify this program, then include a notice stating plainly
  41. X ! that your program is derived from the okbridge program and is not
  42. X ! the same as the official okbridge program.
  43. X !
  44. X ! I welcome any suggestions for improvement to okbridge, and 
  45. X ! I would be especially happy to receive improved source code.
  46. X ! If you have comments or suggestions, or if you would like to
  47. X ! join the okbridge mailing list, then write to
  48. X !
  49. X !   mclegg@cs.ucsd.edu
  50. X !
  51. X*/
  52. X#include <stdio.h>
  53. X#include <string.h>
  54. X#include "globals.h"
  55. X#include "terminal.h"
  56. Xtypedef int window[4];
  57. X/* Conceptually, we think of the screen as being divided into a number
  58. X   of windows, where each window describes one particular type of activity
  59. X   or aspect of the game.  Therefore, we make the following definitions,
  60. X   although these are only guidelines for operation of the display.
  61. XName of
  62. XWindow               Ymin    Xmin    Height    Width
  63. X-------             ----    ----    ----    ----            */
  64. Xwindow title          = { 1,    1,    6,    25};
  65. Xwindow top_hand      = { 2,    30,    4,    26};
  66. Xwindow scores         = { 1,    59,    6,    26};
  67. Xwindow left_hand     = { 8,    6,    6,    18};
  68. Xwindow playing_board = { 5,    27,    9,    26};
  69. Xwindow bidding_board = { 5,    1,    9,    58};
  70. Xwindow right_hand    = { 8,    56,    6,    23};
  71. Xwindow input         = { 13,    1,    6,    26};
  72. Xwindow status         = { 18,    1,    1,    78};
  73. Xwindow bottom_hand   = { 13,    30,    4,    26};
  74. Xwindow help         = { 13,    53,    6,    26};
  75. Xwindow converse         = { 19,    1,    6,    78};
  76. X#define XMIN(w)        w[1]
  77. X#define YMIN(w)         w[0]
  78. X#define XMAX(w)        (w[1] + w[3] - 1)
  79. X#define YMAX(w)        (w[0] + w[2] - 1)
  80. X#define HEIGHT(w)    w[2]
  81. X#define WIDTH(w)    w[3]
  82. X
  83. Xstatic int PLAYERHAND_X [4];
  84. Xstatic int PLAYERHAND_Y [4]; 
  85. Xstatic int CARDPOS_X    [4];
  86. Xstatic int CARDPOS_Y    [4];
  87. Xstatic char *position_names [4];
  88. Xstatic int comments_suspended = 0;
  89. Xstatic char line_buf [81];
  90. Xstatic char status_message_buf[81];
  91. Xstatic underline (ymin, xmin, length)
  92. X       int ymin, xmin, length;
  93. X/* Prints a line of hyphens BELOW the field beginning at (ymin,xmin),
  94. X *  of given length.
  95. X */
  96. X{
  97. X    int i;
  98. X    for (i = 0; i < length; i++)
  99. X        line_buf[i] = '-';
  100. X    line_buf[length] = '\0';
  101. X    print (ymin+1, xmin, line_buf);
  102. X};
  103. Xstatic clear_screen_area (ymin, xmin, height, width)
  104. X       int ymin, xmin, height, width;
  105. X{
  106. X    int i;
  107. X    for (i = 0; i < width; i++) line_buf[i] = ' ';
  108. X    line_buf[width] = '\0';
  109. X    for (i = 0; i < height; i++) print (ymin+i, xmin, line_buf);
  110. X};
  111. XReset_Display ()
  112. X/* Redraws the main features of the screen.  Used in the process
  113. X * of doing a 'refresh'.
  114. X */
  115. X{
  116. X    int i;
  117. X    char program_name[20];
  118. X    sprintf (program_name, "OKBRIDGE %s%s", major_revision_level,
  119. X         minor_revision_level);
  120. X    clear_screen ();
  121. X    /* Display the title of the program: */
  122. X    print (YMIN(title), XMIN(title),  program_name);
  123. X/*    print (YMIN(title)+1, XMIN(title), "MTC    JUNE 90"); */
  124. X    /* Setup the scoreboard: */
  125. X    if (side_of(local_player) == SIDE_NS) {
  126. X      print (YMIN(scores), XMIN(scores) + 8,   "   WE");
  127. X      print (YMIN(scores), XMIN(scores) + 16,  " THEY");
  128. X    } else {
  129. X      print (YMIN(scores), XMIN(scores) + 16,  "   WE");
  130. X      print (YMIN(scores), XMIN(scores) + 8,   " THEY");
  131. X    };
  132. X    underline (YMIN(scores), XMIN(scores) + 8, 5);
  133. X    underline (YMIN(scores), XMIN(scores) + 16, 5);
  134. X    print (YMIN(scores)+2, XMIN(scores), "TRICKS");
  135. X    print (YMIN(scores)+3, XMIN(scores), "VUL");
  136. X
  137. X    switch (scoring_mode) {
  138. X      case RUBBER_SCORING:
  139. X          print (YMIN(scores)+4, XMIN(scores), "ABOVE");
  140. X          print (YMIN(scores)+5, XMIN(scores), "BELOW");
  141. X          print (YMIN(title)+1,  XMIN(title),  "HAND");
  142. X        break;
  143. X      case CHICAGO_SCORING:
  144. X          print (YMIN(scores)+4, XMIN(scores), "TOTAL");
  145. X          print (YMIN(scores)+5, XMIN(scores), "PART");
  146. X          print (YMIN(title)+1,  XMIN(title),  "HAND");
  147. X        break;
  148. X      case DUPLICATE_SCORING:
  149. X      case EMAIL_SCORING:
  150. X          print (YMIN(scores)+4, XMIN(scores), "TOTAL");
  151. X          print (YMIN(scores)+5, XMIN(scores), "PREV");
  152. X          print (YMIN(title)+1,  XMIN(title),  "BOARD");
  153. X        break;
  154. X      case IMP_SCORING:
  155. X          print (YMIN(scores)+4, XMIN(scores), "TOTAL");
  156. X          print (YMIN(scores)+5, XMIN(scores), "IMP");
  157. X          print (YMIN(title)+1,  XMIN(title),  "BOARD");
  158. X        break;
  159. X    };
  160. X    sprintf (program_name, "%d", current_deal_no);
  161. X    print (YMIN(title)+1, XMIN(title)+6, program_name);
  162. X    /* Setup the input area: */
  163. X    print (TALK_ROW, TALK_COL, "TALK");
  164. X    /* Setup the conversational area: */
  165. X    for (i = 0; i <= XMAX(converse); i++) line_buf[i] = '-';
  166. X    line_buf[XMAX(converse)+1] = '\0';
  167. X    print (YMIN(converse), XMIN(converse), line_buf);
  168. X    for (i = YMIN(converse)+1; i <= YMAX(converse); i++) {
  169. X        print (i, XMIN(converse), "|");
  170. X        print (i, XMAX(converse)+1, "|");
  171. X    };
  172. X};
  173. XInitialize_Display ()
  174. X/* Should be called once when the program starts up. */
  175. X{ 
  176. X/*    Initialize_Terminal (); */ 
  177. X    Reset_Display ();
  178. X
  179. X    PLAYERHAND_X [local_player] = XMIN(bottom_hand);
  180. X    PLAYERHAND_Y [local_player] = YMIN(bottom_hand);
  181. X    PLAYERHAND_X [player_next[local_player]] = XMIN(left_hand);
  182. X    PLAYERHAND_Y [player_next[local_player]] = YMIN(left_hand);
  183. X    PLAYERHAND_X [player_partner[local_player]] = XMIN(top_hand);
  184. X    PLAYERHAND_Y [player_partner[local_player]] = YMIN(top_hand);
  185. X    PLAYERHAND_X [player_prev[local_player]] = XMIN(right_hand);
  186. X    PLAYERHAND_Y [player_prev[local_player]] = YMIN(right_hand);
  187. X
  188. X    CARDPOS_Y[local_player] = YMAX(playing_board) - 2;
  189. X    CARDPOS_X[local_player] = (XMAX(playing_board) + 
  190. X                   XMIN(playing_board))/2;
  191. X    CARDPOS_Y[player_next[local_player]] = (YMAX(playing_board) + 
  192. X                        YMIN(playing_board))/2;
  193. X    CARDPOS_X[player_next[local_player]] = XMIN(playing_board) + 3;
  194. X    CARDPOS_Y[player_partner[local_player]] = YMIN(playing_board) + 2;
  195. X    CARDPOS_X[player_partner[local_player]] = (XMAX(playing_board) + 
  196. X                           XMIN(playing_board))/2;
  197. X    CARDPOS_Y[player_prev[local_player]] = (YMAX(playing_board) + 
  198. X                        YMIN(playing_board))/2;
  199. X    CARDPOS_X[player_prev[local_player]] = XMAX(playing_board) - 4;
  200. X    position_names[0] = player_names [local_player];
  201. X    position_names[1] = player_names [player_next[local_player]];
  202. X    position_names[2] = player_names [player_partner[local_player]];
  203. X    position_names[3] = player_names [player_prev[local_player]];
  204. X
  205. X    status_message_buf[0] = '\0';
  206. X};
  207. XRefresh_Display ()
  208. X/* Resets the terminal display and redraws everything. */
  209. X{
  210. X    int i, j, p;
  211. X    Reset_Display ();
  212. X    Display_Tricks_Taken ();
  213. X    Display_Above_Line_Points ();
  214. X    Display_Below_Line_Points ();
  215. X    Display_Vulnerabilities ();
  216. X    Refresh_Player_Comments ();
  217. X    if (game_mode == STARTUP_MODE) {
  218. X        ;
  219. X    } else if (game_mode == BIDDING_MODE) {
  220. X        Display_Bidding_Board ();
  221. X        Display_Hand_for_Bidding (local_player);
  222. X        p = dealer;
  223. X        for (i = 0; i < no_bids; i++) {
  224. X            Display_Bid (i/4 + 1, p);
  225. X            p = player_next [p];
  226. X        };
  227. X                Display_Bidder (p);
  228. X        print (PLAY_ROW, PLAY_COL, "BID ");
  229. X    } else if (game_mode == PLAYING_MODE) {
  230. X        Display_Contract (); 
  231. X        Display_Playing_Board ();
  232. X        Display_Hand (local_player);
  233. X        if ((trick > 1) || (no_plays > 0))
  234. X          Display_Hand (dummy);
  235. X        if (local_player == dummy)
  236. X          Display_Hand (declarer);
  237. X#ifdef LOOPBACK_MODE
  238. X        Display_Hand (player_next[local_player]);    /* DBG */
  239. X        Display_Hand (player_partner[local_player]);    /* DBG */
  240. X        Display_Hand (player_prev[local_player]);    /* DBG */
  241. X#endif
  242. X#ifdef TWOPLAYER_MODE
  243. X        Display_Hand (player_partner[local_player]);
  244. X#endif
  245. X        p = leader;
  246. X        for (i = 0; i < no_plays; i++) {
  247. X            Display_Play (p, plays[p]);
  248. X            p = player_next[p];
  249. X        };
  250. X                Display_Player (p);
  251. X        print (PLAY_ROW, PLAY_COL, "PLAY");
  252. X          } else if (game_mode == REVIEW_MODE) {
  253. X        Display_Contract (); 
  254. X        Display_Playing_Board ();
  255. X        Display_Player (-1);
  256. X        Display_Below_Line_Points ();
  257. X        Display_Above_Line_Points ();
  258. X        for (i = 0; i < 4; i++)
  259. X          Display_Hand (i);
  260. X/*
  261. X        Display_Status 
  262. X          ("REVIEW OF THE HAND -- PRESS RETURN ON A BLANK LINE TO PROCEED");
  263. X*/
  264. X          };
  265. X    Refresh_Status_Display ();
  266. X
  267. X};
  268. X
  269. XDisplay_Tricks_Taken ()
  270. X{
  271. X    sprintf (line_buf,"%5d   %5d",tricks[SIDE_NS], tricks[SIDE_EW]);
  272. X    print (YMIN(scores)+2,XMIN(scores)+8, line_buf);
  273. X};
  274. XDisplay_Above_Line_Points ()
  275. X{
  276. X    sprintf (line_buf,"%5d   %5d",above_line[SIDE_NS],
  277. X        above_line[SIDE_EW]);
  278. X    print (YMIN(scores)+4,XMIN(scores)+8, line_buf);
  279. X};
  280. XDisplay_Below_Line_Points ()
  281. X{
  282. X  sprintf (line_buf,"%5d   %5d",below_line[SIDE_NS],
  283. X       below_line[SIDE_EW]);
  284. X  print (YMIN(scores)+5,XMIN(scores)+8, line_buf);
  285. X};
  286. XDisplay_Vulnerabilities   ()
  287. X{
  288. X    char *nsv, *ewv;
  289. X    if (vulnerable[SIDE_NS]) nsv = "  YES";
  290. X    else              nsv = "   NO";
  291. X    if (vulnerable[SIDE_EW]) ewv = "  YES";
  292. X    else              ewv = "   NO";
  293. X    sprintf (line_buf, "%s   %s",nsv,ewv);
  294. X    print (YMIN(scores)+3, XMIN(scores)+8, line_buf);
  295. X};
  296. XClear_Bidding_Board ()
  297. X{
  298. X    int x, y, h, w;
  299. X
  300. X    x = XMIN(bidding_board);
  301. X    y = YMIN(bidding_board);
  302. X    h = HEIGHT(bidding_board);
  303. X    w = WIDTH(bidding_board);
  304. X    clear_screen_area (y, x, h, w);
  305. X    clear_screen_area (PLAY_ROW, 1, 1, 10);
  306. X};
  307. XDisplay_Bidding_Board ()
  308. X/* The bidding display is given as four columns, similar to that found
  309. X   in many bridge books.  At the top of each column is printed the
  310. X   corresponding input parameter string to identify the bidder. */
  311. X{
  312. X    int i;
  313. X    char *first, *second, *third, *fourth, board_no_buf[10];
  314. X    Clear_Bidding_Board ();
  315. X    first  = player_names [PLAYER_NORTH];
  316. X    second = player_names [player_next[PLAYER_NORTH]];
  317. X    third  = player_names [player_partner[PLAYER_NORTH]];
  318. X    fourth = player_names [player_prev[PLAYER_NORTH]];
  319. X    print(YMIN(bidding_board), XMIN(bidding_board)+05, first);
  320. X    print(YMIN(bidding_board), XMIN(bidding_board)+15, second);
  321. X    print(YMIN(bidding_board), XMIN(bidding_board)+25, third);
  322. X    print(YMIN(bidding_board), XMIN(bidding_board)+35, fourth);
  323. X    underline(YMIN(bidding_board),XMIN(bidding_board)+05,strlen(first));
  324. X    underline(YMIN(bidding_board),XMIN(bidding_board)+15,strlen(second));
  325. X    underline(YMIN(bidding_board),XMIN(bidding_board)+25,strlen(third));
  326. X    underline(YMIN(bidding_board),XMIN(bidding_board)+35,strlen(fourth));
  327. X
  328. X    sprintf (board_no_buf, "%d", current_deal_no);
  329. X    print (YMIN(title)+1, XMIN(title)+6, board_no_buf);
  330. X
  331. X};
  332. Xstatic Display_suit (y, x, cards)
  333. X     int y, x; suit_type cards;
  334. X/* Displays the cards in a given suit held by a player.  As input,
  335. X * cards[] is an array of 13 elements, where cards[i] is TRUE if the
  336. X * player holds the given card.  Displays the cards as a string on
  337. X * the terminal, beginning at coordinates <y,x>.
  338. X */
  339. X{
  340. X    int i;
  341. X    for (i = 12; i >= 0; i--)
  342. X        if (cards[i])
  343. X            print (y, x++, rank_names[i]);
  344. X};
  345. XDisplay_Hand_for_Bidding (pos)
  346. Xint pos;
  347. X{
  348. X    int i, x, y;
  349. X    suit_type h;
  350. X    y = YMIN(bidding_board);
  351. X    x = XMIN(bidding_board) + 45;
  352. X    clear_screen_area (y, x, HEIGHT(bidding_board),
  353. X        XMAX(bidding_board)-x+1);
  354. X    for (i = 0; i < 6; i++)
  355. X        print (y+i, x, "|");
  356. X    x+=1;
  357. X    print (y, x, player_names[pos]);
  358. X    underline (y, x, strlen(player_names[pos]));
  359. X    h = current_hand[pos];
  360. X    print (y+2, x, "S "); Display_suit (y+2, x+2, h+39);
  361. X    print (y+3, x, "H "); Display_suit (y+3, x+2, h+26);
  362. X    print (y+4, x, "D "); Display_suit (y+4, x+2, h+13);
  363. X    print (y+5, x, "C "); Display_suit (y+5, x+2, h);
  364. X};
  365. XDisplay_Bidder (player)
  366. X    int player;
  367. X{
  368. X    char bid_buf[80];
  369. X    sprintf (bid_buf, "%s's BID        ", player_names[player]);
  370. X    print (YMIN(title)+2, XMIN(title), bid_buf);
  371. X};
  372. XDisplay_Bid (round, player)
  373. X     int round, player;
  374. X{
  375. X    int x, y, bid, position;
  376. X    char *bid_string;
  377. X    y = YMIN(bidding_board) + round + 1;
  378. X    sprintf (line_buf, " %2d", round);
  379. X    print (y, XMIN(bidding_board), line_buf);
  380. X
  381. X/* 
  382. X    if (player == dealer) position = 0;
  383. X    else if (player == player_next[dealer]) position = 1;
  384. X    else if (player == player_partner[dealer]) position = 2;
  385. X    else position = 3;
  386. X*/
  387. X    y++; 
  388. X    for (x = dealer; x < 4; x++)
  389. X        if (x == player) y--;
  390. X
  391. X    position = player;
  392. X    x = XMIN(bidding_board) + 10 * position + 5;
  393. X    bid = bids[player][round-1];
  394. X    if (bid == BID_PASS)
  395. X        bid_string = "--";
  396. X    else
  397. X        bid_string = bid_names[bid];
  398. X    print (y, x, bid_string);
  399. X};
  400. XDisplay_Contract ()
  401. X{
  402. X    char double_buf[40], contract_buf[60];
  403. X    clear_screen_area (YMIN(title)+2, XMIN(title), HEIGHT(title),
  404. X               WIDTH(title));
  405. X    if (redoubled)
  406. X        sprintf (double_buf,"  REDOUBLED");
  407. X    else if (doubled)
  408. X        sprintf (double_buf, "  DOUBLED");
  409. X    else
  410. X        double_buf[0] = '\0';
  411. X    sprintf (contract_buf, "%1d%s (%s)%s",contract,suit_names[trump_suit],
  412. X        player_names[declarer], double_buf);
  413. X    print (YMIN(title)+3, XMIN(title), contract_buf);
  414. X}
  415. XClear_Playing_Board ()
  416. X{
  417. X    clear_screen_area (YMIN(playing_board), XMIN(playing_board),
  418. X        HEIGHT(playing_board), WIDTH(playing_board));
  419. X    clear_screen_area (YMIN(left_hand), XMIN(left_hand),
  420. X        HEIGHT(left_hand), WIDTH(left_hand));
  421. X    clear_screen_area (YMIN(right_hand), XMIN(right_hand),
  422. X        HEIGHT(right_hand), WIDTH(right_hand));
  423. X      clear_screen_area (YMIN(top_hand), XMIN(top_hand),
  424. X        HEIGHT(top_hand), WIDTH(top_hand));
  425. X    clear_screen_area (YMIN(bottom_hand), XMIN(bottom_hand),
  426. X        HEIGHT(bottom_hand), WIDTH(bottom_hand));
  427. X    clear_screen_area (YMIN(title)+3, XMIN(title), 1, WIDTH(title));
  428. X};
  429. XDisplay_Playing_Board ()
  430. X{
  431. X    int i;
  432. X/*    Clear_Playing_Board (); */
  433. X    for (i = 0; i < 4; i++)
  434. X        print (PLAYERHAND_Y[i]+1, PLAYERHAND_X[i]+12 -
  435. X               strlen(player_names[i]), player_names[i]);
  436. X    for (i = 0; i < WIDTH(playing_board)-1; i++) line_buf[i] = '-';
  437. X    line_buf[WIDTH(playing_board)-2] = '\0';
  438. X    print (YMIN(playing_board)+1,XMIN(playing_board)+1,line_buf);
  439. X    print (YMAX(playing_board)-1,XMIN(playing_board)+1,line_buf);
  440. X    for (i = YMIN(playing_board)+2; i < YMAX(playing_board)-1; i++) {
  441. X        print (i, XMIN(playing_board)+1, "|");
  442. X        print (i, XMAX(playing_board)-1, "|");
  443. X    };
  444. X};
  445. XDisplay_Player (player)
  446. X    int player;
  447. X{
  448. X    char play_buf[80];
  449. X    if (player < 0)
  450. X        sprintf (play_buf, "                    ");
  451. X    else if (player == dummy)
  452. X        sprintf (play_buf, "DUMMY'S PLAY        ");
  453. X    else
  454. X        sprintf (play_buf, "%s's PLAY        ",
  455. X             player_names[player]);
  456. X    print (YMIN(title)+4, XMIN(title), play_buf);
  457. X};
  458. XDisplay_Play (p, card)
  459. X     int p, card;
  460. X{
  461. X    int x, y, position;
  462. X    y = CARDPOS_Y [p];
  463. X    x = CARDPOS_X [p];
  464. X    if ((0 <= card) && (card < 52))
  465. X        print (y, x, card_names[card]);
  466. X    else
  467. X        print (y, x, "   ");
  468. X};
  469. XClear_Plays  ()
  470. X{
  471. X    Display_Play (PLAYER_NORTH, -1);
  472. X    Display_Play (PLAYER_EAST,  -1);
  473. X    Display_Play (PLAYER_SOUTH, -1);
  474. X    Display_Play (PLAYER_WEST,  -1);
  475. X};
  476. XDisplay_Hand (p)
  477. X     int p;
  478. X{
  479. X    int y, x, i;
  480. X    suit_type h;
  481. X    y = PLAYERHAND_Y [p];
  482. X    x = PLAYERHAND_X [p];
  483. X    for (i = 0; i < 4; i++)
  484. X        print (y+i, x, "                   ");
  485. X
  486. X    h = current_hand[p];
  487. X    print (y,   x+5-strlen(player_names[p]), player_names[p]);
  488. X    if (p == dummy)
  489. X        print (y+1, x+5-7, "(DUMMY)");
  490. X    print (y,   x+7, "S "); Display_suit (y,   x+10, h+39);
  491. X    print (y+1, x+7, "H "); Display_suit (y+1, x+10, h+26);
  492. X    print (y+2, x+7, "D "); Display_suit (y+2, x+10, h+13);
  493. X    print (y+3, x+7, "C "); Display_suit (y+3, x+10, h);
  494. X};
  495. X
  496. XClear_Hand (p)
  497. X     int p;
  498. X{
  499. X    int y, x, i;
  500. X    y = PLAYERHAND_Y [p];
  501. X    x = PLAYERHAND_X [p];
  502. X    for (i = 0; i < 4; i++)
  503. X        print (y+i, x, "                   ");
  504. X
  505. X    print (y,   x+5-strlen(player_names[p]), player_names[p]);
  506. X    if (p == dummy)
  507. X        print (y+1, x+5-7, "(DUMMY)");
  508. X};
  509. XDisplay_Status (message)
  510. X     char *message;
  511. X{
  512. X        Clear_Status_Display ();
  513. X    print (YMIN(status), XMIN(status), message);
  514. X    sprintf (status_message_buf, "%s", message);
  515. X    set_cursor (YMIN(status), XMIN(status) + strlen(message) + 1);
  516. X};
  517. XClear_Status_Display ()
  518. X{
  519. X    clear_screen_area (YMIN(status), XMIN(status), 1, WIDTH(status));
  520. X    status_message_buf [0] = '\0';
  521. X};
  522. X
  523. XRefresh_Status_Display ()
  524. X{
  525. X    clear_screen_area (YMIN(status), XMIN(status), 1, WIDTH(status));
  526. X    print (YMIN(status), XMIN(status), status_message_buf);
  527. X    set_cursor (YMIN(status), 
  528. X            XMIN(status) + strlen(status_message_buf) + 1);
  529. X};
  530. X/* The bottom part of the screen is used for the exchange of comments
  531. X   between the players.  The following procedures are used for managing
  532. X   this part of the display. */
  533. X#define COMMENT_LENGTH 78
  534. X#define COMMENT_BUF_SIZE 5
  535. Xtypedef char comment_line [COMMENT_LENGTH];
  536. Xtypedef comment_line comment_buf [COMMENT_BUF_SIZE];
  537. Xstatic  comment_buf  player_comments;
  538. Xstatic blank_out_comment (c)
  539. X     comment_line c;
  540. X{
  541. X    int i;
  542. X    for (i = 0; i < COMMENT_LENGTH-1; i++) c[i] = ' ';
  543. X    c[COMMENT_LENGTH-1] = '\0';
  544. X};
  545. Xstatic copy_string_to_comment (c, s)
  546. X     comment_line c; char *s;
  547. X{
  548. X    int i;
  549. X    blank_out_comment(c);
  550. X    i = 0;
  551. X    while ((s[i] != '\0') && (i < COMMENT_LENGTH-1)) {
  552. X        c[i] = s[i]; i++; }
  553. X};
  554. Xstatic scroll_player_comments ()
  555. X{
  556. X    int i, j;
  557. X    for (i = 0; i < COMMENT_BUF_SIZE - 1; i++)
  558. X        for (j = 0; j < COMMENT_LENGTH; j++) {
  559. X            player_comments[i][j] =
  560. X                player_comments[i+1][j];
  561. X        };
  562. X};
  563. XRefresh_Player_Comments ()
  564. X{
  565. X    int i, x, y;
  566. X    if (comments_suspended)
  567. X        return;
  568. X
  569. X    x = XMIN(converse) + 1;
  570. X    y = YMIN(converse) + 1;
  571. X    for (i = 0; i < COMMENT_BUF_SIZE; i++)
  572. X        print (y+i, x, player_comments[i]);
  573. X};
  574. XInitialize_Player_Comments ()
  575. X{
  576. X    int i;
  577. X    for (i = 0; i < COMMENT_BUF_SIZE; i++)
  578. X        blank_out_comment (player_comments[i]);
  579. X    Refresh_Player_Comments ();
  580. X};
  581. XDisplay_Player_Comment (player_name, comment)
  582. X     char *player_name, *comment;
  583. X{
  584. X    char message_buf [80];
  585. X    sprintf (message_buf, "%s: %s", player_name, comment);
  586. X    scroll_player_comments ();
  587. X    copy_string_to_comment (player_comments[COMMENT_BUF_SIZE-1],
  588. X                message_buf);
  589. X    Refresh_Player_Comments ();
  590. X};
  591. X
  592. X
  593. Xvoid Suspend_Comment_Display ()
  594. X{
  595. X    comments_suspended = 1;
  596. X};
  597. X
  598. Xvoid Continue_Comment_Display ()
  599. X{
  600. X    comments_suspended = 0;
  601. X};
  602. X
  603. END_OF_FILE
  604. if test 17419 -ne `wc -c <'display.c'`; then
  605.     echo shar: \"'display.c'\" unpacked with wrong size!
  606. fi
  607. # end of 'display.c'
  608. fi
  609. if test -f 'email.c' -a "${1}" != "-c" ; then 
  610.   echo shar: Will not clobber existing file \"'email.c'\"
  611. else
  612. echo shar: Extracting \"'email.c'\" \(18931 characters\)
  613. sed "s/^X//" >'email.c' <<'END_OF_FILE'
  614. X/* email.c
  615. X ! 
  616. X ! Copyright (C) 1990,1991 by Matthew Clegg
  617. X ! 
  618. X ! This program may be copied and distributed freely.  Please do not
  619. X ! charge money for this program or for any program derived from it.
  620. X ! If you modify this program, then include a notice stating plainly
  621. X ! that your program is derived from the okbridge program and is not
  622. X ! the same as the official okbridge program.
  623. X !
  624. X ! I welcome any suggestions for improvement to okbridge, and 
  625. X ! I would be especially happy to receive improved source code.
  626. X ! If you have comments or suggestions, or if you would like to
  627. X ! join the okbridge mailing list, then write to
  628. X !
  629. X !   mclegg@cs.ucsd.edu
  630. X !
  631. X *
  632. X * Implementation of procedures for reading and writing email
  633. X * duplicate files.
  634. X *
  635. X */
  636. X
  637. X#include <stdio.h>
  638. X#include <string.h>
  639. X
  640. Xextern char *malloc ();
  641. X
  642. X#ifdef HPUX
  643. X#define index(X,Y) strchr(X,Y)
  644. X#else 
  645. X#ifndef index
  646. Xextern char *index ();
  647. X#endif
  648. X#endif
  649. X
  650. X#include "globals.h"
  651. X#include "code.h"
  652. X#include "email.h"
  653. X
  654. Xextern char *strdup ();
  655. X
  656. Xchar *email_error_message = NULL;
  657. X
  658. Xstatic char *okbridge_check_string = NULL;
  659. Xstatic char *Unexpected_EOF_message = "Unexpected end of file";
  660. X
  661. Xstatic char *Position_Names [] = {"NORTH", "EAST", "SOUTH", "WEST"};
  662. Xstatic char *Full_Suit_Names [] = {"CLUBS", "DIAMONDS", "HEARTS", "SPADES"};
  663. X
  664. X
  665. X#ifdef NO_STRCASECMP
  666. Xint strcasecmp (s1, s2)
  667. X     char *s1, *s2;
  668. X{
  669. X  char c1, c2;
  670. X
  671. X  c1 = *(s1++); c2 = *(s2++);
  672. X  while (c1 && c2) {
  673. X    if (('a' <= c1) && (c1 <= 'z')) c1 = c1 - 'a' + 'A';
  674. X    if (('a' <= c2) && (c2 <= 'z')) c2 = c2 - 'a' + 'A';
  675. X    if (c1 < c2)
  676. X      return (-1);
  677. X    else if (c2 < c1)
  678. X      return (1);
  679. X    c1 = *(s1++); c2 = *(s2++);
  680. X  };
  681. X  if ((c1 == 0) && (c2 == 0))
  682. X    return (0);
  683. X  else if (c1 == 0)
  684. X    return (-1);
  685. X  else
  686. X    return (1);
  687. X    
  688. X};
  689. X
  690. Xint strncasecmp (s1, s2, count)
  691. X     char *s1, *s2; int count;
  692. X{
  693. X  int i, c1, c2;
  694. X
  695. X  for (i = 0; i < count; i++) {
  696. X    c1 = *(s1++); c2 = *(s2++);
  697. X    if ((c1 == 0) && (c2 == 0))
  698. X      return (0);
  699. X    else if (c1 == 0)
  700. X      return (-1);
  701. X    else if (c2 == 0)
  702. X      return (1);
  703. X    if (('a' <= c1) && (c1 <= 'z')) c1 = c1 - 'a' + 'A';
  704. X    if (('a' <= c2) && (c2 <= 'z')) c2 = c2 - 'a' + 'A';
  705. X    if (c1 < c2)
  706. X      return (-1);
  707. X    else if (c2 < c1)
  708. X      return (1);
  709. X  };
  710. X  return (0);
  711. X};
  712. X#endif
  713. X
  714. Xstatic void Initialize_Check_String ()
  715. X{
  716. X    char check_buf [100];
  717. X
  718. X    if (okbridge_check_string != NULL) return;
  719. X
  720. X    sprintf (check_buf, "%s %s",
  721. X        "This is an email duplicate file for Okbridge version",
  722. X        major_revision_level);
  723. X    okbridge_check_string = strdup (check_buf);
  724. X        
  725. X};
  726. X
  727. Xstatic int Read_Email_Line (cfile, buffer, buflen)
  728. X    Encoded_File *cfile; char *buffer; int buflen;
  729. X{
  730. X    int log;
  731. X
  732. X    do {
  733. X        log = Read_Encoded_Line (cfile, buffer, buflen);
  734. X        if (log < 0) return (log);
  735. X        while ((log > 0) && (buffer[log-1] == ' '))
  736. X            buffer[--log] = '\0';
  737. X    } while ((log == 0) || (buffer[0] == '#'));
  738. X    return (log);
  739. X};
  740. X
  741. Xstatic void fill_buffer (buf, fill_to, fill_char)
  742. X     char *buf; int fill_to; char fill_char;
  743. X{
  744. X    int i;
  745. X
  746. X    for (i = strlen(buf); i < fill_to; i++)
  747. X        buf[i] = fill_char;
  748. X    buf[fill_to] = '\0';
  749. X};
  750. X
  751. Xstatic void unfill_buffer (buf, fill_char)
  752. X     char *buf; char fill_char;
  753. X{
  754. X    int n = strlen(buf);
  755. X
  756. X    while ((n > 0) && (buf[n-1] == fill_char))
  757. X        buf[--n] = '\0';
  758. X};
  759. X
  760. Xint Read_Email_Duplicate_File (filename, email_struct)
  761. X    char *filename; struct Email_Duplicate_struct **email_struct;
  762. X/* Reads an email duplicate file.  If successful, then allocates a
  763. X   structure to represent the file and returns a pointer to that
  764. X   structure in email_struct.  Returns 0 in this case.  If an error
  765. X   occurred opening the file, then returns -1 with the system error
  766. X   code in errno.  If an error is detected in the format of the file,
  767. X   then returns 1.
  768. X*/
  769. X#define EREAD(cfile,buf,buflen) if (Read_Email_Line(cfile,buf,buflen) == -1) return (1);
  770. X/* #define FORMAT_ERROR(s) do{email_error_message=strdup(s); return (1);}while(0) */
  771. X#define FORMAT_ERROR(s) {email_error_message=strdup(s); return (1);}
  772. X{
  773. X    int error_code, i, j, pair_no, n;
  774. X    float ns_mp, ew_mp;
  775. X    char line_buffer[100], ne_name[20], sw_name[20], bid_buf[20],
  776. X        contractor_buf[20], dealer_buf[20], vuln_buf[20];
  777. X    struct Email_Duplicate_struct *e;
  778. X    Encoded_File *ef;
  779. X    Email_Board *bhead, *btail;
  780. X    Email_Score *shead, *stail;
  781. X    Email_Comment *chead, *ctail;
  782. X    char *player_string = "NESW";
  783. X    char *d;
  784. X
  785. X    email_error_message = Unexpected_EOF_message;
  786. X
  787. X    Initialize_Check_String ();
  788. X    error_code = Reset_Encoded_File (filename, okbridge_check_string, &ef);
  789. X    if (error_code < 0) 
  790. X        return (error_code);
  791. X    else if (error_code > 0)
  792. X        FORMAT_ERROR ("Could not find Okbridge check string");
  793. X
  794. X    e = (struct Email_Duplicate_struct *)
  795. X        malloc (sizeof (struct Email_Duplicate_struct));
  796. X
  797. X    EREAD(ef, line_buffer, 100);
  798. X    sscanf (line_buffer, "%d %d", &e->nboards, &e->npairs);
  799. X
  800. X    e->player_list = (Email_Pair *)
  801. X        malloc (sizeof(Email_Pair) * (e->npairs + 1));
  802. X
  803. X    for (i = 0; i < e->npairs; i++) {
  804. X        EREAD(ef, line_buffer, 100);
  805. X        sscanf (line_buffer, "%d %s %s", &pair_no, ne_name, sw_name);
  806. X        if (pair_no == 0)
  807. X            FORMAT_ERROR ("Error in list of player pairs");
  808. X        e->player_list[pair_no].ne = strdup(ne_name);
  809. X        e->player_list[pair_no].sw = strdup(sw_name);
  810. X        e->player_list[pair_no].match_points = 0;
  811. X    };
  812. X
  813. X    bhead = btail = (Email_Board *) malloc (sizeof(Email_Board));
  814. X    shead = (Email_Score *) malloc (sizeof(Email_Score));
  815. X    chead = (Email_Comment *) malloc(sizeof(Email_Comment));
  816. X    for (i = 0; i < e->nboards; i++) {
  817. X        EREAD (ef, line_buffer, 100);
  818. X        btail->next = (Email_Board *) malloc(sizeof(Email_Board));
  819. X        btail = btail->next;
  820. X        ctail = chead;
  821. X        while (line_buffer[0] == '*') {
  822. X            ctail->next = (Email_Comment *) 
  823. X                malloc(sizeof(Email_Comment));
  824. X            ctail = ctail->next;
  825. X            ctail->comment = strdup (line_buffer+1);
  826. X            EREAD (ef, line_buffer, 100);
  827. X        };
  828. X        ctail->next = NULL;
  829. X        btail->pre_script = chead->next;
  830. X            
  831. X        btail->ns_vulnerable = btail->ew_vulnerable = 0;
  832. X        sscanf (line_buffer, "%s %s", dealer_buf, vuln_buf);
  833. X
  834. X        if (!strcasecmp(dealer_buf, "NORTH"))
  835. X          btail->dealer = PLAYER_NORTH;
  836. X        else if (!strcasecmp(dealer_buf, "EAST"))
  837. X          btail->dealer = PLAYER_EAST;
  838. X        else if (!strcasecmp(dealer_buf, "SOUTH"))
  839. X          btail->dealer = PLAYER_SOUTH;
  840. X        else if (!strcasecmp(dealer_buf, "WEST"))
  841. X          btail->dealer = PLAYER_WEST;
  842. X        else
  843. X          FORMAT_ERROR ("Error in dealer");
  844. X
  845. X        if (!strcasecmp(vuln_buf, "BOTH"))
  846. X          btail->ns_vulnerable = btail->ew_vulnerable = 1;
  847. X        else if (!strcasecmp(vuln_buf, "NS"))
  848. X          btail->ns_vulnerable = 1;
  849. X        else if (!strcasecmp(vuln_buf, "EW"))
  850. X          btail->ew_vulnerable = 1;
  851. X        else if (strcasecmp(vuln_buf, "NONE"))
  852. X          FORMAT_ERROR ("Error in vulnerabilities");
  853. X        
  854. X        EREAD (ef, line_buffer, 100);
  855. X        for (j = 0; j < 52; j++) {
  856. X            d = index (player_string, line_buffer[j]);
  857. X            if (d == 0)
  858. X                FORMAT_ERROR ("Error in deal.");
  859. X            btail->deal[j] = d - player_string;
  860. X        };
  861. X        stail = shead;
  862. X        EREAD (ef, line_buffer, 100);
  863. X        ctail = chead;
  864. X        while (line_buffer[0] == '*') {
  865. X            ctail->next = (Email_Comment *) 
  866. X                malloc(sizeof(Email_Comment));
  867. X            ctail = ctail->next;
  868. X            ctail->comment = strdup (line_buffer+1);
  869. X            EREAD (ef, line_buffer, 100);
  870. X        };
  871. X        ctail->next = NULL;
  872. X        btail->post_script = chead->next;
  873. X        while (strcmp(line_buffer, "--")) {
  874. X            stail->next = (Email_Score *) 
  875. X                malloc(sizeof(Email_Score));
  876. X            stail = stail->next;
  877. X            sscanf (line_buffer, 
  878. X                "%d %d %s %s %d %d %f %f",
  879. X                &(stail->ns_pair), &(stail->ew_pair), 
  880. X                bid_buf, contractor_buf, &(stail->result), 
  881. X                &(stail->ns_score), &ns_mp, &ew_mp);
  882. X            if ((stail->ns_pair == 0) || (stail->ew_pair == 0))
  883. X                FORMAT_ERROR 
  884. X                  ("Erroneous pair number in score record");
  885. X            unfill_buffer (bid_buf, 'Z');
  886. X            n = strlen (bid_buf);
  887. X            stail->doubled = 0;
  888. X            if (n >= 3) {
  889. X                if (!strcmp(bid_buf+n-2, "-X")) {
  890. X                    stail->doubled = BID_DOUBLE;
  891. X                    bid_buf[n-2] = '\0';
  892. X                } else if (!strcmp(bid_buf+n-3, "-XX")){
  893. X                    stail->doubled = BID_REDOUBLE;
  894. X                    bid_buf[n-3] = '\0';
  895. X                };
  896. X            };
  897. X            n = 0;
  898. X            for (n = 0; (bid_names[n] != NULL) && 
  899. X                strcmp(bid_names[n], bid_buf); n++);
  900. X            if (bid_names[n] == NULL)
  901. X                FORMAT_ERROR ("Error in bid in score record");
  902. X            stail->bid = n;
  903. X            if (!strcmp(contractor_buf, "N"))
  904. X                stail->contractor = PLAYER_NORTH;
  905. X            else if (!strcmp(contractor_buf, "E"))
  906. X                stail->contractor = PLAYER_EAST;
  907. X            else if (!strcmp(contractor_buf, "S"))
  908. X                stail->contractor = PLAYER_SOUTH;
  909. X            else if (!strcmp(contractor_buf, "W"))
  910. X                stail->contractor = PLAYER_WEST;
  911. X            else
  912. X                FORMAT_ERROR
  913. X                    ("Error in declarer in score record");
  914. X            EREAD (ef, line_buffer, 100);
  915. X        };
  916. X        stail->next = NULL;
  917. X        btail->score_list = shead->next;
  918. X    };
  919. X    e->board_list = bhead->next;
  920. X    btail->next = NULL;
  921. X    Close_Encoded_File (ef);
  922. X
  923. X    free (bhead);
  924. X    free (shead);
  925. X    free (chead);
  926. X    *email_struct = e;
  927. X    return (0);
  928. X};
  929. X
  930. Xint Write_Email_Duplicate_File (filename, encode_flag, email_struct)
  931. X    char *filename; int encode_flag;
  932. X    struct Email_Duplicate_struct *email_struct; 
  933. X/* Writes an email duplicate file to filename.  If encode_flag is true,
  934. X   then encodes critical parts of the file.  If no errors, returns 0.
  935. X   Otherwise, returns -1 with the system error code in errno.
  936. X*/
  937. X#define UPRINT(e,s) if (Write_Unencoded_Line(e,s)) return (-1);
  938. X#define EPRINT(e,s) if (encode_flag? Write_Encoded_Line(e,s): Write_Unencoded_Line(e,s)) return (-1);
  939. X{
  940. X    int error_code, i, j, k, board_number, name_printed, some_name_printed;
  941. X    char line_buffer[100], bid_buf[20], contractor_buf[20], double_buf [20];
  942. X    Encoded_File *ef;
  943. X    struct Email_Duplicate_struct *e;
  944. X    Email_Board *blist;
  945. X    Email_Score *slist;
  946. X    Email_Comment *clist;
  947. X    char *player_string = "NESW";
  948. X    char *dealer_name;
  949. X
  950. X    Initialize_Check_String ();
  951. X    error_code = Rewrite_Encoded_File (filename, okbridge_check_string, 
  952. X        &ef);
  953. X    if (error_code) return (error_code);
  954. X
  955. X    e = email_struct;
  956. X    sprintf (line_buffer, "%d %d", e->nboards, e->npairs);
  957. X    UPRINT (ef, "# nboards npairs");
  958. X    UPRINT (ef, line_buffer);
  959. X
  960. X    for (blist = e->board_list; blist != NULL; blist = blist->next)
  961. X        Compute_Board_Match_Points (blist);
  962. X    for (i = 1; i <= e->npairs; i++)
  963. X        e->player_list[i].match_points = 0;
  964. X    for (blist = e->board_list; blist != NULL; blist = blist->next) {
  965. X        for (slist=blist->score_list; slist!=NULL; slist=slist->next) {
  966. X            e->player_list[slist->ns_pair].match_points +=
  967. X                slist->ns_match_points;
  968. X            e->player_list[slist->ew_pair].match_points +=
  969. X                slist->ew_match_points;
  970. X        };
  971. X    };
  972. X
  973. X    if (e->npairs > 0) {
  974. X      UPRINT (ef, "");
  975. X      sprintf (line_buffer, "# %4s %10s %10s    %s",
  976. X           "pair", "north/east", "south/west", "match points");
  977. X      UPRINT (ef, line_buffer);
  978. X    };
  979. X    for (i = 1; i <= e->npairs; i++) {
  980. X        sprintf (line_buffer, "  %4d %-10s %-10s %6.1f", i,
  981. X            e->player_list[i].ne, e->player_list[i].sw,
  982. X            0.5 * ((float) e->player_list[i].match_points));
  983. X        UPRINT (ef, line_buffer);
  984. X    };
  985. X
  986. X    UPRINT (ef, "");
  987. X    board_number = 1;
  988. X    for (blist = e->board_list; blist != NULL; blist = blist->next) {
  989. X        sprintf (line_buffer, "# board %d", board_number++);
  990. X        UPRINT (ef, line_buffer);
  991. X        for (clist=blist->pre_script; clist!=NULL; clist=clist->next) {
  992. X            sprintf (line_buffer, "* %s", clist->comment);
  993. X            UPRINT (ef, line_buffer);
  994. X        };
  995. X
  996. X        if (!encode_flag) {
  997. X          for (i = 0; i < 4; i++) {
  998. X            some_name_printed = 0;
  999. X            sprintf (line_buffer, "# %-5s  ", Position_Names[i]);
  1000. X            for (j = 0; j < 4; j++) {
  1001. X               name_printed = 0;
  1002. X               for (k = 12; k >= 0; k--) {
  1003. X                if (blist->deal[13*j + k] == i) {
  1004. X                  if (!name_printed) {
  1005. X                    if (some_name_printed) {
  1006. X                      sprintf (line_buffer+strlen(line_buffer),
  1007. X                    ",  ");
  1008. X                    } else
  1009. X                      some_name_printed = 1;
  1010. X                    sprintf (line_buffer+strlen(line_buffer),
  1011. X                    "%s:", Full_Suit_Names[j]);
  1012. X                    name_printed = 1;
  1013. X                  };
  1014. X                  sprintf (line_buffer+strlen(line_buffer),
  1015. X                    " %s", rank_names[k]);
  1016. X                };
  1017. X              };
  1018. X            };
  1019. X            UPRINT (ef, line_buffer);
  1020. X          };
  1021. X        };
  1022. X            
  1023. X        UPRINT (ef, "# Dealer Vulnerabilities");
  1024. X        dealer_name = Position_Names[blist->dealer];
  1025. X        if (blist->ns_vulnerable && blist->ew_vulnerable)
  1026. X            sprintf (line_buffer, "%-6s BOTH", dealer_name);
  1027. X        else if (blist->ns_vulnerable)
  1028. X            sprintf (line_buffer, "%-6s NS", dealer_name);
  1029. X        else if (blist->ew_vulnerable)
  1030. X            sprintf (line_buffer, "%-6s EW", dealer_name);
  1031. X        else
  1032. X            sprintf (line_buffer, "%-6s NONE", dealer_name);
  1033. X        UPRINT (ef, line_buffer);
  1034. X
  1035. X        for (i = 0; i < 52; i++)
  1036. X            line_buffer[i] = player_string[blist->deal[i]];
  1037. X        line_buffer[52] = '\0';
  1038. X        EPRINT (ef, line_buffer);
  1039. X        for (clist=blist->post_script;clist!=NULL;clist=clist->next) {
  1040. X            sprintf (line_buffer, "* %s", clist->comment);
  1041. X            EPRINT (ef, line_buffer);
  1042. X        };
  1043. X        sprintf (line_buffer, 
  1044. X            "#%s%3s %3s %-9s %2s %6s %8s %6s %6s",
  1045. X            (encode_flag? " ": ""),
  1046. X            "ns", "ew", "bid", "by", "result",
  1047. X            "score", "ns-mp", "ew-mp");
  1048. X        UPRINT (ef, line_buffer);
  1049. X        for (slist = blist->score_list; slist != NULL; 
  1050. X          slist = slist->next) {
  1051. X            switch (slist->doubled) {
  1052. X              case 0:
  1053. X                double_buf[0] = '\0';
  1054. X                break;
  1055. X              case BID_DOUBLE:
  1056. X                sprintf (double_buf, "-X");
  1057. X                break;
  1058. X              case BID_REDOUBLE:
  1059. X                sprintf (double_buf, "-XX");
  1060. X                break;
  1061. X            };
  1062. X            sprintf (bid_buf, "%s%s", bid_names[slist->bid], 
  1063. X                double_buf);
  1064. X            if (encode_flag)
  1065. X                fill_buffer (bid_buf, 7, 'Z');
  1066. X            switch (slist->contractor) {
  1067. X              case PLAYER_NORTH:
  1068. X                sprintf (contractor_buf, "N");
  1069. X                break;
  1070. X              case PLAYER_EAST:
  1071. X                sprintf (contractor_buf, "E");
  1072. X                break;
  1073. X              case PLAYER_SOUTH:
  1074. X                sprintf (contractor_buf, "S");
  1075. X                break;
  1076. X              case PLAYER_WEST:
  1077. X                sprintf (contractor_buf, "W");
  1078. X                break;
  1079. X            };
  1080. X            if (encode_flag)
  1081. X              sprintf (line_buffer, 
  1082. X                " %3d %3d %-9s %-2s %06d %08d %6.1f %6.1f",
  1083. X                slist->ns_pair, slist->ew_pair, 
  1084. X                bid_buf, contractor_buf, slist->result, 
  1085. X                slist->ns_score, 
  1086. X                0.5 * ((float) slist->ns_match_points),
  1087. X                0.5 * ((float) slist->ew_match_points));
  1088. X            else
  1089. X              sprintf (line_buffer, 
  1090. X                " %3d %3d %-9s %-2s %+6d %8d %6.1f %6.1f",
  1091. X                slist->ns_pair, slist->ew_pair, 
  1092. X                bid_buf, contractor_buf, slist->result, 
  1093. X                slist->ns_score,
  1094. X                0.5 * ((float) slist->ns_match_points),
  1095. X                0.5 * ((float) slist->ew_match_points));
  1096. X            EPRINT (ef, line_buffer);
  1097. X        };
  1098. X        UPRINT (ef, "--");
  1099. X    };
  1100. X
  1101. X    Close_Encoded_File (ef);
  1102. X    return (0);
  1103. X
  1104. X};
  1105. X
  1106. Xvoid Free_Email_Duplicate_Struct (email_struct)
  1107. X    struct Email_Duplicate_struct *email_struct;
  1108. X/* Simply de-allocates email_struct and its substructures. */
  1109. X{
  1110. X    Email_Board *blist;
  1111. X    Email_Score *slist;
  1112. X    Email_Comment *clist;
  1113. X    int i;
  1114. X
  1115. X    if (email_struct == NULL) return;
  1116. X
  1117. X    if (email_struct->player_list != NULL) {
  1118. X        for (i = 1; i <= email_struct->npairs; i++) {
  1119. X            free (email_struct->player_list[i].ne);
  1120. X            free (email_struct->player_list[i].sw);
  1121. X        };
  1122. X        free (email_struct->player_list);
  1123. X    };
  1124. X
  1125. X    while (email_struct->board_list != NULL) {
  1126. X        blist = email_struct->board_list;
  1127. X        while (blist->pre_script != NULL) {
  1128. X            clist = blist->pre_script;
  1129. X            blist->pre_script = clist->next;
  1130. X            free (clist);
  1131. X        };
  1132. X        while (blist->post_script != NULL) {
  1133. X            clist = blist->post_script;
  1134. X            blist->post_script = clist->next;
  1135. X            free (clist);
  1136. X        };
  1137. X        while (blist->score_list != NULL) {
  1138. X            slist = blist->score_list;
  1139. X            blist->score_list = slist->next;
  1140. X            free (slist);
  1141. X        };
  1142. X        email_struct->board_list = blist->next;
  1143. X        free (blist);
  1144. X    };
  1145. X    free (email_struct);
  1146. X        
  1147. X};
  1148. X
  1149. Xstruct Email_Duplicate_struct *New_Email_Duplicate_Struct ()
  1150. X/* Allocates an empty email duplicate structure to be used for
  1151. X   recording email duplicate hands.
  1152. X*/
  1153. X{
  1154. X    struct Email_Duplicate_struct *e;
  1155. X
  1156. X    e = (struct Email_Duplicate_struct *)
  1157. X        malloc (sizeof(struct Email_Duplicate_struct));
  1158. X    e->nboards = e->npairs = 0;
  1159. X    e->player_list = (Email_Pair *) malloc(sizeof(Email_Pair));
  1160. X    e->board_list = NULL;
  1161. X    return (e);
  1162. X};
  1163. X
  1164. Xint Add_Email_Pair (email_struct, ne_name, sw_name)
  1165. X    struct Email_Duplicate_struct *email_struct;
  1166. X    char *ne_name, *sw_name;
  1167. X/* Appends a new player-pair to the list of players in email_struct.
  1168. X   Returns the pair number assigned to them.
  1169. X*/
  1170. X{
  1171. X    Email_Pair *p;
  1172. X
  1173. X    email_struct->npairs += 1;
  1174. X    email_struct->player_list = (Email_Pair *) 
  1175. X        realloc(email_struct->player_list,
  1176. X            sizeof(Email_Pair) * (email_struct->npairs + 1));
  1177. X    p = email_struct->player_list + email_struct->npairs;
  1178. X    p->ne = strdup (ne_name);
  1179. X    p->sw = strdup (sw_name);
  1180. X    p->match_points = 0;
  1181. X    return (email_struct->npairs);
  1182. X};
  1183. X
  1184. XEmail_Board *Add_Email_Board (email_struct, new_deal)
  1185. X    struct Email_Duplicate_struct *email_struct;
  1186. X    hand new_deal;
  1187. X/* Appends the given hand to the list of boards in email_struct. 
  1188. X   Returns a pointer to the newly allocated board.
  1189. X*/
  1190. X{
  1191. X    int i;
  1192. X    Email_Board *b;
  1193. X
  1194. X    if (email_struct->nboards++) {
  1195. X        b = email_struct->board_list;
  1196. X        while (b->next != NULL) b = b->next;
  1197. X        b->next = (Email_Board *) malloc(sizeof(Email_Board));
  1198. X        b = b->next;
  1199. X    } else
  1200. X        b = email_struct->board_list =
  1201. X            (Email_Board *) malloc(sizeof(Email_Board));
  1202. X
  1203. X    b->score_list = NULL;
  1204. X    b->pre_script = b->post_script = NULL;
  1205. X    b->next = NULL;
  1206. X    for (i = 0; i < 52; i++)
  1207. X        b->deal[i] = new_deal[i];
  1208. X    return (b);
  1209. X};
  1210. X
  1211. Xvoid Record_Email_Score (email_board,
  1212. X    ns_pair, ew_pair, bid, doubled, contractor, result, ns_score)
  1213. X    Email_Board *email_board;
  1214. X    int ns_pair, ew_pair, bid, contractor, result, ns_score;
  1215. X/* Constructs a new score record containing the information
  1216. X   ns_pair, ew_pair, bid, contractor, result and ns_score.
  1217. X   Links this into the list of score records associated to email_board.
  1218. X   The list is maintained in ascending order according to ns_score.
  1219. X*/
  1220. X{
  1221. X    Email_Score *s, *p;
  1222. X
  1223. X    s = (Email_Score *) malloc (sizeof(Email_Score));
  1224. X
  1225. X    s->ns_pair = ns_pair;
  1226. X    s->ew_pair = ew_pair;
  1227. X    s->bid = bid;
  1228. X    s->doubled = doubled;
  1229. X    s->contractor = contractor;
  1230. X    s->result = result;
  1231. X    s->ns_score = ns_score;
  1232. X    s->ns_match_points = 0;
  1233. X    s->ew_match_points = 0;
  1234. X
  1235. X    if (email_board->score_list == NULL) {
  1236. X        email_board->score_list = s;
  1237. X        s->next = NULL;
  1238. X    } else if (email_board->score_list->ns_score >= s->ns_score) {
  1239. X        s->next = email_board->score_list;
  1240. X        email_board->score_list = s;
  1241. X    } else {
  1242. X        p = email_board->score_list;
  1243. X        while ((p->next != NULL) && (p->next->ns_score < s->ns_score))
  1244. X            p = p->next;
  1245. X        s->next = p->next;
  1246. X        p->next = s;
  1247. X    };
  1248. X};
  1249. X
  1250. Xvoid Compute_Board_Match_Points (email_board)
  1251. X    Email_Board *email_board;
  1252. X/* Computes the ns_match_points and ew_match_points fields for each of
  1253. X   the records in the score list of email_board.  The number recorded
  1254. X   is actually twice the number of match points awarded.  
  1255. X*/
  1256. X{
  1257. X    int rank, ties, top_board;
  1258. X    Email_Score *s, *p;
  1259. X
  1260. X    rank = 0;
  1261. X    s = email_board->score_list;
  1262. X    while (s != NULL) {
  1263. X        /* Count the number of ties at the current rank. */
  1264. X        p = s->next;
  1265. X        ties = 0;
  1266. X        while ((p != NULL) && (p->ns_score == s->ns_score)) {
  1267. X            ties++;
  1268. X            p = p->next;
  1269. X        };
  1270. X        /* Award ns match points for each pair at current rank. */
  1271. X        top_board = rank + rank + ties;
  1272. X        p = s;
  1273. X        while ((p != NULL) && (p->ns_score == s->ns_score)) {
  1274. X            p->ns_match_points = top_board;
  1275. X            p = p->next;
  1276. X        };
  1277. X        s = p;
  1278. X        rank += 1 + ties;
  1279. X    };
  1280. X
  1281. X    /* Award ew match points for each pair. */
  1282. X    rank = (rank-1)*2;
  1283. X    for (s = email_board->score_list; s != NULL; s = s->next)
  1284. X        s->ew_match_points = rank - s->ns_match_points;
  1285. X        
  1286. X};
  1287. END_OF_FILE
  1288. if test 18931 -ne `wc -c <'email.c'`; then
  1289.     echo shar: \"'email.c'\" unpacked with wrong size!
  1290. fi
  1291. # end of 'email.c'
  1292. fi
  1293. if test -f 'okbridge.help' -a "${1}" != "-c" ; then 
  1294.   echo shar: Will not clobber existing file \"'okbridge.help'\"
  1295. else
  1296. echo shar: Extracting \"'okbridge.help'\" \(10765 characters\)
  1297. sed "s/^X//" >'okbridge.help' <<'END_OF_FILE'
  1298. X# okbridge.help -- help file for the okbridge program
  1299. X#  
  1300. X# Copyright (C) 1990,1991 by Matthew Clegg
  1301. X# 
  1302. X# This program may be copied and distributed freely.  Please do not
  1303. X# charge money for this program or for any program derived from it.
  1304. X# If you modify this program, then include a notice stating plainly
  1305. X# that your program is derived from the okbridge program and is not
  1306. X# the same as the official okbridge program.
  1307. X#
  1308. X# I welcome any suggestions for improvement to okbridge, and 
  1309. X# I would be especially happy to receive improved source code.
  1310. X# If you have comments or suggestions, or if you would like to
  1311. X# join the okbridge mailing list, then write to
  1312. X#
  1313. X#   mclegg@cs.ucsd.edu
  1314. X#
  1315. X#
  1316. X# The help information in this file is organized as a series of topics.
  1317. X# The first entry in the file is interpreted to be the main topic, 
  1318. X# i.e., it is the entry which is displayed if no particular keyword 
  1319. X# is given.  Each topic entry has a header line which contains an 
  1320. X# identifying keyword and a descriptive phrase.  This is followed 
  1321. X# by the body of the entry and is terminated by an end-of-entry line.  
  1322. X#
  1323. X# The format of an entry is
  1324. X#
  1325. X# <keyword> <phrase>
  1326. X# help text
  1327. X# more help text
  1328. X# ...
  1329. X# last help text
  1330. X# --
  1331. X#
  1332. X# Comment lines such as this one are not printed in the help display.
  1333. X# A page break is given by placing the '^' character on a line by itself.
  1334. X#
  1335. Xmain          A general description of the program
  1336. X
  1337. X                    Welcome to OKBRIDGE, version 1.3
  1338. X
  1339. X     This is a computer-moderated bridge program.  It allows four
  1340. Xpeople at different locations on the Internet to play bridge together.
  1341. XThe computer shuffles the cards and communicates bids and plays between
  1342. Xthe players.
  1343. X
  1344. X
  1345. X     The help system is organized as a series of topics, each
  1346. Xidentified by a keyword.  To obtain information on a particular topic,
  1347. Xjust type '/HELP topic'.  The information displayed on the screen
  1348. Xreflects the current state of the game and is meant to be
  1349. Xself-explanatory.  The input to the program is command-oriented.  See
  1350. Xthe topic '/help input' for more information on this subject.
  1351. X
  1352. X     Good luck at the bridge table!
  1353. X
  1354. X--
  1355. Xbidding     information on how to enter a bid
  1356. X
  1357. X              Information about Bidding
  1358. X                      ----------- ----- -------
  1359. X
  1360. XThe format of a bid is one of the following:
  1361. X
  1362. X     <level> <trump>
  1363. X     DOUBLE               (or X)
  1364. X     REDOUBLE             (or XX)
  1365. X     PASS                 (or P)
  1366. X
  1367. Xwhere 
  1368. X     <level> is either 1, 2, 3, 4, 5, 6, or 7
  1369. X
  1370. X     <suit>  is one of
  1371. X         NOTRUMP  (or NT      or N)
  1372. X         SPADES   (or SPADE   or S)
  1373. X         HEARTS   (or HEART   or H)
  1374. X         DIAMONDS (or DIAMOND or D)
  1375. X         CLUBS    (or CLUB    or C)
  1376. Xexamples
  1377. X     P, 1C, 1 CLUB, 1N, 1NT, 1 NOTRUMP, 2H, 2 HEARTS, X, DOUBLE, XX
  1378. X--
  1379. Xcommands      Commands for controlling the program
  1380. X
  1381. X     /BELL [ON|OFF]
  1382. X       By default, the okbridge program rings the terminal's bell whenever
  1383. X       it requests input from you.  However, this can be disabled by
  1384. X       typing '/BELL OFF'.  The state of the bell can be toggled with ^G.
  1385. X
  1386. X     /CLAIM [n]
  1387. X       This command 'claims' n additional tricks for the declarer.
  1388. X       If n is omitted, then all remaining tricks are claimed.
  1389. X       The other players are shown the declarer's hand and are
  1390. X       asked whether or not they agree to the declarer's request.
  1391. X       If both agree, then the hand is ended early.  This command can
  1392. X       be used only by the declarer and only when it is declarer's or
  1393. X       dummy's turn to play.
  1394. X
  1395. X     /DEFAULT [ON | OFF]
  1396. X       This command controls whether or not defaults will be provided
  1397. X       for bids, plays and questions.  This mode can be toggled with ^D.
  1398. X
  1399. X^
  1400. X     /HELP [topic]
  1401. X       Type '/HELP' alone to obtain general help, or type
  1402. X       '/HELP topic' to obtain help about a particular topic.
  1403. X
  1404. X     /LOG [filename]
  1405. X       Typing '/LOG filename' causes this hand and subsequent hands
  1406. X       to be written to the file with name 'filename'.  Omitting
  1407. X       'filename' causes the current log file to be closed.
  1408. X
  1409. X     /PING
  1410. X       Sends an invisible message to each of the other players, which is
  1411. X       automatically echoed.  Reports the round-trip communication time.
  1412. X
  1413. X     /PROMPT [ON|OFF]
  1414. X       By default, the dummy is asked to press RETURN after the end
  1415. X       of each trick.  This allows the dummy to see each trick as
  1416. X       it is played.  This prompting can be disabled by typing
  1417. X       '/PROMPT OFF' (convenient if you need to run to the wc :-)
  1418. X       The prompt mode can be toggled with ^P.
  1419. X
  1420. X^
  1421. X     /QUIT
  1422. X       Terminates the program.
  1423. X
  1424. X     /REVIEW
  1425. X       Displays the bidding for review.  This is intended to be used
  1426. X       during the playing mode.  This command can be abbreviated with ^B.
  1427. X
  1428. X     /TALK message
  1429. X       Sends a short message to the other players.  This command can be used
  1430. X       when the program is waiting for you to enter a bid or a play.  
  1431. X       Not needed if the word 'TALK' is displayed to the left of the cursor.
  1432. X
  1433. X--
  1434. Xcontrols    Special control characters recognized by the program
  1435. XSpecial control characters recognized by the program
  1436. X------- ------- ---------- ---------- -- --- -------
  1437. X
  1438. X ^B   When used during the play of a hand, the bidding is displayed
  1439. X      for review.
  1440. X
  1441. X ^C   Quits the program.  (The program requests confirmation first.)
  1442. X
  1443. X ^D   Toggles the default input mode.  See the /DEFAULT command.
  1444. X
  1445. X ^G   Toggles the bell.  See the /BELL command.
  1446. X
  1447. X ^P   Toggles the prompt.  See the /PROMPT command.
  1448. X
  1449. X ^R   Refreshes the screen.
  1450. X
  1451. X ^T   Returns to talk mode if you have been asked to bid or play.
  1452. X
  1453. X ESC  Erases the input which has been typed so far.
  1454. X
  1455. XIn addition, if you press RETURN without typing anything, the program will
  1456. Xsupply a default input, which can then be entered by pressing RETURN again.
  1457. X
  1458. X--
  1459. Xcopyright     Copyright notice for the program
  1460. X                Copyright Notice
  1461. X                    --------- ------
  1462. X
  1463. XCopyright (C) 1990,1991 by Matthew Clegg
  1464. XThis program may be copied and distributed freely.  Please do not
  1465. Xcharge money for this program or for any program derived from it.
  1466. XIf you modify this program, then include a notice stating plainly
  1467. Xthat your program is derived from the okbridge program and is not
  1468. Xthe same as the official okbridge program.
  1469. X
  1470. XI welcome any suggestions for improvement to okbridge, and I would be
  1471. Xespecially happy to receive improved source code.  If you have
  1472. Xcomments or suggestions, or if you would like to join the okbridge
  1473. Xmailing list, then write to
  1474. X
  1475. X   mclegg@cs.ucsd.edu
  1476. X
  1477. X--
  1478. Xemail        Commands specific to email duplicate bridge
  1479. X     /DEAL [nhands]
  1480. X       This command can only be used by north when playing Email
  1481. X       duplicate bridge.  It causes nhands boards to be dealt and
  1482. X       played.  After they have been played, the results can be
  1483. X       /SAVEd and emailed to another foursome for play.
  1484. X
  1485. X     /LOAD filename
  1486. X       This command can only be used by north when playing Email
  1487. X       duplicate bridge.  It causes a series of boards to be read
  1488. X       from the file "filename".  
  1489. X
  1490. X     /SAVE filename
  1491. X       This command causes the set of boards which have been played
  1492. X       so far to be saved to the file with name filename.  These
  1493. X       boards can then be emailed to another foursome for competitive
  1494. X       play.  Note that the /SAVE command can be used by any player
  1495. X       at any time.  However, the previous results of play by other
  1496. X       foursomes will only be recorded if /SAVE is used by north.
  1497. X
  1498. X     /REPLAY filename
  1499. X       First /LOAD's "filename".  After the boards have been played,
  1500. X       automatically saves them along with the results back to "filename".
  1501. X--
  1502. Xinput         General info about entering input
  1503. X
  1504. X              How to Enter Input
  1505. X              --- -- ----- -----
  1506. X
  1507. XDuring normal operation, the bridge program is always in one of
  1508. Xthree 'input modes'.  The input which you type is interpreted according
  1509. Xto the input mode, which is displayed at the beginning of the line 
  1510. Xcontaining the cursor.  The input modes are
  1511. X
  1512. XMode       Interpretation
  1513. X----       --------------
  1514. XBID       The program is expecting you to enter your bid.
  1515. XPLAY       The program is expecting you to enter the card you wish to play.
  1516. XTALK       Any text that you enter will be transmitted to the other players.
  1517. X
  1518. XAs you type your text, you may use the backspace key to erase the last
  1519. Xcharacter.  The ESC key will erase all of the text you have typed.
  1520. X
  1521. XThere are number of commands which can be given to the program in any 
  1522. Xinput mode.  For information on these commands, type '/help commands'.
  1523. X
  1524. XAlso, there are a number of special control-characters which are
  1525. Xrecognized by the program.  For information about these, type 
  1526. X'/help controls.'
  1527. X
  1528. X--
  1529. Xmaillist        Information about the okbridge mailing lists
  1530. X
  1531. X              The Okbridge Mailing Lists
  1532. X                      --- -------- ------- -----
  1533. X
  1534. Xokbridge@cs.ucsd.edu
  1535. X  This list is intended for arranging bridge games.
  1536. X
  1537. Xokbridge-pgm@cs.ucsd.edu
  1538. X  This list is intended for announcing new bridge playing software and
  1539. X  updates to old bridge software and for discussing issues in computer
  1540. X  moderated bridge.
  1541. X
  1542. XTo join either list, send a message to the corresponding email address
  1543. Xwhose body contains the single line
  1544. X
  1545. X  ADD <list-name>
  1546. X
  1547. Xwhere <list-name> is okbridge or okbridge-pgm, as appropriate.
  1548. X
  1549. X--
  1550. Xnetwork       Setting up the network communications
  1551. X
  1552. X             Network Information
  1553. X             ------- -----------
  1554. X
  1555. XBefore the game can begin, the players must agree that one person will
  1556. Xact as the 'server'.  All messages transmitted by the program are then
  1557. Xmediated through this server.  When starting the program, the internet
  1558. Xname of the server must be specified on the command line.
  1559. X
  1560. XIf you usually play with the same four people, then you may want to
  1561. Xput the name of the server and your usual position into the .okbridgerc
  1562. Xfile.  The .okbridgerc file contains default information which is read
  1563. Xby the program before it starts.
  1564. X
  1565. X
  1566. X--
  1567. Xplaying   Information about how to enter a play
  1568. X              Information about Playing
  1569. X              ----------- ----- -------
  1570. X
  1571. XA card is played by writing
  1572. X     <suit> <rank>
  1573. X
  1574. Xwhere
  1575. X     <suit>  is one of
  1576. X         SPADES   (or SPADE   or S)
  1577. X         HEARTS   (or HEART   or H)
  1578. X         DIAMONDS (or DIAMOND or D)
  1579. X             CLUBS    (or CLUB    or C)
  1580. X
  1581. X     <rank>  is one of
  1582. X         2, 3, ..., 9, TEN (or T), JACK (or J), QUEEN (or Q),
  1583. X         KING (or K), ACE (or A)
  1584. X
  1585. XSome examples of cards are
  1586. X     CT, C T, C TEN, CLUB T, CLUB TEN, S3, SPADE3, SPADE 3
  1587. X
  1588. XNote that the order <suit> <rank> used in playing is reversed 
  1589. Xfrom the order <level> <trumpsuit> used in bidding.
  1590. X--
  1591. Xslam          A special message when a slam is made
  1592. X
  1593. X
  1594. X
  1595. X
  1596. X     Oh, what a beautiful mornin'!
  1597. X     Oh, what a beautiful day!
  1598. X     I got a beautiful feelin'
  1599. X     Ev'rything's goin' my way.
  1600. X     Oh, what a beautiful day.
  1601. X
  1602. X     ...
  1603. X
  1604. X              
  1605. X          words by Oscar Hammerstein II
  1606. X              from the musical, _Oklahoma_
  1607. X
  1608. END_OF_FILE
  1609. if test 10765 -ne `wc -c <'okbridge.help'`; then
  1610.     echo shar: \"'okbridge.help'\" unpacked with wrong size!
  1611. fi
  1612. # end of 'okbridge.help'
  1613. fi
  1614. if test -f 'ps.c' -a "${1}" != "-c" ; then 
  1615.   echo shar: Will not clobber existing file \"'ps.c'\"
  1616. else
  1617. echo shar: Extracting \"'ps.c'\" \(3779 characters\)
  1618. sed "s/^X//" >'ps.c' <<'END_OF_FILE'
  1619. X/* ps.c -- "parse-string" data structure.
  1620. X ! 
  1621. X ! Copyright (C) 1990,1991 by Matthew Clegg
  1622. X ! 
  1623. X ! This program may be copied and distributed freely.  Please do not
  1624. X ! charge money for this program or for any program derived from it.
  1625. X ! If you modify this program, then include a notice stating plainly
  1626. X ! that your program is derived from the okbridge program and is not
  1627. X ! the same as the official okbridge program.
  1628. X !
  1629. X ! I welcome any suggestions for improvement to okbridge, and 
  1630. X ! I would be especially happy to receive improved source code.
  1631. X ! If you have comments or suggestions, or if you would like to
  1632. X ! join the okbridge mailing list, then write to
  1633. X !
  1634. X !   mclegg@cs.ucsd.edu
  1635. X !
  1636. X */
  1637. X#ifdef __TURBOC__
  1638. X#include <alloc.h>
  1639. X#endif
  1640. X/* #include <ctype.h> */
  1641. X#include <stdio.h>
  1642. X#include "ps.h"
  1643. Xparse_string ps_alloc (n)
  1644. X    int n;
  1645. X/* Returns a parse_string which can hold up to n bytes of text. */
  1646. X{
  1647. X    parse_string ps;
  1648. X    ps = (parse_string) malloc (n + PS_OFFSET + 1);
  1649. X    ps[PS_SIZE] = n;
  1650. X    return (ps);
  1651. X};
  1652. X/* void ps_reset(parse_string ps); */
  1653. X/* Clears a parse_string so that new data can be copied into it. */
  1654. Xps_put (ps, ch)
  1655. Xparse_string ps; char ch;
  1656. X/* void ps_put (parse_string ps, char ch) */
  1657. X/* Adds the character ch to the parse_string ps. */
  1658. X{
  1659. X    if (ps[PS_LENGTH] < ps[PS_SIZE])
  1660. X        ps[PS_OFFSET + ps[PS_LENGTH]++] = ch;
  1661. X};
  1662. Xps_copy (ps, s)
  1663. Xparse_string ps; char *s;
  1664. X/* void ps_copy (parse_string ps, char *s) */
  1665. X/* Copies the string s to the parse_string ps.
  1666. X * Resets ps before doing the copy.
  1667. X */
  1668. X{
  1669. X    ps[PS_POS] = ps[PS_LENGTH] = 0;
  1670. X    while ((*s != '\0') && (ps[PS_LENGTH] < ps[PS_SIZE]))
  1671. X        ps[PS_OFFSET + ps[PS_LENGTH]++] = *(s++);
  1672. X};
  1673. Xps_read (ps, fp)
  1674. Xparse_string ps; FILE *fp;
  1675. X/* void ps_read (parse_string ps, FILE *fp) */
  1676. X/* Copies the next text line from the file fp to the parse_string ps.
  1677. X * Resets ps before doing the copy.
  1678. X */
  1679. X{
  1680. X    char ch;
  1681. X    ps[PS_POS] = ps[PS_LENGTH] = 0;
  1682. X    ch = getc(fp);
  1683. X    while ((ch != '\n') && (ch != EOF)) {
  1684. X        if (ps[PS_LENGTH] < ps[PS_SIZE])
  1685. X            ps[PS_OFFSET + ps[PS_LENGTH]++] = ch;
  1686. X        ch = getc (fp);
  1687. X    };
  1688. X};
  1689. X/* char ps_scan (parse_string ps); */
  1690. X/* Returns the current character in the parse_string ps.
  1691. X * Does not advance the pointer in ps.
  1692. X */
  1693. Xint ps_matches (ps, key)
  1694. Xparse_string ps; char *key;
  1695. X/* int ps_matches (parse_string ps, char *key) */
  1696. X/* Returns TRUE if the next sequence of characters in the parse string
  1697. X * matches key.  If so, then advances the pointer in the parse string
  1698. X * past key.  Otherwise, returns FALSE.
  1699. X */
  1700. X{
  1701. X    int i;
  1702. X    char *text;
  1703. X    ps[PS_OFFSET + ps[PS_LENGTH]] = '\0';
  1704. X    text = ps + PS_OFFSET + ps[PS_POS];
  1705. X    for (i=0; key[i] != '\0'; i++)
  1706. X        if (key[i] != text[i])
  1707. X            return (0);
  1708. X    ps[PS_POS] += i;
  1709. X    return (1);
  1710. X};
  1711. Xint upper (ch)
  1712. Xint ch;
  1713. X{
  1714. X  if (('a' <= ch) && (ch <= 'z')) 
  1715. X    return (ch - 'a' + 'A');
  1716. X  else
  1717. X    return (ch);
  1718. X};
  1719. X
  1720. Xint ps_matches_ic (ps, key)
  1721. Xparse_string ps; char *key;
  1722. X/* int ps_matches_ic (parse_string ps, char *key) */
  1723. X/* Returns TRUE if the next sequence of characters in the parse string
  1724. X * matches key, after both are converted to upper case.  If so, then
  1725. X * advances the pointer in the parse string past key.
  1726. X */
  1727. X{
  1728. X    int i;
  1729. X    char *text;
  1730. X    ps[PS_OFFSET + ps[PS_LENGTH]] = '\0';
  1731. X    text = ps + PS_OFFSET + ps[PS_POS];
  1732. X    for (i=0; key[i] != '\0'; i++)
  1733. X      if (upper(key[i]) != upper(text[i]))
  1734. X        return (0);
  1735. X    ps[PS_POS] += i;
  1736. X    return (1);
  1737. X};
  1738. X/* void ps_next (parse_string ps); */
  1739. X/* Advances the pointer in the parse_string ps to the next character. */
  1740. X/* int ps_size  (parse_string ps); */
  1741. X/* Returns the number of characters allocated for text in ps. */
  1742. X/* int ps_length (parse_string ps); */
  1743. X/* Returns the number of characters of text currently used in ps. */
  1744. X/* int ps_pos (parse_string ps); */
  1745. X/* Returns the index of the current character in ps. */
  1746. END_OF_FILE
  1747. if test 3779 -ne `wc -c <'ps.c'`; then
  1748.     echo shar: \"'ps.c'\" unpacked with wrong size!
  1749. fi
  1750. # end of 'ps.c'
  1751. fi
  1752. echo shar: End of archive 5 \(of 7\).
  1753. cp /dev/null ark5isdone
  1754. MISSING=""
  1755. for I in 1 2 3 4 5 6 7 ; do
  1756.     if test ! -f ark${I}isdone ; then
  1757.     MISSING="${MISSING} ${I}"
  1758.     fi
  1759. done
  1760. if test "${MISSING}" = "" ; then
  1761.     echo You have unpacked all 7 archives.
  1762.     rm -f ark[1-9]isdone
  1763.     echo creating input.c from input.c.aa and input.c.ab
  1764.     cat input.c.aa input.c.ab >input.c
  1765.     rm -f input.c.aa input.c.ab
  1766. else
  1767.     echo You still need to unpack the following archives:
  1768.     echo "        " ${MISSING}
  1769. fi
  1770. ##  End of shell archive.
  1771. exit 0
  1772.