From cd9030a24ed8ee44a0c89f6bc63fc10c3332f46f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Tue, 5 Mar 2019 19:38:07 +0100 Subject: [PATCH 01/25] Create GDS Tree checking functions. Renamed doxygen section of GDS Parser to GDS-Utilities so the cheking function fit into this section --- gds-parser/gds-parser.c | 7 +--- gds-parser/gds-parser.h | 2 +- gds-parser/gds-tree-checker.c | 48 +++++++++++++++++++++++++ gds-parser/gds-tree-checker.h | 55 +++++++++++++++++++++++++++++ gds-parser/gds-types.h | 2 +- trigonometric/cell-trigonometrics.c | 6 ++-- 6 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 gds-parser/gds-tree-checker.c create mode 100644 gds-parser/gds-tree-checker.h diff --git a/gds-parser/gds-parser.c b/gds-parser/gds-parser.c index e6ef61b..8fe475c 100644 --- a/gds-parser/gds-parser.c +++ b/gds-parser/gds-parser.c @@ -17,11 +17,6 @@ * along with GDSII-Converter. If not, see . */ -/* - - */ - - /** * @file gds-parser.c * @brief Implementation of the GDS-Parser @@ -35,7 +30,7 @@ */ /** - * @addtogroup GDS-Parser + * @addtogroup GDS-Utilities * @{ */ diff --git a/gds-parser/gds-parser.h b/gds-parser/gds-parser.h index 1704395..ce745e4 100644 --- a/gds-parser/gds-parser.h +++ b/gds-parser/gds-parser.h @@ -24,7 +24,7 @@ */ /** - * @addtogroup GDS-Parser + * @addtogroup GDS-Utilities * @{ */ diff --git a/gds-parser/gds-tree-checker.c b/gds-parser/gds-tree-checker.c new file mode 100644 index 0000000..7833ec0 --- /dev/null +++ b/gds-parser/gds-tree-checker.c @@ -0,0 +1,48 @@ +/* + * GDSII-Converter + * Copyright (C) 2019 Mario Hüttel + * + * This file is part of GDSII-Converter. + * + * GDSII-Converter is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * GDSII-Converter is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GDSII-Converter. If not, see . + */ + +/** + * @file gds-tree-checker.c + * @brief Checking functions of a cell tree + * + * This file contains cehcking functions for the GDS cell tree. + * These functions include checks if all child references could be resolved, + * and if the cell tree contains loops. + * + * @author Mario Hüttel + */ + +/** + * @addtogroup GDS-Utilities + * @{ + */ + +#include "gds-tree-checker.h" + +int gds_tree_check_cell_references(struct gds_library *lib) +{ + return 0; +} + +int gds_tree_check_reference_loops(struct gds_library *lib) +{ + return 0; +} + +/** @} */ diff --git a/gds-parser/gds-tree-checker.h b/gds-parser/gds-tree-checker.h new file mode 100644 index 0000000..964b1b9 --- /dev/null +++ b/gds-parser/gds-tree-checker.h @@ -0,0 +1,55 @@ +/* + * GDSII-Converter + * Copyright (C) 2019 Mario Hüttel + * + * This file is part of GDSII-Converter. + * + * GDSII-Converter is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * GDSII-Converter is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GDSII-Converter. If not, see . + */ + +/** + * @file gds-tree-checker.h + * @brief Checking functions of a cell tree (Header) + * @author Mario Hüttel + */ + +/** + * @addtogroup GDS-Utilities + * @{ + */ + +#ifndef _GDS_TREE_CHECKER_H_ +#define _GDS_TREE_CHECKER_H_ + +#include "gds-types.h" + +/** + * @brief gds_tree_check_cell_references checks if all child cell references can be resolved in the given library + * @param lib The GDS library to check + * @return less than 0 if an error occured during processing; 0 if all child cells could be resolved; + * greater than zero if the processing was successful but not all cell references could be resolved. + * In this case the number of unresolved references is returned + */ +int gds_tree_check_cell_references(struct gds_library *lib); + +/** + * @brief gds_tree_check_reference_loops checks if the given library contains reference loops + * @param lib GDS library + * @return negative if an error occured, zero if there are no reference loops, else a positive number representing the number + * of affected cells + */ +int gds_tree_check_reference_loops(struct gds_library *lib); + +#endif /* _GDS_TREE_CHECKER_H_ */ + +/** @} */ diff --git a/gds-parser/gds-types.h b/gds-parser/gds-types.h index 80e2acc..d6630cb 100644 --- a/gds-parser/gds-types.h +++ b/gds-parser/gds-types.h @@ -24,7 +24,7 @@ */ /** - * @addtogroup GDS-Parser + * @addtogroup GDS-Utilities * @{ */ diff --git a/trigonometric/cell-trigonometrics.c b/trigonometric/cell-trigonometrics.c index 823a531..7f13d44 100644 --- a/trigonometric/cell-trigonometrics.c +++ b/trigonometric/cell-trigonometrics.c @@ -94,14 +94,16 @@ void calculate_cell_bounding_box(union bounding_box *box, struct gds_cell *cell) } /* Update bounding box with boxes of subcells */ - for (sub_cell_list = cell->child_cells; sub_cell_list != NULL; sub_cell_list = sub_cell_list->next) { + for (sub_cell_list = cell->child_cells; sub_cell_list != NULL; + sub_cell_list = sub_cell_list->next) { sub_cell = (struct gds_cell_instance *)sub_cell_list->data; bounding_box_prepare_empty(&temp_box); /* Recursion Woohoo!! This dies if your GDS is faulty and contains a reference loop */ calculate_cell_bounding_box(&temp_box, sub_cell->cell_ref); /* Apply transformations */ - bounding_box_apply_transform(ABS(sub_cell->magnification), sub_cell->angle, sub_cell->flipped, &temp_box); + bounding_box_apply_transform(ABS(sub_cell->magnification), sub_cell->angle, + sub_cell->flipped, &temp_box); /* Move bounding box to origin */ temp_box.vectors.lower_left.x += sub_cell->origin.x; From 58bb74b905dbb69f49d837eb667eb21d4bc6635d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Tue, 5 Mar 2019 19:48:03 +0100 Subject: [PATCH 02/25] Add checks to cell structure --- gds-parser/gds-types.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/gds-parser/gds-types.h b/gds-parser/gds-types.h index d6630cb..29b0a95 100644 --- a/gds-parser/gds-types.h +++ b/gds-parser/gds-types.h @@ -35,6 +35,8 @@ #include #define CELL_NAME_MAX (100) /**< @brief Maximum length of a gds_cell::name or a gds_library::name */ + +/* Maybe use the macros that ship with the compiler? */ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) /**< @brief Return smaller number */ #define MAX(a,b) (((a) > (b)) ? (a) : (b)) /**< @brief Return bigger number */ @@ -59,6 +61,21 @@ struct gds_point { int y; }; +/** + * @brief Stores the result of the cell checks. + */ +struct gds_cell_checks { + int unresolved_child_count; /**< @brief Number of unresolved cell instances inside this cell */ + int affected_by_reference_loop; /**< @brief 1 if the cell is affected by a reference loop and therefore not renderable */ + /** + * @brief For the internal use of the checker. + * @warning Do not use this structure and its contents! + */ + struct _check_internals { + int marker; + } _internal; +}; + /** * @brief Date information for cells and libraries */ @@ -105,6 +122,7 @@ struct gds_cell { GList *child_cells; /**< @brief List of #gds_cell_instance elements */ GList *graphic_objs; /**< @brief List of #gds_graphics */ struct gds_library *parent_library; /**< @brief Pointer to parent library */ + struct gds_cell_checks checks; /**< @brief Checking results */ }; /** From 0ef6d2f40f15ec494b672adfca7eeeb11417d350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Tue, 5 Mar 2019 19:50:01 +0100 Subject: [PATCH 03/25] update trigonometric library doxygen --- doxygen/trigonometric.dox | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doxygen/trigonometric.dox b/doxygen/trigonometric.dox index 52819eb..9910642 100644 --- a/doxygen/trigonometric.dox +++ b/doxygen/trigonometric.dox @@ -2,7 +2,7 @@ /** * @defgroup trigonometric Trigonometric Helper Functions - * @description The trigonometric helper function will be used in future releases to pcalculate bounding boxes - * @note Currently not in use! - * @warning Code is incomplete. DO NOT USE! + * + * The trigonometric helper function are used to calculate bounding boxes + * @warning Code is incomplete. Please double check the functionality! */ From 0b17c25ecc4f089449dfdfb4919eeb5b47d779fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Tue, 5 Mar 2019 20:08:10 +0100 Subject: [PATCH 04/25] Add defualt value for check results --- gds-parser/gds-parser.c | 2 ++ gds-parser/gds-types.h | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/gds-parser/gds-parser.c b/gds-parser/gds-parser.c index 8fe475c..1cba95f 100644 --- a/gds-parser/gds-parser.c +++ b/gds-parser/gds-parser.c @@ -299,6 +299,8 @@ static GList *append_cell(GList *curr_list, struct gds_cell **cell_ptr) cell->graphic_objs = NULL; cell->name[0] = 0; cell->parent_library = NULL; + cell->checks.unresolved_child_count = GDS_CELL_CHECK_NOT_RUN; + cell->checks.affected_by_reference_loop = GDS_CELL_CHECK_NOT_RUN; } else return NULL; /* return cell */ diff --git a/gds-parser/gds-types.h b/gds-parser/gds-types.h index 29b0a95..1be507c 100644 --- a/gds-parser/gds-types.h +++ b/gds-parser/gds-types.h @@ -40,6 +40,10 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) /**< @brief Return smaller number */ #define MAX(a,b) (((a) > (b)) ? (a) : (b)) /**< @brief Return bigger number */ +/** @brief Defintion of check counter default value + * that indicates that the corresponding check has not yet been executed */ +enum {GDS_CELL_CHECK_NOT_RUN = -1}; + /** @brief Types of graphic objects */ enum graphics_type { @@ -65,8 +69,8 @@ struct gds_point { * @brief Stores the result of the cell checks. */ struct gds_cell_checks { - int unresolved_child_count; /**< @brief Number of unresolved cell instances inside this cell */ - int affected_by_reference_loop; /**< @brief 1 if the cell is affected by a reference loop and therefore not renderable */ + int unresolved_child_count; /**< @brief Number of unresolved cell instances inside this cell. Default: GDS_CELL_CHECK_NOT_RUN */ + int affected_by_reference_loop; /**< @brief 1 if the cell is affected by a reference loop and therefore not renderable. Default: GDS_CELL_CHECK_NOT_RUN*/ /** * @brief For the internal use of the checker. * @warning Do not use this structure and its contents! From 73e4806e650b80b7a3b3f970fbc132c2090cff5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Tue, 5 Mar 2019 20:14:07 +0100 Subject: [PATCH 05/25] Implenment child cell resolve checker --- gds-parser/gds-tree-checker.c | 45 ++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/gds-parser/gds-tree-checker.c b/gds-parser/gds-tree-checker.c index 7833ec0..e848219 100644 --- a/gds-parser/gds-tree-checker.c +++ b/gds-parser/gds-tree-checker.c @@ -34,10 +34,53 @@ */ #include "gds-tree-checker.h" +#include int gds_tree_check_cell_references(struct gds_library *lib) { - return 0; + GList *cell_iter; + struct gds_cell *cell; + GList *instance_iter; + struct gds_cell_instance *cell_inst; + int total_unresolved_count = 0; + + if (!lib) + return -1; + + /* Iterate over all cells in library */ + for (cell_iter = lib->cells; cell_iter != NULL; cell_iter = g_list_next(cell_iter)) { + cell = (struct gds_cell *)cell_iter->data; + + /* Check if this list element is broken. This should never happen */ + if (!cell) { + fprintf(stderr, "Broken cell list item found. Will continue.\n"); + continue; + } + + /* Reset the unresolved cell reference counter to 0 */ + cell->checks.unresolved_child_count = 0; + + /* Iterate through all child cell references and check if the references are set */ + for (instance_iter = cell->child_cells; instance_iter != NULL; + instance_iter = g_list_next(instance_iter)) { + cell_inst = (struct gds_cell_instance *)instance_iter->data; + + /* Check if broken. This should also not happen */ + if (!cell_inst) { + fprintf(stderr, "Broken cell list item found in cell %s. Will continue.\n", + cell->name); + continue; + } + + /* Check if instance is valid; else increment "error" counter of cell */ + if (!cell_inst->cell_ref) { + total_unresolved_count++; + cell->checks.unresolved_child_count++; + } + } + } + + return total_unresolved_count; } int gds_tree_check_reference_loops(struct gds_library *lib) From 976bdd9854045a252d458cdc75076a0e51fc231f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Tue, 5 Mar 2019 20:21:49 +0100 Subject: [PATCH 06/25] Fix function description --- gds-parser/gds-tree-checker.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gds-parser/gds-tree-checker.h b/gds-parser/gds-tree-checker.h index 964b1b9..199ace5 100644 --- a/gds-parser/gds-tree-checker.h +++ b/gds-parser/gds-tree-checker.h @@ -35,6 +35,12 @@ /** * @brief gds_tree_check_cell_references checks if all child cell references can be resolved in the given library + * + * This function will only mark cells that + * directly contain unresolved references. + * + * If a cell contains a reference to a cell with unresolved references, it is not flagged. + * * @param lib The GDS library to check * @return less than 0 if an error occured during processing; 0 if all child cells could be resolved; * greater than zero if the processing was successful but not all cell references could be resolved. From e9b67fe1bccccb653365ccf75cc5f88f78da7b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Tue, 5 Mar 2019 20:50:54 +0100 Subject: [PATCH 07/25] Implement error level indicator for cells --- main-window.c | 8 +------ tree-renderer/lib-cell-renderer.c | 39 +++++++++++++++++++++++++++++-- tree-renderer/lib-cell-renderer.h | 3 +++ tree-renderer/tree-store.c | 6 ++--- tree-renderer/tree-store.h | 2 +- 5 files changed, 45 insertions(+), 13 deletions(-) diff --git a/main-window.c b/main-window.c index 600bf0a..e25ebdb 100644 --- a/main-window.c +++ b/main-window.c @@ -114,7 +114,6 @@ static void on_load_gds(gpointer button, gpointer user) char *filename; GString *mod_date; GString *acc_date; - GdkRGBA cell_text_color; open_dialog = gtk_file_chooser_dialog_new("Open GDSII File", ptr->main_window, GTK_FILE_CHOOSER_ACTION_OPEN, "Cancel", GTK_RESPONSE_CANCEL, "Open GDSII", GTK_RESPONSE_ACCEPT, NULL); @@ -175,11 +174,6 @@ static void on_load_gds(gpointer button, gpointer user) mod_date = generate_string_from_date(&gds_c->mod_time); acc_date = generate_string_from_date(&gds_c->access_time); - cell_text_color.alpha = 1; - cell_text_color.red = (double)61.0/(double)255.0; - cell_text_color.green = (double)152.0/(double)255.0; - cell_text_color.blue = 0.0; - /* Add cell to tree store model * CELL_SEL_CELL_COLOR will always be green, * because no cell cehcker is implemented, yet. @@ -188,7 +182,7 @@ static void on_load_gds(gpointer button, gpointer user) CELL_SEL_CELL, gds_c, CELL_SEL_MODDATE, mod_date->str, CELL_SEL_ACCESSDATE, acc_date->str, - CELL_SEL_CELL_COLOR, &cell_text_color, // TODO: implement cell checker + CELL_SEL_CELL_ERROR_STATE, 0, // TODO: implement cell checker -1); /* Delete GStrings including string data. */ diff --git a/tree-renderer/lib-cell-renderer.c b/tree-renderer/lib-cell-renderer.c index 192210b..c5fe6c9 100644 --- a/tree-renderer/lib-cell-renderer.c +++ b/tree-renderer/lib-cell-renderer.c @@ -25,6 +25,7 @@ G_DEFINE_TYPE(LibCellRenderer, lib_cell_renderer, GTK_TYPE_CELL_RENDERER_TEXT) enum { PROP_LIB = 1, PROP_CELL, + PROP_ERROR_LEVEL, PROP_COUNT }; @@ -38,24 +39,56 @@ static void lib_cell_renderer_constructed(GObject *obj) G_OBJECT_CLASS(lib_cell_renderer_parent_class)->constructed(obj); } +static void convert_error_level_to_color(GdkRGBA *color, unsigned int error_level) +{ + + /* Always use no transparency */ + color->alpha = 1.0; + + if (error_level & LIB_CELL_RENDERER_ERROR_ERR) { + /* Error set. Color cell red */ + color->red = 1.0; + color->blue = 0.0; + color->green = 0.0; + } else if (error_level & LIB_CELL_RENDERER_ERROR_WARN) { + /* Only warning set; orange color */ + color->red = 0.6; + color->blue = 0.0; + color->green = 0.4; + } else { + /* Everything okay; green color */ + color->red = (double)61.0/(double)255.0; + color->green = (double)152.0/(double)255.0; + color->blue = 0.0; + } +} + static void lib_cell_renderer_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { GValue val = G_VALUE_INIT; - - g_value_init(&val, G_TYPE_STRING); + GdkRGBA color; switch (param_id) { case PROP_LIB: + g_value_init(&val, G_TYPE_STRING); g_value_set_string(&val, ((struct gds_library *)g_value_get_pointer(value))->name); g_object_set_property(object, "text", &val); break; case PROP_CELL: + g_value_init(&val, G_TYPE_STRING); g_value_set_string(&val, ((struct gds_cell *)g_value_get_pointer(value))->name); g_object_set_property(object, "text", &val); break; + case PROP_ERROR_LEVEL: + /* Set cell color according to error level */ + g_value_init(&val, GDK_TYPE_RGBA); + convert_error_level_to_color(&color, g_value_get_uint(value)); + g_value_set_boxed(&val, &color); + g_object_set_property(object, "foreground-rgba", &val); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec); break; @@ -89,6 +122,8 @@ void lib_cell_renderer_class_init(LibCellRendererClass *klass) properties[PROP_CELL] = g_param_spec_pointer("gds-cell", "gds-cell", "Cell reference to be displayed", G_PARAM_WRITABLE); + properties[PROP_ERROR_LEVEL] = g_param_spec_uint("error-level", "error-level", + "Error level of this cell", 0, 255, 0, G_PARAM_WRITABLE); g_object_class_install_properties(oclass, PROP_COUNT, properties); } diff --git a/tree-renderer/lib-cell-renderer.h b/tree-renderer/lib-cell-renderer.h index 4e0949f..b71888a 100644 --- a/tree-renderer/lib-cell-renderer.h +++ b/tree-renderer/lib-cell-renderer.h @@ -27,6 +27,9 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE(LibCellRenderer, lib_cell_renderer, LIB_CELL, RENDERER, GtkCellRendererText) #define TYPE_LIB_CELL_RENDERER (lib_cell_renderer_get_type()) +#define LIB_CELL_RENDERER_ERROR_WARN (1U<<0) +#define LIB_CELL_RENDERER_ERROR_ERR (1U<<1) + typedef struct _LibCellRenderer { /* Inheritance */ GtkCellRendererText super; diff --git a/tree-renderer/tree-store.c b/tree-renderer/tree-store.c index 2ba5c11..28b3ec7 100644 --- a/tree-renderer/tree-store.c +++ b/tree-renderer/tree-store.c @@ -127,7 +127,7 @@ struct tree_stores *setup_cell_selector(GtkTreeView* view, GtkEntry *search_entr stores.base_tree_view = view; stores.search_entry = search_entry; - stores.base_store = gtk_tree_store_new(CELL_SEL_COLUMN_COUNT, G_TYPE_POINTER, G_TYPE_POINTER, GDK_TYPE_RGBA, G_TYPE_STRING, G_TYPE_STRING); + stores.base_store = gtk_tree_store_new(CELL_SEL_COLUMN_COUNT, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING); /* Searching */ if (search_entry) { @@ -147,8 +147,8 @@ struct tree_stores *setup_cell_selector(GtkTreeView* view, GtkEntry *search_entr column = gtk_tree_view_column_new_with_attributes("Library", render_lib, "gds-lib", CELL_SEL_LIBRARY, NULL); gtk_tree_view_append_column(view, column); - /* Cell color: #3D9801 */ - column = gtk_tree_view_column_new_with_attributes("Cell", render_cell, "gds-cell", CELL_SEL_CELL, "foreground-rgba", CELL_SEL_CELL_COLOR, NULL); + column = gtk_tree_view_column_new_with_attributes("Cell", render_cell, "gds-cell", CELL_SEL_CELL, + "error-level", CELL_SEL_CELL_ERROR_STATE, NULL); gtk_tree_view_append_column(view, column); column = gtk_tree_view_column_new_with_attributes("Mod. Date", render_dates, "text", CELL_SEL_MODDATE, NULL); diff --git a/tree-renderer/tree-store.h b/tree-renderer/tree-store.h index aa6d283..e9b60da 100644 --- a/tree-renderer/tree-store.h +++ b/tree-renderer/tree-store.h @@ -37,7 +37,7 @@ enum cell_store_columns { CELL_SEL_LIBRARY = 0, CELL_SEL_CELL, - CELL_SEL_CELL_COLOR, /**< Cell column color */ + CELL_SEL_CELL_ERROR_STATE, /**< Used for cell color and selectability */ CELL_SEL_MODDATE, CELL_SEL_ACCESSDATE, CELL_SEL_COLUMN_COUNT /**< Not a column. Used to determine count of coumns **/ From 00b47d7ded68f3dc6d9d032cb9d6525354eb8e55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Tue, 5 Mar 2019 20:55:04 +0100 Subject: [PATCH 08/25] Add lib cell renderer to main window. It is needed for the Error level defines of the cells --- main-window.c | 1 + 1 file changed, 1 insertion(+) diff --git a/main-window.c b/main-window.c index e25ebdb..b4cf106 100644 --- a/main-window.c +++ b/main-window.c @@ -37,6 +37,7 @@ #include "widgets/conv-settings-dialog.h" #include "cairo-output/cairo-output.h" #include "trigonometric/cell-trigonometrics.h" +#include "tree-renderer/lib-cell-renderer.h" /** * @brief User data supplied to callback function of the open button From 3882f3944e8e427ad55409b7ec9244514aa8136f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Tue, 5 Mar 2019 21:02:57 +0100 Subject: [PATCH 09/25] Change selction filter function. Now only cells without major errors are selectable. Warnings are okay because the renderers can handle these (unresolved references etc...) --- tree-renderer/tree-store.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tree-renderer/tree-store.c b/tree-renderer/tree-store.c index 28b3ec7..3da3d63 100644 --- a/tree-renderer/tree-store.c +++ b/tree-renderer/tree-store.c @@ -49,15 +49,20 @@ static gboolean tree_sel_func(GtkTreeSelection *selection, { GtkTreeIter iter; struct gds_cell *cell; + unsigned int error_level; + gboolean ret = FALSE; gtk_tree_model_get_iter(model, &iter, path); - gtk_tree_model_get(model, &iter, CELL_SEL_CELL, &cell, -1); + gtk_tree_model_get(model, &iter, CELL_SEL_CELL, &cell, CELL_SEL_CELL_ERROR_STATE, &error_level, -1); - /* Allow only rows with valid cell to be selected */ - if (cell) - return TRUE; - else - return FALSE; + /* Allow only rows with _valid_ cell to be selected */ + if (cell) { + /* Cell available. Check if it passed the critical checks */ + if (!(error_level & LIB_CELL_RENDERER_ERROR_ERR)) + ret = TRUE; + } + + return ret; } /** From 586339cac1cf1c766eabec26f72e35099cd2fd84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Tue, 5 Mar 2019 21:46:29 +0100 Subject: [PATCH 10/25] fix doxygen --- doxygen/trigonometric.dox | 6 +++--- external-renderer.h | 3 ++- tree-renderer/tree-store.h | 4 ++-- trigonometric/bounding-box.c | 9 +++++---- trigonometric/cell-trigonometrics.c | 6 +++--- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/doxygen/trigonometric.dox b/doxygen/trigonometric.dox index 52819eb..e4a026e 100644 --- a/doxygen/trigonometric.dox +++ b/doxygen/trigonometric.dox @@ -2,7 +2,7 @@ /** * @defgroup trigonometric Trigonometric Helper Functions - * @description The trigonometric helper function will be used in future releases to pcalculate bounding boxes - * @note Currently not in use! - * @warning Code is incomplete. DO NOT USE! + * + * The trigonometric helper function are used to calculate bounding boxes + * @warning Code is incomplete. Please double check forfunctionality! */ diff --git a/external-renderer.h b/external-renderer.h index ecb056b..841b219 100644 --- a/external-renderer.h +++ b/external-renderer.h @@ -36,7 +36,8 @@ /** * @brief function name expected to be found in external library. - * @detail The function has to be defined as follows: + * + * The function has to be defined as follows: * @code * int function_name(gds_cell *toplevel, GList *layer_info_list, char *output_file_name) * @endcode diff --git a/tree-renderer/tree-store.h b/tree-renderer/tree-store.h index aa6d283..85b0f83 100644 --- a/tree-renderer/tree-store.h +++ b/tree-renderer/tree-store.h @@ -37,10 +37,10 @@ enum cell_store_columns { CELL_SEL_LIBRARY = 0, CELL_SEL_CELL, - CELL_SEL_CELL_COLOR, /**< Cell column color */ + CELL_SEL_CELL_COLOR, /**< @brief Cell column color */ CELL_SEL_MODDATE, CELL_SEL_ACCESSDATE, - CELL_SEL_COLUMN_COUNT /**< Not a column. Used to determine count of coumns **/ + CELL_SEL_COLUMN_COUNT /**< @brief Not a column. Used to determine count of columns */ }; struct tree_stores { diff --git a/trigonometric/bounding-box.c b/trigonometric/bounding-box.c index 9d3b26d..c30541d 100644 --- a/trigonometric/bounding-box.c +++ b/trigonometric/bounding-box.c @@ -180,10 +180,11 @@ void bounding_box_update_point(union bounding_box *destination, conv_generic_to_ } /** - * @brief bounding_box_apply_transform - * @param scale scaling factor - * @param rotation roation of bounding box around the origin in degrees (counterclockwise) - * @param box bounding box the operations should be applied to + * @brief Apply transformations onto bounding box. + * @param scale Scaling factor + * @param rotation_deg Roation of bounding box around the origin in degrees (counterclockwise) + * @param flip_at_x Flip the boundig box on the x axis before rotating. + * @param box Bounding box the operations should be applied to. */ void bounding_box_apply_transform(double scale, double rotation_deg, bool flip_at_x, union bounding_box *box) { diff --git a/trigonometric/cell-trigonometrics.c b/trigonometric/cell-trigonometrics.c index 823a531..d6bc4da 100644 --- a/trigonometric/cell-trigonometrics.c +++ b/trigonometric/cell-trigonometrics.c @@ -38,9 +38,9 @@ static void convert_gds_point_to_2d_vector(struct gds_point *pt, struct vector_2 } /** - * @brief update_box_with_gfx - * @param box - * @param gfx_list + * @brief Update the given bounding box with the bounding box of a graphics element. + * @param box box to update + * @param gfx Graphics element */ static void update_box_with_gfx(union bounding_box *box, struct gds_graphics *gfx) { From 5291b682c7b12123108cd8b1e6b27166e0c653de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 6 Mar 2019 17:38:47 +0100 Subject: [PATCH 11/25] remove braces around scale to prevent doxygen from interpreting this as HTML tag --- doxygen/usage.dox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doxygen/usage.dox b/doxygen/usage.dox index b46fb87..254ee82 100644 --- a/doxygen/usage.dox +++ b/doxygen/usage.dox @@ -6,7 +6,7 @@ To use the application on the command line check 'gds-render --help'. Application Options: - -t, --tikz Output TikZ code - -p, --pdf Output PDF document -- -s, --scale= Divide output coordinates by +- -s, --scale=SCALE Divide output coordinates by SCALE - -o, --tex-output=PATH Optional path for TeX file - -O, --pdf-output=PATH Optional path for PDF file - -m, --mapping=PATH Path for Layer Mapping File From 34c113517b8a33a9ebea0417aa85141e039e1ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 6 Mar 2019 18:14:53 +0100 Subject: [PATCH 12/25] Fox doxygen file header --- widgets/conv-settings-dialog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widgets/conv-settings-dialog.c b/widgets/conv-settings-dialog.c index 7460dfb..45e3386 100644 --- a/widgets/conv-settings-dialog.c +++ b/widgets/conv-settings-dialog.c @@ -18,7 +18,7 @@ */ /** - * @file conv-settings-dilaog.c + * @file conv-settings-dialog.c * @brief Implementation of the setting dialog * @author Mario Hüttel */ From fdf2c9a42b710d710b82930a3278590decd4e6b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 6 Mar 2019 18:15:11 +0100 Subject: [PATCH 13/25] fix style issue --- main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.c b/main.c index 1eea1f7..ec49256 100644 --- a/main.c +++ b/main.c @@ -133,7 +133,7 @@ int main(int argc, char **argv) {"tex-layers", 'l', 0, G_OPTION_ARG_NONE, &pdf_layers, "Create PDF Layers (OCG)", NULL }, {"custom-render-lib", 'P', 0, G_OPTION_ARG_FILENAME, &custom_library_path, "Path to a custom shared object, that implements the " EXTERNAL_LIBRARY_FUNCTION " function", "PATH"}, {"external-lib-output", 'e', 0, G_OPTION_ARG_FILENAME, &custom_library_file_name, "Output path for external render library", "PATH"}, - { NULL } + {NULL} }; context = g_option_context_new(" FILE - Convert GDS file to graphic"); From ba53a1151e9b81f9e50d2e3d3e662464cc732ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 6 Mar 2019 18:15:50 +0100 Subject: [PATCH 14/25] Add cell recursion cehck to command line interface --- command-line.c | 56 +++++++++++++++++++++++++++-------- gds-parser/gds-tree-checker.c | 25 +++++++++++++++- 2 files changed, 68 insertions(+), 13 deletions(-) diff --git a/command-line.c b/command-line.c index 8f2d97d..e163d64 100644 --- a/command-line.c +++ b/command-line.c @@ -35,6 +35,7 @@ #include "cairo-output/cairo-output.h" #include "latex-output/latex-output.h" #include "external-renderer.h" +#include "gds-parser/gds-tree-checker.h" /** * @brief Delete layer_info and free nem element. @@ -69,8 +70,10 @@ void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gb GList *layer_info_list = NULL; GList *cell_list; struct layer_info *linfo_temp; + struct gds_library *first_lib; struct gds_cell *toplevel_cell = NULL, *temp_cell; + /* Check if parameters are valid */ if (!gds_name || (!pdf_name && pdf) || (!tex_name && tex) || !layer_file || !cell_name) { printf("Probably missing argument. Check --help option\n"); @@ -81,14 +84,14 @@ void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gb clear_lib_list(&libs); res = parse_gds_from_file(gds_name, &libs); if (res) - return; + goto ret_destroy_library_list; file = g_file_new_for_path(layer_file); stream = g_file_read(file, NULL, NULL); if (!stream) { printf("Layer mapping not readable!\n"); - goto destroy_file; + goto ret_destroy_file; } dstream = g_data_input_stream_new(G_INPUT_STREAM(stream)); i = 0; @@ -100,7 +103,7 @@ void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gb linfo_temp = (struct layer_info *)malloc(sizeof(struct layer_info)); if (!linfo_temp) { printf("Out of memory\n"); - goto ret_clear_list; + goto ret_clear_layer_list; } linfo_temp->color.alpha = layer_color.alpha; linfo_temp->color.red = layer_color.red; @@ -116,9 +119,15 @@ void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gb /* find_cell in first library. */ if (!libs) - goto ret_clear_list; + goto ret_clear_layer_list; - for (cell_list = ((struct gds_library *)libs->data)->cells; cell_list != NULL; cell_list = g_list_next(cell_list)) { + first_lib = (struct gds_library *)libs->data; + if (!first_lib) { + fprintf(stderr, "No library in library list. This should not happen.\n"); + goto ret_clear_layer_list; + } + + for (cell_list = first_lib->cells; cell_list != NULL; cell_list = g_list_next(cell_list)) { temp_cell = (struct gds_cell *)cell_list->data; if (!strcmp(temp_cell->name, cell_name)) { toplevel_cell = temp_cell; @@ -128,9 +137,31 @@ void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gb if (!toplevel_cell) { printf("Couldn't find cell in first library!\n"); - goto ret_clear_list; + goto ret_clear_layer_list; } + /* Check if cell passes vital checks */ + res = gds_tree_check_reference_loops(toplevel_cell->parent_library); + if (res < 0) { + fprintf(stderr, "Checking library %s failed.\n", first_lib->name); + goto ret_clear_layer_list; + } else if (res > 0) { + fprintf(stderr, "%d reference loops found.\n", res); + + /* do further checking if the specified cell and/or its subcells are affected */ + if (toplevel_cell->checks.affected_by_reference_loop == 1) { + fprintf(stderr, "Cell is affected by reference loop. Abort!\n"); + goto ret_clear_layer_list; + } + } + + if (toplevel_cell->checks.affected_by_reference_loop == GDS_CELL_CHECK_NOT_RUN) + fprintf(stderr, "Cell was not checked. This should not happen. Please report this issue. Will continue either way.\n"); + + /* Note: unresolved references are not an abort condition. + * Deal with it. + */ + /* Render outputs */ if (pdf == TRUE || svg == TRUE) { cairo_render_cell_to_vector_file(toplevel_cell, layer_info_list, (pdf == TRUE ? pdf_name : NULL), @@ -140,14 +171,14 @@ void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gb if (tex == TRUE) { tex_file = fopen(tex_name, "w"); if (!tex_file) - goto ret_clear_list; + goto ret_clear_layer_list; latex_render_cell_to_code(toplevel_cell, layer_info_list, tex_file, scale, pdf_layers, pdf_standalone); fclose(tex_file); } if (so_name && so_out_file) { if (strlen(so_name) == 0 || strlen(so_out_file) == 0) - goto ret_clear_list; + goto ret_clear_layer_list; /* Render output using external renderer */ printf("Invoking external renderer!\n"); @@ -155,15 +186,16 @@ void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gb printf("External renderer finished!\n"); } -ret_clear_list: +ret_clear_layer_list: g_list_free_full(layer_info_list, (GDestroyNotify)delete_layer_info_with_name); g_object_unref(dstream); g_object_unref(stream); -destroy_file: +ret_destroy_file: g_object_unref(file); - - + /* Delete all allocated libraries */ +ret_destroy_library_list: + clear_lib_list(&libs); } /** @} */ diff --git a/gds-parser/gds-tree-checker.c b/gds-parser/gds-tree-checker.c index e848219..426ff3b 100644 --- a/gds-parser/gds-tree-checker.c +++ b/gds-parser/gds-tree-checker.c @@ -65,7 +65,7 @@ int gds_tree_check_cell_references(struct gds_library *lib) instance_iter = g_list_next(instance_iter)) { cell_inst = (struct gds_cell_instance *)instance_iter->data; - /* Check if broken. This should also not happen */ + /* Check if broken. This should not happen */ if (!cell_inst) { fprintf(stderr, "Broken cell list item found in cell %s. Will continue.\n", cell->name); @@ -83,6 +83,29 @@ int gds_tree_check_cell_references(struct gds_library *lib) return total_unresolved_count; } +/** + * @brief This function sets the marker element in the check structure of each cell to zero. + * @param lib Library to work with + * @return 0 if successful; negative if a fault (null pointer, ...) occured. + */ +static int gds_tree_check_clear_cell_check_marker(struct gds_library *lib) +{ + GList *cell_iter; + struct gds_cell *cell; + + if (!lib) + return -1; + + for (cell_iter = lib->cells; cell_iter != NULL; cell_iter = g_list_next(cell_iter)) { + cell = (struct gds_cell *)cell_iter->data; + + if (!cell) + return -2; + + cell->checks._internal.marker = 0; + } +} + int gds_tree_check_reference_loops(struct gds_library *lib) { return 0; From d81c6d1037278f78653874875a9a9e49d2f1ac2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 6 Mar 2019 18:16:14 +0100 Subject: [PATCH 15/25] Make gds-parser more robust --- gds-parser/gds-parser.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/gds-parser/gds-parser.c b/gds-parser/gds-parser.c index 1cba95f..241f87f 100644 --- a/gds-parser/gds-parser.c +++ b/gds-parser/gds-parser.c @@ -894,7 +894,8 @@ int parse_gds_from_file(const char *filename, GList **library_list) */ static void delete_cell_inst_element(struct gds_cell_instance *cell_inst) { - free(cell_inst); + if (cell_inst) + free(cell_inst); } /** @@ -903,7 +904,8 @@ static void delete_cell_inst_element(struct gds_cell_instance *cell_inst) */ static void delete_vertex(struct gds_point *vertex) { - free(vertex); + if (vertex) + free(vertex); } /** @@ -912,6 +914,9 @@ static void delete_vertex(struct gds_point *vertex) */ static void delete_graphics_obj(struct gds_graphics *gfx) { + if (!gfx) + return; + g_list_free_full(gfx->vertices, (GDestroyNotify)delete_vertex); free(gfx); } @@ -922,6 +927,9 @@ static void delete_graphics_obj(struct gds_graphics *gfx) */ static void delete_cell_element(struct gds_cell *cell) { + if (!cell) + return; + g_list_free_full(cell->child_cells, (GDestroyNotify)delete_cell_inst_element); g_list_free_full(cell->graphic_objs, (GDestroyNotify)delete_graphics_obj); free(cell); @@ -933,6 +941,9 @@ static void delete_cell_element(struct gds_cell *cell) */ static void delete_library_element(struct gds_library *lib) { + if (!lib) + return; + g_list_free(lib->cell_names); g_list_free_full(lib->cells, (GDestroyNotify)delete_cell_element); free(lib); @@ -940,8 +951,12 @@ static void delete_library_element(struct gds_library *lib) int clear_lib_list(GList **library_list) { + if (!library_list) + return 0; + if (*library_list == NULL) return 0; + g_list_free_full(*library_list, (GDestroyNotify)delete_library_element); *library_list = NULL; return 0; From 59835018aff5f6e937f9c46fa5be1cf8d38ac42d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 6 Mar 2019 19:58:26 +0100 Subject: [PATCH 16/25] Edit colors --- tree-renderer/lib-cell-renderer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tree-renderer/lib-cell-renderer.c b/tree-renderer/lib-cell-renderer.c index c5fe6c9..99e96e5 100644 --- a/tree-renderer/lib-cell-renderer.c +++ b/tree-renderer/lib-cell-renderer.c @@ -52,9 +52,9 @@ static void convert_error_level_to_color(GdkRGBA *color, unsigned int error_leve color->green = 0.0; } else if (error_level & LIB_CELL_RENDERER_ERROR_WARN) { /* Only warning set; orange color */ - color->red = 0.6; + color->red = 1.0; color->blue = 0.0; - color->green = 0.4; + color->green = 0.6; } else { /* Everything okay; green color */ color->red = (double)61.0/(double)255.0; From 43fdab45330d684e25fb2951009d91832b5c9668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 6 Mar 2019 20:04:49 +0100 Subject: [PATCH 17/25] Improve GDS parser --- gds-parser/gds-parser.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/gds-parser/gds-parser.c b/gds-parser/gds-parser.c index 241f87f..185c6b4 100644 --- a/gds-parser/gds-parser.c +++ b/gds-parser/gds-parser.c @@ -662,7 +662,7 @@ int parse_gds_from_file(const char *filename, GList **library_list) break; case SREF: if (current_cell == NULL) { - GDS_ERROR("Path outside of cell"); + GDS_ERROR("Cell Reference outside of cell"); run = -3; break; } @@ -810,7 +810,11 @@ int parse_gds_from_file(const char *filename, GList **library_list) break; case SNAME: - name_cell_ref(current_s_reference, read, workbuff); + if (current_s_reference) { + name_cell_ref(current_s_reference, (unsigned int)read, workbuff); + } else { + GDS_ERROR("reference name set outside of cell reference.\n"); + } break; case WIDTH: if (!current_graphics) { @@ -863,7 +867,7 @@ int parse_gds_from_file(const char *filename, GList **library_list) break; } if (current_graphics->gfx_type == GRAPHIC_PATH) { - current_graphics->path_render_type = (int)gds_convert_signed_int16(workbuff); + current_graphics->path_render_type = (enum path_type)gds_convert_signed_int16(workbuff); GDS_INF("\t\tPathtype: %d\n", current_graphics->path_render_type); } else { GDS_WARN("Path type defined inside non-path graphics object. Ignoring"); From 3146ca801f7da46c31435deeedc49e305209136f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 6 Mar 2019 20:05:48 +0100 Subject: [PATCH 18/25] Add functions for checking cell reference loops --- gds-parser/gds-tree-checker.c | 112 ++++++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 13 deletions(-) diff --git a/gds-parser/gds-tree-checker.c b/gds-parser/gds-tree-checker.c index 426ff3b..3d067fb 100644 --- a/gds-parser/gds-tree-checker.c +++ b/gds-parser/gds-tree-checker.c @@ -84,31 +84,117 @@ int gds_tree_check_cell_references(struct gds_library *lib) } /** - * @brief This function sets the marker element in the check structure of each cell to zero. - * @param lib Library to work with - * @return 0 if successful; negative if a fault (null pointer, ...) occured. + * @brief Check if list contains a cell + * @param list GList to check. May be a null pointer + * @param cell Cell to check for + * @return 0 if cell is not in list. 1 if cell is in list */ -static int gds_tree_check_clear_cell_check_marker(struct gds_library *lib) +static int gds_tree_check_list_contains_cell(GList *list, struct gds_cell *cell) { + GList *iter; + + for (iter = list; iter != NULL; iter = g_list_next(iter)) { + if ((struct gds_cell *)iter->data == cell) + return 1; + } + + return 0; +} + +/** + * @brief This function follows down the reference list of a cell and marks each visited subcell and detects loops + * @param cell_to_check The cell to check for reference loops + * @param visited_cells Pointer to list head. May be zero. + * @return 0 if no loops exist; error in processing: <0; loop found: >0 + */ +static int gds_tree_check_iterate_ref_and_check(struct gds_cell *cell_to_check, GList **visited_cells) { + GList *ref_iter; + struct gds_cell_instance *ref; + struct gds_cell *sub_cell; + int res; + + if (!cell_to_check) + return -1; + + /* Check if this cell is already contained in visited cells. This indicates a loop */ + if (gds_tree_check_list_contains_cell(*visited_cells, cell_to_check)) + return 1; + + /* Add cell to visited cell list */ + *visited_cells = g_list_append(*visited_cells, (gpointer)cell_to_check); + + /* Mark references and process sub cells */ + for (ref_iter = cell_to_check->child_cells; ref_iter != NULL; ref_iter = g_list_next(ref_iter)) { + ref = (struct gds_cell_instance *)ref_iter->data; + + if (!ref) + return -1; + + sub_cell = ref->cell_ref; + + /* If cell is not resolved, ignore. No harm there */ + if (!sub_cell) + continue; + + res = gds_tree_check_iterate_ref_and_check(sub_cell, visited_cells); + if (res < 0) { + /* Error. return. */ + return -3; + } else if (res > 0) { + /* Loop in subcell found. Propagate to top */ + return 1; + } + } + + /* Remove cell from visted cells */ + *visited_cells = g_list_remove(*visited_cells, cell_to_check); + + /* No error found in this chain */ + return 0; +} + +int gds_tree_check_reference_loops(struct gds_library *lib) +{ + int res; + int loop_count = 0; GList *cell_iter; - struct gds_cell *cell; + struct gds_cell *cell_to_check; + GList *visited_cells = NULL; + if (!lib) return -1; for (cell_iter = lib->cells; cell_iter != NULL; cell_iter = g_list_next(cell_iter)) { - cell = (struct gds_cell *)cell_iter->data; + cell_to_check = (struct gds_cell *)cell_iter->data; - if (!cell) + /* A broken cell reference will be counted fatal in this case */ + if (!cell_to_check) return -2; - cell->checks._internal.marker = 0; - } -} + /* iterate through references and check if loop exists */ + res = gds_tree_check_iterate_ref_and_check(cell_to_check, &visited_cells); -int gds_tree_check_reference_loops(struct gds_library *lib) -{ - return 0; + if (res < 0) { + /* Error */ + return res; + } else if (res > 0) { + /* Loop found: increment loop count and flag cell */ + cell_to_check->checks.affected_by_reference_loop = 1; + loop_count++; + } else if (res == 0) { + /* No error found for this cell */ + cell_to_check->checks.affected_by_reference_loop = 0; + } + + } + + if (visited_cells) { + fprintf(stderr, "Visited cell list should be empty. This is a bug. Please report this.\n"); + g_list_free(visited_cells); + } + + return loop_count; } /** @} */ From eeae61ad473b38207300e6d0b81cf6840f5b86ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 6 Mar 2019 20:07:26 +0100 Subject: [PATCH 19/25] Check cells before displaying them and color the cells accordingly. Fixes #4 --- main-window.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/main-window.c b/main-window.c index b4cf106..c0cecf8 100644 --- a/main-window.c +++ b/main-window.c @@ -38,6 +38,7 @@ #include "cairo-output/cairo-output.h" #include "trigonometric/cell-trigonometrics.h" #include "tree-renderer/lib-cell-renderer.h" +#include "gds-parser/gds-tree-checker.h" /** * @brief User data supplied to callback function of the open button @@ -115,6 +116,7 @@ static void on_load_gds(gpointer button, gpointer user) char *filename; GString *mod_date; GString *acc_date; + unsigned int cell_error_level; open_dialog = gtk_file_chooser_dialog_new("Open GDSII File", ptr->main_window, GTK_FILE_CHOOSER_ACTION_OPEN, "Cancel", GTK_RESPONSE_CANCEL, "Open GDSII", GTK_RESPONSE_ACCEPT, NULL); @@ -162,6 +164,11 @@ static void on_load_gds(gpointer button, gpointer user) CELL_SEL_ACCESSDATE, acc_date->str, -1); + /* Check this library. This might take a while */ + + (void)gds_tree_check_cell_references(gds_lib); + (void)gds_tree_check_reference_loops(gds_lib); + /* Delete GStrings including string data. */ /* Cell store copies String type data items */ g_string_free(mod_date, TRUE); @@ -175,16 +182,21 @@ static void on_load_gds(gpointer button, gpointer user) mod_date = generate_string_from_date(&gds_c->mod_time); acc_date = generate_string_from_date(&gds_c->access_time); - /* Add cell to tree store model - * CELL_SEL_CELL_COLOR will always be green, - * because no cell cehcker is implemented, yet. - */ + /* Get the checking results for this cell */ + cell_error_level = 0; + if (gds_c->checks.unresolved_child_count) + cell_error_level |= LIB_CELL_RENDERER_ERROR_WARN; + + /* Check if it is completely b0rken */ + if (gds_c->checks.affected_by_reference_loop) + cell_error_level |= LIB_CELL_RENDERER_ERROR_ERR; + + /* Add cell to tree store model */ gtk_tree_store_set (store, &celliter, CELL_SEL_CELL, gds_c, CELL_SEL_MODDATE, mod_date->str, CELL_SEL_ACCESSDATE, acc_date->str, - CELL_SEL_CELL_ERROR_STATE, 0, // TODO: implement cell checker - -1); + CELL_SEL_CELL_ERROR_STATE, cell_error_level, -1); /* Delete GStrings including string data. */ /* Cell store copies String type data items */ From 187ae2a74b0296d47cbf6cac8119715957a0d9c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Thu, 7 Mar 2019 20:00:54 +0100 Subject: [PATCH 20/25] Add style checker as submodule --- .gitmodules | 3 +++ c-style-checker | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 c-style-checker diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..9358432 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "c-style-checker"] + path = c-style-checker + url = https://git.shimatta.de/mhu/c-style-checker diff --git a/c-style-checker b/c-style-checker new file mode 160000 index 0000000..9238b87 --- /dev/null +++ b/c-style-checker @@ -0,0 +1 @@ +Subproject commit 9238b877ef0c1e659c1bc4cc4a7c198cfa0696dc From d1e6e7b05aba4a52e9cc640c54fed53bee5a9356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Thu, 7 Mar 2019 20:14:44 +0100 Subject: [PATCH 21/25] fix style issues in main.c --- main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main.c b/main.c index ec49256..c6edf45 100644 --- a/main.c +++ b/main.c @@ -31,7 +31,7 @@ struct application_data { static void app_quit(GSimpleAction *action, GVariant *parameter, gpointer user_data) { - struct application_data *appdata = (struct application_data *)user_data; + const struct application_data * const appdata = (const struct application_data *)user_data; (void)action; (void)parameter; @@ -42,7 +42,7 @@ static void app_about(GSimpleAction *action, GVariant *parameter, gpointer user_ { GtkBuilder *builder; GtkDialog *dialog; - struct application_data *appdata = (struct application_data *)user_data; + const struct application_data * const appdata = (const struct application_data *)user_data; (void)action; (void)parameter; @@ -63,7 +63,7 @@ const static GActionEntry app_actions[] = { static void gapp_activate(GApplication *app, gpointer user_data) { GtkWindow *main_window; - struct application_data *appdata = (struct application_data *)user_data; + struct application_data * const appdata = (struct application_data *)user_data; main_window = create_main_window(); appdata->main_window = main_window; From 6e1b7d3f618056f662064967351528a15f0af49f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Thu, 7 Mar 2019 20:26:03 +0100 Subject: [PATCH 22/25] Update style checker to new version --- c-style-checker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c-style-checker b/c-style-checker index 9238b87..3a58e3d 160000 --- a/c-style-checker +++ b/c-style-checker @@ -1 +1 @@ -Subproject commit 9238b877ef0c1e659c1bc4cc4a7c198cfa0696dc +Subproject commit 3a58e3dd1c2ef6de78df89c8fdc7ba96b51cd4e0 From b4ae8eee375de52d6c26d1a86e3e60e8ec83346a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Thu, 7 Mar 2019 20:32:55 +0100 Subject: [PATCH 23/25] fix style issues in main-window.c --- main-window.c | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/main-window.c b/main-window.c index c0cecf8..c7f3a65 100644 --- a/main-window.c +++ b/main-window.c @@ -118,8 +118,11 @@ static void on_load_gds(gpointer button, gpointer user) GString *acc_date; unsigned int cell_error_level; - open_dialog = gtk_file_chooser_dialog_new("Open GDSII File", ptr->main_window, GTK_FILE_CHOOSER_ACTION_OPEN, - "Cancel", GTK_RESPONSE_CANCEL, "Open GDSII", GTK_RESPONSE_ACCEPT, NULL); + open_dialog = gtk_file_chooser_dialog_new("Open GDSII File", ptr->main_window, + GTK_FILE_CHOOSER_ACTION_OPEN, + "Cancel", GTK_RESPONSE_CANCEL, + "Open GDSII", GTK_RESPONSE_ACCEPT, + NULL); file_chooser = GTK_FILE_CHOOSER(open_dialog); /* Add GDS II Filter */ filter = gtk_file_filter_new(); @@ -152,17 +155,17 @@ static void on_load_gds(gpointer button, gpointer user) for (lib = *(ptr->list_ptr); lib != NULL; lib = lib->next) { gds_lib = (struct gds_library *)lib->data; /* Create top level iter */ - gtk_tree_store_append (store, &libiter, NULL); + gtk_tree_store_append(store, &libiter, NULL); /* Convert dates to String */ mod_date = generate_string_from_date(&gds_lib->mod_time); acc_date = generate_string_from_date(&gds_lib->access_time); - gtk_tree_store_set (store, &libiter, - CELL_SEL_LIBRARY, gds_lib, - CELL_SEL_MODDATE, mod_date->str, - CELL_SEL_ACCESSDATE, acc_date->str, - -1); + gtk_tree_store_set(store, &libiter, + CELL_SEL_LIBRARY, gds_lib, + CELL_SEL_MODDATE, mod_date->str, + CELL_SEL_ACCESSDATE, acc_date->str, + -1); /* Check this library. This might take a while */ @@ -176,7 +179,7 @@ static void on_load_gds(gpointer button, gpointer user) for (cell = gds_lib->cells; cell != NULL; cell = cell->next) { gds_c = (struct gds_cell *)cell->data; - gtk_tree_store_append (store, &celliter, &libiter); + gtk_tree_store_append(store, &celliter, &libiter); /* Convert dates to String */ mod_date = generate_string_from_date(&gds_c->mod_time); @@ -192,11 +195,12 @@ static void on_load_gds(gpointer button, gpointer user) cell_error_level |= LIB_CELL_RENDERER_ERROR_ERR; /* Add cell to tree store model */ - gtk_tree_store_set (store, &celliter, - CELL_SEL_CELL, gds_c, - CELL_SEL_MODDATE, mod_date->str, - CELL_SEL_ACCESSDATE, acc_date->str, - CELL_SEL_CELL_ERROR_STATE, cell_error_level, -1); + gtk_tree_store_set(store, &celliter, + CELL_SEL_CELL, gds_c, + CELL_SEL_MODDATE, mod_date->str, + CELL_SEL_ACCESSDATE, acc_date->str, + CELL_SEL_CELL_ERROR_STATE, cell_error_level, + -1); /* Delete GStrings including string data. */ /* Cell store copies String type data items */ @@ -318,8 +322,12 @@ static void on_convert_clicked(gpointer button, gpointer user) case RENDERER_CAIROGRAPHICS_SVG: case RENDERER_CAIROGRAPHICS_PDF: cairo_render_cell_to_vector_file(cell_to_render, layer_list, - (sett.renderer == RENDERER_CAIROGRAPHICS_PDF ? file_name : NULL), - (sett.renderer == RENDERER_CAIROGRAPHICS_SVG ? file_name : NULL), + (sett.renderer == RENDERER_CAIROGRAPHICS_PDF + ? file_name + : NULL), + (sett.renderer == RENDERER_CAIROGRAPHICS_SVG + ? file_name + : NULL), sett.scale); break; } @@ -406,7 +414,7 @@ GtkWindow *create_main_window() g_object_unref(main_builder); - return (conv_data.main_window); + return conv_data.main_window; } /** @} */ From 34a19fa11d30a82961a4137dc43a469aec0545bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Thu, 7 Mar 2019 20:35:23 +0100 Subject: [PATCH 24/25] Fix style in external renderer --- external-renderer.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/external-renderer.c b/external-renderer.c index 8b7dd90..5474b16 100644 --- a/external-renderer.c +++ b/external-renderer.c @@ -32,7 +32,8 @@ #include #include -int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *layer_info_list, char *output_file, char *so_path) +int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *layer_info_list, + char *output_file, char *so_path) { int (*so_render_func)(struct gds_cell *, GList *, char *) = NULL; void *so_handle = NULL; @@ -40,9 +41,8 @@ int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *layer_i int ret = 0; /* Check parameter sanity */ - if (!output_file || !so_path || !toplevel_cell || !layer_info_list) { + if (!output_file || !so_path || !toplevel_cell || !layer_info_list) return -3000; - } /* Load shared object */ so_handle = dlopen(so_path, RTLD_LAZY); @@ -53,7 +53,8 @@ int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *layer_i /* Load symbol from library */ so_render_func = (int (*)(struct gds_cell *, GList *, char *))dlsym(so_handle, EXTERNAL_LIBRARY_FUNCTION); - if ((error_msg = dlerror()) != NULL) { + error_msg = dlerror(); + if (error_msg != NULL) { printf("Rendering function not found in library:\n%s\n", error_msg); goto ret_close_so_handle; } From bbf08a4d6e44768d831f8a07f5a985323731f54b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Fri, 8 Mar 2019 20:46:48 +0100 Subject: [PATCH 25/25] style fix, convert dialog size preview in SI units --- main-window.c | 12 ++++--- widgets/conv-settings-dialog.c | 58 +++++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/main-window.c b/main-window.c index c7f3a65..65b1e92 100644 --- a/main-window.c +++ b/main-window.c @@ -168,7 +168,6 @@ static void on_load_gds(gpointer button, gpointer user) -1); /* Check this library. This might take a while */ - (void)gds_tree_check_cell_references(gds_lib); (void)gds_tree_check_reference_loops(gds_lib); @@ -242,7 +241,7 @@ static void on_convert_clicked(gpointer button, gpointer user) gint res; char *file_name; union bounding_box cell_box; - double height, width; + unsigned int height, width; /* Get selected cell */ selection = gtk_tree_view_get_selection(data->tree_view); @@ -261,9 +260,12 @@ static void on_convert_clicked(gpointer button, gpointer user) bounding_box_prepare_empty(&cell_box); calculate_cell_bounding_box(&cell_box, cell_to_render); - /* Calculate size in meters database units */ - height = (cell_box.vectors.upper_right.y - cell_box.vectors.lower_left.y); - width = (cell_box.vectors.upper_right.x - cell_box.vectors.lower_left.x); + /* Calculate size in database units + * Note that the results are bound to be positive, + * so casting them to unsigned int is asbsolutely valid + */ + height = (unsigned int)(cell_box.vectors.upper_right.y - cell_box.vectors.lower_left.y); + width = (unsigned int)(cell_box.vectors.upper_right.x - cell_box.vectors.lower_left.x); /* Show settings dialog */ settings = renderer_settings_dialog_new(GTK_WINDOW(data->main_window)); diff --git a/widgets/conv-settings-dialog.c b/widgets/conv-settings-dialog.c index 45e3386..d4444d7 100644 --- a/widgets/conv-settings-dialog.c +++ b/widgets/conv-settings-dialog.c @@ -127,24 +127,73 @@ static gboolean shape_drawer_drawing_callback(GtkWidget *widget, cairo_t *cr, gp return FALSE; } +static double convert_number_to_engineering(double input, const char **out_prefix) +{ + const char *selected_prefix = NULL; + double return_val = 0.0; + int idx; + const static char * prefixes[] = {"y", "z", "a", "f", "p", "n", "u", "m", "c", "d", /* < 1 */ + "", /* 1 */ + "h", "k", "M", "G", "T", "P", "E", "Z", "Y"}; /* > 1 */ + const static double scale[] = {1E-24, 1E-21, 1E-18, 1E-15, 1E-12, 1E-9, 1E-6, 1E-3, 1E-2, 1E-1, + 1, + 1E2, 1E3, 1E6, 1E9, 1E12, 1E15, 1E18, 1E21, 1E24}; + const int prefix_count = (int)(sizeof(prefixes)/sizeof(char *)); + + for (idx = 1; idx < prefix_count; idx++) { + if (input < scale[idx]) { + /* This prefix is bigger than the number. Take the previous one */ + selected_prefix = prefixes[idx-1]; + return_val = input / scale[idx-1]; + break; + } + } + + /* Check if prefix was set by loop. Else take the largest in the list */ + if (selected_prefix == NULL) { + selected_prefix = prefixes[prefix_count-1]; + return_val = input / scale[prefix_count-1]; + } + + if (out_prefix) + *out_prefix = selected_prefix; + + return return_val; +} + static void renderer_settings_dialog_update_labels(RendererSettingsDialog *self) { char default_buff[100]; double scale; + double width_meters; + double height_meters; + double width_engineering; + const char *width_prefix; + double height_engineering; + const char *height_prefix; if (!self) return; - snprintf(default_buff, sizeof(default_buff), "Width: %E", self->cell_width * self->unit_in_meters); + width_meters = (double)self->cell_width * self->unit_in_meters; + height_meters = (double)self->cell_height * self->unit_in_meters; + + width_engineering = convert_number_to_engineering(width_meters, &width_prefix); + height_engineering = convert_number_to_engineering(height_meters, &height_prefix); + + snprintf(default_buff, sizeof(default_buff), "Width: %.3lf %sm", width_engineering, width_prefix); gtk_label_set_text(self->x_label, default_buff); - snprintf(default_buff, sizeof(default_buff), "Height: %E", self->cell_height * self->unit_in_meters); + snprintf(default_buff, sizeof(default_buff), "Height: %.3lf %sm", height_engineering, height_prefix); gtk_label_set_text(self->y_label, default_buff); scale = gtk_range_get_value(GTK_RANGE(self->scale)); - snprintf(default_buff, sizeof(default_buff), "Output Width: %u px", (unsigned int)((double)self->cell_width / scale)); + /* Set the pixel sizes */ + snprintf(default_buff, sizeof(default_buff), "Output Width: %u px", + (unsigned int)((double)self->cell_width / scale)); gtk_label_set_text(self->x_output_label, default_buff); - snprintf(default_buff, sizeof(default_buff), "Output Height: %u px", (unsigned int)((double)self->cell_height / scale)); + snprintf(default_buff, sizeof(default_buff), "Output Height: %u px", + (unsigned int)((double)self->cell_height / scale)); gtk_label_set_text(self->y_output_label, default_buff); } @@ -265,7 +314,6 @@ void renderer_settings_dialog_set_cell_width(RendererSettingsDialog *dialog, uns if (width == 0) width = 1; - dialog->cell_width = width; renderer_settings_dialog_update_labels(dialog); }