]> mj.ucw.cz Git - eval.git/blob - judge/judge-tok.c
Eval: Added STACK_LIMIT.
[eval.git] / judge / judge-tok.c
1 /*
2  *      A judge comparing two sequences of tokens
3  *
4  *      (c) 2007 Martin Krulis <bobrik@matfyz.cz>
5  *      (c) 2007 Martin Mares <mj@ucw.cz>
6  */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <getopt.h>
12 #include <math.h>
13
14 #include "judge.h"
15
16 static int ignore_nl, ignore_trailing_nl, ignore_case;
17 static int real_mode;
18 static double rel_eps = 1e-5;
19 static double abs_eps = 1e-30;
20
21 static int tokens_equal(struct tokenizer *t1, struct tokenizer *t2)
22 {
23   if (real_mode)
24     {
25       double x1, x2;
26       if (to_double(t1, &x1) && to_double(t2, &x2))
27         {
28           if (x1 == x2)
29             return 1;
30           double eps = fabs(x2 * rel_eps);
31           if (eps < abs_eps)
32             eps = abs_eps;
33           return (fabs(x1-x2) <= eps);
34         }
35       // If they fail to convert, compare them as strings.
36     }
37   return !(ignore_case ? strcasecmp : strcmp)(t1->token, t2->token);
38 }
39
40 static int trailing_nl(struct tokenizer *t)
41 {
42   // Ignore empty lines at the end of file
43   if (t->token[0] || !ignore_trailing_nl)
44     return 0;
45   t->flags &= ~TF_REPORT_LINES;
46   return !get_token(t);
47 }
48
49 static void usage(void)
50 {
51   fprintf(stderr, "Usage: judge-tok [<options>] <output> <correct>\n\
52 \n\
53 Options:\n\
54 -n\t\tIgnore newlines\n\
55 -t\t\tIgnore newlines at the end of file\n\
56 -i\t\tIgnore case\n\
57 -r\t\tMatch tokens as real numbers and allow small differences:\n\
58 -e <epsilon>\tSet maximum allowed relative error (default: %g)\n\
59 -E <epsilon>\tSet maximum allowed absolute error (default: %g)\n\
60 ", rel_eps, abs_eps);
61   exit(2);
62 }
63
64 int main(int argc, char **argv)
65 {
66   struct tokenizer t1, t2;
67   int opt;
68
69   while ((opt = getopt(argc, argv, "ntire:E:")) >= 0)
70     switch (opt)
71       {
72       case 'n':
73         ignore_nl++;
74         break;
75       case 't':
76         ignore_trailing_nl++;
77         break;
78       case 'i':
79         ignore_case++;
80         break;
81       case 'r':
82         real_mode++;
83         break;
84       case 'e':
85         rel_eps = atof(optarg);
86         break;
87       case 'E':
88         abs_eps = atof(optarg);
89         break;
90       default:
91         usage();
92       }
93   if (optind + 2 != argc)
94     usage();
95
96   tok_init(&t1, sopen_read(argv[optind]));
97   tok_init(&t2, sopen_read(argv[optind+1]));
98   if (!ignore_nl)
99     t1.flags = t2.flags = TF_REPORT_LINES;
100
101   for (;;)
102     {
103       char *a = get_token(&t1), *b = get_token(&t2);
104       if (!a)
105         {
106           if (b && !trailing_nl(&t2))
107             tok_err(&t1, "Ends too early");
108           break;
109         }
110       else if (!b)
111         {
112           if (a && !trailing_nl(&t1))
113             tok_err(&t2, "Garbage at the end");
114           break;
115         }
116       else if (!tokens_equal(&t1, &t2))
117         tok_err(&t1, "Found <%s>, expected <%s>", a, b);
118     }
119
120   return 0;
121 }