copy the classic_statusbar and rockbox_none .sbs's to .rsbs's also so remote displays...
[kugel-rb.git] / apps / plugins / goban / sgf_output.c
blob6a52789f7ae3d8b87e14d935e0ed1e6e4377a4ce
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007-2009 Joshua Simmons <mud at majidejima dot com>
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "goban.h"
23 #include "sgf_output.h"
24 #include "sgf.h"
25 #include "sgf_storage.h"
26 #include "util.h"
27 #include "board.h"
28 #include "game.h"
30 static void pos_to_sgf (unsigned short pos, char *buffer);
32 static void output_prop (int prop_handle);
33 static void output_all_props (void);
34 static bool output_current_node (void);
35 static void output_gametree (void);
36 static void output_header_props (void);
37 static bool output_header_helper (enum prop_type_t type);
38 static int stupid_num_variations (void);
40 bool
41 output_sgf (const char *filename)
43 int current = -1;
44 union prop_data_t temp_data;
45 int saved = current_node;
47 sgf_fd = create_or_open_file (filename);
49 if (sgf_fd < 0)
51 return false;
54 DEBUGF ("outputting to: %s (%d)\n", filename, sgf_fd);
56 empty_stack (&parse_stack);
58 rb->lseek (sgf_fd, 0, SEEK_SET);
59 rb->ftruncate (sgf_fd, 0);
61 if (sgf_fd < 0)
63 return false;
66 if (tree_head < 0)
68 close_file (&sgf_fd);
69 return false;
72 push_int_stack (&parse_stack, tree_head);
74 while (pop_int_stack (&parse_stack, &current))
76 int var_to_process = 0;
77 int temp_prop =
78 get_prop_sgf (current, PROP_VARIATION_TO_PROCESS, NULL);
80 if (temp_prop >= 0)
82 var_to_process = get_prop (temp_prop)->data.number;
85 current_node = current;
87 if (var_to_process > 0)
89 write_char (sgf_fd, ')');
92 if (var_to_process == stupid_num_variations ())
94 delete_prop_sgf (current, PROP_VARIATION_TO_PROCESS);
96 continue;
98 else
100 write_char (sgf_fd, '\n');
101 write_char (sgf_fd, '(');
103 /* we need to do more processing on this branchpoint, either
104 to do more variations or to output the ')' */
105 push_int_stack (&parse_stack, current);
107 /* increment the stored variation to process */
108 temp_data.number = var_to_process + 1;
109 add_or_set_prop_sgf (current,
110 PROP_VARIATION_TO_PROCESS, temp_data);
113 rb->yield ();
115 /* now we did the setup for sibling varaitions to be processed so
116 do the actual outputting of a game tree branch */
118 go_to_variation_sgf (var_to_process);
119 output_gametree ();
122 current_node = saved;
123 close_file (&sgf_fd);
124 DEBUGF ("done outputting, file closed\n");
125 return true;
128 static void
129 output_header_props (void)
131 char buffer[128];
133 rb->strlcpy (buffer, "GM[1]FF[4]CA[UTF-8]AP[Rockbox Goban:1.0]ST[2]\n\n",
134 sizeof (buffer));
135 write_file (sgf_fd, buffer, rb->strlen (buffer));
137 /* board size */
138 if (board_width != board_height)
140 rb->snprintf (buffer, sizeof (buffer), "%s[%d:%d]",
141 prop_names[PROP_SIZE], board_width, board_height);
143 else
145 rb->snprintf (buffer, sizeof (buffer), "%s[%d]",
146 prop_names[PROP_SIZE], board_width);
149 write_file (sgf_fd, buffer, rb->strlen (buffer));
151 rb->snprintf (buffer, sizeof (buffer), "%s[", prop_names[PROP_KOMI]);
152 write_file (sgf_fd, buffer, rb->strlen (buffer));
154 snprint_fixed (buffer, sizeof (buffer), header.komi);
155 write_file (sgf_fd, buffer, rb->strlen (buffer));
157 write_char (sgf_fd, ']');
159 output_header_helper (PROP_RULESET);
160 output_header_helper (PROP_RESULT);
162 output_header_helper (PROP_BLACK_NAME);
163 output_header_helper (PROP_WHITE_NAME);
164 output_header_helper (PROP_BLACK_RANK);
165 output_header_helper (PROP_WHITE_RANK);
166 output_header_helper (PROP_BLACK_TEAM);
167 output_header_helper (PROP_WHITE_TEAM);
169 output_header_helper (PROP_EVENT);
170 output_header_helper (PROP_PLACE);
171 output_header_helper (PROP_DATE);
173 if (output_header_helper (PROP_OVERTIME) || header.time_limit != 0)
175 rb->snprintf (buffer, sizeof (buffer), "%s[%d]",
176 prop_names[PROP_TIME_LIMIT], header.time_limit);
177 write_file (sgf_fd, buffer, rb->strlen (buffer));
180 write_char (sgf_fd, '\n');
181 write_char (sgf_fd, '\n');
184 static bool
185 output_header_helper (enum prop_type_t type)
187 char *buffer;
188 int size;
189 char temp_buffer[16];
191 if (!get_header_string_and_size (&header, type, &buffer, &size))
193 DEBUGF ("output_header_helper called with invalid prop type!!\n");
194 return false;
197 if (rb->strlen (buffer))
199 rb->snprintf (temp_buffer, sizeof (temp_buffer), "%s[",
200 prop_names[type]);
202 write_file (sgf_fd, temp_buffer, rb->strlen (temp_buffer));
204 write_file (sgf_fd, buffer, rb->strlen (buffer));
206 rb->strcpy (temp_buffer, "]");
208 write_file (sgf_fd, temp_buffer, rb->strlen (temp_buffer));
210 return true;
213 return false;
216 bool first_node_in_tree = true;
217 static void
218 output_gametree (void)
220 first_node_in_tree = true;
222 while (output_current_node ())
224 current_node = get_node (current_node)->next;
229 static bool
230 output_current_node (void)
232 if (current_node < 0)
234 return false;
237 if (stupid_num_variations () > 1 &&
238 get_prop_sgf (current_node, PROP_VARIATION_TO_PROCESS, NULL) < 0)
240 /* push it up for the gametree stuff to take care of it and fail
241 out, stopping the node printing */
242 push_int_stack (&parse_stack, current_node);
243 return false;
246 if (first_node_in_tree)
248 first_node_in_tree = false;
250 else
252 write_char (sgf_fd, '\n');
254 write_char (sgf_fd, ';');
256 output_all_props ();
258 return true;
261 enum prop_type_t last_output_type = PROP_INVALID;
262 static void
263 output_all_props (void)
265 int temp_handle = get_node (current_node)->props;
267 last_output_type = PROP_INVALID;
269 while (temp_handle >= 0)
271 output_prop (temp_handle);
272 temp_handle = get_prop (temp_handle)->next;
276 static void
277 output_prop (int prop_handle)
279 char buffer[16];
280 enum prop_type_t temp_type = get_prop (prop_handle)->type;
282 buffer[0] = 't';
283 buffer[1] = 't';
285 if (is_handled_sgf (temp_type) && temp_type != PROP_COMMENT)
287 if (temp_type != last_output_type)
289 write_file (sgf_fd, prop_names[temp_type],
290 PROP_NAME_LEN (temp_type));
293 write_char (sgf_fd, '[');
295 if (temp_type == PROP_HANDICAP)
297 rb->snprintf (buffer, sizeof (buffer), "%d",
298 get_prop (prop_handle)->data.number);
299 write_file (sgf_fd, buffer, rb->strlen (buffer));
301 else if (temp_type == PROP_LABEL)
303 pos_to_sgf (get_prop (prop_handle)->data.position, buffer);
304 buffer[2] = '\0';
306 rb->snprintf (&buffer[2], sizeof (buffer) - 2, ":%c",
307 get_prop (prop_handle)->data.label_extra);
309 write_file (sgf_fd, buffer, rb->strlen (buffer));
311 else
313 pos_to_sgf (get_prop (prop_handle)->data.position, buffer);
315 write_file (sgf_fd, buffer, 2);
318 write_char (sgf_fd, ']');
320 else if (temp_type == PROP_ROOT_PROPS)
322 output_header_props ();
324 else if (temp_type == PROP_GENERIC_UNHANDLED || temp_type == PROP_COMMENT)
326 bool escaped = false;
327 bool in_prop_value = false;
328 int temp;
329 bool done = false;
331 rb->lseek (unhandled_fd, get_prop (prop_handle)->data.number,
332 SEEK_SET);
334 while (!done)
336 temp = peek_char (unhandled_fd);
338 switch (temp)
340 case ';':
341 escaped = false;
342 if (in_prop_value)
344 break;
346 /* otherwise, fall through */
347 case -1:
348 done = true;
349 break;
351 case '\\':
352 escaped = !escaped;
353 break;
355 case '[':
356 escaped = false;
357 in_prop_value = true;
358 break;
360 case ']':
361 if (!escaped)
363 in_prop_value = false;
365 escaped = false;
366 break;
368 default:
369 escaped = false;
370 break;
373 if (!done)
375 write_char (sgf_fd, temp);
376 read_char (unhandled_fd);
381 last_output_type = temp_type;
384 static void
385 pos_to_sgf (unsigned short pos, char *buffer)
387 if (pos == PASS_POS)
389 /* "tt" is a pass per SGF specification */
390 buffer[0] = buffer[1] = 't';
392 else if (pos != INVALID_POS)
394 buffer[0] = 'a' + I (pos);
395 buffer[1] = 'a' + J (pos);
397 else
399 DEBUGF ("invalid pos converted to SGF\n");
403 static int
404 stupid_num_variations (void)
406 int result = 1;
407 struct prop_t *temp_prop;
408 struct node_t *temp_node = get_node (current_node);
410 if (temp_node == 0)
412 return 0;
415 temp_prop = get_prop (temp_node->props);
417 while (temp_prop)
419 if (temp_prop->type == PROP_VARIATION)
421 ++result;
423 else
425 /* variations are at the beginning of the prop list */
426 break;
429 temp_prop = get_prop (temp_prop->next);
432 return result;