8 #define GAME_FILE "./games"
12 static game_info
* parse_game_begin (const char *buf
, int ln
)
15 int n
= strlen(buf
+ 1) - 1;
20 write_log (LOG_ERROR
, GAME_FILE
":%d: parse error", ln
);
25 write_log (LOG_ERROR
, GAME_FILE
":%d: game id is too long", ln
);
29 game
= (game_info
*)malloc(sizeof(game_info
));
32 write_log (LOG_ERROR
, "can't allocate memory for the game list");
36 memset (game
, 0, sizeof(game_info
));
37 memcpy (game
->id
, buf
+ 1, n
- 1);
58 static int parse_game_line (game_info
*game
, const char *buf
, int ln
)
60 static const char* const tags
[G_TOTAL
] = {"name:", "chdir:", "run:", "score:", "copy:", "copy-edit:", "enter:"};
61 static const int lengths
[G_TOTAL
] = {GAME_NAME_LEN
, GAME_DIR_LEN
, GAME_COMMAND_LEN
, GAME_COMMAND_LEN
, GAME_FILE_LEN
, GAME_FILE_LEN
, 3};
62 int taglen
, len
, i
, j
;
67 write_log (LOG_ERROR
, GAME_FILE
":%d: no game is defined before data", ln
);
71 for (i
= 0; i
< G_TOTAL
; i
++)
73 taglen
= strlen(tags
[i
]);
74 if (memcmp(buf
, tags
[i
], taglen
) == 0) break;
78 write_log (LOG_ERROR
, GAME_FILE
":%d: parse error", ln
);
82 // skip whitespaces after colon
83 while (isspace(buf
[taglen
]) && buf
[taglen
] != 0) taglen
++;
85 len
= strlen(&buf
[taglen
]);
86 if (buf
[taglen
+ len
- 1] == '\n') len
--; // subtract 1 for \n at the end
87 if (len
>= lengths
[i
])
89 write_log (LOG_ERROR
, GAME_FILE
":%d: value is too long (max %d)", ln
, lengths
[i
]);
96 memcpy (game
->name
, &buf
[taglen
], len
);
100 memcpy (game
->dir
, &buf
[taglen
], len
);
104 memcpy (game
->cmd
, &buf
[taglen
], len
);
108 memcpy (game
->cmd_score
, &buf
[taglen
], len
);
109 game
->cmd_score
[len
] = 0;
113 for (j
= 0; game
->files
[j
].file
[0] != 0; j
++)
117 write_log (LOG_ERROR
, GAME_FILE
":%d: only %d files can be specified for a game", ln
, GAME_FILES
);
121 memcpy (game
->files
[j
].file
, &buf
[taglen
], len
);
122 game
->files
[j
].file
[len
] = 0;
124 game
->files
[j
].copy
= strchr(game
->files
[j
].file
, ' ');
125 if (game
->files
[j
].copy
== NULL
|| *(game
->files
[j
].copy
+ 1) == 0)
127 write_log (LOG_ERROR
, GAME_FILE
":%d: two file names should be specified, separated by a single space", ln
);
130 *game
->files
[j
].copy
= 0;
131 game
->files
[j
].copy
++;
133 game
->files
[j
].allow_edit
= (i
== G_COPYEDIT
);
136 if (strncasecmp(&buf
[taglen
], "cr", len
) == 0) game
->enter
= '\r';
137 else if (strncasecmp(&buf
[taglen
], "lf", len
) == 0) game
->enter
= '\n';
138 else write_log (LOG_ERROR
, GAME_FILE
":%d: unknown value for enter key", ln
);
141 // should never happen
150 // NB! game may be freed
151 static void add_game (game_info
**gamelist
, game_info
*game
, game_info
**prev
)
153 // check if all required fields are defined
154 if (!game
->name
[0] || !game
->cmd
[0])
156 write_log (LOG_ERROR
, "game [%s] is missing 'name:' or 'run:'", game
->id
);
162 if (*gamelist
== NULL
) *gamelist
= game
;
163 if (*prev
!= NULL
) (*prev
)->next
= game
;
170 #define BUF_SIZE 1 * 1024
172 game_info
* load_gamelist (void)
174 game_info
*gamelist
= NULL
, *game
= NULL
, *lg
= NULL
;
180 if ((f
= fopen(GAME_FILE
, "r")) == NULL
)
182 write_log (LOG_ERROR
, "can't open file \"" GAME_FILE
"\"");
189 if (fgets(buf
, BUF_SIZE
, f
) == NULL
) break;
191 // skip comments and empty strings
192 if (buf
[0] == '#' || buf
[0] == '\n' || buf
[0] == 0)
198 // game section start
201 // add previous game to the list
202 if (game
!= NULL
) add_game (&gamelist
, game
, &lg
);
204 game
= parse_game_begin(buf
, ln
);
211 else if (parse_game_line(game
, buf
, ln
) == -1)
220 // add game to the list
221 if (game
!= NULL
) add_game (&gamelist
, game
, &lg
);
227 free_gamelist (gamelist
);
236 void free_gamelist (game_info
*gamelist
)
238 game_info
*g
= gamelist
;