Put all of the UI utility functions into the "git" namespace.
[anjuta-git-plugin.git] / plugins / debug-manager / data_buffer.c
blobe8b8cfe3d8fae71e20f44a896b2774c608dd386a
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 data_buffer.c
4 Copyright (C) 2006 Sebastien Granjoux
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "data_buffer.h"
23 #include "anjuta-marshal.h"
25 /*#define DEBUG*/
26 #include <libanjuta/anjuta-debug.h>
28 #include <string.h>
29 #include <glib/gprintf.h>
31 enum
33 DMA_DATA_BUFFER_PAGE_SIZE = 512,
34 DMA_DATA_BUFFER_LAST_LEVEL_SIZE = 8,
35 DMA_DATA_BUFFER_LEVEL_SIZE = 16,
36 DMA_DATA_BUFFER_LEVEL = 6
39 enum
41 DMA_DATA_UNDEFINED = 0,
42 DMA_DATA_MODIFIED = 1,
43 DMA_DATA_SAME = 2
46 typedef struct _DmaDataBufferPage DmaDataBufferPage;
47 typedef struct _DmaDataBufferNode DmaDataBufferNode;
48 typedef struct _DmaDataBufferLastNode DmaDataBufferLastNode;
50 struct _DmaDataBufferPage
52 gchar data[DMA_DATA_BUFFER_PAGE_SIZE];
53 gchar tag[DMA_DATA_BUFFER_PAGE_SIZE];
54 guint validation;
57 struct _DmaDataBufferNode
59 DmaDataBufferNode *child[DMA_DATA_BUFFER_LEVEL_SIZE];
62 struct _DmaDataBufferLastNode
64 DmaDataBufferPage *child[DMA_DATA_BUFFER_LAST_LEVEL_SIZE];
67 struct _DmaDataBuffer
69 GObject parent;
71 gulong lower;
72 gulong upper;
74 DmaDataBufferReadFunc read;
75 DmaDataBufferWriteFunc write;
76 gpointer user_data;
78 guint validation;
79 DmaDataBufferNode *top;
82 struct _DmaDataBufferClass
84 GObjectClass parent;
86 void (*changed_notify) (DmaDataBuffer *buffer, gulong lower, gulong upper);
89 static GObjectClass *parent_class = NULL;
91 typedef gchar * (*DmaDisplayDataFunc) (gchar *string, const char *data, const char *tag);
93 enum
95 CHANGED_NOTIFY,
96 LAST_SIGNAL
99 static guint signals[LAST_SIGNAL] = {0};
102 /* Helper functions
103 *---------------------------------------------------------------------------*/
105 static gchar *
106 display_in_octal (gchar *string, const gchar *data, const gchar *tag)
108 if ((data == NULL) || (*tag == DMA_DATA_UNDEFINED))
110 memcpy(string, "??? ", 4);
112 else
114 g_sprintf (string, "%03o ", ((unsigned)*data) & 0xFFU);
117 return string + 4;
120 static gchar *
121 display_in_decimal (gchar *string, const gchar *data, const gchar *tag)
123 if ((data == NULL) || (*tag == DMA_DATA_UNDEFINED))
125 memcpy(string, "??? ", 4);
127 else
129 g_sprintf (string, "%3u ", ((unsigned)*data) & 0xFFU);
132 return string + 4;
135 static gchar *
136 display_in_hexadecimal (gchar *string, const gchar *data, const gchar *tag)
138 if ((data == NULL) || (*tag == DMA_DATA_UNDEFINED))
140 memcpy(string, "?? ", 3);
142 else
144 g_sprintf (string, "%02X ", ((unsigned)*data) & 0xFFU);
147 return string + 3;
150 static gchar *
151 display_in_ascii (gchar *string, const gchar *data, const gchar *tag)
153 if ((data == NULL) || (*tag == DMA_DATA_UNDEFINED))
155 *string = '?';
157 else if (g_ascii_isprint (*data))
159 *string = *data;
161 else
163 *string = '.';
166 return string + 1;
169 /* DmaBufferNode functions
170 *---------------------------------------------------------------------------*/
172 static DmaDataBufferNode**
173 dma_data_buffer_find_node (DmaDataBuffer *buffer, gulong address)
175 DmaDataBufferNode **node;
176 gint i;
178 node = &buffer->top;
179 address /= DMA_DATA_BUFFER_PAGE_SIZE;
180 for (i = DMA_DATA_BUFFER_LEVEL - 1; i >= 0; --i)
182 if (*node == NULL)
184 if (i == 0)
186 *node = (DmaDataBufferNode *)g_new0 (DmaDataBufferLastNode, 1);
188 else
190 *node = g_new0 (DmaDataBufferNode, 1);
193 node = &((*node)->child[address % (i == 0 ? DMA_DATA_BUFFER_LAST_LEVEL_SIZE : DMA_DATA_BUFFER_LEVEL_SIZE)]);
194 address /= DMA_DATA_BUFFER_LEVEL_SIZE;
197 return node;
200 #if 0
201 static DmaDataBufferPage*
202 dma_data_buffer_get_page (DmaDataBuffer *buffer, gulong address)
204 DmaDataBufferNode **node;
206 node = dma_data_buffer_find_node (buffer, address);
208 return (DmaDataBufferPage *)*node;
210 #endif
212 static DmaDataBufferPage*
213 dma_data_buffer_add_page (DmaDataBuffer *buffer, gulong address)
215 DmaDataBufferNode **node;
216 DmaDataBufferPage *page;
218 node = dma_data_buffer_find_node (buffer, address);
220 if (*node == NULL)
222 *node = (DmaDataBufferNode *)g_new0 (DmaDataBufferPage, 1);
223 page = (DmaDataBufferPage *)*node;
224 page->validation = buffer->validation - 1;
226 else
228 page = (DmaDataBufferPage *)*node;
231 return page;
234 static DmaDataBufferPage*
235 dma_data_buffer_read_page (DmaDataBuffer *buffer, gulong address)
237 DmaDataBufferPage *page;
239 page = dma_data_buffer_add_page (buffer, address);
241 if ((page == NULL) || (page->validation != buffer->validation))
243 if (page != NULL) page->validation = buffer->validation;
244 /* Data need to be refresh */
245 if (buffer->read != NULL);
246 buffer->read (address - (address % DMA_DATA_BUFFER_PAGE_SIZE), DMA_DATA_BUFFER_PAGE_SIZE, buffer->user_data);
248 return page;
252 return page;
255 static void
256 dma_data_buffer_free_node (DmaDataBufferNode *node, gint level)
258 gint i;
260 for (i = (level == 0 ? DMA_DATA_BUFFER_LAST_LEVEL_SIZE : DMA_DATA_BUFFER_LEVEL_SIZE) - 1; i >= 0; --i)
262 if (node->child[i] != NULL)
264 if (level != 0)
266 dma_data_buffer_free_node (node->child[i], level - 1);
268 g_free (node->child[i]);
273 /* Private functions
274 *---------------------------------------------------------------------------*/
277 static void
278 dma_data_buffer_changed_notify (DmaDataBuffer *buffer, gulong lower, gulong upper)
282 /* Public functions
283 *---------------------------------------------------------------------------*/
285 void
286 dma_data_buffer_remove_all_page (DmaDataBuffer *buffer)
288 if (buffer->top != NULL)
290 dma_data_buffer_free_node (buffer->top, DMA_DATA_BUFFER_LEVEL - 1);
291 g_free (buffer->top);
292 buffer->top = NULL;
296 gulong
297 dma_data_buffer_get_lower (const DmaDataBuffer *buffer)
299 return buffer->lower;
302 gulong
303 dma_data_buffer_get_upper (const DmaDataBuffer *buffer)
305 return buffer->upper;
308 gchar *
309 dma_data_buffer_get_address (DmaDataBuffer *buffer, gulong lower, guint length, guint step, guint size)
311 gchar *data;
312 gchar *ptr;
313 guint line;
315 line = (length + step - 1) / step;
317 data = g_strnfill (line * (size + 1), ' ');
318 for (ptr = data; line != 0; --line)
320 g_sprintf (ptr, "%0*lx\n", size, lower);
321 lower += step;
322 ptr += size + 1;
324 *(ptr - 1) = '\0';
326 return data;
329 gchar *
330 dma_data_buffer_get_data (DmaDataBuffer *buffer, gulong lower, guint length, guint step, gint base)
332 static const DmaDisplayDataFunc format_table[] = {display_in_octal,
333 display_in_decimal,
334 display_in_hexadecimal,
335 display_in_ascii};
336 gchar *text;
337 gchar *ptr;
338 guint line;
339 guint col;
340 DmaDisplayDataFunc display;
341 guint inc;
342 gchar dummy[16];
343 gchar *data = NULL;
344 gchar *tag = NULL;
345 guint len;
347 line = (length + step - 1) / step;
349 switch (base & DMA_DATA_BASE)
351 case DMA_OCTAL_BASE:
352 case DMA_DECIMAL_BASE:
353 case DMA_HEXADECIMAL_BASE:
354 case DMA_ASCII_BASE:
355 display = format_table[base & DMA_DATA_BASE];
356 break;
357 default:
358 display = format_table[DMA_HEXADECIMAL_BASE];
359 break;
362 /* Dummy call of display function to know the increment */
363 ptr = display (dummy, NULL, NULL);
364 inc = ptr - dummy;
366 text = g_strnfill (line * (step * inc + 1), ' ');
367 len = 0;
368 for (ptr = text; line != 0; --line)
370 for (col = step; col != 0; --col)
372 if (len == 0)
374 DmaDataBufferPage *node;
375 /* Get new data */
376 node = dma_data_buffer_read_page (buffer, lower);
377 if (node == NULL)
379 data = NULL;
380 tag = NULL;
382 else
384 data = &(node->data[lower % DMA_DATA_BUFFER_PAGE_SIZE]);
385 tag = &(node->tag[lower % DMA_DATA_BUFFER_PAGE_SIZE]);
387 len = DMA_DATA_BUFFER_PAGE_SIZE - (lower % DMA_DATA_BUFFER_PAGE_SIZE);
389 ptr = display (ptr, data, tag);
390 if (data != NULL)
392 data++;
393 tag++;
395 lower++;
396 len--;
398 if (inc != 1) --ptr; /* Remove last space */
399 *ptr++ = '\n';
401 *(ptr - 1) = '\0'; /* Remove last carriage return */
403 return text;
406 void
407 dma_data_buffer_invalidate (DmaDataBuffer *buffer)
409 buffer->validation++;
412 void
413 dma_data_buffer_set_data (DmaDataBuffer *buffer, gulong address, gulong length, const gchar *data)
415 gulong upper;
416 gulong lower;
418 if (length == 0) return;
420 upper = address + length -1UL;
421 lower = address;
423 while (length)
425 DmaDataBufferPage *page;
426 guint len;
428 page = dma_data_buffer_add_page (buffer, address);
429 len = DMA_DATA_BUFFER_PAGE_SIZE - (address % DMA_DATA_BUFFER_PAGE_SIZE);
430 if (len > length) len = length;
431 memcpy (&page->data[address % DMA_DATA_BUFFER_PAGE_SIZE], data, len);
432 memset (&page->tag[address % DMA_DATA_BUFFER_PAGE_SIZE], DMA_DATA_MODIFIED, len);
433 page->validation = buffer->validation;
435 length -= len;
436 address += len;
438 g_signal_emit (buffer, signals[CHANGED_NOTIFY], 0, lower, upper);
441 /* GObject functions
442 *---------------------------------------------------------------------------*/
444 /* Used in dispose and finalize */
446 /* dispose is the first destruction step. It is used to unref object created
447 * with instance_init in order to break reference counting cycles. This
448 * function could be called several times. All function should still work
449 * after this call. It has to called its parents.*/
451 static void
452 dma_data_buffer_dispose (GObject *object)
454 /*DmaDataBuffer *this = DMA_DATA_BUFFER (object);*/
456 (* parent_class->dispose) (object);
459 /* finalize is the last destruction step. It must free all memory allocated
460 * with instance_init. It is called only one time just before releasing all
461 * memory */
463 static void
464 dma_data_buffer_finalize (GObject *object)
466 DmaDataBuffer *buffer = DMA_DATA_BUFFER (object);
468 dma_data_buffer_remove_all_page (buffer);
470 (* parent_class->finalize) (object);
473 /* instance_init is the constructor. All functions should work after this
474 * call. */
476 static void
477 dma_data_buffer_instance_init (DmaDataBuffer *this)
479 this->lower = 0;
480 this->upper = 0;
481 this->top = NULL;
484 /* class_init intialize the class itself not the instance */
486 static void
487 dma_data_buffer_class_init (DmaDataBufferClass * klass)
489 GObjectClass *object_class;
491 g_return_if_fail (klass != NULL);
493 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
495 object_class = G_OBJECT_CLASS (klass);
496 object_class->dispose = dma_data_buffer_dispose;
497 object_class->finalize = dma_data_buffer_finalize;
499 klass->changed_notify = dma_data_buffer_changed_notify;
501 signals[CHANGED_NOTIFY] = g_signal_new ("changed_notify",
502 G_OBJECT_CLASS_TYPE (object_class),
503 G_SIGNAL_RUN_LAST,
504 G_STRUCT_OFFSET (DmaDataBufferClass, changed_notify),
505 NULL, NULL,
506 anjuta_marshal_VOID__ULONG_ULONG,
507 G_TYPE_NONE,
509 G_TYPE_ULONG,
510 G_TYPE_ULONG);
513 GType
514 dma_data_buffer_get_type (void)
516 static GType type = 0;
518 if (!type)
520 static const GTypeInfo type_info =
522 sizeof (DmaDataBufferClass),
523 (GBaseInitFunc) NULL,
524 (GBaseFinalizeFunc) NULL,
525 (GClassInitFunc) dma_data_buffer_class_init,
526 (GClassFinalizeFunc) NULL,
527 NULL, /* class_data */
528 sizeof (DmaDataBuffer),
529 0, /* n_preallocs */
530 (GInstanceInitFunc) dma_data_buffer_instance_init,
531 NULL /* value_table */
534 type = g_type_register_static (G_TYPE_OBJECT,
535 "DmaDataBuffer", &type_info, 0);
538 return type;
541 /* Creation and Destruction
542 *---------------------------------------------------------------------------*/
544 DmaDataBuffer*
545 dma_data_buffer_new (gulong lower, gulong upper, DmaDataBufferReadFunc read, DmaDataBufferWriteFunc write, gpointer user_data)
547 DmaDataBuffer *buffer;
549 buffer = g_object_new (DMA_DATA_BUFFER_TYPE, NULL);
550 g_assert (buffer != NULL);
552 buffer->lower = lower;
553 buffer->upper = upper;
554 buffer->read = read;
555 buffer->write = write;
556 buffer->user_data = user_data;
558 return buffer;
561 void
562 dma_data_buffer_free (DmaDataBuffer *buffer)
564 g_object_unref (buffer);