Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

print-list.c

Go to the documentation of this file.
00001 /*
00002  * "$Id: print-list.c,v 1.22 2004/12/06 00:39:48 rlk Exp $"
00003  *
00004  *   Gutenprint list functions.  A doubly-linked list implementation,
00005  *   with callbacks for freeing, sorting, and retrieving nodes by name
00006  *   or long name.
00007  *
00008  *   Copyright 2002 Roger Leigh (rleigh@debian.org)
00009  *
00010  *   This program is free software; you can redistribute it and/or modify it
00011  *   under the terms of the GNU General Public License as published by the Free
00012  *   Software Foundation; either version 2 of the License, or (at your option)
00013  *   any later version.
00014  *
00015  *   This program is distributed in the hope that it will be useful, but
00016  *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00017  *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00018  *   for more details.
00019  *
00020  *   You should have received a copy of the GNU General Public License
00021  *   along with this program; if not, write to the Free Software
00022  *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00023  */
00024 
00025 /*
00026  * This file must include only standard C header files.  The core code must
00027  * compile on generic platforms that don't support glib, gimp, etc.
00028  */
00029 
00030 
00031 #ifdef HAVE_CONFIG_H
00032 #include <config.h>
00033 #endif
00034 #include <gutenprint/gutenprint.h>
00035 #include "gutenprint-internal.h"
00036 #include <gutenprint/gutenprint-intl-internal.h>
00037 #include <assert.h>
00038 #include <stdlib.h>
00039 #include <stdio.h>
00040 #include <string.h>
00041 
00043 struct stp_list_item
00044 {
00045   void *data;                   
00046   struct stp_list_item *prev;   
00047   struct stp_list_item *next;   
00048 };
00049 
00051 struct stp_list
00052 {
00053   int index_cache;                              
00054   struct stp_list_item *start;                  
00055   struct stp_list_item *end;                    
00056   struct stp_list_item *index_cache_node;       
00057   int length;                                   
00058   stp_node_freefunc freefunc;                   
00059   stp_node_copyfunc copyfunc;                   
00060   stp_node_namefunc namefunc;                   
00061   stp_node_namefunc long_namefunc;              
00062   stp_node_sortfunc sortfunc;                   
00063   char *name_cache;                             
00064   struct stp_list_item *name_cache_node;        
00065   char *long_name_cache;                        
00066   struct stp_list_item *long_name_cache_node;   
00067 };
00068 
00075 static void
00076 set_name_cache(stp_list_t *list,
00077                const char *name,
00078                stp_list_item_t *cache)
00079 {
00080   if (list->name_cache)
00081     stp_free(list->name_cache);
00082   list->name_cache = NULL;
00083   if (name)
00084     list->name_cache = stp_strdup(name);
00085   list->name_cache_node = cache;
00086 }
00087 
00094 static void
00095 set_long_name_cache(stp_list_t *list,
00096                     const char *long_name,
00097                     stp_list_item_t *cache)
00098 {
00099   if (list->long_name_cache)
00100     stp_free(list->long_name_cache);
00101   list->long_name_cache = NULL;
00102   if (long_name)
00103     list->long_name_cache = stp_strdup(long_name);
00104   list->long_name_cache_node = cache;
00105 }
00106 
00111 static inline void
00112 clear_cache(stp_list_t *list)
00113 {
00114   list->index_cache = 0;
00115   list->index_cache_node = NULL;
00116   set_name_cache(list, NULL, NULL);
00117   set_long_name_cache(list, NULL, NULL);
00118 }
00119 
00120 void
00121 stp_list_node_free_data (void *item)
00122 {
00123   stp_free(item);
00124   stp_deprintf(STP_DBG_LIST, "stp_list_node_free_data destructor\n");
00125 }
00126 
00128 #define check_list(List) assert(List != NULL)
00129 
00130 /* List head functions.
00131  * These functions operate on the list as a whole, and not the
00132  * individual nodes in a list. */
00133 
00134 /* create a new list */
00135 stp_list_t *
00136 stp_list_create(void)
00137 {
00138   stp_list_t *list =
00139     stp_malloc(sizeof(stp_list_t));
00140 
00141   /* initialise an empty list */
00142   list->index_cache = 0;
00143   list->length = 0;
00144   list->start = NULL;
00145   list->end = NULL;
00146   list->index_cache_node = NULL;
00147   list->freefunc = NULL;
00148   list->namefunc = NULL;
00149   list->long_namefunc = NULL;
00150   list->sortfunc = NULL;
00151   list->copyfunc = NULL;
00152   list->name_cache = NULL;
00153   list->name_cache_node = NULL;
00154   list->long_name_cache = NULL;
00155   list->long_name_cache_node = NULL;
00156 
00157   stp_deprintf(STP_DBG_LIST, "stp_list_head constructor\n");
00158   return list;
00159 }
00160 
00161 stp_list_t *
00162 stp_list_copy(const stp_list_t *list)
00163 {
00164   stp_list_t *ret;
00165   stp_node_copyfunc copyfunc = stp_list_get_copyfunc(list);
00166   stp_list_item_t *item = list->start;
00167 
00168   check_list(list);
00169 
00170   ret = stp_list_create();
00171   stp_list_set_copyfunc(ret, stp_list_get_copyfunc(list));
00172   /* If we use default (shallow) copy, we can't free the elements of it */
00173   if (stp_list_get_copyfunc(list))
00174     stp_list_set_freefunc(ret, stp_list_get_freefunc(list));
00175   stp_list_set_namefunc(ret, stp_list_get_namefunc(list));
00176   stp_list_set_long_namefunc(ret, stp_list_get_long_namefunc(list));
00177   stp_list_set_sortfunc(ret, stp_list_get_sortfunc(list));
00178   while (item)
00179     {
00180       void *data = item->data;
00181       if (copyfunc)
00182         stp_list_item_create (ret, NULL, (*copyfunc)(data));
00183       else
00184         stp_list_item_create(ret, NULL, data);
00185       item = stp_list_item_next(item);
00186     }
00187   return ret;
00188 }
00189 
00190 /* free a list, freeing all child nodes first */
00191 int
00192 stp_list_destroy(stp_list_t *list)
00193 {
00194   stp_list_item_t *cur;
00195   stp_list_item_t *next;
00196 
00197   check_list(list);
00198   clear_cache(list);
00199   cur = list->start;
00200   while(cur)
00201     {
00202       next = cur->next;
00203       stp_list_item_destroy(list, cur);
00204       cur = next;
00205     }
00206   stp_deprintf(STP_DBG_LIST, "stp_list_head destructor\n");
00207   stp_free(list);
00208 
00209   return 0;
00210 }
00211 
00212 int
00213 stp_list_get_length(const stp_list_t *list)
00214 {
00215   check_list(list);
00216   return list->length;
00217 }
00218 
00219 /* find a node */
00220 
00221 /* get the first node in the list */
00222 
00223 stp_list_item_t *
00224 stp_list_get_start(const stp_list_t *list)
00225 {
00226   return list->start;
00227 }
00228 
00229 /* get the last node in the list */
00230 
00231 stp_list_item_t *
00232 stp_list_get_end(const stp_list_t *list)
00233 {
00234   return list->end;
00235 }
00236 
00237 /* get the node by its place in the list */
00238 stp_list_item_t *
00239 stp_list_get_item_by_index(const stp_list_t *list, int idx)
00240 {
00241   stp_list_item_t *node = NULL;
00242   int i; /* current index */
00243   int d = 0; /* direction of list traversal, 0=forward */
00244   int c = 0; /* use cache? */
00245   check_list(list);
00246 
00247   if (idx >= list->length)
00248     return NULL;
00249 
00250   /* see if using the cache is worthwhile */
00251   if (list->index_cache)
00252     {
00253       if (idx < (list->length/2))
00254         {
00255           if (idx > abs(idx - list->index_cache))
00256             c = 1;
00257           else
00258             d = 0;
00259         }
00260       else
00261         {
00262           if (list->length - 1 - idx >
00263               abs (list->length - 1 - idx - list->index_cache))
00264             c = 1;
00265           else
00266             d = 1;
00267         }
00268     }
00269 
00270 
00271   if (c) /* use the cached index and node */
00272     {
00273       if (idx > list->index_cache) /* forward */
00274         d = 0;
00275       else /* backward */
00276         d = 1;
00277       i = list->index_cache;
00278       node = list->index_cache_node;
00279     }
00280   else /* start from one end of the list */
00281     {
00282       if (d)
00283         {
00284           i = list->length - 1;
00285           node = list->end;
00286         }
00287       else
00288         {
00289           i = 0;
00290           node = list->start;
00291         }
00292     }
00293 
00294   while (node && i != idx)
00295     {
00296       if (d)
00297         {
00298           i--;
00299           node = node->prev;
00300         }
00301       else
00302         {
00303           i++;
00304           node = node->next;
00305         }
00306     }
00307 
00308   /* update cache */
00309   ((stp_list_t *)list)->index_cache = i;
00310   ((stp_list_t *)list)->index_cache_node = node;
00311 
00312   return node;
00313 }
00314 
00323 static stp_list_item_t *
00324 stp_list_get_item_by_name_internal(const stp_list_t *list, const char *name)
00325 {
00326   stp_list_item_t *node = list->start;
00327   while (node && strcmp(name, list->namefunc(node->data)))
00328     {
00329       node = node->next;
00330     }
00331   return node;
00332 }
00333 
00334 /* get the first node with name; requires a callback function to
00335    read data */
00336 stp_list_item_t *
00337 stp_list_get_item_by_name(const stp_list_t *list, const char *name)
00338 {
00339   stp_list_item_t *node = NULL;
00340   check_list(list);
00341 
00342   if (!list->namefunc)
00343     return NULL;
00344 
00345   if (list->name_cache && name && list->name_cache_node)
00346     {
00347       const char *new_name;
00348       node = list->name_cache_node;
00349       /* Is this the item we've cached? */
00350       if (strcmp(name, list->name_cache) == 0 &&
00351           strcmp(name, list->namefunc(node->data)) == 0)
00352         return node;
00353 
00354       /* If not, check the next item in case we're searching the list */
00355       node = node->next;
00356       if (node)
00357         {
00358           new_name = list->namefunc(node->data);
00359           if (strcmp(name, new_name) == 0)
00360             {
00361               set_name_cache((stp_list_t *) list, new_name, node);
00362               return node;
00363             }
00364         }
00365       /* If not, check the index cache */
00366       node = list->index_cache_node;
00367       if (node)
00368         {
00369           new_name = list->namefunc(node->data);
00370           if (strcmp(name, new_name) == 0)
00371             {
00372               set_name_cache((stp_list_t *) list, new_name, node);
00373               return node;
00374             }
00375         }
00376     }
00377 
00378   node = stp_list_get_item_by_name_internal(list, name);
00379 
00380   if (node)
00381     set_name_cache((stp_list_t *) list, name, node);
00382 
00383   return node;
00384 }
00385 
00386 
00395 static stp_list_item_t *
00396 stp_list_get_item_by_long_name_internal(const stp_list_t *list,
00397                                          const char *long_name)
00398 {
00399   stp_list_item_t *node = list->start;
00400   while (node && strcmp(long_name, list->long_namefunc(node->data)))
00401     {
00402       node = node->next;
00403     }
00404   return node;
00405 }
00406 
00407 /* get the first node with long_name; requires a callack function to
00408    read data */
00409 stp_list_item_t *
00410 stp_list_get_item_by_long_name(const stp_list_t *list, const char *long_name)
00411 {
00412   stp_list_item_t *node = NULL;
00413   check_list(list);
00414 
00415   if (!list->long_namefunc)
00416     return NULL;
00417 
00418   if (list->long_name_cache && long_name && list->long_name_cache_node)
00419     {
00420       const char *new_long_name;
00421       node = list->long_name_cache_node;
00422       /* Is this the item we've cached? */
00423       if (strcmp(long_name, list->long_name_cache) == 0 &&
00424           strcmp(long_name, list->long_namefunc(node->data)) == 0)
00425         return node;
00426 
00427       /* If not, check the next item in case we're searching the list */
00428       node = node->next;
00429       if (node)
00430         {
00431           new_long_name = list->long_namefunc(node->data);
00432           if (strcmp(long_name, new_long_name) == 0)
00433             {
00434               set_long_name_cache((stp_list_t*) list, new_long_name, node);
00435               return node;
00436             }
00437         }
00438       /* If not, check the index cache */
00439       node = list->index_cache_node;
00440       if (node)
00441         {
00442           new_long_name = list->long_namefunc(node->data);
00443           if (strcmp(long_name, new_long_name) == 0)
00444             {
00445               set_long_name_cache((stp_list_t *) list, new_long_name, node);
00446               return node;
00447             }
00448         }
00449     }
00450 
00451   node = stp_list_get_item_by_long_name_internal(list, long_name);
00452 
00453   if (node)
00454     set_long_name_cache((stp_list_t *) list, long_name, node);
00455 
00456   return node;
00457 }
00458 
00459 
00460 /* callback for freeing data */
00461 void
00462 stp_list_set_freefunc(stp_list_t *list, stp_node_freefunc freefunc)
00463 {
00464   check_list(list);
00465   list->freefunc = freefunc;
00466 }
00467 
00468 stp_node_freefunc
00469 stp_list_get_freefunc(const stp_list_t *list)
00470 {
00471   check_list(list);
00472   return list->freefunc;
00473 }
00474 
00475 /* callback for copying data */
00476 void
00477 stp_list_set_copyfunc(stp_list_t *list, stp_node_copyfunc copyfunc)
00478 {
00479   check_list(list);
00480   list->copyfunc = copyfunc;
00481 }
00482 
00483 stp_node_copyfunc
00484 stp_list_get_copyfunc(const stp_list_t *list)
00485 {
00486   check_list(list);
00487   return list->copyfunc;
00488 }
00489 
00490 /* callback for getting data name */
00491 void
00492 stp_list_set_namefunc(stp_list_t *list, stp_node_namefunc namefunc)
00493 {
00494   check_list(list);
00495   list->namefunc = namefunc;
00496 }
00497 
00498 stp_node_namefunc
00499 stp_list_get_namefunc(const stp_list_t *list)
00500 {
00501   check_list(list);
00502   return list->namefunc;
00503 }
00504 
00505 /* callback for getting data long_name */
00506 void
00507 stp_list_set_long_namefunc(stp_list_t *list, stp_node_namefunc long_namefunc)
00508 {
00509   check_list(list);
00510   list->long_namefunc = long_namefunc;
00511 }
00512 
00513 stp_node_namefunc
00514 stp_list_get_long_namefunc(const stp_list_t *list)
00515 {
00516   check_list(list);
00517   return list->long_namefunc;
00518 }
00519 
00520 /* callback for sorting nodes */
00521 void
00522 stp_list_set_sortfunc(stp_list_t *list, stp_node_sortfunc sortfunc)
00523 {
00524   check_list(list);
00525   list->sortfunc = sortfunc;
00526 }
00527 
00528 stp_node_sortfunc
00529 stp_list_get_sortfunc(const stp_list_t *list)
00530 {
00531   check_list(list);
00532   return list->sortfunc;
00533 }
00534 
00535 
00536 /* list item functions */
00537 
00538 /* these functions operate on individual nodes in a list */
00539 
00540 /*
00541  * create a new node in list, before next (may be null e.g. if sorting
00542  * next is calculated automatically, else defaults to end).  Must be
00543  * initialised with data (null nodes are disallowed).  The
00544  * stp_list_item_t type can not exist unless it is associated with an
00545  * stp_list_t list head.
00546  */
00547 int
00548 stp_list_item_create(stp_list_t *list,
00549                      stp_list_item_t *next,
00550                      const void *data)
00551 {
00552   stp_list_item_t *ln; /* list node to add */
00553   stp_list_item_t *lnn; /* list node next */
00554 
00555   check_list(list);
00556 
00557   clear_cache(list);
00558 
00559   ln = stp_malloc(sizeof(stp_list_item_t));
00560   ln->prev = ln->next = NULL;
00561 
00562   if (data)
00563     ln->data = (void *) data;
00564   else
00565     {
00566       stp_free(ln);
00567       return 1;
00568     }
00569 
00570   if (list->sortfunc)
00571     {
00572       /* set np to the previous node (before the insertion */
00573       lnn = list->end;
00574       while (lnn)
00575         {
00576           if (list->sortfunc(lnn->data, ln->data) <= 0)
00577             break;
00578           lnn = lnn->prev;
00579         }
00580     }
00581 #if 0
00582   /*
00583    * This code #ifdef'ed out by Robert Krawitz on April 3, 2004.
00584    * Setting a debug variable should not result in taking a materially
00585    * different code path.
00586    */
00587   else if (stpi_get_debug_level() & STPI_DBG_LIST)
00588     {
00589       if (next)
00590         {
00591           lnn = list->start;
00592           while (lnn)
00593             {
00594               if (lnn == next)
00595                 break;
00596               lnn = lnn->prev;
00597             }
00598         }
00599       else
00600         lnn = NULL;
00601     }
00602 #endif
00603   else
00604     lnn = next;
00605 
00606   /* got lnp; now insert the new ln */
00607 
00608   /* set next */
00609   ln->next = lnn;
00610 
00611   if (!ln->prev) /* insert at start of list */
00612     {
00613       if (list->start) /* list not empty */
00614         ln->prev = list->end;
00615       else
00616         list->start = ln;
00617       list->end = ln;
00618     }
00619 
00620   /* set prev (already set if at start of list) */
00621 
00622   if (!ln->prev && ln->next) /* insert at end of list */
00623     ln->prev = ln->next->prev;
00624 
00625   if (list->start == ln->next) /* prev was old end */
00626     {
00627       list->start = ln;
00628     }
00629 
00630   /* set next->prev */
00631   if (ln->next)
00632     ln->next->prev = ln;
00633 
00634   /* set prev->next */
00635   if (ln->prev)
00636     ln->prev->next = ln;
00637 
00638   /* increment reference count */
00639   list->length++;
00640 
00641   stp_deprintf(STP_DBG_LIST, "stp_list_node constructor\n");
00642   return 0;
00643 }
00644 
00645 /* remove a node from list */
00646 int
00647 stp_list_item_destroy(stp_list_t *list, stp_list_item_t *item)
00648 {
00649   check_list(list);
00650 
00651   clear_cache(list);
00652   /* decrement reference count */
00653   list->length--;
00654 
00655   if (list->freefunc)
00656     list->freefunc((void *) item->data);
00657   if (item->prev)
00658     item->prev->next = item->next;
00659   else
00660     list->start = item->next;
00661   if (item->next)
00662     item->next->prev = item->prev;
00663   else
00664     list->end = item->prev;
00665   stp_free(item);
00666 
00667   stp_deprintf(STP_DBG_LIST, "stp_list_node destructor\n");
00668   return 0;
00669 }
00670 
00671 /* get previous node */
00672 stp_list_item_t *
00673 stp_list_item_prev(const stp_list_item_t *item)
00674 {
00675   return item->prev;
00676 }
00677 
00678 /* get next node */
00679 stp_list_item_t *
00680 stp_list_item_next(const stp_list_item_t *item)
00681 {
00682   return item->next;
00683 }
00684 
00685 /* get data for node */
00686 void *
00687 stp_list_item_get_data(const stp_list_item_t *item)
00688 {
00689   return item->data;
00690 }
00691 
00692 /* set data for node */
00693 int
00694 stp_list_item_set_data(stp_list_item_t *item, void *data)
00695 {
00696   if (data)
00697     {
00698       item->data = data;
00699       return 0;
00700     }
00701   return 1; /* return error if data was NULL */
00702 }

Generated on Thu Feb 10 19:29:30 2005 for libgutenprint API Reference by  doxygen 1.4.1