Main Page | Directories | File List | Globals | Related Pages

utils.c

Go to the documentation of this file.
00001 /*
00002  * $Id: utils.c,v 1.19 2003/12/01 09:10:17 troth Exp $
00003  *
00004  ****************************************************************************
00005  *
00006  * simulavr - A simulator for the Atmel AVR family of microcontrollers.
00007  * Copyright (C) 2001, 2002, 2003  Theodore A. Roth
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  ****************************************************************************
00024  */
00025 
00026 /**
00027  * \file utils.c
00028  * \brief Utility functions.
00029  *
00030  * This module provides general purpose utilities.
00031  */
00032 
00033 #include <config.h>
00034 
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <unistd.h>
00038 #include <string.h>
00039 #include <errno.h>
00040 #include <sys/time.h>
00041 
00042 #include "avrerror.h"
00043 #include "avrmalloc.h"
00044 #include "avrclass.h"
00045 #include "utils.h"
00046 
00047 /** \brief Utility function to convert a string to a FileFormatType code. */
00048 
00049 int
00050 str2ffmt (char *str)
00051 {
00052     if (strncmp (str, "bin", 3) == 0)
00053         return FFMT_BIN;
00054     if (strncmp (str, "ihex", 4) == 0)
00055         return FFMT_IHEX;
00056     if (strncmp (str, "elf", 3) == 0)
00057         return FFMT_ELF;
00058 
00059     return -1;
00060 }
00061 
00062 /** \brief Set a bit in src to 1 if val != 0, clears bit if val == 0. */
00063 
00064 extern inline uint8_t set_bit_in_byte (uint8_t src, int bit, int val);
00065 
00066 /** \brief Set a bit in src to 1 if val != 0, clears bit if val == 0. */
00067 
00068 extern inline uint16_t set_bit_in_word (uint16_t src, int bit, int val);
00069 
00070 /** \brief Return the number of milliseconds of elapsed program time.
00071 
00072     \return an unsigned 64 bit number. Time zero is not well
00073     defined, so only time differences should be used. */
00074 
00075 uint64_t
00076 get_program_time (void)
00077 {
00078     uint64_t result;
00079     struct timeval tv;
00080 
00081     if (gettimeofday (&tv, NULL) < 0)
00082         avr_error ("Failed to get program time.");
00083 
00084     result = ((uint64_t) tv.tv_sec * 1000) + ((uint64_t) tv.tv_usec / 1000);
00085 
00086     return result;
00087 }
00088 
00089 /***************************************************************************\
00090  *
00091  * DList(AvrClass) Methods : A doubly linked list.
00092  *
00093 \***************************************************************************/
00094 
00095 static DList *dlist_new_node (AvrClass *data);
00096 static void dlist_construct_node (DList *node, AvrClass *data);
00097 static void dlist_destroy_node (void *node);
00098 
00099 #ifndef DOXYGEN                 /* Don't expose to doxygen, structure is
00100                                    opaque. */
00101 
00102 struct _DList
00103 {
00104     AvrClass parent;
00105     struct _DList *prev;
00106     struct _DList *next;
00107     AvrClass *data;
00108 };
00109 
00110 #endif
00111 
00112 static DList *
00113 dlist_new_node (AvrClass *data)
00114 {
00115     DList *node;
00116 
00117     node = avr_new (DList, 1);
00118     dlist_construct_node (node, data);
00119     class_overload_destroy ((AvrClass *)node, dlist_destroy_node);
00120 
00121     return node;
00122 }
00123 
00124 static void
00125 dlist_construct_node (DList *node, AvrClass *data)
00126 {
00127     if (node == NULL)
00128         avr_error ("passed null ptr");
00129 
00130     class_construct ((AvrClass *)node);
00131 
00132     node->prev = NULL;
00133     node->next = NULL;
00134 
00135     node->data = data;
00136 }
00137 
00138 static void
00139 dlist_destroy_node (void *node)
00140 {
00141     DList *_node = (DList *)node;
00142 
00143     if (_node == NULL)
00144         return;
00145 
00146     class_unref (_node->data);
00147 
00148     class_destroy (node);
00149 }
00150 
00151 /** \brief Add a new node to the end of the list.
00152 
00153    If cmp argument is not NULL, use cmp() to see if node already exists and
00154    don't add node if it exists.
00155 
00156    It is the responsibility of this function to unref data if not added. */
00157 
00158 DList *
00159 dlist_add (DList *head, AvrClass *data, DListFP_Cmp cmp)
00160 {
00161     DList *node = head;
00162 
00163     if (head == NULL)
00164         /* The list is empty, make new node the head. */
00165         return dlist_new_node (data);
00166 
00167     /* Walk the list to find the end */
00168 
00169     while (node)
00170     {
00171         if (cmp && ((*cmp) (node->data, data) == 0))
00172         {
00173             /* node already exists and we were asked to keep nodes unique */
00174             class_unref (data);
00175             break;
00176         }
00177 
00178         if (node->next == NULL)
00179         {
00180             /* at the tail */
00181             node->next = dlist_new_node (data);
00182             node->next->prev = node;
00183             break;
00184         }
00185 
00186         /* move on to next node */
00187         node = node->next;
00188     }
00189 
00190     return head;
00191 }
00192 
00193 /** \brief Add a new node at the head of the list. */
00194 
00195 DList *
00196 dlist_add_head (DList *head, AvrClass *data)
00197 {
00198     DList *node = dlist_new_node (data);;
00199 
00200     if (head)
00201     {
00202         head->prev = node;
00203         node->next = head;
00204     }
00205 
00206     return node;
00207 }
00208 
00209 /** \brief Conditionally delete a node from the list.
00210 
00211     Delete a node from the list if the node's data matches the specified
00212     data. Returns the head of the modified list. */
00213 
00214 DList *
00215 dlist_delete (DList *head, AvrClass *data, DListFP_Cmp cmp)
00216 {
00217     DList *node = head;
00218 
00219     if (cmp == NULL)
00220         avr_error ("compare function not specified");
00221 
00222     while (node)
00223     {
00224         if ((*cmp) (node->data, data) == 0)
00225         {
00226             if ((node->prev == NULL) && (node->next == NULL))
00227             {
00228                 /* deleting only node in list (node is head and tail) */
00229                 head = NULL;
00230             }
00231             else if (node->prev == NULL)
00232             {
00233                 /* node is head, but other nodes exist */
00234                 node->next->prev = NULL;
00235                 head = node->next;
00236             }
00237             else if (node->next == NULL)
00238             {
00239                 /* node is tail, but other nodes exist */
00240                 node->prev->next = NULL;
00241             }
00242             else
00243             {
00244                 /* node is not head nor tail */
00245                 node->prev->next = node->next;
00246                 node->next->prev = node->prev;
00247             }
00248 
00249             /* this will also unref the node->data */
00250             class_unref ((AvrClass *)node);
00251 
00252             return head;
00253         }
00254 
00255         /* move on to next node */
00256         node = node->next;
00257     }
00258 
00259     /* if we get here, data wasn't found, just return original head */
00260     return head;
00261 }
00262 
00263 /** \brief Blow away the entire list. */
00264 
00265 void
00266 dlist_delete_all (DList *head)
00267 {
00268     DList *node;
00269 
00270     while (head)
00271     {
00272         node = head;
00273         head = head->next;
00274 
00275         class_unref ((AvrClass *)node);
00276     }
00277 }
00278 
00279 /** \brief Lookup an item in the list.
00280 
00281     Walk the list pointed to by head and return a pointer to the data if
00282     found. If not found, return NULL. 
00283 
00284     \param head The head of the list to be iterated.
00285     \param data The data to be passed to the func when it is applied.
00286     \param cmp  A function to be used for comparing the items.
00287 
00288     \return     A pointer to the data found, or NULL if not found. */
00289 
00290 AvrClass *
00291 dlist_lookup (DList *head, AvrClass *data, DListFP_Cmp cmp)
00292 {
00293     DList *node = head;
00294 
00295     if (cmp == NULL)
00296         avr_error ("compare function not specified");
00297 
00298     while (node)
00299     {
00300         if ((*cmp) (node->data, data) == 0)
00301             return node->data;
00302 
00303         node = node->next;
00304     }
00305 
00306     /* If we get here, no node was found, return NULL. */
00307 
00308     return NULL;
00309 }
00310 
00311 /** \brief Extract the data from the head of the list.
00312 
00313     Returns the data element for the head of the list. If the list is empty,
00314     return a NULL pointer.
00315 
00316     \param head The head of the list.
00317 
00318     \return     A pointer to the data found, or NULL if not found. */
00319 
00320 AvrClass *
00321 dlist_get_head_data (DList *head)
00322 {
00323 
00324     if (head == NULL)
00325     {
00326         return NULL;
00327     }
00328 
00329     return head->data;
00330 }
00331 
00332 /* a simple node compare function for the iterator. */
00333 
00334 static int
00335 dlist_iterator_cmp (AvrClass *n1, AvrClass *n2)
00336 {
00337     /* Since this is only used in the iterator, we are guaranteed that it is
00338        safe to compare data pointers because both n1 and n2 came from the
00339        list. */
00340 
00341     return (int)(n1 - n2);
00342 }
00343 
00344 /** \brief Iterate over all elements of the list.
00345 
00346     For each element, call the user supplied iterator function and pass it the
00347     node data and the user_data. If the iterator function return non-zero,
00348     remove the node from the list.
00349 
00350     \param head The head of the list to be iterated.
00351     \param func The function to be applied.
00352     \param user_data The data to be passed to the func when it is applied.
00353 
00354     \return A pointer to the head of the possibly modified list. */
00355 
00356 DList *
00357 dlist_iterator (DList *head, DListFP_Iter func, void *user_data)
00358 {
00359     DList *node = head;
00360 
00361     if (func == NULL)
00362         avr_error ("no iteration func supplied");
00363 
00364     while (node)
00365     {
00366         if ((*func) (node->data, user_data))
00367         {
00368             /* remove node */
00369             head = dlist_delete (head, node->data, dlist_iterator_cmp);
00370         }
00371 
00372         node = node->next;
00373     }
00374 
00375     return head;
00376 }

Automatically generated by Doxygen 1.4.1 on 21 Oct 2005.