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

  1. Path: uunet!spool.mu.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: v13i019:  okbridge - computer-mediated bridge game, Part04/07
  5. Message-ID: <2278@masterCNA.TEK.COM>
  6. Date: 10 Jan 92 16:44:51 GMT
  7. Article-I.D.: masterCN.2278
  8. Sender: news@masterCNA.TEK.COM
  9. Lines: 1153
  10. Approved: billr@saab.CNA.TEK.COM
  11.  
  12. Submitted-by: mclegg@cs.UCSD.EDU (Matthew Clegg)
  13. Posting-number: Volume 13, Issue 19
  14. Archive-name: okbridge/Part04
  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 4 (of 7)."
  26. # Contents:  input.c.ab
  27. # Wrapped by billr@saab on Fri Jan 10 08:31:28 1992
  28. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  29. if test -f 'input.c.ab' -a "${1}" != "-c" ; then 
  30.   echo shar: Will not clobber existing file \"'input.c.ab'\"
  31. else
  32. echo shar: Extracting \"'input.c.ab'\" \(31325 characters\)
  33. sed "s/^X//" >'input.c.ab' <<'END_OF_FILE'
  34. Xstatic int Reserved_message (message)
  35. X     char *message;
  36. X/* Compares the given message to the list of card and bid names.  If a
  37. X   match is found, then returns true.  Otherwise, returns false.
  38. X*/
  39. X{
  40. X  char compare_buff[100], *ch;
  41. X  int i;
  42. X
  43. X  if (!strlen(message))
  44. X    return (1);
  45. X
  46. X  strcpy (compare_buff, message);
  47. X  ch = compare_buff;
  48. X  for (ch = compare_buff; *ch != '\0'; ch++)
  49. X    *ch = toupper(*ch);
  50. X
  51. X  for (i=0; i < 52; i++)
  52. X    if (!strcmp(card_names[i], compare_buff))
  53. X      return (1);
  54. X
  55. X  for (i=0; i < 38; i++)
  56. X    if (!strcmp(bid_names[i], compare_buff))
  57. X      return (1);
  58. X
  59. X  return (0);
  60. X  
  61. X};
  62. X
  63. Xstatic load_email_file (filename)
  64. X     char *filename;
  65. X/* Attempts to read a sequence of deals from the email duplicate file
  66. X . with name filename.
  67. X */
  68. X{
  69. X  char msg_buf [80];
  70. X
  71. X  total_no_deals = current_deal_no = 0;
  72. X  current_board = NULL;
  73. X  if (email_record != NULL)
  74. X    Free_Email_Duplicate_Struct (email_record);
  75. X  email_record = NULL;
  76. X  current_deal_no = 
  77. X    Read_Email_Duplicate_File (filename, &email_record);
  78. X  if (current_deal_no) {
  79. X    if (email_record != NULL)
  80. X      Free_Email_Duplicate_Struct 
  81. X    (email_record);
  82. X    email_record = NULL;
  83. X    if (current_deal_no > 0) {    
  84. X      sprintf (msg_buf, "%s %d: %s", "FORMAT ERROR NEAR LINE", 
  85. X           codefile_line_no, email_error_message);
  86. X      Display_Player_Comment ("MODERATOR", msg_buf);
  87. X    } else {
  88. X      sprintf (msg_buf, "%s %s: %s", "ERROR IN READING", filename,
  89. X           sys_errlist[errno]);
  90. X      Display_Player_Comment ("MODERATOR", msg_buf);
  91. X    };
  92. X    email_record = New_Email_Duplicate_Struct ();
  93. X    current_deal_no = 0;
  94. X    replaying_mode = 0;
  95. X  } else {
  96. X    total_no_deals = email_record->nboards;
  97. X    current_board = email_record->board_list;
  98. X    replaying_mode = 1;
  99. X    sprintf (msg_buf, "LOADED %d BOARDS FROM %s.",
  100. X         total_no_deals, filename);
  101. X    Display_Player_Comment ("MODERATOR", msg_buf);
  102. X  };
  103. X  ns_pair_no = Add_Email_Pair (email_record,
  104. X                   player_names[PLAYER_NORTH], 
  105. X                   player_names[PLAYER_SOUTH]);
  106. X  ew_pair_no = Add_Email_Pair (email_record,
  107. X                   player_names[PLAYER_EAST], 
  108. X                   player_names[PLAYER_WEST]);
  109. X};
  110. X
  111. Xstatic void save_email_file (filename)
  112. X     char *filename;
  113. X{
  114. X  int error_flag;
  115. X  char msg_buf[80];
  116. X  
  117. X  error_flag = Write_Email_Duplicate_File (filename, 1, email_record);
  118. X  if (error_flag) {
  119. X    sprintf (msg_buf, "%s %s: %s", "ERROR IN WRITING", filename,
  120. X         sys_errlist[errno]);
  121. X    Display_Player_Comment ("MODERATOR", msg_buf);
  122. X  } else {
  123. X    sprintf (msg_buf, "WROTE %d %s %s.",
  124. X         email_record->nboards, "ENCODED BOARDS TO", filename);
  125. X    Display_Player_Comment ("MODERATOR", msg_buf);
  126. X    sprintf (msg_buf, "%s.plain", filename);
  127. X    error_flag = Write_Email_Duplicate_File (msg_buf, 0, email_record);
  128. X    sprintf (filename,"%s", msg_buf);
  129. X    if (error_flag) {
  130. X      sprintf (msg_buf, "%s %s: %s",
  131. X           "ERROR IN WRITING", filename, sys_errlist[errno]);
  132. X      Display_Player_Comment ("MODERATOR", msg_buf);
  133. X      error_flag = 0;
  134. X    } else {
  135. X      sprintf (msg_buf, "WROTE %d %s %s.",
  136. X           email_record->nboards, "UNENCODED BOARDS TO", filename);
  137. X      Display_Player_Comment ("MODERATOR", msg_buf);
  138. X    };
  139. X  };
  140. X};
  141. X
  142. Xstatic process_player_command (pc)
  143. X    player_command pc;
  144. X/* Determines whether the player command pc should be handled internally
  145. X . by the input module, or whether it should be passed upwards.  If it will
  146. X . be handled internally, then performs the appropriate action.  If it will
  147. X . be passed upwards, then places it in an appropriate queue to be handled
  148. X . later.
  149. X */
  150. X{
  151. X    char msg_buf[100], *word, *filename;
  152. X    int mils;    /* milliseconds elapsed between ping and echo */
  153. X    int error_flag;
  154. X    struct timeval ping_end;
  155. X    if ((pc->player_no == local_player) && disabled(pc->command)) {
  156. X        Display_Status ("THIS COMMAND CANNOT BE USED NOW");
  157. X        return;
  158. X    };
  159. X/*
  160. X    if ((pc->command != CMD_HELLO) && !players_here[pc->player_no])
  161. X      return;
  162. X*/
  163. X
  164. X    switch (pc->command) {
  165. X        case CMD_ERROR:
  166. X            break;    /* do nothing for erroneous commands. */
  167. X        case CMD_VULN:
  168. X            enqueue_command (pc);
  169. X            break;
  170. X        case CMD_RDEAL:
  171. X            enqueue_command (pc);
  172. X            if ((pc->player_no != local_player) &&
  173. X                (game_mode != DEALING_MODE)) {
  174. X              Display_Player_Comment ("MODERATOR",
  175. X                  "THE CARDS HAVE NOW BEEN DEALT.");
  176. X            };
  177. X            break;
  178. X        case CMD_BID:
  179. X            enqueue_command (pc);
  180. X            break;
  181. X        case CMD_PLAY:
  182. X            enqueue_command (pc);
  183. X            break;
  184. X        case CMD_FINISH:
  185. X            enqueue_command (pc);
  186. X            break;
  187. X        case CMD_HELLO:
  188. X            if (players_here[pc->player_no]) {
  189. X              sprintf (msg_buf, 
  190. X                  "THERE ARE TWO PEOPLE CLAIMING THE SEAT OF %s",
  191. X                  local_player_names [pc->player_no]);
  192. X              Display_Player_Comment ("MODERATOR", msg_buf);
  193. X              send_message_talk (msg_buf);
  194. X              Terminate_Program ("PROGRAM TERMINATING");
  195. X            };
  196. X            if (pc->player_no == local_player) {
  197. X                /* The following statement should never
  198. X                 * be executed: */
  199. X                break;
  200. X            } else {
  201. X                send_message_ack ();
  202. X                player_names[pc->player_no] =
  203. X                  strdup(pc->data.version_name +
  204. X                     VERSION_LENGTH);
  205. X                if (strlen(player_names[pc->player_no]) > 8)
  206. X                  player_names[pc->player_no][8] = '\0';
  207. X                     error_flag = verify_compatibility 
  208. X                  (pc->player_no, pc->data.version_name);
  209. X                if (!error_flag) {
  210. X                  sprintf (msg_buf,
  211. X                       "%s HAS JOINED THE GAME AS %s",
  212. X                       player_names[pc->player_no],
  213. X                       local_player_names[pc->player_no]);
  214. X                  Display_Player_Comment ("MODERATOR", 
  215. X                              msg_buf);
  216. X                  if (ring_my_bell) ring_bell ();
  217. X                  players_here [pc->player_no] = 1;
  218. X                }
  219. X            };
  220. X#ifdef TWOPLAYER_MODE
  221. X            players_here [player_partner[pc->player_no]] = 1;
  222. X#endif
  223. X            break;
  224. X        case CMD_ACK:
  225. X                verify_compatibility (pc->player_no,
  226. X                          pc->data.version_name);
  227. X                player_names[pc->player_no] =
  228. X             strdup(pc->data.version_name+VERSION_LENGTH);
  229. X            if (strlen(player_names[pc->player_no]) > 8)
  230. X              player_names[pc->player_no][8] = '\0';
  231. X            if (pc->player_no == local_player)
  232. X                send_message_ack ();
  233. X/*
  234. X            else if (game_mode != STARTUP_MODE) {
  235. X                sprintf (msg_buf, 
  236. X                    "ACKNOWLEDGMENT RECEIVED FROM %s", 
  237. X                    player_names[pc->player_no]);
  238. X                Display_Player_Comment ("MODERATOR", msg_buf);
  239. X            }
  240. X*/
  241. X            else if (!players_here[pc->player_no]) {
  242. X                sprintf (msg_buf,
  243. X                    "%s HAS JOINED THE GAME AS %s",
  244. X                     player_names[pc->player_no],
  245. X                     local_player_names[pc->player_no]);
  246. X                Display_Player_Comment ("MODERATOR", msg_buf);
  247. X            };
  248. X            players_here [pc->player_no] = 1;
  249. X#ifdef TWOPLAYER_MODE
  250. X            players_here [player_partner[pc->player_no]] = 1;
  251. X#endif
  252. X            break;
  253. X        case CMD_TALK:
  254. X            if (pc->player_no == local_player) {
  255. X                    if (Reserved_message (pc->data.message))
  256. X                    break;
  257. X                send_message_talk (pc->data.message);
  258. X            };
  259. X            Display_Player_Comment (player_names[pc->player_no],
  260. X                        pc->data.message);
  261. X            players_here [pc->player_no] = 1;
  262. X            break;
  263. X        case CMD_COMMENT:
  264. X            Display_Player_Comment ("MODERATOR", pc->data.message);
  265. X            break;
  266. X        case CMD_QUIT:
  267. X            if (pc->player_no == local_player)
  268. X                    Quit_program ();
  269. X            else {
  270. X                sprintf (msg_buf, "%s HAS QUIT.",
  271. X                    player_names[pc->player_no]);
  272. X                Display_Player_Comment ("MODERATOR",
  273. X                            msg_buf);
  274. X                if (game_mode == STARTUP_MODE)
  275. X                  players_here[pc->player_no] = 0;
  276. X                Close_Network_Connection 
  277. X                  (local_player_names[pc->player_no]);
  278. X            };
  279. X/*            soft_abort (); */
  280. X            break;
  281. X        case CMD_HELP:
  282. X            display_help (pc->data.topic);
  283. X            Refresh_Display ();
  284. X            break;
  285. X        case CMD_BELL:
  286. X            if (pc->data.bell == 0)  ring_my_bell = 0;
  287. X            if (pc->data.bell == 1)  ring_my_bell = 1;
  288. X            if (ring_my_bell) word = "ON";
  289. X            else          word = "OFF";
  290. X            sprintf (msg_buf, "THE BELL IS NOW %s", word);
  291. X            Display_Player_Comment ("MODERATOR", msg_buf);
  292. X            if (ring_my_bell) ring_bell ();
  293. X            break;
  294. X            case CMD_DEFAULT:
  295. X            if (pc->data.defaalt == 0) default_plays = 0;
  296. X            if (pc->data.defaalt == 1) default_plays = 1;
  297. X            if (default_plays) word = "ON";
  298. X            else               word = "OFF";
  299. X            sprintf (msg_buf, "DEFAULT INPUT MODE IS NOW %s", 
  300. X                 word);
  301. X            Display_Player_Comment ("MODERATOR", msg_buf);
  302. X            break;
  303. X            case CMD_REVIEW:
  304. X            Review_Bidding ();
  305. X            break;
  306. X        case CMD_PROMPT:
  307. X            if (pc->data.prompt == 0) prompt_dummy = 0;
  308. X            if (pc->data.prompt == 1) prompt_dummy = 1;
  309. X            if (prompt_dummy) word = "WILL";
  310. X            else              word = "WILL NOT";
  311. X            sprintf (msg_buf, 
  312. X                 "THE DUMMY %s BE PROMPTED AFTER EACH TRICK",
  313. X                 word);
  314. X            Display_Player_Comment ("MODERATOR", msg_buf);
  315. X            break;
  316. X        case CMD_PING:
  317. X            if (pc->player_no == local_player) {
  318. X                gettimeofday (&ping_start, NULL);
  319. X                send_message_ping ();
  320. X            } else
  321. X                send_message_echo (pc->player_no);
  322. X            break;
  323. X        case CMD_ECHO:
  324. X            players_here[pc->player_no] = 1;
  325. X            if (pc->data.ping_source == local_player) {
  326. X                gettimeofday (&ping_end, NULL);
  327. X                mils = (ping_end.tv_sec - ping_start.tv_sec)
  328. X                       * 1000;
  329. X                mils += ping_end.tv_usec / 1000;
  330. X                mils -= ping_start.tv_usec / 1000;
  331. X                sprintf (msg_buf,
  332. X                "ECHO RECEIVED FROM %-10s IN %7.2f SECONDS",
  333. X                     player_names[pc->player_no], 
  334. X                     ((float) mils) * 0.001);
  335. X                Display_Player_Comment ("MODERATOR", msg_buf);
  336. X            };
  337. X            break;
  338. X        case CMD_CLAIM:
  339. X            if (pc->player_no == local_player)
  340. X              process_claim_offer (pc->data.tricks);
  341. X            else if (local_player != dummy)
  342. X              process_claim_response (pc->data.tricks);
  343. X            break;
  344. X        case CMD_RESP:
  345. X            claim_responses++;
  346. X            if (!pc->data.response) {
  347. X/*
  348. X              sprintf (msg_buf, 
  349. X                   "THE CLAIM OFFER WAS DECLINED BY %s",
  350. X                   player_names[pc->player_no]);
  351. X*/
  352. X              if (!claim_rejected) {
  353. X                sprintf (msg_buf, 
  354. X                     "THE CLAIM OFFER WAS DECLINED.");
  355. X                Display_Player_Comment ("MODERATOR", msg_buf);
  356. X              };
  357. X              claim_rejected = 1;
  358. X            };
  359. X            break;
  360. X            case CMD_SCORE:
  361. X            scoring_mode_known = 1;
  362. X            scoring_mode = pc->data.scoring;
  363. X            switch (scoring_mode) {
  364. X            case RUBBER_SCORING:
  365. X              Display_Player_Comment ("MODERATOR",
  366. X                "WE ARE PLAYING RUBBER BRIDGE.");
  367. X              break;
  368. X            case CHICAGO_SCORING:
  369. X              Display_Player_Comment ("MODERATOR",
  370. X                "WE ARE PLAYING CHICAGO BRIDGE.");
  371. X              break;
  372. X            case DUPLICATE_SCORING:
  373. X              Display_Player_Comment ("MODERATOR",
  374. X                "WE ARE PLAYING DUPLICATE BRIDGE.");
  375. X              break;
  376. X            case EMAIL_SCORING:
  377. X              Display_Player_Comment ("MODERATOR",
  378. X                "WE ARE PLAYING EMAIL DUPLICATE BRIDGE.");
  379. X              break;
  380. X                        case IMP_SCORING:
  381. X                          Display_Player_Comment ("MODERATOR",
  382. X                            "WE ARE PLAYING IMP BRIDGE.");
  383. X                          break;
  384. X            };
  385. X            break;
  386. X            case CMD_LOG:
  387. X            if (pc->data.filename[0] == '\0') {
  388. X              if (logfile == NULL)
  389. X                Display_Player_Comment ("MODERATOR",
  390. X                  "THERE IS NO OPEN LOGFILE.");
  391. X              else {
  392. X                fclose (logfile);
  393. X                logfile = NULL;
  394. X                Display_Player_Comment ("MODERATOR",
  395. X                  "THE LOG FILE HAS BEEN CLOSED.");
  396. X              };
  397. X            } else {
  398. X              if (logfile != NULL) fclose (logfile);
  399. X              if (pc->data.filename[0] == '+') {
  400. X                filename = pc->data.filename + 1;
  401. X                logfile = fopen (filename, "a");
  402. X              } else {
  403. X                filename = pc->data.filename;
  404. X                logfile = fopen (filename, "w");
  405. X              };
  406. X              if (logfile == NULL) {
  407. X                sprintf (msg_buf, "%s ERROR OPENING %s",
  408. X                     sys_errlist[errno], filename);
  409. X                Display_Player_Comment ("MODERATOR", msg_buf);
  410. X              } else {
  411. X                sprintf (msg_buf, "NOW LOGGING TO %s",
  412. X                     filename);
  413. X                Display_Player_Comment ("MODERATOR", msg_buf);
  414. X              };
  415. X            };
  416. X            break;
  417. X        case CMD_DEAL:
  418. X            total_no_deals = pc->data.nhands;
  419. X            current_deal_no = 0;
  420. X            if (email_record != NULL)
  421. X                Free_Email_Duplicate_Struct (email_record);
  422. X            email_record = New_Email_Duplicate_Struct ();
  423. X            ns_pair_no = Add_Email_Pair (email_record,
  424. X                player_names[PLAYER_NORTH], 
  425. X                player_names[PLAYER_SOUTH]);
  426. X            ew_pair_no = Add_Email_Pair (email_record,
  427. X                player_names[PLAYER_EAST], 
  428. X                player_names[PLAYER_WEST]);
  429. X            if (total_no_deals < 0)
  430. X                Display_Player_Comment ("MODERATOR",
  431. X                    "ENTERING CONTINUOUS DEAL MODE.");
  432. X            else {
  433. X                sprintf (msg_buf, "%s %d DEALS.",
  434. X                    "BEGINNING A SEQUENCE OF",
  435. X                    total_no_deals);
  436. X                Display_Player_Comment ("MODERATOR", msg_buf);
  437. X            };
  438. X            replaying_mode = 0;
  439. X            current_board = NULL;
  440. X            break;
  441. X        case CMD_LOAD:
  442. X            load_email_file (pc->data.filename);
  443. X            break;
  444. X        case CMD_SAVE:
  445. X            save_email_file (pc->data.filename);
  446. X            break;
  447. X            case CMD_REPLAY:
  448. X            load_email_file (pc->data.filename);
  449. X            if (replaying_mode)
  450. X              autosave_file = strdup (pc->data.filename);
  451. X            break;
  452. X        default:
  453. X            sprintf (msg_buf, "PLAYER %d, CODE %d\n",
  454. X                pc->player_no, pc->command);
  455. X            Display_Player_Comment ("INTERNAL ERROR!", msg_buf);
  456. X    };
  457. X};
  458. Xstatic player_input (rmt_player, ib, default_command)
  459. X    int rmt_player; input_buffer ib; char *default_command;
  460. X/* This procedure monitors the network and the keyboard simultaneously,
  461. X . waiting for a command to arrive.  The local player is free to type at the
  462. X . keyboard, placing characters into the buffer ib.  When he presses
  463. X . enter, a command is issued.  By default, the command which is issued
  464. X . is obtained by concatenating the player's input to the string given
  465. X . in default command.  However, if the player's command begins with a
  466. X . slash '/', then it is interpreted directly as the command.  The exit
  467. X . condition for this procedure is determined by the input value of player.
  468. X . If player = -1, then the procedure exits as soon as any kind of message
  469. X . is received.  If player is in the range 0..3, then the procedure exits
  470. X . only when a play is received from the corresponding player.  No other
  471. X . values for player are valid.
  472. X */
  473. X{
  474. X    struct player_command_struct pcs;
  475. X    char command_buf[100];
  476. X    int polling;
  477. X/*    Clear_Status_Display();        */
  478. X    print (ib->row, 1, default_command);
  479. X    update_input_buffer (ib, '\0');
  480. X    if (rmt_player < 0)
  481. X        polling = 1;
  482. X    else if (rmt_player < 4)
  483. X        polling = !command_available(rmt_player);
  484. X    polling = 1;
  485. X    while (polling) {
  486. X        if (message_available()) {
  487. X            receive_player_command (&pcs);
  488. X            if (pcs.player_no >= 0) {
  489. X                process_player_command (&pcs);
  490. X                polling = 0;
  491. X            };
  492. X        };
  493. X        if (char_avail()) {
  494. X            if (update_input_buffer(ib, input_char())) {
  495. X                Clear_Status_Display ();
  496. X                pcs.player_no = local_player;
  497. X                if (ib->buf[0] == '/')
  498. X                    ps_copy (command_string, ib->buf+1);
  499. X                else {
  500. X                    sprintf (command_buf, "%s %s",
  501. X                        default_command, ib->buf);
  502. X                    ps_copy (command_string, command_buf);
  503. X                };
  504. X                clear_input_buffer (ib);
  505. X                parse_player_command (command_string, &pcs);
  506. X                if (pcs.command == CMD_ERROR)
  507. X                    Display_Status (parsing_errmsg);
  508. X                else {
  509. X                    process_player_command (&pcs);
  510. X                    polling = 0;
  511. X                };
  512. X                update_input_buffer (ib, '\0');
  513. X            };
  514. X        };
  515. X        if ((3 >= rmt_player) && (rmt_player >= 0))
  516. X            polling = !command_available(rmt_player);
  517. X    };
  518. X};
  519. Xstatic input_remote_play (rmt_player, play, pc)
  520. X    int rmt_player; long play; player_command pc;
  521. X/* As input, receives the index of a remote player as rmt_player and
  522. X . a bit string of allowable plays as play.  Waits for the specified
  523. X . player to make one of the plays listed in the bit string play.
  524. X . If we receive any other type of play, then an error message is
  525. X . generated.  Otherwise, creates the play into the structure pc.
  526. X */
  527. X{
  528. X    char error_message [100];
  529. X    int waiting;
  530. X    waiting = 1;
  531. X    while (waiting) {
  532. X            if (QUEUE_EMPTY(rmt_player))
  533. X          player_input (rmt_player,  talk_buffer, "TALK ");
  534. X        dequeue_command (rmt_player, pc);
  535. X        if (pc != NULL) {
  536. X            if (pc->command & play)
  537. X                waiting = 0;
  538. X            else {
  539. X                sprintf (error_message,
  540. X             "EXPECTING PLAY %ld FROM %d; RECEIVED PLAY %ld",
  541. X                 play, rmt_player, pc->command);
  542. X                Display_Player_Comment ("NETWORK ERROR", 
  543. X                 error_message);
  544. X            };
  545. X        };
  546. X    };
  547. X};
  548. XInitialize_Input_Buffers ()
  549. X/* Establishes and initializes the buffers that are used for reading
  550. X . input from the terminal.
  551. X */
  552. X{
  553. X    talk_buffer=(input_buffer) malloc (sizeof(struct input_buffer_struct));
  554. X    play_buffer=(input_buffer) malloc (sizeof(struct input_buffer_struct));
  555. X    ask_buffer =(input_buffer) malloc (sizeof(struct input_buffer_struct));
  556. X    talk_buffer->row = TALK_ROW;
  557. X    talk_buffer->col = TALK_COL + 6;
  558. X    talk_buffer->length = TALK_LENGTH - 6;
  559. X    talk_buffer->pos = 0;
  560. X    talk_buffer->buf[0] = '\0';
  561. X    play_buffer->row = PLAY_ROW;
  562. X    play_buffer->col = PLAY_COL + 6;
  563. X    play_buffer->length = PLAY_LENGTH - 6;
  564. X    play_buffer->pos = 0;
  565. X    play_buffer->buf[0] = '\0';
  566. X
  567. X    ask_buffer->row = TALK_ROW + 1;
  568. X    ask_buffer->col = 0;
  569. X    ask_buffer->length = 5;
  570. X    ask_buffer->pos = 0;
  571. X    ask_buffer->buf[0] = '\0';
  572. X
  573. X    email_record = NULL;
  574. X};
  575. X
  576. XInitialize_Input ()
  577. X/* Initializes the higher-level state of the network connections,
  578. X . including doing the initial handshaking with the other players.
  579. X */
  580. X{
  581. X    int i, wait;
  582. X    char msg_buf[80];
  583. X    initialize_command_queue();
  584. X    command_string = ps_alloc (127);
  585. X    command_disabled  = 0;
  586. X    disable(CMD_RDEAL);
  587. X    disable(CMD_BID);
  588. X    disable(CMD_PLAY);
  589. X    disable(CMD_FINISH);
  590. X    disable(CMD_HELLO);
  591. X    disable(CMD_ACK);
  592. X    disable(CMD_ECHO);
  593. X    disable(CMD_RESP); 
  594. X    disable(CMD_SCORE);
  595. X    disable(CMD_CLAIM);
  596. X    disable(CMD_DEAL);
  597. X    disable(CMD_LOAD);
  598. X    enable(CMD_SAVE);
  599. X
  600. X#ifdef LOOPBACK_MODE
  601. X    for (i = 0; i < 4; i++) players_here[i] = 1;    /* DBG */
  602. X    wait = 0;
  603. X#else
  604. X    for (i = 0; i < 4; i++) players_here[i] = 0;
  605. X    players_here[local_player] = 1;
  606. X    wait = 1;
  607. X#ifdef TWOPLAYER_MODE
  608. X    players_here[player_partner[local_player]] = 1;
  609. X#endif
  610. X#endif
  611. X
  612. X    /* First, wait for the other players to arrive: */
  613. X    send_message_hello ();
  614. X    while (wait) {
  615. X        player_input (-1, talk_buffer, "TALK ");
  616. X        wait = 0;
  617. X        for (i = 0; i < 4; i++)
  618. X            if (!players_here[i]) wait = 1;
  619. X    };
  620. X
  621. X        /* Now we reach an agreement about which scoring convention
  622. X           will be used.  In this implementation, north makes the decision
  623. X           and the others follow this decision. */
  624. X        if (local_player == PLAYER_NORTH)
  625. X      send_message_score ();
  626. X    else {
  627. X      while (!scoring_mode_known)
  628. X        player_input (-1, talk_buffer, "TALK ");
  629. X    };
  630. X
  631. X    /* Now that we have all of this information we can initialize the
  632. X       email duplicate structures.  Even though we may not be playing
  633. X       email duplicate, we still record all of the hands in case one
  634. X       of the players would like to save them.
  635. X    */
  636. X    email_record = New_Email_Duplicate_Struct ();
  637. X    current_board = NULL;
  638. X    ns_pair_no = Add_Email_Pair (email_record,
  639. X        player_names[PLAYER_NORTH], 
  640. X        player_names[PLAYER_SOUTH]);
  641. X    ew_pair_no = Add_Email_Pair (email_record,
  642. X        player_names[PLAYER_EAST], 
  643. X        player_names[PLAYER_WEST]);
  644. X    current_deal_no = total_no_deals = 0;
  645. X};
  646. Xstatic shuffle_the_deck (cards)
  647. X    deal cards;
  648. X/* Using the algorithm suggested by Douglas Foxvog.  Thanks, Doug! */
  649. X{
  650. X    int i, t, c;
  651. X    deal shuffle;
  652. X    for (i = 0; i < 52; i++) 
  653. X        shuffle [i] = i;
  654. X    for (i = 0; i < 51; i++) {
  655. X        c = random (52 - i);
  656. X        t = shuffle[i+c]; 
  657. X        shuffle[i+c] = shuffle[i];
  658. X        shuffle[i] = t;
  659. X    };
  660. X    for (i = 0; i < 52; i++)
  661. X        cards[shuffle[i]] = (i % 4);
  662. X        
  663. X};
  664. Xstatic void Print_Continue_Message (saved_already)
  665. X     int saved_already;
  666. X{
  667. X    if ((total_no_deals == 0) && !replaying_mode) {
  668. X      Display_Player_Comment ("MODERATOR",
  669. X        "TO BEGIN PLAY, TYPE /DEAL [nhands] OR /LOAD filename.");
  670. X    } else {
  671. X      Display_Player_Comment ("MODERATOR",
  672. X        "ALL BOARDS HAVE NOW BEEN PLAYED.");
  673. X      if (!saved_already)
  674. X        Display_Player_Comment ("MODERATOR",
  675. X                "TYPE /SAVE filename TO SAVE THE RESULTS,"); 
  676. X      Display_Player_Comment ("MODERATOR",
  677. X        "THEN /DEAL [nhands] OR /LOAD filename TO CONTINUE PLAY.");
  678. X    };
  679. X};
  680. X
  681. Xstatic int Email_Deal_Available () 
  682. X{
  683. X    if (replaying_mode)
  684. X        return (current_board != NULL);
  685. X    else
  686. X        return (current_deal_no != total_no_deals);
  687. X};
  688. X
  689. Xinput_hand (current_deal)
  690. X    deal current_deal;
  691. X/* If this player is the dealer, then shuffles the deck and deals the
  692. X   cards to everyone.  Otherwise, waits for the dealer to tell what
  693. X   the new shuffle is.  Stores the new deal in current_deal.
  694. X*/
  695. X{
  696. X    struct player_command_struct pcs;
  697. X    int i, saved;
  698. X    char message_buf[80];
  699. X
  700. X#ifdef LOOPBACK_MODE
  701. X    int dealer;
  702. X    dealer = local_player;
  703. X#endif
  704. X#ifdef TWOPLAYER_MODE
  705. X    dealer = dealer % 2;
  706. X#endif
  707. X
  708. X    if (current_board != NULL)
  709. X        current_board = current_board -> next;
  710. X    if ((scoring_mode == EMAIL_SCORING) && (local_player == PLAYER_NORTH)){
  711. X        if (!Email_Deal_Available()) {
  712. X                saved = 0;
  713. X                if (autoload_file != NULL) {
  714. X              load_email_file (autoload_file);
  715. X              autoload_file = NULL;
  716. X              if (!replaying_mode)
  717. X                autosave_file = NULL;
  718. X                } else if (autosave_file != NULL) {
  719. X              save_email_file (autosave_file);
  720. X              autosave_file = NULL;
  721. X              saved = 1;
  722. X            };
  723. X            enable (CMD_DEAL);
  724. X            enable (CMD_LOAD);
  725. X            enable (CMD_REPLAY);
  726. X            if (!Email_Deal_Available())
  727. X              Print_Continue_Message (saved);
  728. X            while (!Email_Deal_Available ())
  729. X                player_input (-1, talk_buffer, "TALK ");
  730. X            disable (CMD_DEAL);
  731. X            disable (CMD_LOAD);
  732. X            disable (CMD_REPLAY);
  733. X        };
  734. X        if (replaying_mode) {
  735. X            for (i = 0; i < 52; i++)
  736. X                current_deal[i] = current_board->deal[i];
  737. X            vulnerable[SIDE_NS] = current_board->ns_vulnerable;
  738. X            vulnerable[SIDE_EW] = current_board->ew_vulnerable;
  739. X            dealer = current_board->dealer;
  740. X        } else {
  741. X            shuffle_the_deck (current_deal);
  742. X            current_board = Add_Email_Board (email_record,
  743. X                current_deal);
  744. X            current_board->ns_vulnerable = vulnerable[SIDE_NS];
  745. X            current_board->ew_vulnerable = vulnerable[SIDE_EW];
  746. X            current_board->dealer = dealer;
  747. X        };
  748. X        send_message_vuln (dealer, vulnerable[SIDE_NS], 
  749. X                   vulnerable[SIDE_EW]);
  750. X        send_message_rdeal (current_deal);
  751. X    } else if (scoring_mode == EMAIL_SCORING) {
  752. X        Display_Status ("WAITING FOR DEAL ... ");
  753. X        input_remote_play (PLAYER_NORTH, CMD_VULN, &pcs);
  754. X        vulnerable[SIDE_NS] = 
  755. X            (pcs.data.vulnerable >> SIDE_NS) & 1;
  756. X        vulnerable[SIDE_EW] =
  757. X            (pcs.data.vulnerable >> SIDE_EW) & 1;
  758. X        dealer = pcs.data.vulnerable >> 2;
  759. X        input_remote_play (PLAYER_NORTH, CMD_RDEAL, &pcs);
  760. X        for (i = 0; i < 52; i++)
  761. X            current_deal[i] = pcs.data.deal[i];
  762. X        Clear_Status_Display ();
  763. X    } else if (dealer == local_player) {
  764. X        shuffle_the_deck (current_deal);
  765. X        send_message_rdeal (current_deal);
  766. X    } else {
  767. X        Display_Status ("WAITING FOR DEAL ... ");
  768. X        input_remote_play (dealer, CMD_RDEAL, &pcs);
  769. X        for (i = 0; i < 52; i++)
  770. X            current_deal[i] = pcs.data.deal[i];
  771. X        Clear_Status_Display ();
  772. X    };
  773. X    if (current_board == NULL) {
  774. X        current_board = Add_Email_Board (email_record, current_deal);
  775. X        current_board->ns_vulnerable = vulnerable[SIDE_NS];
  776. X        current_board->ew_vulnerable = vulnerable[SIDE_EW];
  777. X        current_board->dealer = dealer;
  778. X    };
  779. X    current_deal_no += 1;
  780. X};
  781. Xstatic display_valid_bids (minimum_bid, double_ok, redouble_ok)
  782. X    int minimum_bid, double_ok, redouble_ok;
  783. X{
  784. X    char double_string[40], bid_string[80];
  785. X    if (double_ok)
  786. X        sprintf (double_string, "; DOUBLE IS OK");
  787. X    else if (redouble_ok)
  788. X        sprintf (double_string, "; REDOUBLE IS OK");
  789. X    else
  790. X        double_string[0] = '\0';
  791. X    sprintf (bid_string, "ERROR -- MINIMUM BID IS %s%s",
  792. X         bid_names[minimum_bid], double_string);
  793. X    Display_Status (bid_string);
  794. X};
  795. Xstatic display_valid_plays (current_hand)
  796. X    hand current_hand;
  797. X{
  798. X    char card_string [60], card_message[80];
  799. X    int i, j, c;
  800. X    c = 0;
  801. X    for (i = 0; i < 52; i++) {
  802. X        if (current_hand[i]) {
  803. X            for (j = 0; card_names[i][j] != '\0'; j++)
  804. X                card_string[c++] = card_names[i][j];
  805. X            card_string[c++] = ' ';
  806. X        };
  807. X    };
  808. X    card_string[c++] = '\0';
  809. X    sprintf (card_message,"ERROR -- VALID PLAYS ARE %s", card_string);
  810. X    Display_Status (card_message);
  811. X};
  812. Xstatic int legal_bid (bid, minimum, double_ok, redouble_ok)
  813. X    int bid, double_ok, redouble_ok;
  814. X{
  815. X    if (bid < 0)
  816. X        return (0);
  817. X    else if (bid == BID_PASS)
  818. X        return (1);
  819. X    else if (bid == BID_DOUBLE)
  820. X        return (double_ok);
  821. X    else if (bid == BID_REDOUBLE)
  822. X        return (redouble_ok);
  823. X    else
  824. X        return (minimum <= bid);
  825. X};
  826. Xint input_bid (rmt_player, minimum_bid, double_ok, redouble_ok)
  827. X    int rmt_player, minimum_bid, double_ok, redouble_ok;
  828. X/* Waits for the indicated player to make a bid.  If the player is the
  829. X * one sitting at this terminal, then prompts for the play from the screen.
  830. X * Otherwise, waits for the play to come from the network.  Returns the
  831. X * index of the card played.  The input parameter minimum gives the index
  832. X * of the minimum acceptable contract bid.  The parameters double_ok and
  833. X * redouble_ok are boolean flags which indicate respectively if it is ok
  834. X * to bid double or redouble.
  835. X */
  836. X{
  837. X    int no_bid, bid;
  838. X    struct player_command_struct pcs;
  839. X    if (rmt_player == local_player) {
  840. X        no_bid = 1;
  841. X        enable (CMD_BID);
  842. X        if (ring_my_bell) ring_bell ();
  843. X        play_buffer->length = TALK_LENGTH - 6;
  844. X        default_input = "PASS";
  845. X        while (no_bid) {
  846. X            player_input (local_player, play_buffer, "BID ");
  847. X            dequeue_command (local_player, &pcs);
  848. X            if (pcs.command != CMD_BID)
  849. X                bid = -1;
  850. X            else
  851. X                bid = pcs.data.bid;
  852. X            no_bid = !legal_bid(bid, minimum_bid, double_ok,
  853. X                    redouble_ok);
  854. X            if (no_bid)
  855. X                display_valid_bids (minimum_bid, double_ok,
  856. X                    redouble_ok);
  857. X        };
  858. X        play_buffer->length = PLAY_LENGTH - 6;
  859. X        send_message_bid (bid);
  860. X        disable (CMD_BID);
  861. X        default_input = NULL;
  862. X    } else {
  863. X        input_remote_play (rmt_player, CMD_BID, &pcs);
  864. X        bid = pcs.data.bid;
  865. X    };
  866. X    return (bid);
  867. X};
  868. X
  869. Xstatic int minimum_card (ch)
  870. X  hand ch;
  871. X/* Returns the card of least rank held in the hand ch. */
  872. X{
  873. X  int suit_order[4], suit, mc, i, j;
  874. X
  875. X  for (i = j = 0; i < 4; i++)
  876. X    if (i != trump_suit)
  877. X      suit_order [j++] = i;
  878. X  if (trump_suit < 4)
  879. X    suit_order [3] = trump_suit;
  880. X
  881. X  for (i = 0; i < 4; i++) {
  882. X    suit = suit_order [i];
  883. X    for (j = 0; j < 13; j++) {
  884. X      mc = suit * 13 + j;
  885. X      if (ch[mc]) return (mc);
  886. X    };
  887. X  };
  888. X  return (-1);
  889. X};
  890. X
  891. Xstatic int no_cards (ch)
  892. X  hand ch;
  893. X{
  894. X  int i, n;
  895. X
  896. X  for (i = n = 0; i < 52; i++)
  897. X    if (ch[i]) n++;
  898. X  return (n);
  899. X};
  900. X
  901. Xstatic set_default_suit (ch)
  902. X  hand ch;
  903. X/* Examines the cards in the hand ch.  If all of the cards are from a single
  904. X   suit, then sets default_suit to that suit.  Otherwise, sets default_suit
  905. X   to -1.
  906. X*/
  907. X{
  908. X  int i, d;
  909. X
  910. X  d = default_suit = -1;
  911. X  for (i = 0; i < 52; i++)
  912. X    if (ch[i]) {
  913. X      if (d == -1)
  914. X    d = suit_of (i);
  915. X      else if (d != suit_of(i))
  916. X    return;
  917. X    };
  918. X  default_suit = d;
  919. X        
  920. X};
  921. X
  922. Xint input_play (rmt_player, current_hand)
  923. X    int rmt_player; hand current_hand;
  924. X/* Waits for the indicated player to play a card.  If that player is the
  925. X * one sitting at the terminal, then prompts from the screen for the play.
  926. X * In this case, current_hand gives a list of the valid cards which may
  927. X * be played.  If the indicated player is a remote player, then waits for
  928. X * the play to arrive through the network.  If the return value is 
  929. X * nonnegative, then it is the index of card played.  If the return value
  930. X * is -k-1, then k specifies the number of additional tricks claimed
  931. X * by the contracting team.
  932. X */
  933. X{
  934. X    int no_play, play;
  935. X    struct player_command_struct pcs;
  936. X    char *dp;
  937. X    char temp_buffer[60];
  938. X    if (local_player == rmt_player) {
  939. X        no_play = 1;
  940. X        enable (CMD_PLAY);
  941. X        if (local_player == declarer) enable (CMD_CLAIM);
  942. X        if (ring_my_bell) ring_bell ();
  943. X        default_input = card_names[minimum_card(current_hand)];
  944. X        if (default_plays && (no_cards(current_hand) == 1)) {
  945. X               for (dp = default_input; *dp != '\0'; dp++)
  946. X                   play_buffer->buf[play_buffer->pos++] = *dp;
  947. X            play_buffer->buf[play_buffer->pos] = '\0';
  948. X                play_buffer->defaulted = 1;
  949. X        };
  950. X        set_default_suit (current_hand);
  951. X        while (no_play) {
  952. X            player_input (local_player, play_buffer, "PLAY ");
  953. X            dequeue_command (local_player, &pcs);
  954. X            if (pcs.command == CMD_FINISH) {
  955. X                    play = -pcs.data.tricks - 1;
  956. X                no_play = 0;
  957. X            } else if (pcs.command == CMD_PLAY) {
  958. X                play = pcs.data.card;
  959. X                no_play = !current_hand[play];
  960. X                if (!no_play)
  961. X                  send_message_play (play);
  962. X            };
  963. X            if (no_play)
  964. X                display_valid_plays (current_hand);
  965. X        };
  966. X        default_input = NULL;
  967. X        disable (CMD_PLAY);
  968. X        disable (CMD_CLAIM);
  969. X    } else {
  970. X        input_remote_play (rmt_player, CMD_PLAY | CMD_FINISH, &pcs);
  971. X        if (pcs.command == CMD_FINISH)
  972. X          play = -pcs.data.tricks - 1;
  973. X        else
  974. X          play = pcs.data.card;
  975. X    };
  976. X    return (play);
  977. X};
  978. Xinput_acknowledgment (line)
  979. X    int line;
  980. X/* Displays the message "PRESS RETURN TO CONTINUE" on the given screen line,
  981. X * unless:
  982. X *   line == -1, in which case the message is displayed on the
  983. X *               status line, or
  984. X *   line == -2, in which case no message is displayed,
  985. X *   line == -3, in which case no message is displayed, and the
  986. X *      program enters TALK mode, exiting when a RETURN is pressed
  987. X *      on a blank line.
  988. X * Then waits for the user to press, RETURN.
  989. X */
  990. X{
  991. X    int ch;
  992. X    struct player_command_struct pcs;
  993. X    if (line == -1) {
  994. X        Clear_Status_Display ();
  995. X        Display_Status ("PRESS RETURN TO CONTINUE");
  996. X    } else if (line >= 0) {
  997. X        print (line, 1, "PRESS RETURN TO CONTINUE");
  998. X                set_cursor (line, 1 + strlen("PRESS RETURN TO CONTINUE"));
  999. X        };
  1000. X
  1001. X    if (ring_my_bell) ring_bell ();
  1002. X    waiting_for_acknowledgment = 1;
  1003. X    while (waiting_for_acknowledgment) {
  1004. X      if (line == -3)
  1005. X        player_input (-1, talk_buffer, "TALK ");
  1006. X      else {
  1007. X        if (message_available()) {
  1008. X            receive_player_command (&pcs);
  1009. X            if (pcs.player_no >= 0) 
  1010. X                process_player_command (&pcs);
  1011. X        };
  1012. X        if (char_avail()) {
  1013. X            ch = input_char ();
  1014. X            waiting_for_acknowledgment = (ch != '\012') 
  1015. X                                      && (ch != '\015');
  1016. X            if (ch == '\022')
  1017. X              Refresh_Display ();
  1018. X        };
  1019. X          };
  1020. X    };
  1021. X    if (line != -3)
  1022. X      while (char_avail()) input_char ();
  1023. X    Clear_Status_Display ();
  1024. X    
  1025. X};
  1026. Xinput_answer (question)
  1027. X     char *question;
  1028. X/* Displays the question on the status line and waits for the
  1029. X * local player to press 'y' or 'n'.  Returns 1 if 'y' was entered
  1030. X * and 0 if 'n' was entered.
  1031. X */
  1032. X{
  1033. X    int polling, ch;
  1034. X    struct player_command_struct pcs;
  1035. X
  1036. X    waiting_for_acknowledgment = 0;
  1037. X    Display_Status (question);
  1038. X    ask_buffer->col = strlen(question) + 2;
  1039. X    clear_input_buffer (ask_buffer);
  1040. X    default_input = "NO";
  1041. X    if (ring_my_bell) ring_bell ();
  1042. X    for (polling = 1; polling;) {
  1043. X      if (message_available()) {
  1044. X        receive_player_command (&pcs);
  1045. X        if (pcs.player_no >= 0) 
  1046. X          process_player_command (&pcs);
  1047. X      };
  1048. X      if (char_avail())
  1049. X        if(update_input_buffer (ask_buffer, input_char())) {
  1050. X          ch = ask_buffer->buf[0];
  1051. X          polling = ((ch != 'y') && (ch != 'Y')
  1052. X             && (ch != 'n') && (ch != 'N'));
  1053. X          clear_input_buffer (ask_buffer);
  1054. X        };
  1055. X    };
  1056. X    default_input = NULL;
  1057. X    Clear_Status_Display ();
  1058. X    update_input_buffer (talk_buffer, '\0');
  1059. X    return ((ch == 'y') || (ch == 'Y'));
  1060. X    
  1061. X};
  1062. Xprocess_claim_offer (t)
  1063. X     int t;
  1064. X{
  1065. X  char error_buf[80];
  1066. X  struct player_command_struct pcs;
  1067. X
  1068. X  if ((t + trick) > 14) {
  1069. X    sprintf (error_buf, "THERE ARE ONLY %d TRICKS WHICH CAN BE CLAIMED", 
  1070. X         14 - trick);
  1071. X    Display_Status (error_buf);
  1072. X    return;
  1073. X  };
  1074. X
  1075. X  claim_responses = 0;
  1076. X  claim_rejected  = 0;
  1077. X  send_message_claim (t);
  1078. X  Display_Status ("WAITING FOR A RESPONSE TO YOUR OFFER...");
  1079. X
  1080. X  disable (CMD_CLAIM);
  1081. X  while (claim_responses < 2)
  1082. X    player_input (-1, talk_buffer, "TALK ");
  1083. X  enable (CMD_CLAIM);
  1084. X
  1085. X  Clear_Status_Display ();
  1086. X
  1087. X  if (!claim_rejected) {
  1088. X    send_message_finish (t);
  1089. X    pcs.command = CMD_FINISH;
  1090. X    pcs.player_no = local_player;
  1091. X    pcs.data.tricks = t;
  1092. X    enqueue_command (&pcs);
  1093. X  };
  1094. X};
  1095. X  
  1096. Xprocess_claim_response (t)
  1097. X     int t;
  1098. X{
  1099. X  int response;
  1100. X  char question_buffer [80];
  1101. X
  1102. X  Display_Hand (declarer);
  1103. X  sprintf (question_buffer, "DECLARER CLAIMS %d TRICKS.  DO YOU ACCEPT [YN]?",
  1104. X       t);
  1105. X  response = input_answer (question_buffer);
  1106. X  Clear_Hand (declarer);
  1107. X  update_input_buffer (talk_buffer, '\0');
  1108. X  send_message_respond (response);
  1109. X};
  1110. END_OF_FILE
  1111. if test 31325 -ne `wc -c <'input.c.ab'`; then
  1112.     echo shar: \"'input.c.ab'\" unpacked with wrong size!
  1113. fi
  1114. # end of 'input.c.ab'
  1115. fi
  1116. echo shar: End of archive 4 \(of 7\).
  1117. cp /dev/null ark4isdone
  1118. MISSING=""
  1119. for I in 1 2 3 4 5 6 7 ; do
  1120.     if test ! -f ark${I}isdone ; then
  1121.     MISSING="${MISSING} ${I}"
  1122.     fi
  1123. done
  1124. if test "${MISSING}" = "" ; then
  1125.     echo You have unpacked all 7 archives.
  1126.     rm -f ark[1-9]isdone
  1127.     echo creating input.c from input.c.aa and input.c.ab
  1128.     cat input.c.aa input.c.ab >input.c
  1129.     rm -f input.c.aa input.c.ab
  1130. else
  1131.     echo You still need to unpack the following archives:
  1132.     echo "        " ${MISSING}
  1133. fi
  1134. ##  End of shell archive.
  1135. exit 0
  1136.