added setuid/gid to the startup as defined in config
[rlserver.git] / games.c
bloba2b3f8bef6e3aeda59b645c0faa2fd4e8a54ad07
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <ctype.h>
4 #include <string.h>
5 #include "log.h"
6 #include "games.h"
8 #define GAME_FILE "./games"
12 static game_info* parse_game_begin (const char *buf, int ln)
14 game_info *game;
15 int n = strlen(buf + 1) - 1;
18 if (buf[n] != ']')
20 write_log (LOG_ERROR, GAME_FILE ":%d: parse error", ln);
21 return NULL;
23 if (n >= GAME_ID_LEN)
25 write_log (LOG_ERROR, GAME_FILE ":%d: game id is too long", ln);
26 return NULL;
29 game = (game_info*)malloc(sizeof(game_info));
30 if (game == NULL)
32 write_log (LOG_ERROR, "can't allocate memory for the game list");
33 return NULL;
36 memset (game, 0, sizeof(game_info));
37 memcpy (game->id, buf + 1, n - 1);
38 game->id[n - 1] = 0;
39 game->enter = '\n';
41 return game;
46 enum
48 G_NAME = 0,
49 G_CHDIR,
50 G_RUN,
51 G_SCORE,
52 G_COPY,
53 G_COPYEDIT,
54 G_ENTER,
55 G_TOTAL
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;
65 if (game == NULL)
67 write_log (LOG_ERROR, GAME_FILE ":%d: no game is defined before data", ln);
68 return -1;
71 for (i = 0; i < G_TOTAL; i++)
73 taglen = strlen(tags[i]);
74 if (memcmp(buf, tags[i], taglen) == 0) break;
76 if (tags[i] == NULL)
78 write_log (LOG_ERROR, GAME_FILE ":%d: parse error", ln);
79 return -1;
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]);
90 return -1;
93 switch (i)
95 case G_NAME:
96 memcpy (game->name, &buf[taglen], len);
97 game->name[len] = 0;
98 break;
99 case G_CHDIR:
100 memcpy (game->dir, &buf[taglen], len);
101 game->dir[len] = 0;
102 break;
103 case G_RUN:
104 memcpy (game->cmd, &buf[taglen], len);
105 game->cmd[len] = 0;
106 break;
107 case G_SCORE:
108 memcpy (game->cmd_score, &buf[taglen], len);
109 game->cmd_score[len] = 0;
110 break;
111 case G_COPY:
112 case G_COPYEDIT:
113 for (j = 0; game->files[j].file[0] != 0; j++)
115 if (j >= GAME_FILES)
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);
128 return -1;
130 *game->files[j].copy = 0;
131 game->files[j].copy++;
133 game->files[j].allow_edit = (i == G_COPYEDIT);
134 break;
135 case G_ENTER:
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);
139 break;
140 default:
141 // should never happen
142 return -1;
145 return 0;
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);
157 free (game);
158 return;
161 game->next = NULL;
162 if (*gamelist == NULL) *gamelist = game;
163 if (*prev != NULL) (*prev)->next = game;
164 game->prev = *prev;
165 *prev = game;
170 #define BUF_SIZE 1 * 1024
172 game_info* load_gamelist (void)
174 game_info *gamelist = NULL, *game = NULL, *lg = NULL;
175 char buf[BUF_SIZE];
176 FILE *f;
177 int ln = 1, err = 0;
180 if ((f = fopen(GAME_FILE, "r")) == NULL)
182 write_log (LOG_ERROR, "can't open file \"" GAME_FILE "\"");
183 return NULL;
186 while (1)
188 // end of 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)
194 ln++;
195 continue;
198 // game section start
199 if (buf[0] == '[')
201 // add previous game to the list
202 if (game != NULL) add_game (&gamelist, game, &lg);
204 game = parse_game_begin(buf, ln);
205 if (game == NULL)
207 err = 1;
208 break;
211 else if (parse_game_line(game, buf, ln) == -1)
213 err = 1;
214 break;
217 ln++;
220 // add game to the list
221 if (game != NULL) add_game (&gamelist, game, &lg);
223 fclose (f);
225 if (err)
227 free_gamelist (gamelist);
228 return NULL;
231 return gamelist;
236 void free_gamelist (game_info *gamelist)
238 game_info *g = gamelist;
240 while (g != NULL)
242 game_info *g2 = g;
244 g = g->next;
246 free (g2);