pcb 4.1.1
An interactive printed circuit board layout editor.

hidinit.c

Go to the documentation of this file.
00001 
00035 #ifdef HAVE_CONFIG_H
00036 #include "config.h"
00037 #endif
00038 
00039 #include <stdio.h>
00040 #include <stdlib.h>
00041 #include <string.h>
00042 
00043 #ifdef HAVE_DLFCN_H
00044 #include <dlfcn.h>
00045 #endif
00046 
00047 #include <dirent.h>
00048 #include <sys/types.h>
00049 #include <sys/stat.h>
00050 #include <unistd.h>
00051 
00052 #if defined(WIN32) && defined(HAVE_WINDOWS_H)
00053 #define WIN32_LEAN_AND_MEAN
00054 #include <windows.h>
00055 #endif
00056 
00057 #include "global.h"
00058 #include "hid.h"
00059 #include "hidnogui.h"
00060 #include "../hidint.h"
00061 
00062 /* for dlopen() and friends on windows */
00063 #include "compat.h"
00064 
00065 #include "error.h"
00066 #include "global.h"
00067 #include "misc.h"
00068 #include "pcb-printf.h"
00069 
00070 #ifdef HAVE_LIBDMALLOC
00071 #include <dmalloc.h>
00072 #endif
00073 
00074 #define HID_DEF(x) extern void hid_ ## x ## _init(void);
00075 #include "hid/common/hidlist.h"
00076 #undef HID_DEF
00077 
00078 HID **hid_list = 0;
00079 int hid_num_hids = 0;
00080 
00081 HID *gui = NULL;
00082 HID *exporter = NULL;
00083 
00084 int pixel_slop = 1;
00085 
00097 static void
00098 hid_load_dir (char *dirname)
00099 {
00100   DIR *dir;
00101   struct dirent *de;
00102 
00103   dir = opendir (dirname);
00104   if (!dir)
00105     {
00106       free (dirname);
00107       return;
00108     }
00109   while ((de = readdir (dir)) != NULL)
00110     {
00111       void *sym;
00112       void (*symv)();
00113       void *so;
00114       char *basename, *path, *symname;
00115       struct stat st;
00116 
00117       basename = strdup (de->d_name);
00118       if (strlen (basename) > 3
00119           && strcasecmp (basename+strlen(basename)-3, ".so") == 0)
00120         basename[strlen(basename)-3] = 0;
00121       else if (strlen (basename) > 4
00122                && strcasecmp (basename+strlen(basename)-4, ".dll") == 0)
00123         basename[strlen(basename)-4] = 0;
00124       path = Concat (dirname, PCB_DIR_SEPARATOR_S, de->d_name, NULL);
00125 
00126       if (stat (path, &st) == 0
00127           && (
00128 /* mingw and win32 do not support S_IXGRP or S_IXOTH */
00129 #if defined(S_IXGRP)
00130           (st.st_mode & S_IXGRP) ||
00131 #endif
00132 #if defined(S_IXOTH)
00133           (st.st_mode & S_IXOTH) ||
00134 #endif
00135           (st.st_mode & S_IXUSR) )
00136           && S_ISREG (st.st_mode))
00137         {
00138           if ((so = dlopen (path, RTLD_NOW | RTLD_GLOBAL)) == NULL)
00139             {
00140               fprintf(stderr, "dl_error: %s\n", dlerror ());
00141             }
00142           else
00143             {
00144               symname = Concat ("hid_", basename, "_init", NULL);
00145               if ((sym = dlsym (so, symname)) != NULL)
00146                 {
00147                   symv = (void (*)()) sym;
00148                   symv();
00149                 }
00150               else if ((sym = dlsym (so, "pcb_plugin_init")) != NULL)
00151                 {
00152                   symv = (void (*)()) sym;
00153                   symv();
00154                 }
00155               free (symname);
00156             }
00157         }
00158       free (basename);
00159       free (path);
00160     }
00161   free (dirname);
00162   closedir (dir);
00163 }
00164 
00172 void
00173 hid_init ()
00174 {
00175   /* Setup a "nogui" default HID */
00176   gui = hid_nogui_get_hid ();
00177 
00178   /* Call all of the hid initialization functions */
00179 #define HID_DEF(x) hid_ ## x ## _init();
00180 #include "hid/common/hidlist.h"
00181 #undef HID_DEF
00182 
00183   /* Search the exec_prefix for plugins and load them */
00184   hid_load_dir (Concat (exec_prefix, PCB_DIR_SEPARATOR_S, "lib",
00185         PCB_DIR_SEPARATOR_S, "pcb",
00186         PCB_DIR_SEPARATOR_S, "plugins",
00187         PCB_DIR_SEPARATOR_S, HOST, NULL));
00188   hid_load_dir (Concat (exec_prefix, PCB_DIR_SEPARATOR_S, "lib",
00189         PCB_DIR_SEPARATOR_S, "pcb",
00190         PCB_DIR_SEPARATOR_S, "plugins", NULL));
00191 
00192   /* Search homedir for plugins and load them. homedir is set by the core
00193    * immediately on startup */
00194   if (homedir != NULL)
00195     {
00196       hid_load_dir (Concat (homedir, PCB_DIR_SEPARATOR_S, ".pcb",
00197         PCB_DIR_SEPARATOR_S, "plugins",
00198         PCB_DIR_SEPARATOR_S, HOST, NULL));
00199       hid_load_dir (Concat (homedir, PCB_DIR_SEPARATOR_S, ".pcb",
00200         PCB_DIR_SEPARATOR_S, "plugins", NULL));
00201     }
00202   hid_load_dir (Concat ("plugins", PCB_DIR_SEPARATOR_S, HOST, NULL));
00203   hid_load_dir (Concat ("plugins", NULL));
00204 }
00205 
00206 void
00207 hid_uninit (void)
00208 {
00209 
00210 }
00211 
00215 void
00216 hid_register_hid (HID * hid)
00217 {
00218   int i;
00219   int sz = (hid_num_hids + 2) * sizeof (HID *);
00220 
00221   if (hid->struct_size != sizeof (HID))
00222     {
00223       fprintf (stderr, "Warning: hid \"%s\" has an incompatible ABI.\n",
00224                hid->name);
00225       return;
00226     }
00227 
00228   for (i=0; i<hid_num_hids; i++)
00229     if (hid == hid_list[i])
00230       return;
00231 
00232   hid_num_hids++;
00233   if (hid_list)
00234     hid_list = (HID **) realloc (hid_list, sz);
00235   else
00236     hid_list = (HID **) malloc (sz);
00237 
00238   hid_list[hid_num_hids - 1] = hid;
00239   hid_list[hid_num_hids] = 0;
00240 }
00241 
00242 
00243 HID *
00244 hid_find_gui ()
00245 {
00246   int i;
00247 
00248   for (i = 0; i < hid_num_hids; i++)
00249     if (!hid_list[i]->printer && !hid_list[i]->exporter)
00250       return hid_list[i];
00251 
00252   fprintf (stderr, "Error: No GUI available.\n");
00253   exit (1);
00254 }
00255 
00256 HID *
00257 hid_find_printer ()
00258 {
00259   int i;
00260 
00261   for (i = 0; i < hid_num_hids; i++)
00262     if (hid_list[i]->printer)
00263       return hid_list[i];
00264 
00265   return 0;
00266 }
00267 
00268 HID *
00269 hid_find_exporter (const char *which)
00270 {
00271   int i;
00272 
00273   for (i = 0; i < hid_num_hids; i++)
00274     if (hid_list[i]->exporter && strcmp (which, hid_list[i]->name) == 0)
00275       return hid_list[i];
00276 
00277   fprintf (stderr, "Invalid exporter %s, available ones:", which);
00278   for (i = 0; i < hid_num_hids; i++)
00279     if (hid_list[i]->exporter)
00280       fprintf (stderr, " %s", hid_list[i]->name);
00281   fprintf (stderr, "\n");
00282 
00283   return 0;
00284 }
00285 
00286 HID **
00287 hid_enumerate ()
00288 {
00289   return hid_list;
00290 }
00291 
00292 HID_AttrNode *hid_attr_nodes = 0;
00293 
00294 void
00295 hid_register_attributes (HID_Attribute * a, int n)
00296 {
00297   HID_AttrNode *ha;
00298 
00299   /* printf("%d attributes registered\n", n); */
00300   ha = (HID_AttrNode *) malloc (sizeof (HID_AttrNode));
00301   ha->next = hid_attr_nodes;
00302   hid_attr_nodes = ha;
00303   ha->attributes = a;
00304   ha->n = n;
00305 }
00306 
00307 void
00308 hid_parse_command_line (int *argc, char ***argv)
00309 {
00310   HID_AttrNode *ha;
00311   int i, e, ok;
00312 
00313   (*argc)--;
00314   (*argv)++;
00315 
00316   for (ha = hid_attr_nodes; ha; ha = ha->next)
00317     for (i = 0; i < ha->n; i++)
00318       {
00319         HID_Attribute *a = ha->attributes + i;
00320         switch (a->type)
00321           {
00322           case HID_Label:
00323             break;
00324           case HID_Integer:
00325             if (a->value)
00326               *(int *) a->value = a->default_val.int_value;
00327             break;
00328           case HID_Coord:
00329             if (a->value)
00330               *(Coord *) a->value = a->default_val.coord_value;
00331             break;
00332           case HID_Boolean:
00333             if (a->value)
00334               *(char *) a->value = a->default_val.int_value;
00335             break;
00336           case HID_Real:
00337             if (a->value)
00338               *(double *) a->value = a->default_val.real_value;
00339             break;
00340           case HID_String:
00341             if (a->value)
00342               *(const char **) a->value = a->default_val.str_value;
00343             break;
00344           case HID_Enum:
00345             if (a->value)
00346               *(int *) a->value = a->default_val.int_value;
00347             break;
00348           case HID_Mixed:
00349             if (a->value) {
00350               *(HID_Attr_Val *) a->value = a->default_val;
00351           case HID_Unit:
00352             if (a->value)
00353               *(int *) a->value = a->default_val.int_value;
00354             break;
00355            }
00356            break;
00357           default:
00358             abort ();
00359           }
00360       }
00361 
00362   while (*argc && (*argv)[0][0] == '-' && (*argv)[0][1] == '-')
00363     {
00364       int bool_val;
00365       int arg_ofs;
00366 
00367       bool_val = 1;
00368       arg_ofs = 2;
00369     try_no_arg:
00370       for (ha = hid_attr_nodes; ha; ha = ha->next)
00371         for (i = 0; i < ha->n; i++)
00372           if (strcmp ((*argv)[0] + arg_ofs, ha->attributes[i].name) == 0)
00373             {
00374               HID_Attribute *a = ha->attributes + i;
00375               char *ep;
00376               const Unit *unit;
00377               switch (ha->attributes[i].type)
00378                 {
00379                 case HID_Label:
00380                   break;
00381                 case HID_Integer:
00382                   if (a->value)
00383                     *(int *) a->value = strtol ((*argv)[1], 0, 0);
00384                   else
00385                     a->default_val.int_value = strtol ((*argv)[1], 0, 0);
00386                   (*argc)--;
00387                   (*argv)++;
00388                   break;
00389                 case HID_Coord:
00390                   if (a->value)
00391                     *(Coord *) a->value = GetValue ((*argv)[1], NULL, NULL);
00392                   else
00393                     a->default_val.coord_value = GetValue ((*argv)[1], NULL, NULL);
00394                   (*argc)--;
00395                   (*argv)++;
00396                   break;
00397                 case HID_Real:
00398                   if (a->value)
00399                     *(double *) a->value = strtod ((*argv)[1], 0);
00400                   else
00401                     a->default_val.real_value = strtod ((*argv)[1], 0);
00402                   (*argc)--;
00403                   (*argv)++;
00404                   break;
00405                 case HID_String:
00406                   if (a->value)
00407                     *(char **) a->value = (*argv)[1];
00408                   else
00409                     a->default_val.str_value = (*argv)[1];
00410                   (*argc)--;
00411                   (*argv)++;
00412                   break;
00413                 case HID_Boolean:
00414                   if (a->value)
00415                     *(char *) a->value = bool_val;
00416                   else
00417                     a->default_val.int_value = bool_val;
00418                   break;
00419                 case HID_Mixed:
00420                   a->default_val.real_value = strtod ((*argv)[1], &ep);
00421                   goto do_enum;
00422                 case HID_Enum:
00423                   ep = (*argv)[1];
00424                 do_enum:
00425                   ok = 0;
00426                   for (e = 0; a->enumerations[e]; e++)
00427                     if (strcmp (a->enumerations[e], ep) == 0)
00428                       {
00429                         ok = 1;
00430                         a->default_val.int_value = e;
00431                         a->default_val.str_value = ep;
00432                         break;
00433                       }
00434                   if (!ok)
00435                     {
00436                       fprintf (stderr,
00437                                "ERROR:  \"%s\" is an unknown value for the --%s option\n",
00438                                (*argv)[1], a->name);
00439                       exit (1);
00440                     }
00441                   (*argc)--;
00442                   (*argv)++;
00443                   break;
00444                 case HID_Path:
00445                   abort ();
00446                   a->default_val.str_value = (*argv)[1];
00447                   (*argc)--;
00448                   (*argv)++;
00449                   break;
00450                 case HID_Unit:
00451                   unit = get_unit_struct ((*argv)[1]);
00452                   if (unit == NULL)
00453                     {
00454                       fprintf (stderr,
00455                                "ERROR:  unit \"%s\" is unknown to pcb (option --%s)\n",
00456                                (*argv)[1], a->name);
00457                       exit (1);
00458                     }
00459                   a->default_val.int_value = unit->index;
00460                   a->default_val.str_value = unit->suffix;
00461                   (*argc)--;
00462                   (*argv)++;
00463                   break;
00464                 }
00465               (*argc)--;
00466               (*argv)++;
00467               ha = 0;
00468               goto got_match;
00469             }
00470       if (bool_val == 1 && strncmp ((*argv)[0], "--no-", 5) == 0)
00471         {
00472           bool_val = 0;
00473           arg_ofs = 5;
00474           goto try_no_arg;
00475         }
00476       fprintf (stderr, "unrecognized option: %s\n", (*argv)[0]);
00477       exit (1);
00478     got_match:;
00479     }
00480 
00481   (*argc)++;
00482   (*argv)--;
00483 }
00484 
00485 static int
00486 attr_hash (HID_Attribute *a)
00487 {
00488   unsigned char *cp = (unsigned char *)a;
00489   int i, rv=0;
00490   for (i=0; i<(int)((char *)&(a->hash) - (char *)a); i++)
00491     rv = (rv * 13) ^ (rv >> 16) ^ cp[i];
00492   return rv;
00493 }
00494 
00495 void
00496 hid_save_settings (int locally)
00497 {
00498   char *fname;
00499   struct stat st;
00500   FILE *f;
00501   HID_AttrNode *ha;
00502   int i;
00503 
00504   if (locally)
00505     {
00506       fname = Concat ("pcb.settings", NULL);
00507     }
00508   else
00509     {
00510       if (homedir == NULL)
00511         return;
00512       fname = Concat (homedir, PCB_DIR_SEPARATOR_S, ".pcb", NULL);
00513 
00514       if (stat (fname, &st))
00515         if (MKDIR (fname, 0777))
00516           {
00517             free (fname);
00518             return;
00519           }
00520       free (fname);
00521 
00522       fname = Concat (homedir, PCB_DIR_SEPARATOR_S, ".pcb", 
00523                PCB_DIR_SEPARATOR_S, "settings", NULL);
00524     }
00525 
00526   f = fopen (fname, "w");
00527   if (!f)
00528     {
00529       Message ("Can't open %s", fname);
00530       free (fname);
00531       return;
00532     }
00533 
00534   for (ha = hid_attr_nodes; ha; ha = ha->next)
00535     {
00536       for (i = 0; i < ha->n; i++)
00537         {
00538           const char *str;
00539           HID_Attribute *a = ha->attributes + i;
00540 
00541           if (a->hash == attr_hash (a))
00542             fprintf (f, "# ");
00543           switch (a->type)
00544             {
00545             case HID_Label:
00546               break;
00547             case HID_Integer:
00548               fprintf (f, "%s = %d\n",
00549                        a->name,
00550                        a->value ? *(int *)a->value : a->default_val.int_value);
00551               break;
00552             case HID_Coord:
00553               pcb_fprintf (f, "%s = %$mS\n",
00554                            a->name,
00555                            a->value ? *(Coord *)a->value : a->default_val.coord_value);
00556               break;
00557             case HID_Boolean:
00558               fprintf (f, "%s = %d\n",
00559                        a->name,
00560                        a->value ? *(char *)a->value : a->default_val.int_value);
00561               break;
00562             case HID_Real:
00563               fprintf (f, "%s = %f\n",
00564                        a->name,
00565                        a->value ? *(double *)a->value : a->default_val.real_value);
00566               break;
00567             case HID_String:
00568             case HID_Path:
00569               str = a->value ? *(char **)a->value : a->default_val.str_value;
00570               fprintf (f, "%s = %s\n", a->name, str ? str : "");
00571               break;
00572             case HID_Enum:
00573               fprintf (f, "%s = %s\n",
00574                        a->name,
00575                        a->enumerations[a->value ? *(int *)a->value : a->default_val.int_value]);
00576               break;
00577             case HID_Mixed:
00578              {
00579                HID_Attr_Val *value =
00580                  a->value ? (HID_Attr_Val*) a->value : &(a->default_val);
00581                fprintf (f, "%s = %g%s\n",
00582                         a->name,
00583                         value->real_value,
00584                         a->enumerations[value->int_value]);
00585              }
00586               break;
00587             case HID_Unit:
00588               fprintf (f, "%s = %s\n",
00589                        a->name,
00590                        get_unit_list()[a->value ? *(int *)a->value : a->default_val.int_value].suffix);
00591               break;
00592             }
00593         }
00594       fprintf (f, "\n");
00595     }
00596   fclose (f);
00597   free (fname);
00598 }
00599 
00600 static void
00601 hid_set_attribute (char *name, char *value)
00602 {
00603   const Unit *unit;
00604   HID_AttrNode *ha;
00605   int i, e, ok;
00606 
00607   for (ha = hid_attr_nodes; ha; ha = ha->next)
00608     for (i = 0; i < ha->n; i++)
00609       if (strcmp (name, ha->attributes[i].name) == 0)
00610         {
00611           HID_Attribute *a = ha->attributes + i;
00612           switch (ha->attributes[i].type)
00613             {
00614             case HID_Label:
00615               break;
00616             case HID_Integer:
00617               a->default_val.int_value = strtol (value, 0, 0);
00618               break;
00619             case HID_Coord:
00620               a->default_val.coord_value = GetValue (value, NULL, NULL);
00621               break;
00622             case HID_Real:
00623               a->default_val.real_value = strtod (value, 0);
00624               break;
00625             case HID_String:
00626               a->default_val.str_value = strdup (value);
00627               break;
00628             case HID_Boolean:
00629               a->default_val.int_value = 1;
00630               break;
00631             case HID_Mixed:
00632               a->default_val.real_value = strtod (value, &value);
00633               /* fall through */
00634             case HID_Enum:
00635               ok = 0;
00636               for (e = 0; a->enumerations[e]; e++)
00637                 if (strcmp (a->enumerations[e], value) == 0)
00638                   {
00639                     ok = 1;
00640                     a->default_val.int_value = e;
00641                     a->default_val.str_value = value;
00642                     break;
00643                   }
00644               if (!ok)
00645                 {
00646                   fprintf (stderr,
00647                            "ERROR:  \"%s\" is an unknown value for the %s option\n",
00648                            value, a->name);
00649                   exit (1);
00650                 }
00651               break;
00652             case HID_Path:
00653               a->default_val.str_value = value;
00654               break;
00655             case HID_Unit:
00656               unit = get_unit_struct (value);
00657               if (unit == NULL)
00658                 {
00659                   fprintf (stderr,
00660                            "ERROR:  unit \"%s\" is unknown to pcb (option --%s)\n",
00661                            value, a->name);
00662                   exit (1);
00663                 }
00664               a->default_val.int_value = unit->index;
00665               a->default_val.str_value = unit->suffix;
00666               break;
00667             }
00668         }
00669 }
00670 
00671 static void
00672 hid_load_settings_1 (char *fname)
00673 {
00674   char line[1024], *namep, *valp, *cp;
00675   FILE *f;
00676 
00677   f = fopen (fname, "r");
00678   if (!f)
00679     {
00680       free (fname);
00681       return;
00682     }
00683 
00684   free (fname);
00685   while (fgets (line, sizeof(line), f) != NULL)
00686     {
00687       for (namep=line; *namep && isspace ((int) *namep); namep++)
00688         ;
00689       if (*namep == '#')
00690         continue;
00691       for (valp=namep; *valp && !isspace((int) *valp); valp++)
00692         ;
00693       if (! *valp)
00694         continue;
00695       *valp++ = 0;
00696       while (*valp && (isspace ((int) *valp) || *valp == '='))
00697         valp ++;
00698       if (! *valp)
00699         continue;
00700       cp = valp + strlen(valp) - 1;
00701       while (cp >= valp && isspace ((int) *cp))
00702         *cp-- = 0;
00703       hid_set_attribute (namep, valp);
00704     }
00705 
00706   fclose (f);
00707 }
00708 
00709 void
00710 hid_load_settings ()
00711 {
00712   HID_AttrNode *ha;
00713   int i;
00714 
00715   for (ha = hid_attr_nodes; ha; ha = ha->next)
00716     for (i = 0; i < ha->n; i++)
00717       ha->attributes[i].hash = attr_hash (ha->attributes+i);
00718 
00719   hid_load_settings_1 (Concat (pcblibdir, PCB_DIR_SEPARATOR_S, "settings", NULL));
00720   if (homedir != NULL)
00721     hid_load_settings_1 (Concat (homedir, PCB_DIR_SEPARATOR_S, ".pcb",
00722                PCB_DIR_SEPARATOR_S, "settings", NULL));
00723   hid_load_settings_1 (Concat ("pcb.settings", NULL));
00724 }
00725 
00726 #define HASH_SIZE 31
00727 
00728 typedef struct ecache
00729 {
00730   struct ecache *next;
00731   const char *name;
00732   hidval val;
00733 } ecache;
00734 
00735 typedef struct ccache
00736 {
00737   ecache *colors[HASH_SIZE];
00738   ecache *lru;
00739 } ccache;
00740 
00741 static void
00742 copy_color (int set, hidval * cval, hidval * aval)
00743 {
00744   if (set)
00745     memcpy (cval, aval, sizeof (hidval));
00746   else
00747     memcpy (aval, cval, sizeof (hidval));
00748 }
00749 
00750 int
00751 hid_cache_color (int set, const char *name, hidval * val, void **vcache)
00752 {
00753   unsigned long hash;
00754   const char *cp;
00755   ccache *cache;
00756   ecache *e;
00757 
00758   cache = (ccache *) * vcache;
00759   if (cache == 0) {
00760     cache = (ccache *) calloc (sizeof (ccache), 1);
00761     *vcache = cache;
00762   }
00763   if (cache->lru && strcmp (cache->lru->name, name) == 0)
00764     {
00765       copy_color (set, &(cache->lru->val), val);
00766       return 1;
00767     }
00768 
00769   /* djb2: this algorithm (k=33) was first reported by dan bernstein many
00770    * years ago in comp.lang.c. another version of this algorithm (now favored
00771    * by bernstein) uses xor: hash(i) = hash(i - 1) * 33 ^ str[i]; the magic
00772    * of number 33 (why it works better than many other constants, prime or
00773    * not) has never been adequately explained.
00774    */
00775   hash = 5381;
00776   for (cp = name, hash = 0; *cp; cp++)
00777     hash = ((hash << 5) + hash) + (*cp & 0xff); /* hash * 33 + c */
00778   hash %= HASH_SIZE;
00779 
00780   for (e = cache->colors[hash]; e; e = e->next)
00781     if (strcmp (e->name, name) == 0)
00782       {
00783         copy_color (set, &(e->val), val);
00784         cache->lru = e;
00785         return 1;
00786       }
00787   if (!set)
00788     return 0;
00789 
00790   e = (ecache *) malloc (sizeof (ecache));
00791   e->next = cache->colors[hash];
00792   cache->colors[hash] = e;
00793   e->name = strdup (name);
00794   memcpy (&(e->val), val, sizeof (hidval));
00795   cache->lru = e;
00796 
00797   return 1;
00798 }
00799 
00800 /* otherwise homeless function, refactored out of the five export HIDs */
00801 void
00802 derive_default_filename(const char *pcbfile, HID_Attribute *filename_attrib, const char *suffix, char **memory)
00803 {
00804         char *buf;
00805         char *pf;
00806 
00807         if (pcbfile == NULL)
00808           pf = strdup ("unknown.pcb");
00809         else
00810           pf = strdup (pcbfile);
00811 
00812         if (!pf || (memory && filename_attrib->default_val.str_value != *memory)) return;
00813 
00814         buf = (char *)malloc (strlen (pf) + strlen(suffix) + 1);
00815         if (memory) *memory = buf;
00816         if (buf) {
00817                 size_t bl;
00818                 strcpy (buf, pf);
00819                 bl = strlen(buf);
00820                 if (bl > 4 && strcmp (buf + bl - 4, ".pcb") == 0)
00821                         buf[bl - 4] = 0;
00822                 strcat(buf, suffix);
00823                 if (filename_attrib->default_val.str_value)
00824                         free ((void *) filename_attrib->default_val.str_value);
00825                 filename_attrib->default_val.str_value = buf;
00826         }
00827 
00828         free (pf);
00829 }