1 /*
2  * FILE: xshogi.c
3  *
4  *     Implementation of the X interface for GNU shogi (xshogi).
5  *
6  * ------------------------------------------------------------------------
7  * xshogi is based on XBoard -- an Xt/Athena user interface for GNU Chess.
8  *
9  * Original authors:                                Dan Sears, Chris Sears
10  * Enhancements (Version 2.0 and following):        Tim Mann
11  * Modifications to XShogi (Version 1.0):           Matthias Mutz
12  * Enhancements to XShogi (Version 1.1):            Matthias Mutz
13  * Modified implementation of ISS mode for XShogi:  Matthias Mutz
14  * Current maintainer:                              Michael C. Vanier
15  *
16  * XShogi borrows some of its piece bitmaps from CRANES Shogi.
17  *
18  * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
19  * Enhancements Copyright 1992 Free Software Foundation, Inc.
20  * Enhancements for XShogi Copyright 1993, 1994, 1995 Matthias Mutz
21  * Copyright (c) 1999 Michael Vanier and the Free Software Foundation
22  *
23  * The following terms apply to Digital Equipment Corporation's copyright
24  * interest in XBoard:
25  * ------------------------------------------------------------------------
26  * All Rights Reserved
27  *
28  * Permission to use, copy, modify, and distribute this software and its
29  * documentation for any purpose and without fee is hereby granted,
30  * provided that the above copyright notice appear in all copies and that
31  * both that copyright notice and this permission notice appear in
32  * supporting documentation, and that the name of Digital not be
33  * used in advertising or publicity pertaining to distribution of the
34  * software without specific, written prior permission.
35  *
36  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
37  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
38  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
39  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
40  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
41  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
42  * SOFTWARE.
43  * ------------------------------------------------------------------------
44  *
45  * This file is part of GNU shogi.
46  *
47  * GNU shogi is free software; you can redistribute it and/or modify
48  * it under the terms of the GNU General Public License as published by
49  * the Free Software Foundation.
50  *
51  * GNU shogi is distributed in the hope that it will be useful,
52  * but WITHOUT ANY WARRANTY; without even the implied warranty of
53  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
54  * GNU General Public License for more details.
55  *
56  * You should have received a copy of the GNU General Public License
57  * along with GNU shogi; see the file COPYING.  If not, write to
58  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
59  *
60  * ------------------------------------------------------------------------
61  *
62  */
63 
64 #include "config.h"
65 
66 #ifdef X_DISPLAY_MISSING
67 #error You cannot compile xshogi if X windows is unavailable!
68 #endif
69 
70 #include "sysdeps.h"
71 
72 #define XBOARD_VERSION "2.0/2.1"
73 
74 #include <stdio.h>
75 #include <ctype.h>
76 #include <signal.h>
77 #include <sys/ioctl.h>
78 
79 #include <time.h>
80 #include <pwd.h>
81 
82 #include <X11/Intrinsic.h>
83 #include <X11/StringDefs.h>
84 #include <X11/Shell.h>
85 #include <X11/Xaw/Dialog.h>
86 #include <X11/Xaw/Form.h>
87 #include <X11/Xaw/List.h>
88 #include <X11/Xaw/Label.h>
89 #include <X11/Xaw/SimpleMenu.h>
90 #include <X11/Xaw/SmeBSB.h>
91 #include <X11/Xaw/SmeLine.h>
92 #include <X11/cursorfont.h>
93 
94 #include "xshogi.h"
95 
96 #define BUF_SIZE 1024
97 #define BOARD    1
98 #define MOVES    2
99 
100 #include "bitmaps.h"  /* Piece bitmaps. */
101 #include "xshogifn.h" /* Forward declarations. */
102 
103 #define off_board(x) ((x < 2) || (x > BOARD_SIZE + 1))
104 
105 
106 /**********************************************************************
107  *
108  * Global variables, structs etc.
109  *
110  **********************************************************************/
111 
112 /*
113  * NOTE: XShogi depends on Xt R4 or higher
114  */
115 
116 int xtVersion = XtSpecificationRelease;
117 
118 XtIntervalId firstProgramXID = 0, secondProgramXID = 0,
119     readGameXID = 0, timerXID = 0, blinkSquareXID = 0;
120 
121 XtAppContext appContext;
122 
123 Boolean (*fileProc) (char *name);
124 
125 FILE *fromFirstProgFP, *toFirstProgFP, *fromSecondProgFP,
126     *toSecondProgFP, *gameFileFP, *lastMsgFP;
127 
128 int currentMove = 0, forwardMostMove = 0, backwardMostMove = 0,
129     firstProgramPID = 0,
130     secondProgramPID = 0, fromX = -1,
131     fromY = -1, firstMove = True, flipView = False,
132     xshogiDebug = True, commentUp = False, filenameUp = False,
133     whitePlaysFirst = False, startedFromSetupPosition = False,
134     searchTime = 0, pmFromX = -1, pmFromY = -1,
135     blackFlag = False, whiteFlag = False, maybeThinking = False,
136     filemodeUp = False;
137 
138 int at_least_gnushogi_1_2p03 = False;
139 
140 int firstSendTime = 2, secondSendTime = 2; /* 0 = don't, 1 = do,
141                                               2 = test first */
142 
143 MatchMode matchMode         = MatchFalse;
144 GameMode  gameMode          = BeginningOfGame;
145 GameMode  lastGameMode      = BeginningOfGame;
146 GameMode  pausePreviousMode = BeginningOfGame;
147 
148 char moveList[MAX_MOVES][MOVE_LEN], parseList[MAX_MOVES][MOVE_LEN * 2],
149     ptyname[24], *shogiDir, *programName;
150 
151 char endMessage[MOVE_LEN * 4];
152 
153 long blackTimeRemaining, whiteTimeRemaining, timeControl;
154 long timeRemaining[2][MAX_MOVES];
155 
156 extern char currentMoveString[];
157 
158 int updateRemotePlayer = False;
159 
160 Catched catches[MAX_MOVES];
161 
162 #define DIMENSION 100
163 
164 Widget blackPieceMenu, whitePieceMenu, commentShell;
165 
166 XSetWindowAttributes attr;
167 
168 #define pawn      0
169 #define lance     1
170 #define knight    2
171 #define silver    3
172 #define gold      4
173 #define bishop    5
174 #define rook      6
175 #define king      7
176 #define no_piece  8
177 #define ppawn     9
178 #define plance   10
179 #define pknight  11
180 #define psilver  12
181 #define pbishop  13
182 
183 #define NO_PIECES  15
184 #define NO_SQUARES 81
185 #define NO_COLS     9
186 #define NO_ROWS     9
187 
188 
189 char catchedIndexToChar[8] =
190 {
191     'P', 'L', 'N', 'S', 'G', 'B', 'R', 'K'
192 };
193 
194 ShogiSquare catchedIndexToPiece[2][8] =
195 {
196     {
197         BlackPawn, BlackLance, BlackKnight, BlackSilver, BlackGold,
198         BlackBishop, BlackRook, BlackKing
199     },
200     {
201         WhitePawn, WhiteLance, WhiteKnight, WhiteSilver, WhiteGold,
202         WhiteBishop, WhiteRook, WhiteKing
203     }
204 };
205 
206 
207 int pieceToCatchedIndex[] =
208 {
209     pawn, lance, knight, silver, gold, bishop, rook,
210     pawn, lance, knight, silver, bishop, rook, king,
211     pawn, lance, knight, silver, gold, bishop, rook,
212     pawn, lance, knight, silver, bishop, rook, king,
213     no_piece
214 };
215 
216 
217 
218 Board boards[MAX_MOVES];
219 Board initialPosition =
220 {
221     { BlackLance,  BlackKnight, BlackSilver, BlackGold, BlackKing,
222       BlackGold,   BlackSilver, BlackKnight, BlackLance },
223     { EmptySquare, BlackBishop, EmptySquare, EmptySquare, EmptySquare,
224       EmptySquare, EmptySquare, BlackRook,   EmptySquare },
225     { BlackPawn,   BlackPawn,   BlackPawn,   BlackPawn, BlackPawn,
226       BlackPawn,   BlackPawn,   BlackPawn,   BlackPawn },
227     { EmptySquare, EmptySquare, EmptySquare, EmptySquare, EmptySquare,
228       EmptySquare, EmptySquare, EmptySquare, EmptySquare } ,
229     { EmptySquare, EmptySquare, EmptySquare, EmptySquare, EmptySquare,
230       EmptySquare, EmptySquare, EmptySquare, EmptySquare } ,
231     { EmptySquare, EmptySquare, EmptySquare, EmptySquare, EmptySquare,
232       EmptySquare, EmptySquare, EmptySquare, EmptySquare } ,
233     { WhitePawn,   WhitePawn,   WhitePawn,   WhitePawn, WhitePawn,
234       WhitePawn,   WhitePawn,   WhitePawn,   WhitePawn },
235     { EmptySquare, WhiteRook,   EmptySquare, EmptySquare, EmptySquare,
236       EmptySquare, EmptySquare, WhiteBishop, EmptySquare },
237     { WhiteLance,  WhiteKnight, WhiteSilver, WhiteGold, WhiteKing,
238       WhiteGold,   WhiteSilver, WhiteKnight, WhiteLance }
239 };
240 
241 String gnuButtonStrings[] =
242 {
243     "Quit",       "Load Game",      "Machine White",  "Forward",
244     "Reset",      "Load Position",  "Machine Black",  "Backward",
245     "Flip View",  "Save Game",      "Force Moves",    "Pause",
246     "Hint",       "Save Position",  "Two Machines",   "Edit Position",
247     "Challenge",  "Select Level",   "Move NOW",
248 };
249 
250 /* must be in same order as buttonStrings! */
251 XtActionProc gnuButtonProcs[] =
252 {
253     QuitProc,       LoadGameProc,      MachineWhiteProc,  ForwardProc,
254     ResetProc,      LoadPositionProc,  MachineBlackProc,  BackwardProc,
255     FlipViewProc,   SaveGameProc,      ForceProc,         PauseProc,
256     HintProc,       SavePositionProc,  TwoMachinesProc,   EditPositionProc,
257     ChallengeProc,  SelectLevelProc,   MoveNowProc,
258     NULL
259 };
260 
261 
262 String *buttonStrings;
263 XtActionProc *buttonProcs;
264 int buttonCount;
265 
266 #define PIECE_MENU_SIZE 18
267 
268 String pieceMenuStrings[PIECE_MENU_SIZE] =
269 {
270     "----",     "Pawn",          "Lance",       "Knight", "Silver",
271     "Gold",     "Bishop",        "Rook",
272     "PPawn",    "PLance",        "PKnight",     "PSilver",
273     "PBishop",  "PRook",         "King",
274     "----",     "Empty square",  "Clear board"
275 };
276 
277 /* must be in same order as PieceMenuStrings! */
278 ShogiSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] =
279 {
280     {
281         (ShogiSquare) 0,  BlackPawn,    BlackLance,    BlackKnight,
282         BlackSilver,      BlackGold,    BlackBishop,   BlackRook,
283         BlackPPawn,       BlackPLance,  BlackPKnight,  BlackPSilver,
284         BlackPBishop,     BlackPRook,   BlackKing,
285         (ShogiSquare) 0,  EmptySquare,  ClearBoard
286     },
287     {
288         (ShogiSquare) 0,  WhitePawn,    WhiteLance,    WhiteKnight,
289         WhiteSilver,      WhiteGold,    WhiteBishop,   WhiteRook,
290         WhitePPawn,       WhitePLance,  WhitePKnight,  WhitePSilver,
291         WhitePBishop,     WhitePRook,   WhiteKing,
292         (ShogiSquare) 0,  EmptySquare,  ClearBoard
293     },
294 };
295 
296 
297 typedef struct
298 {
299     Pixel pieceColor;
300     Pixel squareColor;
301     Pixel charPieceColor;
302     Pixel zeroColor;
303     Pixel oneColor;
304     Boolean westernPieceSet;
305     int movesPerSession;
306     String initString;
307     String blackString;
308     String whiteString;
309     String firstShogiProgram;
310     String secondShogiProgram;
311     Boolean noShogiProgram;
312     String firstHost;
313     String secondHost;
314     String reverseBigSolidBitmap;
315     String reverseSmallSolidBitmap;
316     String normalBigSolidBitmap;
317     String normalSmallSolidBitmap;
318     String reversePawnBitmap;
319     String reverseLanceBitmap;
320     String reverseKnightBitmap;
321     String reverseSilverBitmap;
322     String reverseGoldBitmap;
323     String reverseRookBitmap;
324     String reverseBishopBitmap;
325     String reversePPawnBitmap;
326     String reversePLanceBitmap;
327     String reversePKnightBitmap;
328     String reversePSilverBitmap;
329     String reversePBishopBitmap;
330     String reversePRookBitmap;
331     String reverseKingBitmap;
332     String normalPawnBitmap;
333     String normalLanceBitmap;
334     String normalKnightBitmap;
335     String normalSilverBitmap;
336     String normalGoldBitmap;
337     String normalRookBitmap;
338     String normalBishopBitmap;
339     String normalPPawnBitmap;
340     String normalPLanceBitmap;
341     String normalPKnightBitmap;
342     String normalPSilverBitmap;
343     String normalPBishopBitmap;
344     String normalPRookBitmap;
345     String normalKingBitmap;
346     String remoteShell;
347     float  timeDelay;
348     String timeControl;
349     String gameIn;
350 
351     Boolean autoSaveGames;
352     String loadGameFile;
353     String loadPositionFile;
354     String saveGameFile;
355     String savePositionFile;
356     String matchMode;
357     String challengeDisplay;
358     Boolean monoMode;
359     Boolean debugMode;
360     Boolean clockMode;
361     String boardSize;
362     Boolean Iconic;
363     String searchTime;
364     int searchDepth;
365     Boolean showCoords;
366     String mainFont;
367     String coordFont;
368     Boolean ringBellAfterMoves;
369     Boolean autoCallFlag;
370     int borderXoffset;
371     int borderYoffset;
372 } AppData, *AppDataPtr;
373 
374 
375 XtResource clientResources[] =
376 {
377     {
378         "pieceColor", "pieceColor", XtRPixel, sizeof(Pixel),
379         XtOffset(AppDataPtr, pieceColor), XtRString,
380         PIECE_COLOR
381     },
382     {
383         "charPieceColor", "CharPieceColor", XtRPixel, sizeof(Pixel),
384         XtOffset(AppDataPtr, charPieceColor), XtRString,
385         CHAR_PIECE_COLOR
386     },
387     {
388         "oneColor", "OneColor", XtRPixel, sizeof(Pixel),
389         XtOffset(AppDataPtr, oneColor), XtRString,
390         ONE_COLOR
391     },
392     {
393         "zeroColor", "ZeroColor", XtRPixel, sizeof(Pixel),
394         XtOffset(AppDataPtr, zeroColor), XtRString,
395         ZERO_COLOR
396     },
397     {
398         "squareColor", "squareColor", XtRPixel,
399         sizeof(Pixel), XtOffset(AppDataPtr, squareColor),
400         XtRString, SQUARE_COLOR
401     },
402     {
403         "westernPieceSet", "WesternPieceSet", XtRBoolean, sizeof(Boolean),
404         XtOffset(AppDataPtr, westernPieceSet), XtRString,
405         (XtPointer) False
406     },
407     {
408         "movesPerSession", "movesPerSession", XtRInt, sizeof(int),
409         XtOffset(AppDataPtr, movesPerSession), XtRImmediate,
410         (XtPointer) MOVES_PER_SESSION
411     },
412     {
413         "initString", "initString", XtRString, sizeof(String),
414         XtOffset(AppDataPtr, initString), XtRString, INIT_STRING
415     },
416     {
417         "blackString", "blackString", XtRString, sizeof(String),
418         XtOffset(AppDataPtr, blackString), XtRString, BLACK_STRING
419     },
420     {
421         "whiteString", "whiteString", XtRString, sizeof(String),
422         XtOffset(AppDataPtr, whiteString), XtRString, WHITE_STRING
423     },
424     {
425         "firstShogiProgram", "firstShogiProgram", XtRString,
426         sizeof(String), XtOffset(AppDataPtr, firstShogiProgram),
427         XtRString, FIRST_SHOGI_PROGRAM
428     },
429     {
430         "secondShogiProgram", "secondShogiProgram", XtRString,
431         sizeof(String), XtOffset(AppDataPtr, secondShogiProgram),
432         XtRString, SECOND_SHOGI_PROGRAM
433     },
434     {
435         "noShogiProgram", "noShogiProgram", XtRBoolean,
436         sizeof(Boolean), XtOffset(AppDataPtr, noShogiProgram),
437         XtRImmediate, (XtPointer) False
438     },
439     {
440         "firstHost", "firstHost", XtRString, sizeof(String),
441         XtOffset(AppDataPtr, firstHost), XtRString, FIRST_HOST
442     },
443     {
444         "secondHost", "secondHost", XtRString, sizeof(String),
445         XtOffset(AppDataPtr, secondHost), XtRString, SECOND_HOST
446     },
447     {
448         "reversePawnBitmap", "reversePawnBitmap", XtRString,
449         sizeof(String), XtOffset(AppDataPtr, reversePawnBitmap),
450         XtRString, NULL
451     },
452     {
453         "reverseLanceBitmap", "reverseLanceBitmap", XtRString,
454         sizeof(String), XtOffset(AppDataPtr, reverseLanceBitmap),
455         XtRString, NULL
456     },
457     {
458         "reverseKnightBitmap", "reverseKnightBitmap", XtRString,
459         sizeof(String), XtOffset(AppDataPtr, reverseKnightBitmap),
460         XtRString, NULL
461     },
462     {
463         "reverseSilverBitmap", "reverseSilverBitmap", XtRString,
464         sizeof(String), XtOffset(AppDataPtr, reverseSilverBitmap),
465         XtRString, NULL
466     },
467     {
468         "reverseGoldBitmap", "reverseGoldBitmap", XtRString,
469         sizeof(String), XtOffset(AppDataPtr, reverseGoldBitmap),
470         XtRString, NULL
471     },
472     {
473         "reverseRookBitmap", "reverseRookBitmap", XtRString,
474         sizeof(String), XtOffset(AppDataPtr, reverseRookBitmap),
475         XtRString, NULL
476     },
477     {
478         "reverseBishopBitmap", "reverseBishopBitmap", XtRString,
479         sizeof(String), XtOffset(AppDataPtr, reverseBishopBitmap),
480         XtRString, NULL
481     },
482     {
483         "reversePPawnBitmap", "reversePPawnBitmap", XtRString,
484         sizeof(String), XtOffset(AppDataPtr, reversePPawnBitmap),
485         XtRString, NULL
486     },
487     {
488         "reversePLanceBitmap", "reversePLanceBitmap", XtRString,
489         sizeof(String), XtOffset(AppDataPtr, reversePLanceBitmap),
490         XtRString, NULL
491     },
492     {
493         "reversePKnightBitmap", "reversePKnightBitmap", XtRString,
494         sizeof(String), XtOffset(AppDataPtr, reversePKnightBitmap),
495         XtRString, NULL
496     },
497     {
498         "reversePSilverBitmap", "reversePSilverBitmap", XtRString,
499         sizeof(String), XtOffset(AppDataPtr, reversePSilverBitmap),
500         XtRString, NULL
501     },
502     {
503         "reversePRookBitmap", "reversePRookBitmap", XtRString,
504         sizeof(String), XtOffset(AppDataPtr, reversePRookBitmap),
505         XtRString, NULL
506     },
507     {
508         "reversePBishopBitmap", "reversePBishopBitmap", XtRString,
509         sizeof(String), XtOffset(AppDataPtr, reversePBishopBitmap),
510         XtRString, NULL
511     },
512     {
513         "reverseKingBitmap", "reverseKingBitmap", XtRString,
514         sizeof(String), XtOffset(AppDataPtr, reverseKingBitmap),
515         XtRString, NULL
516     },
517     {
518         "normalPawnBitmap", "normalPawnBitmap", XtRString,
519         sizeof(String), XtOffset(AppDataPtr, normalPawnBitmap),
520         XtRString, NULL
521     },
522     {
523         "normalLanceBitmap", "normalLanceBitmap", XtRString,
524         sizeof(String), XtOffset(AppDataPtr, normalLanceBitmap),
525         XtRString, NULL
526     },
527     {
528         "normalKnightBitmap", "normalKnightBitmap", XtRString,
529         sizeof(String), XtOffset(AppDataPtr, normalKnightBitmap),
530         XtRString, NULL
531     },
532     {
533         "normalSilverBitmap", "normalSilverBitmap", XtRString,
534         sizeof(String), XtOffset(AppDataPtr, normalSilverBitmap),
535         XtRString, NULL
536     },
537     {
538         "normalGoldBitmap", "normalGoldBitmap", XtRString,
539         sizeof(String), XtOffset(AppDataPtr, normalGoldBitmap),
540         XtRString, NULL
541     },
542     {
543         "normalBishopBitmap", "normalBishopBitmap", XtRString,
544         sizeof(String), XtOffset(AppDataPtr, normalBishopBitmap),
545         XtRString, NULL
546     },
547     {
548         "normalRookBitmap", "normalRookBitmap", XtRString,
549         sizeof(String), XtOffset(AppDataPtr, normalRookBitmap),
550         XtRString, NULL
551     },
552     {
553         "normalPPawnBitmap", "normalPPawnBitmap", XtRString,
554         sizeof(String), XtOffset(AppDataPtr, normalPPawnBitmap),
555         XtRString, NULL
556     },
557     {
558         "normalPLanceBitmap", "normalPLanceBitmap", XtRString,
559         sizeof(String), XtOffset(AppDataPtr, normalPLanceBitmap),
560         XtRString, NULL
561     },
562     {
563         "normalPKnightBitmap", "normalPKnightBitmap", XtRString,
564         sizeof(String), XtOffset(AppDataPtr, normalPKnightBitmap),
565         XtRString, NULL
566     },
567     {
568         "normalPSilverBitmap", "normalPSilverBitmap", XtRString,
569         sizeof(String), XtOffset(AppDataPtr, normalPSilverBitmap),
570         XtRString, NULL
571     },
572     {
573         "normalPBishopBitmap", "normalPBishopBitmap", XtRString,
574         sizeof(String), XtOffset(AppDataPtr, normalPBishopBitmap),
575         XtRString, NULL
576     },
577     {
578         "normalPRookBitmap", "normalPRookBitmap", XtRString,
579         sizeof(String), XtOffset(AppDataPtr, normalPRookBitmap),
580         XtRString, NULL
581     },
582     {
583         "normalKingBitmap", "normalKingBitmap", XtRString,
584         sizeof(String), XtOffset(AppDataPtr, normalKingBitmap),
585         XtRString, NULL
586     },
587     {
588         "remoteShell", "remoteShell", XtRString, sizeof(String),
589         XtOffset(AppDataPtr, remoteShell), XtRString, "rsh"
590     },
591     {
592         "timeDelay", "timeDelay", XtRFloat, sizeof(float),
593         XtOffset(AppDataPtr, timeDelay), XtRString,
594         (XtPointer) TIME_DELAY
595     },
596     {
597         "timeControl", "timeControl", XtRString, sizeof(String),
598         XtOffset(AppDataPtr, timeControl), XtRString,
599         (XtPointer) TIME_CONTROL
600     },
601     {
602         "gameIn", "gameIn",
603         XtRBoolean, sizeof(Boolean),
604         XtOffset(AppDataPtr, gameIn), XtRImmediate,
605         (XtPointer) False
606     },
607     {
608         "autoSaveGames", "autoSaveGames", XtRBoolean,
609         sizeof(Boolean), XtOffset(AppDataPtr, autoSaveGames),
610         XtRImmediate, (XtPointer) False
611     },
612     {
613         "loadGameFile", "loadGameFile", XtRString, sizeof(String),
614         XtOffset(AppDataPtr, loadGameFile), XtRString, NULL
615     },
616     {
617         "loadPositionFile", "loadPositionFile", XtRString,
618         sizeof(String), XtOffset(AppDataPtr, loadPositionFile),
619         XtRString, NULL
620     },
621     {
622         "saveGameFile", "saveGameFile", XtRString, sizeof(String),
623         XtOffset(AppDataPtr, saveGameFile), XtRString, ""
624     },
625     {
626         "savePositionFile", "savePositionFile", XtRString,
627         sizeof(String), XtOffset(AppDataPtr, savePositionFile),
628         XtRString, ""
629     },
630     {
631         "challengeDisplay", "challengeDisplay", XtRString,
632         sizeof(String), XtOffset(AppDataPtr, challengeDisplay),
633         XtRString, NULL
634     },
635     {
636         "matchMode", "matchMode", XtRString, sizeof(String),
637         XtOffset(AppDataPtr, matchMode), XtRString, MATCH_MODE
638     },
639     {
640         "monoMode", "monoMode", XtRBoolean, sizeof(Boolean),
641         XtOffset(AppDataPtr, monoMode), XtRImmediate,
642         (XtPointer) False
643     },
644     {
645         "debugMode", "debugMode", XtRBoolean, sizeof(Boolean),
646         XtOffset(AppDataPtr, debugMode), XtRImmediate,
647         (XtPointer) False
648     },
649     {
650         "Iconic", "Iconic", XtRBoolean, sizeof(Boolean),
651         XtOffset(AppDataPtr, Iconic), XtRImmediate,
652         (XtPointer) False
653     },
654     {
655         "clockMode", "clockMode", XtRBoolean, sizeof(Boolean),
656         XtOffset(AppDataPtr, clockMode), XtRImmediate,
657         (XtPointer) True
658     },
659     {
660         "autoCallFlag", "autoCallFlag", XtRBoolean,
661         sizeof(Boolean), XtOffset(AppDataPtr, autoCallFlag),
662         XtRImmediate, (XtPointer) False
663     },
664     {
665         "boardSize", "boardSize", XtRString, sizeof(String),
666         XtOffset(AppDataPtr, boardSize), XtRString, DEFAULT_SIZE
667     },
668     {
669         "searchTime", "searchTime", XtRString, sizeof(String),
670         XtOffset(AppDataPtr, searchTime), XtRString,
671         (XtPointer) NULL
672     },
673     {
674         "searchDepth", "searchDepth", XtRInt, sizeof(int),
675         XtOffset(AppDataPtr, searchDepth), XtRImmediate,
676         (XtPointer) 0
677     },
678     {
679         "showCoords", "showCoords", XtRBoolean, sizeof(Boolean),
680         XtOffset(AppDataPtr, showCoords), XtRImmediate,
681         (XtPointer) False
682     },
683     {
684         "mainFont", "mainFont", XtRString, sizeof(String),
685         XtOffset(AppDataPtr, mainFont), XtRString, MAIN_FONT
686     },
687     {
688         "coordFont", "coordFont", XtRString, sizeof(String),
689         XtOffset(AppDataPtr, coordFont), XtRString, COORD_FONT
690     },
691     {
692         "ringBellAfterMoves", "ringBellAfterMoves",
693         XtRBoolean, sizeof(Boolean),
694         XtOffset(AppDataPtr, ringBellAfterMoves),
695         XtRImmediate, (XtPointer) False
696     },
697     {
698         "borderXoffset", "borderXoffset", XtRInt, sizeof(int),
699         XtOffset(AppDataPtr, borderXoffset), XtRImmediate,
700         (XtPointer) BORDER_X_OFFSET
701     },
702     {
703         "borderYoffset", "borderYOffset", XtRInt, sizeof(int),
704         XtOffset(AppDataPtr, borderYoffset), XtRImmediate,
705         (XtPointer) BORDER_Y_OFFSET
706     }
707 };
708 
709 
710 struct DisplayData
711 {
712     AppData appData;
713 
714     Arg shellArgs[6];
715     Arg boardArgs[3];
716     Arg commandsArgs[7];
717     Arg messageArgs[3];
718     Arg timerArgs[2];
719     Arg titleArgs[2];
720 
721     Pixmap reversePawnBitmap, reverseLanceBitmap,   reverseKnightBitmap,
722         reverseSilverBitmap,
723         reverseGoldBitmap,    reverseBishopBitmap,  reverseRookBitmap,
724         reversePPawnBitmap,   reversePLanceBitmap,  reversePKnightBitmap,
725         reversePSilverBitmap, reversePBishopBitmap, reversePRookBitmap,
726         reverseKingBitmap,
727         reverseBigSolidBitmap, reverseSmallSolidBitmap,
728         normalBigSolidBitmap,  normalSmallSolidBitmap,
729         normalPawnBitmap,      normalLanceBitmap,   normalKnightBitmap,
730         normalSilverBitmap,    normalGoldBitmap,
731         normalBishopBitmap,    normalRookBitmap,
732         normalPPawnBitmap,     normalPLanceBitmap,  normalPKnightBitmap,
733         normalPSilverBitmap,   normalPBishopBitmap, normalPRookBitmap,
734         normalKingBitmap,
735         iconPixmap;
736 
737     Display *xDisplay;
738     int xScreen;
739     Window xBoardWindow;
740 
741     GC squareGC, lineGC, pieceGC, oPieceGC, charPieceGC,
742         squareOffBoardGC, coordGC, dropPiece;
743 
744     Font mainFontID, coordFontID;
745     XFontStruct *mainFontStruct, *coordFontStruct;
746 
747     Widget shellWidget, formWidget, boardWidget,
748         commandsWidget, messageWidget,
749         blackTimerWidget, whiteTimerWidget,
750         titleWidget, widgetList[6],
751         promotionShell,
752         filemodeShell, challengeWidget;
753 
754     XSegment gridSegments[(BOARD_SIZE + 1) * 2];
755 
756     Pixel timerForegroundPixel, timerBackgroundPixel;
757 
758     BoardSize boardSize;
759     int squareSize;
760     int black_pixel_is_zero;
761     int flipView;
762     int promotionUp;
763 
764     Boolean monoMode, showCoords, Iconic;
765 };
766 
767 
768 
769 struct DisplayData localPlayer, remotePlayer;
770 
771 
772 typedef struct
773 {
774     ShogiSquare piece;
775     int to_x, to_y;
776 } PromotionMoveInfo;
777 
778 static PromotionMoveInfo pmi;  /* making this global is gross */
779 
780 
781 Pixmap *pieceToReverse[2][28] =
782 {
783     {
784         &localPlayer.reversePawnBitmap,
785         &localPlayer.reverseLanceBitmap,
786         &localPlayer.reverseKnightBitmap,
787         &localPlayer.reverseSilverBitmap,
788         &localPlayer.reverseGoldBitmap,
789         &localPlayer.reverseBishopBitmap,
790         &localPlayer.reverseRookBitmap,
791         &localPlayer.reversePPawnBitmap,
792         &localPlayer.reversePLanceBitmap,
793         &localPlayer.reversePKnightBitmap,
794         &localPlayer.reversePSilverBitmap,
795         &localPlayer.reversePBishopBitmap,
796         &localPlayer.reversePRookBitmap,
797         &localPlayer.reverseKingBitmap,
798         &localPlayer.reversePawnBitmap,
799         &localPlayer.reverseLanceBitmap,
800         &localPlayer.reverseKnightBitmap,
801         &localPlayer.reverseSilverBitmap,
802         &localPlayer.reverseGoldBitmap,
803         &localPlayer.reverseBishopBitmap,
804         &localPlayer.reverseRookBitmap,
805         &localPlayer.reversePPawnBitmap,
806         &localPlayer.reversePLanceBitmap,
807         &localPlayer.reversePKnightBitmap,
808         &localPlayer.reversePSilverBitmap,
809         &localPlayer.reversePBishopBitmap,
810         &localPlayer.reversePRookBitmap,
811         &localPlayer.reverseKingBitmap
812     },
813     {
814         &remotePlayer.reversePawnBitmap,
815         &remotePlayer.reverseLanceBitmap,
816         &remotePlayer.reverseKnightBitmap,
817         &remotePlayer.reverseSilverBitmap,
818         &remotePlayer.reverseGoldBitmap,
819         &remotePlayer.reverseBishopBitmap,
820         &remotePlayer.reverseRookBitmap,
821         &remotePlayer.reversePPawnBitmap,
822         &remotePlayer.reversePLanceBitmap,
823         &remotePlayer.reversePKnightBitmap,
824         &remotePlayer.reversePSilverBitmap,
825         &remotePlayer.reversePBishopBitmap,
826         &remotePlayer.reversePRookBitmap,
827         &remotePlayer.reverseKingBitmap,
828         &remotePlayer.reversePawnBitmap,
829         &remotePlayer.reverseLanceBitmap,
830         &remotePlayer.reverseKnightBitmap,
831         &remotePlayer.reverseSilverBitmap,
832         &remotePlayer.reverseGoldBitmap,
833         &remotePlayer.reverseBishopBitmap,
834         &remotePlayer.reverseRookBitmap,
835         &remotePlayer.reversePPawnBitmap,
836         &remotePlayer.reversePLanceBitmap,
837         &remotePlayer.reversePKnightBitmap,
838         &remotePlayer.reversePSilverBitmap,
839         &remotePlayer.reversePBishopBitmap,
840         &remotePlayer.reversePRookBitmap,
841         &remotePlayer.reverseKingBitmap
842     }
843 };
844 
845 
846 
847 Pixmap *pieceToNormal[2][28] =
848 {
849     {
850         &localPlayer.normalPawnBitmap,
851         &localPlayer.normalLanceBitmap,
852         &localPlayer.normalKnightBitmap,
853         &localPlayer.normalSilverBitmap,
854         &localPlayer.normalGoldBitmap,
855         &localPlayer.normalBishopBitmap,
856         &localPlayer.normalRookBitmap,
857         &localPlayer.normalPPawnBitmap,
858         &localPlayer.normalPLanceBitmap,
859         &localPlayer.normalPKnightBitmap,
860         &localPlayer.normalPSilverBitmap,
861         &localPlayer.normalPBishopBitmap,
862         &localPlayer.normalPRookBitmap,
863         &localPlayer.normalKingBitmap,
864         &localPlayer.normalPawnBitmap,
865         &localPlayer.normalLanceBitmap,
866         &localPlayer.normalKnightBitmap,
867         &localPlayer.normalSilverBitmap,
868         &localPlayer.normalGoldBitmap,
869         &localPlayer.normalBishopBitmap,
870         &localPlayer.normalRookBitmap,
871         &localPlayer.normalPPawnBitmap,
872         &localPlayer.normalPLanceBitmap,
873         &localPlayer.normalPKnightBitmap,
874         &localPlayer.normalPSilverBitmap,
875         &localPlayer.normalPBishopBitmap,
876         &localPlayer.normalPRookBitmap,
877         &localPlayer.normalKingBitmap
878     },
879     {
880         &remotePlayer.normalPawnBitmap,
881         &remotePlayer.normalLanceBitmap,
882         &remotePlayer.normalKnightBitmap,
883         &remotePlayer.normalSilverBitmap,
884         &remotePlayer.normalGoldBitmap,
885         &remotePlayer.normalBishopBitmap,
886         &remotePlayer.normalRookBitmap,
887         &remotePlayer.normalPPawnBitmap,
888         &remotePlayer.normalPLanceBitmap,
889         &remotePlayer.normalPKnightBitmap,
890         &remotePlayer.normalPSilverBitmap,
891         &remotePlayer.normalPBishopBitmap,
892         &remotePlayer.normalPRookBitmap,
893         &remotePlayer.normalKingBitmap,
894         &remotePlayer.normalPawnBitmap,
895         &remotePlayer.normalLanceBitmap,
896         &remotePlayer.normalKnightBitmap,
897         &remotePlayer.normalSilverBitmap,
898         &remotePlayer.normalGoldBitmap,
899         &remotePlayer.normalBishopBitmap,
900         &remotePlayer.normalRookBitmap,
901         &remotePlayer.normalPPawnBitmap,
902         &remotePlayer.normalPLanceBitmap,
903         &remotePlayer.normalPKnightBitmap,
904         &remotePlayer.normalPSilverBitmap,
905         &remotePlayer.normalPBishopBitmap,
906         &remotePlayer.normalPRookBitmap,
907         &remotePlayer.normalKingBitmap
908     }
909 };
910 
911 
912 
913 Pixmap *pieceToReverseSolid[2][28] =
914 {
915     {
916         &localPlayer.reverseSmallSolidBitmap,
917         &localPlayer.reverseSmallSolidBitmap,
918         &localPlayer.reverseSmallSolidBitmap,
919         &localPlayer.reverseBigSolidBitmap,
920         &localPlayer.reverseBigSolidBitmap,
921         &localPlayer.reverseBigSolidBitmap,
922         &localPlayer.reverseBigSolidBitmap,
923         &localPlayer.reverseSmallSolidBitmap,
924         &localPlayer.reverseSmallSolidBitmap,
925         &localPlayer.reverseSmallSolidBitmap,
926         &localPlayer.reverseBigSolidBitmap,
927         &localPlayer.reverseBigSolidBitmap,
928         &localPlayer.reverseBigSolidBitmap,
929         &localPlayer.reverseBigSolidBitmap,
930         &localPlayer.reverseSmallSolidBitmap,
931         &localPlayer.reverseSmallSolidBitmap,
932         &localPlayer.reverseSmallSolidBitmap,
933         &localPlayer.reverseBigSolidBitmap,
934         &localPlayer.reverseBigSolidBitmap,
935         &localPlayer.reverseBigSolidBitmap,
936         &localPlayer.reverseBigSolidBitmap,
937         &localPlayer.reverseSmallSolidBitmap,
938         &localPlayer.reverseSmallSolidBitmap,
939         &localPlayer.reverseSmallSolidBitmap,
940         &localPlayer.reverseBigSolidBitmap,
941         &localPlayer.reverseBigSolidBitmap,
942         &localPlayer.reverseBigSolidBitmap,
943         &localPlayer.reverseBigSolidBitmap
944     },
945     {
946         &remotePlayer.reverseSmallSolidBitmap,
947         &remotePlayer.reverseSmallSolidBitmap,
948         &remotePlayer.reverseSmallSolidBitmap,
949         &remotePlayer.reverseBigSolidBitmap,
950         &remotePlayer.reverseBigSolidBitmap,
951         &remotePlayer.reverseBigSolidBitmap,
952         &remotePlayer.reverseBigSolidBitmap,
953         &remotePlayer.reverseSmallSolidBitmap,
954         &remotePlayer.reverseSmallSolidBitmap,
955         &remotePlayer.reverseSmallSolidBitmap,
956         &remotePlayer.reverseBigSolidBitmap,
957         &remotePlayer.reverseBigSolidBitmap,
958         &remotePlayer.reverseBigSolidBitmap,
959         &remotePlayer.reverseBigSolidBitmap,
960         &remotePlayer.reverseSmallSolidBitmap,
961         &remotePlayer.reverseSmallSolidBitmap,
962         &remotePlayer.reverseSmallSolidBitmap,
963         &remotePlayer.reverseBigSolidBitmap,
964         &remotePlayer.reverseBigSolidBitmap,
965         &remotePlayer.reverseBigSolidBitmap,
966         &remotePlayer.reverseBigSolidBitmap,
967         &remotePlayer.reverseSmallSolidBitmap,
968         &remotePlayer.reverseSmallSolidBitmap,
969         &remotePlayer.reverseSmallSolidBitmap,
970         &remotePlayer.reverseBigSolidBitmap,
971         &remotePlayer.reverseBigSolidBitmap,
972         &remotePlayer.reverseBigSolidBitmap,
973         &remotePlayer.reverseBigSolidBitmap
974     }
975 };
976 
977 
978 
979 Pixmap *pieceToNormalSolid[2][28] =
980 {
981     {
982         &localPlayer.normalSmallSolidBitmap,
983         &localPlayer.normalSmallSolidBitmap,
984         &localPlayer.normalSmallSolidBitmap,
985         &localPlayer.normalBigSolidBitmap,
986         &localPlayer.normalBigSolidBitmap,
987         &localPlayer.normalBigSolidBitmap,
988         &localPlayer.normalBigSolidBitmap,
989         &localPlayer.normalSmallSolidBitmap,
990         &localPlayer.normalSmallSolidBitmap,
991         &localPlayer.normalSmallSolidBitmap,
992         &localPlayer.normalBigSolidBitmap,
993         &localPlayer.normalBigSolidBitmap,
994         &localPlayer.normalBigSolidBitmap,
995         &localPlayer.normalBigSolidBitmap,
996         &localPlayer.normalSmallSolidBitmap,
997         &localPlayer.normalSmallSolidBitmap,
998         &localPlayer.normalSmallSolidBitmap,
999         &localPlayer.normalBigSolidBitmap,
1000         &localPlayer.normalBigSolidBitmap,
1001         &localPlayer.normalBigSolidBitmap,
1002         &localPlayer.normalBigSolidBitmap,
1003         &localPlayer.normalSmallSolidBitmap,
1004         &localPlayer.normalSmallSolidBitmap,
1005         &localPlayer.normalSmallSolidBitmap,
1006         &localPlayer.normalBigSolidBitmap,
1007         &localPlayer.normalBigSolidBitmap,
1008         &localPlayer.normalBigSolidBitmap,
1009         &localPlayer.normalBigSolidBitmap
1010     },
1011     {
1012         &remotePlayer.normalSmallSolidBitmap,
1013         &remotePlayer.normalSmallSolidBitmap,
1014         &remotePlayer.normalSmallSolidBitmap,
1015         &remotePlayer.normalBigSolidBitmap,
1016         &remotePlayer.normalBigSolidBitmap,
1017         &remotePlayer.normalBigSolidBitmap,
1018         &remotePlayer.normalBigSolidBitmap,
1019         &remotePlayer.normalSmallSolidBitmap,
1020         &remotePlayer.normalSmallSolidBitmap,
1021         &remotePlayer.normalSmallSolidBitmap,
1022         &remotePlayer.normalBigSolidBitmap,
1023         &remotePlayer.normalBigSolidBitmap,
1024         &remotePlayer.normalBigSolidBitmap,
1025         &remotePlayer.normalBigSolidBitmap,
1026         &remotePlayer.normalSmallSolidBitmap,
1027         &remotePlayer.normalSmallSolidBitmap,
1028         &remotePlayer.normalSmallSolidBitmap,
1029         &remotePlayer.normalBigSolidBitmap,
1030         &remotePlayer.normalBigSolidBitmap,
1031         &remotePlayer.normalBigSolidBitmap,
1032         &remotePlayer.normalBigSolidBitmap,
1033         &remotePlayer.normalSmallSolidBitmap,
1034         &remotePlayer.normalSmallSolidBitmap,
1035         &remotePlayer.normalSmallSolidBitmap,
1036         &remotePlayer.normalBigSolidBitmap,
1037         &remotePlayer.normalBigSolidBitmap,
1038         &remotePlayer.normalBigSolidBitmap,
1039         &remotePlayer.normalBigSolidBitmap
1040     }
1041 };
1042 
1043 
1044 
1045 int pieceIsPromoted[] =
1046 {
1047     False, False, False, False, False, False, False,
1048     True,  True,  True,  True,  True,  True,  False,
1049     False, False, False, False, False, False, False,
1050     True,  True,  True,  True,  True,  True,  False,
1051     False
1052 };
1053 
1054 
1055 int piecePromotable[] =
1056 {
1057     True,  True,  True,  True,  False, True,  True,
1058     False, False, False, False, False, False, False,
1059     True,  True,  True,  True,  False, True,  True,
1060     False, False, False, False, False, False, False,
1061     False
1062 };
1063 
1064 
1065 char pieceToChar[] =
1066 {
1067     'P', 'L', 'N', 'S', 'G', 'B', 'R', 'P', 'L', 'N', 'S', 'B', 'R', 'K',
1068     'p', 'l', 'n', 's', 'g', 'b', 'r', 'p', 'l', 'n', 's', 'b', 'r', 'k',
1069     '.'
1070 };
1071 
1072 
1073 ShogiSquare pieceToPromoted[] =
1074 {
1075     BlackPPawn,   BlackPLance, BlackPKnight, BlackPSilver, BlackGold,
1076     BlackPBishop, BlackPRook,
1077     BlackPPawn,   BlackPLance, BlackPKnight, BlackPSilver,
1078     BlackPBishop, BlackPRook,  BlackKing,
1079     WhitePPawn,   WhitePLance, WhitePKnight, WhitePSilver, WhiteGold,
1080     WhitePBishop, WhitePRook,
1081     WhitePPawn,   WhitePLance, WhitePKnight, WhitePSilver,
1082     WhitePBishop, WhitePRook,  WhiteKing
1083 };
1084 
1085 
1086 
1087 XrmOptionDescRec shellOptions[] =
1088 {
1089     { "-pieceColor", "pieceColor", XrmoptionSepArg, NULL },
1090     { "-pc", "pieceColor", XrmoptionSepArg, NULL },
1091     { "-charPieceColor", "charPieceColor", XrmoptionSepArg, NULL },
1092     { "-cpc", "charPieceColor", XrmoptionSepArg, NULL },
1093     { "-zeroColor", "zeroColor", XrmoptionSepArg, NULL },
1094     { "-zc", "zeroColor", XrmoptionSepArg, NULL },
1095     { "-oneColor", "oneColor", XrmoptionSepArg, NULL },
1096     { "-oc", "oneColor", XrmoptionSepArg, NULL },
1097     { "-squareColor", "squareColor", XrmoptionSepArg, NULL },
1098     { "-sc", "squareColor", XrmoptionSepArg, NULL },
1099     { "-westernPieceSet", "westernPieceSet", XrmoptionSepArg, NULL },
1100     { "-wps", "westernPieceSet", XrmoptionSepArg, NULL },
1101     { "-movesPerSession", "movesPerSession", XrmoptionSepArg, NULL },
1102     { "-mps", "movesPerSession", XrmoptionSepArg, NULL },
1103     { "-firstShogiProgram", "firstShogiProgram", XrmoptionSepArg, NULL },
1104     { "-fsp", "firstShogiProgram", XrmoptionSepArg, NULL },
1105     { "-secondShogiProgram", "secondShogiProgram", XrmoptionSepArg, NULL },
1106     { "-ssp", "secondShogiProgram", XrmoptionSepArg, NULL },
1107     { "-noShogiProgram", "noShogiProgram", XrmoptionSepArg, NULL },
1108     { "-nsp", "noShogiProgram", XrmoptionSepArg, NULL },
1109     { "-firstHost", "firstHost", XrmoptionSepArg, NULL },
1110     { "-fh", "firstHost", XrmoptionSepArg, NULL },
1111     { "-secondHost", "secondHost", XrmoptionSepArg, NULL },
1112     { "-sh", "secondHost", XrmoptionSepArg, NULL },
1113     { "-reversePawnBitmap", "reversePawnBitmap", XrmoptionSepArg, NULL },
1114     { "-rpb", "reversePawnBitmap", XrmoptionSepArg, NULL },
1115     { "-reverseLanceBitmap", "reverseLanceBitmap", XrmoptionSepArg, NULL },
1116     { "-rlb", "reverseLanceBitmap", XrmoptionSepArg, NULL },
1117     { "-reverseKnightBitmap", "reverseKnightBitmap", XrmoptionSepArg, NULL },
1118     { "-rnb", "reverseKnightBitmap", XrmoptionSepArg, NULL },
1119     { "-reverseSilverBitmap", "reverseSilverBitmap", XrmoptionSepArg, NULL },
1120     { "-rsb", "reverseSilverBitmap", XrmoptionSepArg, NULL },
1121     { "-reverseGoldBitmap", "reverseGoldBitmap", XrmoptionSepArg, NULL },
1122     { "-rgb", "reverseGoldBitmap", XrmoptionSepArg, NULL },
1123     { "-reverseRookBitmap", "reverseRookBitmap", XrmoptionSepArg, NULL },
1124     { "-rrb", "reverseRookBitmap", XrmoptionSepArg, NULL },
1125     { "-reverseBishopBitmap", "reverseBishopBitmap", XrmoptionSepArg, NULL },
1126     { "-rbb", "reverseBishopBitmap", XrmoptionSepArg, NULL },
1127     { "-reversePPawnBitmap", "reversePPawnBitmap",
1128       XrmoptionSepArg, NULL },
1129     { "-rppb", "reversePPawnBitmap", XrmoptionSepArg, NULL },
1130     { "-reversePLanceBitmap", "reversePLanceBitmap",
1131       XrmoptionSepArg, NULL },
1132     { "-rplb", "reversePLanceBitmap", XrmoptionSepArg, NULL },
1133     { "-reversePKnightBitmap", "reversePKnightBitmap",
1134       XrmoptionSepArg, NULL },
1135     { "-rpnb", "reversePKnightBitmap", XrmoptionSepArg, NULL },
1136     { "-reversePSilverBitmap", "reversePSilverBitmap",
1137       XrmoptionSepArg, NULL },
1138     { "-rpsb", "reversePSilverBitmap", XrmoptionSepArg, NULL },
1139     { "-reversePRookBitmap", "reversePRookBitmap",
1140       XrmoptionSepArg, NULL },
1141     { "-rprb", "reversePRookBitmap", XrmoptionSepArg, NULL },
1142     { "-reversePBishopBitmap", "reversePBishopBitmap",
1143       XrmoptionSepArg, NULL },
1144     { "-rpbb", "reversePBishopBitmap", XrmoptionSepArg, NULL },
1145     { "-reverseKingBitmap", "reverseKingBitmap", XrmoptionSepArg, NULL },
1146     { "-rkb", "reverseKingBitmap", XrmoptionSepArg, NULL },
1147     { "-outlinePawnBitmap", "outlinePawnBitmap", XrmoptionSepArg, NULL },
1148     { "-opb", "normalPawnBitmap", XrmoptionSepArg, NULL },
1149     { "-normalLanceBitmap", "normalLanceBitmap", XrmoptionSepArg, NULL },
1150     { "-olb", "normalLanceBitmap", XrmoptionSepArg, NULL },
1151     { "-normalKnightBitmap", "normalKnightBitmap", XrmoptionSepArg, NULL },
1152     { "-onb", "normalKnightBitmap", XrmoptionSepArg, NULL },
1153     { "-normalSilverBitmap", "normalSilverBitmap", XrmoptionSepArg, NULL },
1154     { "-osb", "normalSilverBitmap", XrmoptionSepArg, NULL },
1155     { "-normalGoldBitmap", "normalGoldBitmap", XrmoptionSepArg, NULL },
1156     { "-ogb", "normalGoldBitmap", XrmoptionSepArg, NULL },
1157     { "-normalRookBitmap", "normalRookBitmap", XrmoptionSepArg, NULL },
1158     { "-orb", "normalRookBitmap", XrmoptionSepArg, NULL },
1159     { "-normalBishopBitmap", "normalBishopBitmap", XrmoptionSepArg, NULL },
1160     { "-obb", "normalBishopBitmap", XrmoptionSepArg, NULL },
1161     { "-normalPPawnBitmap", "normalPPawnBitmap", XrmoptionSepArg, NULL },
1162     { "-oppb", "normalPPawnBitmap", XrmoptionSepArg, NULL },
1163     { "-normalPLanceBitmap", "normalPLanceBitmap", XrmoptionSepArg, NULL },
1164     { "-oplb", "normalPLanceBitmap", XrmoptionSepArg, NULL },
1165     { "-normalPKnightBitmap", "normalPKnightBitmap", XrmoptionSepArg, NULL },
1166     { "-opnb", "normalPKnightBitmap", XrmoptionSepArg, NULL },
1167     { "-normalPSilverBitmap", "normalPSilverBitmap", XrmoptionSepArg, NULL },
1168     { "-opsb", "normalPSilverBitmap", XrmoptionSepArg, NULL },
1169     { "-normalPRookBitmap", "normalPRookBitmap", XrmoptionSepArg, NULL },
1170     { "-oprb", "normalPRookBitmap", XrmoptionSepArg, NULL },
1171     { "-normalPBishopBitmap", "normalPBishopBitmap", XrmoptionSepArg, NULL },
1172     { "-opbb", "normalPBishopBitmap", XrmoptionSepArg, NULL },
1173     { "-normalKingBitmap", "normalKingBitmap", XrmoptionSepArg, NULL },
1174     { "-okb", "outlineKingBitmap", XrmoptionSepArg, NULL },
1175     { "-remoteShell", "remoteShell", XrmoptionSepArg, NULL },
1176     { "-rsh", "remoteShell", XrmoptionSepArg, NULL },
1177     { "-timeDelay", "timeDelay", XrmoptionSepArg, NULL },
1178     { "-td", "timeDelay", XrmoptionSepArg, NULL },
1179     { "-timeControl", "timeControl", XrmoptionSepArg, NULL },
1180     { "-tc", "timeControl", XrmoptionSepArg, NULL },
1181     { "-gameIn", "gameIn", XrmoptionSepArg, NULL },
1182     { "-gi", "gameIn", XrmoptionSepArg, NULL },
1183     { "-loadGameFile", "loadGameFile", XrmoptionSepArg, NULL },
1184     { "-lgf", "loadGameFile", XrmoptionSepArg, NULL },
1185     { "-loadPositionFile", "loadPositionFile", XrmoptionSepArg, NULL },
1186     { "-lpf", "loadPositionFile", XrmoptionSepArg, NULL },
1187     { "-saveGameFile", "saveGameFile", XrmoptionSepArg, NULL },
1188     { "-sgf", "saveGameFile", XrmoptionSepArg, NULL },
1189     { "-savePositionFile", "savePositionFile", XrmoptionSepArg, NULL },
1190     { "-spf", "savePositionFile", XrmoptionSepArg, NULL },
1191     { "-challengeDisplay", "challengeDisplay", XrmoptionSepArg, NULL },
1192     { "-cd", "challengeDisplay", XrmoptionSepArg, NULL },
1193     { "-matchMode", "matchMode", XrmoptionSepArg, NULL },
1194     { "-mm", "matchMode", XrmoptionSepArg, NULL },
1195     { "-monoMode", "monoMode", XrmoptionSepArg, NULL },
1196     { "-mono", "monoMode", XrmoptionSepArg, NULL },
1197     { "-debugMode", "debugMode", XrmoptionSepArg, NULL },
1198     { "-debug", "debugMode", XrmoptionSepArg, NULL },
1199     { "-clockMode", "clockMode", XrmoptionSepArg, NULL },
1200     { "-clock", "clockMode", XrmoptionSepArg, NULL },
1201     { "-boardSize", "boardSize", XrmoptionSepArg, NULL },
1202     { "-size", "boardSize", XrmoptionSepArg, NULL },
1203     { "-searchTime", "searchTime", XrmoptionSepArg, NULL },
1204     { "-st", "searchTime", XrmoptionSepArg, NULL },
1205     { "-searchDepth", "searchDepth", XrmoptionSepArg, NULL },
1206     { "-sd", "searchDepth", XrmoptionSepArg, NULL },
1207     { "-showCoords", "showCoords", XrmoptionSepArg, NULL },
1208     { "-coords", "showCoords", XrmoptionSepArg, NULL },
1209     { "-iconic", "Iconic", XrmoptionNoArg, "True" }
1210 };
1211 
1212 
1213 
1214 XtActionsRec boardActions[] =
1215 {
1216     { "DrawPosition",   (XtActionProc) DrawPosition },
1217     { "HandleUserMove", (XtActionProc) HandleUserMove },
1218     { "ResetProc",      (XtActionProc) ResetProc },
1219     { "ResetFileProc",  (XtActionProc) ResetFileProc },
1220     { "LoadGameProc",   (XtActionProc) LoadGameProc },
1221     { "QuitProc",       (XtActionProc) QuitProc },
1222     { "ForwardProc",    (XtActionProc) ForwardProc },
1223     { "BackwardProc",   (XtActionProc) BackwardProc },
1224     { "PauseProc",      (XtActionProc) PauseProc },
1225     { "Iconify",        (XtActionProc) Iconify },
1226     { "FileNameAction", (XtActionProc) FileNameAction },
1227     { "PieceMenuPopup", (XtActionProc) PieceMenuPopup },
1228     { "SetBlackToPlay", (XtActionProc) SetBlackToPlay },
1229     { "SetWhiteToPlay", (XtActionProc) SetWhiteToPlay }
1230 };
1231 
1232 
1233 char translationsTable[] =
1234 "<Expose>: DrawPosition() \n \
1235 <Btn1Down>: HandleUserMove() \n \
1236 <Btn1Up>: HandleUserMove() \n \
1237 <Btn2Down>: XawPositionSimpleMenu(menuW) PieceMenuPopup(menuW) \n \
1238 <Btn3Down>: XawPositionSimpleMenu(menuB) PieceMenuPopup(menuB) \n \
1239 <Key>r: ResetFileProc() ResetProc() \n \
1240 <Key>R: ResetFileProc() ResetProc() \n \
1241 <Key>g: LoadGameProc() \n \
1242 <Key>G: LoadGameProc() \n \
1243 <Key>q: QuitProc() \n \
1244 <Key>Q: QuitProc() \n \
1245 <Message>WM_PROTOCOLS: QuitProc() \n \
1246 <Key>f: ForwardProc() \n \
1247 <Key>F: ForwardProc() \n \
1248 <Key>b: BackwardProc() \n \
1249 <Key>B: BackwardProc() \n \
1250 <Key>p: PauseProc() \n \
1251 <Key>P: PauseProc() \n \
1252 <Key>i: Iconify() \n \
1253 <Key>I: Iconify() \n \
1254 <Key>c: Iconify() \n \
1255 <Key>C: Iconify() \n";
1256 
1257 
1258 char translationsTableReduced[] =
1259 "<Expose>: DrawPosition() \n \
1260 <Btn1Down>: HandleUserMove() \n \
1261 <Btn1Up>: HandleUserMove() \n \
1262 <Message>WM_PROTOCOLS: QuitProc() \n";
1263 
1264 
1265 char blackTranslations[] = "<BtnDown>: SetBlackToPlay()\n";
1266 char whiteTranslations[] = "<BtnDown>: SetWhiteToPlay()\n";
1267 
1268 String xshogiResources[] =
1269 {
1270     DEFAULT_FONT,
1271     "*Dialog*value.translations: #override "
1272     "\\n <Key>Return: FileNameAction()",
1273     NULL
1274 };
1275 
1276 
1277 int global_argc;       /* number of command args */
1278 char *global_argv[10]; /* pointers to up to 10 command args */
1279 
1280 
1281 
1282 static struct DisplayData *player;
1283 
1284 
1285 typedef struct
1286 {
1287     char mode[2];
1288     char name[100];
1289 } FileModeInfo;
1290 
1291 static FileModeInfo fmi;
1292 
1293 
1294 /*
1295  * This is a hack that allows the parser to tell the program
1296  * that the game it's loading has ended.
1297  */
1298 
1299 int loaded_game_finished = 0;
1300 
1301 
1302 /**********************************************************************
1303  *
1304  * End of globals.
1305  *
1306  **********************************************************************/
1307 
1308 
1309 void
CreatePlayerWindow(void)1310 CreatePlayerWindow(void)
1311 {
1312     int mainFontPxlSize, coordFontPxlSize;
1313     int min, sec, matched;
1314     XSetWindowAttributes window_attributes;
1315     char buf[MSG_SIZ];
1316     Arg args[10];
1317     Dimension timerWidth, boardWidth, commandsWidth, w, h;
1318     int local;
1319     int fromRemotePlayer = (player == &remotePlayer);
1320 
1321     player->monoMode = player->appData.monoMode;
1322     player->showCoords = player->appData.showCoords;
1323 
1324     /*
1325      * Parse timeControl resource.
1326      */
1327 
1328     if (player->appData.timeControl != NULL)
1329     {
1330         matched = sscanf(player->appData.timeControl, "%d:%d", &min, &sec);
1331 
1332         if (matched == 1)
1333         {
1334             timeControl = min * 60 * 1000;
1335         }
1336         else if (matched == 2)
1337         {
1338             timeControl = (min * 60 + sec) * 1000;
1339         }
1340         else
1341         {
1342             fprintf(stderr, "%s: bad timeControl option %s\n",
1343                     programName, player->appData.timeControl);
1344             Usage();
1345         }
1346     }
1347 
1348     /*
1349      * Parse searchTime resource
1350      */
1351 
1352     if (player->appData.searchTime != NULL)
1353     {
1354         matched = sscanf(player->appData.searchTime, "%d:%d", &min, &sec);
1355 
1356         if (matched == 1)
1357         {
1358             searchTime = min * 60;
1359         }
1360         else if (matched == 2)
1361         {
1362             searchTime = min * 60 + sec;
1363         }
1364         else
1365         {
1366             fprintf(stderr, "%s: bad searchTime option %s\n",
1367                     programName, player->appData.searchTime);
1368             Usage();
1369         }
1370     }
1371 
1372     if ((player->appData.searchTime != NULL)
1373         || (player->appData.searchDepth > 0)
1374         || player->appData.noShogiProgram)
1375     {
1376         player->appData.clockMode = False;
1377     }
1378 
1379     player->Iconic = False;
1380     player->boardSize = Small;
1381     player->squareSize = SMALL_SQUARE_SIZE;
1382     player->flipView = (player == &remotePlayer);
1383     player->promotionUp = False;
1384 
1385     /*
1386      * Determine boardSize.
1387      */
1388 
1389     if (strcasecmp(player->appData.boardSize, "Large") == 0)
1390     {
1391         player->boardSize = Large;
1392     }
1393     else if (strcasecmp(player->appData.boardSize, "Medium") == 0)
1394     {
1395         player->boardSize = Medium;
1396     }
1397     else if (strcasecmp(player->appData.boardSize, "Small") == 0)
1398     {
1399         player->boardSize = Small;
1400     }
1401     else
1402     {
1403         fprintf(stderr, "%s: bad boardSize option %s\n",
1404                 programName, player->appData.boardSize);
1405         Usage();
1406     }
1407 
1408     if ((local = (player == &localPlayer)))
1409     {
1410         player->xDisplay = XtDisplay(player->shellWidget);
1411         player->xScreen = DefaultScreen(player->xDisplay);
1412     }
1413 
1414 #undef DONT_ADJUST_BOARDSIZE
1415 #ifndef DONT_ADJUST_BOARDSIZE
1416     if (((DisplayWidth(player->xDisplay, player->xScreen) < 800)
1417          || (DisplayHeight(player->xDisplay, player->xScreen) < 800))
1418         && (player->boardSize == Large))
1419     {
1420         player->boardSize = Medium;
1421     }
1422 #endif
1423 
1424     switch (player->boardSize)
1425     {
1426     case Small:
1427         player->squareSize = SMALL_SQUARE_SIZE;
1428         mainFontPxlSize    = 11;
1429         coordFontPxlSize   = 10;
1430         break;
1431 
1432     case Medium:
1433         player->squareSize = MEDIUM_SQUARE_SIZE;
1434         mainFontPxlSize    = 17;
1435         coordFontPxlSize   = 12;
1436         break;
1437 
1438     default:
1439     case Large:
1440         player->squareSize = LARGE_SQUARE_SIZE;
1441         mainFontPxlSize    = 17;
1442         coordFontPxlSize   = 14;
1443         break;
1444     }
1445 
1446     /*
1447      * Detect if there are not enough colors are available and adapt.
1448      */
1449 
1450     if (DefaultDepth(player->xDisplay, player->xScreen) <= 2)
1451         player->monoMode = True;
1452 
1453     /*
1454      * Determine what fonts to use.
1455      */
1456 
1457     player->appData.mainFont
1458         = FindFont(player->appData.mainFont, mainFontPxlSize);
1459     player->mainFontID
1460         = XLoadFont(player->xDisplay, player->appData.mainFont);
1461     player->mainFontStruct
1462         = XQueryFont(player->xDisplay, player->mainFontID);
1463     player->appData.coordFont
1464         = FindFont(player->appData.coordFont, coordFontPxlSize);
1465     player->coordFontID
1466         = XLoadFont(player->xDisplay, player->appData.coordFont);
1467     player->coordFontStruct
1468         = XQueryFont(player->xDisplay, player->coordFontID);
1469 
1470     /*
1471      * Set default arguments.
1472      */
1473 
1474     XtSetArg(player->shellArgs[0], XtNwidth, 0);
1475     XtSetArg(player->shellArgs[1], XtNheight, 0);
1476     XtSetArg(player->shellArgs[2], XtNminWidth, 0);
1477     XtSetArg(player->shellArgs[3], XtNminHeight, 0);
1478     XtSetArg(player->shellArgs[4], XtNmaxWidth, 0);
1479     XtSetArg(player->shellArgs[5], XtNmaxHeight, 0);
1480 
1481     XtSetArg(player->boardArgs[0], XtNborderWidth, 0);
1482     XtSetArg(player->boardArgs[1], XtNwidth,
1483              LINE_GAP + (BOARD_SIZE + 4)
1484              * (SMALL_SQUARE_SIZE + LINE_GAP));
1485     XtSetArg(player->boardArgs[2], XtNheight,
1486              LINE_GAP + BOARD_SIZE
1487              * (SMALL_SQUARE_SIZE + LINE_GAP));
1488 
1489     XtSetArg(player->commandsArgs[0], XtNborderWidth, 0);
1490     XtSetArg(player->commandsArgs[1], XtNdefaultColumns, 4);
1491     XtSetArg(player->commandsArgs[2], XtNforceColumns, True);
1492     XtSetArg(player->commandsArgs[3], XtNcolumnSpacing, 12);
1493     XtSetArg(player->commandsArgs[4], XtNlist, (XtArgVal) buttonStrings);
1494     XtSetArg(player->commandsArgs[5], XtNnumberStrings, buttonCount);
1495     XtSetArg(player->commandsArgs[6], XtNfont, player->mainFontStruct);
1496 
1497     XtSetArg(player->messageArgs[0], XtNborderWidth, 0);
1498     XtSetArg(player->messageArgs[1], XtNjustify, (XtArgVal) XtJustifyLeft);
1499     XtSetArg(player->messageArgs[2], XtNlabel, (XtArgVal) "starting...");
1500 
1501     XtSetArg(player->timerArgs[0], XtNborderWidth, 0);
1502     XtSetArg(player->timerArgs[1], XtNjustify, (XtArgVal) XtJustifyLeft);
1503 
1504     XtSetArg(player->titleArgs[0], XtNborderWidth, 0);
1505     XtSetArg(player->titleArgs[1], XtNjustify, (XtArgVal) XtJustifyLeft);
1506 
1507     boardWidth = LINE_GAP
1508         + (BOARD_SIZE + 4) * (player->squareSize + LINE_GAP);
1509 
1510     XtSetArg(player->boardArgs[1], XtNwidth, boardWidth);
1511     XtSetArg(player->boardArgs[2], XtNheight,
1512              LINE_GAP + BOARD_SIZE * (player->squareSize + LINE_GAP));
1513 
1514     /*
1515      * widget hierarchy
1516      */
1517 
1518     player->formWidget = XtCreateManagedWidget("form",
1519                                                formWidgetClass,
1520                                                player->shellWidget, NULL, 0);
1521 
1522     player->widgetList[0] = player->blackTimerWidget
1523         = XtCreateWidget((local ? "black time:" : "rblack time:"),
1524                          labelWidgetClass,
1525                          player->formWidget, player->timerArgs,
1526                          XtNumber(player->timerArgs));
1527 
1528     XtSetArg(args[0], XtNfont, player->mainFontStruct);
1529     XtSetValues(player->blackTimerWidget, args, 1);
1530 
1531     player->widgetList[1] = player->whiteTimerWidget
1532         = XtCreateWidget((local ? "white time:" : "rwhite time:"),
1533                          labelWidgetClass,
1534                          player->formWidget, player->timerArgs,
1535                          XtNumber(player->timerArgs));
1536 
1537     XtSetArg(args[0], XtNfont, player->mainFontStruct);
1538     XtSetValues(player->whiteTimerWidget, args, 1);
1539 
1540     player->widgetList[2] = player->titleWidget
1541         = XtCreateWidget((local ? "" : "r"), labelWidgetClass,
1542                          player->formWidget, player->titleArgs,
1543                          XtNumber(player->titleArgs));
1544 
1545     XtSetArg(args[0], XtNfont, player->mainFontStruct);
1546     XtSetValues(player->titleWidget, args, 1);
1547 
1548     player->widgetList[3] = player->messageWidget
1549         = XtCreateWidget((local ? "message" : "rmessage"),
1550                          labelWidgetClass, player->formWidget,
1551                          player->messageArgs,
1552                          XtNumber(player->messageArgs));
1553 
1554     XtSetArg(args[0], XtNfont, player->mainFontStruct);
1555     XtSetValues(player->messageWidget, args, 1);
1556 
1557     player->widgetList[4] = player->commandsWidget
1558         = XtCreateWidget((local ? "commands" : "rcommand"),
1559                          listWidgetClass, player->formWidget,
1560                          player->commandsArgs,
1561                          XtNumber(player->commandsArgs));
1562 
1563     player->widgetList[5] = player->boardWidget
1564         = XtCreateWidget((local ? "board" : "rboard"),
1565                          widgetClass, player->formWidget,
1566                          player->boardArgs,
1567                          XtNumber(player->boardArgs));
1568 
1569     XtManageChildren(player->widgetList, XtNumber(player->widgetList));
1570 
1571     /*
1572      * Calculate the width of the timer labels.
1573      */
1574 
1575     XtSetArg(args[0], XtNfont, &player->mainFontStruct);
1576     XtGetValues(player->blackTimerWidget, args, 1);
1577 
1578     if (player->appData.clockMode)
1579     {
1580         timerWidth = XTextWidth(player->mainFontStruct,
1581                                 "Black: 8:88:88 ", 15);
1582     }
1583     else
1584     {
1585         timerWidth = XTextWidth(player->mainFontStruct, "Black  ", 7);
1586     }
1587 
1588     XtSetArg(args[0], XtNwidth, timerWidth);
1589     XtSetValues(player->blackTimerWidget, args, 1);
1590     XtSetValues(player->whiteTimerWidget, args, 1);
1591 
1592     XtSetArg(args[0], XtNbackground, &player->timerForegroundPixel);
1593     XtSetArg(args[1], XtNforeground, &player->timerBackgroundPixel);
1594     XtGetValues(player->blackTimerWidget, args, 2);
1595 
1596     /*
1597      * Calculate the width of the name and message labels.
1598      */
1599 
1600     XtSetArg(args[0], XtNwidth, &commandsWidth);
1601     XtGetValues(player->commandsWidget, args, 1);
1602     w = ((commandsWidth > boardWidth) ? commandsWidth : boardWidth);
1603     XtSetArg(args[0], XtNwidth, w - timerWidth * 2 - 12);
1604     XtSetValues(player->titleWidget, args, 1);
1605     XtSetArg(args[0], XtNwidth, w - 8);
1606     XtSetValues(player->messageWidget, args, 1);
1607 
1608     /*
1609      * 'formWidget' uses these constraints but they are stored
1610      * in the children.
1611      */
1612 
1613     XtSetArg(args[0], XtNfromHoriz, player->blackTimerWidget);
1614     XtSetValues(player->whiteTimerWidget, args, 1);
1615     XtSetArg(args[0], XtNfromHoriz, player->whiteTimerWidget);
1616     XtSetValues(player->titleWidget, args, 1);
1617     XtSetArg(args[0], XtNfromVert, player->blackTimerWidget);
1618     XtSetValues(player->messageWidget, args, 1);
1619     XtSetArg(args[0], XtNfromVert, player->messageWidget);
1620     XtSetValues(player->commandsWidget, args, 1);
1621     XtSetArg(args[0], XtNfromVert, player->commandsWidget);
1622     XtSetValues(player->boardWidget, args, 1);
1623 
1624     XtRealizeWidget(player->shellWidget);
1625 
1626     player->xBoardWindow = XtWindow(player->boardWidget);
1627 
1628     /*
1629      * Create an icon.
1630      */
1631 
1632     player->iconPixmap =
1633         XCreateBitmapFromData(player->xDisplay,
1634                               XtWindow(player->shellWidget),
1635                               (char *)icon_bits, icon_width, icon_height);
1636 
1637     XtSetArg(args[0], XtNiconPixmap, player->iconPixmap);
1638     XtSetValues(player->shellWidget, args, 1);
1639 
1640     /*
1641      * Create a cursor for the board widget.
1642      */
1643 
1644     window_attributes.cursor = XCreateFontCursor(player->xDisplay, XC_hand2);
1645     XChangeWindowAttributes(player->xDisplay, player->xBoardWindow,
1646                             CWCursor, &window_attributes);
1647 
1648     /*
1649      * Inhibit shell resizing.
1650      */
1651 
1652     player->shellArgs[0].value = (XtArgVal) &w;
1653     player->shellArgs[1].value = (XtArgVal) &h;
1654     XtGetValues(player->shellWidget, player->shellArgs, 2);
1655     player->shellArgs[4].value = player->shellArgs[2].value = w;
1656     player->shellArgs[5].value = player->shellArgs[3].value = h;
1657     XtSetValues(player->shellWidget, &player->shellArgs[2], 4);
1658 
1659     /*
1660      * Determine value of black pixel.
1661      */
1662 
1663     player->black_pixel_is_zero =
1664         (XBlackPixel(player->xDisplay, player->xScreen) == 0);
1665 
1666     CreateGCs();
1667     CreateGrid();
1668     CreatePieces();
1669 
1670     if (!fromRemotePlayer)
1671         CreatePieceMenus();
1672 
1673     XtAddCallback(player->commandsWidget, XtNcallback, SelectCommand,
1674                   (XtPointer)fromRemotePlayer);
1675 
1676     if (!fromRemotePlayer)
1677         XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1678 
1679     if (fromRemotePlayer)
1680     {
1681         XtSetArg(args[0], XtNtranslations,
1682                  XtParseTranslationTable(translationsTableReduced));
1683         /* Disable key commands because often keys are pressed
1684            in the board window if using another talk window. */
1685         XtSetValues(player->boardWidget, &args[0], 1);
1686         XtSetValues(localPlayer.boardWidget, &args[0], 1);
1687     }
1688     else
1689     {
1690         XtSetArg(args[0], XtNtranslations,
1691                  XtParseTranslationTable(translationsTable));
1692         XtSetValues(player->boardWidget, &args[0], 1);
1693         XtSetArg(args[0], XtNtranslations,
1694                  XtParseTranslationTable(blackTranslations));
1695         XtSetValues(player->blackTimerWidget, &args[0], 1);
1696         XtSetArg(args[0], XtNtranslations,
1697                  XtParseTranslationTable(whiteTranslations));
1698         XtSetValues(player->whiteTimerWidget, &args[0], 1);
1699     }
1700 
1701     XtAddEventHandler(player->boardWidget, ExposureMask | ButtonPressMask
1702                       | ButtonReleaseMask | Button1MotionMask | KeyPressMask,
1703                       False, (XtEventHandler)EventProc,
1704                       (XtPointer)(player == &remotePlayer));
1705 
1706     sprintf(buf, "xshogi version %s based on "
1707             "xboard version %s",
1708             PACKAGE_VERSION, XBOARD_VERSION);
1709 
1710     /*
1711      * If there is to be a machine match, set it up.
1712      */
1713 
1714     if (matchMode != MatchFalse && player != &remotePlayer)
1715     {
1716         if (player->appData.noShogiProgram)
1717         {
1718             fprintf(stderr,
1719                     "%s: can't have a match with no shogi programs!\n",
1720                     programName);
1721             exit(1);
1722         }
1723 
1724         DisplayMessage(buf, fromRemotePlayer);
1725         TwoMachinesProc(NULL, NULL, NULL, NULL);
1726     }
1727     else
1728     {
1729         Reset(True);
1730         DisplayMessage(buf, fromRemotePlayer);
1731     }
1732 }
1733 
1734 
1735 
1736 
1737 int
main(int argc,char ** argv)1738 main(int argc, char **argv)
1739 {
1740     setbuf(stdout, NULL);
1741     setbuf(stderr, NULL);
1742 
1743     /*
1744      * Copy pointers to command line arguments and number of such pointers.
1745      * (argc, argv will be destroyed by XtAppInitialize)
1746      */
1747 
1748     for (global_argc = 0; global_argc < argc; global_argc++)
1749         global_argv[global_argc] = argv[global_argc];
1750 
1751     programName = strrchr(argv[0], '/');
1752 
1753     if (programName == NULL)
1754         programName = argv[0];
1755     else
1756         programName++;
1757 
1758     localPlayer.shellWidget
1759         = XtAppInitialize(&appContext, "XShogi", shellOptions,
1760                           XtNumber(shellOptions), &argc, argv,
1761                           xshogiResources, NULL, 0);
1762 
1763     if (argc > 1)
1764         Usage();
1765 
1766     if ((shogiDir = (char *)getenv("SHOGIDIR")) == NULL)
1767     {
1768         shogiDir = ".";
1769     }
1770     else
1771     {
1772         if (chdir(shogiDir) != 0)
1773         {
1774             fprintf(stderr, "%s: can't cd to SHOGIDIR\n",
1775                     programName);
1776             perror(shogiDir);
1777             exit(1);
1778         }
1779     }
1780 
1781     XtGetApplicationResources(localPlayer.shellWidget,
1782                               &localPlayer.appData, clientResources,
1783                               XtNumber(clientResources), NULL, 0);
1784 
1785     xshogiDebug = localPlayer.appData.debugMode;
1786 
1787     /*
1788      * Determine matchMode state -- poor man's resource converter.
1789      */
1790 
1791     if (strcasecmp(localPlayer.appData.matchMode, "Init") == 0)
1792     {
1793         matchMode = MatchInit;
1794     }
1795     else if (strcasecmp(localPlayer.appData.matchMode, "Position") == 0)
1796     {
1797         matchMode = MatchPosition;
1798     }
1799     else if (strcasecmp(localPlayer.appData.matchMode, "Opening") == 0)
1800     {
1801         matchMode = MatchOpening;
1802     }
1803     else if (strcasecmp(localPlayer.appData.matchMode, "False") == 0)
1804     {
1805         matchMode = MatchFalse;
1806     }
1807     else
1808     {
1809         fprintf(stderr, "%s: bad matchMode option %s\n",
1810                 programName, localPlayer.appData.matchMode);
1811         Usage();
1812     }
1813 
1814     buttonStrings = gnuButtonStrings;
1815     buttonProcs = gnuButtonProcs;
1816     buttonCount = XtNumber(gnuButtonStrings);
1817 
1818     player = &localPlayer;
1819 
1820     CreatePlayerWindow();
1821 
1822     XtAppMainLoop(appContext);
1823 
1824     return 0;
1825 }
1826 
1827 
1828 
1829 /*
1830  * Find a font that matches "pattern" that is as close as
1831  * possible to the targetPxlSize.  Prefer fonts that are k
1832  * pixels smaller to fonts that are k pixels larger.  The
1833  * pattern must be in the X Consortium standard format,
1834  * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1835  * The return value should be freed with XtFree when no
1836  * longer needed.
1837  */
1838 
1839 char *
FindFont(char * pattern,int targetPxlSize)1840 FindFont(char *pattern, int targetPxlSize)
1841 {
1842     char **fonts, *p, *best;
1843     int i, j, nfonts, minerr, err, pxlSize;
1844 
1845     fonts = XListFonts(player->xDisplay, pattern, 999999, &nfonts);
1846 
1847     if (nfonts < 1)
1848     {
1849         fprintf(stderr, "%s: No fonts match pattern %s\n",
1850                 programName, pattern);
1851         exit(1);
1852     }
1853 
1854     best = "";
1855     minerr = 999999;
1856 
1857     for (i = 0; i < nfonts; i++)
1858     {
1859         j = 0;
1860         p = fonts[i];
1861 
1862         if (*p != '-')
1863             continue;
1864 
1865         while (j < 7)
1866         {
1867             if (*p == NULLCHAR)
1868                 break;
1869 
1870             if (*p++ == '-')
1871                 j++;
1872         }
1873 
1874         if (j < 7)
1875             continue;
1876 
1877         pxlSize = atoi(p);
1878 
1879         if (pxlSize == targetPxlSize)
1880         {
1881             best = fonts[i];
1882             break;
1883         }
1884 
1885         err = pxlSize - targetPxlSize;
1886 
1887         if (abs(err) < abs(minerr)
1888             || ((minerr > 0) && (err < 0) && (-err == minerr)))
1889         {
1890             best = fonts[i];
1891             minerr = err;
1892         }
1893     }
1894 
1895     p = (char *)XtMalloc(strlen(best) + 1);
1896     strcpy(p, best);
1897     XFreeFontNames(fonts);
1898     return p;
1899 }
1900 
1901 
1902 
1903 
1904 void
CreateGCs(void)1905 CreateGCs(void)
1906 {
1907     XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
1908         | GCBackground | GCFunction | GCPlaneMask;
1909     XGCValues gc_values;
1910 
1911     gc_values.plane_mask = AllPlanes;
1912     gc_values.line_width = LINE_GAP;
1913     gc_values.line_style = LineSolid;
1914     gc_values.function = GXcopy;
1915 
1916     gc_values.foreground = XBlackPixel(player->xDisplay, player->xScreen);
1917     gc_values.background = XBlackPixel(player->xDisplay, player->xScreen);
1918     player->lineGC = XtGetGC(player->shellWidget, value_mask, &gc_values);
1919 
1920     gc_values.background = XWhitePixel(player->xDisplay, player->xScreen);
1921     player->coordGC = XtGetGC(player->shellWidget, value_mask, &gc_values);
1922     XSetFont(player->xDisplay, player->coordGC, player->coordFontID);
1923 
1924     if (player->monoMode)
1925     {
1926         gc_values.foreground
1927             = XWhitePixel(player->xDisplay, player->xScreen);
1928         gc_values.background
1929             = XWhitePixel(player->xDisplay, player->xScreen);
1930 
1931         /* empty square off board */
1932         player->squareOffBoardGC
1933             = XtGetGC(player->shellWidget, value_mask, &gc_values);
1934 
1935         /* empty square on board */
1936         player->squareGC
1937             = XtGetGC(player->shellWidget, value_mask, &gc_values);
1938     }
1939     else
1940     {
1941         Pixel bg;         /* background color */
1942         Arg   args[1];
1943 
1944         /* Get background color. */
1945         XtSetArg(args[0], XtNbackground, &bg);
1946         XtGetValues(player->shellWidget, args, 1);
1947 
1948         /* empty square off board */
1949         gc_values.foreground = gc_values.background = bg;
1950         player->squareOffBoardGC
1951             = XtGetGC(player->shellWidget, value_mask, &gc_values);
1952 
1953         /* empty square on board */
1954         gc_values.foreground
1955             = player->appData.squareColor;
1956         gc_values.background
1957             = player->appData.squareColor;
1958         player->squareGC
1959             = XtGetGC(player->shellWidget, value_mask, &gc_values);
1960 
1961         /* piece off board */
1962         gc_values.foreground
1963             = player->appData.pieceColor;
1964         gc_values.background = bg;
1965         player->oPieceGC
1966             = XtGetGC(player->shellWidget, value_mask, &gc_values);
1967 
1968         /* piece on board */
1969         gc_values.foreground
1970             = player->appData.pieceColor;
1971         gc_values.background
1972             = player->appData.squareColor;
1973         player->pieceGC
1974             = XtGetGC(player->shellWidget, value_mask, &gc_values);
1975 
1976         /* piece symbol */
1977         /*
1978          * FIXME: charPieceColor seems to have no effect;
1979          *    the bitmap is *always* black.
1980          */
1981         gc_values.function = (player->black_pixel_is_zero ? GXand : GXor);
1982 
1983         gc_values.foreground
1984             = player->appData.charPieceColor;
1985         gc_values.background
1986             = player->appData.charPieceColor;
1987 
1988         player->charPieceGC
1989             = XtGetGC(player->shellWidget, value_mask, &gc_values);
1990     }
1991 }
1992 
1993 
1994 
1995 
1996 void
CreatePieces(void)1997 CreatePieces(void)
1998 {
1999     XSynchronize(player->xDisplay, True);   /* Work-around for xlib/xt
2000                                                buffering bug */
2001 
2002     if (player->appData.westernPieceSet)
2003     {
2004         ReadBitmap(player->appData.reverseBigSolidBitmap,
2005                    &player->reverseBigSolidBitmap,
2006                    NULL,
2007                    bigsolidR_bits, bigsolidR_m_bits, bigsolidR_l_bits);
2008 
2009         ReadBitmap(player->appData.reverseSmallSolidBitmap,
2010                    &player->reverseSmallSolidBitmap,
2011                    NULL,
2012                    smallsolidR_bits, smallsolidR_m_bits, smallsolidR_l_bits);
2013 
2014         ReadBitmap(player->appData.normalBigSolidBitmap,
2015                    &player->normalBigSolidBitmap,
2016                    NULL,
2017                    bigsolid_bits, bigsolid_m_bits, bigsolid_l_bits);
2018 
2019         ReadBitmap(player->appData.normalSmallSolidBitmap,
2020                    &player->normalSmallSolidBitmap,
2021                    NULL,
2022                    smallsolid_bits, smallsolid_m_bits, smallsolid_l_bits);
2023 
2024         ReadBitmap(player->appData.reversePawnBitmap,
2025                    &player->reversePawnBitmap,
2026                    &player->reverseSmallSolidBitmap,
2027                    pawnRW_bits, pawnRW_bits, pawnRW_bits);
2028 
2029         ReadBitmap(player->appData.reverseLanceBitmap,
2030                    &player->reverseLanceBitmap,
2031                    &player->reverseSmallSolidBitmap,
2032                    lanceRW_bits, lanceRW_bits, lanceRW_bits);
2033 
2034         ReadBitmap(player->appData.reverseKnightBitmap,
2035                    &player->reverseKnightBitmap,
2036                    &player->reverseSmallSolidBitmap,
2037                    knightRW_bits, knightRW_bits, knightRW_bits);
2038 
2039         ReadBitmap(player->appData.reverseSilverBitmap,
2040                    &player->reverseSilverBitmap,
2041                    &player->reverseBigSolidBitmap,
2042                    silverRW_bits, silverRW_bits, silverRW_bits);
2043 
2044         ReadBitmap(player->appData.reverseGoldBitmap,
2045                    &player->reverseGoldBitmap,
2046                    &player->reverseBigSolidBitmap,
2047                    goldRW_bits, goldRW_bits, goldRW_bits);
2048 
2049         ReadBitmap(player->appData.reverseRookBitmap,
2050                    &player->reverseRookBitmap,
2051                    &player->reverseBigSolidBitmap,
2052                    rookRW_bits, rookRW_bits, rookRW_bits);
2053 
2054         ReadBitmap(player->appData.reverseBishopBitmap,
2055                    &player->reverseBishopBitmap,
2056                    &player->reverseBigSolidBitmap,
2057                    bishopRW_bits, bishopRW_bits, bishopRW_bits);
2058 
2059         ReadBitmap(player->appData.reversePPawnBitmap,
2060                    &player->reversePPawnBitmap,
2061                    &player->reverseSmallSolidBitmap,
2062                    pawnPRW_bits, pawnPRW_bits, pawnPRW_bits);
2063 
2064         ReadBitmap(player->appData.reversePLanceBitmap,
2065                    &player->reversePLanceBitmap,
2066                    &player->reverseSmallSolidBitmap,
2067                    lancePRW_bits, lancePRW_bits, lancePRW_bits);
2068 
2069         ReadBitmap(player->appData.reversePKnightBitmap,
2070                    &player->reversePKnightBitmap,
2071                    &player->reverseSmallSolidBitmap,
2072                    knightPRW_bits, knightPRW_bits, knightPRW_bits);
2073 
2074         ReadBitmap(player->appData.reversePSilverBitmap,
2075                    &player->reversePSilverBitmap,
2076                    &player->reverseBigSolidBitmap,
2077                    silverPRW_bits, silverPRW_bits, silverPRW_bits);
2078 
2079         ReadBitmap(player->appData.reversePRookBitmap,
2080                    &player->reversePRookBitmap,
2081                    &player->reverseBigSolidBitmap,
2082                    rookPRW_bits, rookPRW_bits, rookPRW_bits);
2083 
2084         ReadBitmap(player->appData.reversePBishopBitmap,
2085                    &player->reversePBishopBitmap,
2086                    &player->reverseBigSolidBitmap,
2087                    bishopPRW_bits, bishopPRW_bits, bishopPRW_bits);
2088 
2089         ReadBitmap(player->appData.reverseKingBitmap,
2090                    &player->reverseKingBitmap,
2091                    &player->reverseBigSolidBitmap,
2092                    kingRW_bits, kingRW_bits, kingRW_bits);
2093 
2094         ReadBitmap(player->appData.normalPawnBitmap,
2095                    &player->normalPawnBitmap,
2096                    &player->normalSmallSolidBitmap,
2097                    pawnW_bits, pawnW_bits, pawnW_bits);
2098 
2099         ReadBitmap(player->appData.normalLanceBitmap,
2100                    &player->normalLanceBitmap,
2101                    &player->normalSmallSolidBitmap,
2102                    lanceW_bits, lanceW_bits, lanceW_bits);
2103 
2104         ReadBitmap(player->appData.normalKnightBitmap,
2105                    &player->normalKnightBitmap,
2106                    &player->normalSmallSolidBitmap,
2107                    knightW_bits, knightW_bits, knightW_bits);
2108 
2109         ReadBitmap(player->appData.normalSilverBitmap,
2110                    &player->normalSilverBitmap,
2111                    &player->normalBigSolidBitmap,
2112                    silverW_bits, silverW_bits, silverW_bits);
2113 
2114         ReadBitmap(player->appData.normalGoldBitmap,
2115                    &player->normalGoldBitmap,
2116                    &player->normalBigSolidBitmap,
2117                    goldW_bits, goldW_bits, goldW_bits);
2118 
2119         ReadBitmap(player->appData.normalRookBitmap,
2120                    &player->normalRookBitmap,
2121                    &player->normalBigSolidBitmap,
2122                    rookW_bits, rookW_bits, rookW_bits);
2123 
2124         ReadBitmap(player->appData.normalBishopBitmap,
2125                    &player->normalBishopBitmap,
2126                    &player->normalBigSolidBitmap,
2127                    bishopW_bits, bishopW_bits, bishopW_bits);
2128 
2129         ReadBitmap(player->appData.normalPPawnBitmap,
2130                    &player->normalPPawnBitmap,
2131                    &player->normalSmallSolidBitmap,
2132                    pawnPW_bits, pawnPW_bits, pawnPW_bits);
2133 
2134         ReadBitmap(player->appData.normalPLanceBitmap,
2135                    &player->normalPLanceBitmap,
2136                    &player->normalSmallSolidBitmap,
2137                    lancePW_bits, lancePW_bits, lancePW_bits);
2138 
2139         ReadBitmap(player->appData.normalPKnightBitmap,
2140                    &player->normalPKnightBitmap,
2141                    &player->normalSmallSolidBitmap,
2142                    knightPW_bits, knightPW_bits, knightPW_bits);
2143 
2144         ReadBitmap(player->appData.normalPSilverBitmap,
2145                    &player->normalPSilverBitmap,
2146                    &player->normalBigSolidBitmap,
2147                    silverPW_bits, silverPW_bits, silverPW_bits);
2148 
2149         ReadBitmap(player->appData.normalPRookBitmap,
2150                    &player->normalPRookBitmap,
2151                    &player->normalBigSolidBitmap,
2152                    rookPW_bits, rookPW_bits, rookPW_bits);
2153 
2154         ReadBitmap(player->appData.normalPBishopBitmap,
2155                    &player->normalPBishopBitmap,
2156                    &player->normalBigSolidBitmap,
2157                    bishopPW_bits, bishopPW_bits, bishopPW_bits);
2158 
2159         ReadBitmap(player->appData.normalKingBitmap,
2160                    &player->normalKingBitmap,
2161                    &player->normalBigSolidBitmap,
2162                    kingW_bits, kingW_bits, kingW_bits);
2163     }
2164     else
2165     {
2166         ReadBitmap(player->appData.reverseBigSolidBitmap,
2167                    &player->reverseBigSolidBitmap,
2168                    NULL,
2169                    bigsolidR_bits, bigsolidR_m_bits, bigsolidR_l_bits);
2170 
2171         ReadBitmap(player->appData.reverseSmallSolidBitmap,
2172                    &player->reverseSmallSolidBitmap,
2173                    NULL,
2174                    smallsolidR_bits, smallsolidR_m_bits, smallsolidR_l_bits);
2175 
2176         ReadBitmap(player->appData.normalBigSolidBitmap,
2177                    &player->normalBigSolidBitmap,
2178                    NULL,
2179                    bigsolid_bits, bigsolid_m_bits, bigsolid_l_bits);
2180 
2181         ReadBitmap(player->appData.normalSmallSolidBitmap,
2182                    &player->normalSmallSolidBitmap,
2183                    NULL,
2184                    smallsolid_bits, smallsolid_m_bits, smallsolid_l_bits);
2185 
2186         ReadBitmap(player->appData.reversePawnBitmap,
2187                    &player->reversePawnBitmap,
2188                    &player->reverseSmallSolidBitmap,
2189                    pawnR_bits, pawnR_m_bits, pawnR_l_bits);
2190 
2191         ReadBitmap(player->appData.reverseLanceBitmap,
2192                    &player->reverseLanceBitmap,
2193                    &player->reverseSmallSolidBitmap,
2194                    lanceR_bits, lanceR_m_bits, lanceR_l_bits);
2195 
2196         ReadBitmap(player->appData.reverseKnightBitmap,
2197                    &player->reverseKnightBitmap,
2198                    &player->reverseSmallSolidBitmap,
2199                    knightR_bits, knightR_m_bits, knightR_l_bits);
2200 
2201         ReadBitmap(player->appData.reverseSilverBitmap,
2202                    &player->reverseSilverBitmap,
2203                    &player->reverseBigSolidBitmap,
2204                    silverR_bits, silverR_m_bits, silverR_l_bits);
2205 
2206         ReadBitmap(player->appData.reverseGoldBitmap,
2207                    &player->reverseGoldBitmap,
2208                    &player->reverseBigSolidBitmap,
2209                    goldR_bits, goldR_m_bits, goldR_l_bits);
2210 
2211         ReadBitmap(player->appData.reverseRookBitmap,
2212                    &player->reverseRookBitmap,
2213                    &player->reverseBigSolidBitmap,
2214                    rookR_bits, rookR_m_bits, rookR_l_bits);
2215 
2216         ReadBitmap(player->appData.reverseBishopBitmap,
2217                    &player->reverseBishopBitmap,
2218                    &player->reverseBigSolidBitmap,
2219                    bishopR_bits, bishopR_m_bits, bishopR_l_bits);
2220 
2221         ReadBitmap(player->appData.reversePPawnBitmap,
2222                    &player->reversePPawnBitmap,
2223                    &player->reverseSmallSolidBitmap,
2224                    pawnPR_bits, pawnPR_m_bits, pawnPR_l_bits);
2225 
2226         ReadBitmap(player->appData.reversePLanceBitmap,
2227                    &player->reversePLanceBitmap,
2228                    &player->reverseSmallSolidBitmap,
2229                    lancePR_bits, lancePR_m_bits, lancePR_l_bits);
2230 
2231         ReadBitmap(player->appData.reversePKnightBitmap,
2232                    &player->reversePKnightBitmap,
2233                    &player->reverseSmallSolidBitmap,
2234                    knightPR_bits, knightPR_m_bits, knightPR_l_bits);
2235 
2236         ReadBitmap(player->appData.reversePSilverBitmap,
2237                    &player->reversePSilverBitmap,
2238                    &player->reverseBigSolidBitmap,
2239                    silverPR_bits, silverPR_m_bits, silverPR_l_bits);
2240 
2241         ReadBitmap(player->appData.reversePRookBitmap,
2242                    &player->reversePRookBitmap,
2243                    &player->reverseBigSolidBitmap,
2244                    rookPR_bits, rookPR_m_bits, rookPR_l_bits);
2245 
2246         ReadBitmap(player->appData.reversePBishopBitmap,
2247                    &player->reversePBishopBitmap,
2248                    &player->reverseBigSolidBitmap,
2249                    bishopPR_bits, bishopPR_m_bits, bishopPR_l_bits);
2250 
2251         ReadBitmap(player->appData.reverseKingBitmap,
2252                    &player->reverseKingBitmap,
2253                    &player->reverseBigSolidBitmap,
2254                    kingR_bits, kingR_m_bits, kingR_l_bits);
2255 
2256         ReadBitmap(player->appData.normalPawnBitmap,
2257                    &player->normalPawnBitmap,
2258                    &player->normalSmallSolidBitmap,
2259                    pawn_bits, pawn_m_bits, pawn_l_bits);
2260 
2261         ReadBitmap(player->appData.normalLanceBitmap,
2262                    &player->normalLanceBitmap,
2263                    &player->normalSmallSolidBitmap,
2264                    lance_bits, lance_m_bits, lance_l_bits);
2265 
2266         ReadBitmap(player->appData.normalKnightBitmap,
2267                    &player->normalKnightBitmap,
2268                    &player->normalSmallSolidBitmap,
2269                    knight_bits, knight_m_bits, knight_l_bits);
2270 
2271         ReadBitmap(player->appData.normalSilverBitmap,
2272                    &player->normalSilverBitmap,
2273                    &player->normalBigSolidBitmap,
2274                    silver_bits, silver_m_bits, silver_l_bits);
2275 
2276         ReadBitmap(player->appData.normalGoldBitmap,
2277                    &player->normalGoldBitmap,
2278                    &player->normalBigSolidBitmap,
2279                    gold_bits, gold_m_bits, gold_l_bits);
2280 
2281         ReadBitmap(player->appData.normalRookBitmap,
2282                    &player->normalRookBitmap,
2283                    &player->normalBigSolidBitmap,
2284                    rook_bits, rook_m_bits, rook_l_bits);
2285 
2286         ReadBitmap(player->appData.normalBishopBitmap,
2287                    &player->normalBishopBitmap,
2288                    &player->normalBigSolidBitmap,
2289                    bishop_bits, bishop_m_bits, bishop_l_bits);
2290 
2291         ReadBitmap(player->appData.normalPPawnBitmap,
2292                    &player->normalPPawnBitmap,
2293                    &player->normalSmallSolidBitmap,
2294                    pawnP_bits, pawnP_m_bits, pawnP_l_bits);
2295 
2296         ReadBitmap(player->appData.normalPLanceBitmap,
2297                    &player->normalPLanceBitmap,
2298                    &player->normalSmallSolidBitmap,
2299                    lanceP_bits, lanceP_m_bits, lanceP_l_bits);
2300 
2301         ReadBitmap(player->appData.normalPKnightBitmap,
2302                    &player->normalPKnightBitmap,
2303                    &player->normalSmallSolidBitmap,
2304                    knightP_bits, knightP_m_bits, knightP_l_bits);
2305 
2306         ReadBitmap(player->appData.normalPSilverBitmap,
2307                    &player->normalPSilverBitmap,
2308                    &player->normalBigSolidBitmap,
2309                    silverP_bits, silverP_m_bits, silverP_l_bits);
2310 
2311         ReadBitmap(player->appData.normalPRookBitmap,
2312                    &player->normalPRookBitmap,
2313                    &player->normalBigSolidBitmap,
2314                    rookP_bits, rookP_m_bits, rookP_l_bits);
2315 
2316         ReadBitmap(player->appData.normalPBishopBitmap,
2317                    &player->normalPBishopBitmap,
2318                    &player->normalBigSolidBitmap,
2319                    bishopP_bits, bishopP_m_bits, bishopP_l_bits);
2320 
2321         ReadBitmap(player->appData.normalKingBitmap,
2322                    &player->normalKingBitmap,
2323                    &player->normalBigSolidBitmap,
2324                    king_bits, king_m_bits, king_l_bits);
2325 
2326     }
2327 
2328     XSynchronize(player->xDisplay, False);  /* Work-around for xlib/xt
2329                                                buffering bug */
2330 }
2331 
2332 
2333 
2334 
2335 int
ReadBitmapFile(Display * display,Drawable d,char * filename,unsigned int * width_return,unsigned int * height_return,Pixmap * bitmap_return,int * x_hot_return,int * y_hot_return)2336 ReadBitmapFile(Display *display, Drawable d, char *filename,
2337                unsigned int *width_return,
2338                unsigned int *height_return,
2339                Pixmap *bitmap_return,
2340                int *x_hot_return, int *y_hot_return)
2341 {
2342     int n;
2343 
2344     if ((n = XReadBitmapFile(display, d, filename,
2345                              width_return, height_return,
2346                              bitmap_return, x_hot_return, y_hot_return))
2347         != BitmapSuccess)
2348     {
2349         return n;
2350     }
2351     else
2352     {
2353         /* transform a 1 plane pixmap to a k plane pixmap */
2354         return BitmapSuccess;
2355     }
2356 }
2357 
2358 
2359 
2360 
2361 /*
2362  * Create the X pixmap from .xbm file bitmap data.  This may
2363  * have to be revised considerably.
2364  */
2365 
2366 void
ReadBitmap(String name,Pixmap * pm,Pixmap * qm,unsigned char * small_bits,unsigned char * medium_bits,unsigned char * large_bits)2367 ReadBitmap(String name, Pixmap *pm, Pixmap *qm,
2368            unsigned char *small_bits,
2369 		   unsigned char *medium_bits,
2370 		   unsigned char *large_bits)
2371 {
2372     int x_hot, y_hot;
2373     unsigned int w, h;
2374 
2375     if ((name == NULL)
2376         || (ReadBitmapFile(player->xDisplay, player->xBoardWindow, name,
2377                           &w, &h, pm, &x_hot, &y_hot) != BitmapSuccess)
2378         || (w != player->squareSize)
2379         || (h != player->squareSize))
2380     {
2381         unsigned long fg, bg;
2382         unsigned int depth;
2383 
2384         depth = DisplayPlanes(player->xDisplay, player->xScreen);
2385 
2386         if (player->monoMode)
2387         {
2388             fg = XBlackPixel(player->xDisplay, player->xScreen);
2389             bg = XWhitePixel(player->xDisplay, player->xScreen);
2390         }
2391         else if (qm == NULL)
2392         {
2393             fg = player->appData.oneColor;
2394             bg = player->appData.zeroColor;
2395         }
2396         else
2397         {
2398             fg = (player->black_pixel_is_zero ? 0 : ~0);
2399             bg = (player->black_pixel_is_zero ? ~0 : 0);
2400         }
2401 
2402         switch (player->boardSize)
2403         {
2404         case Large:
2405             *pm = XCreatePixmapFromBitmapData(player->xDisplay,
2406                                               player->xBoardWindow,
2407                                               (char *)large_bits,
2408                                               player->squareSize,
2409                                               player->squareSize,
2410                                               fg, bg, depth);
2411             break;
2412 
2413         case Medium:
2414             *pm = XCreatePixmapFromBitmapData(player->xDisplay,
2415                                               player->xBoardWindow,
2416                                               (char *)medium_bits,
2417                                               player->squareSize,
2418                                               player->squareSize,
2419                                               fg, bg, depth);
2420             break;
2421 
2422         case Small:
2423             *pm = XCreatePixmapFromBitmapData(player->xDisplay,
2424                                               player->xBoardWindow,
2425                                               (char *)small_bits,
2426                                               player->squareSize,
2427                                               player->squareSize,
2428                                               fg, bg, depth);
2429             break;
2430         }
2431     }
2432 }
2433 
2434 
2435 
2436 
2437 void
CreateGrid(void)2438 CreateGrid(void)
2439 {
2440     int i, offset;
2441 
2442     offset = 2 * (player->squareSize + LINE_GAP);
2443 
2444     for (i = 0; i < BOARD_SIZE + 1; i++)
2445     {
2446         player->gridSegments[i].x1 = offset;
2447         player->gridSegments[i + BOARD_SIZE + 1].y1 = 0;
2448         player->gridSegments[i].y1 = player->gridSegments[i].y2
2449             = LINE_GAP / 2 + (i * (player->squareSize + LINE_GAP));
2450         player->gridSegments[i].x2 = LINE_GAP + BOARD_SIZE *
2451             (player->squareSize + LINE_GAP) + offset;
2452         player->gridSegments[i + BOARD_SIZE + 1].x1
2453             = player->gridSegments[i + BOARD_SIZE + 1].x2 = LINE_GAP / 2
2454             + (i * (player->squareSize + LINE_GAP)) + offset;
2455         player->gridSegments[i + BOARD_SIZE + 1].y2
2456             = BOARD_SIZE * (player->squareSize + LINE_GAP);
2457     }
2458 }
2459 
2460 
2461 
2462 
2463 void
CreatePieceMenus(void)2464 CreatePieceMenus(void)
2465 {
2466     int i;
2467     Widget entry;
2468     Arg args[1];
2469     ShogiSquare selection;
2470 
2471     XtSetArg(args[0], XtNlabel, "Black");
2472     blackPieceMenu = XtCreatePopupShell("menuW", simpleMenuWidgetClass,
2473                                         localPlayer.boardWidget, args, 1);
2474 
2475     for (i = 0; i < PIECE_MENU_SIZE; i++)
2476     {
2477         String item = pieceMenuStrings[i];
2478 
2479         if (strcmp(item, "----") == 0)
2480         {
2481             entry = XtCreateManagedWidget(item, smeLineObjectClass,
2482                                           blackPieceMenu, NULL, 0);
2483         }
2484         else
2485         {
2486             entry = XtCreateManagedWidget(item, smeBSBObjectClass,
2487                                           blackPieceMenu, NULL, 0);
2488             selection = pieceMenuTranslation[0][i];
2489             XtAddCallback(entry, XtNcallback,
2490                           (XtCallbackProc)PieceMenuSelect,
2491                           (XtPointer)selection);
2492 
2493             if (selection == BlackPawn)
2494             {
2495                 XtSetArg(args[0], XtNpopupOnEntry, entry);
2496                 XtSetValues(blackPieceMenu, args, 1);
2497             }
2498         }
2499     }
2500 
2501     XtSetArg(args[0], XtNlabel, "White");
2502     whitePieceMenu = XtCreatePopupShell("menuB", simpleMenuWidgetClass,
2503                                         localPlayer.boardWidget, args, 1);
2504 
2505     for (i = 0; i < PIECE_MENU_SIZE; i++)
2506     {
2507         String item = pieceMenuStrings[i];
2508 
2509         if (strcmp(item, "----") == 0)
2510         {
2511             entry = XtCreateManagedWidget(item, smeLineObjectClass,
2512                                           whitePieceMenu, NULL, 0);
2513         }
2514         else
2515         {
2516             entry = XtCreateManagedWidget(item, smeBSBObjectClass,
2517                                           whitePieceMenu, NULL, 0);
2518             selection = pieceMenuTranslation[1][i];
2519             XtAddCallback(entry, XtNcallback,
2520                           (XtCallbackProc)PieceMenuSelect,
2521                           (XtPointer)selection);
2522 
2523             if (selection == WhitePawn)
2524             {
2525                 XtSetArg(args[0], XtNpopupOnEntry, entry);
2526                 XtSetValues(whitePieceMenu, args, 1);
2527             }
2528         }
2529     }
2530 
2531     XtRegisterGrabAction(PieceMenuPopup, True,
2532                          (unsigned)(ButtonPressMask|ButtonReleaseMask),
2533                          GrabModeAsync, GrabModeAsync);
2534 }
2535 
2536 
2537 
2538 
2539 void
PieceMenuPopup(Widget w,XEvent * event,String * params,Cardinal * num_params)2540 PieceMenuPopup(Widget w, XEvent *event, String *params, Cardinal *num_params)
2541 {
2542     if (event->type != ButtonPress)
2543         return;
2544 
2545     if (gameMode != EditPosition)
2546         return;
2547 
2548     if (((pmFromX = EventToXSquare(event->xbutton.x)) < 1)
2549         || (pmFromX > BOARD_SIZE + 2)
2550         || ((pmFromY = EventToSquare(event->xbutton.y)) < 0))
2551     {
2552         pmFromX = pmFromY = -1;
2553         return;
2554     }
2555 
2556     if (localPlayer.flipView)
2557         pmFromX = BOARD_SIZE + 3 - pmFromX;
2558     else
2559         pmFromY = BOARD_SIZE - 1 - pmFromY;
2560 
2561     XtPopupSpringLoaded(XtNameToWidget(localPlayer.boardWidget, params[0]));
2562 }
2563 
2564 
2565 
2566 
2567 static void
PieceMenuSelect(Widget w,ShogiSquare piece,char * junk)2568 PieceMenuSelect(Widget w, ShogiSquare piece, char *junk)
2569 {
2570     if ((pmFromX < 0) || (pmFromY < 0))
2571         return;
2572 
2573     if (off_board(pmFromX))
2574     {
2575         int i, c;
2576         switch (piece)
2577         {
2578         case ClearBoard:
2579             break;
2580 
2581         case BlackPlay:
2582             break;
2583 
2584         case WhitePlay:
2585             break;
2586 
2587         default:
2588             i = pieceToCatchedIndex[piece];
2589             c = (piece >= WhitePawn);
2590             catches[0][c][i]++;
2591             DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
2592             XSync(localPlayer.xDisplay, False);
2593             return;
2594         }
2595     }
2596 
2597     pmFromX -= 2;
2598 
2599     switch (piece)
2600     {
2601     case ClearBoard:
2602         for (pmFromY = 0; pmFromY < BOARD_SIZE; pmFromY++)
2603             for (pmFromX = 0; pmFromX < BOARD_SIZE; pmFromX++)
2604                 boards[0][pmFromY][pmFromX] = EmptySquare;
2605 
2606         ClearCatches(catches[0]);
2607         DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
2608         break;
2609 
2610     case BlackPlay:  /* not currently on menu */
2611         SetBlackToPlay();
2612         break;
2613 
2614     case WhitePlay:  /* not currently on menu */
2615         SetWhiteToPlay();
2616         break;
2617 
2618     default:
2619         boards[0][pmFromY][pmFromX] = piece;
2620         DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
2621         break;
2622     }
2623 
2624     XSync(localPlayer.xDisplay, False);
2625 }
2626 
2627 
2628 
2629 
2630 static void
SetBlackToPlay(void)2631 SetBlackToPlay(void)
2632 {
2633     int saveCM;
2634 
2635     if (gameMode != EditPosition)
2636         return;
2637 
2638     whitePlaysFirst = False;
2639     saveCM = currentMove;
2640     currentMove = 0;  /* kludge */
2641     DisplayClocks(ReDisplayTimers);
2642     currentMove = saveCM;
2643 }
2644 
2645 
2646 
2647 
2648 static void
SetWhiteToPlay(void)2649 SetWhiteToPlay(void)
2650 {
2651     int saveCM;
2652 
2653     if (gameMode != EditPosition)
2654         return;
2655 
2656     whitePlaysFirst = True;
2657     saveCM = currentMove;
2658     currentMove = 1;  /* kludge */
2659     DisplayClocks(ReDisplayTimers);
2660     currentMove = saveCM;
2661 }
2662 
2663 
2664 
2665 
2666 /*
2667  * If the user selects on a border boundary or off the board, return failure.
2668  * Otherwise map the event coordinate to the square.
2669  */
2670 
2671 int
EventToSquare(int x)2672 EventToSquare(int x)
2673 {
2674     if (x < LINE_GAP)
2675         return -1;
2676 
2677     x -= LINE_GAP;
2678 
2679     if ((x % (player->squareSize + LINE_GAP)) >= player->squareSize)
2680         return -1;
2681 
2682     x /= (player->squareSize + LINE_GAP);
2683 
2684     if (x >= BOARD_SIZE)
2685         return -1;
2686 
2687     return x;
2688 }
2689 
2690 
2691 
2692 
2693 int
EventToXSquare(int x)2694 EventToXSquare(int x)
2695 {
2696     if (x < LINE_GAP)
2697         return -1;
2698 
2699     x -= LINE_GAP;
2700 
2701     if ((x % (player->squareSize + LINE_GAP)) >= player->squareSize)
2702         return -1;
2703 
2704     x /= (player->squareSize + LINE_GAP);
2705 
2706     if (x >= BOARD_SIZE + 4)
2707         return -1;
2708 
2709     return x;
2710 }
2711 
2712 
2713 
2714 
2715 ShogiSquare
CharToPiece(int c,int p)2716 CharToPiece(int c, int p)
2717 {
2718     if (p)
2719     {
2720         switch (c)
2721         {
2722         default:
2723         case '.':   return EmptySquare;
2724         case 'P':   return BlackPPawn;
2725         case 'L':   return BlackPLance;
2726         case 'N':   return BlackPKnight;
2727         case 'S':   return BlackPSilver;
2728         case 'G':   return BlackGold;
2729         case 'R':   return BlackPRook;
2730         case 'B':   return BlackPBishop;
2731         case 'K':   return BlackKing;
2732         case 'p':   return WhitePPawn;
2733         case 'l':   return WhitePLance;
2734         case 'n':   return WhitePKnight;
2735         case 's':   return WhitePSilver;
2736         case 'g':   return WhiteGold;
2737         case 'r':   return WhitePRook;
2738         case 'b':   return WhitePBishop;
2739         case 'k':   return WhiteKing;
2740         }
2741     }
2742     else
2743     {
2744         switch (c)
2745         {
2746         default:
2747         case '.':   return EmptySquare;
2748         case 'P':   return BlackPawn;
2749         case 'L':   return BlackLance;
2750         case 'N':   return BlackKnight;
2751         case 'S':   return BlackSilver;
2752         case 'G':   return BlackGold;
2753         case 'R':   return BlackRook;
2754         case 'B':   return BlackBishop;
2755         case 'K':   return BlackKing;
2756         case 'p':   return WhitePawn;
2757         case 'l':   return WhiteLance;
2758         case 'n':   return WhiteKnight;
2759         case 's':   return WhiteSilver;
2760         case 'g':   return WhiteGold;
2761         case 'r':   return WhiteRook;
2762         case 'b':   return WhiteBishop;
2763         case 'k':   return WhiteKing;
2764         }
2765     }
2766 }
2767 
2768 
2769 
2770 
2771 /*
2772  * Convert coordinates to normal algebraic notation.
2773  * promoPiece must be NULLCHAR if not a promotion.
2774  */
2775 
2776 ShogiMove
MakeAlg(int fromX,int fromY,int toX,int toY,char promoPiece,int currentBoardIndex,char * out)2777 MakeAlg(int fromX, int fromY, int toX, int toY,
2778         char promoPiece, int currentBoardIndex, char *out)
2779 {
2780     ShogiSquare piece;
2781     char *outp = out;
2782 
2783     if (fromX > 80)
2784     {
2785         piece = (fromX - 81);
2786         *outp++ = catchedIndexToChar[piece];
2787         *outp++ = '*';
2788         *outp++ = '9' - toX;
2789         *outp++ = 'i' - toY;
2790         *outp++ = NULLCHAR;
2791         return (BlackOnMove(forwardMostMove) ? BlackDrop : WhiteDrop);
2792     }
2793     else
2794     {
2795         *outp++ = '9' - fromX;
2796         *outp++ = 'i' - fromY;
2797         *outp++ = '9' - toX;
2798         *outp++ = 'i' - toY;
2799         *outp++ = promoPiece;
2800         *outp++ = NULLCHAR;
2801 
2802         if (promoPiece == NULLCHAR)
2803         {
2804             return NormalMove;
2805         }
2806         else
2807         {
2808             return (BlackOnMove(forwardMostMove)
2809                     ? BlackPromotion : WhitePromotion);
2810         }
2811     }
2812 }
2813 
2814 
2815 
2816 
2817 void
DrawSquare(int row,int column,ShogiSquare piece)2818 DrawSquare(int row, int column, ShogiSquare piece)
2819 {
2820     int square_color, x, y, direction, font_ascent, font_descent;
2821     char string[2];
2822     XCharStruct overall;
2823     struct DisplayData *player;
2824 
2825     for (player = &localPlayer; True; player = &remotePlayer)
2826     {
2827         int offset, remote;
2828 
2829         remote = (player == &remotePlayer);
2830         offset = 2 * (player->squareSize + LINE_GAP);
2831 
2832         if (player->flipView)
2833         {
2834             x = LINE_GAP + ((BOARD_SIZE - 1) - column) *
2835                 (player->squareSize + LINE_GAP) + offset;
2836             y = LINE_GAP + row * (player->squareSize + LINE_GAP);
2837         }
2838         else
2839         {
2840             x = LINE_GAP + column * (player->squareSize + LINE_GAP) + offset;
2841             y = LINE_GAP + ((BOARD_SIZE - 1) - row) *
2842                 (player->squareSize + LINE_GAP);
2843         }
2844 
2845         square_color = (((column + row) % 2) ? LIGHT : DARK);
2846 
2847         if (piece == EmptySquare)
2848         {
2849             if (column < 0 || column >= BOARD_SIZE)
2850             {
2851                 /* empty square off board */
2852                 XFillRectangle(player->xDisplay, player->xBoardWindow,
2853                                player->squareOffBoardGC,
2854                                x, y, player->squareSize,
2855                                player->squareSize);
2856             }
2857             else
2858             {
2859                 /* empty square on board */
2860                 XFillRectangle(player->xDisplay,
2861                                player->xBoardWindow,
2862                                player->squareGC,
2863                                x, y,
2864                                player->squareSize,
2865                                player->squareSize);
2866             }
2867         }
2868         else if (player->monoMode) /* Draw a piece in mono mode. */
2869         {
2870             XCopyArea(player->xDisplay,
2871                       ((((((int)piece) < ((int)WhitePawn)))
2872                         ^ player->flipView)
2873                        ? *pieceToNormal[remote][(int)piece]
2874                        : *pieceToReverse[remote][(int)piece]),
2875                       player->xBoardWindow,
2876                       (player->monoMode
2877                        ? player->squareOffBoardGC  /* ??? FIXME? */
2878                        : player->pieceGC),
2879                       0, 0,
2880                       player->squareSize, player->squareSize, x, y);
2881         }
2882         else /* Draw a piece in color mode. */
2883         {
2884             if ((column < 0) || (column >= BOARD_SIZE))  /* off board */
2885             {
2886                 /* draw piece background */
2887 
2888                 XCopyPlane(player->xDisplay,
2889                            ((((((int)piece) < ((int)WhitePawn)))
2890                              ^ player->flipView)
2891                             ? *pieceToNormalSolid[remote][(int)piece]
2892                             : *pieceToReverseSolid[remote][(int)piece]),
2893                            player->xBoardWindow,
2894                            player->oPieceGC,
2895                            0, 0,
2896                            player->squareSize, player->squareSize, x, y, 1);
2897 
2898                 /* draw piece bitmap */
2899 
2900                 XCopyArea(player->xDisplay,
2901                           ((((((int)piece) < ((int)WhitePawn)))
2902                             ^ player->flipView)
2903                            ? *pieceToNormal[remote][(int)piece]
2904                            : *pieceToReverse[remote][(int)piece]),
2905                           player->xBoardWindow,
2906                           player->charPieceGC,
2907                           0, 0,
2908                           player->squareSize, player->squareSize, x, y);
2909             }
2910             else  /* on board */
2911             {
2912                 /* draw piece background */
2913 
2914                 XCopyPlane(player->xDisplay,
2915                            ((((((int)piece) < ((int)WhitePawn)))
2916                              ^ player->flipView)
2917                             ? *pieceToNormalSolid[remote][(int)piece]
2918                             : *pieceToReverseSolid[remote][(int)piece]),
2919                            player->xBoardWindow,
2920                            player->pieceGC,
2921                            0, 0,
2922                            player->squareSize, player->squareSize, x, y, 1);
2923 
2924                 /* draw piece bitmap */
2925 
2926                 XCopyArea(player->xDisplay,
2927                           ((((((int)piece) < ((int)WhitePawn)))
2928                             ^ player->flipView)
2929                            ? *pieceToNormal[remote][(int)piece]
2930                            : *pieceToReverse[remote][(int)piece]),
2931                           player->xBoardWindow,
2932                           player->charPieceGC,
2933                           0, 0,
2934                           player->squareSize, player->squareSize, x, y);
2935              }
2936         }
2937 
2938         string[1] = NULLCHAR;
2939 
2940         if (player->showCoords
2941             && (column >= 0) && (column < 9)
2942             && (row == (player->flipView ? 8 : 0)))
2943         {
2944             string[0] = '9' - column;
2945             XTextExtents(player->coordFontStruct, string, 1, &direction,
2946                          &font_ascent, &font_descent, &overall);
2947 
2948             if (player->monoMode)
2949             {
2950                 XDrawImageString(player->xDisplay,
2951                                  player->xBoardWindow, player->coordGC,
2952                                  x + player->squareSize - overall.width - 2,
2953                                  y + player->squareSize - font_descent - 1,
2954                                  string, 1);
2955             }
2956             else
2957             {
2958                 XDrawString(player->xDisplay, player->xBoardWindow,
2959                             player->coordGC,
2960                             x + player->squareSize - overall.width - 2,
2961                             y + player->squareSize - font_descent - 1,
2962                             string, 1);
2963             }
2964         }
2965 
2966         if (player->showCoords
2967             && (row >= 0) && (row < 9)
2968             && (column == (player->flipView ? 8 : 0)))
2969         {
2970             string[0] = 'i' - row;
2971             XTextExtents(player->coordFontStruct, string, 1, &direction,
2972                          &font_ascent, &font_descent, &overall);
2973 
2974             if (player->monoMode)
2975             {
2976                 XDrawImageString(player->xDisplay,
2977                                  player->xBoardWindow, player->coordGC,
2978                                  x + 2, y + font_ascent + 1, string, 1);
2979             }
2980             else
2981             {
2982                 XDrawString(player->xDisplay, player->xBoardWindow,
2983                             player->coordGC,
2984                             x + 2, y + font_ascent + 1, string, 1);
2985             }
2986         }
2987 
2988         if (!updateRemotePlayer || (player == &remotePlayer))
2989             break;
2990     }
2991 }
2992 
2993 
2994 
2995 
2996 void
EventProc(Widget widget,XtPointer client_data,XEvent * event)2997 EventProc(Widget widget, XtPointer client_data, XEvent *event)
2998 {
2999     if (event->type == MappingNotify)
3000     {
3001         XRefreshKeyboardMapping((XMappingEvent *) event);
3002         return;
3003     }
3004 
3005     if (!XtIsRealized(widget))
3006         return;
3007 
3008     if ((event->type == ButtonPress) || (event->type == ButtonRelease))
3009     {
3010         if (event->xbutton.button != Button1)
3011             return;
3012     }
3013 
3014     switch (event->type)
3015     {
3016     case Expose:
3017         DrawPosition(widget, event, NULL, NULL);
3018         break;
3019 
3020     default:
3021         return;
3022     }
3023 }
3024 
3025 
3026 
3027 
3028 /*
3029  * event handler for redrawing the board
3030  */
3031 
3032 void
DrawPosition(Widget w,XEvent * event,String * prms,Cardinal * nprms)3033 DrawPosition(Widget w, XEvent *event, String *prms, Cardinal *nprms)
3034 {
3035     Arg args[1];
3036     int i, j;
3037     static Board lastBoard;
3038     static Catched lastCatches;
3039     static int lastBoardValid = 0;
3040     static int lastFlipView = 0, lastRemoteFlipView = 1;
3041 
3042     if (!player->Iconic)
3043     {
3044         XtSetArg(args[0], XtNiconic, False);
3045         XtSetValues(localPlayer.shellWidget, args, 1);
3046     }
3047 
3048     /*
3049      * It would be simpler to clear the window with XClearWindow()
3050      * but this causes a very distracting flicker.
3051      */
3052 
3053     if ((w == localPlayer.boardWidget)
3054         && (event == NULL)
3055         && lastBoardValid
3056         && (lastFlipView == localPlayer.flipView)
3057         && (!updateRemotePlayer
3058             || (lastRemoteFlipView == remotePlayer.flipView)))
3059     {
3060         for (i = 0; i < BOARD_SIZE; i++)
3061         {
3062             for (j = 0; j < BOARD_SIZE; j++)
3063             {
3064                 if (boards[currentMove][i][j] != lastBoard[i][j])
3065                     DrawSquare(i, j, boards[currentMove][i][j]);
3066             }
3067         }
3068 
3069         for (i = 0; i < 2; i++)
3070         {
3071             for (j = 0; j < 8; j++)
3072             {
3073                 if (catches[currentMove][i][j] != lastCatches[i][j])
3074                 {
3075                     UpdateCatched(i, 0, False, True, currentMove);
3076                     break;
3077                 }
3078             }
3079         }
3080     }
3081     else
3082     {
3083         XDrawSegments(localPlayer.xDisplay,
3084                       localPlayer.xBoardWindow, localPlayer.lineGC,
3085                       localPlayer.gridSegments, (BOARD_SIZE + 1) * 2);
3086 
3087         if (updateRemotePlayer)
3088         {
3089             XDrawSegments(remotePlayer.xDisplay,
3090                           remotePlayer.xBoardWindow, remotePlayer.lineGC,
3091                           remotePlayer.gridSegments, (BOARD_SIZE + 1) * 2);
3092         }
3093 
3094         for (i = 0; i < BOARD_SIZE; i++)
3095             for (j = 0; j < BOARD_SIZE; j++)
3096                 DrawSquare(i, j, boards[currentMove][i][j]);
3097 
3098         UpdateCatched(0, 0, False, True, currentMove);
3099         UpdateCatched(1, 0, False, True, currentMove);
3100     }
3101 
3102     CopyBoard(lastBoard, boards[currentMove]);
3103     CopyCatches(lastCatches, catches[currentMove]);
3104     lastBoardValid = 1;
3105     lastFlipView = localPlayer.flipView;
3106 
3107     if (updateRemotePlayer)
3108         lastRemoteFlipView = remotePlayer.flipView;
3109 
3110     XSync(localPlayer.xDisplay, False);
3111 
3112     if (updateRemotePlayer)
3113         XSync(remotePlayer.xDisplay, False);
3114 }
3115 
3116 
3117 
3118 
3119 void
InitPosition(int redraw)3120 InitPosition(int redraw)
3121 {
3122     currentMove = forwardMostMove = backwardMostMove = 0;
3123     CopyBoard(boards[0], initialPosition);
3124     ClearCatches(catches[0]);
3125 
3126     if (redraw)
3127         DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
3128 }
3129 
3130 
3131 
3132 
3133 void
CopyBoard(Board to,Board from)3134 CopyBoard(Board to, Board from)
3135 {
3136     int i, j;
3137 
3138     for (i = 0; i < BOARD_SIZE; i++)
3139         for (j = 0; j < BOARD_SIZE; j++)
3140             to[i][j] = from[i][j];
3141 }
3142 
3143 
3144 
3145 
3146 void
CopyCatches(Catched to,Catched from)3147 CopyCatches(Catched to, Catched from)
3148 {
3149     int i, j;
3150 
3151     for (i = 0; i < 2; i++)
3152         for (j = 0; j < 8; j++)
3153             to[i][j] = from[i][j];
3154 }
3155 
3156 
3157 
3158 
3159 void
SendCurrentBoard(FILE * fp)3160 SendCurrentBoard(FILE *fp)
3161 {
3162     SendBoard(fp, boards[currentMove], catches[currentMove]);
3163 }
3164 
3165 
3166 
3167 
3168 void
SendBoard(FILE * fp,Board board,Catched catches)3169 SendBoard(FILE *fp, Board board, Catched catches)
3170 {
3171     char message[MSG_SIZ];
3172     ShogiSquare *bp;
3173     int i, j;
3174 
3175     SendToProgram("edit\n", fp);
3176     SendToProgram("#\n", fp);
3177 
3178     for (i = BOARD_SIZE - 1; i >= 0; i--)
3179     {
3180         bp = &board[i][0];
3181 
3182         for (j = 0; j < BOARD_SIZE; j++, bp++)
3183         {
3184             if (((int) *bp) < (int)WhitePawn)
3185             {
3186                 sprintf(message, "%c%c%c%s\n",
3187                         pieceToChar[(int) *bp],
3188                         '9' - j, 'i' - i,
3189                         (pieceIsPromoted[(int) *bp] ? "+" : ""));
3190                 SendToProgram(message, fp);
3191             }
3192         }
3193     }
3194 
3195     for (i = 0; i <= 7; i++)
3196     {
3197         int n;
3198 
3199         for (n = catches[0][i]; n > 0; n--)
3200         {
3201             sprintf(message, "%c*\n",
3202                     catchedIndexToChar[i]);
3203             SendToProgram(message, fp);
3204         }
3205     }
3206 
3207     SendToProgram("c\n", fp);
3208 
3209     for (i = BOARD_SIZE - 1; i >= 0; i--)
3210     {
3211         bp = &board[i][0];
3212 
3213         for (j = 0; j < BOARD_SIZE; j++, bp++)
3214         {
3215             if ((((int) *bp) != ((int)EmptySquare))
3216                 && (((int) *bp) >= ((int)WhitePawn)))
3217             {
3218                 sprintf(message, "%c%c%c%s\n",
3219                         pieceToChar[((int) *bp) - ((int)WhitePawn)],
3220                         '9' - j, 'i' - i,
3221                         (pieceIsPromoted[(int) *bp] ? "+" : ""));
3222                 SendToProgram(message, fp);
3223             }
3224         }
3225     }
3226 
3227     for (i = 0; i <= 7; i++)
3228     {
3229         int n;
3230 
3231         for (n = catches[1][i]; n > 0; n--)
3232         {
3233             sprintf(message, "%c*\n",
3234                     catchedIndexToChar[i]);
3235             SendToProgram(message, fp);
3236         }
3237     }
3238 
3239     SendToProgram(".\n", fp);
3240 }
3241 
3242 
3243 
3244 
3245 static int
PromotionPossible(int fromY,int toY,ShogiSquare piece)3246 PromotionPossible(int fromY, int toY, ShogiSquare piece)
3247 {
3248     if (((int)piece) < ((int)WhitePawn))
3249     {
3250         if ((fromY < 6) && (toY < 6))
3251             return False;
3252     }
3253     else
3254     {
3255         if ((fromY > 2) && (toY > 2))
3256             return False;
3257     }
3258 
3259     return piecePromotable[(int)piece];
3260 
3261 }
3262 
3263 
3264 
3265 
3266 static void
ShowCount(int row,int column,int n)3267 ShowCount(int row, int column, int n)
3268 {
3269     int offset = 2 * (player->squareSize + LINE_GAP);
3270     int x, y, direction, font_ascent, font_descent;
3271     char string[2];
3272     XCharStruct overall;
3273     struct DisplayData *player;
3274 
3275     DrawSquare(row, column, EmptySquare);
3276 
3277     if (n <= 1)
3278         return;
3279 
3280     for (player = &localPlayer; True; player = &remotePlayer)
3281     {
3282         if (player->flipView)
3283         {
3284             x = LINE_GAP + ((BOARD_SIZE - 1) - column) *
3285                 (player->squareSize + LINE_GAP) + offset;
3286             y = LINE_GAP + row * (player->squareSize + LINE_GAP);
3287         }
3288         else
3289         {
3290             x = LINE_GAP + column * (player->squareSize + LINE_GAP) + offset;
3291             y = LINE_GAP + ((BOARD_SIZE - 1) - row) *
3292                 (player->squareSize + LINE_GAP);
3293         }
3294 
3295         x -= player->squareSize / 2;
3296 
3297         string[1] = NULLCHAR;
3298 
3299         if (n > 9)
3300             string[0] = '*';
3301         else
3302             string[0] = '0' + n;
3303 
3304         XTextExtents(player->coordFontStruct, string, 1, &direction,
3305                      &font_ascent, &font_descent, &overall);
3306 
3307         if (player->monoMode)
3308         {
3309             XDrawImageString(player->xDisplay, player->xBoardWindow,
3310                              player->coordGC,
3311                              x + player->squareSize - overall.width - 2,
3312                              y + player->squareSize - font_descent - 1,
3313                              string, 1);
3314         }
3315         else
3316         {
3317             XDrawString(player->xDisplay, player->xBoardWindow,
3318                         player->coordGC,
3319                         x + player->squareSize - overall.width - 2,
3320                         y + player->squareSize - font_descent - 1,
3321                         string, 1);
3322         }
3323 
3324         if (!updateRemotePlayer || (player == &remotePlayer))
3325             break;
3326     }
3327 }
3328 
3329 
3330 
3331 
3332 void
UpdateCatched(int Color,int Figure,int Drop,int DropAll,int currentMove)3333 UpdateCatched(int Color, int Figure, int Drop, int DropAll, int currentMove)
3334 {
3335     int n, F;
3336     int x, y;
3337 
3338     /* Determine first row and column. */
3339 
3340     if (Color)
3341     {
3342         x = -1;
3343         y = BOARD_SIZE - 1;
3344     }
3345     else
3346     {
3347         x = BOARD_SIZE;
3348         y = 0;
3349     }
3350 
3351     if (DropAll)
3352         n = 0;
3353     else
3354         n = catches[currentMove][Color][Figure];
3355 
3356     /* Update the display for captured pieces
3357        if no piece of the dropped type is there (Drop && n==1)
3358        or if a piece type is removed (NOT Drop && n==0).
3359        In the other cases update only the count. */
3360 
3361     if (DropAll || (Drop && (n == 1)) || (!Drop && (n == 0)))
3362     {
3363         /* show all captured pieces */
3364         n = 0;
3365 
3366         for (F = pawn; F <= king; F++)
3367         {
3368             int c;
3369 
3370             if ((c = catches[currentMove][Color][F]) > 0)
3371             {
3372                 n++;
3373                 DrawSquare(y, x, catchedIndexToPiece[Color][F]);
3374                 ShowCount(y, (Color ? (x - 1) : (x + 1)), c);
3375 
3376                 if (Color)
3377                     y--;
3378                 else
3379                     y++;
3380             }
3381         }
3382 
3383         if (DropAll)
3384         {
3385             for (; n < 9; n++)
3386             {
3387                 DrawSquare(y, x, EmptySquare);
3388                 ShowCount(y, (Color ? (x - 1) : (x + 1)), 0);
3389 
3390                 if (Color)
3391                     y--;
3392                 else
3393                     y++;
3394             }
3395         }
3396         else if (!Drop)
3397         {
3398             /* remove one line! */
3399             DrawSquare(y, x, EmptySquare);
3400             ShowCount(y, (Color ? (x - 1) : (x + 1)), 0);
3401         }
3402     }
3403     else
3404     {
3405         /* show the actual count */
3406         for (F = pawn; F <= Figure - 1; F++)
3407         {
3408             if (catches[currentMove][Color][F] > 0)
3409             {
3410                 if (Color)
3411                     y--;
3412                 else
3413                     y++;
3414             }
3415         }
3416 
3417         ShowCount(y, (Color ? (x - 1) : (x + 1)), n);
3418     }
3419 }
3420 
3421 
3422 
3423 
3424 #ifdef BLINK_COUNT
3425 
3426 static int BlinkCount = 0;
3427 static int BlinkRow, BlinkCol;
3428 static ShogiSquare BlinkPiece;
3429 
3430 
3431 void
BlinkSquareProc(void)3432 BlinkSquareProc(void)
3433 {
3434     if (BlinkCount > 0)
3435     {
3436         BlinkCount--;
3437         DrawSquare (BlinkRow, BlinkCol,
3438                     ((BlinkCount & 1) ? EmptySquare : BlinkPiece));
3439 
3440         if (BlinkCount > 0)
3441         {
3442             blinkSquareXID
3443                 = XtAppAddTimeOut(appContext,
3444                                   150,
3445                                   (XtTimerCallbackProc)BlinkSquareProc,
3446                                   NULL);
3447         }
3448     }
3449     else
3450     {
3451         BlinkCount = 0;
3452     }
3453 }
3454 
3455 
3456 
3457 
3458 void
BlinkSquare(int row,int col,ShogiSquare piece)3459 BlinkSquare(int row, int col, ShogiSquare piece)
3460 {
3461     BlinkCount = 2 * BLINK_COUNT + 1;
3462     BlinkRow = row;
3463     BlinkCol = col;
3464     BlinkPiece = piece;
3465     BlinkSquareProc();
3466 }
3467 
3468 
3469 #endif /* BLINK_COUNT */
3470 
3471 
3472 
3473 
3474 static int
PieceOfCatched(int color,int x,int y,int currentMove)3475 PieceOfCatched(int color, int x, int y, int currentMove)
3476 {
3477     int F, n;
3478 
3479     if (color)
3480     {
3481         if (x != 1)
3482             return (no_piece);
3483 
3484         y = 8 - y;
3485     }
3486     else
3487     {
3488         if (x != 11)
3489             return no_piece;
3490     }
3491 
3492     for (F = pawn, n = 0; F <= king; F++)
3493     {
3494         if (catches[currentMove][color][F] > 0)
3495         {
3496             if (n == y)
3497                 return F;
3498 
3499             n++;
3500         }
3501     }
3502 
3503     return no_piece;
3504 }
3505 
3506 
3507 
3508 
3509 /*
3510  * event handler for parsing user moves
3511  */
3512 
3513 void
HandleUserMove(Widget w,XEvent * event)3514 HandleUserMove(Widget w, XEvent *event)
3515 {
3516     ShogiMove move_type;
3517     ShogiSquare from_piece;
3518     int to_x, to_y, fromRemotePlayer;
3519 
3520     if (updateRemotePlayer)
3521     {
3522         if (((w != localPlayer.boardWidget)
3523              && (w != remotePlayer.boardWidget))
3524             || (matchMode != MatchFalse))
3525         {
3526             return;
3527         }
3528 
3529         fromRemotePlayer = (w == remotePlayer.boardWidget);
3530     }
3531     else
3532     {
3533         if ((w != localPlayer.boardWidget) || (matchMode != MatchFalse))
3534             return;
3535 
3536         fromRemotePlayer = False;
3537     }
3538 
3539     player = (fromRemotePlayer ? &remotePlayer : &localPlayer);
3540 
3541     if (player->promotionUp)
3542     {
3543         XtPopdown(player->promotionShell);
3544         XtDestroyWidget(player->promotionShell);
3545         player->promotionUp = False;
3546         fromX = fromY = -1;
3547     }
3548 
3549     switch (gameMode)
3550     {
3551     case EndOfGame:
3552     case PlayFromGameFile:
3553     case TwoMachinesPlay:
3554         return;
3555 
3556     case MachinePlaysBlack:
3557         if (BlackOnMove(forwardMostMove))
3558         {
3559             DisplayMessage("It is not your turn", fromRemotePlayer);
3560             return;
3561         }
3562 
3563         break;
3564 
3565     case MachinePlaysWhite:
3566         if (!BlackOnMove(forwardMostMove))
3567         {
3568             DisplayMessage("It is not your turn", fromRemotePlayer);
3569             return;
3570         }
3571 
3572         break;
3573 
3574     case ForceMoves:
3575         forwardMostMove = currentMove;
3576         break;
3577 
3578     default:
3579         break;
3580     }
3581 
3582     if (currentMove != forwardMostMove)
3583     {
3584         DisplayMessage("Displayed position is not current",
3585                        fromRemotePlayer);
3586         return;
3587     }
3588 
3589     switch (event->type)
3590     {
3591     case ButtonPress:
3592         if ((fromX >= 0) || (fromY >= 0))
3593             return;
3594 
3595         if (((fromX = EventToXSquare(event->xbutton.x)) < 1)
3596             || (fromX > BOARD_SIZE + 2)
3597             || ((fromY = EventToSquare(event->xbutton.y)) < 0))
3598         {
3599             fromX = fromY = -1;
3600             return;
3601         }
3602 
3603         if (player->flipView)
3604             fromX = BOARD_SIZE + 3 - fromX;
3605         else
3606             fromY = BOARD_SIZE - 1 - fromY;
3607 
3608         break;
3609 
3610     case ButtonRelease:
3611         if ((fromX < 0) || (fromY < 0))
3612             return;
3613 
3614         if (((to_x = EventToXSquare(event->xbutton.x)) < 1)
3615             || (to_x > BOARD_SIZE + 2)
3616             || ((to_y = EventToSquare(event->xbutton.y)) < 0))
3617         {
3618             if (gameMode == EditPosition && !off_board(fromX))
3619             {
3620                 fromX -= 2;
3621                 boards[0][fromY][fromX] = EmptySquare;
3622                 DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
3623                 XSync(localPlayer.xDisplay, False);
3624 
3625                 if (updateRemotePlayer)
3626                     XSync(remotePlayer.xDisplay, False);
3627             }
3628 
3629             fromX = fromY = -1;
3630             return;
3631         }
3632 
3633         if (player->flipView)
3634             to_x = BOARD_SIZE + 3 - to_x;
3635         else
3636             to_y = BOARD_SIZE - 1 - to_y;
3637 
3638         if ((fromX == to_x) && (fromY == to_y))
3639         {
3640             fromX = fromY = -1;
3641             return;
3642         }
3643 
3644         if (gameMode == EditPosition)
3645         {
3646             ShogiSquare piece;
3647 
3648             if (off_board(fromX))
3649             {
3650                 /* Remove a catched piece */
3651                 int i, c;
3652                 c = ((fromX < 5) ^ player->flipView);
3653                 i = PieceOfCatched(c, fromX, fromY, 0);
3654 
3655                 if (i == no_piece)
3656                 {
3657                     fromX = fromY = -1;
3658                     return;
3659                 }
3660                 else
3661                 {
3662                     piece = catchedIndexToPiece[c][i];
3663                     catches[0][c][i]--;
3664                 }
3665             }
3666             else
3667             {
3668                 /* remove piece from board field */
3669                 fromX -= 2;
3670                 piece = boards[0][fromY][fromX];
3671                 boards[0][fromY][fromX] = EmptySquare;
3672             }
3673 
3674             if (!off_board(to_x))
3675             {
3676                 /* drop piece to board field */
3677                 ShogiSquare catched_piece;
3678                 to_x -= 2;
3679                 catched_piece = boards[0][to_y][to_x];
3680 
3681                 if (catched_piece != EmptySquare)
3682                 {
3683                     /* put piece to catched pieces */
3684                     int i = pieceToCatchedIndex[catched_piece];
3685                     int c = (catched_piece < WhitePawn);
3686                     catches[0][c][i]++;
3687                 }
3688 
3689                 /* place moved piece */
3690                 boards[0][to_y][to_x] = piece;
3691             }
3692 
3693             fromX = fromY = -1;
3694             DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
3695             XSync(localPlayer.xDisplay, False);
3696 
3697             if (updateRemotePlayer)
3698                 XSync(remotePlayer.xDisplay, False);
3699 
3700             return;
3701         }
3702 
3703         if (off_board(fromX))
3704         {
3705             int c     = (BlackOnMove(forwardMostMove) ? 0 : 1);
3706             int piece = PieceOfCatched(c, fromX, fromY, currentMove);
3707 
3708             if (piece == no_piece)
3709             {
3710                 fromX = fromY = -1;
3711                 return;
3712             }
3713             else
3714             {
3715                 if (updateRemotePlayer
3716                     && (BlackOnMove(forwardMostMove) == fromRemotePlayer))
3717                 {
3718                     DisplayMessage("Do not try to drop your opponent's pieces!",
3719                                    fromRemotePlayer);
3720                     fromX = fromY = -1;
3721                     return;
3722                 }
3723 
3724                 fromX = fromY = piece + 81;
3725                 to_x -= 2;
3726                 move_type = (BlackOnMove(forwardMostMove)
3727                              ? BlackDrop : WhiteDrop);
3728                 MakeMove(&move_type, fromX, fromY, to_x, to_y);
3729 
3730 #ifdef BLINK_COUNT
3731                 if (updateRemotePlayer)
3732                     BlinkSquare(to_y, to_x, boards[currentMove][to_y][to_x]);
3733 #endif
3734 
3735                 FinishUserMove(move_type, to_x, to_y);
3736                 break;
3737             }
3738         }
3739         else if (off_board(to_x))
3740         {
3741             fromX = fromY = -1;
3742             return;
3743         }
3744         else
3745         {
3746             fromX -= 2;
3747             to_x -= 2;
3748             from_piece = boards[currentMove][fromY][fromX];
3749 
3750             if ((from_piece != EmptySquare)
3751                 && updateRemotePlayer
3752                 && ((from_piece < WhitePawn) == fromRemotePlayer))
3753             {
3754                 DisplayMessage("Do not try to move your opponent's pieces!",
3755                                fromRemotePlayer);
3756                 fromX = fromY = -1;
3757                 return;
3758             }
3759 
3760             if (PromotionPossible(fromY, to_y, from_piece))
3761             {
3762                 PromotionPopUp(from_piece, to_x, to_y, fromRemotePlayer);
3763                 return;
3764             }
3765 
3766             move_type = NormalMove;
3767             MakeMove(&move_type, fromX, fromY, to_x, to_y);
3768 
3769 #ifdef BLINK_COUNT
3770             if (updateRemotePlayer)
3771                 BlinkSquare(to_y, to_x, boards[currentMove][to_y][to_x]);
3772 #endif
3773 
3774             FinishUserMove(move_type, to_x, to_y);
3775             break;
3776         }
3777     }
3778 }
3779 
3780 
3781 
3782 
3783 void
FinishUserMove(ShogiMove move_type,int to_x,int to_y)3784 FinishUserMove(ShogiMove move_type, int to_x, int to_y)
3785 {
3786     char user_move[MSG_SIZ];
3787 
3788     /* output move for gnushogi */
3789     switch (move_type)
3790     {
3791     case BlackPromotion:
3792     case WhitePromotion:
3793         sprintf(user_move, "%c%c%c%c+\n",
3794                 '9' - fromX, 'i' - fromY, '9' - to_x, 'i' - to_y);
3795         break;
3796 
3797     case BlackDrop:
3798     case WhiteDrop:
3799         sprintf(user_move, "%c*%c%c\n",
3800                 catchedIndexToChar[fromX - 81], '9' - to_x, 'i' - to_y);
3801         break;
3802 
3803     case NormalMove:
3804         sprintf(user_move, "%c%c%c%c\n",
3805                 '9' - fromX, 'i' - fromY, '9' - to_x, 'i' - to_y);
3806         break;
3807 
3808     default:
3809         fprintf(stderr, "%s: internal error; bad move_type\n",
3810                 (char *)programName);
3811         break;
3812     }
3813 
3814     Attention(firstProgramPID);
3815 
3816     if (firstSendTime)
3817         SendTimeRemaining(toFirstProgFP);
3818 
3819     SendToProgram(user_move, toFirstProgFP);
3820     strcpy(moveList[currentMove - 1], user_move);
3821 
3822     fromX = fromY = -1;
3823 
3824     if (gameMode == PauseGame)
3825     {
3826         /* a user move restarts a paused game*/
3827         PauseProc(NULL, NULL, NULL, NULL);
3828     }
3829 
3830     switch (gameMode)
3831     {
3832     case ForceMoves:
3833         break;
3834 
3835     case BeginningOfGame:
3836         if (localPlayer.appData.noShogiProgram)
3837             lastGameMode = gameMode = ForceMoves;
3838         else
3839             lastGameMode = gameMode = MachinePlaysWhite;
3840 
3841         ModeHighlight();
3842         break;
3843 
3844     case MachinePlaysWhite:
3845     case MachinePlaysBlack:
3846     default:
3847         break;
3848     }
3849 }
3850 
3851 
3852 
3853 
3854 /* Simple parser for moves from gnushogi. */
3855 void
ParseMachineMove(char * machine_move,ShogiMove * move_type,int * from_x,int * from_y,int * to_x,int * to_y)3856 ParseMachineMove(char *machine_move, ShogiMove *move_type,
3857                  int *from_x, int *from_y, int *to_x, int *to_y)
3858 {
3859 #define no_digit(c) (c < '0' || c > '9')
3860     {
3861         if (no_digit(machine_move[0]))
3862         {
3863             switch (machine_move[0])
3864             {
3865             case 'P':
3866                 *from_x = 81;
3867                 break;
3868 
3869             case 'L':
3870                 *from_x = 82;
3871                 break;
3872 
3873             case 'N':
3874                 *from_x = 83;
3875                 break;
3876 
3877             case 'S':
3878                 *from_x = 84;
3879                 break;
3880 
3881             case 'G':
3882                 *from_x = 85;
3883                 break;
3884 
3885             case 'B':
3886                 *from_x = 86;
3887                 break;
3888 
3889             case 'R':
3890                 *from_x = 87;
3891                 break;
3892 
3893             case 'K':
3894                 *from_x = 88;
3895                 break;
3896 
3897             default:
3898                 *from_x = -1;
3899             }
3900 
3901             *from_y = *from_x;
3902             *to_x   = '9' - machine_move[2];
3903             *to_y   = 'i' - machine_move[3];
3904         }
3905         else
3906         {
3907             *from_x = '9' - machine_move[0] ;
3908             *from_y = 'i' - machine_move[1];
3909             *to_x   = '9' - machine_move[2];
3910             *to_y   = 'i' - machine_move[3];
3911 
3912             switch (machine_move[4])
3913             {
3914             case '+':
3915                 *move_type = (BlackOnMove(forwardMostMove)
3916                     ? BlackPromotion : WhitePromotion);
3917                 break;
3918 
3919             default:
3920                 *move_type = NormalMove;
3921                 break;
3922             }
3923         }
3924     }
3925 }
3926 
3927 
3928 
3929 
3930 void
SkipString(char ** mpr)3931 SkipString(char **mpr)
3932 {
3933     while (**mpr == ' ')
3934         (*mpr)++;
3935 
3936     while ((**mpr != ' ') && (**mpr != NULLCHAR) && (**mpr != '\n'))
3937         (*mpr)++;
3938 
3939     while (**mpr == ' ')
3940         (*mpr)++;
3941 }
3942 
3943 
3944 
3945 
3946 void
HandleMachineMove(char * message,FILE * fp)3947 HandleMachineMove(char *message, FILE *fp)
3948 {
3949     char machine_move[MSG_SIZ], buf1[MSG_SIZ], buf2[MSG_SIZ];
3950     int from_x, from_y, to_x, to_y;
3951     ShogiMove move_type;
3952     char *mpr;
3953 
3954 #ifdef SYNCHTIME
3955     long time_remaining;
3956 #endif
3957 
3958     maybeThinking = False;
3959 
3960     if (strncmp(message, "warning:", 8) == 0)
3961     {
3962         DisplayMessage(message, False);
3963 
3964         if (updateRemotePlayer)
3965             DisplayMessage(message, True);
3966 
3967         return;
3968     }
3969 
3970     /*
3971      * If shogi program startup fails, exit with an error message.
3972      * Attempts to recover here are futile.
3973      */
3974 
3975     if ((strstr(message, "unknown host") != NULL)
3976         || (strstr(message, "No remote directory") != NULL)
3977         || (strstr(message, "not found") != NULL)
3978         || (strstr(message, "No such file") != NULL)
3979         || (strstr(message, "Permission denied") != NULL))
3980     {
3981         fprintf(stderr,
3982                 "%s: failed to start shogi program %s on %s: %s\n",
3983                 programName,
3984                 ((fp == fromFirstProgFP)
3985                  ? localPlayer.appData.firstShogiProgram
3986                  : localPlayer.appData.secondShogiProgram),
3987                 ((fp == fromFirstProgFP)
3988                  ? localPlayer.appData.firstHost
3989                  : localPlayer.appData.secondHost),
3990                 message);
3991         ShutdownShogiPrograms(message);
3992         exit(1);
3993     }
3994 
3995     /*
3996      * If the move is illegal, cancel it and redraw the board.
3997      */
3998 
3999     if (strncmp(message, "Illegal move", 12) == 0)
4000     {
4001         if (fp == fromFirstProgFP && firstSendTime == 2)
4002         {
4003             /* First program doesn't have the "time" command */
4004             firstSendTime = 0;
4005             return;
4006         }
4007         else if (fp == fromSecondProgFP && secondSendTime == 2)
4008         {
4009             /* Second program doesn't have the "time" command */
4010             secondSendTime = 0;
4011             return;
4012         }
4013 
4014         if (forwardMostMove <= backwardMostMove)
4015             return;
4016 
4017         if (gameMode == PauseGame)
4018             PauseProc(NULL, NULL, NULL, NULL);
4019 
4020         if (gameMode == PlayFromGameFile)
4021         {
4022             /* Stop reading this game file */
4023             gameMode = ForceMoves;
4024             ModeHighlight();
4025         }
4026 
4027         currentMove = --forwardMostMove;
4028 
4029         if ((gameMode == PlayFromGameFile)
4030             || (gameMode == ForceMoves))
4031             DisplayClocks(ReDisplayTimers);
4032         else
4033             DisplayClocks(SwitchTimers);
4034 
4035         sprintf(buf1, "Illegal move: %s", parseList[currentMove]);
4036         DisplayMessage(buf1, False);
4037 
4038         if (updateRemotePlayer)
4039             DisplayMessage(buf1, True);
4040 
4041 #ifdef BLINK_COUNT
4042         /*
4043          * Disable blinking of the target square.
4044          */
4045 
4046         if (BlinkCount > 0)
4047         {
4048             /* If BlinkCount is even, the piece is currently displayed. */
4049             if (!(BlinkCount & 1))
4050                 DrawSquare (BlinkRow, BlinkCol, EmptySquare);
4051 
4052             /* BlinkCount = 0 will force the next blink timeout
4053              * to do nothing. */
4054             BlinkCount = 0;
4055         }
4056 #endif
4057 
4058         DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
4059 
4060         XSync(localPlayer.xDisplay, False);
4061 
4062         if (updateRemotePlayer)
4063             XSync(remotePlayer.xDisplay, False);
4064 
4065         return;
4066     }
4067 
4068     if (strstr(message, "GNU Shogi") != NULL)
4069     {
4070         at_least_gnushogi_1_2p03 = True;
4071         return;
4072     }
4073 
4074     if (strncmp(message, "Hint:", 5) == 0)
4075     {
4076         char promoPiece;
4077         sscanf(message, "Hint: %s", machine_move);
4078         ParseMachineMove(machine_move, &move_type,
4079                          &from_x, &from_y, &to_x, &to_y);
4080 
4081         if (move_type == WhitePromotion || move_type == BlackPromotion)
4082             promoPiece = '+';
4083         else
4084             promoPiece = NULLCHAR;
4085 
4086         move_type = MakeAlg(from_x, from_y, to_x, to_y, promoPiece,
4087                             currentMove, buf1);
4088         sprintf(buf2, "Hint: %s", buf1);
4089         DisplayMessage(buf2, False);
4090 
4091         if (updateRemotePlayer)
4092             DisplayMessage(buf2, True);
4093 
4094         return;
4095     }
4096 
4097     if (strncmp(message, "Clocks:", 7) == 0)
4098     {
4099         sscanf(message, "Clocks: %ld %ld",
4100                &blackTimeRemaining, &whiteTimeRemaining);
4101         DisplayClocks(ReDisplayTimers);
4102 
4103         return;
4104     }
4105 
4106     /*
4107      * win, lose or draw
4108      */
4109 
4110     if (strncmp(message, "Black", 5) == 0)
4111     {
4112         ShutdownShogiPrograms("Black wins");
4113         return;
4114     }
4115     else if (strncmp(message, "White", 5) == 0)
4116     {
4117         ShutdownShogiPrograms("White wins");
4118         return;
4119     }
4120     else if (strncmp(message, "Repetition", 10) == 0)
4121     {
4122         ShutdownShogiPrograms("Repetition");
4123         return;
4124     }
4125     else if (strncmp(message, "opponent mates!", 15) == 0)
4126     {
4127         switch ((gameMode == PauseGame) ? pausePreviousMode : gameMode)
4128         {
4129         case MachinePlaysWhite:
4130             ShutdownShogiPrograms("Black wins");
4131             break;
4132 
4133         case MachinePlaysBlack:
4134             ShutdownShogiPrograms("White wins");
4135             break;
4136 
4137         case TwoMachinesPlay:
4138             ShutdownShogiPrograms((fp == fromFirstProgFP)
4139                                   ? "Black wins" : "White wins");
4140             break;
4141 
4142         default:
4143             /* can't happen */
4144             break;
4145         }
4146 
4147         return;
4148     }
4149     else if (strncmp(message, "computer mates!", 15) == 0)
4150     {
4151         switch ((gameMode == PauseGame) ? pausePreviousMode : gameMode)
4152         {
4153         case MachinePlaysWhite:
4154             ShutdownShogiPrograms("White wins");
4155             break;
4156 
4157         case MachinePlaysBlack:
4158             ShutdownShogiPrograms("Black wins");
4159             break;
4160 
4161         case TwoMachinesPlay:
4162             ShutdownShogiPrograms((fp == fromFirstProgFP)
4163                                   ? "White wins" : "Black wins");
4164             break;
4165 
4166         default:
4167             /* can't happen */
4168             break;
4169         }
4170 
4171         return;
4172     }
4173     else if (strncmp(message, "Draw", 4) == 0)
4174     {
4175         ShutdownShogiPrograms("Draw");
4176         return;
4177     }
4178 
4179     /*
4180      * normal machine reply move
4181      */
4182     maybeThinking = True;
4183 
4184     if (strstr(message, "...") != NULL)
4185     {
4186         sscanf(message, "%s %s %s", buf1, buf2, machine_move);
4187 
4188 #ifdef SYNCHTIME
4189         mpr = message;
4190         SkipString(&mpr); /* skip move number */
4191         SkipString(&mpr); /* skip ... */
4192         SkipString(&mpr); /* skip move */
4193 
4194         if ((gameMode != TwoMachinesPlay) && (gameMode != ForceMoves)
4195             && ((*mpr == '-') || ((*mpr >= '0') && (*mpr <= '9'))))
4196         {
4197             /* synchronize with shogi program clock */
4198             sscanf(mpr, "%ld", &time_remaining);
4199 
4200             if (xshogiDebug)
4201             {
4202                 printf("from '%s' synchronize %s clock %ld\n",
4203                        message,
4204                        (BlackOnMove(forwardMostMove)
4205                         ? "Black's"
4206                         : "White's"),
4207                        time_remaining);
4208             }
4209 
4210             if (BlackOnMove(forwardMostMove))
4211                 blackTimeRemaining = time_remaining;
4212             else
4213                 whiteTimeRemaining = time_remaining;
4214         }
4215 #endif
4216 
4217         if (machine_move[0] == NULLCHAR)
4218             return;
4219     }
4220     else
4221     {
4222         mpr = message;
4223 
4224 #ifdef SYNCHTIME
4225         if (strstr(message, "time") == NULL)
4226         {
4227             /* remaining time will be determined from move */
4228             SkipString(&mpr); /* skip move number */
4229             SkipString(&mpr); /* skip move */
4230         }
4231 
4232         if ((gameMode != TwoMachinesPlay) && (gameMode != ForceMoves)
4233             && ((*mpr == '-') || ((*mpr >= '0') && (*mpr <= '9'))))
4234         {
4235             /* synchronize with shogi program clock */
4236             sscanf(mpr, "%ld", &time_remaining);
4237 
4238             if (xshogiDebug)
4239             {
4240                 printf("from '%s' synchronize %s clock %ld\n",
4241                        message,
4242                        ((!BlackOnMove(forwardMostMove))
4243                         ? "Black's" : "White's"),
4244                        time_remaining);
4245             }
4246 
4247             if (!BlackOnMove(forwardMostMove))
4248                 blackTimeRemaining = time_remaining;
4249             else
4250                 whiteTimeRemaining = time_remaining;
4251         }
4252         else
4253 #endif
4254 
4255             if (xshogiDebug)
4256                 printf("ignore noise: '%s'\n", message);
4257 
4258         return; /* ignore noise */
4259     }
4260 
4261     strcpy(moveList[forwardMostMove], machine_move);
4262 
4263     ParseMachineMove(machine_move, &move_type, &from_x, &from_y,
4264                      &to_x, &to_y);
4265 
4266     if (gameMode != PauseGame)
4267         currentMove = forwardMostMove;  /* display latest move */
4268 
4269     MakeMove(&move_type, from_x, from_y, to_x, to_y);
4270 
4271 #ifdef BLINK_COUNT
4272     if (gameMode != TwoMachinesPlay)
4273         BlinkSquare(to_y, to_x, boards[currentMove][to_y][to_x]);
4274 #endif
4275 
4276     if ((gameMode != PauseGame) && localPlayer.appData.ringBellAfterMoves)
4277         putc(BELLCHAR, stderr);
4278 
4279     if ((gameMode == TwoMachinesPlay)
4280         || ((gameMode == PauseGame)
4281             && (pausePreviousMode == TwoMachinesPlay)))
4282     {
4283         strcat(machine_move, "\n");
4284 
4285         if (BlackOnMove(forwardMostMove))
4286         {
4287             Attention(secondProgramPID);
4288 
4289             if (secondSendTime)
4290                 SendTimeRemaining(toSecondProgFP);
4291 
4292             SendToProgram(machine_move, toSecondProgFP);
4293 
4294             if (firstMove)
4295             {
4296                 firstMove = False;
4297                 SendToProgram(localPlayer.appData.blackString,
4298                               toSecondProgFP);
4299             }
4300         }
4301         else
4302         {
4303             Attention(firstProgramPID);
4304 
4305             if (firstSendTime)
4306                 SendTimeRemaining(toFirstProgFP);
4307 
4308             SendToProgram(machine_move, toFirstProgFP);
4309 
4310             if (firstMove)
4311             {
4312                 firstMove = False;
4313                 SendToProgram(localPlayer.appData.blackString,
4314                               toFirstProgFP);
4315             }
4316         }
4317     }
4318 }
4319 
4320 
4321 
4322 
4323 void
ReadGameFile(void)4324 ReadGameFile(void)
4325 {
4326     for (;;)
4327     {
4328         if (!ReadGameFileProc())
4329             return;
4330 
4331         if (matchMode == MatchOpening)
4332             continue;
4333 
4334         readGameXID
4335             = XtAppAddTimeOut(appContext,
4336                               (int)(1000 * localPlayer.appData.timeDelay),
4337                               (XtTimerCallbackProc) ReadGameFile, NULL);
4338         break;
4339     }
4340 }
4341 
4342 
4343 
4344 /*
4345  * FIXME: there is a naming inconsistency: here ReadGameFileProc() is
4346  * called by ReadGameFile() while in other places XXXProc() calls XXX().
4347  */
4348 
4349 int
ReadGameFileProc(void)4350 ReadGameFileProc(void)
4351 {
4352     ShogiMove move_type;
4353     char move[MSG_SIZ], buf[MSG_SIZ];
4354 
4355     if (gameFileFP == NULL)
4356         return (int)False;
4357 
4358     if (gameMode == PauseGame)
4359         return True;
4360 
4361     if (gameMode != PlayFromGameFile)
4362     {
4363         fclose(gameFileFP);
4364         gameFileFP = NULL;
4365         return (int)False;
4366     }
4367 
4368     if (commentUp)
4369     {
4370         XtPopdown(commentShell);
4371         XtDestroyWidget(commentShell);
4372         commentUp = False;
4373     }
4374 
4375     fgets(move, MSG_SIZ, gameFileFP);
4376     move[strlen(move) - 1] = NULLCHAR;
4377     sprintf(buf, "# %s game file", programName);
4378 
4379     if (strncmp(move, buf, strlen(buf)))
4380     {
4381         strcat(move, ": no xshogi game file");
4382         DisplayMessage(move, False);
4383         return (int)False;
4384     }
4385 
4386     DisplayName(move);
4387     rewind(gameFileFP);
4388 
4389     parseGameFile();
4390 
4391     move_type = (ShogiMove)0;
4392 
4393     lastGameMode = gameMode;
4394     gameMode = ForceMoves;
4395     ModeHighlight();
4396 
4397     if (!loaded_game_finished)
4398         DisplayMessage("End of game file", False);
4399 
4400     if (readGameXID != 0)
4401     {
4402         XtRemoveTimeOut(readGameXID);
4403         readGameXID = 0;
4404     }
4405 
4406     fclose(gameFileFP);
4407     gameFileFP = NULL;
4408 
4409     return (int)False;
4410 }
4411 
4412 
4413 
4414 
4415 /*
4416  * Apply a move to the given board.  Oddity: move_type is ignored on input
4417  * unless the move is seen to be a pawn promotion, in which case move_type
4418  * tells us what to promote to.
4419  */
4420 
4421 void
ApplyMove(ShogiMove * move_type,int from_x,int from_y,int to_x,int to_y,int currentMove)4422 ApplyMove(ShogiMove *move_type, int from_x, int from_y,
4423           int to_x, int to_y, int currentMove)
4424 {
4425     ShogiSquare piece, cpiece;
4426     char pieceChar;
4427     int  i, c;
4428 
4429     if (from_x > 80)
4430     {
4431         i = from_x - 81;
4432         c = (BlackOnMove(currentMove) ? 1 : 0);
4433         cpiece = catchedIndexToPiece[c][i];
4434         boards[currentMove][to_y][to_x] = cpiece;
4435         catches[currentMove][c][i]--;
4436     }
4437     else if (PromotionPossible(from_y, to_y,
4438                                piece = boards[currentMove][from_y][from_x]))
4439     {
4440         cpiece = boards[currentMove][to_y][to_x];
4441 
4442         if (cpiece != EmptySquare)
4443         {
4444             i = pieceToCatchedIndex[cpiece];
4445             c = (cpiece < WhitePawn);
4446             catches[currentMove][c][i]++;
4447         }
4448 
4449         if (*move_type == NormalMove)
4450         {
4451             boards[currentMove][to_y][to_x] = piece;
4452         }
4453         else
4454         {
4455             boards[currentMove][to_y][to_x] = piece = pieceToPromoted[piece];
4456             pieceChar = '+';
4457         }
4458 
4459         boards[currentMove][from_y][from_x] = EmptySquare;
4460     }
4461     else
4462     {
4463         ShogiSquare piece = boards[currentMove][to_y][to_x];
4464 
4465         if (piece != EmptySquare)
4466         {
4467             i = pieceToCatchedIndex[piece];
4468             c = (piece < WhitePawn);
4469             catches[currentMove][c][i]++;
4470         }
4471 
4472         *move_type = NormalMove;
4473         boards[currentMove][to_y][to_x] =
4474             boards[currentMove][from_y][from_x];
4475         boards[currentMove][from_y][from_x] = EmptySquare;
4476     }
4477 }
4478 
4479 
4480 
4481 
4482 /*
4483  * MakeMove() displays moves.  If they are illegal, GNU shogi will detect
4484  * this and send an Illegal move message.  XShogi will then retract the move.
4485  * The clockMode False case is tricky because it displays the player on move.
4486  */
4487 
4488 void
MakeMove(ShogiMove * move_type,int from_x,int from_y,int to_x,int to_y)4489 MakeMove(ShogiMove *move_type, int from_x, int from_y, int to_x, int to_y)
4490 {
4491     char message[MSG_SIZ], movestr[MSG_SIZ];
4492     char promoPiece = NULLCHAR;
4493 
4494     forwardMostMove++;
4495 
4496     CopyBoard(boards[forwardMostMove], boards[forwardMostMove - 1]);
4497     CopyCatches(catches[forwardMostMove], catches[forwardMostMove - 1]);
4498 
4499     ApplyMove(move_type, from_x, from_y, to_x, to_y, forwardMostMove);
4500 
4501     endMessage[0] = NULLCHAR;
4502 
4503     timeRemaining[0][forwardMostMove] = blackTimeRemaining;
4504     timeRemaining[1][forwardMostMove] = whiteTimeRemaining;
4505 
4506     if ((gameMode == PauseGame) && (pausePreviousMode != PlayFromGameFile))
4507         return;
4508 
4509     currentMove = forwardMostMove;
4510 
4511     if (gameMode == PlayFromGameFile)
4512     {
4513         sprintf(message, "%d. %s%s",
4514                 ((currentMove + 1) / 2),
4515                 (BlackOnMove(currentMove) ? "... " : ""),
4516                 currentMoveString);
4517         strcpy(parseList[currentMove - 1], currentMoveString);
4518     }
4519     else
4520     {
4521         if ((*move_type == WhitePromotion) || (*move_type == BlackPromotion))
4522             promoPiece = '+';
4523         else
4524             promoPiece = NULLCHAR;
4525 
4526         MakeAlg(from_x, from_y, to_x, to_y, promoPiece,
4527                 currentMove - 1, movestr);
4528         sprintf(message, "%d. %s%s",
4529                 ((currentMove + 1) / 2),
4530                 (BlackOnMove(currentMove) ? "... " : ""),
4531                 movestr);
4532         strcpy(parseList[currentMove - 1], movestr);
4533     }
4534 
4535     DisplayMessage(message, False);
4536 
4537     if ((gameMode == PlayFromGameFile) || (gameMode == ForceMoves)
4538         || ((gameMode == PauseGame)
4539             && (pausePreviousMode == PlayFromGameFile)))
4540     {
4541         DisplayClocks(ReDisplayTimers);
4542     }
4543     else
4544     {
4545         DisplayClocks(SwitchTimers);
4546     }
4547 
4548     DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
4549 
4550     XSync(localPlayer.xDisplay, False);
4551 
4552     if (updateRemotePlayer)
4553     {
4554         DisplayMessage(message, True);
4555         XSync(remotePlayer.xDisplay, False);
4556     }
4557 }
4558 
4559 
4560 
4561 
4562 void
InitShogiProgram(char * host_name,char * program_name,int * pid,FILE ** to,FILE ** from,XtIntervalId * xid,int * sendTime)4563 InitShogiProgram(char *host_name, char *program_name, int *pid,
4564                  FILE **to, FILE **from, XtIntervalId *xid, int *sendTime)
4565 {
4566     char  arg_buf[10];
4567     char *arg1, *arg2;
4568     int   to_prog[2], from_prog[2];
4569     FILE *from_fp, *to_fp;
4570     int   dummy_source;
4571     XtInputId dummy_id;
4572 
4573     if (localPlayer.appData.noShogiProgram)
4574         return;
4575 
4576     signal(SIGPIPE, CatchPipeSignal);
4577     pipe(to_prog);
4578     pipe(from_prog);
4579 
4580     if ((*pid = fork()) == 0)
4581     {
4582         signal(SIGPIPE, CatchPipeSignal);
4583 
4584         dup2(to_prog[0], 0);
4585         dup2(from_prog[1], 1);
4586         close(to_prog[0]);
4587         close(to_prog[1]);
4588         close(from_prog[0]);
4589         close(from_prog[1]);
4590         dup2(1, fileno(stderr));    /* force stderr to the pipe */
4591 
4592         if (localPlayer.appData.searchTime != NULL)
4593         {
4594             sprintf(arg_buf, "%d", searchTime);
4595             arg1 = arg_buf;
4596             arg2 = (char *)NULL;
4597         }
4598         else if (localPlayer.appData.searchDepth > 0)
4599         {
4600             sprintf(arg_buf, "%d", localPlayer.appData.searchDepth);
4601             arg1 = "1";
4602             arg2 = "9999";
4603         }
4604         else
4605         {
4606             sprintf(arg_buf, "%d", localPlayer.appData.movesPerSession);
4607             arg1 = arg_buf;
4608             arg2 = localPlayer.appData.timeControl;
4609         }
4610 
4611         if (strcmp(host_name, "localhost") == 0)
4612         {
4613             execlp(program_name, program_name, arg1, arg2,
4614                    (char *)NULL);
4615         }
4616         else
4617         {
4618             execlp(localPlayer.appData.remoteShell,
4619                    localPlayer.appData.remoteShell,
4620                    host_name, program_name, arg1, arg2,
4621                    (char *)NULL);
4622         }
4623 
4624         perror(program_name);
4625         exit(1);
4626     }
4627 
4628     close(to_prog[0]);
4629     close(from_prog[1]);
4630 
4631     *from = from_fp = fdopen(from_prog[0], "r");
4632     *to   = to_fp   = fdopen(to_prog[1],   "w");
4633     setbuf(from_fp, NULL);
4634     setbuf(to_fp,   NULL);
4635 
4636     ReceiveFromProgram(from_fp, &dummy_source, &dummy_id); /* "GNU Shogi"*/
4637 
4638     if (!at_least_gnushogi_1_2p03)
4639     {
4640         fprintf(stderr, "you must have at least gnushogi-1.2p03\n");
4641         exit(1);
4642     }
4643 
4644     if (*pid == 0)
4645         return;
4646 
4647     *xid = XtAppAddInput(appContext, fileno(from_fp),
4648                          (XtPointer)XtInputReadMask,
4649                          (XtInputCallbackProc)ReceiveFromProgram,
4650                          (XtPointer)from_fp);
4651 
4652     SendToProgram(localPlayer.appData.initString, *to);
4653 
4654     if (localPlayer.appData.gameIn)
4655         SendToProgram("gamein\n", *to);
4656 
4657     SendSearchDepth(*to);
4658 
4659     if (*sendTime == 2)
4660     {
4661         /* Does program have "time" command? */
4662         char buf[MSG_SIZ];
4663 
4664         sprintf(buf, "time %ld\n", blackTimeRemaining / 10);
4665         SendToProgram(buf, to_fp);
4666         ReceiveFromProgram(from_fp, &dummy_source, &dummy_id);
4667 
4668         if (*sendTime == 2)
4669         {
4670             *sendTime = 1;  /* yes! */
4671             sprintf(buf, "otime %ld\n", whiteTimeRemaining / 10);
4672             SendToProgram(buf, to_fp);
4673             ReceiveFromProgram(from_fp, &dummy_source, &dummy_id);
4674         }
4675     }
4676 }
4677 
4678 
4679 
4680 
4681 void
ShutdownShogiPrograms(char * why)4682 ShutdownShogiPrograms(char *why)
4683 {
4684     lastGameMode = gameMode;
4685     gameMode = EndOfGame;
4686     ModeHighlight();
4687     CopyBoard(boards[currentMove + 1], boards[currentMove]);
4688     CopyCatches(catches[currentMove + 1], catches[currentMove]);
4689     strncpy(parseList[currentMove], why, MOVE_LEN);
4690     parseList[currentMove][MOVE_LEN - 1] = NULLCHAR;
4691     currentMove++;
4692     DisplayMessage(why, False);
4693 
4694     if (readGameXID != 0)
4695         XtRemoveTimeOut(readGameXID);
4696 
4697     readGameXID = 0;
4698 
4699     if (firstProgramPID != 0)
4700     {
4701         fclose(fromFirstProgFP);
4702         fclose(toFirstProgFP);
4703         fromFirstProgFP = toFirstProgFP = NULL;
4704 
4705         if (kill(firstProgramPID, SIGTERM) == 0)
4706             WAIT0;
4707     }
4708 
4709     firstProgramPID = 0;
4710 
4711     if (firstProgramXID != 0)
4712         XtRemoveInput(firstProgramXID);
4713 
4714     firstProgramXID = 0;
4715 
4716     if (secondProgramPID != 0)
4717     {
4718         fclose(fromSecondProgFP);
4719         fclose(toSecondProgFP);
4720         fromSecondProgFP = toSecondProgFP = NULL;
4721 
4722         if (kill(secondProgramPID, SIGTERM) == 0)
4723             WAIT0;
4724     }
4725 
4726     secondProgramPID = 0;
4727 
4728     if (secondProgramXID != 0)
4729         XtRemoveInput(secondProgramXID);
4730 
4731     secondProgramXID = 0;
4732 
4733     DisplayClocks(StopTimers);
4734 
4735     if (matchMode != MatchFalse)
4736     {
4737         if (localPlayer.appData.saveGameFile[0] != NULLCHAR)
4738             SaveGame(localPlayer.appData.saveGameFile);
4739 
4740         exit(0);
4741     }
4742 }
4743 
4744 
4745 
4746 
4747 void
CommentPopUp(char * label)4748 CommentPopUp(char *label)
4749 {
4750     Arg args[2];
4751     Position x, y;
4752     Dimension bw_width, pw_width;
4753 
4754     if (commentUp)
4755     {
4756         XtPopdown(commentShell);
4757         XtDestroyWidget(commentShell);
4758         commentUp = False;
4759     }
4760 
4761     DisplayMessage("Comment", False);
4762 
4763     XtSetArg(args[0], XtNwidth, &bw_width);
4764     XtGetValues(localPlayer.formWidget, args, 1);
4765 
4766     XtSetArg(args[0], XtNresizable, True);
4767     XtSetArg(args[1], XtNwidth, bw_width - 8);
4768 
4769     commentShell = XtCreatePopupShell("Comment",
4770                                       transientShellWidgetClass,
4771                                       localPlayer.commandsWidget, args, 2);
4772 
4773     XtSetArg(args[0], XtNlabel, label);
4774 
4775     (void)XtCreateManagedWidget("commentLabel", labelWidgetClass,
4776                                 commentShell, args, 1);
4777 
4778     XtRealizeWidget(commentShell);
4779 
4780     XtSetArg(args[0], XtNwidth, &pw_width);
4781     XtGetValues(commentShell, args, 1);
4782 
4783     XtTranslateCoords(localPlayer.shellWidget,
4784                       (bw_width - pw_width) / 2, -50, &x, &y);
4785 
4786     XtSetArg(args[0], XtNx, x);
4787     XtSetArg(args[1], XtNy, y);
4788     XtSetValues(commentShell, args, 2);
4789 
4790     XtPopup(commentShell, XtGrabNone);
4791     commentUp = True;
4792 }
4793 
4794 
4795 
4796 
4797 void
FileNamePopUp(char * label,Boolean (* proc)(char *))4798 FileNamePopUp(char *label, Boolean (*proc) (char *))
4799 {
4800     Arg args[2];
4801     Widget popup, dialog;
4802     Position x, y;
4803     Dimension bw_width, pw_width;
4804 
4805     fileProc = proc;
4806 
4807     XtSetArg(args[0], XtNwidth, &bw_width);
4808     XtGetValues(localPlayer.boardWidget, args, 1);
4809 
4810     XtSetArg(args[0], XtNresizable, True);
4811     XtSetArg(args[1], XtNwidth, DIALOG_SIZE);
4812 
4813     popup = XtCreatePopupShell("File Name Prompt",
4814                                transientShellWidgetClass,
4815                                localPlayer.commandsWidget, args, 2);
4816 
4817     XtSetArg(args[0], XtNlabel, label);
4818     XtSetArg(args[1], XtNvalue, "");
4819 
4820     dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
4821                                    popup, args, 2);
4822 
4823     XawDialogAddButton(dialog, "ok", FileNameCallback, (XtPointer) dialog);
4824     XawDialogAddButton(dialog, "cancel", FileNameCallback,
4825                        (XtPointer) dialog);
4826 
4827     XtRealizeWidget(popup);
4828 
4829     XtSetArg(args[0], XtNwidth, &pw_width);
4830     XtGetValues(popup, args, 1);
4831 
4832     XtTranslateCoords(localPlayer.boardWidget,
4833                       (bw_width - pw_width) / 2, 10, &x, &y);
4834 
4835     XtSetArg(args[0], XtNx, x);
4836     XtSetArg(args[1], XtNy, y);
4837     XtSetValues(popup, args, 2);
4838 
4839     XtPopup(popup, XtGrabExclusive);
4840     filenameUp = True;
4841 
4842     XtSetKeyboardFocus(localPlayer.shellWidget, popup);
4843 }
4844 
4845 
4846 
4847 
4848 void
FileNameCallback(Widget w,XtPointer client_data,XtPointer call_data)4849 FileNameCallback(Widget w, XtPointer client_data, XtPointer call_data)
4850 {
4851     String name;
4852     Arg args[1];
4853 
4854     XtSetArg(args[0], XtNlabel, &name);
4855     XtGetValues(w, args, 1);
4856 
4857     if (strcmp(name, "cancel") == 0)
4858     {
4859         XtPopdown(w = XtParent(XtParent(w)));
4860         XtDestroyWidget(w);
4861         filenameUp = False;
4862         ModeHighlight();
4863         return;
4864     }
4865 
4866     FileNameAction(w, NULL, NULL, NULL);
4867 }
4868 
4869 
4870 
4871 
4872 void
FileNameAction(Widget w,XEvent * event,String * prms,Cardinal * nprms)4873 FileNameAction(Widget w, XEvent *event, String *prms, Cardinal *nprms)
4874 {
4875     char buf[MSG_SIZ];
4876     String name;
4877 
4878     name = XawDialogGetValueString(w = XtParent(w));
4879 
4880     if ((name != NULL) && (*name != NULLCHAR))
4881     {
4882         strcpy(buf, name);
4883         XtPopdown(w = XtParent(w));
4884         XtDestroyWidget(w);
4885         filenameUp = False;
4886         (*fileProc)(buf);  /* I can't see a way not
4887                               to use a global here */
4888         ModeHighlight();
4889         return;
4890     }
4891 
4892     XtPopdown(w = XtParent(w));
4893     XtDestroyWidget(w);
4894     filenameUp = False;
4895     ModeHighlight();
4896 }
4897 
4898 
4899 
4900 
4901 void
PromotionPopUp(ShogiSquare piece,int to_x,int to_y,int fromRemotePlayer)4902 PromotionPopUp(ShogiSquare piece, int to_x, int to_y, int fromRemotePlayer)
4903 {
4904     Arg args[2];
4905     Widget dialog;
4906     Position x, y;
4907     Dimension bw_width, bw_height, pw_width, pw_height;
4908 
4909     player = (fromRemotePlayer ? &remotePlayer : &localPlayer);
4910 
4911     pmi.piece = piece;
4912     pmi.to_x = to_x;
4913     pmi.to_y = to_y;
4914 
4915     XtSetArg(args[0], XtNwidth, &bw_width);
4916     XtSetArg(args[1], XtNheight, &bw_height);
4917     XtGetValues(player->boardWidget, args, 2);
4918 
4919     XtSetArg(args[0], XtNresizable, True);
4920 
4921     player->promotionShell
4922         = XtCreatePopupShell("Promotion",
4923                              transientShellWidgetClass,
4924                              player->commandsWidget, args, 1);
4925 
4926     XtSetArg(args[0], XtNlabel, "Promote piece?");
4927     dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
4928                                    player->promotionShell, args, 1);
4929 
4930     XawDialogAddButton(dialog, "Yes", PromotionCallback,
4931                        (XtPointer) dialog);
4932     XawDialogAddButton(dialog, "No", PromotionCallback,
4933                        (XtPointer) dialog);
4934     XawDialogAddButton(dialog, "cancel", PromotionCallback,
4935                        (XtPointer) dialog);
4936 
4937     XtRealizeWidget(player->promotionShell);
4938 
4939     XtSetArg(args[0], XtNwidth, &pw_width);
4940     XtSetArg(args[1], XtNheight, &pw_height);
4941     XtGetValues(player->promotionShell, args, 2);
4942 
4943     XtTranslateCoords(player->boardWidget,
4944                       ((bw_width - pw_width) / 2),
4945                       (LINE_GAP
4946                        + player->squareSize / 3
4947                        + (((piece == BlackPawn) ^ (player->flipView))
4948                           ? 0
4949                           : (6 * (player->squareSize + LINE_GAP)))),
4950                       &x, &y);
4951 
4952     XtSetArg(args[0], XtNx, x);
4953     XtSetArg(args[1], XtNy, y);
4954     XtSetValues(player->promotionShell, args, 2);
4955 
4956     XtPopup(player->promotionShell, XtGrabNone);
4957 
4958     player->promotionUp = True;
4959 }
4960 
4961 
4962 
4963 
4964 void
PromotionCallback(Widget w,XtPointer client_data,XtPointer call_data)4965 PromotionCallback(Widget w, XtPointer client_data, XtPointer call_data)
4966 {
4967     String name;
4968     Arg args[1];
4969     ShogiMove move_type;
4970     struct DisplayData *player;
4971 
4972     XtSetArg(args[0], XtNlabel, &name);
4973     XtGetValues(w, args, 1);
4974 
4975     w = XtParent(XtParent(w));
4976     player = ((w == remotePlayer.promotionShell)
4977               ? &remotePlayer : &localPlayer);
4978     XtPopdown(w);
4979     XtDestroyWidget(w);
4980     player->promotionUp = False;
4981 
4982     if (fromX == -1)
4983         return;
4984 
4985     if (strcmp(name, "Yes") == 0)
4986     {
4987         if ((int)pmi.piece < (int)WhitePawn)
4988             move_type = BlackPromotion;
4989         else
4990             move_type = WhitePromotion;
4991     }
4992     else if (strcmp(name, "No") == 0)
4993     {
4994         move_type = NormalMove;
4995     }
4996     else /* strcmp(name, "cancel") == 0 */
4997     {
4998         fromX = fromY = -1;
4999         return;
5000     }
5001 
5002     MakeMove(&move_type, fromX, fromY, pmi.to_x, pmi.to_y);
5003 
5004 #ifdef BLINK_COUNT
5005     if (updateRemotePlayer)
5006     {
5007         BlinkSquare(pmi.to_y, pmi.to_x,
5008                     boards[currentMove][pmi.to_y][pmi.to_x]);
5009     }
5010 #endif
5011 
5012     FinishUserMove(move_type, pmi.to_x, pmi.to_y);
5013 }
5014 
5015 
5016 
5017 
5018 void
FileModePopUp(char * name)5019 FileModePopUp(char *name)
5020 {
5021     Arg args[2];
5022     Widget dialog;
5023     Position x, y;
5024     Dimension bw_width, bw_height, pw_width, pw_height;
5025 
5026     struct DisplayData *player = &localPlayer;
5027 
5028     strcpy(fmi.name, name);
5029 
5030     XtSetArg(args[0], XtNwidth, &bw_width);
5031     XtSetArg(args[1], XtNheight, &bw_height);
5032     XtGetValues(player->boardWidget, args, 2);
5033 
5034     XtSetArg(args[0], XtNresizable, True);
5035     player->filemodeShell
5036         = XtCreatePopupShell("FileMode",
5037                              transientShellWidgetClass,
5038                              player->commandsWidget, args, 1);
5039 
5040     XtSetArg(args[0], XtNlabel, "Append to existing file?");
5041     dialog = XtCreateManagedWidget("filemode", dialogWidgetClass,
5042                                    player->filemodeShell, args, 1);
5043 
5044     XawDialogAddButton(dialog, "Yes", FileModeCallback,
5045                        (XtPointer) dialog);
5046     XawDialogAddButton(dialog, "No", FileModeCallback,
5047                        (XtPointer) dialog);
5048     XawDialogAddButton(dialog, "cancel", FileModeCallback,
5049                        (XtPointer) dialog);
5050 
5051     XtRealizeWidget(player->filemodeShell);
5052 
5053     XtSetArg(args[0], XtNwidth, &pw_width);
5054     XtSetArg(args[1], XtNheight, &pw_height);
5055     XtGetValues(player->filemodeShell, args, 2);
5056 
5057     XtTranslateCoords(player->boardWidget, (bw_width - pw_width) / 2,
5058                       LINE_GAP + player->squareSize/3 +
5059                       (6*(player->squareSize + LINE_GAP)),
5060                       &x, &y);
5061 
5062     XtSetArg(args[0], XtNx, x);
5063     XtSetArg(args[1], XtNy, y);
5064     XtSetValues(player->filemodeShell, args, 2);
5065 
5066     XtPopup(player->filemodeShell, XtGrabNone);
5067 
5068     filemodeUp = True;
5069 }
5070 
5071 
5072 
5073 
5074 void
FileModeCallback(Widget w,XtPointer client_data,XtPointer call_data)5075 FileModeCallback(Widget w, XtPointer client_data, XtPointer call_data)
5076 {
5077     String name;
5078     Arg args[1];
5079 
5080     XtSetArg(args[0], XtNlabel, &name);
5081     XtGetValues(w, args, 1);
5082 
5083     XtPopdown(w = XtParent(XtParent(w)));
5084     XtDestroyWidget(w);
5085 
5086     if (strcmp(name, "Yes") == 0)
5087     {
5088         strcpy(fmi.mode, "a");
5089     }
5090     else if (strcmp(name, "No") == 0)
5091     {
5092         strcpy(fmi.mode, "w");
5093     }
5094     else /* strcmp(name, "cancel") == 0 */
5095     {
5096         filemodeUp = False;
5097         return;
5098     }
5099 
5100     XtPopdown(localPlayer.filemodeShell);
5101     XtDestroyWidget(localPlayer.filemodeShell);
5102 
5103     SaveGame(fmi.name);
5104 
5105     filemodeUp = False;
5106 }
5107 
5108 
5109 
5110 
5111 void
SelectCommand(Widget w,XtPointer client_data,XtPointer call_data)5112 SelectCommand(Widget w, XtPointer client_data, XtPointer call_data)
5113 {
5114     Cardinal fromRemotePlayer = (Cardinal)client_data;
5115 
5116     XawListReturnStruct *list_return = XawListShowCurrent(w);
5117 
5118     player = fromRemotePlayer ? &remotePlayer : &localPlayer;
5119 
5120     fromX = fromY = -1;
5121 
5122     if (player->promotionUp)
5123     {
5124         XtPopdown(player->promotionShell);
5125         XtDestroyWidget(player->promotionShell);
5126         player->promotionUp = False;
5127     }
5128 
5129     (*buttonProcs[list_return->list_index])
5130         (w, NULL, NULL, &fromRemotePlayer);
5131 
5132     if (!filenameUp)
5133         ModeHighlight();
5134 }
5135 
5136 
5137 
5138 
5139 void
HighlightProcButton(XtActionProc proc)5140 HighlightProcButton(XtActionProc proc)
5141 {
5142     int i = 0;
5143 
5144     if (proc == NULL)
5145     {
5146         XawListUnhighlight(localPlayer.commandsWidget);
5147 
5148         if (updateRemotePlayer)
5149             XawListUnhighlight(remotePlayer.commandsWidget);
5150 
5151         return;
5152     }
5153 
5154     for (;;)
5155     {
5156         if (buttonProcs[i] == NULL)
5157         {
5158             XawListUnhighlight(localPlayer.commandsWidget);
5159 
5160             if (updateRemotePlayer)
5161                 XawListUnhighlight(remotePlayer.commandsWidget);
5162 
5163             return;
5164         }
5165 
5166         if (buttonProcs[i] == proc)
5167         {
5168             XawListHighlight(localPlayer.commandsWidget, i);
5169 
5170             if (updateRemotePlayer)
5171                 XawListHighlight(remotePlayer.commandsWidget, i);
5172 
5173             return;
5174         }
5175 
5176         i++;
5177     }
5178 }
5179 
5180 
5181 
5182 
5183 void
ModeHighlight(void)5184 ModeHighlight(void)
5185 {
5186     switch (gameMode)
5187     {
5188     case BeginningOfGame:
5189         if (localPlayer.appData.noShogiProgram)
5190             HighlightProcButton(ForceProc);
5191         else
5192             HighlightProcButton(MachineBlackProc);
5193 
5194         break;
5195 
5196     case MachinePlaysBlack:
5197         HighlightProcButton(MachineBlackProc);
5198         break;
5199 
5200     case MachinePlaysWhite:
5201         HighlightProcButton(MachineWhiteProc);
5202         break;
5203 
5204     case TwoMachinesPlay:
5205         HighlightProcButton(TwoMachinesProc);
5206         break;
5207 
5208     case ForceMoves:
5209         HighlightProcButton(ForceProc);
5210 
5211         break;
5212 
5213     case PlayFromGameFile:
5214         HighlightProcButton(LoadGameProc);
5215         break;
5216 
5217     case PauseGame:
5218         HighlightProcButton(PauseProc);
5219         break;
5220 
5221     case EditPosition:
5222         HighlightProcButton(EditPositionProc);
5223         break;
5224 
5225     case EndOfGame:
5226     default:
5227         HighlightProcButton(NULL);
5228         break;
5229     }
5230 }
5231 
5232 
5233 
5234 
5235 /*
5236  * Button procedures
5237  */
5238 
5239 void
QuitRemotePlayerProc(void)5240 QuitRemotePlayerProc(void)
5241 {
5242     /* This should be modified... */
5243     XCloseDisplay(remotePlayer.xDisplay);
5244     /* XtDestroyWidget(remotePlayer.shellWidget); */
5245     updateRemotePlayer = False;
5246     DisplayMessage("Remote player has pressed Quit", False);
5247     fromX = fromY = -1;
5248 }
5249 
5250 
5251 
5252 void
QuitProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5253 QuitProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5254 {
5255     if (updateRemotePlayer)
5256         QuitRemotePlayerProc();
5257 
5258     ShutdownShogiPrograms("Quitting");
5259     exit(0);
5260 }
5261 
5262 
5263 
5264 void
LoadGameProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5265 LoadGameProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5266 {
5267     int fromRemotePlayer = *nprms;
5268 
5269     if (fromRemotePlayer)
5270     {
5271         DisplayMessage("only opponent may load game", fromRemotePlayer);
5272         return;
5273     }
5274 
5275     if (gameMode != BeginningOfGame)
5276     {
5277         DisplayMessage("Press Reset first.", False);
5278         return;
5279     }
5280 
5281     if (localPlayer.appData.loadGameFile == NULL)
5282         FileNamePopUp("Game file name?", LoadGame);
5283     else
5284         (void) LoadGame(localPlayer.appData.loadGameFile);
5285 }
5286 
5287 
5288 
5289 
5290 Boolean
LoadGame(char * name)5291 LoadGame(char *name)
5292 {
5293     char buf[MSG_SIZ];
5294 
5295     loaded_game_finished = 0;
5296 
5297     if (gameMode != BeginningOfGame)
5298     {
5299         DisplayMessage("Press Reset first", False);
5300         return (int)False;
5301     }
5302 
5303     if (localPlayer.appData.loadGameFile != name)
5304     {
5305         if (localPlayer.appData.loadGameFile)
5306             XtFree(localPlayer.appData.loadGameFile);
5307 
5308         localPlayer.appData.loadGameFile = XtMalloc(strlen(name) + 1);
5309         strcpy(localPlayer.appData.loadGameFile, name);
5310     }
5311 
5312     if ((gameFileFP = fopen(name, "r")) == NULL)
5313     {
5314         sprintf(buf, "Can't open %s", name);
5315         DisplayMessage(buf, False);
5316         XtFree(localPlayer.appData.loadGameFile);
5317         localPlayer.appData.loadGameFile = NULL;
5318         return (int)False;
5319     }
5320 
5321     lastGameMode = gameMode = PlayFromGameFile;
5322     ModeHighlight();
5323     InitPosition(True);
5324     DisplayClocks(StopTimers);
5325 
5326     if (firstProgramXID == 0)
5327     {
5328         InitShogiProgram(localPlayer.appData.firstHost,
5329                          localPlayer.appData.firstShogiProgram,
5330                          &firstProgramPID, &toFirstProgFP,
5331                          &fromFirstProgFP, &firstProgramXID,
5332                          &firstSendTime);
5333     }
5334 
5335     SendToProgram(localPlayer.appData.initString, toFirstProgFP);
5336     SendSearchDepth(toFirstProgFP);
5337     SendToProgram("force\n", toFirstProgFP);
5338 
5339     currentMove = forwardMostMove = backwardMostMove = 0;
5340 
5341     ReadGameFile();
5342 
5343     return True;
5344 }
5345 
5346 
5347 
5348 
5349 /*
5350  * Restart the shogi program and feed it all the moves made so far.
5351  * Used when the user wants to back up from end of game, when gnushogi
5352  * has already exited.  Assumes gameMode == EndOfGame.
5353  */
5354 
5355 void
ResurrectShogiProgram(void)5356 ResurrectShogiProgram(void)
5357 {
5358     char buf[MSG_SIZ];
5359     int i;
5360 
5361     if (currentMove > 0)
5362         currentMove--;  /* delete "Black wins" or the like */
5363 
5364     InitShogiProgram(localPlayer.appData.firstHost,
5365                      localPlayer.appData.firstShogiProgram,
5366                      &firstProgramPID, &toFirstProgFP, &fromFirstProgFP,
5367                      &firstProgramXID, &firstSendTime);
5368 
5369     SendToProgram(localPlayer.appData.initString, toFirstProgFP);
5370     SendSearchDepth(toFirstProgFP);
5371     SendToProgram("force\n", toFirstProgFP);
5372     gameMode = lastGameMode = ForceMoves;
5373     ModeHighlight();
5374 
5375     i = (whitePlaysFirst ? 1 : 0);
5376 
5377     if (startedFromSetupPosition)
5378         SendBoard(toFirstProgFP, boards[i], catches[i]);
5379 
5380     for (; i < currentMove; i++)
5381     {
5382         strcpy(buf, moveList[i]);
5383         SendToProgram(buf, toFirstProgFP);
5384     }
5385 
5386     if (!firstSendTime)
5387     {
5388         /* can't tell gnushogi what its clock should read,
5389            so we bow to its notion. */
5390         DisplayClocks(ResetTimers);
5391         timeRemaining[0][currentMove] = blackTimeRemaining;
5392         timeRemaining[1][currentMove] = whiteTimeRemaining;
5393     }
5394 }
5395 
5396 
5397 
5398 
5399 void
MachineWhiteProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5400 MachineWhiteProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5401 {
5402     int fromRemotePlayer = *nprms;
5403 
5404     if (updateRemotePlayer)
5405     {
5406         DisplayMessage("no machine moves in challenge mode",
5407                        fromRemotePlayer);
5408 
5409         return;
5410     }
5411 
5412     if (gameMode == PauseGame)
5413         PauseProc(w, event, prms, nprms);
5414 
5415     if (gameMode == PlayFromGameFile)
5416         ForceProc(w, event, prms, nprms);
5417 
5418     if (gameMode == EditPosition)
5419         EditPositionDone();
5420 
5421     if ((gameMode == EndOfGame)
5422         || (gameMode == PlayFromGameFile)
5423         || (gameMode == TwoMachinesPlay)
5424         || localPlayer.appData.noShogiProgram
5425         || (gameMode == MachinePlaysWhite))
5426     {
5427         return;
5428     }
5429 
5430     if (BlackOnMove((gameMode == ForceMoves)
5431                     ? currentMove
5432                     : forwardMostMove))
5433     {
5434         DisplayMessage("It is not White's turn.", False);
5435         return;
5436     }
5437 
5438     if (gameMode == ForceMoves)
5439         forwardMostMove = currentMove;
5440 
5441     lastGameMode = gameMode = MachinePlaysWhite;
5442     ModeHighlight();
5443     SendToProgram(localPlayer.appData.whiteString, toFirstProgFP);
5444     DisplayClocks(StartTimers);
5445 }
5446 
5447 
5448 
5449 
5450 void
MachineBlackProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5451 MachineBlackProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5452 {
5453     int fromRemotePlayer = *nprms;
5454 
5455     if (updateRemotePlayer)
5456     {
5457         DisplayMessage("no machine moves in challenge mode",
5458                        fromRemotePlayer);
5459         return;
5460     }
5461 
5462     if (gameMode == PauseGame)
5463         PauseProc(w, event, prms, nprms);
5464 
5465     if (gameMode == PlayFromGameFile)
5466         ForceProc(w, event, prms, nprms);
5467 
5468     if (gameMode == EditPosition)
5469         EditPositionDone();
5470 
5471     if ((gameMode == EndOfGame)
5472         || (gameMode == PlayFromGameFile)
5473         || (gameMode == TwoMachinesPlay)
5474         || localPlayer.appData.noShogiProgram
5475         || (gameMode == MachinePlaysBlack))
5476     {
5477         return;
5478     }
5479 
5480     if (!BlackOnMove((gameMode == ForceMoves)
5481                      ? currentMove
5482                      : forwardMostMove))
5483     {
5484         DisplayMessage("It is not Black's turn.", False);
5485         return;
5486     }
5487 
5488     if (gameMode == ForceMoves)
5489         forwardMostMove = currentMove;
5490 
5491     lastGameMode = gameMode = MachinePlaysBlack;
5492     ModeHighlight();
5493     SendToProgram(localPlayer.appData.blackString, toFirstProgFP);
5494     DisplayClocks(StartTimers);
5495 }
5496 
5497 
5498 
5499 
5500 void
ForwardProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5501 ForwardProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5502 {
5503     char buf[MSG_SIZ];
5504     int target;
5505     unsigned int state;
5506 
5507     int fromRemotePlayer = *nprms;
5508 
5509     if (updateRemotePlayer)
5510     {
5511         DisplayMessage("Forward button disabled.", fromRemotePlayer);
5512         return;
5513     }
5514 
5515     if ((gameMode == EndOfGame) || (gameMode == EditPosition))
5516         return;
5517 
5518     if (gameMode == PlayFromGameFile)
5519         PauseProc(w, event, prms, nprms);
5520 
5521     if (currentMove >= forwardMostMove)
5522         return;
5523 
5524     if (event == NULL)
5525     {
5526         /* Kludge */
5527         Window root, child;
5528         int root_x, root_y;
5529         int win_x, win_y;
5530         XQueryPointer(localPlayer.xDisplay, localPlayer.xBoardWindow,
5531                       &root, &child, &root_x, &root_y,
5532                       &win_x, &win_y, &state);
5533     }
5534     else
5535     {
5536         state = event->xkey.state;
5537     }
5538 
5539     if (state & ShiftMask)
5540         target = forwardMostMove;
5541     else
5542         target = currentMove + 1;
5543 
5544     if (gameMode == ForceMoves)
5545     {
5546         while (currentMove < target)
5547         {
5548             strcpy(buf, moveList[currentMove++]);
5549             SendToProgram(buf, toFirstProgFP);
5550         }
5551     }
5552     else
5553     {
5554         currentMove = target;
5555     }
5556 
5557     if (gameMode == ForceMoves)
5558     {
5559         blackTimeRemaining = timeRemaining[0][currentMove];
5560         whiteTimeRemaining = timeRemaining[1][currentMove];
5561     }
5562 
5563     DisplayClocks(ReDisplayTimers);
5564     DisplayMove(currentMove - 1);
5565     DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
5566 }
5567 
5568 
5569 
5570 
5571 void
ResetFileProc(void)5572 ResetFileProc(void)
5573 {
5574     char *buf = "";
5575 
5576     if (updateRemotePlayer)
5577         return;
5578 
5579     if (localPlayer.appData.loadGameFile)
5580         XtFree(localPlayer.appData.loadGameFile);
5581 
5582     if (localPlayer.appData.loadPositionFile)
5583         XtFree(localPlayer.appData.loadPositionFile);
5584 
5585     localPlayer.appData.loadGameFile
5586         = localPlayer.appData.loadPositionFile = NULL;
5587     DisplayName(buf);
5588 
5589     if (gameFileFP != NULL)
5590     {
5591         fclose(gameFileFP);
5592         gameFileFP = NULL;
5593     }
5594 }
5595 
5596 
5597 
5598 
5599 void
ResetChallenge(void)5600 ResetChallenge(void)
5601 {
5602     char *buf = "";
5603 
5604     if (localPlayer.appData.challengeDisplay)
5605         XtFree(localPlayer.appData.challengeDisplay);
5606 
5607     localPlayer.appData.challengeDisplay = NULL;
5608     DisplayName(buf);
5609 }
5610 
5611 
5612 
5613 
5614 void
ResetProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5615 ResetProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5616 {
5617     int fromRemotePlayer = *nprms;
5618 
5619     if (fromRemotePlayer)
5620     {
5621         DisplayMessage("Only your opponent may reset the game.",
5622                        fromRemotePlayer);
5623         return;
5624     }
5625 
5626     Reset(True);
5627 }
5628 
5629 
5630 
5631 
5632 void
Reset(int redraw)5633 Reset(int redraw)  /* Boolean */
5634 {
5635     ResetFileProc();
5636     ResetChallenge();
5637 
5638     localPlayer.flipView = False;
5639     remotePlayer.flipView = True;
5640     startedFromSetupPosition = whitePlaysFirst = False;
5641     matchMode = MatchFalse;
5642     firstMove = True;
5643     blackFlag = whiteFlag = False;
5644     maybeThinking = False;
5645 
5646     endMessage[0] = NULLCHAR;
5647 
5648     ShutdownShogiPrograms("");
5649     lastGameMode = gameMode = BeginningOfGame;
5650     ModeHighlight();
5651     InitPosition(redraw);
5652     DisplayClocks(ResetTimers);
5653     timeRemaining[0][0] = blackTimeRemaining;
5654     timeRemaining[1][0] = whiteTimeRemaining;
5655     InitShogiProgram(localPlayer.appData.firstHost,
5656                      localPlayer.appData.firstShogiProgram,
5657                      &firstProgramPID, &toFirstProgFP,
5658                      &fromFirstProgFP, &firstProgramXID,
5659                      &firstSendTime);
5660 
5661     if (commentUp)
5662     {
5663         XtPopdown(commentShell);
5664         XtDestroyWidget(commentShell);
5665         commentUp = False;
5666     }
5667 
5668     if (localPlayer.promotionUp)
5669     {
5670         XtPopdown(localPlayer.promotionShell);
5671         XtDestroyWidget(localPlayer.promotionShell);
5672         localPlayer.promotionUp = False;
5673     }
5674 
5675     if (updateRemotePlayer && remotePlayer.promotionUp)
5676     {
5677         XtPopdown(remotePlayer.promotionShell);
5678         XtDestroyWidget(remotePlayer.promotionShell);
5679         remotePlayer.promotionUp = False;
5680     }
5681 }
5682 
5683 
5684 
5685 
5686 void
ClearCatches(int (* catches)[8])5687 ClearCatches(int (*catches)[8])
5688 {
5689     int c, p;
5690 
5691     for (c = 0; c <= 1; c++)
5692         for (p = 0; p <= 7; p++)
5693             catches[c][p] = 0;
5694 }
5695 
5696 
5697 
5698 
5699 Boolean
Challenge(char * name)5700 Challenge(char *name)
5701 {
5702     char buf[MSG_SIZ];
5703     int argc;
5704     char **argv;
5705     XrmDatabase database;
5706 
5707     if (gameMode != BeginningOfGame)
5708     {
5709         DisplayMessage("Press Reset first.", False);
5710         return (int)False;
5711     }
5712 
5713     if (localPlayer.appData.challengeDisplay != name)
5714     {
5715         if (localPlayer.appData.challengeDisplay)
5716             XtFree(localPlayer.appData.challengeDisplay);
5717 
5718         localPlayer.appData.challengeDisplay = XtMalloc(strlen(name) + 1);
5719         strcpy(localPlayer.appData.challengeDisplay, name);
5720     }
5721 
5722     sprintf(buf, "trying to connect to %s.....", name);
5723     DisplayMessage(buf, False);
5724 
5725     argc = global_argc;
5726     argv = global_argv;
5727 
5728     if ((remotePlayer.xDisplay
5729          = XtOpenDisplay(appContext, name, "XShogi",
5730                          "XShogi", 0, 0, &argc, argv)) == NULL)
5731     {
5732         sprintf(buf, "Can't open display %s", name);
5733         DisplayMessage(buf, False);
5734         XtFree(localPlayer.appData.challengeDisplay);
5735         localPlayer.appData.challengeDisplay = NULL;
5736         return (int)False;
5737     }
5738 
5739     DisplayMessage("connected! creating remote window...", False);
5740 
5741     remotePlayer.xScreen = DefaultScreen(remotePlayer.xDisplay);
5742 
5743     remotePlayer.shellWidget
5744         = XtAppCreateShell(NULL, "XShogi",
5745                            applicationShellWidgetClass,
5746                            remotePlayer.xDisplay, NULL, 0);
5747 
5748     database = XtDatabase(remotePlayer.xDisplay);
5749 
5750     XrmParseCommand(&database,
5751                     shellOptions, XtNumber(shellOptions),
5752                     "XShogi", &argc, argv);
5753 
5754     XtGetApplicationResources(remotePlayer.shellWidget,
5755                               &remotePlayer.appData, clientResources,
5756                               XtNumber(clientResources), NULL, 0);
5757 
5758     player = &remotePlayer;
5759 
5760     CreatePlayerWindow();
5761 
5762     updateRemotePlayer = True;
5763 
5764     DisplayName("REMOTE");
5765     DrawPosition(remotePlayer.boardWidget, NULL, NULL, NULL);
5766     DisplayClocks(ReDisplayTimers);
5767 
5768     DisplayMessage("ready to play", False);
5769     DisplayMessage("ready to play", True);
5770 
5771     return True;
5772 }
5773 
5774 
5775 
5776 
5777 void
ChallengeProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5778 ChallengeProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5779 {
5780     int fromRemotePlayer = *nprms;
5781 
5782     if (updateRemotePlayer)
5783     {
5784         DisplayMessage("You are already in challenge mode.",
5785                        fromRemotePlayer);
5786         return;
5787     }
5788 
5789     if (gameMode != BeginningOfGame)
5790     {
5791         DisplayMessage("Press Reset first.", False);
5792         return;
5793     }
5794 
5795     if (localPlayer.appData.challengeDisplay == NULL)
5796         FileNamePopUp("Challenge display?", Challenge);
5797     else
5798         (void) Challenge(localPlayer.appData.challengeDisplay);
5799 }
5800 
5801 
5802 
5803 
5804 Boolean
SelectLevel(char * command)5805 SelectLevel(char *command)
5806 {
5807     char buf[MSG_SIZ];
5808 
5809     sprintf(buf, "level %s\n", command);
5810     SendToProgram(buf, toFirstProgFP);
5811 
5812     return True;
5813 }
5814 
5815 
5816 
5817 
5818 void
SelectLevelProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5819 SelectLevelProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5820 {
5821     if ((BlackOnMove(forwardMostMove) && (gameMode == MachinePlaysBlack))
5822         || (!BlackOnMove(forwardMostMove) && (gameMode == MachinePlaysWhite)))
5823     {
5824         DisplayMessage("Wait until your turn.", False);
5825     }
5826     else
5827     {
5828         FileNamePopUp("#moves #minutes", SelectLevel);
5829     }
5830 }
5831 
5832 
5833 
5834 
5835 void
MoveNowProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5836 MoveNowProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5837 {
5838     if ((!BlackOnMove(forwardMostMove) && (gameMode == MachinePlaysBlack))
5839         || (BlackOnMove(forwardMostMove) && (gameMode == MachinePlaysWhite)))
5840     {
5841         DisplayMessage("Wait until machine's turn.", False);
5842     }
5843     else
5844     {
5845         Attention(firstProgramPID);
5846     }
5847 }
5848 
5849 
5850 
5851 
5852 void
LoadPositionProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)5853 LoadPositionProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5854 {
5855     int fromRemotePlayer = *nprms;
5856 
5857     if (fromRemotePlayer)
5858     {
5859         DisplayMessage("only opponent may load position", fromRemotePlayer);
5860         return;
5861     }
5862 
5863     if (gameMode != BeginningOfGame)
5864     {
5865         DisplayMessage("Press Reset first.", False);
5866         return;
5867     }
5868 
5869     FileNamePopUp("Position file name?", LoadPosition);
5870 }
5871 
5872 
5873 
5874 
5875 Boolean
LoadPosition(char * name)5876 LoadPosition(char *name)
5877 {
5878     char *p, line[MSG_SIZ], buf[MSG_SIZ];
5879     Board initial_position;
5880     Catched initial_catches;
5881     FILE *fp;
5882     int i, j;
5883 
5884     if (gameMode != BeginningOfGame)
5885     {
5886         DisplayMessage("Press Reset first.", False);
5887         return False;
5888     }
5889 
5890     if (localPlayer.appData.loadPositionFile != name)
5891     {
5892         if (localPlayer.appData.loadPositionFile)
5893             XtFree(localPlayer.appData.loadPositionFile);
5894 
5895         localPlayer.appData.loadPositionFile = XtMalloc(strlen(name) + 1);
5896         strcpy(localPlayer.appData.loadPositionFile, name);
5897     }
5898 
5899     if ((fp = fopen(name, "r")) == NULL)
5900     {
5901         sprintf(buf, "Can't open %s", name);
5902         DisplayMessage(buf, False);
5903         XtFree(localPlayer.appData.loadPositionFile);
5904         localPlayer.appData.loadPositionFile = NULL;
5905         return False;
5906     }
5907 
5908     lastGameMode = gameMode = ForceMoves;
5909     ModeHighlight();
5910     startedFromSetupPosition = True;
5911 
5912     if (firstProgramXID == 0)
5913     {
5914         InitShogiProgram(localPlayer.appData.firstHost,
5915                          localPlayer.appData.firstShogiProgram,
5916                          &firstProgramPID, &toFirstProgFP,
5917                          &fromFirstProgFP, &firstProgramXID,
5918                          &firstSendTime);
5919     }
5920 
5921     /*
5922      * Check and skip header information in position file.
5923      */
5924 
5925     fgets(line, MSG_SIZ, fp);
5926     line[strlen(line) - 1] = NULLCHAR;
5927     sprintf(buf, "# %s position file", programName);
5928 
5929     if (strncmp(line, buf, strlen(buf)))
5930     {
5931         strcat(line, ": no xshogi position file");
5932         DisplayMessage(line, False);
5933         return False;
5934     }
5935 
5936     DisplayName(line);
5937     fgets(line, MSG_SIZ, fp); /* skip opponents */
5938 
5939     for (i = BOARD_SIZE - 1; i >= 0; i--)
5940     {
5941         fgets(line, MSG_SIZ, fp);
5942 
5943         for (p = line, j = 0; j < BOARD_SIZE; p++)
5944         {
5945             int promoted = False;  /* CHECKME: is this valid? */
5946 
5947             if (*p == '+')
5948                 promoted = True;
5949 
5950             if (*p == ' ')
5951                 promoted = False;
5952 
5953             p++;
5954             initial_position[i][j++] = CharToPiece(*p, promoted);
5955         }
5956     }
5957 
5958     {
5959         int color;
5960 
5961         for (color = 0; color <= 1; color++)
5962         {
5963             fscanf(fp, "%i%i%i%i%i%i%i%i\n",
5964                    &initial_catches[color][pawn],
5965                    &initial_catches[color][lance],
5966                    &initial_catches[color][knight],
5967                    &initial_catches[color][silver],
5968                    &initial_catches[color][gold],
5969                    &initial_catches[color][bishop],
5970                    &initial_catches[color][rook],
5971                    &initial_catches[color][king]);
5972         }
5973     }
5974 
5975     whitePlaysFirst = False;
5976 
5977     if (!feof(fp))
5978     {
5979         fgets(line, MSG_SIZ, fp);
5980 
5981         if (strncmp(line, "white", strlen("white")) == 0)
5982             whitePlaysFirst = True;
5983     }
5984 
5985     fclose(fp);
5986 
5987     if (whitePlaysFirst)
5988     {
5989         CopyBoard(boards[0], initial_position);
5990         CopyCatches(catches[0], initial_catches);
5991         strcpy(moveList[0], " ...\n");
5992         strcpy(parseList[0], " ...\n");
5993         currentMove = forwardMostMove = backwardMostMove = 1;
5994         CopyBoard(boards[1], initial_position);
5995         CopyCatches(catches[1], initial_catches);
5996         SendToProgram("white\n", toFirstProgFP);
5997         SendToProgram("force\n", toFirstProgFP);
5998         SendCurrentBoard(toFirstProgFP);
5999         DisplayMessage("White to play", False);
6000     }
6001     else
6002     {
6003         currentMove = forwardMostMove = backwardMostMove = 0;
6004         CopyBoard(boards[0], initial_position);
6005         CopyCatches(catches[0], initial_catches);
6006         SendCurrentBoard(toFirstProgFP);
6007         SendToProgram("force\n", toFirstProgFP);
6008         DisplayMessage("Black to play", False);
6009     }
6010 
6011     DisplayClocks(ResetTimers);
6012     timeRemaining[0][1] = blackTimeRemaining;
6013     timeRemaining[1][1] = whiteTimeRemaining;
6014 
6015     DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
6016     return True;
6017 }
6018 
6019 
6020 
6021 
6022 void
EditPositionProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6023 EditPositionProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6024 {
6025     int fromRemotePlayer = *nprms;
6026 
6027     if (updateRemotePlayer)
6028     {
6029         DisplayMessage("Edit button disabled", fromRemotePlayer);
6030         return;
6031     }
6032 
6033     if (gameMode == EditPosition)
6034         return;
6035 
6036     ForceProc(w, event, prms, nprms);
6037 
6038     if (gameMode != ForceMoves)
6039         return;
6040 
6041     DisplayName("<-- Press to set side to play next");
6042     DisplayMessage("Mouse: 1=drag, 2=black, 3=white", False);
6043 
6044     lastGameMode = gameMode = EditPosition;
6045     ModeHighlight();
6046 
6047     if (currentMove > 0)
6048         CopyBoard(boards[0], boards[currentMove]);
6049 
6050     whitePlaysFirst = !BlackOnMove(forwardMostMove);
6051     currentMove = forwardMostMove = backwardMostMove = 0;
6052 }
6053 
6054 
6055 
6056 
6057 void
EditPositionDone(void)6058 EditPositionDone(void)
6059 {
6060     startedFromSetupPosition = True;
6061     SendToProgram(localPlayer.appData.initString, toFirstProgFP);
6062     SendSearchDepth(toFirstProgFP);
6063 
6064     if (whitePlaysFirst)
6065     {
6066         strcpy(moveList[0], " ...\n");
6067         strcpy(parseList[0], " ...\n");
6068         currentMove = forwardMostMove = backwardMostMove = 1;
6069         CopyBoard(boards[1], boards[0]);
6070         CopyCatches(catches[1], catches[0]);
6071         SendToProgram("force\n", toFirstProgFP);
6072         SendCurrentBoard(toFirstProgFP);
6073         DisplayName(" ");
6074         DisplayMessage("White to play", False);
6075     }
6076     else
6077     {
6078         currentMove = forwardMostMove = backwardMostMove = 0;
6079         SendCurrentBoard(toFirstProgFP);
6080         SendToProgram("force\n", toFirstProgFP);
6081         DisplayName(" ");
6082         DisplayMessage("Black to play", False);
6083     }
6084 
6085     lastGameMode = gameMode = ForceMoves;
6086 }
6087 
6088 
6089 
6090 /*
6091  * FUNCTION
6092  *     BackwardProc
6093  *
6094  * DESCRIPTION
6095  *     This function executes when undoing a move.
6096  *     FIXME: this function is totally hosed!!!
6097  *
6098  * ARGUMENTS
6099  *     Widget w
6100  *     XEvent *event
6101  *     String *prms
6102  *     Cardinal *nprms
6103  *
6104  * RETURN VALUE
6105  *     void
6106  *
6107  */
6108 
6109 void
BackwardProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6110 BackwardProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6111 {
6112     int target;
6113     unsigned int state;
6114 
6115     int fromRemotePlayer = *nprms;
6116 
6117     if (updateRemotePlayer)
6118     {
6119         DisplayMessage("Backward button disabled", fromRemotePlayer);
6120         return;
6121     }
6122 
6123     /*
6124      * Why do we need this here?
6125      */
6126 
6127     ForceProc(w, event, prms, nprms);
6128 
6129     if ((currentMove <= backwardMostMove) || (gameMode == EditPosition))
6130         return;
6131 
6132     if (gameMode == EndOfGame)
6133         ResurrectShogiProgram();
6134 
6135     if (gameMode == PlayFromGameFile)
6136         PauseProc(w, event, prms, nprms);
6137 
6138     if (event == NULL)
6139     {
6140         /* Kludge */
6141         Window root, child;
6142         int root_x, root_y;
6143         int win_x, win_y;
6144 
6145         XQueryPointer(localPlayer.xDisplay, localPlayer.xBoardWindow,
6146                       &root, &child, &root_x, &root_y,
6147                       &win_x, &win_y, &state);
6148     }
6149     else
6150     {
6151         state = event->xkey.state;
6152     }
6153 
6154     if (state & ShiftMask)
6155     {
6156         target = backwardMostMove;
6157     }
6158     else
6159     {
6160         target = currentMove - 1;
6161     }
6162 
6163     if (gameMode == ForceMoves)
6164     {
6165         Attention(firstProgramPID);
6166 
6167         while (currentMove > target)
6168         {
6169             SendToProgram("undo\n", toFirstProgFP);
6170             currentMove--;
6171         }
6172     }
6173     else
6174     {
6175         currentMove = target;
6176     }
6177 
6178     if (gameMode == ForceMoves)
6179     {
6180         whiteTimeRemaining = timeRemaining[0][currentMove];
6181         blackTimeRemaining = timeRemaining[1][currentMove];
6182     }
6183 
6184     DisplayClocks(ReDisplayTimers);
6185     DisplayMove(currentMove - 1);
6186     DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
6187 }
6188 
6189 
6190 
6191 
6192 void
FlipViewProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6193 FlipViewProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6194 {
6195     struct DisplayData *player = (*nprms ? &remotePlayer : &localPlayer);
6196 
6197     player->flipView = !player->flipView;
6198     DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
6199 }
6200 
6201 
6202 
6203 
6204 void
SaveGameProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6205 SaveGameProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6206 {
6207     char def[MSG_SIZ];
6208 
6209     int fromRemotePlayer = *nprms;
6210 
6211     if (fromRemotePlayer)
6212     {
6213         DisplayMessage("only opponent may save game", fromRemotePlayer);
6214         return;
6215     }
6216 
6217     def[0] = NULLCHAR;
6218 
6219     FileNamePopUp("Filename for saved game?", SaveGame);
6220 }
6221 
6222 
6223 
6224 
6225 Boolean
SaveGame(char * name)6226 SaveGame(char *name)
6227 {
6228     char buf[MSG_SIZ];
6229     int i, len, move = 0;
6230     time_t tm;
6231 
6232     if (!filemodeUp) /* if called via FileModeCallback avoid recursion */
6233     {
6234         if ((gameFileFP = fopen(name, "r")) == NULL)
6235         {
6236             strcpy(fmi.mode, "w");
6237         }
6238         else
6239         {
6240             fclose(gameFileFP);
6241             FileModePopUp(name);
6242             return False; /* CHECKME: what should the return value be? */
6243         }
6244     }
6245 
6246     if ((gameFileFP = fopen(name, fmi.mode)) == NULL)
6247     {
6248         sprintf(buf, "Can't open %s (mode %s)", name, fmi.mode);
6249         DisplayMessage(buf, False);
6250         return False;
6251     }
6252 
6253     tm = time((time_t *) NULL);
6254 
6255     fprintf(gameFileFP, "# %s game file -- %s", programName, ctime(&tm));
6256     PrintOpponents(gameFileFP);
6257 
6258     for (i = 0; i < currentMove;)
6259     {
6260         if ((i % 5) == 0)
6261             fprintf(gameFileFP, "\n");
6262 
6263         fprintf(gameFileFP, "%d. %s ", ++move, parseList[i++]);
6264 
6265         if (i >= currentMove)
6266         {
6267             fprintf(gameFileFP, "\n");
6268             break;
6269         }
6270 
6271         if ((len = strlen(parseList[i])) == 0)
6272             break;
6273 
6274         fprintf(gameFileFP, "%s ", parseList[i++]);
6275     }
6276 
6277     fprintf(gameFileFP, "\n");
6278 
6279     fclose(gameFileFP);
6280     gameFileFP = NULL;
6281 
6282     return True;
6283 }
6284 
6285 
6286 
6287 
6288 void
SwitchProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6289 SwitchProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6290 {
6291     if (localPlayer.appData.noShogiProgram)
6292         return;
6293 
6294     switch (gameMode)
6295     {
6296     default:
6297         return;
6298 
6299     case MachinePlaysBlack:
6300         if (BlackOnMove(forwardMostMove))
6301         {
6302             DisplayMessage("Wait until your turn", False);
6303             return;
6304         }
6305 
6306         lastGameMode = gameMode = MachinePlaysWhite;
6307         ModeHighlight();
6308         break;
6309 
6310     case BeginningOfGame:
6311 
6312     case MachinePlaysWhite:
6313         if (!BlackOnMove(forwardMostMove))
6314         {
6315             DisplayMessage("Wait until your turn", False);
6316             return;
6317         }
6318 
6319         if (forwardMostMove == 0)
6320         {
6321             MachineBlackProc(w, event, prms, nprms);
6322             return;
6323         }
6324 
6325         lastGameMode = gameMode = MachinePlaysBlack;
6326         ModeHighlight();
6327         break;
6328     }
6329 
6330     Attention(firstProgramPID);
6331     SendToProgram("switch\n", toFirstProgFP);
6332 }
6333 
6334 
6335 
6336 
6337 void
ForceProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6338 ForceProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6339 {
6340     int i;
6341 
6342     switch (gameMode)
6343     {
6344     case MachinePlaysBlack:
6345         if (BlackOnMove(forwardMostMove))
6346         {
6347             DisplayMessage("Wait until your turn", False);
6348             return;
6349         }
6350 
6351         Attention(firstProgramPID);
6352         SendToProgram("force\n", toFirstProgFP);
6353         break;
6354 
6355     case MachinePlaysWhite:
6356         if (!BlackOnMove(forwardMostMove))
6357         {
6358             DisplayMessage("Wait until your turn", False);
6359             return;
6360         }
6361 
6362         Attention(firstProgramPID);
6363         SendToProgram("force\n", toFirstProgFP);
6364         break;
6365 
6366     case BeginningOfGame:
6367         SendToProgram("force\n", toFirstProgFP);
6368         break;
6369 
6370     case PlayFromGameFile:
6371         if (readGameXID != 0)
6372         {
6373             XtRemoveTimeOut(readGameXID);
6374             readGameXID = 0;
6375         }
6376 
6377         if (gameFileFP != NULL)
6378         {
6379             fclose(gameFileFP);
6380             gameFileFP = NULL;
6381         }
6382 
6383         break;
6384 
6385     case EndOfGame:
6386         ResurrectShogiProgram();
6387         break;
6388 
6389     case EditPosition:
6390         EditPositionDone();
6391         break;
6392 
6393     case TwoMachinesPlay:
6394         ShutdownShogiPrograms("");
6395         ResurrectShogiProgram();
6396         return;
6397 
6398     default:
6399         return;
6400     }
6401 
6402     if ((gameMode == MachinePlaysWhite)
6403         || (gameMode == MachinePlaysBlack)
6404         || (gameMode == TwoMachinesPlay)
6405         || (gameMode == PlayFromGameFile))
6406     {
6407         i = forwardMostMove;
6408 
6409         while (i > currentMove)
6410         {
6411             SendToProgram("undo\n", toFirstProgFP);
6412             i--;
6413         }
6414 
6415         blackTimeRemaining = timeRemaining[0][currentMove];
6416         whiteTimeRemaining = timeRemaining[1][currentMove];
6417 
6418         if (whiteFlag || blackFlag)
6419         {
6420             whiteFlag = blackFlag = 0;
6421         }
6422 
6423         DisplayTitle("");
6424     }
6425 
6426     lastGameMode = gameMode = ForceMoves;
6427     ModeHighlight();
6428     DisplayClocks(StopTimers);
6429 }
6430 
6431 
6432 
6433 void
HintProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6434 HintProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6435 {
6436     int fromRemotePlayer = *nprms;
6437 
6438     if (updateRemotePlayer)
6439     {
6440         DisplayMessage("no hints in challenge mode", fromRemotePlayer);
6441         return;
6442     }
6443 
6444     if (localPlayer.appData.noShogiProgram)
6445         return;
6446 
6447     switch (gameMode)
6448     {
6449     case MachinePlaysBlack:
6450         if (BlackOnMove(forwardMostMove))
6451         {
6452             DisplayMessage("Wait until your turn", False);
6453             return;
6454         }
6455 
6456         break;
6457 
6458     case BeginningOfGame:
6459     case MachinePlaysWhite:
6460         if (!BlackOnMove(forwardMostMove))
6461         {
6462             DisplayMessage("Wait until your turn", False);
6463             return;
6464         }
6465 
6466         break;
6467 
6468     default:
6469         DisplayMessage("No hint available", False);
6470         return;
6471     }
6472 
6473     Attention(firstProgramPID);
6474     SendToProgram("hint\n", toFirstProgFP);
6475 }
6476 
6477 
6478 
6479 
6480 void
PrintPosition(FILE * fp,int move)6481 PrintPosition(FILE *fp, int move)
6482 {
6483     int i, j, color;
6484 
6485     for (i = BOARD_SIZE - 1; i >= 0; i--)
6486     {
6487         for (j = 0; j < BOARD_SIZE; j++)
6488         {
6489             if (pieceIsPromoted[(int)boards[currentMove][i][j]])
6490                 fprintf(fp, "%c", '+');
6491             else
6492                 fprintf(fp, "%c", ' ');
6493 
6494             fprintf(fp, "%c",
6495                     pieceToChar[(int)boards[currentMove][i][j]]);
6496 
6497             if (j == BOARD_SIZE - 1)
6498                 fputc('\n', fp);
6499         }
6500     }
6501 
6502     for (color = 0; color <= 1; color++)
6503     {
6504         fprintf(fp, "%i %i %i %i %i %i %i %i\n",
6505                 catches[currentMove][color][pawn],
6506                 catches[currentMove][color][lance],
6507                 catches[currentMove][color][knight],
6508                 catches[currentMove][color][silver],
6509                 catches[currentMove][color][gold],
6510                 catches[currentMove][color][bishop],
6511                 catches[currentMove][color][rook],
6512                 catches[currentMove][color][king]);
6513     }
6514 
6515     if ((gameMode == EditPosition)
6516         ? !whitePlaysFirst
6517         : BlackOnMove(forwardMostMove))
6518     {
6519         fprintf(fp, "black to play\n");
6520     }
6521     else
6522     {
6523         fprintf(fp, "white to play\n");
6524     }
6525 }
6526 
6527 
6528 
6529 
6530 void
PrintOpponents(FILE * fp)6531 PrintOpponents(FILE *fp)
6532 {
6533     char host_name[MSG_SIZ];
6534 
6535 #ifdef HAVE_GETHOSTNAME
6536     gethostname(host_name, MSG_SIZ);
6537 #else
6538     strncpy(host_name, "hostname not available", MSG_SIZ);
6539 #endif
6540 
6541     switch (lastGameMode)
6542     {
6543     case MachinePlaysWhite:
6544         fprintf(fp, "# %s@%s vs. %s@%s\n",
6545                 localPlayer.appData.firstShogiProgram,
6546                 localPlayer.appData.firstHost,
6547                 getpwuid(getuid())->pw_name,
6548                 host_name);
6549         break;
6550 
6551     case MachinePlaysBlack:
6552         fprintf(fp, "# %s@%s vs. %s@%s\n",
6553                 getpwuid(getuid())->pw_name,
6554                 host_name,
6555                 localPlayer.appData.firstShogiProgram,
6556                 localPlayer.appData.firstHost);
6557         break;
6558 
6559     case TwoMachinesPlay:
6560         fprintf(fp, "# %s@%s vs. %s@%s\n",
6561                 localPlayer.appData.secondShogiProgram,
6562                 localPlayer.appData.secondHost,
6563                 localPlayer.appData.firstShogiProgram,
6564                 localPlayer.appData.firstHost);
6565         break;
6566 
6567     default:
6568         fprintf(fp, "#\n");
6569         break;
6570     }
6571 }
6572 
6573 
6574 
6575 
6576 void
SavePositionProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6577 SavePositionProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6578 {
6579     char def[MSG_SIZ];
6580 
6581     int fromRemotePlayer = *nprms;
6582 
6583     if (fromRemotePlayer)
6584     {
6585         DisplayMessage("only opponent may save game", fromRemotePlayer);
6586         return;
6587     }
6588 
6589     def[0] = NULLCHAR;
6590 
6591     FileNamePopUp("Filename for saved position?", SavePosition);
6592 }
6593 
6594 
6595 
6596 
6597 Boolean
SavePosition(char * name)6598 SavePosition(char *name)
6599 {
6600     char buf[MSG_SIZ];
6601     FILE *fp;
6602     time_t tm;
6603 
6604     if ((fp = fopen(name, "w")) == NULL)
6605     {
6606         sprintf(buf, "Can't open %s", name);
6607         DisplayMessage(buf, False);
6608         return False;
6609     }
6610 
6611     tm = time((time_t *) NULL);
6612 
6613     fprintf(fp, "# %s position file -- %s", programName, ctime(&tm));
6614     PrintOpponents(fp);
6615     PrintPosition(fp, currentMove);
6616     fclose(fp);
6617 
6618     return True;
6619 }
6620 
6621 
6622 
6623 
6624 void
TwoMachinesProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6625 TwoMachinesProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6626 {
6627     int i;
6628     MatchMode matchKind;
6629 
6630     int fromRemotePlayer = *nprms;
6631 
6632     if (updateRemotePlayer)
6633     {
6634         DisplayMessage("no machine moves in challenge mode",
6635                        fromRemotePlayer);
6636         return;
6637     }
6638 
6639     if (gameMode == PauseGame)
6640         PauseProc(w, event, prms, nprms);
6641 
6642     if (gameMode == PlayFromGameFile)
6643         ForceProc(w, event, prms, nprms);
6644 
6645     if ((gameMode == EndOfGame)
6646         || (gameMode == TwoMachinesPlay)
6647         || localPlayer.appData.noShogiProgram)
6648     {
6649         return;
6650     }
6651 
6652     if (matchMode == MatchFalse)
6653     {
6654         switch (gameMode)
6655         {
6656         case PauseGame:
6657         case PlayFromGameFile:
6658             return;
6659 
6660         case MachinePlaysBlack:
6661         case MachinePlaysWhite:
6662             ForceProc(w, event, prms, nprms);
6663 
6664             if (gameMode != ForceMoves)
6665                 return;
6666 
6667             matchKind = MatchOpening;
6668             break;
6669 
6670         case ForceMoves:
6671             matchKind = MatchOpening;
6672             break;
6673 
6674         case EditPosition:
6675             EditPositionDone();
6676             matchKind = MatchPosition;
6677             break;
6678 
6679         case BeginningOfGame:
6680         default:
6681             matchKind = MatchInit;
6682             break;
6683         }
6684     }
6685     else
6686     {
6687         matchKind = matchMode;
6688     }
6689 
6690     forwardMostMove = currentMove;
6691 
6692     localPlayer.flipView = False;
6693     remotePlayer.flipView = True;
6694     firstMove = False;
6695     DisplayClocks(ResetTimers);
6696     DisplayClocks(StartTimers);
6697 
6698     switch (matchKind)
6699     {
6700     case MatchOpening:
6701         if (firstProgramXID == 0)
6702         {
6703             if (localPlayer.appData.loadGameFile == NULL)
6704             {
6705                 DisplayMessage("Select game file first", False);
6706                 return;
6707             }
6708 
6709             InitShogiProgram(localPlayer.appData.firstHost,
6710                              localPlayer.appData.firstShogiProgram,
6711                              &firstProgramPID, &toFirstProgFP,
6712                              &fromFirstProgFP, &firstProgramXID,
6713                              &firstSendTime);
6714 
6715             if (!LoadGame(localPlayer.appData.loadGameFile))
6716             {
6717                 ShutdownShogiPrograms("Bad game file");
6718                 return;
6719             }
6720 
6721             DrawPosition(localPlayer.boardWidget, NULL, NULL, NULL);
6722         }
6723 
6724         InitShogiProgram(localPlayer.appData.secondHost,
6725                          localPlayer.appData.secondShogiProgram,
6726                          &secondProgramPID, &toSecondProgFP,
6727                          &fromSecondProgFP, &secondProgramXID,
6728                          &secondSendTime);
6729 
6730         if (startedFromSetupPosition)
6731         {
6732             if (whitePlaysFirst)
6733             {
6734                 i = 1;
6735                 SendToProgram("force\n", toSecondProgFP);
6736                 SendBoard(toSecondProgFP, boards[i], catches[i]);
6737             }
6738             else
6739             {
6740                 i = 0;
6741                 SendBoard(toSecondProgFP, boards[i], catches[i]);
6742                 SendToProgram("force\n", toSecondProgFP);
6743             }
6744         }
6745         else
6746         {
6747             i = 0;
6748             SendToProgram("force\n", toSecondProgFP);
6749         }
6750 
6751         for (i = backwardMostMove; i < forwardMostMove; i++)
6752             SendToProgram(moveList[i], toSecondProgFP);
6753 
6754         lastGameMode = gameMode = TwoMachinesPlay;
6755         ModeHighlight();
6756         firstMove = True;
6757 
6758         if (BlackOnMove(forwardMostMove))
6759             SendToProgram(localPlayer.appData.blackString, toSecondProgFP);
6760         else
6761             SendToProgram(localPlayer.appData.whiteString, toFirstProgFP);
6762 
6763         break;
6764 
6765     case MatchPosition:
6766         if (firstProgramXID == 0)
6767         {
6768             if (localPlayer.appData.loadPositionFile == NULL)
6769             {
6770                 DisplayMessage("Select position file first", False);
6771                 return;
6772             }
6773 
6774             InitShogiProgram(localPlayer.appData.firstHost,
6775                              localPlayer.appData.firstShogiProgram,
6776                              &firstProgramPID, &toFirstProgFP,
6777                              &fromFirstProgFP, &firstProgramXID,
6778                              &firstSendTime);
6779 
6780             if (!LoadPosition(localPlayer.appData.loadPositionFile))
6781                 return;
6782         }
6783 
6784         InitShogiProgram(localPlayer.appData.secondHost,
6785                          localPlayer.appData.secondShogiProgram,
6786                          &secondProgramPID, &toSecondProgFP,
6787                          &fromSecondProgFP, &secondProgramXID,
6788                          &secondSendTime);
6789 
6790         if (whitePlaysFirst)
6791             SendToProgram("force\n", toSecondProgFP);
6792 
6793         SendCurrentBoard(toSecondProgFP);
6794         lastGameMode = gameMode = TwoMachinesPlay;
6795         ModeHighlight();
6796         firstMove = True;
6797 
6798         if (BlackOnMove(forwardMostMove))
6799             SendToProgram(localPlayer.appData.blackString, toSecondProgFP);
6800         else
6801             SendToProgram(localPlayer.appData.whiteString, toFirstProgFP);
6802 
6803         break;
6804 
6805     case MatchInit:
6806         InitPosition(True);
6807 
6808         if (firstProgramXID == 0)
6809         {
6810             InitShogiProgram(localPlayer.appData.firstHost,
6811                              localPlayer.appData.firstShogiProgram,
6812                              &firstProgramPID, &toFirstProgFP,
6813                              &fromFirstProgFP, &firstProgramXID,
6814                              &firstSendTime);
6815         }
6816 
6817         InitShogiProgram(localPlayer.appData.secondHost,
6818                          localPlayer.appData.secondShogiProgram,
6819                          &secondProgramPID, &toSecondProgFP,
6820                          &fromSecondProgFP, &secondProgramXID,
6821                          &secondSendTime);
6822 
6823         lastGameMode = gameMode = TwoMachinesPlay;
6824         ModeHighlight();
6825         SendToProgram(localPlayer.appData.blackString, toSecondProgFP);
6826 
6827     default:
6828         break;
6829     }
6830 
6831     if (!firstSendTime || !secondSendTime)
6832     {
6833         DisplayClocks(ResetTimers);
6834         timeRemaining[0][forwardMostMove] = blackTimeRemaining;
6835         timeRemaining[1][forwardMostMove] = whiteTimeRemaining;
6836     }
6837 
6838     DisplayClocks(StartTimers);
6839 }
6840 
6841 
6842 
6843 
6844 void
PauseProc(Widget w,XEvent * event,String * prms,Cardinal * nprms)6845 PauseProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6846 {
6847     static GameMode previous_mode = PauseGame;
6848 
6849     switch (gameMode)
6850     {
6851     case ForceMoves:
6852     case EndOfGame:
6853     case EditPosition:
6854     default:
6855         return;
6856 
6857     case PauseGame:
6858         gameMode = previous_mode;
6859         ModeHighlight();
6860         previous_mode = PauseGame;
6861         DisplayClocks(StartTimers);
6862         DisplayMessage("", False);
6863 
6864         if (updateRemotePlayer)
6865             DisplayMessage("", True);
6866         break;
6867 
6868     case PlayFromGameFile:
6869         if (readGameXID == 0)
6870         {
6871             readGameXID =
6872                 XtAppAddTimeOut(appContext,
6873                                 (int)(1000 * localPlayer.appData.timeDelay),
6874                                 (XtTimerCallbackProc) ReadGameFile, NULL);
6875         }
6876         else
6877         {
6878             XtRemoveTimeOut(readGameXID);
6879             readGameXID = 0;
6880         }
6881 
6882         DisplayMessage("Pausing", False);
6883 
6884         if (updateRemotePlayer)
6885             DisplayMessage("Pausing", True);
6886 
6887         break;
6888 
6889     case BeginningOfGame:
6890     case MachinePlaysBlack:
6891     case MachinePlaysWhite:
6892     case TwoMachinesPlay:
6893         if (forwardMostMove == 0)   /* Don't pause if no one has moved. */
6894             return;
6895 
6896         if (((gameMode == MachinePlaysWhite)
6897              && !BlackOnMove(forwardMostMove))
6898             || ((gameMode == MachinePlaysBlack) &&
6899                 BlackOnMove(forwardMostMove)))
6900         {
6901             DisplayClocks(StopTimers);
6902         }
6903 
6904         previous_mode = gameMode;
6905         gameMode = PauseGame;
6906         ModeHighlight();
6907         DisplayClocks(StopTimers);
6908         DisplayMessage("Pausing", False);
6909 
6910         if (updateRemotePlayer)
6911             DisplayMessage("Pausing", True);
6912 
6913         break;
6914     }
6915 }
6916 
6917 
6918 
6919 
6920 void
Iconify(Widget w,XEvent * event,String * prms,Cardinal * nprms)6921 Iconify(Widget w, XEvent *event, String *prms, Cardinal *nprms)
6922 {
6923     Arg args[1];
6924 
6925     fromX = fromY = -1;
6926 
6927     XtSetArg(args[0], XtNiconic, True);
6928     XtSetValues(localPlayer.shellWidget, args, 1);
6929 }
6930 
6931 
6932 
6933 
6934 void
SendToProgram(char * message,FILE * fp)6935 SendToProgram(char *message, FILE *fp)
6936 {
6937     if (fp == NULL)
6938         return;
6939 
6940     lastMsgFP = fp;
6941 
6942     if (xshogiDebug)
6943     {
6944         fprintf(stderr, "Sending to %s: %s\n",
6945                 ((fp == toFirstProgFP) ? "first" : "second"), message);
6946     }
6947 
6948     if (message[strlen(message) - 1] != '\n')
6949         fprintf(fp, "\n%s\n", message);
6950     else
6951         fputs(message, fp);
6952 
6953     fflush(fp);
6954 }
6955 
6956 
6957 
6958 
6959 void
ReceiveFromProgram(FILE * fp,int * source,XtInputId * id)6960 ReceiveFromProgram(FILE *fp, int *source, XtInputId *id)
6961 {
6962     char message[MSG_SIZ], *end_str, *number, *name;
6963 
6964     if (fgets(message, MSG_SIZ, fp) == NULL)
6965     {
6966         if (fp == fromFirstProgFP)
6967         {
6968             number = "first";
6969             name = localPlayer.appData.firstShogiProgram;
6970         }
6971         else if (fp == fromSecondProgFP)
6972         {
6973             number = "second";
6974             name = localPlayer.appData.secondShogiProgram;
6975         }
6976         else
6977         {
6978             return;
6979         }
6980 
6981         if (ferror(fp) == 0)
6982         {
6983             sprintf(message, "%s shogi program (%s) exited unexpectedly",
6984                     number, name);
6985             fprintf(stderr, "%s: %s\n", programName, message);
6986         }
6987         else
6988         {
6989             sprintf(message,
6990                     "error reading from %s shogi program (%s): %s",
6991                     number, name, strerror(ferror(fp)));
6992             fprintf(stderr, "%s: %s\n", programName, message);
6993         }
6994 
6995         return;
6996     }
6997 
6998     if ((end_str = (char *)strchr(message, '\r')) != NULL)
6999         *end_str = NULLCHAR;
7000 
7001     if ((end_str = (char *)strchr(message, '\n')) != NULL)
7002         *end_str = NULLCHAR;
7003 
7004     if (xshogiDebug || localPlayer.appData.debugMode)
7005     {
7006         fprintf(stderr, "Received from %s: %s\n",
7007                 ((fp == fromFirstProgFP) ? "first" : "second"), message);
7008     }
7009 
7010     HandleMachineMove(message, fp);
7011 }
7012 
7013 
7014 
7015 
7016 void
SendSearchDepth(FILE * fp)7017 SendSearchDepth(FILE *fp)
7018 {
7019     char message[MSG_SIZ];
7020 
7021     if (localPlayer.appData.searchDepth <= 0)
7022         return;
7023 
7024     sprintf(message, "depth\n%d\nhelp\n", localPlayer.appData.searchDepth);
7025     /* Note kludge: "help" command forces gnushogi to print
7026      * out something that ends with a newline. */
7027     SendToProgram(message, fp);
7028 }
7029 
7030 
7031 
7032 
7033 void
DisplayMessage(char * message,int toRemotePlayer)7034 DisplayMessage(char *message, int toRemotePlayer)
7035 {
7036     Arg arg;
7037 
7038     XtSetArg(arg, XtNlabel, message);
7039 
7040     if (!toRemotePlayer)
7041         XtSetValues(localPlayer.messageWidget, &arg, 1);
7042 
7043     if (updateRemotePlayer && toRemotePlayer)
7044         XtSetValues(remotePlayer.messageWidget, &arg, 1);
7045 }
7046 
7047 
7048 
7049 
7050 void
DisplayName(char * name)7051 DisplayName(char *name)
7052 {
7053     Arg arg;
7054 
7055     XtSetArg(arg, XtNlabel, name);
7056     XtSetValues(localPlayer.titleWidget, &arg, 1);
7057 
7058     if (updateRemotePlayer)
7059         XtSetValues(remotePlayer.titleWidget, &arg, 1);
7060 }
7061 
7062 
7063 
7064 
SendTimeRemaining(FILE * fp)7065 void SendTimeRemaining(FILE *fp)
7066 {
7067     char message[MSG_SIZ];
7068     long comtime, opptime;
7069 
7070     if (BlackOnMove(forwardMostMove) == (fp == toFirstProgFP))
7071     {
7072         comtime = blackTimeRemaining;
7073         opptime = whiteTimeRemaining;
7074     }
7075     else
7076     {
7077         comtime = whiteTimeRemaining;
7078         opptime = blackTimeRemaining;
7079     }
7080 
7081     if (comtime <= 0)
7082         comtime = 1000;
7083 
7084     if (opptime <= 0)
7085         opptime = 1000;
7086 
7087     sprintf(message, "time %ld\n",  comtime / 10);
7088     SendToProgram(message, fp);
7089     sprintf(message, "otime %ld\n", opptime / 10);
7090     SendToProgram(message, fp);
7091 }
7092 
7093 
7094 
7095 
DisplayMove(int moveNumber)7096 void DisplayMove(int moveNumber)
7097 {
7098     char message[MSG_SIZ];
7099 
7100     if (moveNumber < 0)
7101     {
7102         if (moveNumber == forwardMostMove - 1)
7103             DisplayMessage(endMessage, False);
7104         else
7105             DisplayMessage("", False);
7106     }
7107     else
7108     {
7109         sprintf(message, "%d. %s%s  %s",
7110                 (moveNumber / 2 + 1),
7111                 (BlackOnMove(moveNumber) ? "" : "... "),
7112                 parseList[moveNumber],
7113                 (moveNumber == (forwardMostMove - 1)) ? endMessage : "");
7114         DisplayMessage(message, False);
7115     }
7116 }
7117 
7118 
7119 
7120 
DisplayTitle(char * title)7121 void DisplayTitle(char *title)
7122 {
7123     Arg arg;
7124 
7125     XtSetArg(arg, XtNlabel, title);
7126     XtSetValues(localPlayer.titleWidget, &arg, 1);
7127 }
7128 
7129 
7130 
7131 
7132 /*
7133  * This routine used to send a SIGINT (^C interrupt) to gnushogi to awaken it
7134  * if it might be busy thinking on our time.  This normally isn't needed,
7135  * but is useful on systems where the FIONREAD ioctl doesn't work since
7136  * on those systems the gnushogi feature that lets you interrupt its thinking
7137  * just by typing a command does not work.
7138  *
7139  * Now gnushogi periodically checks for user input without a need for
7140  * this hack.
7141  */
7142 
7143 void
Attention(int pid)7144 Attention(int pid)
7145 {
7146 #if 0
7147     if (localPlayer.appData.noShogiProgram || (pid == 0))
7148         return;
7149 
7150     switch (gameMode)
7151     {
7152     case MachinePlaysBlack:
7153     case MachinePlaysWhite:
7154     case TwoMachinesPlay:
7155         if ((forwardMostMove > backwardMostMove + 1) && maybeThinking)
7156         {
7157             if (xshogiDebug || localPlayer.appData.debugMode)
7158             {
7159                 fprintf(stderr, "Sending SIGINT to %s\n",
7160                         ((pid == firstProgramPID) ? "first" : "second"));
7161             }
7162 
7163             (void)kill(pid, SIGINT); /* stop it thinking */
7164         }
7165         break;
7166 
7167     default:
7168         break;  /* CHECKME: is this OK? */
7169     }
7170 #endif /* !defined(FIONREAD) */
7171 }
7172 
7173 
7174 
7175 
7176 void
CheckFlags(void)7177 CheckFlags(void)
7178 {
7179     if (blackTimeRemaining <= 0)
7180     {
7181         if (!blackFlag)
7182         {
7183             blackFlag = True;
7184 
7185             if (whiteFlag)
7186                 DisplayName("  Both flags have fallen");
7187             else
7188                 DisplayName("  Black's flag has fallen");
7189         }
7190     }
7191 
7192     if (whiteTimeRemaining <= 0)
7193     {
7194         if (!whiteFlag)
7195         {
7196             whiteFlag = True;
7197 
7198             if (blackFlag)
7199                 DisplayName("  Both flags have fallen");
7200             else
7201                 DisplayName("  White's flag has fallen");
7202         }
7203     }
7204 }
7205 
7206 
7207 
7208 
7209 void
CheckTimeControl(void)7210 CheckTimeControl(void)
7211 {
7212     if (!localPlayer.appData.clockMode)
7213         return;
7214 
7215     if (forwardMostMove == 0)
7216         return;
7217 
7218     /*
7219      * Add time to clocks when time control is achieved.
7220      */
7221 
7222     if ((forwardMostMove % (localPlayer.appData.movesPerSession * 2)) == 0)
7223     {
7224         blackTimeRemaining += timeControl;
7225         whiteTimeRemaining += timeControl;
7226     }
7227 }
7228 
7229 
7230 
7231 
7232 void
DisplayLabels(void)7233 DisplayLabels(void)
7234 {
7235     DisplayTimerLabel(localPlayer.blackTimerWidget, "Black",
7236                       blackTimeRemaining);
7237     DisplayTimerLabel(localPlayer.whiteTimerWidget, "White",
7238                       whiteTimeRemaining);
7239 
7240     if (updateRemotePlayer)
7241     {
7242         DisplayTimerLabel(remotePlayer.blackTimerWidget, "Black",
7243                           blackTimeRemaining);
7244         DisplayTimerLabel(remotePlayer.whiteTimerWidget, "White",
7245                           whiteTimeRemaining);
7246     }
7247 }
7248 
7249 
7250 
7251 
7252 #ifdef HAVE_GETTIMEOFDAY
7253 static struct timeval tickStartTV;
7254 static int tickLength;
7255 
7256 int
PartialTickLength(void)7257 PartialTickLength(void)
7258 {
7259     struct timeval tv;
7260     int ptl;
7261 
7262     gettimeofday(&tv, NULL);
7263     ptl = ((tv.tv_sec - tickStartTV.tv_sec) * 1000000 +
7264            (tv.tv_usec - tickStartTV.tv_usec) + 500) / 1000;
7265 
7266     if (ptl > tickLength)
7267         ptl = tickLength;
7268 
7269     return ptl;
7270 }
7271 #else /* !HAVE_GETTIMEOFDAY */
7272 #define tickLength 1000
7273 #endif /* HAVE_GETTIMEOFDAY */
7274 
7275 
7276 
7277 
7278 /*
7279  * DisplayClocks manages the game clocks.
7280  *
7281  * In tournament play, white starts the clock and then black makes a move.
7282  * We give the human user a slight advantage if he is playing black---the
7283  * clocks don't run until he makes his first move, so it takes zero time.
7284  * Also, DisplayClocks doesn't account for network lag so it could get out
7285  * of sync with GNU Shogi's clock -- but then, referees are always right.
7286  */
7287 
7288 void
DisplayClocks(int clock_mode)7289 DisplayClocks(int clock_mode)
7290 {
7291     long timeRemaining;
7292 
7293     switch (clock_mode)
7294     {
7295     case ResetTimers:
7296         /* Stop clocks and reset to a fresh time control */
7297         if (timerXID != 0)
7298         {
7299             XtRemoveTimeOut(timerXID);
7300             timerXID = 0;
7301         }
7302 
7303         blackTimeRemaining = timeControl;
7304         whiteTimeRemaining = timeControl;
7305 
7306         if (blackFlag || whiteFlag)
7307         {
7308             DisplayName("");
7309             blackFlag = whiteFlag = False;
7310         }
7311 
7312         DisplayLabels();
7313         break;
7314 
7315     case DecrementTimers:
7316         /* Decrement running clock to next 1-second boundary */
7317         if (gameMode == PauseGame)
7318             return;
7319 
7320         timerXID = 0;
7321 
7322         if (!localPlayer.appData.clockMode)
7323             return;
7324 
7325         if (BlackOnMove(forwardMostMove))
7326         {
7327             timeRemaining = (blackTimeRemaining -= tickLength);
7328         }
7329         else
7330         {
7331             timeRemaining = (whiteTimeRemaining -= tickLength);
7332         }
7333 
7334         DisplayLabels();
7335         CheckFlags();
7336 
7337 #ifdef HAVE_GETTIMEOFDAY
7338         tickLength = (((timeRemaining <= 1000) && (timeRemaining > 0))
7339                       ? 100 : 1000);
7340         gettimeofday(&tickStartTV, NULL);
7341 #endif /* HAVE_GETTIMEOFDAY */
7342 
7343         timerXID =
7344             XtAppAddTimeOut(appContext, tickLength,
7345                             (XtTimerCallbackProc) DisplayClocks,
7346                             (XtPointer) DecrementTimers);
7347         break;
7348 
7349     case SwitchTimers:
7350         /* A player has just moved, so stop the previously running
7351            clock and start the other one. */
7352 
7353         if (timerXID != 0)
7354         {
7355             XtRemoveTimeOut(timerXID);
7356             timerXID = 0;
7357 
7358 #ifdef HAVE_GETTIMEOFDAY
7359             if (localPlayer.appData.clockMode)
7360             {
7361                 if (BlackOnMove(forwardMostMove))
7362                     whiteTimeRemaining -= PartialTickLength();
7363                 else
7364                     blackTimeRemaining -= PartialTickLength();
7365                 CheckFlags();
7366             }
7367 #endif /* HAVE_GETTIMEOFDAY */
7368         }
7369 
7370         CheckTimeControl();
7371         DisplayLabels();
7372 
7373         if (!localPlayer.appData.clockMode)
7374             return;
7375 
7376         if ((gameMode == PauseGame)
7377             && ((pausePreviousMode == MachinePlaysBlack)
7378                 || (pausePreviousMode == MachinePlaysWhite)))
7379         {
7380             return;
7381         }
7382 
7383         timeRemaining = (BlackOnMove(forwardMostMove)
7384                          ? blackTimeRemaining : whiteTimeRemaining);
7385 
7386 #ifdef HAVE_GETTIMEOFDAY
7387         tickLength = (((timeRemaining <= 1000) && (timeRemaining > 0))
7388                       ? (((timeRemaining - 1) % 100) + 1)
7389                       : (((timeRemaining - 1) % 1000) + 1));
7390 
7391         if (tickLength <= 0)
7392             tickLength += 1000;
7393 
7394         gettimeofday(&tickStartTV, NULL);
7395 
7396 #endif /* HAVE_GETTIMEOFDAY */
7397         timerXID =
7398             XtAppAddTimeOut(appContext, tickLength,
7399                             (XtTimerCallbackProc) DisplayClocks,
7400                             (XtPointer) DecrementTimers);
7401         break;
7402 
7403     case ReDisplayTimers:
7404         /* Display current clock values */
7405         DisplayLabels();
7406         break;
7407 
7408     case StopTimers:
7409         /* Stop both clocks */
7410         if (timerXID == 0)
7411             return;
7412 
7413         XtRemoveTimeOut(timerXID);
7414         timerXID = 0;
7415 
7416         if (!localPlayer.appData.clockMode)
7417             return;
7418 
7419 #ifdef HAVE_GETTIMEOFDAY
7420         if (BlackOnMove(forwardMostMove))
7421             blackTimeRemaining -= PartialTickLength();
7422         else
7423             whiteTimeRemaining -= PartialTickLength();
7424         CheckFlags();
7425         DisplayLabels();
7426 #endif /* HAVE_GETTIMEOFDAY */
7427         break;
7428 
7429     case StartTimers:
7430         /* Start clock of player on move, if not already running. */
7431         if (timerXID != 0)
7432             return;
7433 
7434         DisplayLabels();
7435 
7436         if (!localPlayer.appData.clockMode)
7437             return;
7438 
7439         timeRemaining = (BlackOnMove(forwardMostMove)
7440                          ? blackTimeRemaining : whiteTimeRemaining);
7441 
7442         if (timeRemaining == 0)
7443             return;
7444 
7445 #ifdef HAVE_GETTIMEOFDAY
7446         tickLength = (((timeRemaining <= 1000) && (timeRemaining > 0))
7447                       ? (((timeRemaining - 1) % 100) + 1)
7448                       : (((timeRemaining - 1) % 1000) + 1));
7449 
7450         if (tickLength <= 0)
7451             tickLength += 1000;
7452 
7453         gettimeofday(&tickStartTV, NULL);
7454 #endif /* HAVE_GETTIMEOFDAY */
7455 
7456         timerXID =
7457             XtAppAddTimeOut(appContext, tickLength,
7458                             (XtTimerCallbackProc) DisplayClocks,
7459                             (XtPointer)DecrementTimers);
7460         break;
7461     }
7462 }
7463 
7464 
7465 
7466 
7467 void
DisplayTimerLabel(Widget w,char * color,long int timer)7468 DisplayTimerLabel(Widget w, char *color, long int timer)
7469 {
7470     char buf[MSG_SIZ];
7471     Arg args[3];
7472     struct DisplayData *player;
7473 
7474     player = (((w == localPlayer.blackTimerWidget)
7475                || (w == localPlayer.whiteTimerWidget))
7476               ? &localPlayer : &remotePlayer);
7477 
7478     if (localPlayer.appData.clockMode)
7479     {
7480         sprintf(buf, "%s: %s", color, TimeString(timer));
7481         XtSetArg(args[0], XtNlabel, buf);
7482     }
7483     else
7484     {
7485         XtSetArg(args[0], XtNlabel, color);
7486     }
7487 
7488     if (((color[0] == 'W') && BlackOnMove(forwardMostMove))
7489         || ((color[0] == 'B') && !BlackOnMove(forwardMostMove)))
7490     {
7491         XtSetArg(args[1], XtNbackground, player->timerForegroundPixel);
7492         XtSetArg(args[2], XtNforeground, player->timerBackgroundPixel);
7493     }
7494     else
7495     {
7496         XtSetArg(args[1], XtNbackground, player->timerBackgroundPixel);
7497         XtSetArg(args[2], XtNforeground, player->timerForegroundPixel);
7498     }
7499 
7500     XtSetValues(w, args, 3);
7501 }
7502 
7503 
7504 
7505 
7506 char *
TimeString(long tm)7507 TimeString(long tm)
7508 {
7509     int second, minute, hour, day;
7510     char *sign = "";
7511     static char buf[32];
7512 
7513     if ((tm > 0) && (tm <= 900))
7514     {
7515         /* convert milliseconds to tenths, rounding up */
7516         sprintf(buf, " 0.%1ld ", (tm + 99) / 100);
7517         return buf;
7518     }
7519 
7520     /* convert milliseconds to seconds, rounding up */
7521     tm = (tm + 999) / 1000;
7522 
7523     if (tm < 0)
7524     {
7525         sign = "-";
7526         tm = -tm;
7527     }
7528 
7529     if (tm >= (60 * 60 * 24))
7530     {
7531         day = (int)(tm / (60 * 60 * 24));
7532         tm -= day * 60 * 60 * 24;
7533     }
7534     else
7535     {
7536         day = 0;
7537     }
7538 
7539     if (tm >= (60 * 60))
7540     {
7541         hour = (int)(tm / (60 * 60));
7542         tm -= hour * 60 * 60;
7543     }
7544     else
7545     {
7546         hour = 0;
7547     }
7548 
7549     if (tm >= 60)
7550     {
7551         minute = (int)(tm / 60);
7552         tm -= minute * 60;
7553     }
7554     else
7555     {
7556         minute = 0;
7557     }
7558 
7559     second = tm % 60;
7560 
7561     if (day > 0)
7562     {
7563         sprintf(buf, " %s%d:%02d:%02d:%02d ",
7564                 sign, day, hour, minute, second);
7565     }
7566     else if (hour > 0)
7567     {
7568         sprintf(buf, " %s%d:%02d:%02d ",
7569                 sign, hour, minute, second);
7570     }
7571     else
7572     {
7573         sprintf(buf, " %s%2d:%02d ",
7574                 sign, minute, second);
7575     }
7576 
7577     return buf;
7578 }
7579 
7580 
7581 
7582 
7583 void
Usage(void)7584 Usage(void)
7585 {
7586     fprintf(stderr, "Usage: %s\n", programName);
7587     fprintf(stderr, "\tstandard Xt options\n");
7588     fprintf(stderr, "\t-iconic\n");
7589     fprintf(stderr, "\t-tc or -timeControl minutes[:seconds]\n");
7590     fprintf(stderr, "\t-gi or -gameIn (True | False)\n");
7591     fprintf(stderr, "\t-mps or -movesPerSession moves\n");
7592     fprintf(stderr, "\t-st or -searchTime minutes[:seconds]\n");
7593     fprintf(stderr, "\t-sd or -searchDepth number\n");
7594     fprintf(stderr, "\t-clock or -clockMode (True | False)\n");
7595     fprintf(stderr, "\t-td or -timeDelay seconds\n");
7596 
7597     fprintf(stderr, "\t-nsp or -noShogiProgram (True | False)\n");
7598     fprintf(stderr, "\t-fsp or -firstShogiProgram program_name\n");
7599     fprintf(stderr, "\t-ssp or -secondShogiProgram program_name\n");
7600     fprintf(stderr, "\t-fh or -firstHost host_name\n");
7601     fprintf(stderr, "\t-sh or -secondHost host_name\n");
7602     fprintf(stderr, "\t-rsh or -remoteShell shell_name\n");
7603     fprintf(stderr,
7604             "\t-mm or -matchMode (False | Init | Position | Opening)\n");
7605     fprintf(stderr, "\t-lgf or -loadGameFile file_name\n");
7606     fprintf(stderr, "\t-lpf or -loadPositionFile file_name\n");
7607     fprintf(stderr, "\t-sgf or -saveGameFile file_name\n");
7608     fprintf(stderr, "\t-spf or -savePositionFile file_name\n");
7609     fprintf(stderr, "\t-size or -boardSize (Large | Medium | Small)\n");
7610     fprintf(stderr, "\t-coords or -showCoords (True | False)\n");
7611     fprintf(stderr, "\t-mono or -monoMode (True | False)\n");
7612     fprintf(stderr, "\t-pc or -pieceColor color\n");
7613     fprintf(stderr, "\t-sc  or -squareColor color\n");
7614     fprintf(stderr, "\t-wps or -westernPieceSet (True | False)\n");
7615     fprintf(stderr, "\t-debug or -debugMode (True | False)\n");
7616     exit(2);
7617 }
7618 
7619 
7620 
7621 void
CatchPipeSignal(int dummy)7622 CatchPipeSignal(int dummy)
7623 {
7624     char message[MSG_SIZ];
7625 
7626     sprintf(message,
7627             "%s shogi program (%s) exited unexpectedly",
7628             ((lastMsgFP == toFirstProgFP) ? "first" : "second"),
7629             ((lastMsgFP == toFirstProgFP)
7630              ? localPlayer.appData.firstShogiProgram
7631              : localPlayer.appData.secondShogiProgram));
7632     fprintf(stderr, "%s: %s\n", programName, message);
7633     ShutdownShogiPrograms(message);
7634     return;
7635 }
7636 
7637