1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
23 #include "sgf_output.h"
25 #include "sgf_storage.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);
41 output_sgf (const char *filename
)
44 union prop_data_t temp_data
;
45 int saved
= current_node
;
47 sgf_fd
= create_or_open_file (filename
);
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);
72 push_int_stack (&parse_stack
, tree_head
);
74 while (pop_int_stack (&parse_stack
, ¤t
))
76 int var_to_process
= 0;
78 get_prop_sgf (current
, PROP_VARIATION_TO_PROCESS
, NULL
);
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
);
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
);
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
);
122 current_node
= saved
;
123 close_file (&sgf_fd
);
124 DEBUGF ("done outputting, file closed\n");
129 output_header_props (void)
133 rb
->strlcpy (buffer
, "GM[1]FF[4]CA[UTF-8]AP[Rockbox Goban:1.0]ST[2]\n\n",
135 write_file (sgf_fd
, buffer
, rb
->strlen (buffer
));
138 if (board_width
!= board_height
)
140 rb
->snprintf (buffer
, sizeof (buffer
), "%s[%d:%d]",
141 prop_names
[PROP_SIZE
], board_width
, board_height
);
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');
185 output_header_helper (enum prop_type_t type
)
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");
197 if (rb
->strlen (buffer
))
199 rb
->snprintf (temp_buffer
, sizeof (temp_buffer
), "%s[",
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
));
216 bool first_node_in_tree
= true;
218 output_gametree (void)
220 first_node_in_tree
= true;
222 while (output_current_node ())
224 current_node
= get_node (current_node
)->next
;
230 output_current_node (void)
232 if (current_node
< 0)
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
);
246 if (first_node_in_tree
)
248 first_node_in_tree
= false;
252 write_char (sgf_fd
, '\n');
254 write_char (sgf_fd
, ';');
261 enum prop_type_t last_output_type
= PROP_INVALID
;
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
;
277 output_prop (int prop_handle
)
280 enum prop_type_t temp_type
= get_prop (prop_handle
)->type
;
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
);
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
));
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;
331 rb
->lseek (unhandled_fd
, get_prop (prop_handle
)->data
.number
,
336 temp
= peek_char (unhandled_fd
);
346 /* otherwise, fall through */
357 in_prop_value
= true;
363 in_prop_value
= false;
375 write_char (sgf_fd
, temp
);
376 read_char (unhandled_fd
);
381 last_output_type
= temp_type
;
385 pos_to_sgf (unsigned short pos
, char *buffer
)
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
);
399 DEBUGF ("invalid pos converted to SGF\n");
404 stupid_num_variations (void)
407 struct prop_t
*temp_prop
;
408 struct node_t
*temp_node
= get_node (current_node
);
415 temp_prop
= get_prop (temp_node
->props
);
419 if (temp_prop
->type
== PROP_VARIATION
)
425 /* variations are at the beginning of the prop list */
429 temp_prop
= get_prop (temp_prop
->next
);