home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / procedural_db.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  12.5 KB  |  530 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <stdarg.h>
  22. #include <string.h>
  23.  
  24. #include <glib.h>
  25.  
  26. #include "apptypes.h"
  27.  
  28. #include "appenv.h"
  29. #include "app_procs.h"
  30. #include "plug_in.h"
  31. #include "procedural_db.h"
  32.  
  33. #include "libgimp/gimpparasite.h"
  34.  
  35. #include "libgimp/gimpintl.h"
  36.  
  37.  
  38. GHashTable *procedural_ht = NULL;
  39.  
  40. /*  Local functions  */
  41. static guint   procedural_db_hash_func (gconstpointer key);
  42. static void    pdb_id_init             (void);
  43.  
  44.  
  45. void
  46. procedural_db_init (void)
  47. {
  48.   app_init_update_status (_("Procedural Database"), NULL, -1);
  49.  
  50.   if (!procedural_ht)
  51.     procedural_ht = g_hash_table_new (procedural_db_hash_func, g_str_equal);
  52.   pdb_id_init ();
  53. }
  54.  
  55. static void
  56. procedural_db_free_entry (gpointer key,
  57.               gpointer value,
  58.               gpointer user_data)
  59. {
  60.   if (value)
  61.     g_list_free (value);
  62. }
  63.  
  64. void
  65. procedural_db_free (void)
  66. {
  67.   if (procedural_ht)
  68.     {
  69.       g_hash_table_foreach (procedural_ht, procedural_db_free_entry, NULL);
  70.       g_hash_table_destroy (procedural_ht);
  71.     }
  72.   
  73.   procedural_ht = NULL;
  74. }
  75.  
  76. void
  77. procedural_db_register (ProcRecord *procedure)
  78. {
  79.   GList *list;
  80.  
  81.   if (!procedural_ht)
  82.     procedural_db_init ();
  83.  
  84.   list = g_hash_table_lookup (procedural_ht, (gpointer) procedure->name);
  85.   list = g_list_prepend (list, (gpointer) procedure);
  86.  
  87.   g_hash_table_insert (procedural_ht,
  88.                (gpointer) procedure->name,
  89.                (gpointer) list);
  90. }
  91.  
  92. void
  93. procedural_db_unregister (gchar *name)
  94. {
  95.   GList *list;
  96.  
  97.   list = g_hash_table_lookup (procedural_ht, (gpointer) name);
  98.   if (list)
  99.     {
  100.       list = g_list_remove (list, list->data);
  101.  
  102.       if (list)
  103.     g_hash_table_insert (procedural_ht,
  104.                  (gpointer) name,
  105.                  (gpointer) list);
  106.       else 
  107.     g_hash_table_remove (procedural_ht,
  108.                  (gpointer) name);
  109.     }
  110. }
  111.  
  112. ProcRecord *
  113. procedural_db_lookup (gchar *name)
  114. {
  115.   GList *list;
  116.   ProcRecord *procedure;
  117.  
  118.   list = g_hash_table_lookup (procedural_ht, (gpointer) name);
  119.   if (list != NULL)
  120.     procedure = (ProcRecord *) list->data;
  121.   else
  122.     procedure = NULL;
  123.  
  124.   return procedure;
  125. }
  126.  
  127. Argument *
  128. procedural_db_execute (gchar    *name,
  129.                Argument *args)
  130. {
  131.   ProcRecord *procedure;
  132.   Argument   *return_args;
  133.   GList      *list;
  134.   gint        i;
  135.  
  136.   return_args = NULL;
  137.  
  138.   list = g_hash_table_lookup (procedural_ht, (gpointer) name);
  139.  
  140.   if (list == NULL)
  141.     {
  142.       g_message (_("PDB calling error %s not found"), name);
  143.       
  144.       return_args = g_new (Argument, 1);
  145.       return_args->arg_type = PDB_STATUS;
  146.       return_args->value.pdb_int = PDB_CALLING_ERROR;
  147.       return return_args;
  148.     }
  149.   
  150.   while (list)
  151.     {
  152.       if ((procedure = (ProcRecord *) list->data) == NULL)
  153.     {
  154.       g_message (_("PDB calling error %s not found"), name);
  155.  
  156.       return_args = g_new (Argument, 1);
  157.       return_args->arg_type = PDB_STATUS;
  158.       return_args->value.pdb_int = PDB_CALLING_ERROR;
  159.       return return_args;
  160.     }
  161.       list = list->next;
  162.  
  163.       /*  check the arguments  */
  164.       for (i = 0; i < procedure->num_args; i++)
  165.     {
  166.       if (args[i].arg_type != procedure->args[i].arg_type)
  167.         {
  168.           return_args = g_new (Argument, 1);
  169.           return_args->arg_type = PDB_STATUS;
  170.           return_args->value.pdb_int = PDB_CALLING_ERROR;
  171.  
  172.           g_message (_("PDB calling error %s"), procedure->name);
  173.  
  174.           return return_args;
  175.         }
  176.     }
  177.  
  178.       /*  call the procedure  */
  179.       switch (procedure->proc_type)
  180.     {
  181.     case PDB_INTERNAL:
  182.       return_args = (* procedure->exec_method.internal.marshal_func) (args);
  183.       break;
  184.  
  185.     case PDB_PLUGIN:
  186.       return_args = plug_in_run (procedure, args, procedure->num_args, TRUE, FALSE, -1);
  187.       break;
  188.  
  189.     case PDB_EXTENSION:
  190.       return_args = plug_in_run (procedure, args, procedure->num_args, TRUE, FALSE, -1);
  191.       break;
  192.  
  193.     case PDB_TEMPORARY:
  194.       return_args = plug_in_run (procedure, args, procedure->num_args, TRUE, FALSE, -1);
  195.       break;
  196.  
  197.     default:
  198.       return_args = g_new (Argument, 1);
  199.       return_args->arg_type = PDB_STATUS;
  200.       return_args->value.pdb_int = PDB_EXECUTION_ERROR;
  201.       break;
  202.     }
  203.  
  204.       if ((return_args[0].value.pdb_int != PDB_SUCCESS) &&
  205.       (procedure->num_values > 0))
  206.     memset (&return_args[1], 0, sizeof (Argument) * procedure->num_values);
  207.  
  208.       /*  Check if the return value is a PDB_PASS_THROUGH, in which case run the
  209.        *  next procedure in the list
  210.        */
  211.       if (return_args[0].value.pdb_int != PDB_PASS_THROUGH)
  212.     break;
  213.       else if (list)  /*  Pass through, so destroy return values and run another procedure  */
  214.     procedural_db_destroy_args (return_args, procedure->num_values);
  215.     }
  216.  
  217.   return return_args;
  218. }
  219.  
  220. Argument *
  221. procedural_db_run_proc (gchar *name,
  222.             gint  *nreturn_vals,
  223.             ...)
  224. {
  225.   ProcRecord *proc;
  226.   Argument   *params;
  227.   Argument   *return_vals;
  228.   va_list     args;
  229.   gint        i;
  230.  
  231.   if ((proc = procedural_db_lookup (name)) == NULL)
  232.     {
  233.       return_vals = g_new (Argument, 1);
  234.       return_vals->arg_type = PDB_STATUS;
  235.       return_vals->value.pdb_int = PDB_CALLING_ERROR;
  236.       return return_vals;
  237.     }
  238.  
  239.   /*  allocate the parameter array  */
  240.   params = g_new (Argument, proc->num_args);
  241.  
  242.   va_start (args, nreturn_vals);
  243.  
  244.   for (i = 0; i < proc->num_args; i++)
  245.     {
  246.       if (proc->args[i].arg_type != (params[i].arg_type = va_arg (args, PDBArgType)))
  247.     {
  248.       g_message (_("Incorrect arguments passed to procedural_db_run_proc:\n"
  249.                "Argument %d to '%s' should be a %s, but got passed a %s"),
  250.              i+1, proc->name,
  251.              pdb_type_name (proc->args[i].arg_type),
  252.              pdb_type_name (params[i].arg_type));
  253.       g_free (params);
  254.       return NULL;
  255.     }
  256.  
  257.       switch (proc->args[i].arg_type)
  258.     {
  259.     case PDB_INT32:
  260.     case PDB_INT16:
  261.     case PDB_INT8:
  262.         case PDB_DISPLAY:
  263.       params[i].value.pdb_int = (gint32) va_arg (args, int);
  264.       break;
  265.         case PDB_FLOAT:
  266.           params[i].value.pdb_float = (gdouble) va_arg (args, double);
  267.           break;
  268.         case PDB_STRING:
  269.         case PDB_INT32ARRAY:
  270.         case PDB_INT16ARRAY:
  271.         case PDB_INT8ARRAY:
  272.         case PDB_FLOATARRAY:
  273.         case PDB_STRINGARRAY:
  274.         case PDB_COLOR:
  275.           params[i].value.pdb_pointer = va_arg (args, void *);
  276.           break;
  277.         case PDB_REGION:
  278.           break;
  279.         case PDB_IMAGE:
  280.         case PDB_LAYER:
  281.         case PDB_CHANNEL:
  282.         case PDB_DRAWABLE:
  283.         case PDB_SELECTION:
  284.         case PDB_BOUNDARY:
  285.         case PDB_PATH:
  286.       params[i].value.pdb_int = (gint32) va_arg (args, int);
  287.       break;
  288.         case PDB_PARASITE:
  289.           params[i].value.pdb_pointer = va_arg (args, void *);
  290.           break;
  291.         case PDB_STATUS:
  292.       params[i].value.pdb_int = (gint32) va_arg (args, int);
  293.       break;
  294.     case PDB_END:
  295.       break;
  296.     }
  297.     }
  298.  
  299.   va_end (args);
  300.  
  301.   *nreturn_vals = proc->num_values;
  302.  
  303.   return_vals = procedural_db_execute (name, params);
  304.  
  305.   g_free (params);
  306.  
  307.   return return_vals;
  308. }
  309.  
  310. Argument *
  311. procedural_db_return_args (ProcRecord *procedure,
  312.                gboolean    success)
  313. {
  314.   Argument *return_args;
  315.   gint i;
  316.  
  317.   return_args = g_new (Argument, procedure->num_values + 1);
  318.  
  319.   if (success)
  320.     {
  321.       return_args[0].arg_type = PDB_STATUS;
  322.       return_args[0].value.pdb_int = PDB_SUCCESS;
  323.     }
  324.   else
  325.     {
  326.       return_args[0].arg_type = PDB_STATUS;
  327.       return_args[0].value.pdb_int = PDB_EXECUTION_ERROR;
  328.     }
  329.  
  330.   /*  Set the arg types for the return values  */
  331.   for (i = 0; i < procedure->num_values; i++)
  332.     return_args[i+1].arg_type = procedure->values[i].arg_type;
  333.  
  334.   return return_args;
  335. }
  336.  
  337. void
  338. procedural_db_destroy_args (Argument *args,
  339.                 int       nargs)
  340. {
  341.   gint    i, j;
  342.   gint    prev_val = 0;
  343.   gchar **strs;
  344.  
  345.   if (!args)
  346.     return;
  347.  
  348.   for (i = 0; i < nargs; i++)
  349.     {
  350.       switch (args[i].arg_type)
  351.     {
  352.     case PDB_INT32:
  353.       /*  Keep this around in case we need to free an array of strings  */
  354.       prev_val = args[i].value.pdb_int;
  355.       break;
  356.     case PDB_INT16:
  357.     case PDB_INT8:
  358.     case PDB_FLOAT:
  359.       break;
  360.     case PDB_STRING:
  361.     case PDB_INT32ARRAY:
  362.     case PDB_INT16ARRAY:
  363.     case PDB_INT8ARRAY:
  364.     case PDB_FLOATARRAY:
  365.       g_free (args[i].value.pdb_pointer);
  366.       break;
  367.     case PDB_STRINGARRAY:
  368.       strs = (gchar **) args[i].value.pdb_pointer;
  369.       for (j = 0; j < prev_val; j++)
  370.         g_free (strs[j]);
  371.       g_free (strs);
  372.       break;
  373.     case PDB_COLOR:
  374.       g_free (args[i].value.pdb_pointer);
  375.       break;
  376.     case PDB_REGION:
  377.     case PDB_DISPLAY:
  378.     case PDB_IMAGE:
  379.     case PDB_LAYER:
  380.     case PDB_CHANNEL:
  381.     case PDB_DRAWABLE:
  382.     case PDB_SELECTION:
  383.     case PDB_BOUNDARY:
  384.     case PDB_PATH:
  385.     case PDB_PARASITE:
  386.     case PDB_STATUS:
  387.     case PDB_END:
  388.       break;
  389.     }
  390.     }
  391.  
  392.   g_free (args);
  393. }
  394.  
  395. /* We could just use g_str_hash() here ... that uses a different
  396.  * hash function, though
  397.  */
  398.  
  399. static guint
  400. procedural_db_hash_func (gconstpointer key)
  401. {
  402.   const gchar *string;
  403.   guint result;
  404.   int c;
  405.  
  406.   /*
  407.    * I tried a zillion different hash functions and asked many other
  408.    * people for advice.  Many people had their own favorite functions,
  409.    * all different, but no-one had much idea why they were good ones.
  410.    * I chose the one below (multiply by 9 and add new character)
  411.    * because of the following reasons:
  412.    *
  413.    * 1. Multiplying by 10 is perfect for keys that are decimal strings,
  414.    *    and multiplying by 9 is just about as good.
  415.    * 2. Times-9 is (shift-left-3) plus (old).  This means that each
  416.    *    character's bits hang around in the low-order bits of the
  417.    *    hash value for ever, plus they spread fairly rapidly up to
  418.    *    the high-order bits to fill out the hash value.  This seems
  419.    *    works well both for decimal and non-decimal strings.
  420.    *
  421.    * tclHash.c --
  422.    *
  423.    *      Implementation of in-memory hash tables for Tcl and Tcl-based
  424.    *      applications.
  425.    *
  426.    * Copyright (c) 1991-1993 The Regents of the University of California.
  427.    * Copyright (c) 1994 Sun Microsystems, Inc.
  428.    */
  429.  
  430.   string = (const gchar *) key;
  431.   result = 0;
  432.   while (1)
  433.     {
  434.       c = *string;
  435.       string++;
  436.       if (c == 0)
  437.     break;
  438.       result += (result << 3) + c;
  439.     }
  440.  
  441.   return result;
  442. }
  443.  
  444.  
  445. /* The id system's remnants ... */
  446.  
  447.  
  448. static gint next_image_id;
  449. /*
  450. static gint next_drawable_id;
  451. static gint next_display_id;
  452. */
  453.  
  454. static GHashTable *image_hash;
  455. static GHashTable *drawable_hash;
  456. static GHashTable *display_hash;
  457.  
  458. static guint
  459. id_hash_func (gconstpointer id)
  460. {
  461.   return *((guint*) id);
  462. }
  463.  
  464. static gboolean
  465. id_cmp_func (gconstpointer id1,
  466.              gconstpointer id2)
  467. {
  468.   return (*((guint*) id1) == *((guint*) id2));
  469. }
  470.  
  471. static void
  472. add_cb (GimpSet   *set,
  473.         GimpImage *gimage,
  474.     gpointer   data)
  475. {
  476.   guint *id;
  477.  
  478.   id = g_new (guint, 1);
  479.   *id = next_image_id++;
  480.  
  481.   gtk_object_set_data (GTK_OBJECT (gimage), "pdb_id", id);
  482.   g_hash_table_insert (image_hash, id, gimage);
  483. }
  484.  
  485. static void
  486. remove_cb (GimpSet   *set,
  487.            GimpImage *image,
  488.        gpointer   data)
  489. {
  490.   guint *id;
  491.  
  492.   id = (guint *) gtk_object_get_data (GTK_OBJECT (image), "pdb_id");
  493.  
  494.   gtk_object_remove_data (GTK_OBJECT(image), "pdb_id");
  495.   g_hash_table_remove (image_hash, id);
  496.   g_free (id);
  497. }
  498.  
  499. static void
  500. pdb_id_init (void)
  501. {
  502.   image_hash    = g_hash_table_new (id_hash_func, id_cmp_func);
  503.   drawable_hash = g_hash_table_new (id_hash_func, id_cmp_func);
  504.   display_hash  = g_hash_table_new (id_hash_func, id_cmp_func);
  505.  
  506.   gtk_signal_connect (GTK_OBJECT (image_context), "add",
  507.               GTK_SIGNAL_FUNC (add_cb),
  508.               NULL);
  509.   gtk_signal_connect (GTK_OBJECT (image_context), "remove",
  510.               GTK_SIGNAL_FUNC (remove_cb),
  511.               NULL);
  512. }
  513.  
  514.  
  515. gint
  516. pdb_image_to_id (GimpImage *gimage)
  517. {
  518.   guint *id;
  519.  
  520.   id = (guint *) gtk_object_get_data (GTK_OBJECT (gimage), "pdb_id");
  521.  
  522.   return id ? (gint) *id : -1;
  523. }
  524.     
  525. GimpImage *
  526. pdb_id_to_image (gint id)
  527. {
  528.   return g_hash_table_lookup (image_hash, &id);
  529. }
  530.