utils.c
Go to the documentation of this file.
1 /*
2  * $Id: utils.c,v 1.20 2008/03/19 22:39:02 joerg_wunsch Exp $
3  *
4  ****************************************************************************
5  *
6  * simulavr - A simulator for the Atmel AVR family of microcontrollers.
7  * Copyright (C) 2001, 2002, 2003 Theodore A. Roth
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  *
23  ****************************************************************************
24  */
25 
26 /**
27  * \file utils.c
28  * \brief Utility functions.
29  *
30  * This module provides general purpose utilities.
31  */
32 
33 #include <config.h>
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <sys/time.h>
41 
42 #include "avrerror.h"
43 #include "avrmalloc.h"
44 #include "avrclass.h"
45 #include "utils.h"
46 
47 /** \brief Utility function to convert a string to a FileFormatType code. */
48 
49 int
50 str2ffmt (char *str)
51 {
52  if (strncmp (str, "bin", 3) == 0)
53  return FFMT_BIN;
54  if (strncmp (str, "ihex", 4) == 0)
55  return FFMT_IHEX;
56  if (strncmp (str, "elf", 3) == 0)
57  return FFMT_ELF;
58 
59  return -1;
60 }
61 
62 /** \brief Set a bit in src to 1 if val != 0, clears bit if val == 0. */
63 
64 extern inline uint8_t set_bit_in_byte (uint8_t src, int bit, int val);
65 
66 /** \brief Set a bit in src to 1 if val != 0, clears bit if val == 0. */
67 
68 extern inline uint16_t set_bit_in_word (uint16_t src, int bit, int val);
69 
70 /** \brief Return the number of milliseconds of elapsed program time.
71 
72  \return an unsigned 64 bit number. Time zero is not well
73  defined, so only time differences should be used. */
74 
75 uint64_t
77 {
78  uint64_t result;
79  struct timeval tv;
80 
81  if (gettimeofday (&tv, NULL) < 0)
82  avr_error ("Failed to get program time.");
83 
84  result = ((uint64_t) tv.tv_sec * 1000) + ((uint64_t) tv.tv_usec / 1000);
85 
86  return result;
87 }
88 
89 /***************************************************************************\
90  *
91  * DList(AvrClass) Methods : A doubly linked list.
92  *
93 \***************************************************************************/
94 
95 static DList *dlist_new_node (AvrClass *data);
96 static void dlist_construct_node (DList *node, AvrClass *data);
97 static void dlist_destroy_node (void *node);
98 
99 #ifndef DOXYGEN /* Don't expose to doxygen, structure is
100  opaque. */
101 
102 struct _DList
103 {
104  AvrClass parent;
105  struct _DList *prev;
106  struct _DList *next;
107  AvrClass *data;
108 };
109 
110 #endif
111 
112 static DList *
113 dlist_new_node (AvrClass *data)
114 {
115  DList *node;
116 
117  node = avr_new (DList, 1);
118  dlist_construct_node (node, data);
119  class_overload_destroy ((AvrClass *)node, dlist_destroy_node);
120 
121  return node;
122 }
123 
124 static void
125 dlist_construct_node (DList *node, AvrClass *data)
126 {
127  if (node == NULL)
128  avr_error ("passed null ptr");
129 
130  class_construct ((AvrClass *)node);
131 
132  node->prev = NULL;
133  node->next = NULL;
134 
135  node->data = data;
136 }
137 
138 static void
139 dlist_destroy_node (void *node)
140 {
141  DList *_node = (DList *)node;
142 
143  if (_node == NULL)
144  return;
145 
146  class_unref (_node->data);
147 
148  class_destroy (node);
149 }
150 
151 /** \brief Add a new node to the end of the list.
152 
153  If cmp argument is not NULL, use cmp() to see if node already exists and
154  don't add node if it exists.
155 
156  It is the responsibility of this function to unref data if not added. */
157 
158 DList *
159 dlist_add (DList *head, AvrClass *data, DListFP_Cmp cmp)
160 {
161  DList *node = head;
162 
163  if (head == NULL)
164  /* The list is empty, make new node the head. */
165  return dlist_new_node (data);
166 
167  /* Walk the list to find the end */
168 
169  while (node)
170  {
171  if (cmp && ((*cmp) (node->data, data) == 0))
172  {
173  /* node already exists and we were asked to keep nodes unique */
174  class_unref (data);
175  break;
176  }
177 
178  if (node->next == NULL)
179  {
180  /* at the tail */
181  node->next = dlist_new_node (data);
182  node->next->prev = node;
183  break;
184  }
185 
186  /* move on to next node */
187  node = node->next;
188  }
189 
190  return head;
191 }
192 
193 /** \brief Add a new node at the head of the list. */
194 
195 DList *
196 dlist_add_head (DList *head, AvrClass *data)
197 {
198  DList *node = dlist_new_node (data);;
199 
200  if (head)
201  {
202  head->prev = node;
203  node->next = head;
204  }
205 
206  return node;
207 }
208 
209 /** \brief Conditionally delete a node from the list.
210 
211  Delete a node from the list if the node's data matches the specified
212  data. Returns the head of the modified list. */
213 
214 DList *
215 dlist_delete (DList *head, AvrClass *data, DListFP_Cmp cmp)
216 {
217  DList *node = head;
218 
219  if (cmp == NULL)
220  avr_error ("compare function not specified");
221 
222  while (node)
223  {
224  if ((*cmp) (node->data, data) == 0)
225  {
226  if ((node->prev == NULL) && (node->next == NULL))
227  {
228  /* deleting only node in list (node is head and tail) */
229  head = NULL;
230  }
231  else if (node->prev == NULL)
232  {
233  /* node is head, but other nodes exist */
234  node->next->prev = NULL;
235  head = node->next;
236  }
237  else if (node->next == NULL)
238  {
239  /* node is tail, but other nodes exist */
240  node->prev->next = NULL;
241  }
242  else
243  {
244  /* node is not head nor tail */
245  node->prev->next = node->next;
246  node->next->prev = node->prev;
247  }
248 
249  /* this will also unref the node->data */
250  class_unref ((AvrClass *)node);
251 
252  return head;
253  }
254 
255  /* move on to next node */
256  node = node->next;
257  }
258 
259  /* if we get here, data wasn't found, just return original head */
260  return head;
261 }
262 
263 /** \brief Blow away the entire list. */
264 
265 void
266 dlist_delete_all (DList *head)
267 {
268  DList *node;
269 
270  while (head)
271  {
272  node = head;
273  head = head->next;
274 
275  class_unref ((AvrClass *)node);
276  }
277 }
278 
279 /** \brief Lookup an item in the list.
280 
281  Walk the list pointed to by head and return a pointer to the data if
282  found. If not found, return NULL.
283 
284  \param head The head of the list to be iterated.
285  \param data The data to be passed to the func when it is applied.
286  \param cmp A function to be used for comparing the items.
287 
288  \return A pointer to the data found, or NULL if not found. */
289 
290 AvrClass *
291 dlist_lookup (DList *head, AvrClass *data, DListFP_Cmp cmp)
292 {
293  DList *node = head;
294 
295  if (cmp == NULL)
296  avr_error ("compare function not specified");
297 
298  while (node)
299  {
300  if ((*cmp) (node->data, data) == 0)
301  return node->data;
302 
303  node = node->next;
304  }
305 
306  /* If we get here, no node was found, return NULL. */
307 
308  return NULL;
309 }
310 
311 /** \brief Extract the data from the head of the list.
312 
313  Returns the data element for the head of the list. If the list is empty,
314  return a NULL pointer.
315 
316  \param head The head of the list.
317 
318  \return A pointer to the data found, or NULL if not found. */
319 
320 AvrClass *
321 dlist_get_head_data (DList *head)
322 {
323 
324  if (head == NULL)
325  {
326  return NULL;
327  }
328 
329  return head->data;
330 }
331 
332 /* a simple node compare function for the iterator. */
333 
334 static int
335 dlist_iterator_cmp (AvrClass *n1, AvrClass *n2)
336 {
337  /* Since this is only used in the iterator, we are guaranteed that it is
338  safe to compare data pointers because both n1 and n2 came from the
339  list. */
340 
341  return (int)(n1 - n2);
342 }
343 
344 /** \brief Iterate over all elements of the list.
345 
346  For each element, call the user supplied iterator function and pass it the
347  node data and the user_data. If the iterator function return non-zero,
348  remove the node from the list.
349 
350  \param head The head of the list to be iterated.
351  \param func The function to be applied.
352  \param user_data The data to be passed to the func when it is applied.
353 
354  \return A pointer to the head of the possibly modified list. */
355 
356 DList *
357 dlist_iterator (DList *head, DListFP_Iter func, void *user_data)
358 {
359  DList *node = head;
360  DList *n;
361 
362  if (func == NULL)
363  avr_error ("no iteration func supplied");
364 
365  while (node)
366  {
367  n = node->next;
368 
369  if ((*func) (node->data, user_data))
370  {
371  /* remove node */
372  head = dlist_delete (head, node->data, dlist_iterator_cmp);
373  }
374 
375  node = n;
376  }
377 
378  return head;
379 }

Automatically generated by Doxygen 1.8.2 on Sun Mar 17 2013.