1
2 /*-
3 # MOTIF-BASED MASTERBALL(tm)
4 #
5 # xmmball.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/02 Xt/Motif
29 Version 1: 94/09/15 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 <Xm/ToggleBG.h>
59 #include "Mball.h"
60 #include "mball.xbm"
61 #include "mouse-l.xbm"
62 #include "mouse-r.xbm"
63
64 #ifndef SCOREFILE
65 #define SCOREFILE "/usr/games/lib/mball.scores"
66 #endif
67
68 /* The following are in MballP.h also */
69 #define MINWEDGES 2
70 #define MAXWEDGES 12
71 #define MINRINGS 1
72
73 #define MAXRINGS 6
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(Widget w);
86 static void CallbackMball(Widget w, caddr_t clientData, mballCallbackStruct * callData);
87
88 static void PrintRecord(int wedges, int rings, Boolean orient, Boolean practice);
89 static Boolean HandleSolved(int counter, int wedges, int rings, Boolean orient);
90 static void InitRecords(void);
91 static void ReadRecords(void);
92 static void WriteRecords(void);
93
94 static void WedgeToggle(Widget w, int bit, XmToggleButtonCallbackStruct * cbs);
95 static void RingSlider(Widget w, XtPointer clientData, XmScaleCallbackStruct * cbs);
96 static void OrientToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct * cbs);
97 static void PracticeToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct * cbs);
98 static void motif_print(Widget w, char *text);
99
100 static Arg arg[5];
101 static Widget moves, record, message, mball, orientSwitch, practiceSwitch,
102 wedge[(MAXWEDGES - MINWEDGES) / 2 + 1], ring;
103 static GameRecord mballRecord[2][(MAXWEDGES - MINWEDGES) / 2 + 1]
104 [MAXRINGS - MINRINGS + 1];
105 static int movesDsp = 0;
106 static char messageDsp[128] = "Welcome";
107 static char usernameDsp[USERNAMELEN] = "";
108 static char buff[256];
109
110 static char *wedgeString[] =
111 {
112 "Two", "Four", "Six", "Eight", "Ten", "Twelve"
113 };
114
115 static void
usage(void)116 usage(void)
117 {
118 (void) fprintf(stderr, "usage: xmmball\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}] [-wedge{0|1|2|3|4|5|6|7} {color}]\n");
127 (void) fprintf(stderr,
128 "\t[-{wedges {int}}] [-{rings {int}}] [-[no]orient] [-[no]practice]\n");
129 (void) fprintf(stderr,
130 "\t[-base {int}] [-username {string}]\n");
131 exit(1);
132 }
133
134 static XrmOptionDescRec options[] =
135 {
136 {"-mono", "*mball.mono", XrmoptionNoArg, "TRUE"},
137 {"-nomono", "*mball.mono", XrmoptionNoArg, "FALSE"},
138 {"-rv", "*mball.reverse", XrmoptionNoArg, "TRUE"},
139 {"-reverse", "*mball.reverse", XrmoptionNoArg, "TRUE"},
140 {"-norv", "*mball.reverse", XrmoptionNoArg, "FALSE"},
141 {"-noreverse", "*mball.reverse", XrmoptionNoArg, "FALSE"},
142 {"-fg", "*mball.Foreground", XrmoptionSepArg, NULL},
143 {"-foreground", "*mball.Foreground", XrmoptionSepArg, NULL},
144 {"-bg", "*Background", XrmoptionSepArg, NULL},
145 {"-background", "*Background", XrmoptionSepArg, NULL},
146 {"-bd", "*mball.pieceBorder", XrmoptionSepArg, NULL},
147 {"-border", "*mball.pieceBorder", XrmoptionSepArg, NULL},
148 {"-wedge0", "*mball.wedgeColor0", XrmoptionSepArg, NULL},
149 {"-wedge1", "*mball.wedgeColor1", XrmoptionSepArg, NULL},
150 {"-wedge2", "*mball.wedgeColor2", XrmoptionSepArg, NULL},
151 {"-wedge3", "*mball.wedgeColor3", XrmoptionSepArg, NULL},
152 {"-wedge4", "*mball.wedgeColor4", XrmoptionSepArg, NULL},
153 {"-wedge5", "*mball.wedgeColor5", XrmoptionSepArg, NULL},
154 {"-wedge6", "*mball.wedgeColor6", XrmoptionSepArg, NULL},
155 {"-wedge7", "*mball.wedgeColor7", XrmoptionSepArg, NULL},
156 {"-wedges", "*mball.wedges", XrmoptionSepArg, NULL},
157 {"-rings", "*mball.rings", XrmoptionSepArg, NULL},
158 {"-orient", "*mball.orient", XrmoptionNoArg, "TRUE"},
159 {"-noorient", "*mball.orient", XrmoptionNoArg, "FALSE"},
160 {"-practice", "*mball.practice", XrmoptionNoArg, "TRUE"},
161 {"-nopractice", "*mball.practice", XrmoptionNoArg, "FALSE"},
162 {"-base", "*mball.base", XrmoptionSepArg, NULL},
163 {"-username", "*mball.userName", XrmoptionSepArg, NULL}
164 };
165
166 int
main(int argc,char ** argv)167 main(int argc, char **argv)
168 {
169 Widget toplevel;
170 Widget panel, panel2;
171 Widget rowcol, rowcol2, rowcol3, rowcol4, rowcol5, rowcol6;
172 Pixmap mouseLeftCursor, mouseRightCursor;
173 Pixel fg, bg;
174 int i;
175
176 toplevel = XtInitialize(argv[0], "Mball",
177 options, XtNumber(options), &argc, argv);
178 if (argc != 1)
179 usage();
180
181 XtSetArg(arg[0],
182 XtNiconPixmap, XCreateBitmapFromData(XtDisplay(toplevel),
183 RootWindowOfScreen(XtScreen(toplevel)),
184 (char *) mball_bits, mball_width, mball_height));
185 XtSetArg(arg[1], XmNkeyboardFocusPolicy, XmPOINTER); /* not XmEXPLICIT */
186 XtSetValues(toplevel, arg, 2);
187 panel = XtCreateManagedWidget("panel",
188 xmPanedWindowWidgetClass, toplevel, NULL, 0);
189 panel2 = XtVaCreateManagedWidget("panel2",
190 xmPanedWindowWidgetClass, panel,
191 XmNseparatorOn, False,
192 XmNsashWidth, 1,
193 XmNsashHeight, 1, NULL);
194
195 rowcol = XtVaCreateManagedWidget("Rowcol",
196 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", 5, 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("CallbackMball",
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("Rowcol3",
235 xmRowColumnWidgetClass, panel2, NULL);
236 XtVaGetValues(rowcol2,
237 XmNforeground, &fg,
238 XmNbackground, &bg, NULL);
239 rowcol3 = XtVaCreateManagedWidget("Rowcol2",
240 xmRowColumnWidgetClass, rowcol2,
241 XmNnumColumns, 1,
242 XmNorientation, XmHORIZONTAL,
243 XmNpacking, XmPACK_COLUMN,
244 XmNradioBehavior, True, NULL);
245 for (i = 0; i < XtNumber(wedgeString); i++) {
246 wedge[i] = XtVaCreateManagedWidget(wedgeString[i],
247 xmToggleButtonGadgetClass, rowcol3,
248 XmNradioBehavior, True, NULL);
249 XtAddCallback(wedge[i],
250 XmNvalueChangedCallback, (XtCallbackProc) WedgeToggle, (XtPointer) i);
251 }
252 XtVaCreateManagedWidget("WedgeText",
253 xmLabelGadgetClass, rowcol2,
254 XtVaTypedArg, XmNlabelString, XmRString, "Wedges", 7, NULL);
255
256 rowcol4 = XtVaCreateManagedWidget("Rowcol4",
257 xmRowColumnWidgetClass, panel2, NULL);
258 ring = XtVaCreateManagedWidget("ring",
259 xmScaleWidgetClass, rowcol4,
260 XtVaTypedArg, XmNtitleString, XmRString, "Rings", 6,
261 XmNminimum, MINRINGS,
262 XmNmaximum, MAXRINGS,
263 XmNvalue, MINRINGS,
264 XmNshowValue, True,
265 XmNorientation, XmHORIZONTAL, NULL);
266 XtAddCallback(ring,
267 XmNvalueChangedCallback, (XtCallbackProc) RingSlider, (XtPointer) NULL);
268
269 rowcol5 = XtVaCreateManagedWidget("Rowcol5",
270 xmRowColumnWidgetClass, panel2,
271 XmNnumColumns, 1,
272 XmNorientation, XmHORIZONTAL,
273 XmNpacking, XmPACK_COLUMN, NULL);
274 orientSwitch = XtVaCreateManagedWidget("Orient",
275 xmToggleButtonWidgetClass, rowcol5, NULL);
276 XtAddCallback(orientSwitch,
277 XmNvalueChangedCallback, (XtCallbackProc) OrientToggle, (XtPointer) NULL);
278 practiceSwitch = XtVaCreateManagedWidget("Practice",
279 xmToggleButtonWidgetClass, rowcol5, NULL);
280 XtAddCallback(practiceSwitch,
281 XmNvalueChangedCallback, (XtCallbackProc) PracticeToggle, (XtPointer) NULL);
282
283 rowcol6 = XtVaCreateManagedWidget("Rowcol6",
284 xmRowColumnWidgetClass, panel2, NULL);
285 message = XtVaCreateManagedWidget("Play Masterball! (use mouse and keypad)",
286 xmLabelWidgetClass, rowcol6, NULL);
287
288 mball = XtCreateManagedWidget("mball",
289 mballWidgetClass, panel, NULL, 0);
290 XtAddCallback(mball,
291 XtNselectCallback, (XtCallbackProc) CallbackMball, (XtPointer) NULL);
292 Initialize(mball);
293 XtRealizeWidget(toplevel);
294 XGrabButton(XtDisplay(mball), (unsigned int) AnyButton, AnyModifier,
295 XtWindow(mball), TRUE,
296 (unsigned int) (ButtonPressMask | ButtonMotionMask | ButtonReleaseMask),
297 GrabModeAsync, GrabModeAsync, XtWindow(mball),
298 XCreateFontCursor(XtDisplay(mball), XC_crosshair));
299 XtMainLoop();
300
301 #ifdef VMS
302 return 1;
303 #else
304 return 0;
305 #endif
306 }
307
308 static void
Initialize(Widget w)309 Initialize(Widget w)
310 {
311 int wedges, rings;
312 Boolean orient, practice;
313 String username;
314
315 XtVaSetValues(w,
316 XtNstart, False, NULL);
317 XtVaGetValues(w,
318 XtNuserName, &username,
319 XtNwedges, &wedges,
320 XtNrings, &rings,
321 XtNorient, &orient,
322 XtNpractice, &practice, NULL);
323 XmToggleButtonSetState(wedge[(wedges - MINWEDGES) / 2], True, False);
324 if (rings <= MAXRINGS)
325 XmScaleSetValue(ring, rings);
326 XmToggleButtonSetState(orientSwitch, orient, True);
327 XmToggleButtonSetState(practiceSwitch, practice, True);
328 InitRecords();
329 ReadRecords();
330 (void) strcpy(usernameDsp, username);
331 if (!strcmp(usernameDsp, "") || !strcmp(usernameDsp, NOACCESS) ||
332 !strcmp(usernameDsp, NOBODY)) {
333 /* The NOACCESS is not necasary, but it stops people from being cute. */
334 (void) sprintf(usernameDsp, "%s", getlogin());
335 if (!strcmp(usernameDsp, "") || !strcmp(usernameDsp, NOACCESS))
336 (void) sprintf(usernameDsp, "%s", NOBODY); /* It really IS nobody */
337 }
338 PrintRecord(wedges, rings, orient, practice);
339 }
340
341 static void
CallbackMball(Widget w,caddr_t clientData,mballCallbackStruct * callData)342 CallbackMball(Widget w, caddr_t clientData, mballCallbackStruct * callData)
343 {
344 int wedges, rings;
345 Boolean orient, practice, start;
346
347 XtVaGetValues(w,
348 XtNwedges, &wedges,
349 XtNrings, &rings,
350 XtNorient, &orient,
351 XtNpractice, &practice,
352 XtNstart, &start, NULL);
353 (void) strcpy(messageDsp, "");
354 switch (callData->reason) {
355 case MBALL_RESTORE:
356 if (practice)
357 motif_print(record, "practice");
358 movesDsp = 0;
359 break;
360 case MBALL_RESET:
361 movesDsp = 0;
362 break;
363 case MBALL_AMBIGUOUS:
364 (void) strcpy(messageDsp, "Ambiguous move");
365 break;
366 case MBALL_ILLEGAL:
367 if (practice || start)
368 (void) strcpy(messageDsp, "Illegal move");
369 else
370 (void) strcpy(messageDsp, "Randomize to start");
371 break;
372 case MBALL_MOVED:
373 movesDsp++;
374 XtSetArg(arg[0], XtNstart, True);
375 XtSetValues(w, arg, 1);
376 break;
377 case MBALL_CONTROL:
378 return;
379 case MBALL_SOLVED:
380 if (practice)
381 movesDsp = 0;
382 else {
383 if (HandleSolved(movesDsp, wedges, rings, orient))
384 (void) sprintf(messageDsp, "Congratulations %s!!", usernameDsp);
385 else
386 (void) strcpy(messageDsp, "Solved!");
387 }
388 XtSetArg(arg[0], XtNstart, False);
389 XtSetValues(w, arg, 1);
390 break;
391 case MBALL_PRACTICE:
392 movesDsp = 0;
393 practice = !practice;
394 if (!practice)
395 (void) strcpy(messageDsp, "Randomize to start");
396 PrintRecord(wedges, rings, orient, practice);
397 XtSetArg(arg[0], XtNpractice, practice);
398 XtSetArg(arg[1], XtNstart, False);
399 XtSetValues(w, arg, 2);
400 XmToggleButtonSetState(practiceSwitch, practice, True);
401 break;
402 case MBALL_RANDOMIZE:
403 movesDsp = 0;
404 XtSetArg(arg[0], XtNpractice, False);
405 XtSetArg(arg[1], XtNstart, False);
406 XtSetValues(w, arg, 2);
407 break;
408 case MBALL_DEC:
409 movesDsp = 0;
410 rings--;
411 PrintRecord(wedges, rings, orient, practice);
412 XtSetArg(arg[0], XtNrings, rings);
413 XtSetValues(w, arg, 1);
414 if (rings <= MAXRINGS)
415 XmScaleSetValue(ring, rings);
416 break;
417 case MBALL_ORIENT:
418 movesDsp = 0;
419 orient = !orient;
420 PrintRecord(wedges, rings, orient, practice);
421 XtSetArg(arg[0], XtNorient, orient);
422 XtSetValues(w, arg, 1);
423 XmToggleButtonSetState(orientSwitch, orient, True);
424 break;
425 case MBALL_INC:
426 movesDsp = 0;
427 rings++;
428 PrintRecord(wedges, rings, orient, practice);
429 XtSetArg(arg[0], XtNrings, rings);
430 XtSetValues(w, arg, 1);
431 if (rings <= MAXRINGS)
432 XmScaleSetValue(ring, rings);
433 break;
434 case MBALL_WEDGE2:
435 case MBALL_WEDGE4:
436 case MBALL_WEDGE6:
437 case MBALL_WEDGE8:
438 case MBALL_WEDGE10:
439 case MBALL_WEDGE12:
440 movesDsp = 0;
441 wedges = 2 * (callData->reason - MBALL_WEDGE2) + MINWEDGES;
442 PrintRecord(wedges, rings, orient, practice);
443 XtSetArg(arg[0], XtNwedges, wedges);
444 XtSetValues(w, arg, 1);
445 XmToggleButtonSetState(wedge[(wedges - MINWEDGES) / 2], True, True);
446 break;
447 case MBALL_COMPUTED:
448 XtSetArg(arg[0], XtNstart, False);
449 XtSetValues(w, arg, 1);
450 break;
451 case MBALL_UNDO:
452 movesDsp--;
453 XtSetArg(arg[0], XtNstart, True);
454 XtSetValues(w, arg, 1);
455 break;
456 }
457 motif_print(message, messageDsp);
458 (void) sprintf(buff, "%d", movesDsp);
459 motif_print(moves, buff);
460 }
461
462 static void
WedgeToggle(Widget w,int bit,XmToggleButtonCallbackStruct * cbs)463 WedgeToggle(Widget w, int bit, XmToggleButtonCallbackStruct * cbs)
464 {
465 int wedges, rings;
466 Boolean orient, practice;
467
468 if (cbs->set) {
469 XtVaGetValues(mball,
470 XtNrings, &rings,
471 XtNorient, &orient,
472 XtNpractice, &practice, NULL);
473 wedges = bit * 2 + MINWEDGES;
474 XtVaSetValues(mball,
475 XtNwedges, wedges, NULL);
476 movesDsp = 0;
477 (void) sprintf(buff, "%d", movesDsp);
478 motif_print(moves, buff);
479 PrintRecord(wedges, rings, orient, practice);
480 }
481 }
482
483 static void
RingSlider(Widget w,XtPointer clientData,XmScaleCallbackStruct * cbs)484 RingSlider(Widget w, XtPointer clientData, XmScaleCallbackStruct * cbs)
485 {
486 int wedges, rings = cbs->value, old;
487 Boolean orient, practice;
488
489 XtVaGetValues(mball,
490 XtNwedges, &wedges,
491 XtNrings, &old,
492 XtNorient, &orient,
493 XtNpractice, &practice, NULL);
494 if (old != rings) {
495 XtVaSetValues(mball,
496 XtNrings, rings, NULL);
497 movesDsp = 0;
498 (void) sprintf(buff, "%d", movesDsp);
499 motif_print(moves, buff);
500 PrintRecord(wedges, rings, orient, practice);
501 }
502 }
503
504 static void
OrientToggle(Widget w,XtPointer clientData,XmToggleButtonCallbackStruct * cbs)505 OrientToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct * cbs)
506 {
507 int wedges, rings;
508 Boolean orient = cbs->set, practice;
509
510 XtVaSetValues(mball,
511 XtNorient, orient, NULL);
512 XtVaGetValues(mball,
513 XtNwedges, &wedges,
514 XtNrings, &rings,
515 XtNpractice, &practice, NULL);
516 movesDsp = 0;
517 (void) sprintf(buff, "%d", movesDsp);
518 motif_print(moves, buff);
519 PrintRecord(wedges, rings, orient, practice);
520 }
521
522 static void
PracticeToggle(Widget w,XtPointer clientData,XmToggleButtonCallbackStruct * cbs)523 PracticeToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct * cbs)
524 {
525 int wedges, rings;
526 Boolean orient, practice = cbs->set;
527
528 XtVaSetValues(mball,
529 XtNpractice, practice,
530 XtNstart, False, NULL);
531 XtVaGetValues(mball,
532 XtNwedges, &wedges,
533 XtNrings, &rings,
534 XtNorient, &orient, NULL);
535 movesDsp = 0;
536 (void) sprintf(buff, "%d", movesDsp);
537 motif_print(moves, buff);
538 if (!practice)
539 (void) strcpy(messageDsp, "Randomize to start");
540 PrintRecord(wedges, rings, orient, practice);
541 }
542
543 static void
PrintRecord(int wedges,int rings,Boolean orient,Boolean practice)544 PrintRecord(int wedges, int rings, Boolean orient, Boolean practice)
545 {
546 int i = (orient) ? 1 : 0;
547 int w = (wedges - MINWEDGES) / 2;
548 int r = rings - MINRINGS;
549
550 if (practice)
551 motif_print(record, "practice");
552 else if (rings > MAXRINGS)
553 motif_print(record, "NOT RECORDED");
554 else if (mballRecord[i][w][r].score >= MAXRECORD) {
555 (void) sprintf(buff, "NEVER %s", NOACCESS);
556 motif_print(record, buff);
557 } else {
558 (void) sprintf(buff, "%d %s",
559 mballRecord[i][w][r].score, mballRecord[i][w][r].name);
560 motif_print(record, buff);
561 }
562 }
563
564 static Boolean
HandleSolved(int counter,int wedges,int rings,Boolean orient)565 HandleSolved(int counter, int wedges, int rings, Boolean orient)
566 {
567 int i = (orient) ? 1 : 0;
568 int w = (wedges - MINWEDGES) / 2;
569 int r = rings - MINRINGS;
570
571 if (rings <= MAXRINGS && counter < mballRecord[i][w][r].score) {
572 mballRecord[i][w][r].score = counter;
573 (void) strcpy(mballRecord[i][w][r].name, usernameDsp);
574 if (orient && counter < mballRecord[!i][w][r].score) {
575 mballRecord[!i][w][r].score = counter;
576 (void) strcpy(mballRecord[!i][w][r].name, usernameDsp);
577 }
578 WriteRecords();
579 PrintRecord(wedges, rings, orient, False);
580 return True;
581 }
582 return False;
583 }
584
585 static void
InitRecords(void)586 InitRecords(void)
587 {
588 int i, j, orient;
589
590 for (orient = 0; orient < 2; orient++)
591 for (i = 0; i < (MAXWEDGES - MINWEDGES) / 2 + 1; i++)
592 for (j = 0; j < MAXRINGS - MINRINGS + 1; j++) {
593 mballRecord[orient][i][j].score = MAXRECORD;
594 (void) strcpy(mballRecord[orient][i][j].name, NOACCESS);
595 }
596 }
597
598
599 static void
ReadRecords(void)600 ReadRecords(void)
601 {
602 FILE *fp;
603 int i, j, n, orient;
604 char username[USERNAMELEN];
605
606 if ((fp = fopen(SCOREFILE, "r")) == NULL) {
607 (void) sprintf(buff, "Can not open %s, taking defaults.", SCOREFILE);
608 motif_print(message, buff);
609 } else {
610 for (orient = 0; orient < 2; orient++)
611 for (i = 0; i < (MAXWEDGES - MINWEDGES) / 2 + 1; i++)
612 for (j = 0; j < MAXRINGS - MINRINGS + 1; j++) {
613 (void) fscanf(fp, "%d %s\n", &n, username);
614 if (n <= mballRecord[orient][i][j].score) {
615 mballRecord[orient][i][j].score = n;
616 (void) strcpy(mballRecord[orient][i][j].name, username);
617 }
618 }
619 (void) fclose(fp);
620 }
621 }
622
623 static void
WriteRecords(void)624 WriteRecords(void)
625 {
626 FILE *fp;
627 int i, j, orient;
628
629 ReadRecords(); /* Maybe its been updated by another */
630 if ((fp = fopen(SCOREFILE, "w")) == NULL) {
631 (void) sprintf(buff, "Can not write to %s.", SCOREFILE);
632 motif_print(message, buff);
633 } else {
634 #if HAVE_FCNTL_H
635 int lfd;
636 char lockfile[FILENAMELEN];
637
638 (void) strcpy(lockfile, SCOREFILE);
639 (void) strcat(lockfile, ".lock");
640 while (((lfd = open(lockfile, O_CREAT | O_EXCL, 0644)) < 0) &&
641 errno == EEXIST)
642 (void) sleep(1);
643 if (lfd < 0) {
644 #if 1
645 (void) fprintf(stderr, "Lock file exists... guessing its an old one.\n");
646 #else
647 (void) fprintf(stderr, "Lock file exists... score not recorded - sorry.\n"
648 );
649 return;
650 #endif
651 }
652 #endif
653 for (orient = 0; orient < 2; orient++) {
654 for (i = 0; i < (MAXWEDGES - MINWEDGES) / 2 + 1; i++) {
655 for (j = 0; j < MAXRINGS - MINRINGS + 1; j++)
656 (void) fprintf(fp, "%d %s\n",
657 mballRecord[orient][i][j].score, mballRecord[orient][i][j].name);
658 (void) fprintf(fp, "\n");
659 }
660 (void) fprintf(fp, "\n");
661 }
662 #if HAVE_FCNTL_H
663 (void) close(lfd);
664 (void) unlink(lockfile);
665 #endif
666 (void) fclose(fp);
667 }
668 }
669
670 static void
motif_print(Widget w,char * text)671 motif_print(Widget w, char *text)
672 {
673 Arg wargs[1];
674 XmString xmstr;
675
676 if (!XtIsSubclass(w, xmLabelWidgetClass))
677 XtError("motif_print() requires a Label Widget");
678 xmstr = XmStringCreateLtoR(text, XmSTRING_DEFAULT_CHARSET);
679 XtSetArg(wargs[0], XmNlabelString, xmstr);
680 XtSetValues(w, wargs, 1);
681 }
682