1 
2 /*-
3 # MOTIF-BASED DINOSAUR CUBE
4 #
5 #  xmdino.c
6 #
7 ###
8 #
9 #  Copyright (c) 1995 - 99	David Albert Bagley, bagleyd@tux.org
10 #
11 #                   All Rights Reserved
12 #
13 #  Permission to use, copy, modify, and distribute this software and
14 #  its documentation for any purpose and without fee is hereby granted,
15 #  provided that the above copyright notice appear in all copies and
16 #  that both that copyright notice and this permission notice appear in
17 #  supporting documentation, and that the name of the author not be
18 #  used in advertising or publicity pertaining to distribution of the
19 #  software without specific, written prior permission.
20 #
21 #  This program is distributed in the hope that it will be "playable",
22 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
23 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24 #
25 */
26 
27 /*-
28   Version 5: 95/10/06 Xt/Motif
29   Version 4: 94/05/30 Xt
30 */
31 
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <errno.h>
35 #ifdef VMS
36 #include <unixlib.h>
37 #define getlogin() cuserid(NULL)
38 #else
39 #if HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42 #endif
43 #if HAVE_FCNTL_H
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #endif
48 #include <X11/Intrinsic.h>
49 #include <X11/StringDefs.h>
50 #include <X11/Shell.h>
51 #include <X11/cursorfont.h>
52 #include <Xm/PanedW.h>
53 #include <Xm/RowColumn.h>
54 #include <Xm/Label.h>
55 #include <Xm/LabelG.h>
56 #include <Xm/Scale.h>
57 #include <Xm/ToggleB.h>
58 #include <Xm/ToggleBG.h>
59 #include "Dino.h"
60 #include "Dino2d.h"
61 #include "Dino3d.h"
62 #include "dino.xbm"
63 #include "mouse-l.xbm"
64 #include "mouse-r.xbm"
65 
66 #ifndef SCOREFILE
67 #define SCOREFILE "/usr/games/lib/dino.scores"
68 #endif
69 
70 /* The following are in DinoP.h also */
71 #define PERIOD2 2
72 #define PERIOD3 3
73 #define BOTH 4
74 #define MAXMODES 3
75 #define MAXFACES 6
76 
77 #define MAXRECORD 32767
78 #define FILENAMELEN 1024
79 #define USERNAMELEN 128
80 #define NOACCESS "noaccess"
81 #define NOBODY "nobody"
82 
83 typedef struct {
84 	int         score;
85 	char        name[USERNAMELEN];
86 } GameRecord;
87 
88 static void Initialize(void);
89 static void CallbackDino(Widget w, caddr_t clientData, dinoCallbackStruct * callData);
90 
91 static void PrintRecord(int mode, Boolean orient, Boolean practice);
92 static Boolean HandleSolved(int counter, int mode, Boolean orient);
93 static void InitRecords(void);
94 static void ReadRecords(void);
95 static void WriteRecords(void);
96 
97 static void ModeToggle(Widget w, int mode, XmToggleButtonCallbackStruct * cbs);
98 static void OrientToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct * cbs);
99 static void PracticeToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct * cbs);
100 static void motif_print(Widget w, char *text);
101 
102 static Arg  arg[5];
103 static Widget moves, record, message, dino2d, dino3d, modes[MAXMODES], orientSwitch,
104             practiceSwitch;
105 static GameRecord dinoRecord[MAXMODES][2];
106 static int  movesDsp = 0;
107 static char messageDsp[128] = "Welcome";
108 static char usernameDsp[USERNAMELEN] = "";
109 static char buff[256];
110 
111 static char *modeString[] =
112 {
113 	"Period 2", "Period 3", "Both"
114 };
115 
116 static void
Usage(void)117 Usage(void)
118 {
119 	(void) fprintf(stderr, "usage: xmdino\n");
120 	(void) fprintf(stderr,
121 	     "\t[-geometry [{width}][x{height}][{+-}{xoff}[{+-}{yoff}]]]\n");
122 	(void) fprintf(stderr,
123 	   "\t[-display [{host}]:[{vs}]] [-[no]mono] [-[no]{reverse|rv}]\n");
124 	(void) fprintf(stderr,
125 		"\t[-{foreground|fg} {color}] [-{background|bg} {color}]\n");
126 	(void) fprintf(stderr,
127 		  "\t[-{border|bd} {color}] [-face{0|1|2|3|4|5} {color}]\n");
128 	(void) fprintf(stderr,
129 		 "\t[-{mode {int} | both}] [-[no]orient] [-[no]practice]\n");
130 	(void) fprintf(stderr,
131 		       "\t[-username {string}]\n");
132 	exit(1);
133 }
134 
135 static XrmOptionDescRec options[] =
136 {
137 	{"-mono", "*dino.mono", XrmoptionNoArg, "TRUE"},
138 	{"-nomono", "*dino.mono", XrmoptionNoArg, "FALSE"},
139 	{"-rv", "*dino.reverse", XrmoptionNoArg, "TRUE"},
140 	{"-reverse", "*dino.reverse", XrmoptionNoArg, "TRUE"},
141 	{"-norv", "*dino.reverse", XrmoptionNoArg, "FALSE"},
142 	{"-noreverse", "*dino.reverse", XrmoptionNoArg, "FALSE"},
143 	{"-fg", "*dino.Foreground", XrmoptionSepArg, NULL},
144 	{"-foreground", "*dino.Foreground", XrmoptionSepArg, NULL},
145 	{"-bg", "*Background", XrmoptionSepArg, NULL},
146 	{"-background", "*Background", XrmoptionSepArg, NULL},
147 	{"-bd", "*dino.pieceBorder", XrmoptionSepArg, NULL},
148 	{"-border", "*dino.pieceBorder", XrmoptionSepArg, NULL},
149 	{"-face0", "*dino.faceColor0", XrmoptionSepArg, NULL},
150 	{"-face1", "*dino.faceColor1", XrmoptionSepArg, NULL},
151 	{"-face2", "*dino.faceColor2", XrmoptionSepArg, NULL},
152 	{"-face3", "*dino.faceColor3", XrmoptionSepArg, NULL},
153 	{"-face4", "*dino.faceColor4", XrmoptionSepArg, NULL},
154 	{"-face5", "*dino.faceColor5", XrmoptionSepArg, NULL},
155 	{"-mode", "*dino.mode", XrmoptionSepArg, NULL},
156 	{"-both", "*dino.mode", XrmoptionNoArg, "4"},
157 	{"-orient", "*dino.orient", XrmoptionNoArg, "TRUE"},
158 	{"-noorient", "*dino.orient", XrmoptionNoArg, "FALSE"},
159 	{"-practice", "*dino.practice", XrmoptionNoArg, "TRUE"},
160 	{"-nopractice", "*dino.practice", XrmoptionNoArg, "FALSE"},
161 	{"-username", "*dino.userName", XrmoptionSepArg, NULL}
162 };
163 
164 int
main(int argc,char ** argv)165 main(int argc, char **argv)
166 {
167 	Widget      toplevel;
168 	Widget      panel, panel2, rowcol, rowcol2, rowcol3, rowcol4;
169 	Pixmap      mouseLeftCursor, mouseRightCursor;
170 	Pixel       fg, bg;
171 	int         i;
172 
173 	toplevel = XtInitialize(argv[0], "Dino",
174 				options, XtNumber(options), &argc, argv);
175 	if (argc != 1)
176 		Usage();
177 
178 	XtSetArg(arg[0],
179 		 XtNiconPixmap, XCreateBitmapFromData(XtDisplay(toplevel),
180 				      RootWindowOfScreen(XtScreen(toplevel)),
181 			       (char *) dino_bits, dino_width, dino_height));
182 	XtSetArg(arg[1], XmNkeyboardFocusPolicy, XmPOINTER);	/* not XmEXPLICIT */
183 	XtSetValues(toplevel, arg, 2);
184 	panel = XtCreateManagedWidget("panel",
185 				xmPanedWindowWidgetClass, toplevel, NULL, 0);
186 	panel2 = XtVaCreateManagedWidget("panel2", xmPanedWindowWidgetClass, panel,
187 					 XmNseparatorOn, False,
188 					 XmNsashWidth, 1,
189 					 XmNsashHeight, 1, NULL);
190 
191 	rowcol = XtVaCreateManagedWidget("Rowcol", xmRowColumnWidgetClass, panel2,
192 					 XmNnumColumns, 2,
193 					 XmNorientation, XmHORIZONTAL,
194 					 XmNpacking, XmPACK_COLUMN, NULL);
195 	XtVaGetValues(rowcol,
196 		      XmNforeground, &fg,
197 		      XmNbackground, &bg, NULL);
198 	mouseLeftCursor = XCreatePixmapFromBitmapData(XtDisplay(rowcol),
199 	      RootWindowOfScreen(XtScreen(rowcol)), (char *) mouse_left_bits,
200 				 mouse_left_width, mouse_left_height, fg, bg,
201 				     DefaultDepthOfScreen(XtScreen(rowcol)));
202 	mouseRightCursor = XCreatePixmapFromBitmapData(XtDisplay(rowcol),
203 	     RootWindowOfScreen(XtScreen(rowcol)), (char *) mouse_right_bits,
204 			       mouse_right_width, mouse_right_height, fg, bg,
205 				     DefaultDepthOfScreen(XtScreen(rowcol)));
206 	XtVaCreateManagedWidget("mouseLeftText",
207 				xmLabelGadgetClass, rowcol,
208 		   XtVaTypedArg, XmNlabelString, XmRString, "Move", 5, NULL);
209 	XtVaCreateManagedWidget("mouseLeft",
210 				xmLabelGadgetClass, rowcol,
211 	      XmNlabelType, XmPIXMAP, XmNlabelPixmap, mouseLeftCursor, NULL);
212 	XtVaCreateManagedWidget("mouseRightText",
213 				xmLabelGadgetClass, rowcol,
214 	     XtVaTypedArg, XmNlabelString, XmRString, "Randomize", 10, NULL);
215 	XtVaCreateManagedWidget("mouseRight",
216 				xmLabelGadgetClass, rowcol,
217 	     XmNlabelType, XmPIXMAP, XmNlabelPixmap, mouseRightCursor, NULL);
218 	XtVaCreateManagedWidget("movesText",
219 				xmLabelGadgetClass, rowcol,
220 		  XtVaTypedArg, XmNlabelString, XmRString, "Moves", 6, NULL);
221 	moves = XtVaCreateManagedWidget("0",
222 					xmLabelWidgetClass, rowcol, NULL);
223 	XtVaCreateManagedWidget("recordText",
224 				xmLabelGadgetClass, rowcol,
225 		 XtVaTypedArg, XmNlabelString, XmRString, "Record", 7, NULL);
226 	record = XtVaCreateManagedWidget("0",
227 					 xmLabelWidgetClass, rowcol, NULL);
228 
229 	rowcol2 = XtVaCreateManagedWidget("Rowcol2",
230 					  xmRowColumnWidgetClass, panel2,
231 					  XmNnumColumns, 1,
232 					  XmNorientation, XmHORIZONTAL,
233 					  XmNpacking, XmPACK_COLUMN,
234 					  XmNradioBehavior, True, NULL);
235 	for (i = 0; i < XtNumber(modeString); i++) {
236 		modes[i] = XtVaCreateManagedWidget(modeString[i],
237 					  xmToggleButtonGadgetClass, rowcol2,
238 					       XmNradioBehavior, True, NULL);
239 		XtAddCallback(modes[i],
240 			      XmNvalueChangedCallback, (XtCallbackProc) ModeToggle, (XtPointer) i);
241 	}
242 
243 	rowcol3 = XtVaCreateManagedWidget("Rowcol3",
244 					  xmRowColumnWidgetClass, panel2,
245 					  XmNnumColumns, 1,
246 					  XmNorientation, XmHORIZONTAL,
247 					  XmNpacking, XmPACK_COLUMN, NULL);
248 	orientSwitch = XtVaCreateManagedWidget("Orient",
249 				   xmToggleButtonWidgetClass, rowcol3, NULL);
250 	XtAddCallback(orientSwitch,
251 		      XmNvalueChangedCallback, (XtCallbackProc) OrientToggle, (XtPointer) NULL);
252 	practiceSwitch = XtVaCreateManagedWidget("Practice",
253 				   xmToggleButtonWidgetClass, rowcol3, NULL);
254 	XtAddCallback(practiceSwitch,
255 		      XmNvalueChangedCallback, (XtCallbackProc) PracticeToggle, (XtPointer) NULL);
256 
257 	rowcol4 = XtVaCreateManagedWidget("Rowcol4",
258 					  xmRowColumnWidgetClass, panel2,
259 					  XmNnumColumns, 1,
260 					  XmNorientation, XmHORIZONTAL,
261 					  XmNpacking, XmPACK_COLUMN, NULL);
262 	message = XtVaCreateManagedWidget("Play Dino! (use mouse and keypad)",
263 					  xmLabelWidgetClass, rowcol4, NULL);
264 
265 	dino2d = XtCreateManagedWidget("dino",
266 				       dino2dWidgetClass, panel, NULL, 0);
267 	XtVaSetValues(dino2d,
268 		      XtNheight, 200, NULL);
269 	XtAddCallback(dino2d,
270 	 XtNselectCallback, (XtCallbackProc) CallbackDino, (XtPointer) NULL);
271 	dino3d = XtCreateManagedWidget("dino",
272 				       dino3dWidgetClass, panel, NULL, 0);
273 	XtVaSetValues(dino3d,
274 		      XtNheight, 200, NULL);
275 	XtAddCallback(dino3d,
276 	 XtNselectCallback, (XtCallbackProc) CallbackDino, (XtPointer) NULL);
277 	Initialize();
278 	XtRealizeWidget(toplevel);
279 	XGrabButton(XtDisplay(dino2d), (unsigned int) AnyButton, AnyModifier,
280 		    XtWindow(dino2d), TRUE,
281 		    (unsigned int) (ButtonPressMask | ButtonMotionMask | ButtonReleaseMask),
282 		    GrabModeAsync, GrabModeAsync, XtWindow(dino2d),
283 		    XCreateFontCursor(XtDisplay(dino2d), XC_crosshair));
284 	XGrabButton(XtDisplay(dino3d), (unsigned int) AnyButton, AnyModifier,
285 		    XtWindow(dino3d), TRUE,
286 		    (unsigned int) (ButtonPressMask | ButtonMotionMask | ButtonReleaseMask),
287 		    GrabModeAsync, GrabModeAsync, XtWindow(dino3d),
288 		    XCreateFontCursor(XtDisplay(dino3d), XC_crosshair));
289 	XtMainLoop();
290 
291 #ifdef VMS
292 	return 1;
293 #else
294 	return 0;
295 #endif
296 }
297 
298 /* There's probably a better way to assure that they are the same but I don't
299    know it off hand. */
300 static void
MakeEquivalent(String * username,int * mode,Boolean * orient,Boolean * practice)301 MakeEquivalent(String * username, int *mode, Boolean * orient, Boolean * practice)
302 {
303 	Boolean     mono, reverse;
304 	Pixel       foreground, background, pieceBorder;
305 	String      faceColor[MAXFACES];
306 
307 	XtVaGetValues(dino2d,
308 		      XtNuserName, username,
309 		      XtNmode, mode,
310 		      XtNorient, orient,
311 		      XtNpractice, practice,
312 		      XtNmono, &mono,
313 		      XtNreverse, &reverse,
314 		      XtNforeground, &foreground,
315 		      XtNbackground, &background,
316 		      XtNpieceBorder, &pieceBorder,
317 		      XtNfaceColor0, &(faceColor[0]),
318 		      XtNfaceColor1, &(faceColor[1]),
319 		      XtNfaceColor2, &(faceColor[2]),
320 		      XtNfaceColor3, &(faceColor[3]),
321 		      XtNfaceColor4, &(faceColor[4]),
322 		      XtNfaceColor5, &(faceColor[5]), NULL);
323 	XtVaSetValues(dino2d,
324 		      XtNdirection, DINO_IGNORE,
325 		      XtNstart, False, NULL);
326 	XtVaSetValues(dino3d,
327 		      XtNuserName, *username,
328 		      XtNmode, *mode,
329 		      XtNorient, *orient,
330 		      XtNpractice, *practice,
331 		      XtNmono, mono,
332 		      XtNreverse, reverse,
333 		      XtNdirection, DINO_IGNORE,
334 		      XtNstart, False,
335 		      XtNforeground, foreground,
336 		      XtNbackground, background,
337 		      XtNpieceBorder, pieceBorder,
338 		      XtNfaceColor0, faceColor[0],
339 		      XtNfaceColor1, faceColor[1],
340 		      XtNfaceColor2, faceColor[2],
341 		      XtNfaceColor3, faceColor[3],
342 		      XtNfaceColor4, faceColor[4],
343 		      XtNfaceColor5, faceColor[5], NULL);
344 }
345 
346 static void
Initialize(void)347 Initialize(void)
348 {
349 	int         mode;
350 	Boolean     orient, practice;
351 	String      username;
352 
353 	MakeEquivalent(&username, &mode, &orient, &practice);
354 	XmToggleButtonSetState(modes[mode - PERIOD2], True, False);
355 	XmToggleButtonSetState(orientSwitch, orient, True);
356 	XmToggleButtonSetState(practiceSwitch, practice, True);
357 	InitRecords();
358 	ReadRecords();
359 	(void) strcpy(usernameDsp, username);
360 	if (!strcmp(usernameDsp, "") || !strcmp(usernameDsp, NOACCESS) ||
361 	    !strcmp(usernameDsp, NOBODY)) {
362 		/* The NOACCESS is not necasary, but it stops people from being cute. */
363 		(void) sprintf(usernameDsp, "%s", getlogin());
364 		if (!strcmp(usernameDsp, "") || !strcmp(usernameDsp, NOACCESS))
365 			(void) sprintf(usernameDsp, "%s", NOBODY);	/* It really IS nobody */
366 	}
367 	PrintRecord(mode, orient, practice);
368 }
369 
370 static void
CallbackDino(Widget w,caddr_t clientData,dinoCallbackStruct * callData)371 CallbackDino(Widget w, caddr_t clientData, dinoCallbackStruct * callData)
372 {
373 	int         mode;
374 	Boolean     orient, practice, start;
375 	Widget      otherw;
376 
377 	if (w == dino2d)
378 		otherw = dino3d;
379 	else			/* (w == dino3d) */
380 		otherw = dino2d;
381 	XtVaGetValues(w,
382 		      XtNorient, &orient,
383 		      XtNmode, &mode,
384 		      XtNpractice, &practice,
385 		      XtNstart, &start, NULL);
386 	(void) strcpy(messageDsp, "");
387 	switch (callData->reason) {
388 		case DINO_RESTORE:
389 			XtSetArg(arg[0], XtNdirection, DINO_RESTORE);
390 			XtSetValues(otherw, arg, 1);
391 			XtSetValues(w, arg, 1);
392 			movesDsp = 0;
393 			break;
394 		case DINO_RESET:
395 			movesDsp = 0;
396 			break;
397 		case DINO_ILLEGAL:
398 			if (practice || start)
399 				(void) strcpy(messageDsp, "Illegal move");
400 			else
401 				(void) strcpy(messageDsp, "Randomize to start");
402 			break;
403 		case DINO_MOVED:
404 			movesDsp++;
405 			XtSetArg(arg[0], XtNstart, True);
406 			XtSetArg(arg[1], XtNface, callData->face);
407 			XtSetArg(arg[2], XtNpos, callData->position);
408 			XtSetArg(arg[3], XtNdirection, callData->direction);
409 			XtSetArg(arg[4], XtNstyle, callData->style);
410 			XtSetValues(otherw, arg, 5);
411 			XtSetValues(w, arg, 1);
412 			break;
413 		case DINO_CONTROL:
414 			XtSetArg(arg[0], XtNface, callData->face);
415 			XtSetArg(arg[1], XtNpos, callData->position);
416 			XtSetArg(arg[2], XtNdirection, callData->direction);
417 			XtSetArg(arg[3], XtNstyle, callData->style);
418 			XtSetValues(otherw, arg, 4);
419 			return;
420 		case DINO_SOLVED:
421 			if (practice)
422 				movesDsp = 0;
423 			else {
424 				if (HandleSolved(movesDsp, mode, orient))
425 					(void) sprintf(messageDsp, "Congratulations %s!!", usernameDsp);
426 				else
427 					(void) strcpy(messageDsp, "Solved!");
428 			}
429 			XtSetArg(arg[0], XtNstart, False);
430 			XtSetValues(w, arg, 1);
431 			XtSetValues(otherw, arg, 1);
432 			break;
433 		case DINO_PRACTICE:
434 			movesDsp = 0;
435 			practice = !practice;
436 			if (!practice)
437 				(void) strcpy(messageDsp, "Randomize to start");
438 			PrintRecord(mode, orient, practice);
439 			XtSetArg(arg[0], XtNpractice, practice);
440 			XtSetArg(arg[1], XtNstart, False);
441 			XtSetValues(w, arg, 2);
442 			XtSetValues(otherw, arg, 2);
443 			XmToggleButtonSetState(practiceSwitch, practice, True);
444 			break;
445 		case DINO_RANDOMIZE:
446 			movesDsp = 0;
447 			XtSetArg(arg[0], XtNpractice, False);
448 			XtSetArg(arg[1], XtNstart, False);
449 			XtSetValues(w, arg, 2);
450 			XtSetValues(otherw, arg, 2);
451 			break;
452 		case DINO_ORIENT:
453 			movesDsp = 0;
454 			orient = !orient;
455 			PrintRecord(mode, orient, practice);
456 			XtSetArg(arg[0], XtNorient, orient);
457 			XtSetValues(w, arg, 1);
458 			XtSetValues(otherw, arg, 1);
459 			XmToggleButtonSetState(orientSwitch, orient, True);
460 			break;
461 		case DINO_PERIOD2:
462 		case DINO_PERIOD3:
463 		case DINO_BOTH:
464 			movesDsp = 0;
465 			mode = callData->reason - DINO_PERIOD2 + PERIOD2;
466 			PrintRecord(mode, orient, practice);
467 			XtSetArg(arg[0], XtNmode, mode);
468 			XtSetValues(w, arg, 1);
469 			XtSetValues(otherw, arg, 1);
470 			XmToggleButtonSetState(modes[mode - PERIOD2], True, True);
471 			break;
472 		case DINO_COMPUTED:
473 			XtSetArg(arg[0], XtNstart, False);
474 			XtSetValues(w, arg, 1);
475 			XtSetValues(otherw, arg, 1);
476 			break;
477 		case DINO_UNDO:
478 			movesDsp--;
479 			XtSetArg(arg[0], XtNstart, True);
480 			XtSetArg(arg[1], XtNface, callData->face);
481 			XtSetArg(arg[2], XtNpos, callData->position);
482 			XtSetArg(arg[3], XtNdirection, callData->direction);
483 			XtSetArg(arg[4], XtNstyle, callData->style);
484 			XtSetValues(otherw, arg, 5);
485 			XtSetValues(w, arg, 1);
486 			break;
487 	}
488 	motif_print(message, messageDsp);
489 	(void) sprintf(buff, "%d", movesDsp);
490 	motif_print(moves, buff);
491 }
492 
493 static void
ModeToggle(Widget w,int mode,XmToggleButtonCallbackStruct * cbs)494 ModeToggle(Widget w, int mode, XmToggleButtonCallbackStruct * cbs)
495 {
496 	Boolean     orient, practice;
497 
498 	if (cbs->set) {
499 		XtVaGetValues(dino2d,
500 			      XtNorient, &orient,
501 			      XtNpractice, &practice, NULL);
502 		XtVaSetValues(dino2d,
503 			      XtNmode, mode + PERIOD2, NULL);
504 		XtVaSetValues(dino3d,
505 			      XtNmode, mode + PERIOD2, NULL);
506 		movesDsp = 0;
507 		(void) sprintf(buff, "%d", movesDsp);
508 		motif_print(moves, buff);
509 		PrintRecord(mode + PERIOD2, orient, practice);
510 	}
511 }
512 
513 static void
OrientToggle(Widget w,XtPointer clientData,XmToggleButtonCallbackStruct * cbs)514 OrientToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct * cbs)
515 {
516 	int         mode;
517 	Boolean     orient = cbs->set, practice;
518 
519 	XtVaGetValues(dino2d,
520 		      XtNmode, &mode,
521 		      XtNpractice, &practice, NULL);
522 	XtVaSetValues(dino2d,
523 		      XtNorient, orient, NULL);
524 	XtVaSetValues(dino3d,
525 		      XtNorient, orient, NULL);
526 	movesDsp = 0;
527 	(void) sprintf(buff, "%d", movesDsp);
528 	motif_print(moves, buff);
529 	PrintRecord(mode, orient, practice);
530 }
531 
532 static void
PracticeToggle(Widget w,XtPointer clientData,XmToggleButtonCallbackStruct * cbs)533 PracticeToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct * cbs)
534 {
535 	int         mode;
536 	Boolean     orient, practice = cbs->set;
537 
538 	XtVaSetValues(dino2d,
539 		      XtNpractice, practice,
540 		      XtNstart, False, NULL);
541 	XtVaSetValues(dino3d,
542 		      XtNpractice, practice,
543 		      XtNstart, False, NULL);
544 	XtVaGetValues(dino2d,
545 		      XtNmode, &mode,
546 		      XtNpractice, &orient, NULL);
547 	movesDsp = 0;
548 	(void) sprintf(buff, "%d", movesDsp);
549 	motif_print(moves, buff);
550 	if (!practice)
551 		(void) strcpy(messageDsp, "Randomize to start");
552 	PrintRecord(mode, orient, practice);
553 }
554 
555 static void
PrintRecord(int mode,Boolean orient,Boolean practice)556 PrintRecord(int mode, Boolean orient, Boolean practice)
557 {
558 	int         i = mode - PERIOD2;
559 	int         j = (orient) ? 1 : 0;
560 
561 	if (practice)
562 		motif_print(record, "practice");
563 	else if (dinoRecord[i][j].score >= MAXRECORD) {
564 		(void) sprintf(buff, "NEVER %s", NOACCESS);
565 		motif_print(record, buff);
566 	} else {
567 		(void) sprintf(buff, "%d %s",
568 			       dinoRecord[i][j].score, dinoRecord[i][j].name);
569 		motif_print(record, buff);
570 	}
571 }
572 
573 static      Boolean
HandleSolved(int counter,int mode,Boolean orient)574 HandleSolved(int counter, int mode, Boolean orient)
575 {
576 	int         i = mode - PERIOD2;
577 	int         j = (orient) ? 1 : 0;
578 
579 	if (counter < dinoRecord[i][j].score) {
580 		dinoRecord[i][j].score = counter;
581 		(void) strcpy(dinoRecord[i][j].name, usernameDsp);
582 		if (orient && (counter < dinoRecord[!i][j].score)) {
583 			dinoRecord[!i][j].score = counter;
584 			(void) strcpy(dinoRecord[!i][j].name, usernameDsp);
585 		}
586 		WriteRecords();
587 		PrintRecord(mode, orient, False);
588 		return True;
589 	}
590 	return False;
591 }
592 
593 static void
InitRecords(void)594 InitRecords(void)
595 {
596 	int         mode, orient;
597 
598 	for (mode = 0; mode < MAXMODES; mode++)
599 		for (orient = 0; orient < 2; orient++) {
600 			dinoRecord[mode][orient].score = MAXRECORD;
601 			(void) strcpy(dinoRecord[mode][orient].name, NOACCESS);
602 		}
603 }
604 
605 static void
ReadRecords(void)606 ReadRecords(void)
607 {
608 	FILE       *fp;
609 	int         n, mode, orient;
610 	char        username[USERNAMELEN];
611 
612 	if ((fp = fopen(SCOREFILE, "r")) == NULL) {
613 		(void) sprintf(buff, "Can not open %s, taking defaults.", SCOREFILE);
614 		motif_print(message, buff);
615 	} else {
616 		for (mode = 0; mode < MAXMODES; mode++)
617 			for (orient = 0; orient < 2; orient++) {
618 				(void) fscanf(fp, "%d %s\n", &n, username);
619 				if (n <= dinoRecord[mode][orient].score) {
620 					dinoRecord[mode][orient].score = n;
621 					(void) strcpy(dinoRecord[mode][orient].name, username);
622 				}
623 			}
624 		(void) fclose(fp);
625 	}
626 }
627 
628 static void
WriteRecords(void)629 WriteRecords(void)
630 {
631 	FILE       *fp;
632 	int         mode, orient;
633 
634 	if ((fp = fopen(SCOREFILE, "w")) == NULL) {
635 		(void) sprintf(buff, "Can not write to %s.", SCOREFILE);
636 		motif_print(message, buff);
637 	} else {
638 #if HAVE_FCNTL_H
639 		int         lfd;
640 		char        lockfile[FILENAMELEN];
641 
642 		(void) strcpy(lockfile, SCOREFILE);
643 		(void) strcat(lockfile, ".lock");
644 		while (((lfd = open(lockfile, O_CREAT | O_EXCL, 0644)) < 0) &&
645 		       errno == EEXIST)
646 			(void) sleep(1);
647 		if (lfd < 0) {
648 #if 1
649 			(void) fprintf(stderr, "Lock file exists... guessing its an old one.\n");
650 #else
651 			(void) fprintf(stderr, "Lock file exists... score not recorded - sorry.\n"
652 				);
653 			return;
654 #endif
655 		}
656 #endif
657 		for (mode = 0; mode < MAXMODES; mode++) {
658 			for (orient = 0; orient < 2; orient++)
659 				(void) fprintf(fp, "%d %s\n",
660 					       dinoRecord[mode][orient].score, dinoRecord[mode][orient].name);
661 			(void) fprintf(fp, "\n");
662 		}
663 #if HAVE_FCNTL_H
664 		(void) close(lfd);
665 		(void) unlink(lockfile);
666 #endif
667 		(void) fclose(fp);
668 	}
669 }
670 
671 static void
motif_print(Widget w,char * text)672 motif_print(Widget w, char *text)
673 {
674 	Arg         wargs[1];
675 	XmString    xmstr;
676 
677 	if (!XtIsSubclass(w, xmLabelWidgetClass))
678 		XtError("motif_print() requires a Label Widget");
679 	xmstr = XmStringCreateLtoR(text, XmSTRING_DEFAULT_CHARSET);
680 	XtSetArg(wargs[0], XmNlabelString, xmstr);
681 	XtSetValues(w, wargs, 1);
682 }
683