1 
2 /*-
3 # MOTIF-BASED MISSING LINK(tm)
4 #
5 #  xmmlink.c
6 #
7 ###
8 #
9 #  Copyright (c) 1994 - 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/01 Xt/Motif
29   Version 1: 94/08/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 "Mlink.h"
59 #include "mlink.xbm"
60 #include "mouse-l.xbm"
61 #include "mouse-r.xbm"
62 
63 #ifndef SCOREFILE
64 #define SCOREFILE "/usr/games/lib/mlink.scores"
65 #endif
66 
67 /* The following are in MlinkP.h also */
68 #define MINFACES 1
69 #define MAXFACES 8
70 #define MINTILES 1
71 
72 #define MAXTILES 8
73 #define MAXRECORD 32767
74 #define FILENAMELEN 1024
75 #define USERNAMELEN 128
76 #define NOACCESS "noaccess"
77 #define NOBODY "nobody"
78 
79 typedef struct {
80 	int         score;
81 	char        name[USERNAMELEN];
82 } GameRecord;
83 
84 static void Initialize(Widget w);
85 static void CallbackMlink(Widget w, caddr_t clientData,
86 			  mlinkCallbackStruct * callData);
87 
88 static void PrintRecord(int tiles, int faces, Boolean orient, Boolean middle);
89 static Boolean HandleSolved(int counter, int tiles, int faces, Boolean orient,
90 			    Boolean middle);
91 static void InitRecords(void);
92 static void ReadRecords(void);
93 static void WriteRecords(void);
94 
95 static void motif_print(Widget w, char *text);
96 static void TileSlider(Widget w, XtPointer clientData,
97 		       XmScaleCallbackStruct * cbs);
98 static void FaceSlider(Widget w, XtPointer clientData,
99 		       XmScaleCallbackStruct * cbs);
100 static void OrientToggle(Widget w, XtPointer clientData,
101 			 XmToggleButtonCallbackStruct * cbs);
102 static void MiddleToggle(Widget w, XtPointer clientData,
103 			 XmToggleButtonCallbackStruct * cbs);
104 
105 static Arg  arg[2];
106 static Widget moves, record, message, mlink, orientSwitch, middleSwitch,
107             tile, face;
108 static GameRecord mlinkRecord[2][2][MAXFACES - MINFACES + 1]
109 [MAXTILES - MINTILES + 1];
110 static int  movesDsp = 0;
111 static char messageDsp[128] = "Welcome";
112 static char usernameDsp[USERNAMELEN] = "";
113 static char buff[256];
114 
115 static void
Usage(void)116 Usage(void)
117 {
118 	(void) fprintf(stderr, "usage: xmmlink\n");
119 	(void) fprintf(stderr,
120 	     "\t[-geometry [{width}][x{height}][{+-}{xoff}[{+-}{yoff}]]]\n");
121 	(void) fprintf(stderr,
122 	   "\t[-display [{host}]:[{vs}]] [-[no]mono] [-[no]{reverse|rv}]\n");
123 	(void) fprintf(stderr,
124 		"\t[-{foreground|fg} {color}] [-{background|bg} {color}]\n");
125 	(void) fprintf(stderr,
126 		       "\t[-{border|bd} {color}] [-tile {color}]\n");
127 	(void) fprintf(stderr,
128 		       "\t[-face{0|1|2|3|4|5|6|7} {color}]\n");
129 	(void) fprintf(stderr,
130 	    "\t[-tiles {int}] [-faces {int}] [-[no]orient] [-[no]middle]\n");
131 	(void) fprintf(stderr,
132 		       "\t[-base {int}] [-username {string}]\n");
133 	exit(1);
134 }
135 
136 static XrmOptionDescRec options[] =
137 {
138 	{"-mono", "*mlink.mono", XrmoptionNoArg, "TRUE"},
139 	{"-nomono", "*mlink.mono", XrmoptionNoArg, "FALSE"},
140 	{"-rv", "*mlink.reverse", XrmoptionNoArg, "TRUE"},
141 	{"-reverse", "*mlink.reverse", XrmoptionNoArg, "TRUE"},
142 	{"-norv", "*mlink.reverse", XrmoptionNoArg, "FALSE"},
143 	{"-noreverse", "*mlink.reverse", XrmoptionNoArg, "FALSE"},
144 	{"-fg", "*mlink.Foreground", XrmoptionSepArg, NULL},
145 	{"-foreground", "*mlink.Foreground", XrmoptionSepArg, NULL},
146 	{"-bg", "*Background", XrmoptionSepArg, NULL},
147 	{"-background", "*Background", XrmoptionSepArg, NULL},
148 	{"-bd", "*mlink.tileBorder", XrmoptionSepArg, NULL},
149 	{"-border", "*mlink.tileBorder", XrmoptionSepArg, NULL},
150 	{"-tile", "*mlink.tileColor", XrmoptionSepArg, NULL},
151 	{"-face0", "*mlink.faceColor0", XrmoptionSepArg, NULL},
152 	{"-face1", "*mlink.faceColor1", XrmoptionSepArg, NULL},
153 	{"-face2", "*mlink.faceColor2", XrmoptionSepArg, NULL},
154 	{"-face3", "*mlink.faceColor3", XrmoptionSepArg, NULL},
155 	{"-face4", "*mlink.faceColor4", XrmoptionSepArg, NULL},
156 	{"-face5", "*mlink.faceColor5", XrmoptionSepArg, NULL},
157 	{"-face6", "*mlink.faceColor6", XrmoptionSepArg, NULL},
158 	{"-face7", "*mlink.faceColor7", XrmoptionSepArg, NULL},
159 	{"-tiles", "*mlink.tiles", XrmoptionSepArg, NULL},
160 	{"-faces", "*mlink.faces", XrmoptionSepArg, NULL},
161 	{"-orient", "*mlink.orient", XrmoptionNoArg, "TRUE"},
162 	{"-noorient", "*mlink.orient", XrmoptionNoArg, "FALSE"},
163 	{"-middle", "*mlink.middle", XrmoptionNoArg, "TRUE"},
164 	{"-nomiddle", "*mlink.middle", XrmoptionNoArg, "FALSE"},
165 	{"-base", "*mlink.base", XrmoptionSepArg, NULL},
166 	{"-username", "*mlink.userName", XrmoptionSepArg, NULL}
167 };
168 
169 int
main(int argc,char ** argv)170 main(int argc, char **argv)
171 {
172 	Widget      toplevel;
173 	Widget      panel, panel2, rowcol, rowcol2, rowcol3, rowcol4, rowcol5;
174 	Pixmap      mouseLeftCursor, mouseRightCursor;
175 	Pixel       fg, bg;
176 
177 	toplevel = XtInitialize(argv[0], "Mlink",
178 				options, XtNumber(options), &argc, argv);
179 	if (argc != 1)
180 		Usage();
181 
182 	XtSetArg(arg[0],
183 		 XtNiconPixmap, XCreateBitmapFromData(XtDisplay(toplevel),
184 				      RootWindowOfScreen(XtScreen(toplevel)),
185 			    (char *) mlink_bits, mlink_width, mlink_height));
186 	XtSetArg(arg[1], XmNkeyboardFocusPolicy, XmPOINTER);	/* not XmEXPLICIT */
187 	XtSetValues(toplevel, arg, 2);
188 	panel = XtCreateManagedWidget("panel",
189 				xmPanedWindowWidgetClass, toplevel, NULL, 0);
190 	panel2 = XtVaCreateManagedWidget("panel2",
191 					 xmPanedWindowWidgetClass, panel,
192 					 XmNseparatorOn, False,
193 					 XmNsashWidth, 1,
194 					 XmNsashHeight, 1, NULL);
195 
196 	rowcol = XtVaCreateManagedWidget("Rowcol", xmRowColumnWidgetClass, panel2,
197 					 XmNnumColumns, 2,
198 					 XmNorientation, XmHORIZONTAL,
199 					 XmNpacking, XmPACK_COLUMN, NULL);
200 	XtVaGetValues(rowcol,
201 		      XmNforeground, &fg,
202 		      XmNbackground, &bg, NULL);
203 	mouseLeftCursor = XCreatePixmapFromBitmapData(XtDisplay(rowcol),
204 	      RootWindowOfScreen(XtScreen(rowcol)), (char *) mouse_left_bits,
205 				 mouse_left_width, mouse_left_height, fg, bg,
206 				     DefaultDepthOfScreen(XtScreen(rowcol)));
207 	mouseRightCursor = XCreatePixmapFromBitmapData(XtDisplay(rowcol),
208 	     RootWindowOfScreen(XtScreen(rowcol)), (char *) mouse_right_bits,
209 			       mouse_right_width, mouse_right_height, fg, bg,
210 				     DefaultDepthOfScreen(XtScreen(rowcol)));
211 	XtVaCreateManagedWidget("mouseLeftText",
212 				xmLabelGadgetClass, rowcol,
213 	     XtVaTypedArg, XmNlabelString, XmRString, "Move tile", 10, NULL);
214 	XtVaCreateManagedWidget("mouseLeft",
215 				xmLabelGadgetClass, rowcol,
216 	      XmNlabelType, XmPIXMAP, XmNlabelPixmap, mouseLeftCursor, NULL);
217 	XtVaCreateManagedWidget("mouseRightText",
218 				xmLabelGadgetClass, rowcol,
219 	     XtVaTypedArg, XmNlabelString, XmRString, "Randomize", 10, NULL);
220 	XtVaCreateManagedWidget("mouseRight",
221 				xmLabelGadgetClass, rowcol,
222 	     XmNlabelType, XmPIXMAP, XmNlabelPixmap, mouseRightCursor, NULL);
223 	XtVaCreateManagedWidget("movesText",
224 				xmLabelGadgetClass, rowcol,
225 		  XtVaTypedArg, XmNlabelString, XmRString, "Moves", 6, NULL);
226 	moves = XtVaCreateManagedWidget("0",
227 					xmLabelWidgetClass, rowcol, NULL);
228 	XtVaCreateManagedWidget("recordText",
229 				xmLabelGadgetClass, rowcol,
230 		 XtVaTypedArg, XmNlabelString, XmRString, "Record", 7, NULL);
231 	record = XtVaCreateManagedWidget("0",
232 					 xmLabelWidgetClass, rowcol, NULL);
233 
234 	rowcol2 = XtVaCreateManagedWidget("Rowcol2",
235 				       xmRowColumnWidgetClass, panel2, NULL);
236 	XtVaGetValues(rowcol2,
237 		      XmNforeground, &fg,
238 		      XmNbackground, &bg, NULL);
239 	tile = XtVaCreateManagedWidget("tile",
240 				       xmScaleWidgetClass, rowcol2,
241 			 XtVaTypedArg, XmNtitleString, XmRString, "Tiles", 6,
242 				       XmNminimum, MINTILES,
243 				       XmNmaximum, MAXTILES,
244 				       XmNvalue, MINTILES,
245 				       XmNshowValue, True,
246 				       XmNorientation, XmHORIZONTAL, NULL);
247 	XtAddCallback(tile,
248 		      XmNvalueChangedCallback, (XtCallbackProc) TileSlider, (XtPointer) NULL);
249 	rowcol3 = XtVaCreateManagedWidget("Rowcol3",
250 				       xmRowColumnWidgetClass, panel2, NULL);
251 	face = XtVaCreateManagedWidget("face",
252 				       xmScaleWidgetClass, rowcol3,
253 			 XtVaTypedArg, XmNtitleString, XmRString, "Faces", 6,
254 				       XmNminimum, MINFACES,
255 				       XmNmaximum, MAXFACES,
256 				       XmNvalue, MINFACES,
257 				       XmNshowValue, True,
258 				       XmNorientation, XmHORIZONTAL, NULL);
259 	XtAddCallback(face,
260 		      XmNvalueChangedCallback, (XtCallbackProc) FaceSlider, (XtPointer) NULL);
261 	rowcol4 = XtVaCreateManagedWidget("Rowcol4",
262 					  xmRowColumnWidgetClass, panel2,
263 					  XmNnumColumns, 1,
264 					  XmNorientation, XmHORIZONTAL,
265 					  XmNpacking, XmPACK_COLUMN, NULL);
266 	orientSwitch = XtVaCreateManagedWidget("Orient",
267 				   xmToggleButtonWidgetClass, rowcol4, NULL);
268 	XtAddCallback(orientSwitch,
269 		      XmNvalueChangedCallback, (XtCallbackProc) OrientToggle, (XtPointer) NULL);
270 	middleSwitch = XtVaCreateManagedWidget("Middle",
271 				   xmToggleButtonWidgetClass, rowcol4, NULL);
272 	XtAddCallback(middleSwitch,
273 		      XmNvalueChangedCallback, (XtCallbackProc) MiddleToggle, (XtPointer) NULL);
274 	rowcol5 = XtVaCreateManagedWidget("Rowcol5",
275 				       xmRowColumnWidgetClass, panel2, NULL);
276 	message = XtVaCreateManagedWidget("Play Missing Link! (use mouse and keypad)",
277 					  xmLabelWidgetClass, rowcol5, NULL);
278 
279 	mlink = XtCreateManagedWidget("mlink",
280 				      mlinkWidgetClass, panel, NULL, 0);
281 	XtAddCallback(mlink,
282 	XtNselectCallback, (XtCallbackProc) CallbackMlink, (XtPointer) NULL);
283 	Initialize(mlink);
284 	XtRealizeWidget(toplevel);
285 	XGrabButton(XtDisplay(mlink), (unsigned int) AnyButton, AnyModifier,
286 		    XtWindow(mlink), TRUE,
287 		    (unsigned int) (ButtonPressMask | ButtonMotionMask | ButtonReleaseMask),
288 		    GrabModeAsync, GrabModeAsync, XtWindow(mlink),
289 		    XCreateFontCursor(XtDisplay(mlink), XC_crosshair));
290 	XtMainLoop();
291 
292 #ifdef VMS
293 	return 1;
294 #else
295 	return 0;
296 #endif
297 }
298 
299 static void
Initialize(Widget w)300 Initialize(Widget w)
301 {
302 	int         tiles, faces;
303 	Boolean     orient, middle;
304 	String      username;
305 
306 	XtVaSetValues(w,
307 		      XtNstart, False, NULL);
308 	XtVaGetValues(w,
309 		      XtNuserName, &username,
310 		      XtNtiles, &tiles,
311 		      XtNfaces, &faces,
312 		      XtNorient, &orient,
313 		      XtNmiddle, &middle, NULL);
314 	if (tiles <= MAXTILES)
315 		XmScaleSetValue(tile, tiles);
316 	XmScaleSetValue(face, faces);
317 	XmToggleButtonSetState(orientSwitch, orient, True);
318 	XmToggleButtonSetState(middleSwitch, middle, True);
319 	InitRecords();
320 	ReadRecords();
321 	(void) strcpy(usernameDsp, username);
322 	if (!strcmp(usernameDsp, "") || !strcmp(usernameDsp, NOACCESS) ||
323 	    !strcmp(usernameDsp, NOBODY)) {
324 		/* The NOACCESS is not necasary, but it stops people from being cute. */
325 		(void) sprintf(usernameDsp, "%s", getlogin());
326 		if (!strcmp(usernameDsp, "") || !strcmp(usernameDsp, NOACCESS))
327 			(void) sprintf(usernameDsp, "%s", NOBODY);	/* It really IS nobody */
328 	}
329 	PrintRecord(tiles, faces, orient, middle);
330 }
331 
332 static void
CallbackMlink(Widget w,caddr_t clientData,mlinkCallbackStruct * callData)333 CallbackMlink(Widget w, caddr_t clientData, mlinkCallbackStruct * callData)
334 {
335 	int         tiles, faces;
336 	Boolean     orient, middle;
337 
338 	XtVaGetValues(w,
339 		      XtNtiles, &tiles,
340 		      XtNfaces, &faces,
341 		      XtNorient, &orient,
342 		      XtNmiddle, &middle, NULL);
343 	(void) strcpy(messageDsp, "");
344 	switch (callData->reason) {
345 		case MLINK_RESTORE:
346 		case MLINK_RESET:
347 			movesDsp = 0;
348 			break;
349 		case MLINK_BLOCKED:
350 			(void) strcpy(messageDsp, "Blocked");
351 			break;
352 		case MLINK_SPACE:
353 #if 0
354 			/* Too annoying */
355 			(void) strcpy(messageDsp, "A spaces can not slide");
356 #endif
357 			break;
358 		case MLINK_IGNORE:
359 			(void) strcpy(messageDsp, "Randomize to start");
360 			break;
361 		case MLINK_MOVED:
362 			movesDsp++;
363 			XtSetArg(arg[0], XtNstart, True);
364 			XtSetValues(w, arg, 1);
365 			break;
366 		case MLINK_CONTROL:
367 			return;
368 		case MLINK_SOLVED:
369 			if (HandleSolved(movesDsp, tiles, faces, orient, middle))
370 				(void) sprintf(messageDsp, "Congratulations %s!!", usernameDsp);
371 			else
372 				(void) strcpy(messageDsp, "Solved!");
373 			XtSetArg(arg[0], XtNstart, False);
374 			XtSetValues(w, arg, 1);
375 			break;
376 		case MLINK_RANDOMIZE:
377 			movesDsp = 0;
378 			XtSetArg(arg[0], XtNstart, False);
379 			XtSetValues(w, arg, 1);
380 			break;
381 		case MLINK_ORIENT:
382 			movesDsp = 0;
383 			orient = !orient;
384 			PrintRecord(tiles, faces, orient, middle);
385 			XtSetArg(arg[0], XtNorient, orient);
386 			XtSetValues(w, arg, 1);
387 			XmToggleButtonSetState(orientSwitch, orient, True);
388 			break;
389 		case MLINK_MIDDLE:
390 			movesDsp = 0;
391 			middle = !middle;
392 			PrintRecord(tiles, faces, orient, middle);
393 			XtSetArg(arg[0], XtNmiddle, middle);
394 			XtSetValues(w, arg, 1);
395 			XmToggleButtonSetState(middleSwitch, middle, True);
396 			break;
397 		case MLINK_DEC_X:
398 			movesDsp = 0;
399 			tiles--;
400 			PrintRecord(tiles, faces, orient, middle);
401 			XtSetArg(arg[0], XtNtiles, tiles);
402 			XtSetValues(w, arg, 1);
403 			if (tiles <= MAXTILES)
404 				XmScaleSetValue(tile, tiles);
405 			break;
406 		case MLINK_INC_X:
407 			movesDsp = 0;
408 			tiles++;
409 			PrintRecord(tiles, faces, orient, middle);
410 			XtSetArg(arg[0], XtNtiles, tiles);
411 			XtSetValues(w, arg, 1);
412 			if (tiles <= MAXTILES)
413 				XmScaleSetValue(tile, tiles);
414 			break;
415 		case MLINK_DEC_Y:
416 			movesDsp = 0;
417 			faces--;
418 			PrintRecord(tiles, faces, orient, middle);
419 			XtSetArg(arg[0], XtNfaces, faces);
420 			XtSetValues(w, arg, 1);
421 			XmScaleSetValue(face, faces);
422 			break;
423 		case MLINK_INC_Y:
424 			movesDsp = 0;
425 			faces++;
426 			PrintRecord(tiles, faces, orient, middle);
427 			XtSetArg(arg[0], XtNfaces, faces);
428 			XtSetValues(w, arg, 1);
429 			XmScaleSetValue(face, faces);
430 			break;
431 		case MLINK_COMPUTED:
432 			XtSetArg(arg[0], XtNstart, False);
433 			XtSetValues(w, arg, 1);
434 			break;
435 		case MLINK_UNDO:
436 			movesDsp--;
437 			XtSetArg(arg[0], XtNstart, True);
438 			XtSetValues(w, arg, 1);
439 			break;
440 	}
441 	motif_print(message, messageDsp);
442 	(void) sprintf(buff, "%d", movesDsp);
443 	motif_print(moves, buff);
444 }
445 
446 static void
TileSlider(Widget w,XtPointer clientData,XmScaleCallbackStruct * cbs)447 TileSlider(Widget w, XtPointer clientData, XmScaleCallbackStruct * cbs)
448 {
449 	int         tiles = cbs->value, faces, old;
450 
451 	XtVaGetValues(mlink,
452 		      XtNtiles, &old,
453 		      XtNfaces, &faces, NULL);
454 	if (old != tiles) {
455 		XtVaSetValues(mlink,
456 			      XtNtiles, tiles, NULL);
457 		movesDsp = 0;
458 		(void) sprintf(buff, "%d", movesDsp);
459 		motif_print(moves, buff);
460 		PrintRecord(tiles, faces, XmToggleButtonGetState(orientSwitch),
461 			    XmToggleButtonGetState(middleSwitch));
462 	}
463 }
464 
465 static void
FaceSlider(Widget w,XtPointer clientData,XmScaleCallbackStruct * cbs)466 FaceSlider(Widget w, XtPointer clientData, XmScaleCallbackStruct * cbs)
467 {
468 	int         tiles, faces = cbs->value, old;
469 
470 	XtVaGetValues(mlink,
471 		      XtNtiles, &tiles,
472 		      XtNfaces, &old, NULL);
473 	if (old != faces) {
474 		XtVaSetValues(mlink,
475 			      XtNfaces, faces, NULL);
476 		movesDsp = 0;
477 		(void) sprintf(buff, "%d", movesDsp);
478 		motif_print(moves, buff);
479 		PrintRecord(tiles, faces, XmToggleButtonGetState(orientSwitch),
480 			    XmToggleButtonGetState(middleSwitch));
481 	}
482 }
483 
484 static void
OrientToggle(Widget w,XtPointer clientData,XmToggleButtonCallbackStruct * cbs)485 OrientToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct * cbs)
486 {
487 	int         tiles, faces;
488 	Boolean     orient = cbs->set;
489 
490 	XtVaSetValues(mlink,
491 		      XtNorient, orient, NULL);
492 	XtVaGetValues(mlink,
493 		      XtNtiles, &tiles,
494 		      XtNfaces, &faces, NULL);
495 	movesDsp = 0;
496 	(void) sprintf(buff, "%d", movesDsp);
497 	motif_print(moves, buff);
498 	PrintRecord(tiles, faces, orient, XmToggleButtonGetState(middleSwitch));
499 }
500 
501 static void
MiddleToggle(Widget w,XtPointer clientData,XmToggleButtonCallbackStruct * cbs)502 MiddleToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct * cbs)
503 {
504 	int         tiles, faces;
505 	Boolean     middle = cbs->set;
506 
507 	XtVaSetValues(mlink,
508 		      XtNmiddle, middle, NULL);
509 	XtVaGetValues(mlink,
510 		      XtNtiles, &tiles,
511 		      XtNfaces, &faces, NULL);
512 	movesDsp = 0;
513 	(void) sprintf(buff, "%d", movesDsp);
514 	motif_print(moves, buff);
515 	PrintRecord(tiles, faces, XmToggleButtonGetState(orientSwitch), middle);
516 }
517 
518 static void
PrintRecord(int tiles,int faces,Boolean orient,Boolean middle)519 PrintRecord(int tiles, int faces, Boolean orient, Boolean middle)
520 {
521 	int         i = tiles - MINTILES, j = faces - MINFACES;
522 	int         k = (orient) ? 1 : 0, l = (middle) ? 1 : 0;
523 
524 	if (tiles > MAXTILES)
525 		motif_print(record, "NOT RECORDED");
526 	else if (mlinkRecord[l][k][j][i].score >= MAXRECORD) {
527 		(void) sprintf(buff, "NEVER %s", NOACCESS);
528 		motif_print(record, buff);
529 	} else {
530 		(void) sprintf(buff, "%d %s",
531 		mlinkRecord[l][k][j][i].score, mlinkRecord[l][k][j][i].name);
532 		motif_print(record, buff);
533 	}
534 }
535 
536 static      Boolean
HandleSolved(int counter,int tiles,int faces,Boolean orient,Boolean middle)537 HandleSolved(int counter, int tiles, int faces, Boolean orient, Boolean middle)
538 {
539 	int         i = tiles - MINTILES, j = faces - MINFACES;
540 	int         k = (orient) ? 1 : 0, l = (middle) ? 1 : 0;
541 
542 	if (tiles <= MAXTILES && counter < mlinkRecord[l][k][j][i].score) {
543 		mlinkRecord[l][k][j][i].score = counter;
544 		(void) strcpy(mlinkRecord[l][k][j][i].name, usernameDsp);
545 		if (tiles < 4 || faces < 2) {
546 			mlinkRecord[!l][k][j][i].score = counter;
547 			(void) strcpy(mlinkRecord[!l][k][j][i].name, usernameDsp);
548 		}
549 		WriteRecords();
550 		PrintRecord(tiles, faces, orient, middle);
551 		return True;
552 	}
553 	return False;
554 }
555 
556 static void
InitRecords(void)557 InitRecords(void)
558 {
559 	int         i, j, k, l;
560 
561 	for (l = 0; l < 2; l++)
562 		for (k = 0; k < 2; k++)
563 			for (j = 0; j < MAXFACES - MINFACES + 1; j++)
564 				for (i = 0; i < MAXTILES - MINTILES + 1; i++) {
565 					mlinkRecord[l][k][j][i].score = MAXRECORD;
566 					(void) strcpy(mlinkRecord[l][k][j][i].name, NOACCESS);
567 				}
568 }
569 
570 static void
ReadRecords(void)571 ReadRecords(void)
572 {
573 	FILE       *fp;
574 	int         i, j, k, l, n;
575 	char        username[USERNAMELEN];
576 
577 	if ((fp = fopen(SCOREFILE, "r")) == NULL) {
578 		(void) sprintf(buff, "Can not open %s, taking defaults.", SCOREFILE);
579 		motif_print(message, buff);
580 	} else {
581 		for (l = 0; l < 2; l++)
582 			for (k = 0; k < 2; k++)
583 				for (j = 0; j < MAXFACES - MINFACES + 1; j++)
584 					for (i = 0; i < MAXTILES - MINTILES + 1; i++) {
585 						(void) fscanf(fp, "%d %s\n", &n, username);
586 						if (n <= mlinkRecord[l][k][j][i].score) {
587 							mlinkRecord[l][k][j][i].score = n;
588 							(void) strcpy(mlinkRecord[l][k][j][i].name, username);
589 						}
590 					}
591 		(void) fclose(fp);
592 	}
593 }
594 
595 static void
WriteRecords(void)596 WriteRecords(void)
597 {
598 	FILE       *fp;
599 	int         i, j, k, l;
600 
601 	ReadRecords();		/* Maybe its been updated by another */
602 	if ((fp = fopen(SCOREFILE, "w")) == NULL) {
603 		(void) sprintf(buff, "Can not write to %s.", SCOREFILE);
604 		motif_print(message, buff);
605 	} else {
606 #if HAVE_FCNTL_H
607 		int         lfd;
608 		char        lockfile[FILENAMELEN];
609 
610 		(void) strcpy(lockfile, SCOREFILE);
611 		(void) strcat(lockfile, ".lock");
612 		while (((lfd = open(lockfile, O_CREAT | O_EXCL, 0644)) < 0) &&
613 		       errno == EEXIST)
614 			(void) sleep(1);
615 		if (lfd < 0) {
616 #if 1
617 			(void) fprintf(stderr, "Lock file exists... guessing its an old one.\n");
618 #else
619 			(void) fprintf(stderr, "Lock file exists... score not recorded - sorry.\n"
620 				);
621 			return;
622 #endif
623 		}
624 #endif
625 		for (l = 0; l < 2; l++) {
626 			for (k = 0; k < 2; k++) {
627 				for (j = 0; j < MAXFACES - MINFACES + 1; j++) {
628 					for (i = 0; i < MAXTILES - MINTILES + 1; i++)
629 						(void) fprintf(fp, "%d %s\n",
630 							       mlinkRecord[l][k][j][i].score, mlinkRecord[l][k][j][i].name);
631 					(void) fprintf(fp, "\n");
632 				}
633 				(void) fprintf(fp, "\n");
634 			}
635 			(void) fprintf(fp, "\n");
636 		}
637 #if HAVE_FCNTL_H
638 		(void) close(lfd);
639 		(void) unlink(lockfile);
640 #endif
641 		(void) fclose(fp);
642 	}
643 }
644 
645 static void
motif_print(Widget w,char * text)646 motif_print(Widget w, char *text)
647 {
648 	Arg         wargs[1];
649 	XmString    xmstr;
650 
651 	if (!XtIsSubclass(w, xmLabelWidgetClass))
652 		XtError("motif_print() requires a Label Widget");
653 	xmstr = XmStringCreateLtoR(text, XmSTRING_DEFAULT_CHARSET);
654 	XtSetArg(wargs[0], XmNlabelString, xmstr);
655 	XtSetValues(w, wargs, 1);
656 }
657