Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Globals  

src/main/print-list.c

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

Generated on Wed May 12 20:21:32 2004 for libgimpprint API Reference by doxygen1.2.17