| 35 #include "colors.h" |
35 #include "colors.h" |
| 36 #include <string.h> |
36 #include <string.h> |
| 37 #include <time.h> |
37 #include <time.h> |
| 38 #include <getopt.h> |
38 #include <getopt.h> |
| 39 #include <locale.h> |
39 #include <locale.h> |
| |
40 #include <sys/stat.h> |
| 40 |
41 |
| 41 int get_settings(int argc, char **argv, Settings *settings) { |
42 int get_settings(int argc, char **argv, Settings *settings) { |
| 42 char *valid; |
43 char *valid; |
| 43 unsigned long int time, port; |
44 unsigned long int time, port; |
| 44 uint8_t timeunit = 60; |
45 uint8_t timeunit = 60; |
| 45 size_t len; |
46 size_t len; |
| 46 |
47 bool port_set = false; |
| 47 for (int opt ; (opt = getopt(argc, argv, "a:bc:Fhp:rsS:t:Uv")) != -1 ;) { |
48 |
| |
49 for (int opt ; (opt = getopt(argc, argv, "a:bc:Fhp:rsS:t:uUv")) != -1 ;) { |
| 48 switch (opt) { |
50 switch (opt) { |
| 49 case 'c': |
51 case 'c': |
| 50 settings->continuepgn = optarg; |
52 settings->continuepgn = optarg; |
| 51 break; |
53 break; |
| 52 case 'b': |
54 case 'b': |
| 85 settings->gameinfo.addtime = time; |
95 settings->gameinfo.addtime = time; |
| 86 } |
96 } |
| 87 } |
97 } |
| 88 break; |
98 break; |
| 89 case 'p': |
99 case 'p': |
| |
100 if (port_set) { |
| |
101 fprintf(stderr, "Cannot use -p twice.\n"); |
| |
102 return 1; |
| |
103 } |
| |
104 if (settings->usedomainsocket) { |
| |
105 fprintf(stderr, "Cannot specify TCP port " |
| |
106 "when using Unix domain sockets.\n"); |
| |
107 return 1; |
| |
108 } |
| 90 port = strtol(optarg, &valid, 10); |
109 port = strtol(optarg, &valid, 10); |
| 91 if (port < 1025 || port > 65535 || *valid != '\0') { |
110 if (port < 1025 || port > 65535 || *valid != '\0') { |
| 92 fprintf(stderr, |
111 fprintf(stderr, |
| 93 "Invalid port number (%s) - choose a number between " |
112 "Invalid port number (%s) - choose a number between " |
| 94 "1025 and 65535\n", |
113 "1025 and 65535\n", |
| 95 optarg); |
114 optarg); |
| 96 return 1; |
115 return 1; |
| 97 } else { |
116 } else { |
| 98 settings->port = (short) port; |
117 settings->port = (short) port; |
| |
118 port_set = true; |
| 99 } |
119 } |
| 100 break; |
120 break; |
| 101 case 'v': |
121 case 'v': |
| 102 printf("terminal-chess : Version %s (Netcode Version %d)\n", |
122 printf("terminal-chess : Version %s (Netcode Version %d)\n", |
| 103 PROGRAM_VERSION, NETCODE_VERSION); |
123 PROGRAM_VERSION, NETCODE_VERSION); |
| 109 "Starts/joins a network chess game\n" |
129 "Starts/joins a network chess game\n" |
| 110 "\nGeneral options\n" |
130 "\nGeneral options\n" |
| 111 " -c <PGN file> Continue the specified game\n" |
131 " -c <PGN file> Continue the specified game\n" |
| 112 " -h This help page\n" |
132 " -h This help page\n" |
| 113 " -p TCP port to use (default: 27015)\n" |
133 " -p TCP port to use (default: 27015)\n" |
| |
134 " -u Use Unix domain socket instead of TCP\n" |
| 114 " -U Disables unicode pieces\n" |
135 " -U Disables unicode pieces\n" |
| 115 " -v Print version information and exits\n" |
136 " -v Print version information and exits\n" |
| 116 "\nServer options\n" |
137 "\nServer options\n" |
| 117 " -a <time> Specifies the time to add after each move\n" |
138 " -a <time> Specifies the time to add after each move\n" |
| 118 " -b Server plays black pieces (default: white)\n" |
139 " -b Server plays black pieces (default: white)\n" |
| 119 " -r Distribute color randomly\n" |
140 " -r Distribute color randomly\n" |
| 120 " -t <time> Specifies time limit (default: no limit)\n" |
141 " -t <time> Specifies time limit (default: no limit)\n" |
| 121 "\nHot seat\n" |
142 "\nHot seat\n" |
| 122 " -s Play a hot seat game (no client/server)\n" |
143 " -s Play a hot seat game (network options are ignored)\n" |
| 123 " -F Do not automatically flip the board in hot seat games\n" |
144 " -F Do not automatically flip the board in hot seat games\n" |
| 124 "\nNotes\n" |
145 "\nNotes\n" |
| 125 "The time unit for -a is seconds and for -t minutes by default. To " |
146 "The time unit for -a is seconds and for -t minutes by default. To " |
| 126 "specify\nseconds for the -t option, use the s suffix.\n" |
147 "specify\nseconds for the -t option, use the s suffix.\n" |
| 127 "Example: -t 150s\n\n" |
148 "Example: -t 150s\n\n" |
| 128 "Use '-' for PGN files to read PGN data from standard input\n" |
149 "Use '-' for PGN files to read PGN data from standard input\n\n" |
| |
150 "When playing over Unix domain socket, the HOST denotes the socket path.\n" |
| |
151 "When the path doest not exist, a game is created. Otherwise, the program\n" |
| |
152 "joins the existing game. When HOST is omitted, /tmp/chess.sock is used.\n" |
| 129 ); |
153 ); |
| 130 exit(0); |
154 exit(0); |
| 131 } |
155 } |
| 132 } |
156 } |
| 133 |
157 |
| 143 if (settings->serverhost) { |
167 if (settings->serverhost) { |
| 144 fprintf(stderr, "Can't continue a game when joining a server.\n"); |
168 fprintf(stderr, "Can't continue a game when joining a server.\n"); |
| 145 return 1; |
169 return 1; |
| 146 } |
170 } |
| 147 } |
171 } |
| |
172 |
| |
173 if (settings->usedomainsocket) { |
| |
174 if (!settings->serverhost) { |
| |
175 settings->serverhost = "/tmp/chess.sock"; |
| |
176 } |
| |
177 struct stat st; |
| |
178 if (stat(settings->serverhost, &st) == 0) { |
| |
179 if (S_ISSOCK(st.st_mode)) { |
| |
180 settings->ishost = false; |
| |
181 } else { |
| |
182 fprintf(stderr, "%s is not a Unix domain socket.\n", |
| |
183 settings->serverhost); |
| |
184 return 1; |
| |
185 } |
| |
186 } else { |
| |
187 settings->ishost = true; |
| |
188 } |
| |
189 } else { |
| |
190 settings->ishost = !settings->serverhost; |
| |
191 } |
| 148 |
192 |
| 149 return 0; |
193 return 0; |
| 150 } |
194 } |
| 151 |
195 |
| 152 static Settings default_settings() { |
196 static Settings settings; |
| 153 Settings settings = {0}; |
197 |
| |
198 static void init_settings(void) { |
| |
199 memset(&settings, 0, sizeof(settings)); |
| 154 settings.gameinfo.servercolor = WHITE; |
200 settings.gameinfo.servercolor = WHITE; |
| 155 settings.port = 27015; |
201 settings.port = 27015; |
| 156 settings.unicode = !!setlocale(LC_CTYPE, "C.UTF-8"); |
202 settings.unicode = !!setlocale(LC_CTYPE, "C.UTF-8"); |
| 157 return settings; |
203 } |
| |
204 |
| |
205 static void cleanup() { |
| |
206 endwin(); |
| |
207 if (settings.usedomainsocket && settings.ishost) { |
| |
208 remove(settings.serverhost); |
| |
209 } |
| 158 } |
210 } |
| 159 |
211 |
| 160 int main(int argc, char **argv) { |
212 int main(int argc, char **argv) { |
| 161 srand(time(NULL)); |
213 srand(time(NULL)); |
| 162 |
214 |
| 163 Settings settings = default_settings(); |
215 init_settings(); |
| 164 if (get_settings(argc, argv, &settings)) { |
216 if (get_settings(argc, argv, &settings)) { |
| 165 return 1; |
217 return 1; |
| 166 } |
218 } |
| 167 |
219 |
| 168 initscr(); |
220 initscr(); |
| 175 } else { |
227 } else { |
| 176 fprintf(stderr, "Non-colored terminals are not supported yet."); |
228 fprintf(stderr, "Non-colored terminals are not supported yet."); |
| 177 endwin(); |
229 endwin(); |
| 178 return EXIT_FAILURE; |
230 return EXIT_FAILURE; |
| 179 } |
231 } |
| 180 atexit((void(*)())endwin); |
232 atexit(cleanup); |
| 181 |
233 |
| 182 int exitcode; |
234 int exitcode; |
| 183 if (settings.singlemachine) { |
235 if (settings.singlemachine) { |
| 184 game_play_singlemachine(&settings); |
236 game_play_singlemachine(&settings); |
| 185 exitcode = EXIT_SUCCESS; |
237 exitcode = EXIT_SUCCESS; |
| 186 } else { |
238 } else { |
| 187 exitcode = is_server(&settings) ? |
239 exitcode = settings.ishost ? |
| 188 server_run(&settings) : client_run(&settings); |
240 server_run(&settings) : client_run(&settings); |
| 189 } |
241 } |
| 190 |
242 |
| 191 mvaddstr(getmaxy(stdscr)-1, 0, |
243 mvaddstr(getmaxy(stdscr)-1, 0, |
| 192 "Game has ended. Press any key to leave..."); |
244 "Game has ended. Press any key to leave..."); |