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