~ubuntu-branches/ubuntu/trusty/xshisen/trusty-proposed

« back to all changes in this revision

Viewing changes to score.C

  • Committer: Bazaar Package Importer
  • Author(s): Steve Kemp
  • Date: 2003-10-28 13:49:29 UTC
  • Revision ID: james.westby@ubuntu.com-20031028134929-mbcy7vcl9z5gg9t3
Tags: 1.51-1-1
* Non-maintainer upload with consent from Grzegorz.
* Fix a locally exploitable buffer overflow allowing GID(games).
  (Closes: #213957)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <pwd.h>
 
2
#include "components.h"
 
3
#include "kconv.h"
 
4
 
 
5
XtResource Score::resources[] = {
 
6
    { "scoreTitle",  "ScoreTitle",  XtRString, sizeof(char *),
 
7
      0*sizeof(char *), XtRString, (XtPointer)"XShisen High Score\n\n" },
 
8
    { "scoreFormat", "ScoreFormat", XtRString, sizeof(char *),
 
9
      1*sizeof(char *), XtRString, (XtPointer)"%2d  %2.2d:%2.2d:%2.2d  %-28s  %s %s\n" },
 
10
    { "strPeriod", "StrPeriod", XtRString, sizeof(char *),
 
11
      2*sizeof(char *), XtRString, (XtPointer)"Last %d days" },
 
12
    { "averagePeriod", "AveragePeriod", XtRString, sizeof(char *),
 
13
      3*sizeof(char *), XtRString, (XtPointer)"14" },
 
14
    { "strPlayed", "StrPlayed", XtRString, sizeof(char *),
 
15
      4*sizeof(char *), XtRString, (XtPointer)"Played" },
 
16
    { "strCompleted", "StrCompleted", XtRString, sizeof(char *),
 
17
      5*sizeof(char *), XtRString, (XtPointer)"Completed" },
 
18
    { "strTedumari", "StrTedumari", XtRString, sizeof(char *),
 
19
      6*sizeof(char *), XtRString, (XtPointer)"Deadlocked" },
 
20
    { "strSearched", "StrSearched", XtRString, sizeof(char *),
 
21
      7*sizeof(char *), XtRString, (XtPointer)"Search used" },
 
22
    { "strGiveUp", "StrGiveUp", XtRString, sizeof(char *),
 
23
      8*sizeof(char *), XtRString, (XtPointer)"Given up" },
 
24
    { "strTotal", "StrTotal", XtRString, sizeof(char *),
 
25
      9*sizeof(char *), XtRString, (XtPointer)"Total" },
 
26
    { "strAverage", "StrAverage", XtRString, sizeof(char *),
 
27
      10*sizeof(char *), XtRString, (XtPointer)"Whole Average" },
 
28
    { "strGames", "StrGames", XtRString, sizeof(char *),
 
29
      11*sizeof(char *), XtRString, (XtPointer)"games" },
 
30
    { "personalTitle", "PersonalTitle", XtRString, sizeof(char *),
 
31
      12*sizeof(char *), XtRString, (XtPointer)"Personal Statistics for %s" }
 
32
};
 
33
 
 
34
void
 
35
ScoreRecord::SetDefault(void)
 
36
{
 
37
    strcpy(name, "                            ");
 
38
    hour = 99;
 
39
    min  = 99;
 
40
    sec  = 99;
 
41
    strcpy(date, "00-00-00");
 
42
    strcpy(time, "00:00:00");
 
43
}
 
44
 
 
45
void
 
46
ScoreRecord::ReadField(FILE *fp, int kanjiCode, int &offset)
 
47
{
 
48
    char buffer[64];
 
49
 
 
50
    if (fread((void*)buffer,  sizeof(char), 64, fp) != 64 ||
 
51
        buffer[0] == '\0') {
 
52
        SetDefault();
 
53
        return;
 
54
    }
 
55
    for(int i=0; i<64; i++) {
 
56
        buffer[i] = ((buffer[i] - offset - i) & 0xff);
 
57
    }
 
58
    offset += 64;
 
59
    strncpy(name, buffer, 28);
 
60
    name[28] = '\0';
 
61
    switch(kanjiCode) {
 
62
    case 1:
 
63
        strcpy(name, sjis_to_euc(name));
 
64
        break;
 
65
    case 2:
 
66
        strcpy(name, sjis_to_jis(name));
 
67
        break;
 
68
    }
 
69
    hour = atoi(&buffer[35]);
 
70
    min  = atoi(&buffer[38]);
 
71
    sec  = atoi(&buffer[41]);
 
72
    strncpy(date, &buffer[44], 8);
 
73
    date[8] = '\0';
 
74
    strncpy(time, &buffer[53], 8);
 
75
    time[8] = '\0';
 
76
    if (date[0] == '1') {
 
77
        for(int i=1; i<8; i++) {
 
78
            date[i-1] = date[i];
 
79
        }
 
80
        date[7] = date[6] == '0' ? '1' : '0';
 
81
    }
 
82
}
 
83
 
 
84
void
 
85
ScoreRecord::WriteField(FILE *fp, int kanjiCode, int &cr_offset, int cr)
 
86
{
 
87
    char buffer[64];
 
88
 
 
89
    switch(kanjiCode) {
 
90
    case 1:
 
91
        strcpy(buffer, euc_to_sjis(name));
 
92
        break;
 
93
    case 2:
 
94
        strcpy(buffer, jis_to_sjis(name));
 
95
        break;
 
96
    default:
 
97
        strcpy(buffer, name);
 
98
        break;
 
99
    }
 
100
    buffer[28] = ' ';
 
101
    strncpy(&buffer[29], "X" XSHISEN_VERSION, 5);
 
102
    buffer[34] = ' ';
 
103
    sprintf(&buffer[35], "%2.2d:%2.2d:%2.2d", hour, min, sec);
 
104
    buffer[43] = ' ';
 
105
    strncpy(&buffer[44], date, 8);
 
106
    buffer[52] = ' ';
 
107
    strncpy(&buffer[53], time, 8);
 
108
    buffer[61] = ' ';
 
109
    buffer[62] = '\r';
 
110
    buffer[63] = '\n';
 
111
    if (cr) {
 
112
        for(int i=0; i<64; i++) {
 
113
            buffer[i] = ((buffer[i] + cr_offset + i) & 0xff);
 
114
        }
 
115
        cr_offset += 64;
 
116
    }
 
117
    fwrite((void*)buffer, sizeof(char), 64, fp);
 
118
}
 
119
 
 
120
void
 
121
Score::retry_button(Widget w, XtPointer client_data)
 
122
{
 
123
    Score *p = (Score *)client_data;
 
124
#if USE_MOTIF
 
125
    XtUnmanageChild(w);
 
126
#else /* USE_MOTIF */
 
127
    XtPopdown(p->mdialog);
 
128
#endif /* USE_MOTIF */
 
129
    p->Register();
 
130
}
 
131
 
 
132
void
 
133
Score::abandon_button(Widget w, XtPointer client_data)
 
134
{
 
135
    Score *p = (Score *)client_data;
 
136
#if USE_MOTIF
 
137
    XtUnmanageChild(w);
 
138
#else /* USE_MOTIF */
 
139
    XtPopdown(p->mdialog);
 
140
#endif /* USE_MOTIF */
 
141
    p->DisplayScore(p->game);
 
142
}
 
143
 
 
144
void
 
145
Score::problem(void)
 
146
{
 
147
#if USE_MOTIF
 
148
    if (!mdialog_exist) {
 
149
        mdialog = XmCreateWarningDialog(toplevel, "mdialog", NULL, 0);
 
150
        XtAddCallback(mdialog, XmNokCallback,
 
151
                      (XtCallbackProc)retry_button,
 
152
                      (XtPointer)this);
 
153
        XtAddCallback(mdialog, XmNcancelCallback,
 
154
                      (XtCallbackProc)abandon_button,
 
155
                      (XtPointer)this);
 
156
        mdialog_exist = 1;
 
157
        XtUnmanageChild(XmMessageBoxGetChild(mdialog, XmDIALOG_HELP_BUTTON));
 
158
    }
 
159
    XtManageChild(mdialog);
 
160
#else /* USE_MOTIF */
 
161
    if (!mdialog_exist) {
 
162
        Widget form, label, b1, b2;
 
163
        Position x, y;
 
164
        XtVaGetValues(toplevel, XtNx, &x, XtNy, &y, NULL);
 
165
        mdialog = XtVaCreatePopupShell("mdialog_popup", transientShellWidgetClass,
 
166
                                       toplevel,
 
167
                                       XtNx, x+10,
 
168
                                       XtNy, y+10,
 
169
                                       NULL);
 
170
        form = XtVaCreateManagedWidget("mdialog", formWidgetClass, mdialog,
 
171
                                       NULL);
 
172
        label = XtVaCreateManagedWidget("label", labelWidgetClass, form,
 
173
                                        XtNresizable, True,
 
174
                                        NULL);
 
175
        b1 = XtVaCreateManagedWidget("ok_button", commandWidgetClass, form,
 
176
                                     XtNfromVert, label,
 
177
                                     NULL);
 
178
        b2 = XtVaCreateManagedWidget("cancel_button", commandWidgetClass, form,
 
179
                                     XtNfromVert,  label,
 
180
                                     XtNfromHoriz, b1,
 
181
                                     NULL);
 
182
        XtAddCallback(b1, XtNcallback,
 
183
                      (XtCallbackProc)retry_button,
 
184
                      (XtPointer)this);
 
185
        XtAddCallback(b2, XtNcallback,
 
186
                      (XtCallbackProc)abandon_button,
 
187
                      (XtPointer)this);
 
188
        mdialog_exist = 1;
 
189
    }
 
190
    XtPopup(mdialog, XtGrabNone);
 
191
#endif /* USE_MOTIF */
 
192
}
 
193
 
 
194
void
 
195
Score::readfile(void)
 
196
{
 
197
    FILE *fp = fopen(filename, "r");
 
198
    int offset;
 
199
 
 
200
    if (fp == NULL) {
 
201
        for(int i=0; i<SCORENUM; i++) {
 
202
            rec[i].SetDefault();
 
203
        }
 
204
        return;
 
205
    }
 
206
    if (fseek(fp, 1344*game+704, SEEK_SET) != 0)
 
207
        fseek(fp, 0, SEEK_END);
 
208
    offset = 1;
 
209
    for(int i=0; i<SCORENUM; i++){
 
210
        rec[i].ReadField(fp, kanjiCode, offset);
 
211
    }
 
212
    fclose(fp);
 
213
}
 
214
 
 
215
int
 
216
Score::writefile(void)
 
217
{
 
218
    static const char filler[] = "\032"
 
219
        "                                                               ";
 
220
    FILE *fp = fopen(filename, "r+");
 
221
    int offset;
 
222
    int i;
 
223
 
 
224
    if (fp == NULL) {
 
225
        problem();
 
226
        return 1; // fail!
 
227
    }
 
228
    offset = 1;
 
229
    fseek(fp, 1344*game, SEEK_SET);
 
230
    for(i=0; i<SCORENUM; i++) {
 
231
        rec[i].WriteField(fp, kanjiCode, offset);
 
232
    }
 
233
    fwrite((void*)filler, sizeof(filler)-1, 1, fp);
 
234
    for(i=0; i<SCORENUM; i++) {
 
235
        rec[i].WriteField(fp, kanjiCode, offset, 1);
 
236
    }
 
237
    fclose(fp);
 
238
    return 0; // no problem
 
239
}
 
240
 
 
241
Score::Score(Widget parent)
 
242
{
 
243
#if USE_MOTIF
 
244
    score = XmCreateMessageDialog(parent, "score", NULL, 0);
 
245
    XtAddCallback(score, XmNokCallback, (XtCallbackProc)PopDownCB, NULL);
 
246
    XtUnmanageChild(XmMessageBoxGetChild(score, XmDIALOG_CANCEL_BUTTON));
 
247
    XtUnmanageChild(XmMessageBoxGetChild(score, XmDIALOG_HELP_BUTTON));
 
248
#else /* USE_MOTIF */
 
249
    Widget form, label, button;
 
250
    score = XtVaCreatePopupShell("score", transientShellWidgetClass, parent,
 
251
                                 XtNallowShellResize, True,
 
252
                                 NULL);
 
253
    form = XtVaCreateManagedWidget("mf", formWidgetClass, score,
 
254
                                   NULL);
 
255
    label = XtVaCreateManagedWidget("label", labelWidgetClass, form,
 
256
                                    XtNresizable, True,
 
257
                                    XtNtop,       XawChainTop,
 
258
                                    XtNbottom,    XawChainBottom,
 
259
                                    XtNleft,      XawRubber,
 
260
                                    XtNright,     XawRubber,
 
261
                                    NULL);
 
262
    button = XtVaCreateManagedWidget("ok_button", commandWidgetClass, form,
 
263
                                     XtNfromVert, label,
 
264
                                     XtNtop,      XawChainTop,
 
265
                                     XtNbottom,   XawChainTop,
 
266
                                     XtNleft,     XawChainLeft,
 
267
                                     XtNright,    XawChainLeft,
 
268
                                     XtNlabel,    "OK",
 
269
                                     NULL);
 
270
    XtAddCallback(button, XtNcallback, (XtCallbackProc)PopDownCB, (XtPointer)score);
 
271
#endif /* USE_MOTIF */
 
272
    mdialog_exist = 0;
 
273
    first_call = 1;
 
274
}
 
275
 
 
276
void
 
277
Score::Popup(String str)
 
278
{
 
279
#if USE_MOTIF
 
280
    XmString mstr = XmStringCreateLtoR(str, XmFONTLIST_DEFAULT_TAG);
 
281
    XtVaSetValues(score,
 
282
                  XmNmessageString, mstr,
 
283
                  NULL);
 
284
    XmStringFree(mstr);
 
285
    XtManageChild(score);
 
286
#else /* USE_MOTIF */
 
287
    XtVaSetValues(XtNameToWidget(score, "*label"),
 
288
                  XtNlabel, str,
 
289
                  NULL);
 
290
    XtPopup(score, XtGrabNone);
 
291
#endif /* USE_MOTIF */
 
292
}
 
293
 
 
294
void
 
295
Score::SetScoreFile(const char *scorefile, const char *kcode, const char *personal)
 
296
{
 
297
    char *home;
 
298
 
 
299
    filename = strdup(scorefile);
 
300
    home = getenv("HOME");
 
301
    if (home == NULL)
 
302
        home = ".";
 
303
    logfile = new char[strlen(home)+strlen(personal)+2];
 
304
    sprintf(logfile, "%s/%s", home, personal);
 
305
 
 
306
    if (strcasecmp(kcode, "euc") == 0)
 
307
        kanjiCode = 1;
 
308
    else if (strcasecmp(kcode, "jis") == 0)
 
309
        kanjiCode = 2;
 
310
    else
 
311
        kanjiCode = 0;
 
312
}
 
313
 
 
314
void
 
315
Score::do_first_call(void)
 
316
{
 
317
    XtVaGetApplicationResources(score, (XtPointer)res_strings,
 
318
                                resources, XtNumber(resources), NULL);
 
319
    first_call = 0;
 
320
#if !USE_MOTIF
 
321
    Position x, y;
 
322
    XtVaGetValues(toplevel, XtNx, &x, XtNy, &y, NULL);
 
323
    XtVaSetValues(score, XtNx, x+10, XtNy, y+10, NULL);
 
324
#endif /* !USE_MOTIF */
 
325
}
 
326
 
 
327
void
 
328
Score::DisplayScore(int kind_of_game)
 
329
{
 
330
    char format[SCORENUM*80+20], buff[SCORENUM*80];
 
331
    long prev_time, this_time;
 
332
    int  num;
 
333
 
 
334
    game = kind_of_game;
 
335
    if (first_call) {
 
336
        do_first_call();
 
337
    }
 
338
    // Always read the latest high score
 
339
    readfile();
 
340
    sprintf(format, res_strings[0]);
 
341
    prev_time = -1;
 
342
    for(int i=0; i<SCORENUM; i++) {
 
343
        this_time = rec[i].hour * 3600 + rec[i].min * 60 + rec[i].sec;
 
344
        if (this_time == prev_time)
 
345
            num++;
 
346
        else
 
347
            num = 0;
 
348
        prev_time = this_time;
 
349
        sprintf(buff, res_strings[1], i+1-num, rec[i].hour, rec[i].min, rec[i].sec,
 
350
                rec[i].name, rec[i].date, rec[i].time);
 
351
        strcat(format, buff);
 
352
    }
 
353
    Popup(format);
 
354
}
 
355
 
 
356
// Convert milisecond data into hour:minute:second
 
357
void
 
358
Score::ms_to_hms(int ms, unsigned char &h, unsigned char &m, unsigned char &s)
 
359
{
 
360
    h = ms/3600000;
 
361
    m = ms/60000 - h*60;
 
362
    s = (ms/1000)%60;
 
363
}
 
364
 
 
365
// Call Score::SetScore formerly!
 
366
void
 
367
Score::Register(void)
 
368
{
 
369
    unsigned char m, s, h;
 
370
    int    s1, i, mybest;
 
371
    int    inspos;
 
372
    time_t t;
 
373
    struct tm *tp;
 
374
    struct passwd *pw;
 
375
    char   namebuf[128], myname[NAMELEN+1], gecos[128], *po;
 
376
 
 
377
    s1 = scoreToRegister / 1000;
 
378
    ms_to_hms(scoreToRegister, h, m, s);
 
379
    pw = getpwuid(getuid());
 
380
    strcpy(gecos, pw->pw_gecos);
 
381
    if ((po = strchr(gecos, ',')) != NULL)
 
382
        *po = 0;
 
383
    sprintf(namebuf, "%-8.8s (%s)", pw->pw_name, gecos);
 
384
    sprintf(myname, "%-28.28s", namebuf);
 
385
    // Always read the latest high score
 
386
    readfile();
 
387
 
 
388
    // Get my best score in past
 
389
    mybest = SCORENUM;
 
390
#if !ALLOW_DUPSCORE
 
391
    for(i=0; i<SCORENUM; i++) {
 
392
        if (strcmp(myname, rec[i].name) == 0) {
 
393
            mybest = i;
 
394
            break;
 
395
        }
 
396
    }
 
397
#endif /* !ALLOW_DUPSCORE */
 
398
 
 
399
    // Check if this score values as high score
 
400
    inspos = SCORENUM;
 
401
    for(i=0; i<SCORENUM; i++) {
 
402
        int sx = rec[i].hour * 3600 + rec[i].min * 60 + rec[i].sec;
 
403
        if (s1 < sx) {
 
404
            inspos = i;
 
405
            break;
 
406
        }
 
407
    }
 
408
    if (inspos == SCORENUM || mybest < inspos) {
 
409
        return;  // Not high score!
 
410
    }
 
411
 
 
412
    for(i=mybest; i>inspos; i--) {
 
413
        if (i>=SCORENUM) continue;
 
414
        rec[i] = rec[i-1];
 
415
    }
 
416
 
 
417
    rec[inspos].hour = h;
 
418
    rec[inspos].min  = m;
 
419
    rec[inspos].sec  = s;
 
420
    strcpy(rec[inspos].name, myname);
 
421
    time(&t);
 
422
    tp = localtime(&t);
 
423
    sprintf(rec[i].date, "%2.2d-%2.2d-%2.2d", tp->tm_year%100, tp->tm_mon+1, tp->tm_mday);
 
424
    sprintf(rec[i].time, "%2.2d:%2.2d:%2.2d", tp->tm_hour, tp->tm_min, tp->tm_sec);
 
425
    if (writefile() == 0)
 
426
        DisplayScore(game);
 
427
}
 
428
 
 
429
void
 
430
Score::LogRecord(int flag, int result, int gamesize, int level, int rest)
 
431
// flag: 0=giveup 1=finished 2=finish+help 3=tedumari
 
432
{
 
433
    FILE       *stream;
 
434
    time_t     t;
 
435
    struct tm  *tp;
 
436
    int        check_digit;
 
437
 
 
438
    stream = fopen(logfile, "a");
 
439
    if (stream == NULL)
 
440
        return; /* Just do not record, no notifying */
 
441
    time(&t);
 
442
    tp = localtime(&t);
 
443
    check_digit = flag*3 + gamesize + level*7 + (tp->tm_year%100)*3 + rest*7
 
444
        + tp->tm_mon*7 + tp->tm_mday*3 + tp->tm_hour*7 + tp->tm_min*3 + tp->tm_sec;
 
445
    check_digit %= 857;
 
446
    fprintf(stream, "%2.2d%2.2d%8.8d%2.2d%1.1d%2.2d%4.4d%2.2d%3.3d%3.3d%2.2d%2.2d\n",
 
447
            flag,
 
448
            tp->tm_sec, result, tp->tm_min, gamesize, tp->tm_year%100, level, tp->tm_mon,
 
449
            check_digit, rest, tp->tm_mday, tp->tm_hour);
 
450
    fclose(stream);
 
451
}
 
452
 
 
453
int
 
454
Score::PersonalStat(int kind_of_game)
 
455
{
 
456
    FILE *s;
 
457
    char buf[4096], *bufp, xb[128];
 
458
    char scorebuf[SCORENUM*2+1][128];
 
459
    int  sec, min, hour, day, month, year;
 
460
    int  g, f, c1, c2, l, t;
 
461
    int  rest;
 
462
    int  w1[2][4], w2[2][4], w3[2][4]; // for average
 
463
    int  i;
 
464
    struct tm tb;
 
465
    unsigned char t1, t2, t3;
 
466
    time_t    tm1, tm2;
 
467
    struct passwd *pw;
 
468
 
 
469
    game = kind_of_game;
 
470
    time(&tm2);  // Time of now
 
471
    if (first_call) {
 
472
        do_first_call();
 
473
    }
 
474
    tm2 -= 86400 * atoi(res_strings[3]);
 
475
    s = fopen(logfile, "r");
 
476
    if (s == NULL)
 
477
        return -1;
 
478
    for(i=0; i<SCORENUM*2; i++)
 
479
        strcpy(scorebuf[i], "99:99:99 (  0) [00-00-00 00:00:00]");
 
480
    memset(w1, 0, 2*4*sizeof(int));
 
481
    memset(w2, 0, 2*4*sizeof(int));
 
482
    memset(w3, 0, 2*4*sizeof(int));
 
483
    while(fgets(buf, 128, s) != NULL) {
 
484
        switch(strlen(buf)) {
 
485
        case 31:
 
486
            // Just for compatibility with xshisen 1.10
 
487
            f     = atoiSubstring(buf +  0, 2);
 
488
            sec   = atoiSubstring(buf +  2, 2);
 
489
            t     = atoiSubstring(buf +  4, 8);
 
490
            min   = atoiSubstring(buf + 12, 2);
 
491
            g     = atoiSubstring(buf + 14, 1);
 
492
            year  = atoiSubstring(buf + 15, 2);
 
493
            l     = atoiSubstring(buf + 17, 4);
 
494
            month = atoiSubstring(buf + 21, 2);
 
495
            c1    = atoiSubstring(buf + 23, 3);
 
496
            day   = atoiSubstring(buf + 26, 2);
 
497
            hour  = atoiSubstring(buf + 28, 2);
 
498
            rest = -1;
 
499
            c2 = f*3 + g + l*7 + year*3 + month*7 + day*3 + hour*7 + min*3 + sec;
 
500
            break;
 
501
        case 32:
 
502
            // Just for compatibility with xshisen 1.10, Y2K
 
503
            f     = atoiSubstring(buf +  0, 2);
 
504
            sec   = atoiSubstring(buf +  2, 2);
 
505
            t     = atoiSubstring(buf +  4, 8);
 
506
            min   = atoiSubstring(buf + 12, 2);
 
507
            g     = atoiSubstring(buf + 14, 1);
 
508
            year  = atoiSubstring(buf + 15, 3) - 100;
 
509
            l     = atoiSubstring(buf + 18, 4);
 
510
            month = atoiSubstring(buf + 22, 2);
 
511
            c1    = atoiSubstring(buf + 24, 3);
 
512
            day   = atoiSubstring(buf + 27, 2);
 
513
            hour  = atoiSubstring(buf + 29, 2);
 
514
            rest = -1;
 
515
            c2 = f*3 + g + l*7 + (year+100)*3 + month*7 + day*3 + hour*7 + min*3 + sec
 
516
;
 
517
            break;
 
518
         case 34:
 
519
            // This is usual format
 
520
            f     = atoiSubstring(buf +  0, 2);
 
521
            sec   = atoiSubstring(buf +  2, 2);
 
522
            t     = atoiSubstring(buf +  4, 8);
 
523
            min   = atoiSubstring(buf + 12, 2);
 
524
            g     = atoiSubstring(buf + 14, 1);
 
525
            year  = atoiSubstring(buf + 15, 2);
 
526
            l     = atoiSubstring(buf + 17, 4);
 
527
            month = atoiSubstring(buf + 21, 2);
 
528
            c1    = atoiSubstring(buf + 23, 3);
 
529
            rest  = atoiSubstring(buf + 26, 3);
 
530
            day   = atoiSubstring(buf + 29, 2);
 
531
            hour  = atoiSubstring(buf + 31, 2);
 
532
            c2 = f*3 + g + l*7 + year*3 + month*7 + day*3 + hour*7 + min*3
 
533
                + sec + rest*7;
 
534
            break;
 
535
         case 35: 
 
536
            // This is usual format, Y2K
 
537
            f     = atoiSubstring(buf +  0, 2);
 
538
            sec   = atoiSubstring(buf +  2, 2);
 
539
            t     = atoiSubstring(buf +  4, 8);
 
540
            min   = atoiSubstring(buf + 12, 2);
 
541
            g     = atoiSubstring(buf + 14, 1);
 
542
            year  = atoiSubstring(buf + 15, 3) - 100;
 
543
            l     = atoiSubstring(buf + 18, 4);
 
544
            month = atoiSubstring(buf + 22, 2);
 
545
            c1    = atoiSubstring(buf + 24, 3);
 
546
            rest  = atoiSubstring(buf + 27, 3);
 
547
            day   = atoiSubstring(buf + 30, 2);
 
548
            hour  = atoiSubstring(buf + 32, 2);
 
549
            c2 = f*3 + g + l*7 + (year+100)*3 + month*7 + day*3 + hour*7 + min*3
 
550
                + sec + rest*7;
 
551
            break;
 
552
        default:
 
553
            // Someone edited this file?
 
554
            continue;
 
555
        }
 
556
        c2 %= 857;
 
557
        if (c1 != c2 || g != game)
 
558
            continue; // Check digit was incorrect, or other game size
 
559
        if (f < 0 || f > 3)
 
560
            continue; // Invalid value
 
561
        l /= 2;
 
562
        ms_to_hms(t, t1, t2, t3);
 
563
        if (f == 1) {  // Only completed game can be included
 
564
            sprintf(scorebuf[SCORENUM*2],
 
565
                    "%2.2d:%2.2d:%2.2d (%3d) [%2.2d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d]",
 
566
                    t1, t2, t3, l, year, month+1, day, hour, min, sec);
 
567
            for(i=SCORENUM*2; i>0 && strcmp(scorebuf[i-1],scorebuf[i])>0; i--) {
 
568
                char p[128];
 
569
                strcpy(p, scorebuf[i-1]);
 
570
                strcpy(scorebuf[i-1], scorebuf[i]);
 
571
                strcpy(scorebuf[i], p);
 
572
            }
 
573
        }
 
574
        tb.tm_isdst = 0;
 
575
        tb.tm_sec   = sec;
 
576
        tb.tm_min   = min;
 
577
        tb.tm_hour  = hour;
 
578
        tb.tm_mday  = day;
 
579
        tb.tm_mon   = month;
 
580
        tb.tm_year  = year > 69 ? year : year + 100;
 
581
        tm1 = mktime(&tb);  // Time of the score
 
582
        w1[0][f] += t;
 
583
        w2[0][f]++;
 
584
        w3[0][f] += l;
 
585
        if (tm1 >= tm2) { // if the time of the score is newer than specified days ago
 
586
            w1[1][f] += t;
 
587
            w2[1][f]++;
 
588
            w3[1][f] += l;
 
589
        }
 
590
    }
 
591
    fclose(s);
 
592
    bufp = buf;
 
593
    *bufp = '\0';
 
594
    pw = getpwuid(getuid());
 
595
    sprintf(bufp, res_strings[12], pw->pw_name);
 
596
    bufp += strlen(bufp);
 
597
    for(i=0; i<SCORENUM; i++) {
 
598
        sprintf(bufp, "%2d ", i+1);
 
599
        bufp += 3;
 
600
        strcpy(bufp, scorebuf[i]);
 
601
        bufp += strlen(bufp);
 
602
        sprintf(bufp, "    %2d ", SCORENUM+i+1);
 
603
        bufp += 7;
 
604
        strcpy(bufp, scorebuf[SCORENUM+i]);
 
605
        bufp += strlen(bufp);
 
606
        *bufp = '\n';
 
607
        bufp++;
 
608
    }
 
609
    *bufp = '\n'; bufp++;
 
610
    *bufp = '\n'; bufp++;
 
611
    sprintf(xb, res_strings[2], atoi(res_strings[3]));
 
612
    strcpy(bufp, makeStatistics(xb, w1[1], w2[1], w3[1]));
 
613
    bufp += strlen(bufp);
 
614
    strcpy(bufp, makeStatistics(res_strings[9], w1[0], w2[0], w3[0]));
 
615
    bufp += strlen(bufp);
 
616
    *bufp = '\0';
 
617
    Popup(buf);
 
618
}
 
619
 
 
620
int
 
621
Score::atoiSubstring(const char *str, int length)
 
622
{
 
623
    char b[16];
 
624
    strncpy(b, str, length);
 
625
    *(b+length) = '\0';
 
626
    return atoi(b);
 
627
}
 
628
 
 
629
char
 
630
*Score::makeStatistics(const char *title, int rtime[], int rcount[], int rlev[])
 
631
{
 
632
    int x;
 
633
    double y;
 
634
    unsigned char t1, t2, t3;
 
635
    static char b[1024], *bp;
 
636
 
 
637
    bp = b;
 
638
    x = rcount[0] + rcount[1] + rcount[2] + rcount[3];
 
639
    sprintf(bp, "%-20.20s: %6d %s\n", title, x, res_strings[11]);
 
640
    bp += strlen(bp);
 
641
    if (rcount[1]) {
 
642
        x = rtime[1] / rcount[1];
 
643
        y = (double)rlev[1] / (double)rcount[1];
 
644
        ms_to_hms(x, t1, t2, t3);
 
645
        bp += strlen(bp);
 
646
        sprintf(bp, "    %-14.14s: %2.2d:%2.2d:%2.2d (%4.1f) %6d %s\n",
 
647
                res_strings[5], t1, t2, t3, y, rcount[1], res_strings[11]);
 
648
        bp += strlen(bp);
 
649
    }
 
650
    if (rcount[3]) {
 
651
        x = rtime[3] / rcount[3];
 
652
        y = (double)rlev[3] / (double)rcount[3];
 
653
        ms_to_hms(x, t1, t2, t3);
 
654
        bp += strlen(bp);
 
655
        sprintf(bp, "    %-14.14s: %2.2d:%2.2d:%2.2d (%4.1f) %6d %s\n",
 
656
                res_strings[6], t1, t2, t3, y, rcount[3], res_strings[11]);
 
657
        bp += strlen(bp);
 
658
    }
 
659
    if (rcount[2]) {
 
660
        x = rtime[2] / rcount[2];
 
661
        y = (double)rlev[2] / (double)rcount[2];
 
662
        ms_to_hms(x, t1, t2, t3);
 
663
        bp += strlen(bp);
 
664
        sprintf(bp, "    %-14.14s: %2.2d:%2.2d:%2.2d (%4.1f) %6d %s\n",
 
665
                res_strings[7], t1, t2, t3, y, rcount[2], res_strings[11]);
 
666
        bp += strlen(bp);
 
667
    }
 
668
    if (rcount[0]) {
 
669
        x = rtime[0] / rcount[0];
 
670
        y = (double)rlev[0] / (double)rcount[0];
 
671
        ms_to_hms(x, t1, t2, t3);
 
672
        bp += strlen(bp);
 
673
        sprintf(bp, "    %-14.14s: %2.2d:%2.2d:%2.2d (%4.1f) %6d %s\n",
 
674
                res_strings[8], t1, t2, t3, y, rcount[0], res_strings[11]);
 
675
        bp += strlen(bp);
 
676
    }
 
677
    *bp = '\0';
 
678
    return b;
 
679
}