libgimpprint API Reference: src/main/print-list.c Source File

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

# src/main/print-list.c

Go to the documentation of this file.

    00001 /*
    00002  * "$Id: print-list_8c-source.html,v 1.1.1.2 2004/12/22 23:49:08 jlovell 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 }