summaryrefslogtreecommitdiff
path: root/delete.c
diff options
context:
space:
mode:
authorXiangfu Liu <xiangfu@openmobilefree.net>2012-10-08 05:38:57 +0200
committerXiangfu Liu <xiangfu@openmobilefree.net>2012-10-08 05:38:57 +0200
commit4edcd19776f36123e6bcb7581b6863af719da84b (patch)
tree7d11bc6c0272a4a9c3499d544f36e00ab6474a28 /delete.c
Import fped_0.1+201210.orig.tar.gz
[dgit import orig fped_0.1+201210.orig.tar.gz]
Diffstat (limited to 'delete.c')
-rw-r--r--delete.c705
1 files changed, 705 insertions, 0 deletions
diff --git a/delete.c b/delete.c
new file mode 100644
index 0000000..7128f9e
--- /dev/null
+++ b/delete.c
@@ -0,0 +1,705 @@
+/*
+ * delete.c - Object deletion
+ *
+ * Written 2009, 2010, 2012 by Werner Almesberger
+ * Copyright 2009, 2010, 2012 by Werner Almesberger
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "util.h"
+#include "error.h"
+#include "expr.h"
+#include "obj.h"
+#include "delete.h"
+
+
+static struct deletion {
+ enum del_type {
+ dt_vec,
+ dt_obj,
+ dt_frame,
+ dt_table,
+ dt_row,
+ dt_column,
+ dt_loop,
+ } type;
+ union {
+ struct {
+ struct frame *ref;
+ struct frame *prev;
+ } frame;
+ struct {
+ struct vec *ref;
+ struct vec *prev;
+ } vec;
+ struct {
+ struct obj *ref;
+ struct obj *prev;
+ } obj;
+ struct {
+ struct table *ref;
+ struct table *prev;
+ } table;
+ struct {
+ struct row *ref;
+ struct row *prev;
+ } row;
+ struct column {
+ struct var *var;
+ struct value *values;
+ struct table *table;
+ int n;
+ } col;
+ struct {
+ struct loop *ref;
+ struct loop *prev;
+ } loop;
+ } u;
+ int group;
+ struct deletion *next;
+} *deletions = NULL;
+
+static int groups = 0;
+
+
+static void do_delete_vec(struct vec *vec);
+static void do_delete_obj(struct obj *obj);
+
+
+/* ----- helper functions -------------------------------------------------- */
+
+
+static struct deletion *new_deletion(enum del_type type)
+{
+ struct deletion *del;
+
+ del = alloc_type(struct deletion);
+ del->type = type;
+ del->group = groups;
+ del->next = deletions;
+ deletions = del;
+ return del;
+}
+
+
+static void reset_active_ref(struct frame *ref)
+{
+ const struct frame *frame;
+ struct obj *obj = NULL;
+
+ for (frame = frames; frame; frame = frame->next)
+ for (obj = frame->objs; obj; obj = obj->next)
+ if (obj->type == ot_frame && obj->u.frame.ref == ref)
+ break;
+ ref->active_ref = obj;
+}
+
+
+/* ----- vectors ----------------------------------------------------------- */
+
+
+static void destroy_vec(struct vec *vec)
+{
+ free_expr(vec->x);
+ free_expr(vec->y);
+ free(vec);
+}
+
+
+static void delete_vecs_by_ref(struct vec *vecs, const struct vec *ref)
+{
+ while (vecs) {
+ if (vecs->base == ref)
+ do_delete_vec(vecs);
+ vecs = vecs->next;
+ }
+}
+
+
+static int obj_has_ref(const struct obj *obj, const struct vec *ref)
+{
+ if (obj->base == ref)
+ return 1;
+ switch (obj->type) {
+ case ot_frame:
+ return 0;
+ case ot_line:
+ return obj->u.line.other == ref;
+ case ot_rect:
+ return obj->u.rect.other == ref;
+ case ot_pad:
+ return obj->u.pad.other == ref;
+ case ot_hole:
+ return obj->u.hole.other == ref;
+ case ot_arc:
+ return obj->u.arc.start == ref || obj->u.arc.end == ref;
+ case ot_meas:
+ return obj->u.meas.high == ref;
+ case ot_iprint:
+ return 0;
+ default:
+ abort();
+ }
+}
+
+
+static void delete_objs_by_ref(struct obj **objs, const struct vec *ref)
+{
+ struct obj *obj;
+
+ for (obj = *objs; obj; obj = obj->next)
+ if (obj_has_ref(obj, ref))
+ do_delete_obj(obj);
+}
+
+
+static void do_delete_vec(struct vec *vec)
+{
+ struct vec *walk, *prev;
+ struct deletion *del;
+
+ prev = NULL;
+ for (walk = vec->frame->vecs; walk != vec; walk = walk->next)
+ prev = walk;
+ if (prev)
+ prev->next = vec->next;
+ else
+ vec->frame->vecs = vec->next;
+ del = new_deletion(dt_vec);
+ del->u.vec.ref = vec;
+ del->u.vec.prev = prev;
+
+ delete_vecs_by_ref(vec->frame->vecs, vec);
+ delete_objs_by_ref(&vec->frame->objs, vec);
+ /*
+ * Catch measurements. During final cleanup, we may operate on an empty
+ * list of frames, hence the test.
+ */
+ if (frames)
+ delete_objs_by_ref(&frames->objs, vec);
+}
+
+
+void delete_vec(struct vec *vec)
+{
+ groups++;
+ do_delete_vec(vec);
+}
+
+
+static void undelete_vec(struct vec *vec, struct vec *prev)
+{
+ if (prev) {
+ assert(vec->next == prev->next);
+ prev->next = vec;
+ } else {
+ assert(vec->next == vec->frame->vecs);
+ vec->frame->vecs = vec;
+ }
+}
+
+
+/* ----- objects ----------------------------------------------------------- */
+
+
+static void destroy_obj(struct obj *obj)
+{
+ switch (obj->type) {
+ case ot_frame:
+ if (obj->u.frame.ref->active_ref == obj)
+ reset_active_ref(obj->u.frame.ref);
+ break;
+ case ot_pad:
+ free(obj->u.pad.name);
+ break;
+ case ot_hole:
+ break;
+ case ot_line:
+ if (obj->u.line.width)
+ free_expr(obj->u.line.width);
+ break;
+ case ot_rect:
+ if (obj->u.rect.width)
+ free_expr(obj->u.rect.width);
+ break;
+ case ot_arc:
+ if (obj->u.arc.width)
+ free_expr(obj->u.arc.width);
+ break;
+ case ot_meas:
+ if (obj->u.meas.label)
+ free(obj->u.meas.label);
+ if (obj->u.meas.offset)
+ free_expr(obj->u.meas.offset);
+ break;
+ case ot_iprint:
+ free_expr(obj->u.iprint.expr);
+ break;
+ default:
+ abort();
+ }
+ free(obj);
+}
+
+
+static void do_delete_obj(struct obj *obj)
+{
+ struct obj *walk, *prev;
+ struct deletion *del;
+
+ prev = NULL;
+ for (walk = obj->frame->objs; walk != obj; walk = walk->next)
+ prev = walk;
+ if (prev)
+ prev->next = obj->next;
+ else
+ obj->frame->objs = obj->next;
+ del = new_deletion(dt_obj);
+ del->u.obj.ref = obj;
+ del->u.obj.prev = prev;
+ if (obj->type == ot_frame && obj->u.frame.ref->active_ref == obj)
+ reset_active_ref(obj->u.frame.ref);
+}
+
+
+void delete_obj(struct obj *obj)
+{
+ groups++;
+ do_delete_obj(obj);
+}
+
+
+static void undelete_obj(struct obj *obj, struct obj *prev)
+{
+ if (prev) {
+ assert(obj->next == prev->next);
+ prev->next = obj;
+ } else {
+ assert(obj->next == obj->frame->objs);
+ obj->frame->objs = obj;
+ }
+}
+
+
+
+/* ----- rows -------------------------------------------------------------- */
+
+
+static void destroy_row(struct row *row)
+{
+ struct value *next_value;
+
+ while (row->values) {
+ next_value = row->values->next;
+ free_expr(row->values->expr);
+ free(row->values);
+ row->values = next_value;
+ }
+ free(row);
+}
+
+
+void delete_row(struct row *row)
+{
+ struct deletion *del;
+ struct row *walk, *prev;
+
+ groups++;
+ prev = NULL;
+ for (walk = row->table->rows; walk != row; walk = walk->next)
+ prev = walk;
+ if (prev)
+ prev->next = row->next;
+ else
+ row->table->rows = row->next;
+ del = new_deletion(dt_row);
+ del->u.row.ref = row;
+ del->u.row.prev = prev;
+}
+
+
+static void undelete_row(struct row *row, struct row *prev)
+{
+ if (prev) {
+ assert(row->next == prev->next);
+ prev->next = row;
+ } else {
+ assert(row->next == row->table->rows);
+ row->table->rows = row;
+ }
+}
+
+
+/* ----- columns ----------------------------------------------------------- */
+
+
+void delete_column(struct table *table, int n)
+{
+ struct deletion *del;
+ struct column *col;
+ struct var **var;
+ struct row *row;
+ struct value **next, **value;
+ int i;
+
+ groups++;
+
+ del = new_deletion(dt_column);
+ col = &del->u.col;
+ col->table = table;
+ col->n = n;
+
+ var = &table->vars;
+ for (i = 0; i != n; i++)
+ var = &(*var)->next;
+ col->var = *var;
+ *var = (*var)->next;
+
+ next = &col->values;
+ for (row = table->rows; row; row = row->next) {
+ value = &row->values;
+ for (i = 0; i != n; i++)
+ value = &(*value)->next;
+ *next = *value;
+ *value = (*value)->next;
+ next = &(*next)->next;
+ }
+ *next = NULL;
+}
+
+
+static void undelete_column(const struct column *col)
+{
+ struct var **var;
+ struct row *row;
+ struct value **anchor, *value, *next;
+ int i;
+
+ var = &col->table->vars;
+ for (i = 0; i != col->n; i++)
+ var = &(*var)->next;
+ col->var->next = *var;
+ *var = col->var;
+
+ value = col->values;
+ for (row = col->table->rows; row; row = row->next) {
+ anchor = &row->values;
+ for (i = 0; i != col->n; i++)
+ anchor = &(*anchor)->next;
+ next = value->next;
+ value->next = *anchor;
+ *anchor = value;
+ value = next;
+ }
+}
+
+
+/* ----- tables ------------------------------------------------------------ */
+
+
+static void destroy_table(struct table *table)
+{
+ struct var *next_var;
+
+ while (table->vars) {
+ next_var = table->vars->next;
+ free(table->vars);
+ table->vars = next_var;
+ }
+ while (table->rows) {
+ delete_row(table->rows);
+ destroy();
+ }
+ free(table);
+}
+
+
+void delete_table(struct table *table)
+{
+ struct frame *frame = table->vars->frame;
+ struct deletion *del;
+ struct table *walk, *prev;
+
+ groups++;
+ prev = NULL;
+ for (walk = frame->tables; walk != table; walk = walk->next)
+ prev = walk;
+ if (prev)
+ prev->next = table->next;
+ else
+ frame->tables = table->next;
+ del = new_deletion(dt_table);
+ del->u.table.ref = table;
+ del->u.table.prev = prev;
+}
+
+
+static void undelete_table(struct table *table, struct table *prev)
+{
+ struct frame *frame = table->vars->frame;
+
+ if (prev) {
+ assert(table->next == prev->next);
+ prev->next = table;
+ } else {
+ assert(table->next == frame->tables);
+ frame->tables = table;
+ }
+}
+
+
+/* ----- loops ------------------------------------------------------------- */
+
+
+static void destroy_loop(struct loop *loop)
+{
+ free_expr(loop->from.expr);
+ free_expr(loop->to.expr);
+ free(loop);
+}
+
+
+void delete_loop(struct loop *loop)
+{
+ struct frame *frame = loop->var.frame;
+ struct deletion *del;
+ struct loop *walk, *prev;
+
+ groups++;
+ prev = NULL;
+ for (walk = frame->loops; walk != loop; walk = walk->next)
+ prev = walk;
+ if (prev)
+ prev->next = loop->next;
+ else
+ frame->loops = loop->next;
+ del = new_deletion(dt_loop);
+ del->u.loop.ref = loop;
+ del->u.loop.prev = prev;
+}
+
+
+static void undelete_loop(struct loop *loop, struct loop *prev)
+{
+ struct frame *frame = loop->var.frame;
+
+ if (prev) {
+ assert(loop->next == prev->next);
+ prev->next = loop;
+ } else {
+ assert(loop->next == frame->loops);
+ frame->loops = loop;
+ }
+}
+
+
+/* ----- frames ------------------------------------------------------------ */
+
+
+static void destroy_frame(struct frame *frame)
+{
+ while (frame->tables) {
+ delete_table(frame->tables);
+ destroy();
+ }
+ while (frame->loops) {
+ delete_loop(frame->loops);
+ destroy();
+ }
+ while (frame->vecs) {
+ delete_vec(frame->vecs);
+ destroy();
+ }
+ while (frame->objs) {
+ delete_obj(frame->objs);
+ destroy();
+ }
+ free(frame);
+}
+
+
+static int qual_ref(const struct frame_qual *qual, const struct frame *ref)
+{
+ while (qual) {
+ if (qual->frame == ref)
+ return 1;
+ qual = qual->next;
+ }
+ return 0;
+}
+
+
+static void delete_references(const struct frame *ref)
+{
+ struct frame *frame;
+ struct obj *obj;
+
+ for (frame = frames; frame; frame = frame->next)
+ for (obj = frame->objs; obj; obj = obj->next)
+ switch (obj->type) {
+ case ot_frame:
+ if (obj->u.frame.ref == ref)
+ do_delete_obj(obj);
+ break;
+ case ot_meas:
+ if (obj->base->frame == ref ||
+ obj->u.meas.high->frame == ref ||
+ qual_ref(obj->u.meas.low_qual, ref) ||
+ qual_ref(obj->u.meas.high_qual, ref))
+ do_delete_obj(obj);
+ break;
+ default:
+ break;
+ }
+ for (obj = ref->objs; obj; obj = obj->next)
+ if (obj->type == ot_frame)
+ if (obj->u.frame.ref->active_ref == obj)
+ reset_active_ref(obj->u.frame.ref);
+}
+
+
+void delete_frame(struct frame *frame)
+{
+ struct deletion *del;
+ struct frame *walk;
+ groups++;
+
+ del = new_deletion(dt_frame);
+ del->u.frame.ref = frame;
+ del->u.frame.prev = NULL;
+ for (walk = frames; walk != frame; walk = walk->next)
+ del->u.frame.prev = walk;
+ if (del->u.frame.prev)
+ del->u.frame.prev->next = frame->next;
+ else
+ frames = frame->next; /* hmm, deleting the root frame ? */
+
+ delete_references(frame);
+}
+
+
+static void undelete_frame(struct frame *frame, struct frame *prev)
+{
+ if (prev) {
+ assert(frame->next == prev->next);
+ prev->next = frame;
+ } else {
+ assert(frame->next == frames);
+ frames = frame;
+ }
+}
+
+
+/* ----- destroy/undelete interface ---------------------------------------- */
+
+
+static void destroy_one(void)
+{
+ struct deletion *del;
+
+ del = deletions;
+ switch (del->type) {
+ case dt_vec:
+ destroy_vec(del->u.vec.ref);
+ break;
+ case dt_obj:
+ destroy_obj(del->u.obj.ref);
+ break;
+ case dt_frame:
+ destroy_frame(del->u.frame.ref);
+ break;
+ case dt_loop:
+ destroy_loop(del->u.loop.ref);
+ break;
+ case dt_table:
+ destroy_table(del->u.table.ref);
+ break;
+ case dt_row:
+ destroy_row(del->u.row.ref);
+ break;
+ case dt_column:
+ abort(); /* @@@ later */
+ break;
+ default:
+ abort();
+ }
+ deletions = del->next;
+ free(del);
+}
+
+
+void destroy(void)
+{
+ int group;
+
+ assert(deletions);
+ group = deletions->group;
+ while (deletions && deletions->group == group)
+ destroy_one();
+}
+
+
+static int undelete_one(void)
+{
+ struct deletion *del;
+
+ if (!deletions)
+ return 0;
+ del = deletions;
+ switch (del->type) {
+ case dt_vec:
+ undelete_vec(del->u.vec.ref, del->u.vec.prev);
+ break;
+ case dt_obj:
+ undelete_obj(del->u.obj.ref, del->u.obj.prev);
+ break;
+ case dt_frame:
+ undelete_frame(del->u.frame.ref, del->u.frame.prev);
+ break;
+ case dt_loop:
+ undelete_loop(del->u.loop.ref, del->u.loop.prev);
+ break;
+ case dt_table:
+ undelete_table(del->u.table.ref, del->u.table.prev);
+ break;
+ case dt_row:
+ undelete_row(del->u.row.ref, del->u.row.prev);
+ break;
+ case dt_column:
+ undelete_column(&del->u.col);
+ break;
+ default:
+ abort();
+ }
+ deletions = del->next;
+ free(del);
+ return 1;
+}
+
+
+int undelete(void)
+{
+ int group;
+
+ if (!deletions)
+ return 0;
+ group = deletions->group;
+ while (deletions && deletions->group == group)
+ undelete_one();
+ return 1;
+}
+
+
+void purge(void)
+{
+ while (deletions)
+ destroy();
+}