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