libgeda
|
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