1 
2 /*-
3 # MOTIF-BASED SKEWB
4 #
5 #  xmskewb.c
6 #
7 ###
8 #
9 #  Copyright (c) 1993 - 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 "useful",
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   Version 3: 93/10/03 Motif
31   Version 2: 92/01/22 XView
32   Version 1: 91/03/19 SunView
33 */
34 
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <errno.h>
38 #ifdef VMS
39 #include <unixlib.h>
40 #define getlogin() cuserid(NULL)
41 #else
42 #if HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
45 #endif
46 #if HAVE_FCNTL_H
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <fcntl.h>
50 #endif
51 #include <X11/Intrinsic.h>
52 #include <X11/StringDefs.h>
53 #include <X11/Shell.h>
54 #include <X11/cursorfont.h>
55 #include <Xm/PanedW.h>
56 #include <Xm/RowColumn.h>
57 #include <Xm/Label.h>
58 #include <Xm/LabelG.h>
59 #include <Xm/ToggleB.h>
60 #include "Skewb.h"
61 #include "Skewb2d.h"
62 #include "Skewb3d.h"
63 #include "skewb.xbm"
64 #include "mouse-l.xbm"
65 #include "mouse-r.xbm"
66 
67 #ifndef SCOREFILE
68 #define SCOREFILE "/usr/games/lib/mball.scores"
69 #endif
70 
71 /* The following is in SkewbP.h also */
72 #define MAXFACES 6
73 
74 #define MAXRECORD 32767
75 #define FILENAMELEN 1024
76 #define USERNAMELEN 128
77 #define NOACCESS "noaccess"
78 #define NOBODY "nobody"
79 
80 typedef struct {
81 	int         score;
82 	char        name[USERNAMELEN];
83 } GameRecord;
84 
85 static void Initialize(void);
86 static void CallbackSkewb(Widget w, caddr_t clientData, skewbCallbackStruct * callData);
87 
88 static void PrintRecord(Boolean orient, Boolean practice);
89 static Boolean HandleSolved(int counter, Boolean orient);
90 static void InitRecords(void);
91 static void ReadRecords(void);
92 static void WriteRecords(void);
93 
94 static void OrientToggle(Widget w, XtPointer clientData,
95 			 XmToggleButtonCallbackStruct * cbs);
96 static void PracticeToggle(Widget w, XtPointer clientData,
97 			   XmToggleButtonCallbackStruct * cbs);
98 static void motif_print(Widget w, char *text);
99 
100 static Arg  arg[4];
101 static Widget moves, record, message, skewb2d, skewb3d, orientSwitch, practiceSwitch;
102 static GameRecord skewbRecord[2];
103 static int  movesDsp = 0;
104 static char messageDsp[128] = "Welcome";
105 static char usernameDsp[USERNAMELEN] = "";
106 static char buff[256];
107 
108 static void
Usage(void)109 Usage(void)
110 {
111 	(void) fprintf(stderr, "usage: xmskewb\n");
112 	(void) fprintf(stderr,
113 	     "\t[-geometry [{width}][x{height}][{+-}{xoff}[{+-}{yoff}]]]\n");
114 	(void) fprintf(stderr,
115 	   "\t[-display [{host}]:[{vs}]] [-[no]mono] [-[no]{reverse|rv}]\n");
116 	(void) fprintf(stderr,
117 		"\t[-{foreground|fg} {color}] [-{background|bg} {color}]\n");
118 	(void) fprintf(stderr,
119 		  "\t[-{border|bd} {color}] [-face{0|1|2|3|4|5} {color}]\n");
120 	(void) fprintf(stderr,
121 		   "\t[-[no]orient] [-[no]practice] [-username {string}]\n");
122 	exit(1);
123 }
124 
125 static XrmOptionDescRec options[] =
126 {
127 	{"-mono", "*skewb.mono", XrmoptionNoArg, "TRUE"},
128 	{"-nomono", "*skewb.mono", XrmoptionNoArg, "FALSE"},
129 	{"-rv", "*skewb.reverse", XrmoptionNoArg, "TRUE"},
130 	{"-reverse", "*skewb.reverse", XrmoptionNoArg, "TRUE"},
131 	{"-norv", "*skewb.reverse", XrmoptionNoArg, "FALSE"},
132 	{"-noreverse", "*skewb.reverse", XrmoptionNoArg, "FALSE"},
133 	{"-fg", "*skewb.Foreground", XrmoptionSepArg, NULL},
134 	{"-foreground", "*skewb.Foreground", XrmoptionSepArg, NULL},
135 	{"-bg", "*Background", XrmoptionSepArg, NULL},
136 	{"-background", "*Background", XrmoptionSepArg, NULL},
137 	{"-bd", "*skewb.pieceBorder", XrmoptionSepArg, NULL},
138 	{"-border", "*skewb.pieceBorder", XrmoptionSepArg, NULL},
139 	{"-face0", "*skewb.faceColor0", XrmoptionSepArg, NULL},
140 	{"-face1", "*skewb.faceColor1", XrmoptionSepArg, NULL},
141 	{"-face2", "*skewb.faceColor2", XrmoptionSepArg, NULL},
142 	{"-face3", "*skewb.faceColor3", XrmoptionSepArg, NULL},
143 	{"-face4", "*skewb.faceColor4", XrmoptionSepArg, NULL},
144 	{"-face5", "*skewb.faceColor5", XrmoptionSepArg, NULL},
145 	{"-orient", "*skewb.orient", XrmoptionNoArg, "TRUE"},
146 	{"-noorient", "*skewb.orient", XrmoptionNoArg, "FALSE"},
147 	{"-practice", "*skewb.practice", XrmoptionNoArg, "TRUE"},
148 	{"-nopractice", "*skewb.practice", XrmoptionNoArg, "FALSE"},
149 	{"-username", "*skewb.userName", XrmoptionSepArg, NULL}
150 };
151 
152 int
main(int argc,char ** argv)153 main(int argc, char **argv)
154 {
155 	Widget      toplevel;
156 	Widget      panel, panel2, rowcol, rowcol2, rowcol3;
157 	Pixmap      mouseLeftCursor, mouseRightCursor;
158 	Pixel       fg, bg;
159 
160 	toplevel = XtInitialize(argv[0], "Skewb",
161 				options, XtNumber(options), &argc, argv);
162 	if (argc != 1)
163 		Usage();
164 
165 	XtSetArg(arg[0],
166 		 XtNiconPixmap, XCreateBitmapFromData(XtDisplay(toplevel),
167 				      RootWindowOfScreen(XtScreen(toplevel)),
168 			    (char *) skewb_bits, skewb_width, skewb_height));
169 	XtSetArg(arg[1], XmNkeyboardFocusPolicy, XmPOINTER);	/* not XmEXPLICIT */
170 	XtSetValues(toplevel, arg, 2);
171 	panel = XtCreateManagedWidget("panel",
172 				xmPanedWindowWidgetClass, toplevel, NULL, 0);
173 	panel2 = XtVaCreateManagedWidget("panel2",
174 					 xmPanedWindowWidgetClass, panel,
175 					 XmNseparatorOn, False,
176 					 XmNsashWidth, 1,
177 					 XmNsashHeight, 1, NULL);
178 
179 	rowcol = XtVaCreateManagedWidget("Rowcol",
180 					 xmRowColumnWidgetClass, panel2,
181 					 XmNnumColumns, 2,
182 					 XmNorientation, XmHORIZONTAL,
183 					 XmNpacking, XmPACK_COLUMN, NULL);
184 	XtVaGetValues(rowcol,
185 		      XmNforeground, &fg,
186 		      XmNbackground, &bg, NULL);
187 	mouseLeftCursor = XCreatePixmapFromBitmapData(XtDisplay(rowcol),
188 	      RootWindowOfScreen(XtScreen(rowcol)), (char *) mouse_left_bits,
189 				 mouse_left_width, mouse_left_height, fg, bg,
190 				     DefaultDepthOfScreen(XtScreen(rowcol)));
191 	mouseRightCursor = XCreatePixmapFromBitmapData(XtDisplay(rowcol),
192 	     RootWindowOfScreen(XtScreen(rowcol)), (char *) mouse_right_bits,
193 			       mouse_right_width, mouse_right_height, fg, bg,
194 				     DefaultDepthOfScreen(XtScreen(rowcol)));
195 	XtVaCreateManagedWidget("mouseLeftText",
196 				xmLabelGadgetClass, rowcol,
197 		  XtVaTypedArg, XmNlabelString, XmRString, "Moves", 5, NULL);
198 	XtVaCreateManagedWidget("mouseLeft",
199 				xmLabelGadgetClass, rowcol,
200 	      XmNlabelType, XmPIXMAP, XmNlabelPixmap, mouseLeftCursor, NULL);
201 	XtVaCreateManagedWidget("mouseRightText",
202 				xmLabelGadgetClass, rowcol,
203 	     XtVaTypedArg, XmNlabelString, XmRString, "Randomize", 10, NULL);
204 	XtVaCreateManagedWidget("mouseRight",
205 				xmLabelGadgetClass, rowcol,
206 	     XmNlabelType, XmPIXMAP, XmNlabelPixmap, mouseRightCursor, NULL);
207 	XtVaCreateManagedWidget("movesText",
208 				xmLabelGadgetClass, rowcol,
209 		  XtVaTypedArg, XmNlabelString, XmRString, "Moves", 6, NULL);
210 	moves = XtVaCreateManagedWidget("0",
211 					xmLabelWidgetClass, rowcol, NULL);
212 	XtVaCreateManagedWidget("recordText",
213 				xmLabelGadgetClass, rowcol,
214 		 XtVaTypedArg, XmNlabelString, XmRString, "Record", 7, NULL);
215 	record = XtVaCreateManagedWidget("0",
216 					 xmLabelWidgetClass, rowcol, NULL);
217 
218 	rowcol2 = XtVaCreateManagedWidget("Rowcol2",
219 					  xmRowColumnWidgetClass, panel2,
220 					  XmNnumColumns, 1,
221 					  XmNorientation, XmHORIZONTAL,
222 					  XmNpacking, XmPACK_COLUMN, NULL);
223 	orientSwitch = XtVaCreateManagedWidget("Orient",
224 				   xmToggleButtonWidgetClass, rowcol2, NULL);
225 	XtAddCallback(orientSwitch,
226 		      XmNvalueChangedCallback, (XtCallbackProc) OrientToggle, (XtPointer) NULL);
227 	practiceSwitch = XtVaCreateManagedWidget("Practice",
228 				   xmToggleButtonWidgetClass, rowcol2, NULL);
229 	XtAddCallback(practiceSwitch,
230 		      XmNvalueChangedCallback, (XtCallbackProc) PracticeToggle, (XtPointer) NULL);
231 	rowcol3 = XtVaCreateManagedWidget("Rowcol3",
232 				       xmRowColumnWidgetClass, panel2, NULL);
233 	message = XtVaCreateManagedWidget("Play Skewb! (use mouse and keypad)",
234 					  xmLabelWidgetClass, rowcol3, NULL);
235 
236 	skewb2d = XtCreateManagedWidget("skewb",
237 					skewb2dWidgetClass, panel, NULL, 0);
238 	XtVaSetValues(skewb2d,
239 		      XtNheight, 200, NULL);
240 	XtAddCallback(skewb2d,
241 	XtNselectCallback, (XtCallbackProc) CallbackSkewb, (XtPointer) NULL);
242 	skewb3d = XtCreateManagedWidget("skewb",
243 					skewb3dWidgetClass, panel, NULL, 0);
244 	XtVaSetValues(skewb3d,
245 		      XtNheight, 200, NULL);
246 	XtAddCallback(skewb3d,
247 	XtNselectCallback, (XtCallbackProc) CallbackSkewb, (XtPointer) NULL);
248 	Initialize();
249 	XtRealizeWidget(toplevel);
250 	XGrabButton(XtDisplay(skewb2d), (unsigned int) AnyButton, AnyModifier,
251 		    XtWindow(skewb2d), TRUE,
252 		    (unsigned int) (ButtonPressMask | ButtonMotionMask | ButtonReleaseMask),
253 		    GrabModeAsync, GrabModeAsync, XtWindow(skewb2d),
254 		    XCreateFontCursor(XtDisplay(skewb2d), XC_crosshair));
255 	XGrabButton(XtDisplay(skewb3d), (unsigned int) AnyButton, AnyModifier,
256 		    XtWindow(skewb3d), TRUE,
257 		    (unsigned int) (ButtonPressMask | ButtonMotionMask | ButtonReleaseMask),
258 		    GrabModeAsync, GrabModeAsync, XtWindow(skewb3d),
259 		    XCreateFontCursor(XtDisplay(skewb3d), XC_crosshair));
260 	XtMainLoop();
261 
262 #ifdef VMS
263 	return 1;
264 #else
265 	return 0;
266 #endif
267 }
268 
269 /* There's probably a better way to assure that they are the same but I don't
270    know it off hand. */
271 static void
MakeEquivalent(String * username,Boolean * orient,Boolean * practice)272 MakeEquivalent(String * username, Boolean * orient, Boolean * practice)
273 {
274 	Boolean     mono, reverse;
275 	Pixel       foreground, background, pieceBorder;
276 	String      faceColor[MAXFACES];
277 
278 	XtVaGetValues(skewb2d,
279 		      XtNuserName, username,
280 		      XtNorient, orient,
281 		      XtNpractice, practice,
282 		      XtNmono, &mono,
283 		      XtNreverse, &reverse,
284 		      XtNforeground, &foreground,
285 		      XtNbackground, &background,
286 		      XtNpieceBorder, &pieceBorder,
287 		      XtNfaceColor0, &(faceColor[0]),
288 		      XtNfaceColor1, &(faceColor[1]),
289 		      XtNfaceColor2, &(faceColor[2]),
290 		      XtNfaceColor3, &(faceColor[3]),
291 		      XtNfaceColor4, &(faceColor[4]),
292 		      XtNfaceColor5, &(faceColor[5]), NULL);
293 	XtVaSetValues(skewb2d,
294 		      XtNdirection, SKEWB_IGNORE,
295 		      XtNstart, False, NULL);
296 	XtVaSetValues(skewb3d,
297 		      XtNuserName, *username,
298 		      XtNorient, *orient,
299 		      XtNpractice, *practice,
300 		      XtNmono, mono,
301 		      XtNreverse, reverse,
302 		      XtNdirection, SKEWB_IGNORE,
303 		      XtNstart, False,
304 		      XtNforeground, foreground,
305 		      XtNbackground, background,
306 		      XtNpieceBorder, pieceBorder,
307 		      XtNfaceColor0, faceColor[0],
308 		      XtNfaceColor1, faceColor[1],
309 		      XtNfaceColor2, faceColor[2],
310 		      XtNfaceColor3, faceColor[3],
311 		      XtNfaceColor4, faceColor[4],
312 		      XtNfaceColor5, faceColor[5], NULL);
313 }
314 
315 static void
Initialize(void)316 Initialize(void)
317 {
318 	Boolean     orient, practice;
319 	String      username;
320 
321 	MakeEquivalent(&username, &orient, &practice);
322 	XmToggleButtonSetState(orientSwitch, orient, True);
323 	XmToggleButtonSetState(practiceSwitch, practice, True);
324 	InitRecords();
325 	ReadRecords();
326 	(void) strcpy(usernameDsp, username);
327 	if (!strcmp(usernameDsp, "") || !strcmp(usernameDsp, NOACCESS) ||
328 	    !strcmp(usernameDsp, NOBODY)) {
329 		/* The NOACCESS is not necasary, but it stops people from being cute. */
330 		(void) sprintf(usernameDsp, "%s", getlogin());
331 		if (!strcmp(usernameDsp, "") || !strcmp(usernameDsp, NOACCESS))
332 			(void) sprintf(usernameDsp, "%s", NOBODY);	/* It really IS nobody */
333 	}
334 	PrintRecord(orient, practice);
335 }
336 
337 static void
CallbackSkewb(Widget w,caddr_t clientData,skewbCallbackStruct * callData)338 CallbackSkewb(Widget w, caddr_t clientData, skewbCallbackStruct * callData)
339 {
340 	Boolean     orient, practice, start;
341 	Widget      otherw;
342 
343 	if (w == skewb2d)
344 		otherw = skewb3d;
345 	else			/* (w == skewb3d) */
346 		otherw = skewb2d;
347 	XtVaGetValues(w,
348 		      XtNorient, &orient,
349 		      XtNpractice, &practice,
350 		      XtNstart, &start, NULL);
351 	(void) strcpy(messageDsp, "");
352 	switch (callData->reason) {
353 		case SKEWB_RESTORE:
354 			XtSetArg(arg[0], XtNdirection, SKEWB_RESTORE);
355 			XtSetValues(otherw, arg, 1);
356 			XtSetValues(w, arg, 1);
357 			movesDsp = 0;
358 			break;
359 		case SKEWB_RESET:
360 			movesDsp = 0;
361 			break;
362 		case SKEWB_ILLEGAL:
363 			if (practice || start)
364 				(void) strcpy(messageDsp, "Illegal move");
365 			else
366 				(void) strcpy(messageDsp, "Randomize to start");
367 			break;
368 		case SKEWB_MOVED:
369 			movesDsp++;
370 			XtSetArg(arg[0], XtNstart, True);
371 			XtSetArg(arg[1], XtNface, callData->face);
372 			XtSetArg(arg[2], XtNpos, callData->position);
373 			XtSetArg(arg[3], XtNdirection, callData->direction);
374 			XtSetValues(otherw, arg, 4);
375 			XtSetValues(w, arg, 1);
376 			break;
377 		case SKEWB_CONTROL:
378 			XtSetArg(arg[0], XtNface, callData->face);
379 			XtSetArg(arg[1], XtNpos, callData->position);
380 			XtSetArg(arg[2], XtNdirection, callData->direction);
381 			XtSetValues(otherw, arg, 3);
382 			return;
383 		case SKEWB_SOLVED:
384 			if (practice)
385 				movesDsp = 0;
386 			else {
387 				if (HandleSolved(movesDsp, orient))
388 					(void) sprintf(messageDsp, "Congratulations %s!!", usernameDsp);
389 				else
390 					(void) strcpy(messageDsp, "Solved!");
391 			}
392 			XtSetArg(arg[0], XtNstart, False);
393 			XtSetValues(w, arg, 1);
394 			XtSetValues(otherw, arg, 1);
395 			break;
396 		case SKEWB_PRACTICE:
397 			movesDsp = 0;
398 			practice = !practice;
399 			if (!practice)
400 				(void) strcpy(messageDsp, "Randomize to start");
401 			PrintRecord(orient, practice);
402 			XtSetArg(arg[0], XtNpractice, practice);
403 			XtSetArg(arg[1], XtNstart, False);
404 			XtSetValues(w, arg, 2);
405 			XtSetValues(otherw, arg, 2);
406 			XmToggleButtonSetState(practiceSwitch, practice, True);
407 			break;
408 		case SKEWB_RANDOMIZE:
409 			movesDsp = 0;
410 			XtSetArg(arg[0], XtNpractice, False);
411 			XtSetArg(arg[1], XtNstart, False);
412 			XtSetValues(w, arg, 2);
413 			XtSetValues(otherw, arg, 2);
414 			break;
415 		case SKEWB_ORIENT:
416 			movesDsp = 0;
417 			orient = !orient;
418 			PrintRecord(orient, practice);
419 			XtSetArg(arg[0], XtNorient, orient);
420 			XtSetValues(w, arg, 1);
421 			XtSetValues(otherw, arg, 1);
422 			XmToggleButtonSetState(orientSwitch, orient, True);
423 			break;
424 		case SKEWB_COMPUTED:
425 			XtSetArg(arg[0], XtNstart, False);
426 			XtSetValues(w, arg, 1);
427 			XtSetValues(otherw, arg, 1);
428 			break;
429 		case SKEWB_UNDO:
430 			movesDsp--;
431 			XtSetArg(arg[0], XtNstart, True);
432 			XtSetArg(arg[1], XtNface, callData->face);
433 			XtSetArg(arg[2], XtNpos, callData->position);
434 			XtSetArg(arg[3], XtNdirection, callData->direction);
435 			XtSetValues(otherw, arg, 4);
436 			XtSetValues(w, arg, 1);
437 			break;
438 	}
439 	motif_print(message, messageDsp);
440 	(void) sprintf(buff, "%d", movesDsp);
441 	motif_print(moves, buff);
442 }
443 
444 static void
OrientToggle(Widget w,XtPointer clientData,XmToggleButtonCallbackStruct * cbs)445 OrientToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct * cbs)
446 {
447 	Boolean     orient = cbs->set, practice;
448 
449 	XtVaGetValues(skewb2d,
450 		      XtNpractice, &practice, NULL);
451 	XtVaSetValues(skewb2d,
452 		      XtNorient, orient, NULL);
453 	XtVaSetValues(skewb3d,
454 		      XtNorient, orient, NULL);
455 	movesDsp = 0;
456 	(void) sprintf(buff, "%d", movesDsp);
457 	motif_print(moves, buff);
458 	PrintRecord(orient, practice);
459 }
460 
461 static void
PracticeToggle(Widget w,XtPointer clientData,XmToggleButtonCallbackStruct * cbs)462 PracticeToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct * cbs)
463 {
464 	Boolean     orient, practice = cbs->set;
465 
466 	XtVaSetValues(skewb2d,
467 		      XtNpractice, practice,
468 		      XtNstart, False, NULL);
469 	XtVaSetValues(skewb3d,
470 		      XtNpractice, practice,
471 		      XtNstart, False, NULL);
472 	XtVaGetValues(skewb2d,
473 		      XtNpractice, &orient, NULL);
474 	movesDsp = 0;
475 	(void) sprintf(buff, "%d", movesDsp);
476 	motif_print(moves, buff);
477 	if (!practice)
478 		(void) strcpy(messageDsp, "Randomize to start");
479 	PrintRecord(orient, practice);
480 }
481 
482 static void
PrintRecord(Boolean orient,Boolean practice)483 PrintRecord(Boolean orient, Boolean practice)
484 {
485 	int         i = (orient) ? 1 : 0;
486 
487 	if (practice)
488 		motif_print(record, "practice");
489 	else if (skewbRecord[i].score >= MAXRECORD) {
490 		(void) sprintf(buff, "NEVER %s", NOACCESS);
491 		motif_print(record, buff);
492 	} else {
493 		(void) sprintf(buff, "%d %s",
494 			       skewbRecord[i].score, skewbRecord[i].name);
495 		motif_print(record, buff);
496 	}
497 }
498 
499 static      Boolean
HandleSolved(int counter,Boolean orient)500 HandleSolved(int counter, Boolean orient)
501 {
502 	int         i = (orient) ? 1 : 0;
503 
504 	if (counter < skewbRecord[i].score) {
505 		skewbRecord[i].score = counter;
506 		(void) strcpy(skewbRecord[i].name, usernameDsp);
507 		if (orient && (counter < skewbRecord[!i].score)) {
508 			skewbRecord[!i].score = counter;
509 			(void) strcpy(skewbRecord[!i].name, usernameDsp);
510 		}
511 		WriteRecords();
512 		PrintRecord(orient, False);
513 		return True;
514 	}
515 	return False;
516 }
517 
518 static void
InitRecords(void)519 InitRecords(void)
520 {
521 	int         orient;
522 
523 	for (orient = 0; orient < 2; orient++) {
524 		skewbRecord[orient].score = MAXRECORD;
525 		(void) strcpy(skewbRecord[orient].name, NOACCESS);
526 	}
527 }
528 
529 static void
ReadRecords(void)530 ReadRecords(void)
531 {
532 	FILE       *fp;
533 	int         n, orient;
534 	char        username[USERNAMELEN];
535 
536 	if ((fp = fopen(SCOREFILE, "r")) == NULL) {
537 		(void) sprintf(buff, "Can not open %s, taking defaults.", SCOREFILE);
538 		motif_print(message, buff);
539 	} else {
540 		for (orient = 0; orient < 2; orient++) {
541 			(void) fscanf(fp, "%d %s\n", &n, username);
542 			if (n <= skewbRecord[orient].score) {
543 				skewbRecord[orient].score = n;
544 				(void) strcpy(skewbRecord[orient].name, username);
545 			}
546 		}
547 		(void) fclose(fp);
548 	}
549 }
550 
551 static void
WriteRecords(void)552 WriteRecords(void)
553 {
554 	FILE       *fp;
555 	int         orient;
556 
557 	if ((fp = fopen(SCOREFILE, "w")) == NULL) {
558 		(void) sprintf(buff, "Can not write to %s.", SCOREFILE);
559 		motif_print(message, buff);
560 	} else {
561 #if HAVE_FCNTL_H
562 		int         lfd;
563 		char        lockfile[FILENAMELEN];
564 
565 		(void) strcpy(lockfile, SCOREFILE);
566 		(void) strcat(lockfile, ".lock");
567 		while (((lfd = open(lockfile, O_CREAT | O_EXCL, 0644)) < 0) &&
568 		       errno == EEXIST)
569 			(void) sleep(1);
570 		if (lfd < 0) {
571 #if 1
572 			(void) fprintf(stderr, "Lock file exists... guessing its an old one.\n");
573 #else
574 			(void) fprintf(stderr, "Lock file exists... score not recorded - sorry.\n"
575 				);
576 			return;
577 #endif
578 		}
579 #endif
580 		for (orient = 0; orient < 2; orient++)
581 			(void) fprintf(fp, "%d %s\n",
582 			skewbRecord[orient].score, skewbRecord[orient].name);
583 #if HAVE_FCNTL_H
584 		(void) close(lfd);
585 		(void) unlink(lockfile);
586 #endif
587 		(void) fclose(fp);
588 	}
589 }
590 
591 static void
motif_print(Widget w,char * text)592 motif_print(Widget w, char *text)
593 {
594 	Arg         wargs[1];
595 	XmString    xmstr;
596 
597 	if (!XtIsSubclass(w, xmLabelWidgetClass))
598 		XtError("motif_print() requires a Label Widget");
599 	xmstr = XmStringCreateLtoR(text, XmSTRING_DEFAULT_CHARSET);
600 	XtSetArg(wargs[0], XmNlabelString, xmstr);
601 	XtSetValues(w, wargs, 1);
602 }
603