libgeda

a_basic.c

Go to the documentation of this file.
00001 /* gEDA - GPL Electronic Design Automation
00002  * libgeda - gEDA's library
00003  * Copyright (C) 1998-2010 Ales Hvezda
00004  * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 
00024 #include <config.h>
00025 #include <version.h>
00026 
00027 #include <stdio.h>
00028 #ifdef HAVE_STRING_H
00029 #include <string.h>
00030 #endif
00031 
00032 #include "libgeda_priv.h"
00033 
00034 #ifdef HAVE_LIBDMALLOC
00035 #include <dmalloc.h>
00036 #endif
00037 
00045 const gchar *o_file_format_header()
00046 {
00047   static gchar *header = NULL;
00048 
00049   if (header == NULL)
00050     header = g_strdup_printf("v %s %u\n", PACKAGE_DATE_VERSION,
00051                              FILEFORMAT_VERSION);
00052 
00053   return header;
00054 }
00055 
00065 gchar *o_save_buffer (TOPLEVEL *toplevel, const GList *object_list)
00066 {
00067   GString *acc;
00068   gchar *buffer;
00069 
00070   if (toplevel == NULL) return NULL;
00071 
00072   acc = g_string_new (o_file_format_header());
00073 
00074   buffer = o_save_objects (toplevel, object_list, FALSE);
00075   g_string_append (acc, buffer);
00076   g_free (buffer);
00077 
00078   return g_string_free (acc, FALSE);
00079 }
00080 
00097 gchar *o_save_objects (TOPLEVEL *toplevel, const GList *object_list, gboolean save_attribs)
00098 {
00099   OBJECT *o_current;
00100   const GList *iter;
00101   gchar *out;
00102   GString *acc;
00103   gboolean already_wrote = FALSE;
00104 
00105   acc = g_string_new("");
00106 
00107   iter = object_list;
00108 
00109   while ( iter != NULL ) {
00110     o_current = (OBJECT *)iter->data;
00111 
00112     if (save_attribs || o_current->attached_to == NULL) {
00113 
00114       switch (o_current->type) {
00115 
00116         case(OBJ_LINE):
00117           out = o_line_save(toplevel, o_current);
00118           break;
00119 
00120         case(OBJ_NET):
00121           out = o_net_save(toplevel, o_current);
00122           break;
00123 
00124         case(OBJ_BUS):
00125           out = o_bus_save(toplevel, o_current);
00126           break;
00127 
00128         case(OBJ_BOX):
00129           out = o_box_save(toplevel, o_current);
00130           break;
00131 
00132         case(OBJ_CIRCLE):
00133           out = o_circle_save(toplevel, o_current);
00134           break;
00135 
00136         case(OBJ_COMPLEX):
00137           out = o_complex_save(toplevel, o_current);
00138           g_string_append_printf(acc, "%s\n", out);
00139           already_wrote = TRUE;
00140           g_free(out); /* need to free here because of the above flag */
00141 
00142           if (o_complex_is_embedded(o_current)) {
00143             g_string_append(acc, "[\n");
00144 
00145             out = o_save_objects(toplevel, o_current->complex->prim_objs, FALSE);
00146             g_string_append (acc, out);
00147             g_free(out);
00148 
00149             g_string_append(acc, "]\n");
00150           }
00151           break;
00152 
00153         case(OBJ_PLACEHOLDER):  /* new type by SDB 1.20.2005 */
00154           out = o_complex_save(toplevel, o_current);
00155           break;
00156 
00157         case(OBJ_TEXT):
00158           out = o_text_save(toplevel, o_current);
00159           break;
00160 
00161         case(OBJ_PATH):
00162           out = o_path_save(toplevel, o_current);
00163           break;
00164 
00165         case(OBJ_PIN):
00166           out = o_pin_save(toplevel, o_current);
00167           break;
00168 
00169         case(OBJ_ARC):
00170           out = o_arc_save(toplevel, o_current);
00171           break;
00172 
00173         case(OBJ_PICTURE):
00174           out = o_picture_save(toplevel, o_current);
00175           break;
00176 
00177         default:
00182           g_critical (_("o_save_objects: object %p has unknown type '%c'\n"),
00183                       o_current, o_current->type);
00184           /* Dump string built so far */
00185           g_string_free (acc, TRUE);
00186           return NULL;
00187       }
00188 
00189       /* output the line */
00190       if (!already_wrote) {
00191         g_string_append_printf(acc, "%s\n", out);
00192         g_free(out);
00193       } else {
00194         already_wrote = FALSE;
00195       }
00196 
00197       /* save any attributes */
00198       if (o_current->attribs != NULL) {
00199         g_string_append (acc, "{\n");
00200 
00201         out = o_save_objects (toplevel, o_current->attribs, TRUE);
00202         g_string_append (acc, out);
00203         g_free(out);
00204 
00205         g_string_append (acc, "}\n");
00206       }
00207     }
00208 
00209     iter = g_list_next (iter);
00210   }
00211 
00212   return g_string_free (acc, FALSE);
00213 }
00214 
00228 int o_save (TOPLEVEL *toplevel, const GList *object_list,
00229             const char *filename, GError **err)
00230 {
00231   char *buffer;
00232 
00233   /* Check to see if real filename is writable; if file doesn't exists
00234      we assume all is well */
00235   if (g_file_test(filename, G_FILE_TEST_EXISTS) && 
00236       g_access(filename, W_OK) != 0) {
00237     g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_PERM,
00238                  _("File %s is read-only"), filename);
00239     return 0;      
00240   }
00241 
00242   buffer = o_save_buffer (toplevel, object_list);
00243   if (!g_file_set_contents (filename, buffer, strlen(buffer), err)) {
00244     g_free (buffer);
00245     return 0;
00246   }
00247   g_free (buffer);
00248 
00249   return 1;
00250 }
00251 
00269 GList *o_read_buffer (TOPLEVEL *toplevel, GList *object_list,
00270                       char *buffer, const int size,
00271                       const char *name, GError **err)
00272 {
00273   const char *line = NULL;
00274   TextBuffer *tb = NULL;
00275 
00276   char objtype;
00277   GList *object_list_save=NULL;
00278   OBJECT *new_obj=NULL;
00279   GList *new_attrs_list;
00280   GList *new_object_list = NULL;
00281   GList *iter;
00282   unsigned int release_ver = 0;
00283   unsigned int fileformat_ver = 0;
00284   unsigned int current_fileformat_ver = FILEFORMAT_VERSION;
00285   int found_pin = 0;
00286   OBJECT* last_complex = NULL;
00287   int itemsread = 0;
00288 
00289   int embedded_level = 0;
00290 
00291   g_return_val_if_fail ((buffer != NULL), NULL);
00292 
00293   tb = s_textbuffer_new (buffer, size);
00294 
00295   while (1) {
00296 
00297     line = s_textbuffer_next_line(tb);
00298     if (line == NULL) break;
00299 
00300     sscanf(line, "%c", &objtype);
00301 
00302     /* Do we need to check the symbol version?  Yes, but only if */
00303     /* 1) the last object read was a complex and */
00304     /* 2) the next object isn't the start of attributes.  */
00305     /* If the next object is the start of attributes, then check the */
00306     /* symbol version after the attributes have been read in, see the */
00307     /* STARTATTACH_ATTR case */
00308     if (last_complex && objtype != STARTATTACH_ATTR)
00309     {
00310         /* yes */
00311         /* verify symbol version (not file format but rather contents) */
00312         o_complex_check_symversion(toplevel, last_complex);
00313         last_complex = NULL;  /* no longer need to check */
00314     }
00315 
00316     switch (objtype) {
00317 
00318       case(OBJ_LINE):
00319         if ((new_obj = o_line_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
00320           goto error;
00321         new_object_list = g_list_prepend (new_object_list, new_obj);
00322         break;
00323 
00324 
00325       case(OBJ_NET):
00326         if ((new_obj = o_net_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
00327           goto error;
00328         new_object_list = g_list_prepend (new_object_list, new_obj);
00329         break;
00330 
00331       case(OBJ_BUS):
00332         if ((new_obj = o_bus_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
00333           goto error;
00334         new_object_list = g_list_prepend (new_object_list, new_obj);
00335         break;
00336 
00337       case(OBJ_BOX):
00338         if ((new_obj = o_box_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
00339           goto error;
00340         new_object_list = g_list_prepend (new_object_list, new_obj);
00341         break;
00342 
00343       case(OBJ_PICTURE):
00344         new_obj = o_picture_read (toplevel, line, tb, release_ver, fileformat_ver, err);
00345         if (new_obj == NULL)
00346           goto error;
00347         new_object_list = g_list_prepend (new_object_list, new_obj);
00348         break;
00349 
00350       case(OBJ_CIRCLE):
00351         if ((new_obj = o_circle_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
00352       goto error;
00353         new_object_list = g_list_prepend (new_object_list, new_obj);
00354         break;
00355 
00356       case(OBJ_COMPLEX):
00357       case(OBJ_PLACEHOLDER):
00358         if ((new_obj = o_complex_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
00359           goto error;
00360         new_object_list = g_list_prepend (new_object_list, new_obj);
00361 
00362         /* last_complex is used for verifying symversion attribute */
00363         last_complex = new_obj;
00364         break;
00365 
00366       case(OBJ_TEXT):
00367         new_obj = o_text_read (toplevel, line, tb, release_ver, fileformat_ver, err);
00368         if (new_obj == NULL)
00369           goto error;
00370         new_object_list = g_list_prepend (new_object_list, new_obj);
00371         break;
00372 
00373       case(OBJ_PATH):
00374         new_obj = o_path_read (toplevel, line, tb, release_ver, fileformat_ver, err);
00375         if (new_obj == NULL)
00376           goto error;
00377         new_object_list = g_list_prepend (new_object_list, new_obj);
00378         break;
00379 
00380       case(OBJ_PIN):
00381         if ((new_obj = o_pin_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
00382           goto error;
00383         new_object_list = g_list_prepend (new_object_list, new_obj);
00384         found_pin++;
00385         break;
00386 
00387       case(OBJ_ARC):
00388         if ((new_obj = o_arc_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
00389           goto error;
00390         new_object_list = g_list_prepend (new_object_list, new_obj);
00391         break;
00392 
00393       case(STARTATTACH_ATTR): 
00394         /* first is the fp */
00395         /* 2nd is the object to get the attributes */
00396         if (new_obj != NULL) {
00397           o_attrib_freeze_hooks (toplevel, new_obj);
00398           new_attrs_list = o_read_attribs (toplevel, new_obj, tb, release_ver, fileformat_ver, err);
00399           if (new_attrs_list == NULL)
00400             goto error;
00401           new_object_list = g_list_concat (new_attrs_list, new_object_list);
00402           o_attrib_thaw_hooks (toplevel, new_obj);
00403 
00404           /* by now we have finished reading all the attributes */
00405           /* did we just finish attaching to a complex object? */
00406           if (last_complex)
00407           {
00408             /* yes */
00409             /* verify symbol version (not file format but rather contents) */
00410             o_complex_check_symversion(toplevel, last_complex);
00411             last_complex = NULL;
00412           }
00413 
00414           /* slots only apply to complex objects */
00415           if (new_obj != NULL &&
00416               (new_obj->type == OBJ_COMPLEX ||
00417                new_obj->type == OBJ_PLACEHOLDER)) {
00418             s_slot_update_object (toplevel, new_obj);
00419           }
00420           new_obj = NULL;
00421         }
00422         else {
00423           g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Read unexpected attach "
00424                                                                  "symbol start marker in [%s] :\n>>\n%s<<\n"),
00425                        name, line);
00426           goto error;
00427         }
00428         break;
00429 
00430       case(START_EMBEDDED):
00431         if (new_obj != NULL &&
00432             (new_obj->type == OBJ_COMPLEX ||
00433              new_obj->type == OBJ_PLACEHOLDER)) {
00434 
00435           object_list_save = new_object_list;
00436           new_object_list = new_obj->complex->prim_objs;
00437 
00438           embedded_level++;
00439         } else {
00440           g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Read unexpected embedded "
00441                                                                  "symbol start marker in [%s] :\n>>\n%s<<\n"),
00442                        name, line);
00443           goto error;
00444         }
00445         break;
00446 
00447       case(END_EMBEDDED):
00448         if (embedded_level>0) {
00449           /* don't do this since objects are already
00450            * stored/read translated
00451            * o_complex_translate_world (toplevel, new_object_list->x,
00452            *                            new_object_list->y, new_object_list->complex);
00453            */
00454           new_object_list = g_list_reverse (new_object_list);
00455 
00456           new_obj = object_list_save->data;
00457           new_obj->complex->prim_objs = new_object_list;
00458           new_object_list = object_list_save;
00459 
00460           /* set the parent field now */
00461           for (iter = new_obj->complex->prim_objs;
00462                iter != NULL; iter = g_list_next (iter)) {
00463             OBJECT *tmp = iter->data;
00464             tmp->parent = new_obj;
00465           }
00466 
00467           o_recalc_single_object (toplevel, new_obj);
00468 
00469           embedded_level--;
00470         } else {
00471           g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Read unexpected embedded "
00472                                                                  "symbol end marker in [%s] :\n>>\n%s<<\n"),
00473                        name, line);
00474           goto error;
00475         }
00476         break;
00477 
00478       case(ENDATTACH_ATTR):
00479         /* this case is never hit, since the } is consumed by o_read_attribs */
00480         break;
00481 
00482       case(INFO_FONT):
00483         /* NOP */
00484         break;
00485 
00486       case(COMMENT):
00487         /* do nothing */
00488         break;
00489 
00490       case(VERSION_CHAR):
00491         itemsread = sscanf(line, "v %u %u\n", &release_ver, &fileformat_ver);
00492 
00493         if (itemsread == 0) {
00494           g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, "Failed to parse version from buffer.");
00495           goto error;
00496         }
00497 
00498         /* 20030921 was the last version which did not have a fileformat */
00499         /* version.  The below latter test should not happen, but it is here */
00500         /* just in in case. */
00501         if (release_ver <= VERSION_20030921 || itemsread == 1) {
00502           fileformat_ver = 0;
00503         }
00504 
00505         if (fileformat_ver == 0) {
00506           s_log_message(_("Read an old format sym/sch file!\n"
00507                           "Please run g[sym|sch]update on:\n[%s]\n"), name);
00508         }
00509         break;
00510 
00511       default:
00512         g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Read garbage in [%s] :\n>>\n%s<<\n"), name, line);
00513         new_obj = NULL;
00514         goto error;
00515     }
00516 
00517   }
00518 
00519   /* Was the very last thing we read a complex and has it not been checked */
00520   /* yet?  This would happen if the complex is at the very end of the file  */
00521   /* and had no attached attributes */
00522   if (last_complex)
00523   {
00524         o_complex_check_symversion(toplevel, last_complex);
00525         last_complex = NULL;  /* no longer need to check */
00526   }
00527 
00528   if (found_pin) {
00529     if (release_ver <= VERSION_20020825) {
00530       o_pin_update_whichend (toplevel, new_object_list, found_pin);
00531     }
00532   }
00533 
00534   tb = s_textbuffer_free(tb);
00535 
00536   new_object_list = g_list_reverse(new_object_list);
00537   object_list = g_list_concat (object_list, new_object_list);
00538 
00539   return(object_list);
00540  error:
00541   s_delete_object_glist(toplevel, new_object_list);
00542   return NULL;
00543 }
00544 
00556 GList *o_read (TOPLEVEL *toplevel, GList *object_list, char *filename,
00557                GError **err)
00558 {
00559   char *buffer = NULL;
00560   size_t size;
00561   GList *result;
00562 
00563   /* Return NULL if error reporting is enabled and the return location
00564    * for an error isn't NULL. */
00565   g_return_val_if_fail (err == NULL || *err == NULL, NULL);
00566 
00567   if (!g_file_get_contents(filename, &buffer, &size, err)) {
00568     return NULL;
00569   } 
00570 
00571   /* Parse file contents */
00572   result = o_read_buffer (toplevel, object_list, buffer, size, filename, err);
00573   g_free (buffer);
00574   return result;
00575 }
00576 
00592 void o_scale (TOPLEVEL *toplevel, GList *list, int x_scale, int y_scale)
00593 {
00594   OBJECT *o_current;
00595   GList *iter;
00596 
00597   /* this is okay if you just hit scale and have nothing selected */
00598   if (list == NULL) {
00599     return;
00600   }
00601 
00602   iter = list;
00603   while (iter != NULL) {
00604     o_current = (OBJECT *)iter->data;
00605     switch(o_current->type) {
00606       case(OBJ_LINE):
00607         o_line_scale_world(toplevel, x_scale, y_scale, o_current);
00608         break;
00609     }
00610     iter = g_list_next (iter);
00611   }
00612 }
00613 
00614 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines