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