/*! \brief Re-poll a library command for symbols. * \par Function Description * Runs a library command, requesting a list of available symbols, * and updates the source with the new list. * * Private function used only in s_clib.c. */ static void refresh_command (CLibSource *source) { gchar *cmdout; TextBuffer *tb; const gchar *line; CLibSymbol *symbol; gchar *name; g_return_if_fail (source != NULL); g_return_if_fail (source->type == CLIB_CMD); /* Clear the current symbol list */ g_list_foreach (source->symbols, (GFunc) free_symbol, NULL); g_list_free (source->symbols); source->symbols = NULL; /* Run the command to get the list of symbols */ cmdout = run_source_command (source->list_cmd); if (cmdout == NULL) return; /* Use a TextBuffer to help reading out the lines of the output */ tb = s_textbuffer_new (cmdout, -1, "s_clib.c::refresh_command()"); while (1) { line = s_textbuffer_next_line (tb); if (line == NULL) break; if (line[0] == '.') continue; /* TODO is this sane? */ name = geda_string_get_first_line (g_strdup(line)); /* skip symbols already known about */ if (source_has_symbol (source, name) != NULL) { g_free (name); continue; } symbol = g_new0 (CLibSymbol, 1); symbol->source = source; symbol->name = name; /* Prepend because it's faster and it doesn't matter what order we * add them. */ source->symbols = g_list_prepend (source->symbols, symbol); } s_textbuffer_free (tb); g_free (cmdout); /* Sort all symbols by name. */ source->symbols = g_list_sort (source->symbols, (GCompareFunc) compare_symbol_name); s_clib_flush_search_cache(); s_clib_flush_symbol_cache(); }
/*! \brief Create path OBJECT from character string. * \par Function Description * This function creates a path OBJECT from the character string * <B>*buf</B> and a number of lines following that describing the * path, read from <B>*tb</B>. * * Depending on <B>*version</B>, the correct file format is considered. * Currently two file format revisions are supported : * <DL> * <DT>*</DT><DD>the file format used until 20010704 release. * <DT>*</DT><DD>the file format used for the releases after 20010704. * </DL> * * \param [in] toplevel The TOPLEVEL object. * \param [in] first_line Character string with path description. * \param [in] tb Text buffer containing the path string. * \param [in] release_ver libgeda release version number. * \param [in] fileformat_ver libgeda file format version number. * \return A pointer to the new path object, or NULL on error; */ OBJECT *o_path_read (TOPLEVEL *toplevel, const char *first_line, TextBuffer *tb, unsigned int release_ver, unsigned int fileformat_ver, GError **err) { OBJECT *new_obj; char type; int color; int line_width, line_space, line_length; int line_end; int line_type; int fill_type, fill_width, angle1, pitch1, angle2, pitch2; int num_lines = 0; int i; char *string; GString *pathstr; /* * The current path format to describe a line is a space separated * list of characters and numbers in plain ASCII on a single path. * The meaning of each item is described in the file format documentation. */ /* Allocate enough space */ if (sscanf (first_line, "%c %d %d %d %d %d %d %d %d %d %d %d %d %d\n", &type, &color, &line_width, &line_end, &line_type, &line_length, &line_space, &fill_type, &fill_width, &angle1, &pitch1, &angle2, &pitch2, &num_lines) != 14) { g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse path object")); return NULL; } /* * Checks if the required color is valid. */ if (color < 0 || color > MAX_COLORS) { s_log_message (_("Found an invalid color [ %1$s ]"), first_line); s_log_message (_("Setting color to default color.")); color = DEFAULT_COLOR; } /* * A path is internally described by its two ends. A new object is * allocated, initialized and added to the list of objects. Its path * type is set according to the values of the fields on the path. */ pathstr = g_string_new (""); for (i = 0; i < num_lines; i++) { const gchar *line; line = s_textbuffer_next_line (tb); if (line == NULL) { g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Unexpected end-of-file when reading path")); return NULL; } pathstr = g_string_append (pathstr, line); } /* retrieve the character string from the GString */ string = g_string_free (pathstr, FALSE); string = geda_string_remove_ending_newline (string); /* create a new path */ new_obj = geda_path_object_new (toplevel, type, color, string); g_free (string); /* set its line options */ o_set_line_options (toplevel, new_obj, (OBJECT_END) line_end, (OBJECT_TYPE) line_type, line_width, line_length, line_space); /* set its fill options */ o_set_fill_options (toplevel, new_obj, (OBJECT_FILLING) fill_type, fill_width, pitch1, angle1, pitch2, angle2); return new_obj; }
/*! \brief Read attributes from a buffer. * \par Function Description * Read attributes from a TextBuffer. * * \param [in] toplevel The TOPLEVEL object. * \param [in] object_to_get_attribs Object which gets these attribs. * \param [in] tb The text buffer to read from. * \param [in] release_ver libgeda release version number. * \param [in] fileformat_ver file format version number. * \return GList of attributes read, or NULL on error. */ GList *o_read_attribs (TOPLEVEL *toplevel, OBJECT *object_to_get_attribs, TextBuffer *tb, unsigned int release_ver, unsigned int fileformat_ver, GError ** err) { GList *object_list = NULL; OBJECT *new_obj; const char *line = NULL; char objtype; int ATTACH=FALSE; while (1) { line = s_textbuffer_next_line (tb); if (line == NULL) break; sscanf(line, "%c", &objtype); switch (objtype) { case(OBJ_LINE): if ((new_obj = o_line_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL) goto error; object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_NET): if ((new_obj = o_net_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL) goto error; object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_BUS): if ((new_obj = o_bus_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL) goto error; object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_BOX): if ((new_obj = o_box_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL) goto error; object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_CIRCLE): if ((new_obj = o_circle_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL) goto error; object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_COMPLEX): case(OBJ_PLACEHOLDER): if ((new_obj = o_complex_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL) goto error; object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_PATH): new_obj = o_path_read (toplevel, line, tb, release_ver, fileformat_ver, err); if (new_obj == NULL) goto error; object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_PIN): if ((new_obj = o_pin_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL) goto error; object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_ARC): if ((new_obj = o_arc_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL) goto error; object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_TEXT): new_obj = o_text_read (toplevel, line, tb, release_ver, fileformat_ver, err); if (new_obj == NULL) goto error; object_list = g_list_prepend (object_list, new_obj); ATTACH=TRUE; break; case(ENDATTACH_ATTR): return object_list; break; } if (ATTACH) { o_attrib_attach (toplevel, new_obj, object_to_get_attribs, FALSE); ATTACH=FALSE; } else { g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Tried to attach a non-text item as an attribute")); goto error; } } /* The attribute list wasn't terminated, so it's a parse error! */ g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Unexpected end-of-file in attribute list")); error: s_delete_object_glist(toplevel, object_list); return NULL; }
/*! \brief Read attributes from a buffer. * \par Function Description * Read attributes from a TextBuffer. * * \param [in] toplevel The TOPLEVEL object. * \param [out] list Storage for attributes. * \param [in] object_to_get_attribs Object which gets these attribs. * \param [in] tb The text buffer to read from. * \param [in] release_ver libgeda release version number. * \param [in] fileformat_ver file format version number. * \return GList of attributes read. */ GList *o_read_attribs (TOPLEVEL *toplevel, GList *list, OBJECT *object_to_get_attribs, TextBuffer *tb, unsigned int release_ver, unsigned int fileformat_ver) { GList *object_list; OBJECT *new_obj; char *line = NULL; char objtype; int ATTACH=FALSE; object_list = g_list_reverse (list); while (1) { line = s_textbuffer_next_line (tb); if (line == NULL) break; sscanf(line, "%c", &objtype); switch (objtype) { case(OBJ_LINE): new_obj = o_line_read (toplevel, line, release_ver, fileformat_ver); object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_NET): new_obj = o_net_read (toplevel, line, release_ver, fileformat_ver); object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_BUS): new_obj = o_bus_read (toplevel, line, release_ver, fileformat_ver); object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_BOX): new_obj = o_box_read (toplevel, line, release_ver, fileformat_ver); object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_CIRCLE): new_obj = o_circle_read (toplevel, line, release_ver, fileformat_ver); object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_COMPLEX): case(OBJ_PLACEHOLDER): new_obj = o_complex_read (toplevel, line, release_ver, fileformat_ver); object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_PATH): line = g_strdup (line); new_obj = o_path_read (toplevel, line, tb, release_ver, fileformat_ver); g_free (line); object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_PIN): new_obj = o_pin_read (toplevel, line, release_ver, fileformat_ver); object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_ARC): new_obj = o_arc_read (toplevel, line, release_ver, fileformat_ver); object_list = g_list_prepend (object_list, new_obj); break; case(OBJ_TEXT): line = g_strdup (line); new_obj = o_text_read (toplevel, line, tb, release_ver, fileformat_ver); g_free (line); object_list = g_list_prepend (object_list, new_obj); ATTACH=TRUE; break; case(ENDATTACH_ATTR): object_list = g_list_reverse (object_list); return(object_list); break; } if (ATTACH) { o_attrib_attach (toplevel, new_obj, object_to_get_attribs, FALSE); ATTACH=FALSE; } else { fprintf(stderr, "Tried to attach a non-text item as an attribute\n"); } } object_list = g_list_reverse (object_list); return(object_list); }
/*! \brief Create picture OBJECT from character string. * \par Function Description * This function will get the description of a picture from the * character string <B>*first_line</B>. * * \param [in] toplevel The TOPLEVEL object. * \param [in] first_line Character string with picture description. * \param [in] tb Text buffer to load embedded data from. * \param [in] release_ver libgeda release version number. * \param [in] fileformat_ver libgeda file format version number. * \return A pointer to the new picture object. */ OBJECT *o_picture_read (TOPLEVEL *toplevel, const char *first_line, TextBuffer *tb, unsigned int release_ver, unsigned int fileformat_ver) { OBJECT *new_obj; int x1, y1; int width, height, angle; gchar mirrored, embedded; int num_conv; gchar type; gchar *line = NULL; gchar *filename; GdkPixbuf *pixbuf = NULL; gchar *file_content = NULL; guint file_length = 0; GError *err = NULL; num_conv = sscanf(first_line, "%c %d %d %d %d %d %c %c\n", &type, &x1, &y1, &width, &height, &angle, &mirrored, &embedded); if (num_conv != 8) { s_log_message (_("Error reading picture definition line: %s.\n"), first_line); } /* Convert from ascii character to number */ if (g_ascii_isdigit(mirrored)) { mirrored -= 0x30; } if (g_ascii_isdigit(embedded)) { embedded -= 0x30; } if (width == 0 || height == 0) { s_log_message(_("Found a zero width/height picture [ %c %d %d %d %d ]\n"), type, x1, y1, width, height); } if ( (mirrored > 1) || (mirrored < 0)) { s_log_message(_("Found a picture with a wrong 'mirrored' parameter: %c.\n"), mirrored); s_log_message(_("Setting mirrored to 0\n")); mirrored = 0; } if ( (embedded > 1) || (embedded < 0)) { s_log_message(_("Found a picture with a wrong 'embedded' parameter: %c.\n"), embedded); s_log_message(_("Setting embedded to 0\n")); embedded = 0; } switch(angle) { case(0): case(90): case(180): case(270): break; default: s_log_message(_("Found an unsupported picture angle [ %d ]\n"), angle); s_log_message(_("Setting angle to 0\n")); angle=0; break; } filename = g_strdup(s_textbuffer_next_line(tb)); filename = remove_last_nl(filename); if (embedded == 1) { GString *encoded_picture=g_string_new(""); char finished = 0; /* Read the encoded picture */ do { line = s_textbuffer_next_line(tb); if (line == NULL) break; if (g_strcasecmp(line, ".\n") != 0) { encoded_picture = g_string_append (encoded_picture, line); } else { finished = 1; } } while (finished == 0); /* Decode the picture */ file_content = s_encoding_base64_decode(encoded_picture->str, encoded_picture->len, &file_length); if (encoded_picture != NULL) { g_string_free (encoded_picture, TRUE); } if (file_content == NULL) { s_log_message (_("Failed to load image from embedded data [%s]: %s\n"), filename, _("Base64 decoding failed.")); s_log_message (_("Falling back to file loading. Picture unembedded.\n")); embedded = 0; } } /* If we have embedded data, try loading from the decoded buffer */ if (file_content != NULL) { pixbuf = o_picture_pixbuf_from_buffer (file_content, file_length, &err); if (err != NULL) { s_log_message (_("Failed to load image from embedded data [%s]: %s\n"), filename, err->message); s_log_message (_("Falling back to file loading. Picture unembedded.\n")); g_error_free (err); err = NULL; embedded = 0; } } /* If we haven't loaded the pixbuf above, try loading from file */ if (pixbuf == NULL) { pixbuf = gdk_pixbuf_new_from_file (filename, &err); if (err != NULL) { s_log_message (_("Failed to load image from file [%s]: %s\n"), filename, err->message); g_error_free (err); err = NULL; } } /* If the pixbuf couldn't be loaded, then try to load a warning picture */ if (pixbuf == NULL) { char *temp_filename; s_log_message (_("Loading warning picture.\n")); temp_filename = g_build_filename (toplevel->bitmap_directory, "gschem-warning.png", NULL); pixbuf = gdk_pixbuf_new_from_file (temp_filename, NULL); if (pixbuf == NULL) { s_log_message( _("Error loading picture from file: %s.\n"), temp_filename); } g_free (temp_filename); } /* create the picture */ /* The picture is described by its upper left and lower right corner */ new_obj = o_picture_new(toplevel, pixbuf, file_content, file_length, filename, (double)width / (double)height, type, x1, y1+height, x1+width, y1, angle, mirrored, embedded); /* Don't free file_content, it is now owned by the picture object */ return new_obj; }
/*! \brief Create picture OBJECT from character string. * \par Function Description * Parses \a first_line and subsequent lines from \a tb, and returns * a newly-created picture #OBJECT. * * \param [in] toplevel The TOPLEVEL object. * \param [in] first_line Character string with picture description. * \param [in] tb Text buffer to load embedded data from. * \param [in] release_ver libgeda release version number. * \param [in] fileformat_ver libgeda file format version number. * \return A pointer to the new picture object, or NULL on error. */ OBJECT *o_picture_read (TOPLEVEL *toplevel, const char *first_line, TextBuffer *tb, unsigned int release_ver, unsigned int fileformat_ver, GError **err) { OBJECT *new_obj; int x1, y1; int width, height, angle; int mirrored, embedded; int num_conv; gchar type; const gchar *line = NULL; gchar *filename; gchar *file_content = NULL; guint file_length = 0; num_conv = sscanf(first_line, "%c %d %d %d %d %d %d %d\n", &type, &x1, &y1, &width, &height, &angle, &mirrored, &embedded); if (num_conv != 8) { g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse picture definition")); return NULL; } if (width == 0 || height == 0) { s_log_message(_("Found a zero width/height picture " "[ %1$c %2$d %3$d %4$d %5$d ]"), type, x1, y1, width, height); } if ( (mirrored > 1) || (mirrored < 0)) { s_log_message(_("Found a picture with a wrong 'mirrored' parameter: %1$d."), mirrored); s_log_message(_("Setting mirrored to 0.")); mirrored = 0; } if ( (embedded > 1) || (embedded < 0)) { s_log_message(_("Found a picture with a wrong 'embedded' parameter: %1$d."), embedded); s_log_message(_("Setting embedded to 0.")); embedded = 0; } switch(angle) { case(0): case(90): case(180): case(270): break; default: s_log_message(_("Found an unsupported picture angle [ %1$d ]"), angle); s_log_message(_("Setting angle to 0.")); angle=0; break; } filename = g_strdup(s_textbuffer_next_line(tb)); filename = geda_string_remove_ending_newline (filename); /* Handle empty filenames */ if (strlen (filename) == 0) { s_log_message (_("Found an image with no filename.")); g_free (filename); filename = NULL; } if (embedded == 1) { GString *encoded_picture=g_string_new(""); char finished = 0; /* Read the encoded picture */ do { line = s_textbuffer_next_line(tb); if (line == NULL) break; if (strcmp (line, ".\n") != 0) { encoded_picture = g_string_append (encoded_picture, line); } else { finished = 1; } } while (finished == 0); /* Decode the picture */ if (encoded_picture != NULL) { file_content = s_encoding_base64_decode(encoded_picture->str, encoded_picture->len, &file_length); g_string_free (encoded_picture, TRUE); } if (file_content == NULL) { s_log_message (_("Failed to load image from embedded data [%1$s]: %2$s"), filename, _("Base64 decoding failed.")); s_log_message (_("Falling back to file loading. Picture unembedded.")); embedded = 0; } } /* create the picture */ /* The picture is described by its upper left and lower right corner */ new_obj = o_picture_new (toplevel, file_content, file_length, filename, type, x1, y1+height, x1+width, y1, angle, mirrored, embedded); g_free (file_content); g_free (filename); return new_obj; }
/*! \brief read a text object from a char buffer * \par Function Description * This function reads a text object from the textbuffer \a tb and * the text starting with the line \a firstline. * If the line object was read successfully, a new object is * create and appended to the \a object_list. * * \param [in] toplevel The TOPLEVEL object * \param [in] first_line the first line of the text * \param [in] tb a text buffer (usually a line of a schematic file) * \param [in] release_ver The release number gEDA * \param [in] fileformat_ver a integer value of the file format * \return The object list, or NULL on error. */ OBJECT* o_text_read (TOPLEVEL *toplevel, const char *first_line, TextBuffer *tb, unsigned int release_ver, unsigned int fileformat_ver, GError **err) { OBJECT *new_obj; char type; int x, y; int color; int size; int visibility; int show_name_value; int angle; int alignment; int num_lines = 0; int i; char* string = NULL; GString *textstr; if (fileformat_ver >= 1) { if (sscanf(first_line, "%c %d %d %d %d %d %d %d %d %d\n", &type, &x, &y, &color, &size, &visibility, &show_name_value, &angle, &alignment, &num_lines) != 10) { g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse text object")); return NULL; } } else if (release_ver < VERSION_20000220) { /* yes, above less than (not less than and equal) is correct. The format */ /* change occurred in 20000220 */ if (sscanf(first_line, "%c %d %d %d %d %d %d %d\n", &type, &x, &y, &color, &size, &visibility, &show_name_value, &angle) != 8) { g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse text object")); return NULL; } alignment = LOWER_LEFT; /* older versions didn't have this */ num_lines = 1; /* only support a single line */ } else { if (sscanf(first_line, "%c %d %d %d %d %d %d %d %d\n", &type, &x, &y, &color, &size, &visibility, &show_name_value, &angle, &alignment) != 9) { g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse text object")); return NULL; } num_lines = 1; /* only support a single line */ } if (size < MINIMUM_TEXT_SIZE) { s_log_message (_("Found an invalid text size [ %1$s ]"), first_line); size = DEFAULT_TEXT_SIZE; s_log_message (_("Setting text size to %1$d."), size); } if (!geda_angle_is_ortho (angle)) { s_log_message (_("Found an unsupported text angle [ %1$s ]"), first_line); angle = geda_angle_make_ortho (angle); s_log_message (_("Setting angle to %1$d."), angle); } switch(alignment) { case(LOWER_LEFT): case(MIDDLE_LEFT): case(UPPER_LEFT): case(LOWER_MIDDLE): case(MIDDLE_MIDDLE): case(UPPER_MIDDLE): case(LOWER_RIGHT): case(MIDDLE_RIGHT): case(UPPER_RIGHT): break; default: s_log_message (_("Found an unsupported text alignment [ %1$s ]"), first_line); alignment = LOWER_LEFT; s_log_message(_("Setting alignment to LOWER_LEFT.")); break; } if (color < 0 || color > MAX_COLORS) { s_log_message(_("Found an invalid color [ %1$s ]"), first_line); color = DEFAULT_COLOR; s_log_message(_("Setting color to default color.")); } g_assert(num_lines && num_lines > 0); textstr = g_string_new (""); for (i = 0; i < num_lines; i++) { const gchar *line; line = s_textbuffer_next_line (tb); if (line == NULL) { g_string_free (textstr, TRUE); g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Unexpected end-of-file after %1$d lines"), i); return NULL; } textstr = g_string_append (textstr, line); } /* retrieve the character string from the GString */ string = g_string_free (textstr, FALSE); string = geda_string_remove_ending_newline (string); /* convert the character string to UTF-8 if necessary */ if (!g_utf8_validate (string, -1, NULL)) { /* if it is not utf-8, it is ISO_8859-15 */ gchar *tmp = g_convert (string, strlen (string), "UTF-8", "ISO_8859-15", NULL, NULL, NULL); if (tmp == NULL) { fprintf (stderr, "Failed to convert text string to UTF-8: %1$s.\n", string); } else { /* successfully converted string, now use tmp as string */ g_free (string); string = tmp; } } new_obj = geda_text_object_new (toplevel, color, x, y, alignment, angle, string, size, visibility, show_name_value); g_free(string); return new_obj; }