Add deployment script for Theme Editor.
[kugel-rb.git] / apps / plugins / goban / sgf_storage.c
blob7ee0848543dcc1c66ec3588da99a1a4683846b35
2 /***************************************************************************
3 * __________ __ ___.
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 * \/ \/ \/ \/ \/
9 * $Id$
11 * Copyright (C) 2007-2009 Joshua Simmons <mud at majidejima dot com>
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
23 #include "goban.h"
24 #include "sgf_storage.h"
25 #include "sgf.h"
26 #include "util.h"
28 #define ALIGNMENT_VAL (sizeof (union storage_t))
30 union storage_t *storage_buffer[] = { NULL, NULL };
31 size_t storage_buffer_size[] = { 0, 0 };
33 uint8_t *storage_free_list[] = { NULL, NULL };
34 size_t storage_free_list_size[] = { 0, 0 };
36 bool storage_initialized[] = { false, false };
38 size_t total_storage_size = 0;
40 /* the next handle to check */
41 int next_free_handle_buffer;
42 int next_free_handle;
44 static bool setup_storage_buffer (char *temp_buffer, size_t size);
45 static void clear_storage_buffer (int index);
46 static bool find_free (int *ret_buffer, int *ret_handle);
47 static bool is_free (int buffer_num, int handle);
48 static void set_free (int buffer_num, int handle, bool free);
50 #if 0
51 static void debugf_current_node (void);
53 static void
54 debugf_current_node (void)
56 int temp_prop = NO_PROP;
57 if (current_node < 0)
59 DEBUGF ("CURRENT_NODE < 0 ON DEBUGF_CURRENT_NODE!!!!\n");
60 return;
62 DEBUGF ("-----------------------------------------\n");
63 DEBUGF ("current_node: %d\n", current_node);
64 DEBUGF ("start_node %d %d\n", start_node, tree_head);
65 DEBUGF ("prev/next: %d/%d\n", get_node (current_node)->prev,
66 get_node (current_node)->next);
67 DEBUGF ("num variations: %d\n", num_variations_sgf ());
68 DEBUGF ("props:\n");
69 if (!get_node (current_node) ||
70 (temp_prop = get_node (current_node)->props) < 0)
72 DEBUGF ("none\n");
75 while (1)
77 if (temp_prop < 0)
79 break;
81 DEBUGF (" handle: %d\n", temp_prop);
82 DEBUGF (" type: %d ", get_prop (temp_prop)->type);
83 if (get_prop (temp_prop)->type < PROP_NAMES_SIZE)
85 DEBUGF ("(%s)", prop_names[get_prop (temp_prop)->type]);
87 DEBUGF ("\n");
88 if (get_prop (temp_prop)->type == PROP_BLACK_MOVE ||
89 get_prop (temp_prop)->type == PROP_WHITE_MOVE ||
90 get_prop (temp_prop)->type == PROP_ADD_BLACK ||
91 get_prop (temp_prop)->type == PROP_ADD_WHITE ||
92 get_prop (temp_prop)->type == PROP_ADD_EMPTY)
94 DEBUGF (" i: %d j: %d\n",
95 I (get_prop (temp_prop)->data.position),
96 J (get_prop (temp_prop)->data.position));
98 else
100 DEBUGF (" data: %d\n", get_prop (temp_prop)->data.number);
102 DEBUGF (" next: %d\n", get_prop (temp_prop)->next);
104 temp_prop = get_prop (temp_prop)->next;
105 if (temp_prop >= 0)
107 DEBUGF ("\n");
111 DEBUGF ("-----------------------------------------\n");
113 #endif
115 static void
116 clear_storage_buffer (int index)
118 int temp;
121 /* everything starts free */
122 rb->memset (storage_free_list[index],
123 (unsigned char) 0xFF,
124 storage_free_list_size[index]);
126 /* if there are extra bits at the end of the free list (because
127 storage_buffer_size is not divisible by 8) then we set them not
128 free, so we won't end up using those ever by accident (shouldn't be
129 possible anyways, but makes calculation easier later) */
130 temp = storage_free_list_size[index] * 8 - storage_buffer_size[index];
131 storage_free_list[index][storage_free_list_size[index] - 1] ^=
132 (1 << temp) - 1;
135 void
136 free_tree_sgf (void)
138 unsigned int i;
139 for (i = 0;
140 i < sizeof (storage_initialized) /
141 sizeof (storage_initialized[0]); ++i)
143 if (storage_initialized[i])
145 clear_storage_buffer (i);
149 tree_head = start_node = current_node = alloc_storage_sgf ();
151 if (tree_head < 0)
153 rb->splash (5 * HZ,
154 "Error allocating first node! Please exit immediately.");
157 get_node (tree_head)->props = NO_PROP;
158 get_node (tree_head)->next = NO_NODE;
159 get_node (tree_head)->prev = NO_NODE;
163 bool
164 audio_stolen_sgf (void)
166 return storage_initialized[1];
170 alloc_storage_sgf (void)
172 int buffer_num;
173 int handle;
174 int temp_buffer;
175 int ret_val;
177 char *new_storage_buffer;
178 size_t size;
180 if (!find_free (&buffer_num, &handle))
182 if (!storage_initialized[1])
184 rb->splash (2 * HZ, "Stopping music playback to get more space");
185 DEBUGF ("stealing audio buffer: %d\n", (int) total_storage_size);
187 new_storage_buffer = rb->plugin_get_audio_buffer (&size);
188 setup_storage_buffer (new_storage_buffer, size);
190 DEBUGF ("after stealing: %d\n", (int) total_storage_size);
192 else
194 return -1;
197 /* try again */
198 if (!find_free (&buffer_num, &handle))
200 return -1;
204 set_free (buffer_num, handle, false);
206 temp_buffer = 0;
207 ret_val = handle;
209 while (temp_buffer != buffer_num)
211 if (storage_initialized[temp_buffer])
213 ret_val += storage_buffer_size[temp_buffer];
216 ++temp_buffer;
219 return ret_val;
222 void
223 free_storage_sgf (int handle)
225 int index;
227 if (handle < 0 || (unsigned int) handle >= total_storage_size)
229 DEBUGF ("tried to free an out of bounds handle!!\n");
231 else
233 index = 0;
234 while ((unsigned int) handle >= storage_buffer_size[index])
236 handle -= storage_buffer_size[index++];
238 rb->memset (&storage_buffer[index][handle], 0xFF,
239 sizeof (union storage_t));
240 set_free (index, handle, true);
244 static bool
245 find_free (int *ret_buffer, int *ret_handle)
247 unsigned int handle = next_free_handle;
248 unsigned int buffer_index = next_free_handle_buffer;
250 /* so we know where we started, to prevent infinite loop */
251 unsigned int start_handle = handle;
252 unsigned int start_buffer = buffer_index;
257 ++handle;
259 if (handle >= storage_buffer_size[buffer_index])
261 handle = 0;
265 ++buffer_index;
267 if (buffer_index >= sizeof (storage_initialized) /
268 sizeof (storage_initialized[0]))
270 buffer_index = 0;
273 while (!storage_initialized[buffer_index]);
277 if (is_free (buffer_index, handle))
279 next_free_handle_buffer = buffer_index;
280 next_free_handle = handle;
282 *ret_buffer = buffer_index;
283 *ret_handle = handle;
285 return true;
288 while (handle != start_handle || buffer_index != start_buffer);
290 return false;
293 static bool
294 is_free (int buffer_num, int handle)
296 return storage_free_list[buffer_num][handle / 8] &
297 (1 << (7 - (handle % 8)));
300 static void
301 set_free (int buffer_num, int handle, bool free)
303 if (free)
305 /* simple, just 'or' the byte with the specific bit switched on */
306 storage_free_list[buffer_num][handle / 8] |= 1 << (7 - (handle % 8));
308 else
310 /* start with a byte with all bits turned on and turn off the one
311 we're trying to set to zero. then take that result and 'and'
312 it with the current value */
313 storage_free_list[buffer_num][handle / 8] &=
314 0xFF ^ (1 << (7 - (handle % 8)));
318 bool
319 setup_sgf (void)
321 size_t size;
322 char *temp_buffer;
324 temp_buffer = rb->plugin_get_buffer (&size);
325 setup_storage_buffer (temp_buffer, size);
327 if (total_storage_size < MIN_STORAGE_BUFFER_SIZE)
329 rb->splash (1 * HZ, "Stopping music playback to get more space");
330 DEBUGF ("storage_buffer_size < MIN!!: %d\n", (int) total_storage_size);
332 temp_buffer = rb->plugin_get_audio_buffer (&size);
333 setup_storage_buffer (temp_buffer, size);
336 if (total_storage_size < MIN_STORAGE_BUFFER_SIZE)
338 rb->splash (1 * HZ, "Low memory. Large files may not load.");
340 DEBUGF ("storage_buffer_size < MIN!!!!: %d\n",
341 (int) total_storage_size);
344 DEBUGF ("storage_buffer_size: %d\n", (int) total_storage_size);
347 unhandled_fd = create_or_open_file (UNHANDLED_PROP_LIST_FILE);
349 if (unhandled_fd < 0)
351 return false;
354 rb->lseek (unhandled_fd, 0, SEEK_SET);
355 rb->ftruncate (unhandled_fd, 0);
357 empty_stack (&parse_stack);
359 return true;
363 void
364 clear_caches_sgf (void)
366 empty_stack (&parse_stack);
368 rb->lseek (unhandled_fd, 0, SEEK_SET);
369 rb->ftruncate (unhandled_fd, 0);
372 void
373 cleanup_sgf (void)
375 empty_stack (&parse_stack);
377 rb->lseek (unhandled_fd, 0, SEEK_SET);
378 rb->ftruncate (unhandled_fd, 0);
379 close_file (&unhandled_fd);
381 close_file (&sgf_fd);
384 static bool
385 setup_storage_buffer (char *temp_buffer, size_t size)
387 unsigned int index = 0;
388 int temp;
390 #if PLUGIN_BUFFER_SIZE < 0x10000 && !defined(SIMULATOR)
391 /* loaded as an overlay plugin, protect from overwriting ourselves */
392 if (plugin_start_addr >= (unsigned char *) temp_buffer &&
393 plugin_start_addr < (unsigned char *) temp_buffer + size)
395 size = plugin_start_addr - (unsigned char *) temp_buffer;
397 #endif
399 while (1)
401 if (index >= sizeof (storage_initialized) /
402 sizeof (storage_initialized[0]))
404 return false;
407 if (!storage_initialized[index])
409 break;
411 ++index;
414 temp_buffer = align_buffer (temp_buffer, &size);
415 if (!temp_buffer || !size)
417 return false;
420 /* same as temp = size / (sizeof(union storage_t) + 1/8)
421 (we need 1 bit extra for each union storage_t, for the free list) */
422 temp =
423 (8 * (size - ALIGNMENT_VAL - 1)) / (8 * sizeof (union storage_t) + 1);
424 /* the - ALIGNMENT_VAL - 1 is for possible wasted space in alignment
425 and possible extra byte needed in the free list */
427 storage_buffer[index] = (void *) temp_buffer;
428 storage_buffer_size[index] = temp;
430 storage_free_list_size[index] = storage_buffer_size[index] / 8;
431 if (storage_free_list_size[index] * 8 < storage_buffer_size[index])
433 ++(storage_free_list_size[index]);
436 temp_buffer += sizeof (union storage_t) * temp;
437 size -= sizeof (union storage_t) * temp;
439 temp_buffer = align_buffer (temp_buffer, &size);
440 if (!temp_buffer || !size)
442 return false;
445 if (size < storage_free_list_size[index])
447 DEBUGF ("Big problem on line %d in sgf.c\n", __LINE__);
448 rb->splashf (5 * HZ,
449 "Error in allocating storage buffer! Exit and report this!\n");
450 return false;
453 storage_free_list[index] = temp_buffer;
454 total_storage_size += storage_buffer_size[index];
455 storage_initialized[index] = true;
457 clear_storage_buffer (index);
459 return true;
462 struct node_t *
463 get_node (int handle)
465 if (handle < 0)
467 return NULL;
469 else if ((unsigned int) handle >= total_storage_size)
471 return NULL;
474 int index = 0;
475 while ((unsigned int) handle >= storage_buffer_size[index])
477 handle -= storage_buffer_size[index++];
479 return &(storage_buffer[index][handle].node);
482 struct prop_t *
483 get_prop (int handle)
485 if (handle < 0)
487 return NULL;
489 else if ((unsigned int) handle >= total_storage_size)
491 return NULL;
494 int index = 0;
495 while ((unsigned int) handle >= storage_buffer_size[index])
497 handle -= storage_buffer_size[index++];
499 return &(storage_buffer[index][handle].prop);