[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

gEDA-cvs: CVS update: Makefile.am



  User: ahvezda 
  Date: 06/07/04 23:13:40

  Modified:    .        Makefile.am
  Added:       .        a_basic.c f_basic.c f_image.c f_print.c g_basic.c
                        g_rc.c g_register.c g_smob.c gdk-pixbuf-hacks.c
                        i_vars.c libgeda.c m_basic.c o_arc_basic.c
                        o_attrib.c o_basic.c o_box_basic.c o_bus_basic.c
                        o_circle_basic.c o_complex_basic.c o_image.c
                        o_line_basic.c o_list.c o_net_basic.c o_picture.c
                        o_pin_basic.c o_selection.c o_text_basic.c
                        s_attrib.c s_basic.c s_clib.c s_color.c s_conn.c
                        s_cue.c s_encoding.c s_hierarchy.c s_log.c s_menu.c
                        s_page.c s_papersizes.c s_slib.c s_stretch.c
                        s_tile.c s_toplevel.c s_undo.c u_basic.c
  Log:
  First checkin to new gaf toplevel directory.  Integrated noweb removal
  
  patch by Jason Childs.
  
  
  
  
  Revision  Changes    Path
  1.56      +14 -32    eda/geda/gaf/libgeda/src/Makefile.am
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: Makefile.am
  ===================================================================
  RCS file: /home/cvspsrv/cvsroot/eda/geda/gaf/libgeda/src/Makefile.am,v
  retrieving revision 1.55
  retrieving revision 1.56
  diff -u -b -r1.55 -r1.56
  --- Makefile.am	21 May 2006 13:19:56 -0000	1.55
  +++ Makefile.am	5 Jul 2006 03:13:38 -0000	1.56
  @@ -1,18 +1,14 @@
  -# $Id: Makefile.am,v 1.55 2006/05/21 13:19:56 werner Exp $
  +# $Id: Makefile.am,v 1.56 2006/07/05 03:13:38 ahvezda Exp $
   #
   # NOTE: Don't forget that in the libtool distribution, files in this
   # directory are distributed by the demo_distfiles variable in the top
   # level Makefile.
   AUTOMAKE_OPTIONS = foreign
   
  -NOTANGLE=       @NOTANGLE@
  -NOTANGLEROOT=	@NOTANGLEROOT@
  -NOTANGLEFLAGS=  @NOTANGLEFLAGS@
  -
   INDENTBIN=      @INDENT@
   INDENTFLAG=     -kr -i2
   
  -VPATH = ../noweb:../include:src
  +VPATH = ../include:src
   
   if CCISGCC
   AM_CFLAGS = -Wall
  @@ -21,39 +17,26 @@
   # Build a libtool library, libhello.la for installation in libdir.
   lib_LTLIBRARIES = libgeda.la
   
  -BUILT_SOURCES = \
  -	a_basic.nw f_basic.nw f_print.nw f_image.nw g_basic.nw m_basic.nw \
  -	o_arc_basic.nw o_attrib.nw o_basic.nw o_box_basic.nw \
  -	o_circle_basic.nw o_complex_basic.nw o_line_basic.nw o_list.nw \
  -	o_net_basic.nw o_selection.nw o_bus_basic.nw o_text_basic.nw \
  -	o_pin_basic.nw o_image.nw u_basic.nw s_attrib.nw s_basic.nw \
  -	s_clib.nw s_encoding.nw s_hierarchy.nw s_papersizes.nw s_stretch.nw \
  -	s_log.nw \
  -	s_page.nw s_slib.nw s_color.nw s_undo.nw s_conn.nw \
  -	s_cue.nw s_tile.nw s_menu.nw s_toplevel.nw g_smob.nw libgeda.nw \
  -	g_register.nw g_rc.nw i_vars.nw o_picture.nw gdk-pixbuf-hacks.nw
  -
  -libgeda_la_SOURCES = $(BUILT_SOURCES:.nw=.c)
  +libgeda_la_SOURCES = \
  +	a_basic.c f_basic.c f_print.c f_image.c g_basic.c m_basic.c \
  +	o_arc_basic.c o_attrib.c o_basic.c o_box_basic.c \
  +	o_circle_basic.c o_complex_basic.c o_line_basic.c o_list.c \
  +	o_net_basic.c o_selection.c o_bus_basic.c o_text_basic.c \
  +	o_pin_basic.c o_image.c u_basic.c s_attrib.c s_basic.c \
  +	s_clib.c s_encoding.c s_hierarchy.c s_papersizes.c s_stretch.c \
  +	s_log.c \
  +	s_page.c s_slib.c s_color.c s_undo.c s_conn.c \
  +	s_cue.c s_tile.c s_menu.c s_toplevel.c g_smob.c libgeda.c \
  +	g_register.c g_rc.c i_vars.c o_picture.c gdk-pixbuf-hacks.c
   
   INCLUDES = -I$(top_srcdir)/include @LIBGEDA_CFLAGS@
   libgeda_la_LDFLAGS = @LIBTOOL_FLAGS@ @LIBGEDA_LDFLAGS@
   
  -
   EXTRA_DIST = create_proto 
   
  -TEXIFILES = $(BUILT_SOURCES:.nw=.texi)
  -
   src: $(libgeda_la_SOURCES)
   	@echo Finished building the C source
   
  -SUFFIXES = .nw
  -
  -.nw.c:
  -	$(NOTANGLE) $(NOTANGLEFLAGS) $(NOTANGLEROOT)'$@ : *' $< > ../src/$@.tmp
  -	mv -f ../src/$@.tmp ../src/$@
  -#       $(INDENTBIN) $(INDENTFLAG) ../src/$@
  -	rm -f ../src/$@~
  -
   CPROTO =	cproto
   CPROTOCFLAGS = 	$(INCLUDES) -I. -I.. -I../include
   ALES_HACK =	-D__GNUC__
  @@ -69,8 +52,7 @@
   CLEANFILES = *.log core FILE *~ prototype.bak
   DISTCLEANFILES = *.log core FILE *~ prototype.bak
   MAINTAINERCLEANFILES = *.log core FILE *~ prototype.bak prototype.h \
  -			Makefile.in configure \
  -			*.c
  +			Makefile.in configure
   
   # Unfortunately, in order to test libtool thoroughly, we need access
   # to its private directory.
  
  
  
  1.19      +478 -347  eda/geda/gaf/libgeda/src/a_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: a_basic.c
  ===================================================================
  RCS file: a_basic.c
  diff -N a_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ a_basic.c	5 Jul 2006 03:13:38 -0000	1.19
  @@ -0,0 +1,572 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \brief Current version string */
  +#define VERSION_20020825 20020825
  +
  +/*! \brief Save embedded attributes to current file
  + *  \par Function Description
  + *  This function will save all embedded attributes to a file.
  + *
  + *  \param [in,out] w_current
  + *  \param [in]     object_list  The list of attributes to write to file
  + *  \param [in]     fp           The file to write to.
  + */
  +void o_save_embedded(TOPLEVEL *w_current, OBJECT *object_list, FILE *fp)
  +{
  +  OBJECT *o_current=NULL;
  +  char *out;
  +
  +  /* make sure you init net_consolide to false (default) in all */
  +  /* programs */
  +  if (w_current->net_consolidate == TRUE) {
  +    o_net_consolidate(w_current);
  +  }
  +	
  +  o_current = object_list;
  +
  +  while ( o_current != NULL ) {
  +
  +    if (o_current->type != OBJ_HEAD) {
  +
  +      if (o_current->attribute == 0) {
  +
  +        switch (o_current->type) {
  +
  +          case(OBJ_LINE):
  +            out = (char *) o_line_save(o_current);
  +            break;
  +	
  +          case(OBJ_NET):
  +            out = (char *) o_net_save(o_current);
  +            break;
  +
  +          case(OBJ_BUS):
  +            out = (char *) o_bus_save(o_current);
  +            break;
  +	
  +          case(OBJ_BOX):
  +            out = (char *) o_box_save(o_current);
  +            break;
  +			
  +          case(OBJ_CIRCLE):
  +            out = (char *) o_circle_save(o_current);
  +            break;
  +
  +          case(OBJ_COMPLEX):
  +            out = (char *) o_complex_save(o_current);
  +            if (strncmp(o_current->complex_clib, "EMBEDDED", 8) == 0) {
  +              fprintf(fp, "[\n");
  +								
  +              o_save_embedded(
  +                              w_current,
  +                              o_current->
  +                              complex->prim_objs,
  +                              fp);
  +
  +              fprintf(fp, "]\n");
  +            }
  +            break;
  +
  +          case(OBJ_PLACEHOLDER):  /* new type by SDB 1.20.2005 */
  +            out = (char *) o_complex_save(o_current);
  +            break;
  +
  +          case(OBJ_TEXT):
  +            out = (char *) o_text_save(o_current);
  +            break;
  +
  +          case(OBJ_PIN):
  +            out = (char *) o_pin_save(o_current);
  +            break;
  +	
  +          case(OBJ_ARC):
  +            out = (char *) o_arc_save(o_current);
  +            break;
  +
  +  	  case(OBJ_PICTURE):
  +	    out = (char *) o_picture_save(o_current); 
  +	    break;
  +
  +          default:
  +            fprintf(stderr, "Error type!\n");
  +            exit(-1);
  +            break;
  +        }
  +
  +	/* output the line */
  +        fprintf(fp, "%s\n", out);
  +	free(out);
  +
  +        /* save those attributes */
  +        if (o_current->attribs != NULL) {
  +          if (o_current->attribs->next != NULL) {
  +            o_save_attribs(fp, o_current->attribs->next);
  +          }
  +        }
  +
  +      }
  +    } 
  +    o_current = o_current->next;
  +  }
  +}
  +
  +/*! \brief Write libgeda file header
  + *  \par Function Description
  + *  This function simply prints the VERSION and FILEFORMAT_VERSION
  + *  definitions to the file.
  + *  
  + *  \param [in] fp  The file to write the header to.
  + */
  +void o_save_write_header(FILE *fp)
  +{
  +  fprintf(fp, "v %s %u\n", VERSION, FILEFORMAT_VERSION);
  +}
  +
  +/*! \brief Save a file
  + *  \par Function Description
  + *  This function saves the data in a libgeda format to a file
  + *  \param [in] w_current  The data to save to file.
  + *  \param [in] filename   The filename to save the data to.
  + *  \return 1 on success, 0 on failure.
  + */
  +int o_save(TOPLEVEL *w_current, const char *filename)
  +{
  +  OBJECT *o_current=NULL;
  +  FILE *fp;
  +  char *out;
  +  int already_wrote=0;
  +	
  +  fp = fopen(filename, "w");
  +	
  +  if (fp == NULL) {
  +    s_log_message("o_save: Could not open [%s]\n", filename);
  +    return 0;
  +  }
  +
  +
  +  o_current = w_current->page_current->object_head;
  +
  +  /* make sure you init net_consolide to false (default) in all */
  +  /* programs */
  +  if (w_current->net_consolidate == TRUE) {
  +    o_net_consolidate(w_current);
  +  }
  +
  +  o_save_write_header(fp);
  +
  +  while ( o_current != NULL ) {
  +
  +    if (o_current->type != OBJ_HEAD) {
  +
  +      if (o_current->attribute == 0) {
  +
  +        switch (o_current->type) {
  +
  +          case(OBJ_LINE):
  +            out = (char *) o_line_save(o_current);
  +            break;
  +	
  +          case(OBJ_NET):
  +            out = (char *) o_net_save(o_current);
  +            break;
  +
  +          case(OBJ_BUS):
  +            out = (char *) o_bus_save(o_current);
  +            break;
  +	
  +          case(OBJ_BOX):
  +            out = (char *) o_box_save(o_current);
  +            break;
  +			
  +          case(OBJ_CIRCLE):
  +            out = (char *) o_circle_save(o_current);
  +            break;
  +
  +          case(OBJ_COMPLEX):
  +            out = (char *) o_complex_save(o_current);
  +            fprintf(fp, "%s\n", out);
  +            already_wrote=1;
  +            if (strncmp(o_current->complex_clib, "EMBEDDED", 8) == 0) {
  +              fprintf(fp, "[\n");
  +								
  +              o_save_embedded(
  +                              w_current,
  +                              o_current->
  +                              complex->prim_objs,
  +                              fp);
  +
  +              fprintf(fp, "]\n");
  +            }
  +            break;
  +
  +          case(OBJ_PLACEHOLDER):  /* new type by SDB 1.20.2005 */
  +            out = (char *) o_complex_save(o_current);
  +            break;
  +
  +          case(OBJ_TEXT):
  +            out = (char *) o_text_save(o_current);
  +            break;
  +
  +          case(OBJ_PIN):
  +            out = (char *) o_pin_save(o_current);
  +            break;
  +	
  +          case(OBJ_ARC):
  +            out = (char *) o_arc_save(o_current);
  +            break;
  +
  +  	  case(OBJ_PICTURE):
  +	    out = (char *) o_picture_save(o_current); 
  +	    break;
  +
  +          default:
  +            fprintf(stderr, "Error type!\n");
  +            exit(-1);
  +            break;
  +        }
  +
  +				/* output the line */
  +        if (!already_wrote) {
  +          fprintf(fp, "%s\n", out);
  +	  free(out);
  +        } else {
  +          already_wrote=0;
  +        }
  +
  +				/* save those attributes */
  +        if (o_current->attribs != NULL) {
  +          if (o_current->attribs->next != NULL) {
  +            o_save_attribs(fp, o_current->attribs->next);
  +          }
  +        }
  +
  +      }
  +    } 
  +    o_current = o_current->next;
  +  }
  +
  +  fclose(fp);
  +  return 1;
  +}
  +
  +/*! \brief Read a file
  + *  \par Function Description
  + *  This function reads a file in libgead format.
  + *
  + *  \param [in,out] w_current    The current TOPLEVEL structure.
  + *  \param [in]     object_list  The object_list to read data to.
  + *  \param [in]     filename     The filename to read from.
  + *  \return object_list if successful read, or NULL on error.
  + */
  +OBJECT *o_read(TOPLEVEL *w_current, OBJECT *object_list, char *filename)
  +{
  +  FILE *fp;
  +  char buf[1024];
  +  char objtype;
  +  OBJECT *object_list_save=NULL;
  +  OBJECT *temp_tail=NULL;
  +  OBJECT *temp_parent=NULL;
  +  OBJECT *object_before_attr=NULL;
  +  unsigned int release_ver;
  +  unsigned int fileformat_ver;
  +  unsigned int current_fileformat_ver;
  +  int found_pin = 0;
  +  OBJECT* last_complex = NULL;
  +  int itemsread = 0;
  +
  +  /* fill version with default file format version (the current one) */
  +  current_fileformat_ver = FILEFORMAT_VERSION;
  +
  +  fp = fopen(filename, "r");
  +
  +  if (fp == NULL) {
  +    s_log_message("o_read: Could not open [%s]\n", filename);
  +    return(NULL);
  +  }
  +
  +  while ( fgets(buf, 1024, fp) != NULL) {
  +
  +    sscanf(buf, "%c", &objtype);
  +
  +    /* Do we need to check the symbol version?  Yes, but only if */
  +    /* 1) the last object read was a complex and */
  +    /* 2) the next object isn't the start of attributes.  */
  +    /* If the next object is the start of attributes, then check the */
  +    /* symbol version after the attributes have been read in, see the */
  +    /* STARTATTACH_ATTR case */
  +    if (last_complex && objtype != STARTATTACH_ATTR)
  +    {
  +        /* yes */
  +        /* verify symbol version (not file format but rather contents) */
  +        o_complex_check_symversion(w_current, last_complex);
  +        last_complex = NULL;  /* no longer need to check */
  +    }
  +
  +    switch (objtype) {
  +
  +      case(OBJ_LINE):
  +        object_list = (OBJECT *) o_line_read(w_current, object_list, buf, 
  +	                                     release_ver, fileformat_ver);
  +        break;
  +
  +
  +      case(OBJ_NET):
  +        object_list = (OBJECT *) o_net_read(w_current, object_list, buf,
  +                                            release_ver, fileformat_ver);
  +        break;
  +
  +      case(OBJ_BUS):
  +        object_list = (OBJECT *) o_bus_read(w_current, object_list, buf,
  +                                            release_ver, fileformat_ver);
  +        break;
  +
  +      case(OBJ_BOX):
  +        object_list = (OBJECT *) o_box_read(w_current, object_list, buf,
  +                                            release_ver, fileformat_ver);
  +        break;
  +		
  +      case(OBJ_PICTURE):
  +        object_list = (OBJECT *) o_picture_read(w_current, object_list, buf,
  +						fp,
  +						release_ver, fileformat_ver);
  +        break;
  +		
  +      case(OBJ_CIRCLE):
  +        object_list = (OBJECT *) o_circle_read(w_current, object_list, buf,
  +                                               release_ver, fileformat_ver);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +        object_list = (OBJECT *) o_complex_read(w_current, object_list, buf,
  +                                                release_ver, fileformat_ver);
  +
  +        /* this is necessary because complex may add attributes which float */
  +	/* needed now? */
  +        object_list = (OBJECT *) return_tail(object_list);
  +
  +        /* last_complex is used for verifying symversion attribute */
  +        last_complex = object_list;
  +        break;
  +
  +      case(OBJ_TEXT):
  +        /* fgets(string, 1024, fp); string lines are now read inside: */
  +        object_list = (OBJECT *) o_text_read(w_current, object_list, buf,
  +                                             fp,
  +                                             release_ver, fileformat_ver);
  +        break;
  +
  +      case(OBJ_PIN):
  +        object_list = (OBJECT *) o_pin_read(w_current, object_list, buf,
  +                                            release_ver, fileformat_ver);
  +        found_pin++;
  +        break;
  +
  +      case(OBJ_ARC):
  +        object_list = (OBJECT *) o_arc_read(w_current, object_list, buf,
  +                                            release_ver, fileformat_ver);
  +        break;
  +
  +      case(STARTATTACH_ATTR): 
  +        object_before_attr = object_list;
  +	/* first is the fp */
  +	/* 2nd is the object to get the attributes */ 
  +        object_list = (OBJECT *) o_read_attribs(w_current, fp, object_list,
  +                                                release_ver, fileformat_ver);
  +
  +        /* by now we have finished reading all the attributes */
  +        /* did we just finish attaching to a complex object? */
  +        if (last_complex)
  +        {
  +          /* yes */
  +          /* verify symbol version (not file format but rather contents) */
  +          o_complex_check_symversion(w_current, last_complex);
  +          last_complex = NULL;
  +        }
  +        
  +	/* slots only apply to complex objects */
  +        if (object_before_attr->type == OBJ_COMPLEX || 
  +	    object_before_attr->type == OBJ_PLACEHOLDER) {
  +          o_attrib_slot_update(w_current, object_before_attr);	
  +        }
  +
  +	/* need this? nope */
  +	/*object_list = return_tail(object_list);*/
  +        object_before_attr = NULL;
  +        break;
  +
  +      case(START_EMBEDDED): 
  +        object_list_save = object_list;
  +        object_list = object_list_save->complex->
  +          prim_objs;
  +				
  +        temp_tail =
  +          w_current->page_current->object_tail;
  +        temp_parent =
  +          w_current->page_current->object_parent;
  +        w_current->page_current->object_parent = 
  +          object_list;
  +        break;
  +
  +      case(END_EMBEDDED): 
  +        object_list = object_list_save;
  +	/* don't do this since objects are already
  +	 * stored/read translated 
  +         * o_complex_world_translate(w_current, object_list->x,
  +         *                           object_list->y, object_list->complex);
  +	 */
  +        w_current->page_current->object_tail = temp_tail;
  +        w_current->page_current->object_parent = temp_parent;
  +        break;
  +
  +      case(ENDATTACH_ATTR):
  +        /* this case is never hit, since the } is consumed by o_read_attribs */
  +        break;	
  +
  +      case(INFO_FONT): 
  +        o_text_set_info_font(buf);
  +        break;	
  +
  +      case(COMMENT):
  +	/* do nothing */
  +        break;
  +
  +      case(VERSION_CHAR):
  +        itemsread = sscanf(buf, "v %u %u\n", &release_ver, &fileformat_ver);
  +
  +	/* 20030921 was the last version which did not have a fileformat */
  +	/* version.  The below latter test should not happen, but it is here */
  +	/* just in in case. */
  +	if (release_ver <= VERSION_20030921 || itemsread == 1)
  +        { 
  +          fileformat_ver = 0;
  +	}
  +        
  +	if (fileformat_ver < current_fileformat_ver)
  +        {
  +       	  s_log_message("Read an old format sym/sch file!\n"
  +                        "Please run g[sym|sch]update on:\n[%s]\n", filename);
  +	}
  +        break;
  +
  +      default:
  +        fprintf(stderr, "Read garbage in [%s] :\n>>\n%s<<\n",
  +                filename, buf);
  +        break;
  +    }
  +
  +  }
  +  fclose(fp);
  +
  +  /* Was the very last thing we read a complex and has it not been checked */
  +  /* yet?  This would happen if the complex is at the very end of the file  */
  +  /* and had no attached attributes */
  +  if (last_complex)
  +  {
  +        o_complex_check_symversion(w_current, last_complex);
  +        last_complex = NULL;  /* no longer need to check */
  +  }
  +
  +  if (found_pin) {
  +    if (release_ver <= VERSION_20020825) {
  +      o_pin_update_whichend(w_current, return_head(object_list), found_pin);
  +    }
  +  }
  +  
  +  return(object_list);
  +}
  +
  +/*! \brief Scale a set of lines.
  + *  \par Function Description
  + *  This function takes a list of lines and scales them
  + *  by the values of x_scale and y_scale.
  + *
  + *  \param [in] w_current  The current TOPLEVEL object.
  + *  \param [in,out]  list  The list with lines to scale.
  + *  \param [in]   x_scale  The x scale value for the lines.
  + *  \param [in]   y_scale  The y scale value for the lines.
  + *
  + *  \todo this really doesn't belong here. you need more of a core routine
  + *        first. yes.. this is the core routine, just strip out the drawing
  + *        stuff
  + *        move it to o_complex_scale
  + */
  +void o_scale(TOPLEVEL *w_current, OBJECT *list, int x_scale, int y_scale)
  +{
  +  OBJECT *o_current;
  +
  +  /* this is okay if you just hit scale and have nothing selected */
  +  if (list == NULL) { 
  +    /* w_current->event_state = SELECT;*/
  +    /* i_update_status(w_current, "Select Mode"); not here */
  +    /*		w_current->inside_action = 0;*/
  +    return;
  +  }
  +
  +
  +  o_current = list;
  +
  +
  +  while (o_current != NULL) {
  +
  +    switch(o_current->type) {
  +
  +      case(OBJ_LINE):
  +				/* erase the current selection */
  +        w_current->override_color =
  +          w_current->background_color;
  +        o_redraw_single(w_current, o_current);
  +                                /* o_line_draw(w_current, o_current);*/
  +        w_current->override_color = -1;
  +
  +        o_line_scale_world(w_current, 
  +                           x_scale, y_scale, o_current);
  +        break;
  +    }
  +
  +    o_current = o_current->next;
  +  }
  +
  +  /* don't do this at this level */
  +  /* w_current->page_current->CHANGED=1;*/
  +}
  +
  +
  
  
  
  1.18      +443 -50   eda/geda/gaf/libgeda/src/f_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: f_basic.c
  ===================================================================
  RCS file: f_basic.c
  diff -N f_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ f_basic.c	5 Jul 2006 03:13:38 -0000	1.18
  @@ -0,0 +1,489 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h> 
  +
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h> 
  +#endif
  +
  +#include <sys/param.h>
  +#include <stdlib.h>
  +#include <time.h>
  +#include <sys/types.h>
  +#include <sys/stat.h>
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"  
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \brief Opens the schematic file.
  + *  \par Function Description
  + *  Opens the schematic file. Before it reads the schematic, it tries to
  + *  open and read the local gafrc file.
  + *
  + *  \param [in,out] w_current  The TOPLEVEL object to load the schematic into.
  + *  \param [in]      filename  A character string containing the file name
  + *                             to open.
  + *  \return 0 on failure, 1 on success.
  + */
  +int f_open(TOPLEVEL *w_current, char *filename)
  +{
  +  int opened=FALSE;
  +  char *full_filename = NULL;
  +  char *full_rcfilename = NULL;
  +  char *file_directory = NULL;
  +  char *saved_cwd = NULL;
  +  char *backup_filename = NULL;
  +  char load_backup_file = 0;
  +
  +  /* has the head been freed yet? */
  +  /* probably not hack PAGE */
  +
  +  set_window(w_current, w_current->page_current,
  +             w_current->init_left, w_current->init_right,
  +             w_current->init_top,  w_current->init_bottom);
  +
  +
  +  /* 
  +   * If we are only opening a preview window, we don't want to 
  +   * change the directory. Therefore, if this is only a preview window, 
  +   * we cache the cwd so we can restore it later.
  +   */
  +  if (w_current->wid == -1) {
  +    saved_cwd = getcwd(NULL, 1024);
  +  }
  +
  +  /* get full, absolute path to file */
  +  full_filename = f_normalize_filename(filename); 
  +
  +  /* write full, absolute filename into page_current->page_filename */
  +  if (w_current->page_current->page_filename) {
  +    free(w_current->page_current->page_filename);
  +  }
  +  w_current->page_current->page_filename = g_strdup(full_filename);
  +
  +  /* Before we open the page, let's load the corresponding gafrc. */
  +  /* First cd into file's directory. */
  +  file_directory = g_dirname (full_filename);
  +
  +  full_rcfilename = g_strconcat (file_directory,  
  +                                 G_DIR_SEPARATOR_S, 
  +                                 "gafrc",
  +                                 NULL);
  +  if (file_directory) { 
  +    chdir(file_directory);  
  +    /* Probably should do some checking of chdir return values */
  +  }
  +  /* If directory is not found, we should do something . . . . */
  +
  +  /* Now open RC and process file */
  +  g_rc_parse_specified_rc(w_current, full_rcfilename);
  +
  +  /* Check if there is a newer autosave backup file */
  +  backup_filename = g_strdup_printf("%s%c"AUTOSAVE_BACKUP_FILENAME_STRING,
  +				    file_directory, G_DIR_SEPARATOR, 
  +				    g_path_get_basename(full_filename));
  +
  +  g_free (file_directory);
  +
  +  if ( g_file_test (backup_filename, G_FILE_TEST_EXISTS) && 
  +       (! g_file_test (backup_filename, G_FILE_TEST_IS_DIR))) {
  +    /* An autosave backup file exists. Check if it's newer */
  +    struct stat stat_backup;
  +    struct stat stat_file;
  +    char error_stat = 0;
  +    GString *message;
  +    
  +    if (stat (backup_filename, &stat_backup) != 0) {
  +      s_log_message ("f_open: Unable to get stat information of backup file %s.", 
  +		     backup_filename);
  +      error_stat = 1 ;
  +    }
  +    if (stat (full_filename, &stat_file) != 0) {
  +      s_log_message ("f_open: Unable to get stat information of file %s.", 
  +		     full_filename);
  +      error_stat = 1;
  +    }
  +    if ((difftime (stat_file.st_ctime, stat_backup.st_ctime) < 0) ||
  +	(error_stat == 1))
  +    {
  +      /* Found an autosave backup. It's newer if error_stat is 0 */
  +      message = g_string_new ("");
  +      g_string_append_printf(message, "\nWARNING: Found an autosave backup file:\n  %s.\n\n", backup_filename);
  +      if (error_stat == 1) {
  +	g_string_append(message, "I could not guess if it is newer, so you have to"
  +			  "do it manually.\n");
  +      }
  +      else {
  +	g_string_append(message, "The backup copy is newer than the schematic, so it seems you should load it instead of the original file.\n");
  +      }
  +      g_string_append (message, "Gschem usually makes backup copies automatically, and this situation happens when it crashed or it was forced to exit abruptely.\n");
  +      if (w_current->page_current->load_newer_backup_func == NULL) {
  +	s_log_message(message->str);
  +	s_log_message("\nRun gschem and correct the situation.\n\n");
  +	fprintf(stderr, message->str);
  +	fprintf(stderr, "\nRun gschem and correct the situation.\n\n");
  +      }
  +      else {
  +	/* Ask the user if load the backup or the original file */
  +	if (w_current->page_current->load_newer_backup_func 
  +	    (w_current, message)) {
  +	  /* Load the backup file */
  +	  load_backup_file = 1;
  +	}
  +      }
  +      g_string_free (message, TRUE);
  +    }
  +  }
  +
  +  /* Now that we have set the current directory and read
  +   * the RC file, it's time to read in the file. */
  +  if (load_backup_file == 1) {
  +    /* Load the backup file */
  +    w_current->page_current->object_tail = (OBJECT *) 
  +    o_read(w_current, w_current->page_current->object_tail, 
  +	   backup_filename);
  +  }
  +  else {
  +    /* Load the original file */
  +    w_current->page_current->object_tail = (OBJECT *) 
  +    o_read(w_current, w_current->page_current->object_tail, 
  +	   full_filename);
  +  }
  +
  +  g_free (backup_filename);
  +
  +  if (w_current->page_current->object_tail != NULL) {
  +    s_log_message("Opened file [%s]\n", full_filename);
  +    opened = TRUE;
  +
  +  } else {
  +    /* Failed to open page */
  +    opened = FALSE;	 
  +  }
  +
  +
  +  w_current->page_current->object_tail = (OBJECT *) 
  +  return_tail(w_current->page_current->object_head); 
  +
  +  /* make sure you init net_consolide to false (default) in all */
  +  /* programs */
  +  if (w_current->net_consolidate == TRUE) {	
  +    o_net_consolidate(w_current);
  +  }
  +
  +  if (load_backup_file == 0) {
  +    /* If it's not the backup file */
  +    w_current->page_current->CHANGED=0; /* added 4/7/98 */
  +  }
  +  else {
  +    /* We are loading the backup file, so gschem should ask
  +       the user if save it or not when closing the page. */
  +    w_current->page_current->CHANGED=1;
  +  }
  +
  +  free(full_filename);
  +  free(full_rcfilename);
  +
  +  /* If this was a preview window, reset the directory to the 
  +   * value it had when f_open was called.  Also get rid of component
  +   * libraries opened while opening preview window.  If the component
  +   * is actually selected, they will be re-read later. */
  +  if (w_current->wid == -1) {
  +    chdir(saved_cwd);
  +    free(saved_cwd);
  +  }
  +
  +  if (!opened) {
  +    return (FALSE);
  +  } else {
  +    return (TRUE);
  +  }
  +}
  +
  +/*! \brief Closes the schematic file
  + *  \par Function Description
  + *  Does nothing
  + *
  + *  \param [in,out] w_current  The TOPLEVEL object with schematic to be closed.
  + */
  +void f_close(TOPLEVEL *w_current)
  +{
  +
  +}
  +
  +/*! \brief Save schematic file and close
  + *  \par Function Description
  + *  This function will save the current schematic file before closing it.
  + *  It also deletes the page_current item in the TOPLEVEL structure.
  + *
  + *  \param [in,out] w_current  The TOPLEVEL object containing the schematic.
  + *  \param [in]      filename  The file name to save the schematic to.
  + */
  +void f_save_close(TOPLEVEL *w_current, char *filename)
  +{
  +  o_save(w_current, filename);
  +  s_page_delete (w_current, w_current->page_current);
  +}
  +
  +/*! \brief Save the schematic file
  + *  \par Function Description
  + *  This function saves the current schematic file in the w_current object.
  + *
  + *  \param [in,out] w_current  The TOPLEVEL object containing the schematic.
  + *  \param [in]      filename  The file name to save the schematic to.
  + *  \return 1 on success, 0 on failure.
  + */
  +int f_save(TOPLEVEL *w_current, const char *filename)
  +{
  +  gchar *backup_filename;
  +  gchar *real_filename;
  +  gchar *only_filename;
  +  gchar *dirname;
  +  mode_t saved_umask, mask;
  +  struct stat st;
  +
  +  /* Get the real filename and file permissions */
  +  real_filename = follow_symlinks (filename, NULL);
  +
  +  if (real_filename == NULL) {
  +    s_log_message ("Can't get the real filename of %s.", filename);
  +    fprintf (stderr, "Can't get the real filename of %s.\n", filename);
  +    return 0;
  +  }
  +  
  +  /* Get the directory in which the real filename lives */
  +  dirname = g_path_get_dirname (real_filename);
  +  only_filename = g_path_get_basename(real_filename);  
  +
  +  /* Do a backup if it's not an undo file backup and it was never saved. */
  +  if (w_current->page_current->saved_since_first_loaded == 0) {    
  +    if ( (g_file_test (real_filename, G_FILE_TEST_EXISTS)) && 
  +	 (!g_file_test(real_filename, G_FILE_TEST_IS_DIR)) )
  +    {
  +      backup_filename = g_strdup_printf("%s%c%s~", dirname, 
  +					G_DIR_SEPARATOR, only_filename);
  +
  +      /* Make the backup file read-write before saving a new one */
  +      if ( g_file_test (backup_filename, G_FILE_TEST_EXISTS) && 
  +	   (! g_file_test (backup_filename, G_FILE_TEST_IS_DIR))) {
  +	if (chmod(backup_filename, S_IREAD|S_IWRITE) != 0) {
  +	  s_log_message ("Could NOT set previous backup file [%s] read-write\n", 
  +			 backup_filename);	    
  +	}
  +      }
  +	
  +      if (rename(real_filename, backup_filename) != 0) {
  +	s_log_message ("Can't save backup file: %s.", backup_filename);
  +	fprintf (stderr, "Can't save backup file: %s.", backup_filename);
  +      }
  +      else {
  +	/* Make the backup file readonly so a 'rm *' command will ask 
  +	   the user before deleting it */
  +	saved_umask = umask(0);
  +	mask = (S_IWRITE|S_IWGRP|S_IEXEC|S_IXGRP|S_IXOTH);
  +	mask = (~mask)&0777;
  +	mask &= ((~saved_umask) & 0777);
  +	if (chmod(backup_filename, mask) != 0) {
  +	  s_log_message ("Could NOT set backup file [%s] readonly\n", 
  +			   backup_filename);	    
  +	}
  +	umask(saved_umask);
  +      }
  +
  +      g_free(backup_filename);
  +    }
  +  }
  +    /* If there is not an existing file with that name, compute the
  +     * permissions and uid/gid that we will use for the newly-created file.
  +     */
  +       
  +  if (stat (real_filename, &st) != 0)
  +  {
  +    struct stat dir_st;
  +    int result;
  +    
  +    /* Use default permissions */
  +    saved_umask = umask(0);
  +    st.st_mode = 0666 & ~saved_umask;
  +    umask(saved_umask);
  +    st.st_uid = getuid ();
  +    
  +    result = stat (dirname, &dir_st);
  +    
  +    if (result == 0 && (dir_st.st_mode & S_ISGID))
  +	  st.st_gid = dir_st.st_gid;
  +    else
  +    st.st_gid = getgid ();
  +  }
  +  g_free (dirname);
  +  g_free (only_filename);
  +  
  +  if (o_save(w_current, real_filename)) {
  +
  +    w_current->page_current->saved_since_first_loaded = 1;
  +
  +    /* Reset the last saved timer */
  +    g_get_current_time (&w_current->page_current->last_load_or_save_time);
  +    w_current->page_current->ops_since_last_backup = 0;
  +    w_current->page_current->do_autosave_backup = 0;
  +
  +    /* Restore permissions. */
  +    chmod (real_filename, st.st_mode);
  +    chown (real_filename, st.st_uid, st.st_gid);
  +
  +    g_free (real_filename);
  +    return 1;
  +  }
  +  else {
  +    g_free (real_filename);
  +    return 0;
  +  }
  +}
  +
  +/*! \brief Reformats a filename as an absolute resolved filename
  + *  \par Function Description
  + *  Given a filename in any format, this returns the full, absolute
  + *  resolved filename.
  + *
  + *  \param [in] filename  A character string containing the file
  + *                        name to resolve.
  + *  \return A character string with the resolved filename.
  + */
  +char* f_normalize_filename(const gchar *filename)
  +{
  +  char filename_buffer[MAXPATHLEN];  /* nasty hack for realpath */
  +  char *full_filename;
  +
  +  /*  Check for pathological case  */
  +  if (filename == NULL) {
  +    return NULL;
  +  }
  +
  +  realpath(filename, filename_buffer);  /* places reult in filename_buffer */
  +  full_filename = g_strdup (filename_buffer);
  +
  +#ifdef DEBUG
  +  printf("In f_normalize_filename, returning full_filename= %s \n", full_filename);
  +#endif 
  +
  +  return full_filename;
  +}
  +
  +/*! \brief Follow symlinks until a real file is found
  + *  \par Function Description
  + *  Does readlink() recursively until we find a real filename.
  + *
  + *  \param [in] filename  The filename to search for.
  + *  \param [out]   error  Unused, set to NULL
  + *  \return The path to real file on success, NULL otherwise.
  + *
  + *  \note Taken from gedit's source code.
  + */
  +char *follow_symlinks (const gchar *filename, GError **error)
  +{
  +  gchar *followed_filename;
  +  gint link_count;
  +  
  +  g_return_val_if_fail (filename != NULL, NULL);
  +  
  +  g_return_val_if_fail (strlen (filename) + 1 <= MAXPATHLEN, NULL);
  +  
  +  followed_filename = g_strdup (filename);
  +  link_count = 0;
  +  
  +  while (link_count < MAX_LINK_LEVEL) {
  +    struct stat st;
  +    
  +    if (lstat (followed_filename, &st) != 0)
  +      /* We could not access the file, so perhaps it does not
  +       * exist.  Return this as a real name so that we can
  +       * attempt to create the file.
  +       */
  +      return followed_filename;
  +    
  +    if (S_ISLNK (st.st_mode)) {
  +      gint len;
  +      gchar linkname[MAXPATHLEN];
  +      
  +      link_count++;
  +      
  +      len = readlink (followed_filename, linkname, MAXPATHLEN - 1);
  +      
  +      if (len == -1) {
  +	s_log_message("Could not read symbolic link information for %s", followed_filename);
  +	fprintf(stderr, "Could not read symbolic link information for %s", followed_filename);
  +	g_free (followed_filename);
  +	return NULL;
  +      }
  +      
  +      linkname[len] = '\0';
  +      
  +      /* If the linkname is not an absolute path name, append
  +       * it to the directory name of the followed filename.  E.g.
  +       * we may have /foo/bar/baz.lnk -> eek.txt, which really
  +       * is /foo/bar/eek.txt.
  +       */
  +      
  +      if (linkname[0] != G_DIR_SEPARATOR) {
  +	gchar *slashpos;
  +	gchar *tmp;
  +	
  +	slashpos = strrchr (followed_filename, G_DIR_SEPARATOR);
  +	
  +	if (slashpos)
  +	  *slashpos = '\0';
  +	else {
  +	  tmp = g_strconcat ("./", followed_filename, NULL);
  +	  g_free (followed_filename);
  +	  followed_filename = tmp;
  +	}
  +	
  +	tmp = g_build_filename (followed_filename, linkname, NULL);
  +	g_free (followed_filename);
  +	followed_filename = tmp;
  +      } else {
  +	g_free (followed_filename);
  +	followed_filename = g_strdup (linkname);
  +      }
  +    } else
  +      return followed_filename;
  +  }
  +
  +  /* Too many symlinks */
  +  
  +  s_log_message("The file has too many symbolic links.");
  +  fprintf(stderr, "The file has too many symbolic links.");
  +  
  +  return NULL;
  +}
  
  
  
  1.18      +141 -135  eda/geda/gaf/libgeda/src/f_image.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: f_image.c
  ===================================================================
  RCS file: f_image.c
  diff -N f_image.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ f_image.c	5 Jul 2006 03:13:38 -0000	1.18
  @@ -0,0 +1,222 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#ifdef HAS_LIBGDGEDA
  +#include <gdgeda/gd.h>
  +#endif
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +#ifdef HAS_LIBGDGEDA
  +/*! \todo Finish function description!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \param [in,out] w_current  The TOPLEVEL object to write to.
  + *  \param [in,out]      head  The object to read image from.
  + *  \param [in]       start_x  X Offset to start from.
  + *  \param [in]       start_y  Y Offset to start from.
  + *  \param [in]    color_mode
  + *
  + *  \todo what happens if snap is off? hack deal with this !!!!!!!!
  + */
  +void f_image_write_objects(TOPLEVEL *w_current, OBJECT *head, 
  +			   int start_x, int start_y,
  +			   float scale, int color_mode)
  +{
  +  OBJECT *o_current=NULL;
  +  int origin_x, origin_y;
  +	
  +  if (head == NULL) {
  +    return;
  +  }
  +
  +  origin_x = 0;
  +  origin_y = 0;
  +
  +  o_current = head;
  +
  +
  +  while ( o_current != NULL ) {
  +
  +    if (o_current->type != OBJ_HEAD) {
  +
  +      switch (o_current->type) {
  +        case(OBJ_LINE):
  +          o_line_image_write(w_current, o_current,
  +                             origin_x, origin_y, color_mode);
  +          break;
  +
  +        case(OBJ_PIN):
  +          o_pin_image_write(w_current, o_current,
  +                            origin_x, origin_y, color_mode);
  +          break;
  +
  +        case(OBJ_COMPLEX):
  +        case(OBJ_PLACEHOLDER):
  +
  +          f_image_write_objects(w_current, 
  +                                o_current->complex->prim_objs,
  +                                origin_x, origin_y, scale, color_mode);
  +          break;
  +
  +        case(OBJ_TEXT):
  +          if (o_current->visibility == VISIBLE) {
  +			
  +            /*if (w_current->text_output == VECTOR_FONTS) {	*/
  +            f_image_write_objects(w_current, 
  +                                  o_current->text->
  +                                  prim_objs,
  +                                  origin_x, origin_y, scale, color_mode);
  +            /*} else {*/
  +#if 0
  +            o_text_image_write(w_current, fp, 
  +                               o_current,
  +                               origin_x, origin_y);
  +
  +            /*}*/
  +#endif
  +
  +          }
  +          break;
  +
  +        case(OBJ_NET):
  +          o_net_image_write(w_current, o_current,
  +                            origin_x, origin_y, color_mode);
  +
  +          break;
  +
  +        case(OBJ_BUS):
  +          o_bus_image_write(w_current, o_current,
  +                            origin_x, origin_y, color_mode);
  +          break;
  +
  +        case(OBJ_CIRCLE):
  +          o_circle_image_write(w_current, 
  +                               o_current,
  +                               origin_x, origin_y, color_mode);
  +          break;
  +
  +        case(OBJ_ARC):
  +          o_arc_image_write(w_current, o_current,
  +                            origin_x, origin_y, color_mode);
  +          break;
  +
  +        case(OBJ_BOX):
  +          o_box_image_write(w_current, o_current,
  +                            origin_x, origin_y, color_mode);
  +          break;
  +			
  +	case(OBJ_PICTURE):
  +          /*! \todo FIXME: Implement this */
  +	  fprintf(stderr, "f_image_write_objects: o_picture_image_write not implemented yet\n");
  +	  /* out = NULL; */
  +	  /* out = (char *) o_picture_image_write(w_current, o_current,
  +	     origin_x, origin_y, color_mode); */
  +	  break;
  +
  +        default:
  +          fprintf(stderr, "Error type!\n");
  +          exit(-1);
  +          break;
  +      }
  +
  +    } 
  +    o_current = o_current->next;
  +  }
  +
  +  s_cue_output_all(w_current, head, NULL, PNG);
  +
  +  return;
  +}
  +#endif
  +
  +/*! \todo Finish function description!!!
  + *  \brief Write image to file from w_current
  + *  \par Function Description
  + *
  + *  \param [in,out] w_current  The TOPLEVEL object to read image from.
  + *  \param [in]      filename  The name of the file to write image to.
  + *  \param [in]         width  The width of the image to write
  + *  \param [in]        height  The height of the image to write
  + *  \param [in]    color_mode  
  + */
  +void f_image_write(TOPLEVEL *w_current, const char *filename,
  +		   int width, int height, 
  +		   int color_mode)
  +{
  +
  +#ifdef HAS_LIBGDGEDA
  +  int origin_x, origin_y, bottom, right;
  +  float scale=0.0;
  +
  +  /* dots are breaking my filename selection hack hack !!!! */
  +	
  +
  +  /*	printf("%d %d\n", w_current->paper_width, w_current->paper_height);*/
  +
  +  world_get_complex_bounds(w_current, 
  +                           w_current->page_current->object_head, 
  +                           &origin_x, &origin_y, 
  +                           &right, &bottom);
  +
  +  o_image_create(width, height, color_mode);
  +
  +  f_image_write_objects(w_current,
  +			w_current->page_current->object_head,
  +			w_current->page_current->left,
  +			w_current->page_current->top, scale, color_mode);
  +	
  +  o_image_write(filename);
  +  o_image_close();
  +#else
  +  fprintf(stderr, "f_image_write: Called this function without libgdgeda support.\n");
  +  s_log_message("f_image_write: Called this function without libgdgeda support.\n");
  +#endif
  +
  +}
  +
  +/*! \brief Sets the image output type
  + *  \par Function Description
  + *  This function will set the image output type in the TOPLEVEL object.
  + *
  + *  \param [in,out] w_current  The TOPLEVEL object to set image type in.
  + *  \param [in]          type  The image type to set
  + */
  +void f_image_set_type(TOPLEVEL *w_current, int type)
  +{
  +  w_current->image_output_type = type;
  +}
  
  
  
  1.23      +5001 -405 eda/geda/gaf/libgeda/src/f_print.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: f_print.c
  ===================================================================
  RCS file: f_print.c
  diff -N f_print.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ f_print.c	5 Jul 2006 03:13:38 -0000	1.23
  @@ -0,0 +1,5081 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <unistd.h>
  +#include <time.h>
  +#include <math.h>
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "funcs.h"
  +#include "colors.h"
  +
  +#include "../include/prototype.h"
  +
  +/*! \brief Hashtable storing mapping between character and
  + *         postscript glyph name
  + */
  +GHashTable *unicode_char_to_glyph = NULL;
  +
  +static int f_print_get_unicode_chars(TOPLEVEL * w_current, OBJECT * head,
  +				     int count, gunichar * table);
  +static void f_print_unicode_map(FILE * fp, int count, gunichar * table);
  +
  +/*! \brief Prints the line width in mils to a postscript document.
  + *  \par Function Description
  + *  This function writes the line width in mils to the specified
  + *  postscript document.
  + *
  + *  \param [in]     fp     The postscript document to write to.
  + *  \param [in]     width  The width of the line in mils to set.
  + */
  +void f_print_set_line_width(FILE *fp, int width)
  +{
  +  if (width > 0) {
  +    fprintf(fp, "%d mils setlinewidth\n", width);
  +  }
  +}
  +
  +/*! \brief Prints the color to a postscript document
  + *  \par Function Description
  + *  This function converts the color number passed to a string
  + *  and prints it to the postscript document provided.
  + *
  + *  \param [in]     fp     The postscript document to print the color to.
  + *  \param [in]     color  Integer color to convert and print.
  + */
  +void f_print_set_color(FILE *fp, int color) 
  +{
  +  char *string;
  +
  +  /* DO NOT free string... it's a reference to a malloced */
  +  /* string, there is *no* memory leak here */
  +  string = s_color_ps_string(color);
  +
  +  if (string) {
  +    fprintf(fp, "%s setrgbcolor\n", string);
  +  } else {
  +    fprintf(fp, "0 0 0 setrgbcolor\n");
  +  }
  +}
  +
  +/*! \brief Prints the header to a postscript document.
  + *  \par Function Description
  + *  This function will print a document preamble and header
  + *  for a postscript document.
  + *
  + *  \param [in] w_current     The TOPLEVEL object to create document for.
  + *  \param [in] fp            The postscript document to write to.
  + *  \param [in] paper_size_x  The width of the document on paper in inches.
  + *  \param [in] paper_size_y  The height of the document on paper in inches.
  + *  \return 1 on success, 0 on failure.
  + */
  +int f_print_header(TOPLEVEL *w_current, FILE *fp, 
  +		   int paper_size_x, int paper_size_y) 
  +{
  +  char *buf;
  +  FILE *prolog;
  +  size_t bytes;
  +  int llx,lly,urx,ury;
  +  time_t current_time,time_rc;
  +
  +  /* Compute bounding box */
  +  llx=0;                          /* So, right now, the box starts at (0,0) */
  +  lly=0;
  +  urx=((float)paper_size_y * 72.0)/1000; 
  +  ury=((float)paper_size_x * 72.0)/1000; 
  +  
  +  /* Get Time of day for creation date */
  +  time_rc = time(&current_time);
  +  if(time_rc == (time_t)-1) {
  +    s_log_message("Unable to get time of day in f_print_header()\n");
  +    current_time=0; /* Just set it to 1970... */
  +  }
  +
  +  /* Output the DSC comments at the beginning of the document */
  +  fprintf(fp, "%%!PS-Adobe-3.0\n"
  +	  "%%%%Creator: gEDA gschem %s\n"
  +	  "%%%%CreationDate: %s"
  +	  "%%%%Title: %s\n"
  +	  "%%%%Author: %s\n"
  +	  "%%%%BoundingBox: %d %d %d %d\n"
  +	  "%%%%Pages: 1\n"
  +	  "%%%%Endcomments\n"
  +	  "%%%%BeginProlog\n",
  +	  VERSION,
  +	  ctime(&current_time),
  +	  w_current->page_current->page_filename,
  +	  getlogin(),
  +	  llx, lly, urx, ury
  +	  );
  +
  +  /* Fetch and insert the Postscript prolog from disk here */
  +  
  +  /* Allocate a buffer to use during copy */
  +#define PROLOG_BUFFER_SIZE 8192
  +  buf = malloc(PROLOG_BUFFER_SIZE);
  +  if(buf == NULL) {
  +    s_log_message("Unable to allocate %d bytes in f_print_header()\n"
  +		  "Giving up on printing.\n",PROLOG_BUFFER_SIZE);
  +    return 0;
  +  }
  +  /* Open the prolog file */
  +  prolog = fopen(w_current->postscript_prolog,"r");
  +  if(prolog == NULL) {
  +    s_log_message("Unable to open the prolog file `%s' for reading "
  +		  "in f_print_header()\n"
  +		  "Giving up on printing\n", w_current->postscript_prolog);
  +    free(buf);  /* If we got to here, the buffer was allocated. */
  +    return 0;
  +  }
  +  /* Loop while reading file into buffer and dump it
  +   * back out to the supplied file handle
  +   */
  +  do {
  +    bytes = fread(buf, 1, PROLOG_BUFFER_SIZE, prolog);
  +    if(ferror(prolog)) break;
  +    fwrite(buf, 1, bytes, fp);
  +  } while(!feof(prolog) && !ferror(prolog) && !ferror(fp));
  +
  +  if(ferror(prolog)) {
  +    s_log_message("Error during reading of the prolog file `%s' "
  +		  "in f_print_header()\n"
  +		  "Giving up on printing\n", w_current->postscript_prolog);
  +    free(buf);  /* If we got to here, the buffer was allocated. */
  +    return 0;
  +  }
  +
  +  if(ferror(fp)) {
  +    s_log_message("Error during writing of the output postscript file "
  +		  "in f_print_header()\n"
  +		  "Giving up on printing\n");
  +    free(buf);  /* If we got to here, the buffer was allocated. */
  +    return 0;
  +  }
  +  free(buf);  /* If we got to here, the buffer was allocated. */
  +
  +  fprintf(fp,"%%%%EndProlog\n"
  +	  "%%%%Page: 1 1\n");     /* Just name it `page 1' for now */
  +  
  +  /* These go after the prolog ends because they affect the graphics
  +   * state
  +   */
  +
  +  return 0;
  +}
  +
  +/*! \brief Prints the footer to a postscript document
  + *  \par Function Description
  + *  This function will print a document footer and end
  + *  a postscript document.
  + *  
  + *  \param [in] fp The postscript document to write footer to.
  + */
  +void f_print_footer(FILE *fp)
  +{
  +  fprintf(fp,"showpage\n"
  +	  "%%%%End\n");
  +}
  +
  +/*! \brief Print all objects from the w_current TOPLEVEL object.
  + *  \par Function Description
  + *  This function will parse the head parameter for all objects
  + *  and write the to the postscript document.
  + *
  + *  \param [in] w_current      The current TOPLEVEL object.
  + *  \param [in] fp             The postscript document to print to.
  + *  \param [in] head           Container for objects to be printed.
  + *  \param [in] start_x        X origin on page to start printing objects.
  + *  \param [in] start_y        Y origin on page to start printing objects.
  + *  \param [in] scale          Scale factor for object output.
  + *  \param [in] unicode_count  Number of items in unicode table.
  + *  \param [in] unicode_table  Table of unicode items.
  + *  \return void
  + *
  + *  \todo  what happens if snap is off? hack deal with this !!!!!!!!
  + */
  +void f_print_objects(TOPLEVEL *w_current, FILE *fp, OBJECT *head, 
  +		     int start_x, int start_y, float scale, 
  +		     int unicode_count, gunichar *unicode_table)
  +{
  +  OBJECT *o_current=NULL;
  +  int origin_x, origin_y;
  +	
  +  origin_x = start_x;
  +  origin_y = start_y;
  +
  +  if (head == NULL) {
  +    return;
  +  }
  +
  +  /* Apply a translation to move the origin to where we want it */
  +  if (origin_x != 0 && origin_y != 0) {
  +    fprintf(fp, "%d %d translate\n", -origin_x, -origin_y);
  +  } 
  +
  +
  +  /* no longer change the coords, the postscript translate takes care 
  +   * of this */
  +  origin_x = 0;
  +  origin_y = 0;
  +
  +  o_current = head;
  +
  +  while ( o_current != NULL ) {
  +
  +    if (o_current->type != OBJ_HEAD) {
  +
  +      switch (o_current->type) {
  +        case(OBJ_LINE):
  +          o_line_print(w_current, fp, o_current,
  +                       origin_x, origin_y);
  +          break;
  +	
  +        case(OBJ_NET):
  +          o_net_print(w_current, fp, o_current,
  +                      origin_x, origin_y);
  +          break;
  +
  +        case(OBJ_BUS):
  +          o_bus_print(w_current, fp, o_current,
  +                      origin_x, origin_y);
  +          break;
  +	
  +        case(OBJ_BOX):
  +          o_box_print(w_current, fp, o_current,
  +                      origin_x, origin_y);
  +          break;
  +			
  +        case(OBJ_CIRCLE):
  +          o_circle_print(w_current, fp, o_current,
  +                         origin_x, origin_y);
  +          break;
  +
  +        case(OBJ_COMPLEX):
  +        case(OBJ_PLACEHOLDER): /* new object -- 1.20.2005 SDB */
  +          fprintf(fp, "gsave\n");
  +
  +          f_print_objects(w_current, fp, 
  +                          o_current->complex->prim_objs,
  +                          origin_x, origin_y, scale,
  +			  unicode_count, unicode_table);
  +          fprintf(fp, "grestore\n");
  +          break;
  +
  +        case(OBJ_TEXT):
  +          if (o_current->visibility == VISIBLE) {
  +	    int vectors = 0;
  +
  +	    /* Look at flags and determine if vector text should
  +	     * be used for output.
  +	     */
  +	    if(w_current->text_output == VECTOR_FONTS) {
  +	      vectors = 1;
  +	    } else if( (w_current->print_vector_threshold > 0)
  +			&& ( o_text_num_lines(o_current->text->string) > 
  +			     w_current->print_vector_threshold)) {
  +	      vectors = 1;
  +	    }
  +            
  +            fprintf(fp, "gsave\n");
  +			
  +            if (vectors)
  +            {	
  +	      /* Output vectors */
  +              f_print_objects(w_current, 
  +                              fp, 
  +                              o_current->text->
  +                              prim_objs,
  +                              origin_x, origin_y, 
  +                              scale, unicode_count, unicode_table);
  +            } else {
  +	      /* Output text */
  +              o_text_print(w_current, fp, 
  +                           o_current,
  +                           origin_x, origin_y, unicode_count, unicode_table);
  +            }
  +
  +            fprintf(fp, "grestore\n");
  +          }
  +          break;
  +
  +
  +        case(OBJ_PIN):
  +          o_pin_print(w_current, fp, o_current,
  +                      origin_x, origin_y);
  +          break;
  +	
  +        case(OBJ_ARC):
  +          o_arc_print(w_current, fp, o_current,
  +                      origin_x, origin_y);
  +          break;
  +
  +  	case(OBJ_PICTURE):
  +          o_picture_print(w_current, fp, o_current,
  +			  origin_x, origin_y);
  +	  break;
  +
  +        default:
  +          fprintf(stderr, "Error type!\n");
  +          exit(-1);
  +          break;
  +      }
  +
  +    } 
  +    o_current = o_current->next;
  +  }
  +
  +  s_cue_output_all(w_current, head, fp, POSTSCRIPT);
  +  return;
  +}
  +
  +/*! \brief Print the current TOPLEVEL object to a postscript document.
  + *  \par Function Description
  + *
  + *  \param [in] w_current  The TOPLEVEL object to print.
  + *  \param [in] filename   The file name of the output postscript document.
  + *  \return 0 on success, -1 on failure.
  + */
  +int f_print(TOPLEVEL *w_current, const char *filename)
  +{
  +  FILE *fp;
  +  int origin_x, origin_y, bottom, right;
  +  int margin_x, margin_y;
  +  int dx,dy;
  +  float scale;
  +  int unicode_count;
  +  gunichar unicode_table [128];  /* to contain the list of unicode
  +				    characters that need mapping */
  +
  +
  +  /* Unicode support */
  +  f_print_initialize_glyph_table();  /* Fill up unicode map */
  +
  +  /* Find all the unicode characters */
  +  unicode_count = f_print_get_unicode_chars(w_current,
  +			 w_current->page_current->object_head, 
  +			 0, unicode_table);
  +
  +
  +  /* dots are breaking my filename selection hack hack !!!! */
  +  fp = fopen(filename, "w");
  +
  +  /* check to see if it worked */ 
  +  if (fp == NULL) {
  +    s_log_message("Could not open [%s] for printing\n", filename);
  +    return(-1);
  +  }
  +
  +  /*	printf("%d %d\n", w_current->paper_width, w_current->paper_height);*/
  +
  +  world_get_complex_bounds(w_current, 
  +                           w_current->page_current->object_head, 
  +                           &origin_x, &origin_y, 
  +                           &right, &bottom);
  +
  +  /* Calculate scale factor that will make the image fit on the page */
  +  dx = 0; dy = 0;
  +  margin_x = 0; margin_y = 0;
  +  switch (w_current->print_output_type) {
  +  case EXTENTS:
  +    dx = right  - origin_x;
  +    dy = bottom - origin_y;
  +    
  +    /* Add a 10% margin */
  +    margin_x = dx/10;
  +    margin_y = dy/10;
  +    dx = dx + margin_x;
  +    dy = dy + margin_y;
  +    break;
  +
  +  case WINDOW:
  +    dx = w_current->page_current->right - w_current->page_current->left;
  +    dy = w_current->page_current->bottom - w_current->page_current->top;
  +    origin_x = w_current->page_current->left;
  +    origin_y = w_current->page_current->top;
  +    right = w_current->page_current->right;
  +    bottom = w_current->page_current->bottom;
  +    break;
  +
  +  case EXTENTS_NOMARGINS:
  +    dx = right  - origin_x;
  +    dy = bottom - origin_y;
  +    break;
  +
  +  default:
  +    break;
  +
  +  }
  +
  +  scale = 0.0;
  +  if(w_current->print_orientation == LANDSCAPE) {
  +    /* First attempt to fit in x direction. */
  +    scale = w_current->paper_width / (float)dx;
  +    if((w_current->paper_height / (float)dy) < scale ) {
  +      /* Else fit with y direction */
  +      scale = (w_current->paper_height / (float)dy);
  +    }
  +  } else { /* portrait */
  +    /* First attempt to fit in y direction. */
  +    scale = w_current->paper_width / (float) dy;
  +    if((w_current->paper_height / (float)dx) < scale ) {
  +      /* Else fit with x direction */
  +      scale = (w_current->paper_height / (float)dx);
  +    }
  +  }
  +
  +#if 0
  +  /* Debug */
  +  printf("dx: %d dy:%d, origin_x:%d origin_y:%d, right:%d bottom:%d\n",
  +	 dx,dy,origin_x,origin_y,right,bottom);
  +  printf("scale:%f\n",scale);
  +#endif  
  +
  +  /* Output the header */
  +  f_print_header(w_current, fp, 
  +		 w_current->paper_width, 
  +		 w_current->paper_height);
  +
  +  /* Output font re-encoding */
  +  if (unicode_count) {
  +    f_print_unicode_map(fp, unicode_count, unicode_table);
  +    /* output font re-encodeing command, use our re-encoding */
  +    fprintf(fp,"/gEDAFont UTFencoding /Helvetica RE\n");
  +  } else {
  +    /* Otherwise, use LATIN1 extended encoding from prolog */
  +    fprintf(fp,"/gEDAFont ISOLatin1Extended /Helvetica RE\n");
  +  }
  +
  +
  +  /* XXX - Do page orientation selection */
  +
  +/*   if (w_current->setpagedevice_orientation) { */
  +/*     if (w_current->print_orientation == LANDSCAPE) { */
  +/*       fprintf(fp, "%c%c /Orientation 1 %c%c setpagedevice\n\n", '<', '<', */
  +/*               '>', '>'); */
  +/*     } else { */
  +/*       fprintf(fp, "%c%c /Orientation 0 %c%c setpagedevice\n\n", '<', '<', */
  +/*               '>', '>'); */
  +/*     } */
  +/*   } */
  +
  +  /* the height and width are in the right order here, since they were
  +   * specified in landscape order in the system-gschemrc file.
  +   * \074 is '<', \076 is '>' */
  +  if (w_current->setpagedevice_pagesize) {
  +    fprintf(fp, "\074\074 /PageSize [%d %d] \076\076 setpagedevice\n",
  +            (w_current->paper_height * 72) / MILS_PER_INCH,
  +            (w_current->paper_width * 72) / MILS_PER_INCH);
  +  }
  +
  +
  +  /* Set line end style */
  +  if (w_current->print_output_capstyle == BUTT_CAP) {
  +    fprintf(fp, "0 setlinecap\n");
  +  } else if (w_current->print_output_capstyle == SQUARE_CAP) {
  +    fprintf(fp, "2 setlinecap\n");
  +  } else if (w_current->print_output_capstyle == ROUND_CAP) {
  +    fprintf(fp, "1 setlinecap\n");
  +  }
  +
  +  /* Apply mils to postscript native units scaling to CTM */
  +  fprintf(fp,"%f %f scale\n",
  +	  72.0 / 1000.0 , 72.0 / 1000.0);
  +
  +  /* Now the output is defined in terms of mils */
  +  /* Draw a box with the background colour covering the whole page */
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, w_current->print_color_background);
  +    fprintf(fp,"%d %d 0 0 fbox\n",
  +	    w_current->paper_height,
  +	    w_current->paper_width);
  +  }
  +
  +  /* Now rotate and translate the graphics to fit onto the desired
  +   * page with the orientation we want. Center it too */
  +  if(w_current->print_orientation == LANDSCAPE) {
  +    fprintf(fp,
  +	    "%d %d translate 90 rotate\n",
  +	    (int)((w_current->paper_height + ( dy-margin_y) * scale)/2.0),
  +	    (int)((w_current->paper_width  + (-dx+margin_x) * scale)/2.0));
  +  } else { /* portrait */
  +    fprintf(fp,"%d %d translate\n",
  +	    (int)((w_current->paper_height + (-dx + margin_x) * scale)/2.0),
  +	    (int)((w_current->paper_width  + (-dy + margin_y) * scale)/2.0));
  +
  +  }
  +
  +  /* Now apply final mils to output scaling factor */
  +  fprintf(fp,"%f %f scale\n",
  +	  scale, scale);
  +
  +  /* Print the objects */
  +  f_print_objects(w_current, fp, 
  +		  w_current->page_current->object_head,
  +		  origin_x, origin_y, scale, unicode_count, unicode_table);
  +
  +  f_print_footer(fp);
  +
  +  fclose(fp);
  +  return(0);
  +}
  +
  +/*! \brief Sets the current TOPLEVEL object output type
  + *  \par Function Description
  + *  Sets the current TOPLEVEL object output type.
  + *
  + *  \param [in,out] w_current  The TOPLEVEL object to set output type in.
  + *  \param [in]     type       The print type to set.
  + */
  +void f_print_set_type(TOPLEVEL *w_current, int type)
  +{
  +  w_current->print_output_type = type;
  +}
  +
  +/*! \brief Converts all text strings to unicode format.
  + *  \par Function Description
  + *  Converts all text strings to unicode format.
  + *
  + *  \param [in,out] w_current  The output TOPLEVEL element to store converted
  + *                             strings in.
  + *  \param [in]     head       The object containing strings for conversion.
  + *  \param [in]     count      The number of elements in the unicode table.
  + *  \param [in]     table      The unicode table.
  + *  \return count on success, 0 otherwise.
  + */
  +static int f_print_get_unicode_chars(TOPLEVEL *w_current, OBJECT *head,
  +				     int count, gunichar *table)
  +{
  +  OBJECT *o_current = NULL;
  +  gchar *aux;
  +  gunichar current_char;
  +  int i, found;
  +
  +  if (head == NULL) {
  +    return(0);
  +  }
  +
  +  o_current = head;
  +
  +  while (o_current != NULL) {
  +
  +    if (o_current->type != OBJ_HEAD) {
  +
  +      switch (o_current->type) {
  +
  +      case (OBJ_COMPLEX):
  +      case (OBJ_PLACEHOLDER):	/* new object -- 1.20.2005 SDB */
  +
  +	count = f_print_get_unicode_chars(w_current, 
  +                                          o_current->complex->prim_objs, 
  +                                          count, table);
  +	break;
  +
  +      case (OBJ_TEXT):
  +	if (o_current->visibility == VISIBLE) {
  +
  +          aux = o_current->text->string;
  +          while (aux && ((gunichar) (*aux) != 0)) {
  +            current_char = g_utf8_get_char_validated(aux, -1);
  +            if (current_char >= 127) {
  +	      found = 0;  
  +	      i = 0;
  +	      while (i < count) {
  +	        if (table[i] == current_char)
  +	          found = 1;
  +		i++;  
  +	      }
  +              if (!found) {
  +	        if (count < 128)
  +		  table[count++] = current_char;
  +	        else 
  +	          s_log_message("Too many UTF-8 characters, cannot print\n");
  +	      }
  +	    }  
  +            aux = g_utf8_find_next_char(aux, NULL);
  +	  }
  +	}
  +	break;
  +
  +      default:
  +	break;
  +      }
  +    }
  +    o_current = o_current->next;
  +  }
  +  return (count);
  +}
  +
  +/*! \brief Prints unicode map to postscript document.
  + *  \par Function Description
  + *  Prints unicode map to postscript document.
  + *
  + *  \param [in] fp     The postscript document to write unicode map to.
  + *  \param [in] count  Size of unicode map table.
  + *  \param [in] table  The unicode map to write.
  + */
  +static void f_print_unicode_map(FILE * fp, int count, gunichar * table)
  +{
  +  unsigned int i;
  +  int line_count;
  +  char *glyph_map[256];     /* To contain the postscript remapping */
  +
  +  /* update the glyph map, undefine everything */
  +  for(i=0; i<256; i++) glyph_map[i]="/.notdef";
  +
  +  /* Now fill in the active characters */
  +  for (i=0; i<128; i++) {  /* Copy in the regular latin chars */
  +      glyph_map[i] = g_hash_table_lookup (unicode_char_to_glyph,
  +					  GUINT_TO_POINTER (i));
  +  }
  +  /* Finish by using up the rest of the spares */
  +  for (i=128; i<(count+128); i++) { 
  +    if(i < (count+128)) {
  +      glyph_map[i] = g_hash_table_lookup (unicode_char_to_glyph,
  +					  GUINT_TO_POINTER (table[i-128]));
  +    }
  +  }
  +
  +  fprintf(fp, "%%%%BeginResource: encoding UTFencoding\n");
  +  fprintf(fp, "/UTFencoding [\n");
  +  
  +  /* Output the re-encoding vector, prettily */
  +  line_count = 0;
  +  for (i=0; i<256; i++) {
  +      line_count += fprintf(fp, "%s ", glyph_map[i]);
  +      if(line_count > 60) {
  +	line_count = 0;
  +	fprintf(fp, "\n");
  +      }
  +  }
  +
  +  fprintf(fp, "] def\n");
  +  fprintf(fp, "%%%%EndResource\n");
  +}
  +
  +
  +/*! \brief */
  +static struct glyph_list {
  +  gpointer key;
  +  gpointer name;
  +} glyphs[] = {
  +  { GUINT_TO_POINTER (0x0000), "/.notdef" },
  +  { GUINT_TO_POINTER (0x0041), "/A" },
  +  { GUINT_TO_POINTER (0x00C6), "/AE" },
  +  { GUINT_TO_POINTER (0x01FC), "/AEacute" },
  +  { GUINT_TO_POINTER (0x01E2), "/AEmacron" },
  +  { GUINT_TO_POINTER (0xF7E6), "/AEsmall" },
  +  { GUINT_TO_POINTER (0x00C1), "/Aacute" },
  +  { GUINT_TO_POINTER (0xF7E1), "/Aacutesmall" },
  +  { GUINT_TO_POINTER (0x0102), "/Abreve" },
  +  { GUINT_TO_POINTER (0x1EAE), "/Abreveacute" },
  +  { GUINT_TO_POINTER (0x04D0), "/Abrevecyrillic" },
  +  { GUINT_TO_POINTER (0x1EB6), "/Abrevedotbelow" },
  +  { GUINT_TO_POINTER (0x1EB0), "/Abrevegrave" },
  +  { GUINT_TO_POINTER (0x1EB2), "/Abrevehookabove" },
  +  { GUINT_TO_POINTER (0x1EB4), "/Abrevetilde" },
  +  { GUINT_TO_POINTER (0x01CD), "/Acaron" },
  +  { GUINT_TO_POINTER (0x24B6), "/Acircle" },
  +  { GUINT_TO_POINTER (0x00C2), "/Acircumflex" },
  +  { GUINT_TO_POINTER (0x1EA4), "/Acircumflexacute" },
  +  { GUINT_TO_POINTER (0x1EAC), "/Acircumflexdotbelow" },
  +  { GUINT_TO_POINTER (0x1EA6), "/Acircumflexgrave" },
  +  { GUINT_TO_POINTER (0x1EA8), "/Acircumflexhookabove" },
  +  { GUINT_TO_POINTER (0xF7E2), "/Acircumflexsmall" },
  +  { GUINT_TO_POINTER (0x1EAA), "/Acircumflextilde" },
  +  { GUINT_TO_POINTER (0xF6C9), "/Acute" },
  +  { GUINT_TO_POINTER (0xF7B4), "/Acutesmall" },
  +  { GUINT_TO_POINTER (0x0410), "/Acyrillic" },
  +  { GUINT_TO_POINTER (0x0200), "/Adblgrave" },
  +  { GUINT_TO_POINTER (0x00C4), "/Adieresis" },
  +  { GUINT_TO_POINTER (0x04D2), "/Adieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x01DE), "/Adieresismacron" },
  +  { GUINT_TO_POINTER (0xF7E4), "/Adieresissmall" },
  +  { GUINT_TO_POINTER (0x1EA0), "/Adotbelow" },
  +  { GUINT_TO_POINTER (0x01E0), "/Adotmacron" },
  +  { GUINT_TO_POINTER (0x00C0), "/Agrave" },
  +  { GUINT_TO_POINTER (0xF7E0), "/Agravesmall" },
  +  { GUINT_TO_POINTER (0x1EA2), "/Ahookabove" },
  +  { GUINT_TO_POINTER (0x04D4), "/Aiecyrillic" },
  +  { GUINT_TO_POINTER (0x0202), "/Ainvertedbreve" },
  +  { GUINT_TO_POINTER (0x0391), "/Alpha" },
  +  { GUINT_TO_POINTER (0x0386), "/Alphatonos" },
  +  { GUINT_TO_POINTER (0x0100), "/Amacron" },
  +  { GUINT_TO_POINTER (0xFF21), "/Amonospace" },
  +  { GUINT_TO_POINTER (0x0104), "/Aogonek" },
  +  { GUINT_TO_POINTER (0x00C5), "/Aring" },
  +  { GUINT_TO_POINTER (0x01FA), "/Aringacute" },
  +  { GUINT_TO_POINTER (0x1E00), "/Aringbelow" },
  +  { GUINT_TO_POINTER (0xF7E5), "/Aringsmall" },
  +  { GUINT_TO_POINTER (0xF761), "/Asmall" },
  +  { GUINT_TO_POINTER (0x00C3), "/Atilde" },
  +  { GUINT_TO_POINTER (0xF7E3), "/Atildesmall" },
  +  { GUINT_TO_POINTER (0x0531), "/Aybarmenian" },
  +  { GUINT_TO_POINTER (0x0042), "/B" },
  +  { GUINT_TO_POINTER (0x24B7), "/Bcircle" },
  +  { GUINT_TO_POINTER (0x1E02), "/Bdotaccent" },
  +  { GUINT_TO_POINTER (0x1E04), "/Bdotbelow" },
  +  { GUINT_TO_POINTER (0x0411), "/Becyrillic" },
  +  { GUINT_TO_POINTER (0x0532), "/Benarmenian" },
  +  { GUINT_TO_POINTER (0x0392), "/Beta" },
  +  { GUINT_TO_POINTER (0x0181), "/Bhook" },
  +  { GUINT_TO_POINTER (0x1E06), "/Blinebelow" },
  +  { GUINT_TO_POINTER (0xFF22), "/Bmonospace" },
  +  { GUINT_TO_POINTER (0xF6F4), "/Brevesmall" },
  +  { GUINT_TO_POINTER (0xF762), "/Bsmall" },
  +  { GUINT_TO_POINTER (0x0182), "/Btopbar" },
  +  { GUINT_TO_POINTER (0x0043), "/C" },
  +  { GUINT_TO_POINTER (0x053E), "/Caarmenian" },
  +  { GUINT_TO_POINTER (0x0106), "/Cacute" },
  +  { GUINT_TO_POINTER (0xF6CA), "/Caron" },
  +  { GUINT_TO_POINTER (0xF6F5), "/Caronsmall" },
  +  { GUINT_TO_POINTER (0x010C), "/Ccaron" },
  +  { GUINT_TO_POINTER (0x00C7), "/Ccedilla" },
  +  { GUINT_TO_POINTER (0x1E08), "/Ccedillaacute" },
  +  { GUINT_TO_POINTER (0xF7E7), "/Ccedillasmall" },
  +  { GUINT_TO_POINTER (0x24B8), "/Ccircle" },
  +  { GUINT_TO_POINTER (0x0108), "/Ccircumflex" },
  +  { GUINT_TO_POINTER (0x010A), "/Cdot" },
  +  { GUINT_TO_POINTER (0x010A), "/Cdotaccent" },
  +  { GUINT_TO_POINTER (0xF7B8), "/Cedillasmall" },
  +  { GUINT_TO_POINTER (0x0549), "/Chaarmenian" },
  +  { GUINT_TO_POINTER (0x04BC), "/Cheabkhasiancyrillic" },
  +  { GUINT_TO_POINTER (0x0427), "/Checyrillic" },
  +  { GUINT_TO_POINTER (0x04BE), "/Chedescenderabkhasiancyrillic" },
  +  { GUINT_TO_POINTER (0x04B6), "/Chedescendercyrillic" },
  +  { GUINT_TO_POINTER (0x04F4), "/Chedieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x0543), "/Cheharmenian" },
  +  { GUINT_TO_POINTER (0x04CB), "/Chekhakassiancyrillic" },
  +  { GUINT_TO_POINTER (0x04B8), "/Cheverticalstrokecyrillic" },
  +  { GUINT_TO_POINTER (0x03A7), "/Chi" },
  +  { GUINT_TO_POINTER (0x0187), "/Chook" },
  +  { GUINT_TO_POINTER (0xF6F6), "/Circumflexsmall" },
  +  { GUINT_TO_POINTER (0xFF23), "/Cmonospace" },
  +  { GUINT_TO_POINTER (0x0551), "/Coarmenian" },
  +  { GUINT_TO_POINTER (0xF763), "/Csmall" },
  +  { GUINT_TO_POINTER (0x0044), "/D" },
  +  { GUINT_TO_POINTER (0x01F1), "/DZ" },
  +  { GUINT_TO_POINTER (0x01C4), "/DZcaron" },
  +  { GUINT_TO_POINTER (0x0534), "/Daarmenian" },
  +  { GUINT_TO_POINTER (0x0189), "/Dafrican" },
  +  { GUINT_TO_POINTER (0x010E), "/Dcaron" },
  +  { GUINT_TO_POINTER (0x1E10), "/Dcedilla" },
  +  { GUINT_TO_POINTER (0x24B9), "/Dcircle" },
  +  { GUINT_TO_POINTER (0x1E12), "/Dcircumflexbelow" },
  +  { GUINT_TO_POINTER (0x0110), "/Dcroat" },
  +  { GUINT_TO_POINTER (0x1E0A), "/Ddotaccent" },
  +  { GUINT_TO_POINTER (0x1E0C), "/Ddotbelow" },
  +  { GUINT_TO_POINTER (0x0414), "/Decyrillic" },
  +  { GUINT_TO_POINTER (0x03EE), "/Deicoptic" },
  +  { GUINT_TO_POINTER (0x2206), "/Delta" },
  +  { GUINT_TO_POINTER (0x0394), "/Deltagreek" },
  +  { GUINT_TO_POINTER (0x018A), "/Dhook" },
  +  { GUINT_TO_POINTER (0xF6CB), "/Dieresis" },
  +  { GUINT_TO_POINTER (0xF6CC), "/DieresisAcute" },
  +  { GUINT_TO_POINTER (0xF6CD), "/DieresisGrave" },
  +  { GUINT_TO_POINTER (0xF7A8), "/Dieresissmall" },
  +  { GUINT_TO_POINTER (0x03DC), "/Digammagreek" },
  +  { GUINT_TO_POINTER (0x0402), "/Djecyrillic" },
  +  { GUINT_TO_POINTER (0x1E0E), "/Dlinebelow" },
  +  { GUINT_TO_POINTER (0xFF24), "/Dmonospace" },
  +  { GUINT_TO_POINTER (0xF6F7), "/Dotaccentsmall" },
  +  { GUINT_TO_POINTER (0x0110), "/Dslash" },
  +  { GUINT_TO_POINTER (0xF764), "/Dsmall" },
  +  { GUINT_TO_POINTER (0x018B), "/Dtopbar" },
  +  { GUINT_TO_POINTER (0x01F2), "/Dz" },
  +  { GUINT_TO_POINTER (0x01C5), "/Dzcaron" },
  +  { GUINT_TO_POINTER (0x04E0), "/Dzeabkhasiancyrillic" },
  +  { GUINT_TO_POINTER (0x0405), "/Dzecyrillic" },
  +  { GUINT_TO_POINTER (0x040F), "/Dzhecyrillic" },
  +  { GUINT_TO_POINTER (0x0045), "/E" },
  +  { GUINT_TO_POINTER (0x00C9), "/Eacute" },
  +  { GUINT_TO_POINTER (0xF7E9), "/Eacutesmall" },
  +  { GUINT_TO_POINTER (0x0114), "/Ebreve" },
  +  { GUINT_TO_POINTER (0x011A), "/Ecaron" },
  +  { GUINT_TO_POINTER (0x1E1C), "/Ecedillabreve" },
  +  { GUINT_TO_POINTER (0x0535), "/Echarmenian" },
  +  { GUINT_TO_POINTER (0x24BA), "/Ecircle" },
  +  { GUINT_TO_POINTER (0x00CA), "/Ecircumflex" },
  +  { GUINT_TO_POINTER (0x1EBE), "/Ecircumflexacute" },
  +  { GUINT_TO_POINTER (0x1E18), "/Ecircumflexbelow" },
  +  { GUINT_TO_POINTER (0x1EC6), "/Ecircumflexdotbelow" },
  +  { GUINT_TO_POINTER (0x1EC0), "/Ecircumflexgrave" },
  +  { GUINT_TO_POINTER (0x1EC2), "/Ecircumflexhookabove" },
  +  { GUINT_TO_POINTER (0xF7EA), "/Ecircumflexsmall" },
  +  { GUINT_TO_POINTER (0x1EC4), "/Ecircumflextilde" },
  +  { GUINT_TO_POINTER (0x0404), "/Ecyrillic" },
  +  { GUINT_TO_POINTER (0x0204), "/Edblgrave" },
  +  { GUINT_TO_POINTER (0x00CB), "/Edieresis" },
  +  { GUINT_TO_POINTER (0xF7EB), "/Edieresissmall" },
  +  { GUINT_TO_POINTER (0x0116), "/Edot" },
  +  { GUINT_TO_POINTER (0x0116), "/Edotaccent" },
  +  { GUINT_TO_POINTER (0x1EB8), "/Edotbelow" },
  +  { GUINT_TO_POINTER (0x0424), "/Efcyrillic" },
  +  { GUINT_TO_POINTER (0x00C8), "/Egrave" },
  +  { GUINT_TO_POINTER (0xF7E8), "/Egravesmall" },
  +  { GUINT_TO_POINTER (0x0537), "/Eharmenian" },
  +  { GUINT_TO_POINTER (0x1EBA), "/Ehookabove" },
  +  { GUINT_TO_POINTER (0x2167), "/Eightroman" },
  +  { GUINT_TO_POINTER (0x0206), "/Einvertedbreve" },
  +  { GUINT_TO_POINTER (0x0464), "/Eiotifiedcyrillic" },
  +  { GUINT_TO_POINTER (0x041B), "/Elcyrillic" },
  +  { GUINT_TO_POINTER (0x216A), "/Elevenroman" },
  +  { GUINT_TO_POINTER (0x0112), "/Emacron" },
  +  { GUINT_TO_POINTER (0x1E16), "/Emacronacute" },
  +  { GUINT_TO_POINTER (0x1E14), "/Emacrongrave" },
  +  { GUINT_TO_POINTER (0x041C), "/Emcyrillic" },
  +  { GUINT_TO_POINTER (0xFF25), "/Emonospace" },
  +  { GUINT_TO_POINTER (0x041D), "/Encyrillic" },
  +  { GUINT_TO_POINTER (0x04A2), "/Endescendercyrillic" },
  +  { GUINT_TO_POINTER (0x014A), "/Eng" },
  +  { GUINT_TO_POINTER (0x04A4), "/Enghecyrillic" },
  +  { GUINT_TO_POINTER (0x04C7), "/Enhookcyrillic" },
  +  { GUINT_TO_POINTER (0x0118), "/Eogonek" },
  +  { GUINT_TO_POINTER (0x0190), "/Eopen" },
  +  { GUINT_TO_POINTER (0x0395), "/Epsilon" },
  +  { GUINT_TO_POINTER (0x0388), "/Epsilontonos" },
  +  { GUINT_TO_POINTER (0x0420), "/Ercyrillic" },
  +  { GUINT_TO_POINTER (0x018E), "/Ereversed" },
  +  { GUINT_TO_POINTER (0x042D), "/Ereversedcyrillic" },
  +  { GUINT_TO_POINTER (0x0421), "/Escyrillic" },
  +  { GUINT_TO_POINTER (0x04AA), "/Esdescendercyrillic" },
  +  { GUINT_TO_POINTER (0x01A9), "/Esh" },
  +  { GUINT_TO_POINTER (0xF765), "/Esmall" },
  +  { GUINT_TO_POINTER (0x0397), "/Eta" },
  +  { GUINT_TO_POINTER (0x0538), "/Etarmenian" },
  +  { GUINT_TO_POINTER (0x0389), "/Etatonos" },
  +  { GUINT_TO_POINTER (0x00D0), "/Eth" },
  +  { GUINT_TO_POINTER (0xF7F0), "/Ethsmall" },
  +  { GUINT_TO_POINTER (0x1EBC), "/Etilde" },
  +  { GUINT_TO_POINTER (0x1E1A), "/Etildebelow" },
  +  { GUINT_TO_POINTER (0x20AC), "/Euro" },
  +  { GUINT_TO_POINTER (0x01B7), "/Ezh" },
  +  { GUINT_TO_POINTER (0x01EE), "/Ezhcaron" },
  +  { GUINT_TO_POINTER (0x01B8), "/Ezhreversed" },
  +  { GUINT_TO_POINTER (0x0046), "/F" },
  +  { GUINT_TO_POINTER (0x24BB), "/Fcircle" },
  +  { GUINT_TO_POINTER (0x1E1E), "/Fdotaccent" },
  +  { GUINT_TO_POINTER (0x0556), "/Feharmenian" },
  +  { GUINT_TO_POINTER (0x03E4), "/Feicoptic" },
  +  { GUINT_TO_POINTER (0x0191), "/Fhook" },
  +  { GUINT_TO_POINTER (0x0472), "/Fitacyrillic" },
  +  { GUINT_TO_POINTER (0x2164), "/Fiveroman" },
  +  { GUINT_TO_POINTER (0xFF26), "/Fmonospace" },
  +  { GUINT_TO_POINTER (0x2163), "/Fourroman" },
  +  { GUINT_TO_POINTER (0xF766), "/Fsmall" },
  +  { GUINT_TO_POINTER (0x0047), "/G" },
  +  { GUINT_TO_POINTER (0x3387), "/GBsquare" },
  +  { GUINT_TO_POINTER (0x01F4), "/Gacute" },
  +  { GUINT_TO_POINTER (0x0393), "/Gamma" },
  +  { GUINT_TO_POINTER (0x0194), "/Gammaafrican" },
  +  { GUINT_TO_POINTER (0x03EA), "/Gangiacoptic" },
  +  { GUINT_TO_POINTER (0x011E), "/Gbreve" },
  +  { GUINT_TO_POINTER (0x01E6), "/Gcaron" },
  +  { GUINT_TO_POINTER (0x0122), "/Gcedilla" },
  +  { GUINT_TO_POINTER (0x24BC), "/Gcircle" },
  +  { GUINT_TO_POINTER (0x011C), "/Gcircumflex" },
  +  { GUINT_TO_POINTER (0x0122), "/Gcommaaccent" },
  +  { GUINT_TO_POINTER (0x0120), "/Gdot" },
  +  { GUINT_TO_POINTER (0x0120), "/Gdotaccent" },
  +  { GUINT_TO_POINTER (0x0413), "/Gecyrillic" },
  +  { GUINT_TO_POINTER (0x0542), "/Ghadarmenian" },
  +  { GUINT_TO_POINTER (0x0494), "/Ghemiddlehookcyrillic" },
  +  { GUINT_TO_POINTER (0x0492), "/Ghestrokecyrillic" },
  +  { GUINT_TO_POINTER (0x0490), "/Gheupturncyrillic" },
  +  { GUINT_TO_POINTER (0x0193), "/Ghook" },
  +  { GUINT_TO_POINTER (0x0533), "/Gimarmenian" },
  +  { GUINT_TO_POINTER (0x0403), "/Gjecyrillic" },
  +  { GUINT_TO_POINTER (0x1E20), "/Gmacron" },
  +  { GUINT_TO_POINTER (0xFF27), "/Gmonospace" },
  +  { GUINT_TO_POINTER (0xF6CE), "/Grave" },
  +  { GUINT_TO_POINTER (0xF760), "/Gravesmall" },
  +  { GUINT_TO_POINTER (0xF767), "/Gsmall" },
  +  { GUINT_TO_POINTER (0x029B), "/Gsmallhook" },
  +  { GUINT_TO_POINTER (0x01E4), "/Gstroke" },
  +  { GUINT_TO_POINTER (0x0048), "/H" },
  +  { GUINT_TO_POINTER (0x25CF), "/H18533" },
  +  { GUINT_TO_POINTER (0x25AA), "/H18543" },
  +  { GUINT_TO_POINTER (0x25AB), "/H18551" },
  +  { GUINT_TO_POINTER (0x25A1), "/H22073" },
  +  { GUINT_TO_POINTER (0x33CB), "/HPsquare" },
  +  { GUINT_TO_POINTER (0x04A8), "/Haabkhasiancyrillic" },
  +  { GUINT_TO_POINTER (0x04B2), "/Hadescendercyrillic" },
  +  { GUINT_TO_POINTER (0x042A), "/Hardsigncyrillic" },
  +  { GUINT_TO_POINTER (0x0126), "/Hbar" },
  +  { GUINT_TO_POINTER (0x1E2A), "/Hbrevebelow" },
  +  { GUINT_TO_POINTER (0x1E28), "/Hcedilla" },
  +  { GUINT_TO_POINTER (0x24BD), "/Hcircle" },
  +  { GUINT_TO_POINTER (0x0124), "/Hcircumflex" },
  +  { GUINT_TO_POINTER (0x1E26), "/Hdieresis" },
  +  { GUINT_TO_POINTER (0x1E22), "/Hdotaccent" },
  +  { GUINT_TO_POINTER (0x1E24), "/Hdotbelow" },
  +  { GUINT_TO_POINTER (0xFF28), "/Hmonospace" },
  +  { GUINT_TO_POINTER (0x0540), "/Hoarmenian" },
  +  { GUINT_TO_POINTER (0x03E8), "/Horicoptic" },
  +  { GUINT_TO_POINTER (0xF768), "/Hsmall" },
  +  { GUINT_TO_POINTER (0xF6CF), "/Hungarumlaut" },
  +  { GUINT_TO_POINTER (0xF6F8), "/Hungarumlautsmall" },
  +  { GUINT_TO_POINTER (0x3390), "/Hzsquare" },
  +  { GUINT_TO_POINTER (0x0049), "/I" },
  +  { GUINT_TO_POINTER (0x042F), "/IAcyrillic" },
  +  { GUINT_TO_POINTER (0x0132), "/IJ" },
  +  { GUINT_TO_POINTER (0x042E), "/IUcyrillic" },
  +  { GUINT_TO_POINTER (0x00CD), "/Iacute" },
  +  { GUINT_TO_POINTER (0xF7ED), "/Iacutesmall" },
  +  { GUINT_TO_POINTER (0x012C), "/Ibreve" },
  +  { GUINT_TO_POINTER (0x01CF), "/Icaron" },
  +  { GUINT_TO_POINTER (0x24BE), "/Icircle" },
  +  { GUINT_TO_POINTER (0x00CE), "/Icircumflex" },
  +  { GUINT_TO_POINTER (0xF7EE), "/Icircumflexsmall" },
  +  { GUINT_TO_POINTER (0x0406), "/Icyrillic" },
  +  { GUINT_TO_POINTER (0x0208), "/Idblgrave" },
  +  { GUINT_TO_POINTER (0x00CF), "/Idieresis" },
  +  { GUINT_TO_POINTER (0x1E2E), "/Idieresisacute" },
  +  { GUINT_TO_POINTER (0x04E4), "/Idieresiscyrillic" },
  +  { GUINT_TO_POINTER (0xF7EF), "/Idieresissmall" },
  +  { GUINT_TO_POINTER (0x0130), "/Idot" },
  +  { GUINT_TO_POINTER (0x0130), "/Idotaccent" },
  +  { GUINT_TO_POINTER (0x1ECA), "/Idotbelow" },
  +  { GUINT_TO_POINTER (0x04D6), "/Iebrevecyrillic" },
  +  { GUINT_TO_POINTER (0x0415), "/Iecyrillic" },
  +  { GUINT_TO_POINTER (0x2111), "/Ifraktur" },
  +  { GUINT_TO_POINTER (0x00CC), "/Igrave" },
  +  { GUINT_TO_POINTER (0xF7EC), "/Igravesmall" },
  +  { GUINT_TO_POINTER (0x1EC8), "/Ihookabove" },
  +  { GUINT_TO_POINTER (0x0418), "/Iicyrillic" },
  +  { GUINT_TO_POINTER (0x020A), "/Iinvertedbreve" },
  +  { GUINT_TO_POINTER (0x0419), "/Iishortcyrillic" },
  +  { GUINT_TO_POINTER (0x012A), "/Imacron" },
  +  { GUINT_TO_POINTER (0x04E2), "/Imacroncyrillic" },
  +  { GUINT_TO_POINTER (0xFF29), "/Imonospace" },
  +  { GUINT_TO_POINTER (0x053B), "/Iniarmenian" },
  +  { GUINT_TO_POINTER (0x0401), "/Iocyrillic" },
  +  { GUINT_TO_POINTER (0x012E), "/Iogonek" },
  +  { GUINT_TO_POINTER (0x0399), "/Iota" },
  +  { GUINT_TO_POINTER (0x0196), "/Iotaafrican" },
  +  { GUINT_TO_POINTER (0x03AA), "/Iotadieresis" },
  +  { GUINT_TO_POINTER (0x038A), "/Iotatonos" },
  +  { GUINT_TO_POINTER (0xF769), "/Ismall" },
  +  { GUINT_TO_POINTER (0x0197), "/Istroke" },
  +  { GUINT_TO_POINTER (0x0128), "/Itilde" },
  +  { GUINT_TO_POINTER (0x1E2C), "/Itildebelow" },
  +  { GUINT_TO_POINTER (0x0474), "/Izhitsacyrillic" },
  +  { GUINT_TO_POINTER (0x0476), "/Izhitsadblgravecyrillic" },
  +  { GUINT_TO_POINTER (0x004A), "/J" },
  +  { GUINT_TO_POINTER (0x0541), "/Jaarmenian" },
  +  { GUINT_TO_POINTER (0x24BF), "/Jcircle" },
  +  { GUINT_TO_POINTER (0x0134), "/Jcircumflex" },
  +  { GUINT_TO_POINTER (0x0408), "/Jecyrillic" },
  +  { GUINT_TO_POINTER (0x054B), "/Jheharmenian" },
  +  { GUINT_TO_POINTER (0xFF2A), "/Jmonospace" },
  +  { GUINT_TO_POINTER (0xF76A), "/Jsmall" },
  +  { GUINT_TO_POINTER (0x004B), "/K" },
  +  { GUINT_TO_POINTER (0x3385), "/KBsquare" },
  +  { GUINT_TO_POINTER (0x33CD), "/KKsquare" },
  +  { GUINT_TO_POINTER (0x04A0), "/Kabashkircyrillic" },
  +  { GUINT_TO_POINTER (0x1E30), "/Kacute" },
  +  { GUINT_TO_POINTER (0x041A), "/Kacyrillic" },
  +  { GUINT_TO_POINTER (0x049A), "/Kadescendercyrillic" },
  +  { GUINT_TO_POINTER (0x04C3), "/Kahookcyrillic" },
  +  { GUINT_TO_POINTER (0x039A), "/Kappa" },
  +  { GUINT_TO_POINTER (0x049E), "/Kastrokecyrillic" },
  +  { GUINT_TO_POINTER (0x049C), "/Kaverticalstrokecyrillic" },
  +  { GUINT_TO_POINTER (0x01E8), "/Kcaron" },
  +  { GUINT_TO_POINTER (0x0136), "/Kcedilla" },
  +  { GUINT_TO_POINTER (0x24C0), "/Kcircle" },
  +  { GUINT_TO_POINTER (0x0136), "/Kcommaaccent" },
  +  { GUINT_TO_POINTER (0x1E32), "/Kdotbelow" },
  +  { GUINT_TO_POINTER (0x0554), "/Keharmenian" },
  +  { GUINT_TO_POINTER (0x053F), "/Kenarmenian" },
  +  { GUINT_TO_POINTER (0x0425), "/Khacyrillic" },
  +  { GUINT_TO_POINTER (0x03E6), "/Kheicoptic" },
  +  { GUINT_TO_POINTER (0x0198), "/Khook" },
  +  { GUINT_TO_POINTER (0x040C), "/Kjecyrillic" },
  +  { GUINT_TO_POINTER (0x1E34), "/Klinebelow" },
  +  { GUINT_TO_POINTER (0xFF2B), "/Kmonospace" },
  +  { GUINT_TO_POINTER (0x0480), "/Koppacyrillic" },
  +  { GUINT_TO_POINTER (0x03DE), "/Koppagreek" },
  +  { GUINT_TO_POINTER (0x046E), "/Ksicyrillic" },
  +  { GUINT_TO_POINTER (0xF76B), "/Ksmall" },
  +  { GUINT_TO_POINTER (0x004C), "/L" },
  +  { GUINT_TO_POINTER (0x01C7), "/LJ" },
  +  { GUINT_TO_POINTER (0xF6BF), "/LL" },
  +  { GUINT_TO_POINTER (0x0139), "/Lacute" },
  +  { GUINT_TO_POINTER (0x039B), "/Lambda" },
  +  { GUINT_TO_POINTER (0x013D), "/Lcaron" },
  +  { GUINT_TO_POINTER (0x013B), "/Lcedilla" },
  +  { GUINT_TO_POINTER (0x24C1), "/Lcircle" },
  +  { GUINT_TO_POINTER (0x1E3C), "/Lcircumflexbelow" },
  +  { GUINT_TO_POINTER (0x013B), "/Lcommaaccent" },
  +  { GUINT_TO_POINTER (0x013F), "/Ldot" },
  +  { GUINT_TO_POINTER (0x013F), "/Ldotaccent" },
  +  { GUINT_TO_POINTER (0x1E36), "/Ldotbelow" },
  +  { GUINT_TO_POINTER (0x1E38), "/Ldotbelowmacron" },
  +  { GUINT_TO_POINTER (0x053C), "/Liwnarmenian" },
  +  { GUINT_TO_POINTER (0x01C8), "/Lj" },
  +  { GUINT_TO_POINTER (0x0409), "/Ljecyrillic" },
  +  { GUINT_TO_POINTER (0x1E3A), "/Llinebelow" },
  +  { GUINT_TO_POINTER (0xFF2C), "/Lmonospace" },
  +  { GUINT_TO_POINTER (0x0141), "/Lslash" },
  +  { GUINT_TO_POINTER (0xF6F9), "/Lslashsmall" },
  +  { GUINT_TO_POINTER (0xF76C), "/Lsmall" },
  +  { GUINT_TO_POINTER (0x004D), "/M" },
  +  { GUINT_TO_POINTER (0x3386), "/MBsquare" },
  +  { GUINT_TO_POINTER (0xF6D0), "/Macron" },
  +  { GUINT_TO_POINTER (0xF7AF), "/Macronsmall" },
  +  { GUINT_TO_POINTER (0x1E3E), "/Macute" },
  +  { GUINT_TO_POINTER (0x24C2), "/Mcircle" },
  +  { GUINT_TO_POINTER (0x1E40), "/Mdotaccent" },
  +  { GUINT_TO_POINTER (0x1E42), "/Mdotbelow" },
  +  { GUINT_TO_POINTER (0x0544), "/Menarmenian" },
  +  { GUINT_TO_POINTER (0xFF2D), "/Mmonospace" },
  +  { GUINT_TO_POINTER (0xF76D), "/Msmall" },
  +  { GUINT_TO_POINTER (0x019C), "/Mturned" },
  +  { GUINT_TO_POINTER (0x039C), "/Mu" },
  +  { GUINT_TO_POINTER (0x004E), "/N" },
  +  { GUINT_TO_POINTER (0x01CA), "/NJ" },
  +  { GUINT_TO_POINTER (0x0143), "/Nacute" },
  +  { GUINT_TO_POINTER (0x0147), "/Ncaron" },
  +  { GUINT_TO_POINTER (0x0145), "/Ncedilla" },
  +  { GUINT_TO_POINTER (0x24C3), "/Ncircle" },
  +  { GUINT_TO_POINTER (0x1E4A), "/Ncircumflexbelow" },
  +  { GUINT_TO_POINTER (0x0145), "/Ncommaaccent" },
  +  { GUINT_TO_POINTER (0x1E44), "/Ndotaccent" },
  +  { GUINT_TO_POINTER (0x1E46), "/Ndotbelow" },
  +  { GUINT_TO_POINTER (0x019D), "/Nhookleft" },
  +  { GUINT_TO_POINTER (0x2168), "/Nineroman" },
  +  { GUINT_TO_POINTER (0x01CB), "/Nj" },
  +  { GUINT_TO_POINTER (0x040A), "/Njecyrillic" },
  +  { GUINT_TO_POINTER (0x1E48), "/Nlinebelow" },
  +  { GUINT_TO_POINTER (0xFF2E), "/Nmonospace" },
  +  { GUINT_TO_POINTER (0x0546), "/Nowarmenian" },
  +  { GUINT_TO_POINTER (0xF76E), "/Nsmall" },
  +  { GUINT_TO_POINTER (0x00D1), "/Ntilde" },
  +  { GUINT_TO_POINTER (0xF7F1), "/Ntildesmall" },
  +  { GUINT_TO_POINTER (0x039D), "/Nu" },
  +  { GUINT_TO_POINTER (0x004F), "/O" },
  +  { GUINT_TO_POINTER (0x0152), "/OE" },
  +  { GUINT_TO_POINTER (0xF6FA), "/OEsmall" },
  +  { GUINT_TO_POINTER (0x00D3), "/Oacute" },
  +  { GUINT_TO_POINTER (0xF7F3), "/Oacutesmall" },
  +  { GUINT_TO_POINTER (0x04E8), "/Obarredcyrillic" },
  +  { GUINT_TO_POINTER (0x04EA), "/Obarreddieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x014E), "/Obreve" },
  +  { GUINT_TO_POINTER (0x01D1), "/Ocaron" },
  +  { GUINT_TO_POINTER (0x019F), "/Ocenteredtilde" },
  +  { GUINT_TO_POINTER (0x24C4), "/Ocircle" },
  +  { GUINT_TO_POINTER (0x00D4), "/Ocircumflex" },
  +  { GUINT_TO_POINTER (0x1ED0), "/Ocircumflexacute" },
  +  { GUINT_TO_POINTER (0x1ED8), "/Ocircumflexdotbelow" },
  +  { GUINT_TO_POINTER (0x1ED2), "/Ocircumflexgrave" },
  +  { GUINT_TO_POINTER (0x1ED4), "/Ocircumflexhookabove" },
  +  { GUINT_TO_POINTER (0xF7F4), "/Ocircumflexsmall" },
  +  { GUINT_TO_POINTER (0x1ED6), "/Ocircumflextilde" },
  +  { GUINT_TO_POINTER (0x041E), "/Ocyrillic" },
  +  { GUINT_TO_POINTER (0x0150), "/Odblacute" },
  +  { GUINT_TO_POINTER (0x020C), "/Odblgrave" },
  +  { GUINT_TO_POINTER (0x00D6), "/Odieresis" },
  +  { GUINT_TO_POINTER (0x04E6), "/Odieresiscyrillic" },
  +  { GUINT_TO_POINTER (0xF7F6), "/Odieresissmall" },
  +  { GUINT_TO_POINTER (0x1ECC), "/Odotbelow" },
  +  { GUINT_TO_POINTER (0xF6FB), "/Ogoneksmall" },
  +  { GUINT_TO_POINTER (0x00D2), "/Ograve" },
  +  { GUINT_TO_POINTER (0xF7F2), "/Ogravesmall" },
  +  { GUINT_TO_POINTER (0x0555), "/Oharmenian" },
  +  { GUINT_TO_POINTER (0x2126), "/Ohm" },
  +  { GUINT_TO_POINTER (0x1ECE), "/Ohookabove" },
  +  { GUINT_TO_POINTER (0x01A0), "/Ohorn" },
  +  { GUINT_TO_POINTER (0x1EDA), "/Ohornacute" },
  +  { GUINT_TO_POINTER (0x1EE2), "/Ohorndotbelow" },
  +  { GUINT_TO_POINTER (0x1EDC), "/Ohorngrave" },
  +  { GUINT_TO_POINTER (0x1EDE), "/Ohornhookabove" },
  +  { GUINT_TO_POINTER (0x1EE0), "/Ohorntilde" },
  +  { GUINT_TO_POINTER (0x0150), "/Ohungarumlaut" },
  +  { GUINT_TO_POINTER (0x01A2), "/Oi" },
  +  { GUINT_TO_POINTER (0x020E), "/Oinvertedbreve" },
  +  { GUINT_TO_POINTER (0x014C), "/Omacron" },
  +  { GUINT_TO_POINTER (0x1E52), "/Omacronacute" },
  +  { GUINT_TO_POINTER (0x1E50), "/Omacrongrave" },
  +  { GUINT_TO_POINTER (0x2126), "/Omega" },
  +  { GUINT_TO_POINTER (0x0460), "/Omegacyrillic" },
  +  { GUINT_TO_POINTER (0x03A9), "/Omegagreek" },
  +  { GUINT_TO_POINTER (0x047A), "/Omegaroundcyrillic" },
  +  { GUINT_TO_POINTER (0x047C), "/Omegatitlocyrillic" },
  +  { GUINT_TO_POINTER (0x038F), "/Omegatonos" },
  +  { GUINT_TO_POINTER (0x039F), "/Omicron" },
  +  { GUINT_TO_POINTER (0x038C), "/Omicrontonos" },
  +  { GUINT_TO_POINTER (0xFF2F), "/Omonospace" },
  +  { GUINT_TO_POINTER (0x2160), "/Oneroman" },
  +  { GUINT_TO_POINTER (0x01EA), "/Oogonek" },
  +  { GUINT_TO_POINTER (0x01EC), "/Oogonekmacron" },
  +  { GUINT_TO_POINTER (0x0186), "/Oopen" },
  +  { GUINT_TO_POINTER (0x00D8), "/Oslash" },
  +  { GUINT_TO_POINTER (0x01FE), "/Oslashacute" },
  +  { GUINT_TO_POINTER (0xF7F8), "/Oslashsmall" },
  +  { GUINT_TO_POINTER (0xF76F), "/Osmall" },
  +  { GUINT_TO_POINTER (0x01FE), "/Ostrokeacute" },
  +  { GUINT_TO_POINTER (0x047E), "/Otcyrillic" },
  +  { GUINT_TO_POINTER (0x00D5), "/Otilde" },
  +  { GUINT_TO_POINTER (0x1E4C), "/Otildeacute" },
  +  { GUINT_TO_POINTER (0x1E4E), "/Otildedieresis" },
  +  { GUINT_TO_POINTER (0xF7F5), "/Otildesmall" },
  +  { GUINT_TO_POINTER (0x0050), "/P" },
  +  { GUINT_TO_POINTER (0x1E54), "/Pacute" },
  +  { GUINT_TO_POINTER (0x24C5), "/Pcircle" },
  +  { GUINT_TO_POINTER (0x1E56), "/Pdotaccent" },
  +  { GUINT_TO_POINTER (0x041F), "/Pecyrillic" },
  +  { GUINT_TO_POINTER (0x054A), "/Peharmenian" },
  +  { GUINT_TO_POINTER (0x04A6), "/Pemiddlehookcyrillic" },
  +  { GUINT_TO_POINTER (0x03A6), "/Phi" },
  +  { GUINT_TO_POINTER (0x01A4), "/Phook" },
  +  { GUINT_TO_POINTER (0x03A0), "/Pi" },
  +  { GUINT_TO_POINTER (0x0553), "/Piwrarmenian" },
  +  { GUINT_TO_POINTER (0xFF30), "/Pmonospace" },
  +  { GUINT_TO_POINTER (0x03A8), "/Psi" },
  +  { GUINT_TO_POINTER (0x0470), "/Psicyrillic" },
  +  { GUINT_TO_POINTER (0xF770), "/Psmall" },
  +  { GUINT_TO_POINTER (0x0051), "/Q" },
  +  { GUINT_TO_POINTER (0x24C6), "/Qcircle" },
  +  { GUINT_TO_POINTER (0xFF31), "/Qmonospace" },
  +  { GUINT_TO_POINTER (0xF771), "/Qsmall" },
  +  { GUINT_TO_POINTER (0x0052), "/R" },
  +  { GUINT_TO_POINTER (0x054C), "/Raarmenian" },
  +  { GUINT_TO_POINTER (0x0154), "/Racute" },
  +  { GUINT_TO_POINTER (0x0158), "/Rcaron" },
  +  { GUINT_TO_POINTER (0x0156), "/Rcedilla" },
  +  { GUINT_TO_POINTER (0x24C7), "/Rcircle" },
  +  { GUINT_TO_POINTER (0x0156), "/Rcommaaccent" },
  +  { GUINT_TO_POINTER (0x0210), "/Rdblgrave" },
  +  { GUINT_TO_POINTER (0x1E58), "/Rdotaccent" },
  +  { GUINT_TO_POINTER (0x1E5A), "/Rdotbelow" },
  +  { GUINT_TO_POINTER (0x1E5C), "/Rdotbelowmacron" },
  +  { GUINT_TO_POINTER (0x0550), "/Reharmenian" },
  +  { GUINT_TO_POINTER (0x211C), "/Rfraktur" },
  +  { GUINT_TO_POINTER (0x03A1), "/Rho" },
  +  { GUINT_TO_POINTER (0xF6FC), "/Ringsmall" },
  +  { GUINT_TO_POINTER (0x0212), "/Rinvertedbreve" },
  +  { GUINT_TO_POINTER (0x1E5E), "/Rlinebelow" },
  +  { GUINT_TO_POINTER (0xFF32), "/Rmonospace" },
  +  { GUINT_TO_POINTER (0xF772), "/Rsmall" },
  +  { GUINT_TO_POINTER (0x0281), "/Rsmallinverted" },
  +  { GUINT_TO_POINTER (0x02B6), "/Rsmallinvertedsuperior" },
  +  { GUINT_TO_POINTER (0x0053), "/S" },
  +  { GUINT_TO_POINTER (0x250C), "/SF010000" },
  +  { GUINT_TO_POINTER (0x2514), "/SF020000" },
  +  { GUINT_TO_POINTER (0x2510), "/SF030000" },
  +  { GUINT_TO_POINTER (0x2518), "/SF040000" },
  +  { GUINT_TO_POINTER (0x253C), "/SF050000" },
  +  { GUINT_TO_POINTER (0x252C), "/SF060000" },
  +  { GUINT_TO_POINTER (0x2534), "/SF070000" },
  +  { GUINT_TO_POINTER (0x251C), "/SF080000" },
  +  { GUINT_TO_POINTER (0x2524), "/SF090000" },
  +  { GUINT_TO_POINTER (0x2500), "/SF100000" },
  +  { GUINT_TO_POINTER (0x2502), "/SF110000" },
  +  { GUINT_TO_POINTER (0x2561), "/SF190000" },
  +  { GUINT_TO_POINTER (0x2562), "/SF200000" },
  +  { GUINT_TO_POINTER (0x2556), "/SF210000" },
  +  { GUINT_TO_POINTER (0x2555), "/SF220000" },
  +  { GUINT_TO_POINTER (0x2563), "/SF230000" },
  +  { GUINT_TO_POINTER (0x2551), "/SF240000" },
  +  { GUINT_TO_POINTER (0x2557), "/SF250000" },
  +  { GUINT_TO_POINTER (0x255D), "/SF260000" },
  +  { GUINT_TO_POINTER (0x255C), "/SF270000" },
  +  { GUINT_TO_POINTER (0x255B), "/SF280000" },
  +  { GUINT_TO_POINTER (0x255E), "/SF360000" },
  +  { GUINT_TO_POINTER (0x255F), "/SF370000" },
  +  { GUINT_TO_POINTER (0x255A), "/SF380000" },
  +  { GUINT_TO_POINTER (0x2554), "/SF390000" },
  +  { GUINT_TO_POINTER (0x2569), "/SF400000" },
  +  { GUINT_TO_POINTER (0x2566), "/SF410000" },
  +  { GUINT_TO_POINTER (0x2560), "/SF420000" },
  +  { GUINT_TO_POINTER (0x2550), "/SF430000" },
  +  { GUINT_TO_POINTER (0x256C), "/SF440000" },
  +  { GUINT_TO_POINTER (0x2567), "/SF450000" },
  +  { GUINT_TO_POINTER (0x2568), "/SF460000" },
  +  { GUINT_TO_POINTER (0x2564), "/SF470000" },
  +  { GUINT_TO_POINTER (0x2565), "/SF480000" },
  +  { GUINT_TO_POINTER (0x2559), "/SF490000" },
  +  { GUINT_TO_POINTER (0x2558), "/SF500000" },
  +  { GUINT_TO_POINTER (0x2552), "/SF510000" },
  +  { GUINT_TO_POINTER (0x2553), "/SF520000" },
  +  { GUINT_TO_POINTER (0x256B), "/SF530000" },
  +  { GUINT_TO_POINTER (0x256A), "/SF540000" },
  +  { GUINT_TO_POINTER (0x015A), "/Sacute" },
  +  { GUINT_TO_POINTER (0x1E64), "/Sacutedotaccent" },
  +  { GUINT_TO_POINTER (0x03E0), "/Sampigreek" },
  +  { GUINT_TO_POINTER (0x0160), "/Scaron" },
  +  { GUINT_TO_POINTER (0x1E66), "/Scarondotaccent" },
  +  { GUINT_TO_POINTER (0xF6FD), "/Scaronsmall" },
  +  { GUINT_TO_POINTER (0x015E), "/Scedilla" },
  +  { GUINT_TO_POINTER (0x018F), "/Schwa" },
  +  { GUINT_TO_POINTER (0x04D8), "/Schwacyrillic" },
  +  { GUINT_TO_POINTER (0x04DA), "/Schwadieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x24C8), "/Scircle" },
  +  { GUINT_TO_POINTER (0x015C), "/Scircumflex" },
  +  { GUINT_TO_POINTER (0x0218), "/Scommaaccent" },
  +  { GUINT_TO_POINTER (0x1E60), "/Sdotaccent" },
  +  { GUINT_TO_POINTER (0x1E62), "/Sdotbelow" },
  +  { GUINT_TO_POINTER (0x1E68), "/Sdotbelowdotaccent" },
  +  { GUINT_TO_POINTER (0x054D), "/Seharmenian" },
  +  { GUINT_TO_POINTER (0x2166), "/Sevenroman" },
  +  { GUINT_TO_POINTER (0x0547), "/Shaarmenian" },
  +  { GUINT_TO_POINTER (0x0428), "/Shacyrillic" },
  +  { GUINT_TO_POINTER (0x0429), "/Shchacyrillic" },
  +  { GUINT_TO_POINTER (0x03E2), "/Sheicoptic" },
  +  { GUINT_TO_POINTER (0x04BA), "/Shhacyrillic" },
  +  { GUINT_TO_POINTER (0x03EC), "/Shimacoptic" },
  +  { GUINT_TO_POINTER (0x03A3), "/Sigma" },
  +  { GUINT_TO_POINTER (0x2165), "/Sixroman" },
  +  { GUINT_TO_POINTER (0xFF33), "/Smonospace" },
  +  { GUINT_TO_POINTER (0x042C), "/Softsigncyrillic" },
  +  { GUINT_TO_POINTER (0xF773), "/Ssmall" },
  +  { GUINT_TO_POINTER (0x03DA), "/Stigmagreek" },
  +  { GUINT_TO_POINTER (0x0054), "/T" },
  +  { GUINT_TO_POINTER (0x03A4), "/Tau" },
  +  { GUINT_TO_POINTER (0x0166), "/Tbar" },
  +  { GUINT_TO_POINTER (0x0164), "/Tcaron" },
  +  { GUINT_TO_POINTER (0x0162), "/Tcedilla" },
  +  { GUINT_TO_POINTER (0x24C9), "/Tcircle" },
  +  { GUINT_TO_POINTER (0x1E70), "/Tcircumflexbelow" },
  +  { GUINT_TO_POINTER (0x0162), "/Tcommaaccent" },
  +  { GUINT_TO_POINTER (0x1E6A), "/Tdotaccent" },
  +  { GUINT_TO_POINTER (0x1E6C), "/Tdotbelow" },
  +  { GUINT_TO_POINTER (0x0422), "/Tecyrillic" },
  +  { GUINT_TO_POINTER (0x04AC), "/Tedescendercyrillic" },
  +  { GUINT_TO_POINTER (0x2169), "/Tenroman" },
  +  { GUINT_TO_POINTER (0x04B4), "/Tetsecyrillic" },
  +  { GUINT_TO_POINTER (0x0398), "/Theta" },
  +  { GUINT_TO_POINTER (0x01AC), "/Thook" },
  +  { GUINT_TO_POINTER (0x00DE), "/Thorn" },
  +  { GUINT_TO_POINTER (0xF7FE), "/Thornsmall" },
  +  { GUINT_TO_POINTER (0x2162), "/Threeroman" },
  +  { GUINT_TO_POINTER (0xF6FE), "/Tildesmall" },
  +  { GUINT_TO_POINTER (0x054F), "/Tiwnarmenian" },
  +  { GUINT_TO_POINTER (0x1E6E), "/Tlinebelow" },
  +  { GUINT_TO_POINTER (0xFF34), "/Tmonospace" },
  +  { GUINT_TO_POINTER (0x0539), "/Toarmenian" },
  +  { GUINT_TO_POINTER (0x01BC), "/Tonefive" },
  +  { GUINT_TO_POINTER (0x0184), "/Tonesix" },
  +  { GUINT_TO_POINTER (0x01A7), "/Tonetwo" },
  +  { GUINT_TO_POINTER (0x01AE), "/Tretroflexhook" },
  +  { GUINT_TO_POINTER (0x0426), "/Tsecyrillic" },
  +  { GUINT_TO_POINTER (0x040B), "/Tshecyrillic" },
  +  { GUINT_TO_POINTER (0xF774), "/Tsmall" },
  +  { GUINT_TO_POINTER (0x216B), "/Twelveroman" },
  +  { GUINT_TO_POINTER (0x2161), "/Tworoman" },
  +  { GUINT_TO_POINTER (0x0055), "/U" },
  +  { GUINT_TO_POINTER (0x00DA), "/Uacute" },
  +  { GUINT_TO_POINTER (0xF7FA), "/Uacutesmall" },
  +  { GUINT_TO_POINTER (0x016C), "/Ubreve" },
  +  { GUINT_TO_POINTER (0x01D3), "/Ucaron" },
  +  { GUINT_TO_POINTER (0x24CA), "/Ucircle" },
  +  { GUINT_TO_POINTER (0x00DB), "/Ucircumflex" },
  +  { GUINT_TO_POINTER (0x1E76), "/Ucircumflexbelow" },
  +  { GUINT_TO_POINTER (0xF7FB), "/Ucircumflexsmall" },
  +  { GUINT_TO_POINTER (0x0423), "/Ucyrillic" },
  +  { GUINT_TO_POINTER (0x0170), "/Udblacute" },
  +  { GUINT_TO_POINTER (0x0214), "/Udblgrave" },
  +  { GUINT_TO_POINTER (0x00DC), "/Udieresis" },
  +  { GUINT_TO_POINTER (0x01D7), "/Udieresisacute" },
  +  { GUINT_TO_POINTER (0x1E72), "/Udieresisbelow" },
  +  { GUINT_TO_POINTER (0x01D9), "/Udieresiscaron" },
  +  { GUINT_TO_POINTER (0x04F0), "/Udieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x01DB), "/Udieresisgrave" },
  +  { GUINT_TO_POINTER (0x01D5), "/Udieresismacron" },
  +  { GUINT_TO_POINTER (0xF7FC), "/Udieresissmall" },
  +  { GUINT_TO_POINTER (0x1EE4), "/Udotbelow" },
  +  { GUINT_TO_POINTER (0x00D9), "/Ugrave" },
  +  { GUINT_TO_POINTER (0xF7F9), "/Ugravesmall" },
  +  { GUINT_TO_POINTER (0x1EE6), "/Uhookabove" },
  +  { GUINT_TO_POINTER (0x01AF), "/Uhorn" },
  +  { GUINT_TO_POINTER (0x1EE8), "/Uhornacute" },
  +  { GUINT_TO_POINTER (0x1EF0), "/Uhorndotbelow" },
  +  { GUINT_TO_POINTER (0x1EEA), "/Uhorngrave" },
  +  { GUINT_TO_POINTER (0x1EEC), "/Uhornhookabove" },
  +  { GUINT_TO_POINTER (0x1EEE), "/Uhorntilde" },
  +  { GUINT_TO_POINTER (0x0170), "/Uhungarumlaut" },
  +  { GUINT_TO_POINTER (0x04F2), "/Uhungarumlautcyrillic" },
  +  { GUINT_TO_POINTER (0x0216), "/Uinvertedbreve" },
  +  { GUINT_TO_POINTER (0x0478), "/Ukcyrillic" },
  +  { GUINT_TO_POINTER (0x016A), "/Umacron" },
  +  { GUINT_TO_POINTER (0x04EE), "/Umacroncyrillic" },
  +  { GUINT_TO_POINTER (0x1E7A), "/Umacrondieresis" },
  +  { GUINT_TO_POINTER (0xFF35), "/Umonospace" },
  +  { GUINT_TO_POINTER (0x0172), "/Uogonek" },
  +  { GUINT_TO_POINTER (0x03A5), "/Upsilon" },
  +  { GUINT_TO_POINTER (0x03D2), "/Upsilon1" },
  +  { GUINT_TO_POINTER (0x03D3), "/Upsilonacutehooksymbolgreek" },
  +  { GUINT_TO_POINTER (0x01B1), "/Upsilonafrican" },
  +  { GUINT_TO_POINTER (0x03AB), "/Upsilondieresis" },
  +  { GUINT_TO_POINTER (0x03D4), "/Upsilondieresishooksymbolgreek" },
  +  { GUINT_TO_POINTER (0x03D2), "/Upsilonhooksymbol" },
  +  { GUINT_TO_POINTER (0x038E), "/Upsilontonos" },
  +  { GUINT_TO_POINTER (0x016E), "/Uring" },
  +  { GUINT_TO_POINTER (0x040E), "/Ushortcyrillic" },
  +  { GUINT_TO_POINTER (0xF775), "/Usmall" },
  +  { GUINT_TO_POINTER (0x04AE), "/Ustraightcyrillic" },
  +  { GUINT_TO_POINTER (0x04B0), "/Ustraightstrokecyrillic" },
  +  { GUINT_TO_POINTER (0x0168), "/Utilde" },
  +  { GUINT_TO_POINTER (0x1E78), "/Utildeacute" },
  +  { GUINT_TO_POINTER (0x1E74), "/Utildebelow" },
  +  { GUINT_TO_POINTER (0x0056), "/V" },
  +  { GUINT_TO_POINTER (0x24CB), "/Vcircle" },
  +  { GUINT_TO_POINTER (0x1E7E), "/Vdotbelow" },
  +  { GUINT_TO_POINTER (0x0412), "/Vecyrillic" },
  +  { GUINT_TO_POINTER (0x054E), "/Vewarmenian" },
  +  { GUINT_TO_POINTER (0x01B2), "/Vhook" },
  +  { GUINT_TO_POINTER (0xFF36), "/Vmonospace" },
  +  { GUINT_TO_POINTER (0x0548), "/Voarmenian" },
  +  { GUINT_TO_POINTER (0xF776), "/Vsmall" },
  +  { GUINT_TO_POINTER (0x1E7C), "/Vtilde" },
  +  { GUINT_TO_POINTER (0x0057), "/W" },
  +  { GUINT_TO_POINTER (0x1E82), "/Wacute" },
  +  { GUINT_TO_POINTER (0x24CC), "/Wcircle" },
  +  { GUINT_TO_POINTER (0x0174), "/Wcircumflex" },
  +  { GUINT_TO_POINTER (0x1E84), "/Wdieresis" },
  +  { GUINT_TO_POINTER (0x1E86), "/Wdotaccent" },
  +  { GUINT_TO_POINTER (0x1E88), "/Wdotbelow" },
  +  { GUINT_TO_POINTER (0x1E80), "/Wgrave" },
  +  { GUINT_TO_POINTER (0xFF37), "/Wmonospace" },
  +  { GUINT_TO_POINTER (0xF777), "/Wsmall" },
  +  { GUINT_TO_POINTER (0x0058), "/X" },
  +  { GUINT_TO_POINTER (0x24CD), "/Xcircle" },
  +  { GUINT_TO_POINTER (0x1E8C), "/Xdieresis" },
  +  { GUINT_TO_POINTER (0x1E8A), "/Xdotaccent" },
  +  { GUINT_TO_POINTER (0x053D), "/Xeharmenian" },
  +  { GUINT_TO_POINTER (0x039E), "/Xi" },
  +  { GUINT_TO_POINTER (0xFF38), "/Xmonospace" },
  +  { GUINT_TO_POINTER (0xF778), "/Xsmall" },
  +  { GUINT_TO_POINTER (0x0059), "/Y" },
  +  { GUINT_TO_POINTER (0x00DD), "/Yacute" },
  +  { GUINT_TO_POINTER (0xF7FD), "/Yacutesmall" },
  +  { GUINT_TO_POINTER (0x0462), "/Yatcyrillic" },
  +  { GUINT_TO_POINTER (0x24CE), "/Ycircle" },
  +  { GUINT_TO_POINTER (0x0176), "/Ycircumflex" },
  +  { GUINT_TO_POINTER (0x0178), "/Ydieresis" },
  +  { GUINT_TO_POINTER (0xF7FF), "/Ydieresissmall" },
  +  { GUINT_TO_POINTER (0x1E8E), "/Ydotaccent" },
  +  { GUINT_TO_POINTER (0x1EF4), "/Ydotbelow" },
  +  { GUINT_TO_POINTER (0x042B), "/Yericyrillic" },
  +  { GUINT_TO_POINTER (0x04F8), "/Yerudieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x1EF2), "/Ygrave" },
  +  { GUINT_TO_POINTER (0x01B3), "/Yhook" },
  +  { GUINT_TO_POINTER (0x1EF6), "/Yhookabove" },
  +  { GUINT_TO_POINTER (0x0545), "/Yiarmenian" },
  +  { GUINT_TO_POINTER (0x0407), "/Yicyrillic" },
  +  { GUINT_TO_POINTER (0x0552), "/Yiwnarmenian" },
  +  { GUINT_TO_POINTER (0xFF39), "/Ymonospace" },
  +  { GUINT_TO_POINTER (0xF779), "/Ysmall" },
  +  { GUINT_TO_POINTER (0x1EF8), "/Ytilde" },
  +  { GUINT_TO_POINTER (0x046A), "/Yusbigcyrillic" },
  +  { GUINT_TO_POINTER (0x046C), "/Yusbigiotifiedcyrillic" },
  +  { GUINT_TO_POINTER (0x0466), "/Yuslittlecyrillic" },
  +  { GUINT_TO_POINTER (0x0468), "/Yuslittleiotifiedcyrillic" },
  +  { GUINT_TO_POINTER (0x005A), "/Z" },
  +  { GUINT_TO_POINTER (0x0536), "/Zaarmenian" },
  +  { GUINT_TO_POINTER (0x0179), "/Zacute" },
  +  { GUINT_TO_POINTER (0x017D), "/Zcaron" },
  +  { GUINT_TO_POINTER (0xF6FF), "/Zcaronsmall" },
  +  { GUINT_TO_POINTER (0x24CF), "/Zcircle" },
  +  { GUINT_TO_POINTER (0x1E90), "/Zcircumflex" },
  +  { GUINT_TO_POINTER (0x017B), "/Zdot" },
  +  { GUINT_TO_POINTER (0x017B), "/Zdotaccent" },
  +  { GUINT_TO_POINTER (0x1E92), "/Zdotbelow" },
  +  { GUINT_TO_POINTER (0x0417), "/Zecyrillic" },
  +  { GUINT_TO_POINTER (0x0498), "/Zedescendercyrillic" },
  +  { GUINT_TO_POINTER (0x04DE), "/Zedieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x0396), "/Zeta" },
  +  { GUINT_TO_POINTER (0x053A), "/Zhearmenian" },
  +  { GUINT_TO_POINTER (0x04C1), "/Zhebrevecyrillic" },
  +  { GUINT_TO_POINTER (0x0416), "/Zhecyrillic" },
  +  { GUINT_TO_POINTER (0x0496), "/Zhedescendercyrillic" },
  +  { GUINT_TO_POINTER (0x04DC), "/Zhedieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x1E94), "/Zlinebelow" },
  +  { GUINT_TO_POINTER (0xFF3A), "/Zmonospace" },
  +  { GUINT_TO_POINTER (0xF77A), "/Zsmall" },
  +  { GUINT_TO_POINTER (0x01B5), "/Zstroke" },
  +  { GUINT_TO_POINTER (0x0061), "/a" },
  +  { GUINT_TO_POINTER (0x0986), "/aabengali" },
  +  { GUINT_TO_POINTER (0x00E1), "/aacute" },
  +  { GUINT_TO_POINTER (0x0906), "/aadeva" },
  +  { GUINT_TO_POINTER (0x0A86), "/aagujarati" },
  +  { GUINT_TO_POINTER (0x0A06), "/aagurmukhi" },
  +  { GUINT_TO_POINTER (0x0A3E), "/aamatragurmukhi" },
  +  { GUINT_TO_POINTER (0x3303), "/aarusquare" },
  +  { GUINT_TO_POINTER (0x09BE), "/aavowelsignbengali" },
  +  { GUINT_TO_POINTER (0x093E), "/aavowelsigndeva" },
  +  { GUINT_TO_POINTER (0x0ABE), "/aavowelsigngujarati" },
  +  { GUINT_TO_POINTER (0x055F), "/abbreviationmarkarmenian" },
  +  { GUINT_TO_POINTER (0x0970), "/abbreviationsigndeva" },
  +  { GUINT_TO_POINTER (0x0985), "/abengali" },
  +  { GUINT_TO_POINTER (0x311A), "/abopomofo" },
  +  { GUINT_TO_POINTER (0x0103), "/abreve" },
  +  { GUINT_TO_POINTER (0x1EAF), "/abreveacute" },
  +  { GUINT_TO_POINTER (0x04D1), "/abrevecyrillic" },
  +  { GUINT_TO_POINTER (0x1EB7), "/abrevedotbelow" },
  +  { GUINT_TO_POINTER (0x1EB1), "/abrevegrave" },
  +  { GUINT_TO_POINTER (0x1EB3), "/abrevehookabove" },
  +  { GUINT_TO_POINTER (0x1EB5), "/abrevetilde" },
  +  { GUINT_TO_POINTER (0x01CE), "/acaron" },
  +  { GUINT_TO_POINTER (0x24D0), "/acircle" },
  +  { GUINT_TO_POINTER (0x00E2), "/acircumflex" },
  +  { GUINT_TO_POINTER (0x1EA5), "/acircumflexacute" },
  +  { GUINT_TO_POINTER (0x1EAD), "/acircumflexdotbelow" },
  +  { GUINT_TO_POINTER (0x1EA7), "/acircumflexgrave" },
  +  { GUINT_TO_POINTER (0x1EA9), "/acircumflexhookabove" },
  +  { GUINT_TO_POINTER (0x1EAB), "/acircumflextilde" },
  +  { GUINT_TO_POINTER (0x00B4), "/acute" },
  +  { GUINT_TO_POINTER (0x0317), "/acutebelowcmb" },
  +  { GUINT_TO_POINTER (0x0301), "/acutecmb" },
  +  { GUINT_TO_POINTER (0x0301), "/acutecomb" },
  +  { GUINT_TO_POINTER (0x0954), "/acutedeva" },
  +  { GUINT_TO_POINTER (0x02CF), "/acutelowmod" },
  +  { GUINT_TO_POINTER (0x0341), "/acutetonecmb" },
  +  { GUINT_TO_POINTER (0x0430), "/acyrillic" },
  +  { GUINT_TO_POINTER (0x0201), "/adblgrave" },
  +  { GUINT_TO_POINTER (0x0A71), "/addakgurmukhi" },
  +  { GUINT_TO_POINTER (0x0905), "/adeva" },
  +  { GUINT_TO_POINTER (0x00E4), "/adieresis" },
  +  { GUINT_TO_POINTER (0x04D3), "/adieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x01DF), "/adieresismacron" },
  +  { GUINT_TO_POINTER (0x1EA1), "/adotbelow" },
  +  { GUINT_TO_POINTER (0x01E1), "/adotmacron" },
  +  { GUINT_TO_POINTER (0x00E6), "/ae" },
  +  { GUINT_TO_POINTER (0x01FD), "/aeacute" },
  +  { GUINT_TO_POINTER (0x3150), "/aekorean" },
  +  { GUINT_TO_POINTER (0x01E3), "/aemacron" },
  +  { GUINT_TO_POINTER (0x2015), "/afii00208" },
  +  { GUINT_TO_POINTER (0x20A4), "/afii08941" },
  +  { GUINT_TO_POINTER (0x0410), "/afii10017" },
  +  { GUINT_TO_POINTER (0x0411), "/afii10018" },
  +  { GUINT_TO_POINTER (0x0412), "/afii10019" },
  +  { GUINT_TO_POINTER (0x0413), "/afii10020" },
  +  { GUINT_TO_POINTER (0x0414), "/afii10021" },
  +  { GUINT_TO_POINTER (0x0415), "/afii10022" },
  +  { GUINT_TO_POINTER (0x0401), "/afii10023" },
  +  { GUINT_TO_POINTER (0x0416), "/afii10024" },
  +  { GUINT_TO_POINTER (0x0417), "/afii10025" },
  +  { GUINT_TO_POINTER (0x0418), "/afii10026" },
  +  { GUINT_TO_POINTER (0x0419), "/afii10027" },
  +  { GUINT_TO_POINTER (0x041A), "/afii10028" },
  +  { GUINT_TO_POINTER (0x041B), "/afii10029" },
  +  { GUINT_TO_POINTER (0x041C), "/afii10030" },
  +  { GUINT_TO_POINTER (0x041D), "/afii10031" },
  +  { GUINT_TO_POINTER (0x041E), "/afii10032" },
  +  { GUINT_TO_POINTER (0x041F), "/afii10033" },
  +  { GUINT_TO_POINTER (0x0420), "/afii10034" },
  +  { GUINT_TO_POINTER (0x0421), "/afii10035" },
  +  { GUINT_TO_POINTER (0x0422), "/afii10036" },
  +  { GUINT_TO_POINTER (0x0423), "/afii10037" },
  +  { GUINT_TO_POINTER (0x0424), "/afii10038" },
  +  { GUINT_TO_POINTER (0x0425), "/afii10039" },
  +  { GUINT_TO_POINTER (0x0426), "/afii10040" },
  +  { GUINT_TO_POINTER (0x0427), "/afii10041" },
  +  { GUINT_TO_POINTER (0x0428), "/afii10042" },
  +  { GUINT_TO_POINTER (0x0429), "/afii10043" },
  +  { GUINT_TO_POINTER (0x042A), "/afii10044" },
  +  { GUINT_TO_POINTER (0x042B), "/afii10045" },
  +  { GUINT_TO_POINTER (0x042C), "/afii10046" },
  +  { GUINT_TO_POINTER (0x042D), "/afii10047" },
  +  { GUINT_TO_POINTER (0x042E), "/afii10048" },
  +  { GUINT_TO_POINTER (0x042F), "/afii10049" },
  +  { GUINT_TO_POINTER (0x0490), "/afii10050" },
  +  { GUINT_TO_POINTER (0x0402), "/afii10051" },
  +  { GUINT_TO_POINTER (0x0403), "/afii10052" },
  +  { GUINT_TO_POINTER (0x0404), "/afii10053" },
  +  { GUINT_TO_POINTER (0x0405), "/afii10054" },
  +  { GUINT_TO_POINTER (0x0406), "/afii10055" },
  +  { GUINT_TO_POINTER (0x0407), "/afii10056" },
  +  { GUINT_TO_POINTER (0x0408), "/afii10057" },
  +  { GUINT_TO_POINTER (0x0409), "/afii10058" },
  +  { GUINT_TO_POINTER (0x040A), "/afii10059" },
  +  { GUINT_TO_POINTER (0x040B), "/afii10060" },
  +  { GUINT_TO_POINTER (0x040C), "/afii10061" },
  +  { GUINT_TO_POINTER (0x040E), "/afii10062" },
  +  { GUINT_TO_POINTER (0xF6C4), "/afii10063" },
  +  { GUINT_TO_POINTER (0xF6C5), "/afii10064" },
  +  { GUINT_TO_POINTER (0x0430), "/afii10065" },
  +  { GUINT_TO_POINTER (0x0431), "/afii10066" },
  +  { GUINT_TO_POINTER (0x0432), "/afii10067" },
  +  { GUINT_TO_POINTER (0x0433), "/afii10068" },
  +  { GUINT_TO_POINTER (0x0434), "/afii10069" },
  +  { GUINT_TO_POINTER (0x0435), "/afii10070" },
  +  { GUINT_TO_POINTER (0x0451), "/afii10071" },
  +  { GUINT_TO_POINTER (0x0436), "/afii10072" },
  +  { GUINT_TO_POINTER (0x0437), "/afii10073" },
  +  { GUINT_TO_POINTER (0x0438), "/afii10074" },
  +  { GUINT_TO_POINTER (0x0439), "/afii10075" },
  +  { GUINT_TO_POINTER (0x043A), "/afii10076" },
  +  { GUINT_TO_POINTER (0x043B), "/afii10077" },
  +  { GUINT_TO_POINTER (0x043C), "/afii10078" },
  +  { GUINT_TO_POINTER (0x043D), "/afii10079" },
  +  { GUINT_TO_POINTER (0x043E), "/afii10080" },
  +  { GUINT_TO_POINTER (0x043F), "/afii10081" },
  +  { GUINT_TO_POINTER (0x0440), "/afii10082" },
  +  { GUINT_TO_POINTER (0x0441), "/afii10083" },
  +  { GUINT_TO_POINTER (0x0442), "/afii10084" },
  +  { GUINT_TO_POINTER (0x0443), "/afii10085" },
  +  { GUINT_TO_POINTER (0x0444), "/afii10086" },
  +  { GUINT_TO_POINTER (0x0445), "/afii10087" },
  +  { GUINT_TO_POINTER (0x0446), "/afii10088" },
  +  { GUINT_TO_POINTER (0x0447), "/afii10089" },
  +  { GUINT_TO_POINTER (0x0448), "/afii10090" },
  +  { GUINT_TO_POINTER (0x0449), "/afii10091" },
  +  { GUINT_TO_POINTER (0x044A), "/afii10092" },
  +  { GUINT_TO_POINTER (0x044B), "/afii10093" },
  +  { GUINT_TO_POINTER (0x044C), "/afii10094" },
  +  { GUINT_TO_POINTER (0x044D), "/afii10095" },
  +  { GUINT_TO_POINTER (0x044E), "/afii10096" },
  +  { GUINT_TO_POINTER (0x044F), "/afii10097" },
  +  { GUINT_TO_POINTER (0x0491), "/afii10098" },
  +  { GUINT_TO_POINTER (0x0452), "/afii10099" },
  +  { GUINT_TO_POINTER (0x0453), "/afii10100" },
  +  { GUINT_TO_POINTER (0x0454), "/afii10101" },
  +  { GUINT_TO_POINTER (0x0455), "/afii10102" },
  +  { GUINT_TO_POINTER (0x0456), "/afii10103" },
  +  { GUINT_TO_POINTER (0x0457), "/afii10104" },
  +  { GUINT_TO_POINTER (0x0458), "/afii10105" },
  +  { GUINT_TO_POINTER (0x0459), "/afii10106" },
  +  { GUINT_TO_POINTER (0x045A), "/afii10107" },
  +  { GUINT_TO_POINTER (0x045B), "/afii10108" },
  +  { GUINT_TO_POINTER (0x045C), "/afii10109" },
  +  { GUINT_TO_POINTER (0x045E), "/afii10110" },
  +  { GUINT_TO_POINTER (0x040F), "/afii10145" },
  +  { GUINT_TO_POINTER (0x0462), "/afii10146" },
  +  { GUINT_TO_POINTER (0x0472), "/afii10147" },
  +  { GUINT_TO_POINTER (0x0474), "/afii10148" },
  +  { GUINT_TO_POINTER (0xF6C6), "/afii10192" },
  +  { GUINT_TO_POINTER (0x045F), "/afii10193" },
  +  { GUINT_TO_POINTER (0x0463), "/afii10194" },
  +  { GUINT_TO_POINTER (0x0473), "/afii10195" },
  +  { GUINT_TO_POINTER (0x0475), "/afii10196" },
  +  { GUINT_TO_POINTER (0xF6C7), "/afii10831" },
  +  { GUINT_TO_POINTER (0xF6C8), "/afii10832" },
  +  { GUINT_TO_POINTER (0x04D9), "/afii10846" },
  +  { GUINT_TO_POINTER (0x200E), "/afii299" },
  +  { GUINT_TO_POINTER (0x200F), "/afii300" },
  +  { GUINT_TO_POINTER (0x200D), "/afii301" },
  +  { GUINT_TO_POINTER (0x066A), "/afii57381" },
  +  { GUINT_TO_POINTER (0x060C), "/afii57388" },
  +  { GUINT_TO_POINTER (0x0660), "/afii57392" },
  +  { GUINT_TO_POINTER (0x0661), "/afii57393" },
  +  { GUINT_TO_POINTER (0x0662), "/afii57394" },
  +  { GUINT_TO_POINTER (0x0663), "/afii57395" },
  +  { GUINT_TO_POINTER (0x0664), "/afii57396" },
  +  { GUINT_TO_POINTER (0x0665), "/afii57397" },
  +  { GUINT_TO_POINTER (0x0666), "/afii57398" },
  +  { GUINT_TO_POINTER (0x0667), "/afii57399" },
  +  { GUINT_TO_POINTER (0x0668), "/afii57400" },
  +  { GUINT_TO_POINTER (0x0669), "/afii57401" },
  +  { GUINT_TO_POINTER (0x061B), "/afii57403" },
  +  { GUINT_TO_POINTER (0x061F), "/afii57407" },
  +  { GUINT_TO_POINTER (0x0621), "/afii57409" },
  +  { GUINT_TO_POINTER (0x0622), "/afii57410" },
  +  { GUINT_TO_POINTER (0x0623), "/afii57411" },
  +  { GUINT_TO_POINTER (0x0624), "/afii57412" },
  +  { GUINT_TO_POINTER (0x0625), "/afii57413" },
  +  { GUINT_TO_POINTER (0x0626), "/afii57414" },
  +  { GUINT_TO_POINTER (0x0627), "/afii57415" },
  +  { GUINT_TO_POINTER (0x0628), "/afii57416" },
  +  { GUINT_TO_POINTER (0x0629), "/afii57417" },
  +  { GUINT_TO_POINTER (0x062A), "/afii57418" },
  +  { GUINT_TO_POINTER (0x062B), "/afii57419" },
  +  { GUINT_TO_POINTER (0x062C), "/afii57420" },
  +  { GUINT_TO_POINTER (0x062D), "/afii57421" },
  +  { GUINT_TO_POINTER (0x062E), "/afii57422" },
  +  { GUINT_TO_POINTER (0x062F), "/afii57423" },
  +  { GUINT_TO_POINTER (0x0630), "/afii57424" },
  +  { GUINT_TO_POINTER (0x0631), "/afii57425" },
  +  { GUINT_TO_POINTER (0x0632), "/afii57426" },
  +  { GUINT_TO_POINTER (0x0633), "/afii57427" },
  +  { GUINT_TO_POINTER (0x0634), "/afii57428" },
  +  { GUINT_TO_POINTER (0x0635), "/afii57429" },
  +  { GUINT_TO_POINTER (0x0636), "/afii57430" },
  +  { GUINT_TO_POINTER (0x0637), "/afii57431" },
  +  { GUINT_TO_POINTER (0x0638), "/afii57432" },
  +  { GUINT_TO_POINTER (0x0639), "/afii57433" },
  +  { GUINT_TO_POINTER (0x063A), "/afii57434" },
  +  { GUINT_TO_POINTER (0x0640), "/afii57440" },
  +  { GUINT_TO_POINTER (0x0641), "/afii57441" },
  +  { GUINT_TO_POINTER (0x0642), "/afii57442" },
  +  { GUINT_TO_POINTER (0x0643), "/afii57443" },
  +  { GUINT_TO_POINTER (0x0644), "/afii57444" },
  +  { GUINT_TO_POINTER (0x0645), "/afii57445" },
  +  { GUINT_TO_POINTER (0x0646), "/afii57446" },
  +  { GUINT_TO_POINTER (0x0648), "/afii57448" },
  +  { GUINT_TO_POINTER (0x0649), "/afii57449" },
  +  { GUINT_TO_POINTER (0x064A), "/afii57450" },
  +  { GUINT_TO_POINTER (0x064B), "/afii57451" },
  +  { GUINT_TO_POINTER (0x064C), "/afii57452" },
  +  { GUINT_TO_POINTER (0x064D), "/afii57453" },
  +  { GUINT_TO_POINTER (0x064E), "/afii57454" },
  +  { GUINT_TO_POINTER (0x064F), "/afii57455" },
  +  { GUINT_TO_POINTER (0x0650), "/afii57456" },
  +  { GUINT_TO_POINTER (0x0651), "/afii57457" },
  +  { GUINT_TO_POINTER (0x0652), "/afii57458" },
  +  { GUINT_TO_POINTER (0x0647), "/afii57470" },
  +  { GUINT_TO_POINTER (0x06A4), "/afii57505" },
  +  { GUINT_TO_POINTER (0x067E), "/afii57506" },
  +  { GUINT_TO_POINTER (0x0686), "/afii57507" },
  +  { GUINT_TO_POINTER (0x0698), "/afii57508" },
  +  { GUINT_TO_POINTER (0x06AF), "/afii57509" },
  +  { GUINT_TO_POINTER (0x0679), "/afii57511" },
  +  { GUINT_TO_POINTER (0x0688), "/afii57512" },
  +  { GUINT_TO_POINTER (0x0691), "/afii57513" },
  +  { GUINT_TO_POINTER (0x06BA), "/afii57514" },
  +  { GUINT_TO_POINTER (0x06D2), "/afii57519" },
  +  { GUINT_TO_POINTER (0x06D5), "/afii57534" },
  +  { GUINT_TO_POINTER (0x20AA), "/afii57636" },
  +  { GUINT_TO_POINTER (0x05BE), "/afii57645" },
  +  { GUINT_TO_POINTER (0x05C3), "/afii57658" },
  +  { GUINT_TO_POINTER (0x05D0), "/afii57664" },
  +  { GUINT_TO_POINTER (0x05D1), "/afii57665" },
  +  { GUINT_TO_POINTER (0x05D2), "/afii57666" },
  +  { GUINT_TO_POINTER (0x05D3), "/afii57667" },
  +  { GUINT_TO_POINTER (0x05D4), "/afii57668" },
  +  { GUINT_TO_POINTER (0x05D5), "/afii57669" },
  +  { GUINT_TO_POINTER (0x05D6), "/afii57670" },
  +  { GUINT_TO_POINTER (0x05D7), "/afii57671" },
  +  { GUINT_TO_POINTER (0x05D8), "/afii57672" },
  +  { GUINT_TO_POINTER (0x05D9), "/afii57673" },
  +  { GUINT_TO_POINTER (0x05DA), "/afii57674" },
  +  { GUINT_TO_POINTER (0x05DB), "/afii57675" },
  +  { GUINT_TO_POINTER (0x05DC), "/afii57676" },
  +  { GUINT_TO_POINTER (0x05DD), "/afii57677" },
  +  { GUINT_TO_POINTER (0x05DE), "/afii57678" },
  +  { GUINT_TO_POINTER (0x05DF), "/afii57679" },
  +  { GUINT_TO_POINTER (0x05E0), "/afii57680" },
  +  { GUINT_TO_POINTER (0x05E1), "/afii57681" },
  +  { GUINT_TO_POINTER (0x05E2), "/afii57682" },
  +  { GUINT_TO_POINTER (0x05E3), "/afii57683" },
  +  { GUINT_TO_POINTER (0x05E4), "/afii57684" },
  +  { GUINT_TO_POINTER (0x05E5), "/afii57685" },
  +  { GUINT_TO_POINTER (0x05E6), "/afii57686" },
  +  { GUINT_TO_POINTER (0x05E7), "/afii57687" },
  +  { GUINT_TO_POINTER (0x05E8), "/afii57688" },
  +  { GUINT_TO_POINTER (0x05E9), "/afii57689" },
  +  { GUINT_TO_POINTER (0x05EA), "/afii57690" },
  +  { GUINT_TO_POINTER (0xFB2A), "/afii57694" },
  +  { GUINT_TO_POINTER (0xFB2B), "/afii57695" },
  +  { GUINT_TO_POINTER (0xFB4B), "/afii57700" },
  +  { GUINT_TO_POINTER (0xFB1F), "/afii57705" },
  +  { GUINT_TO_POINTER (0x05F0), "/afii57716" },
  +  { GUINT_TO_POINTER (0x05F1), "/afii57717" },
  +  { GUINT_TO_POINTER (0x05F2), "/afii57718" },
  +  { GUINT_TO_POINTER (0xFB35), "/afii57723" },
  +  { GUINT_TO_POINTER (0x05B4), "/afii57793" },
  +  { GUINT_TO_POINTER (0x05B5), "/afii57794" },
  +  { GUINT_TO_POINTER (0x05B6), "/afii57795" },
  +  { GUINT_TO_POINTER (0x05BB), "/afii57796" },
  +  { GUINT_TO_POINTER (0x05B8), "/afii57797" },
  +  { GUINT_TO_POINTER (0x05B7), "/afii57798" },
  +  { GUINT_TO_POINTER (0x05B0), "/afii57799" },
  +  { GUINT_TO_POINTER (0x05B2), "/afii57800" },
  +  { GUINT_TO_POINTER (0x05B1), "/afii57801" },
  +  { GUINT_TO_POINTER (0x05B3), "/afii57802" },
  +  { GUINT_TO_POINTER (0x05C2), "/afii57803" },
  +  { GUINT_TO_POINTER (0x05C1), "/afii57804" },
  +  { GUINT_TO_POINTER (0x05B9), "/afii57806" },
  +  { GUINT_TO_POINTER (0x05BC), "/afii57807" },
  +  { GUINT_TO_POINTER (0x05BD), "/afii57839" },
  +  { GUINT_TO_POINTER (0x05BF), "/afii57841" },
  +  { GUINT_TO_POINTER (0x05C0), "/afii57842" },
  +  { GUINT_TO_POINTER (0x02BC), "/afii57929" },
  +  { GUINT_TO_POINTER (0x2105), "/afii61248" },
  +  { GUINT_TO_POINTER (0x2113), "/afii61289" },
  +  { GUINT_TO_POINTER (0x2116), "/afii61352" },
  +  { GUINT_TO_POINTER (0x202C), "/afii61573" },
  +  { GUINT_TO_POINTER (0x202D), "/afii61574" },
  +  { GUINT_TO_POINTER (0x202E), "/afii61575" },
  +  { GUINT_TO_POINTER (0x200C), "/afii61664" },
  +  { GUINT_TO_POINTER (0x066D), "/afii63167" },
  +  { GUINT_TO_POINTER (0x02BD), "/afii64937" },
  +  { GUINT_TO_POINTER (0x00E0), "/agrave" },
  +  { GUINT_TO_POINTER (0x0A85), "/agujarati" },
  +  { GUINT_TO_POINTER (0x0A05), "/agurmukhi" },
  +  { GUINT_TO_POINTER (0x3042), "/ahiragana" },
  +  { GUINT_TO_POINTER (0x1EA3), "/ahookabove" },
  +  { GUINT_TO_POINTER (0x0990), "/aibengali" },
  +  { GUINT_TO_POINTER (0x311E), "/aibopomofo" },
  +  { GUINT_TO_POINTER (0x0910), "/aideva" },
  +  { GUINT_TO_POINTER (0x04D5), "/aiecyrillic" },
  +  { GUINT_TO_POINTER (0x0A90), "/aigujarati" },
  +  { GUINT_TO_POINTER (0x0A10), "/aigurmukhi" },
  +  { GUINT_TO_POINTER (0x0A48), "/aimatragurmukhi" },
  +  { GUINT_TO_POINTER (0x0639), "/ainarabic" },
  +  { GUINT_TO_POINTER (0xFECA), "/ainfinalarabic" },
  +  { GUINT_TO_POINTER (0xFECB), "/aininitialarabic" },
  +  { GUINT_TO_POINTER (0xFECC), "/ainmedialarabic" },
  +  { GUINT_TO_POINTER (0x0203), "/ainvertedbreve" },
  +  { GUINT_TO_POINTER (0x09C8), "/aivowelsignbengali" },
  +  { GUINT_TO_POINTER (0x0948), "/aivowelsigndeva" },
  +  { GUINT_TO_POINTER (0x0AC8), "/aivowelsigngujarati" },
  +  { GUINT_TO_POINTER (0x30A2), "/akatakana" },
  +  { GUINT_TO_POINTER (0xFF71), "/akatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x314F), "/akorean" },
  +  { GUINT_TO_POINTER (0x05D0), "/alef" },
  +  { GUINT_TO_POINTER (0x0627), "/alefarabic" },
  +  { GUINT_TO_POINTER (0xFB30), "/alefdageshhebrew" },
  +  { GUINT_TO_POINTER (0xFE8E), "/aleffinalarabic" },
  +  { GUINT_TO_POINTER (0x0623), "/alefhamzaabovearabic" },
  +  { GUINT_TO_POINTER (0xFE84), "/alefhamzaabovefinalarabic" },
  +  { GUINT_TO_POINTER (0x0625), "/alefhamzabelowarabic" },
  +  { GUINT_TO_POINTER (0xFE88), "/alefhamzabelowfinalarabic" },
  +  { GUINT_TO_POINTER (0x05D0), "/alefhebrew" },
  +  { GUINT_TO_POINTER (0xFB4F), "/aleflamedhebrew" },
  +  { GUINT_TO_POINTER (0x0622), "/alefmaddaabovearabic" },
  +  { GUINT_TO_POINTER (0xFE82), "/alefmaddaabovefinalarabic" },
  +  { GUINT_TO_POINTER (0x0649), "/alefmaksuraarabic" },
  +  { GUINT_TO_POINTER (0xFEF0), "/alefmaksurafinalarabic" },
  +  { GUINT_TO_POINTER (0xFEF3), "/alefmaksurainitialarabic" },
  +  { GUINT_TO_POINTER (0xFEF4), "/alefmaksuramedialarabic" },
  +  { GUINT_TO_POINTER (0xFB2E), "/alefpatahhebrew" },
  +  { GUINT_TO_POINTER (0xFB2F), "/alefqamatshebrew" },
  +  { GUINT_TO_POINTER (0x2135), "/aleph" },
  +  { GUINT_TO_POINTER (0x224C), "/allequal" },
  +  { GUINT_TO_POINTER (0x03B1), "/alpha" },
  +  { GUINT_TO_POINTER (0x03AC), "/alphatonos" },
  +  { GUINT_TO_POINTER (0x0101), "/amacron" },
  +  { GUINT_TO_POINTER (0xFF41), "/amonospace" },
  +  { GUINT_TO_POINTER (0x0026), "/ampersand" },
  +  { GUINT_TO_POINTER (0xFF06), "/ampersandmonospace" },
  +  { GUINT_TO_POINTER (0xF726), "/ampersandsmall" },
  +  { GUINT_TO_POINTER (0x33C2), "/amsquare" },
  +  { GUINT_TO_POINTER (0x3122), "/anbopomofo" },
  +  { GUINT_TO_POINTER (0x3124), "/angbopomofo" },
  +  { GUINT_TO_POINTER (0x0E5A), "/angkhankhuthai" },
  +  { GUINT_TO_POINTER (0x2220), "/angle" },
  +  { GUINT_TO_POINTER (0x3008), "/anglebracketleft" },
  +  { GUINT_TO_POINTER (0xFE3F), "/anglebracketleftvertical" },
  +  { GUINT_TO_POINTER (0x3009), "/anglebracketright" },
  +  { GUINT_TO_POINTER (0xFE40), "/anglebracketrightvertical" },
  +  { GUINT_TO_POINTER (0x2329), "/angleleft" },
  +  { GUINT_TO_POINTER (0x232A), "/angleright" },
  +  { GUINT_TO_POINTER (0x212B), "/angstrom" },
  +  { GUINT_TO_POINTER (0x0387), "/anoteleia" },
  +  { GUINT_TO_POINTER (0x0952), "/anudattadeva" },
  +  { GUINT_TO_POINTER (0x0982), "/anusvarabengali" },
  +  { GUINT_TO_POINTER (0x0902), "/anusvaradeva" },
  +  { GUINT_TO_POINTER (0x0A82), "/anusvaragujarati" },
  +  { GUINT_TO_POINTER (0x0105), "/aogonek" },
  +  { GUINT_TO_POINTER (0x3300), "/apaatosquare" },
  +  { GUINT_TO_POINTER (0x249C), "/aparen" },
  +  { GUINT_TO_POINTER (0x055A), "/apostrophearmenian" },
  +  { GUINT_TO_POINTER (0x02BC), "/apostrophemod" },
  +  { GUINT_TO_POINTER (0xF8FF), "/apple" },
  +  { GUINT_TO_POINTER (0x2250), "/approaches" },
  +  { GUINT_TO_POINTER (0x2248), "/approxequal" },
  +  { GUINT_TO_POINTER (0x2252), "/approxequalorimage" },
  +  { GUINT_TO_POINTER (0x2245), "/approximatelyequal" },
  +  { GUINT_TO_POINTER (0x318E), "/araeaekorean" },
  +  { GUINT_TO_POINTER (0x318D), "/araeakorean" },
  +  { GUINT_TO_POINTER (0x2312), "/arc" },
  +  { GUINT_TO_POINTER (0x1E9A), "/arighthalfring" },
  +  { GUINT_TO_POINTER (0x00E5), "/aring" },
  +  { GUINT_TO_POINTER (0x01FB), "/aringacute" },
  +  { GUINT_TO_POINTER (0x1E01), "/aringbelow" },
  +  { GUINT_TO_POINTER (0x2194), "/arrowboth" },
  +  { GUINT_TO_POINTER (0x21E3), "/arrowdashdown" },
  +  { GUINT_TO_POINTER (0x21E0), "/arrowdashleft" },
  +  { GUINT_TO_POINTER (0x21E2), "/arrowdashright" },
  +  { GUINT_TO_POINTER (0x21E1), "/arrowdashup" },
  +  { GUINT_TO_POINTER (0x21D4), "/arrowdblboth" },
  +  { GUINT_TO_POINTER (0x21D3), "/arrowdbldown" },
  +  { GUINT_TO_POINTER (0x21D0), "/arrowdblleft" },
  +  { GUINT_TO_POINTER (0x21D2), "/arrowdblright" },
  +  { GUINT_TO_POINTER (0x21D1), "/arrowdblup" },
  +  { GUINT_TO_POINTER (0x2193), "/arrowdown" },
  +  { GUINT_TO_POINTER (0x2199), "/arrowdownleft" },
  +  { GUINT_TO_POINTER (0x2198), "/arrowdownright" },
  +  { GUINT_TO_POINTER (0x21E9), "/arrowdownwhite" },
  +  { GUINT_TO_POINTER (0x02C5), "/arrowheaddownmod" },
  +  { GUINT_TO_POINTER (0x02C2), "/arrowheadleftmod" },
  +  { GUINT_TO_POINTER (0x02C3), "/arrowheadrightmod" },
  +  { GUINT_TO_POINTER (0x02C4), "/arrowheadupmod" },
  +  { GUINT_TO_POINTER (0xF8E7), "/arrowhorizex" },
  +  { GUINT_TO_POINTER (0x2190), "/arrowleft" },
  +  { GUINT_TO_POINTER (0x21D0), "/arrowleftdbl" },
  +  { GUINT_TO_POINTER (0x21CD), "/arrowleftdblstroke" },
  +  { GUINT_TO_POINTER (0x21C6), "/arrowleftoverright" },
  +  { GUINT_TO_POINTER (0x21E6), "/arrowleftwhite" },
  +  { GUINT_TO_POINTER (0x2192), "/arrowright" },
  +  { GUINT_TO_POINTER (0x21CF), "/arrowrightdblstroke" },
  +  { GUINT_TO_POINTER (0x279E), "/arrowrightheavy" },
  +  { GUINT_TO_POINTER (0x21C4), "/arrowrightoverleft" },
  +  { GUINT_TO_POINTER (0x21E8), "/arrowrightwhite" },
  +  { GUINT_TO_POINTER (0x21E4), "/arrowtableft" },
  +  { GUINT_TO_POINTER (0x21E5), "/arrowtabright" },
  +  { GUINT_TO_POINTER (0x2191), "/arrowup" },
  +  { GUINT_TO_POINTER (0x2195), "/arrowupdn" },
  +  { GUINT_TO_POINTER (0x21A8), "/arrowupdnbse" },
  +  { GUINT_TO_POINTER (0x21A8), "/arrowupdownbase" },
  +  { GUINT_TO_POINTER (0x2196), "/arrowupleft" },
  +  { GUINT_TO_POINTER (0x21C5), "/arrowupleftofdown" },
  +  { GUINT_TO_POINTER (0x2197), "/arrowupright" },
  +  { GUINT_TO_POINTER (0x21E7), "/arrowupwhite" },
  +  { GUINT_TO_POINTER (0xF8E6), "/arrowvertex" },
  +  { GUINT_TO_POINTER (0x005E), "/asciicircum" },
  +  { GUINT_TO_POINTER (0xFF3E), "/asciicircummonospace" },
  +  { GUINT_TO_POINTER (0x007E), "/asciitilde" },
  +  { GUINT_TO_POINTER (0xFF5E), "/asciitildemonospace" },
  +  { GUINT_TO_POINTER (0x0251), "/ascript" },
  +  { GUINT_TO_POINTER (0x0252), "/ascriptturned" },
  +  { GUINT_TO_POINTER (0x3041), "/asmallhiragana" },
  +  { GUINT_TO_POINTER (0x30A1), "/asmallkatakana" },
  +  { GUINT_TO_POINTER (0xFF67), "/asmallkatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x002A), "/asterisk" },
  +  { GUINT_TO_POINTER (0x066D), "/asteriskaltonearabic" },
  +  { GUINT_TO_POINTER (0x066D), "/asteriskarabic" },
  +  { GUINT_TO_POINTER (0x2217), "/asteriskmath" },
  +  { GUINT_TO_POINTER (0xFF0A), "/asteriskmonospace" },
  +  { GUINT_TO_POINTER (0xFE61), "/asterisksmall" },
  +  { GUINT_TO_POINTER (0x2042), "/asterism" },
  +  { GUINT_TO_POINTER (0xF6E9), "/asuperior" },
  +  { GUINT_TO_POINTER (0x2243), "/asymptoticallyequal" },
  +  { GUINT_TO_POINTER (0x0040), "/at" },
  +  { GUINT_TO_POINTER (0x00E3), "/atilde" },
  +  { GUINT_TO_POINTER (0xFF20), "/atmonospace" },
  +  { GUINT_TO_POINTER (0xFE6B), "/atsmall" },
  +  { GUINT_TO_POINTER (0x0250), "/aturned" },
  +  { GUINT_TO_POINTER (0x0994), "/aubengali" },
  +  { GUINT_TO_POINTER (0x3120), "/aubopomofo" },
  +  { GUINT_TO_POINTER (0x0914), "/audeva" },
  +  { GUINT_TO_POINTER (0x0A94), "/augujarati" },
  +  { GUINT_TO_POINTER (0x0A14), "/augurmukhi" },
  +  { GUINT_TO_POINTER (0x09D7), "/aulengthmarkbengali" },
  +  { GUINT_TO_POINTER (0x0A4C), "/aumatragurmukhi" },
  +  { GUINT_TO_POINTER (0x09CC), "/auvowelsignbengali" },
  +  { GUINT_TO_POINTER (0x094C), "/auvowelsigndeva" },
  +  { GUINT_TO_POINTER (0x0ACC), "/auvowelsigngujarati" },
  +  { GUINT_TO_POINTER (0x093D), "/avagrahadeva" },
  +  { GUINT_TO_POINTER (0x0561), "/aybarmenian" },
  +  { GUINT_TO_POINTER (0x05E2), "/ayin" },
  +  { GUINT_TO_POINTER (0xFB20), "/ayinaltonehebrew" },
  +  { GUINT_TO_POINTER (0x05E2), "/ayinhebrew" },
  +  { GUINT_TO_POINTER (0x0062), "/b" },
  +  { GUINT_TO_POINTER (0x09AC), "/babengali" },
  +  { GUINT_TO_POINTER (0x005C), "/backslash" },
  +  { GUINT_TO_POINTER (0xFF3C), "/backslashmonospace" },
  +  { GUINT_TO_POINTER (0x092C), "/badeva" },
  +  { GUINT_TO_POINTER (0x0AAC), "/bagujarati" },
  +  { GUINT_TO_POINTER (0x0A2C), "/bagurmukhi" },
  +  { GUINT_TO_POINTER (0x3070), "/bahiragana" },
  +  { GUINT_TO_POINTER (0x0E3F), "/bahtthai" },
  +  { GUINT_TO_POINTER (0x30D0), "/bakatakana" },
  +  { GUINT_TO_POINTER (0x007C), "/bar" },
  +  { GUINT_TO_POINTER (0xFF5C), "/barmonospace" },
  +  { GUINT_TO_POINTER (0x3105), "/bbopomofo" },
  +  { GUINT_TO_POINTER (0x24D1), "/bcircle" },
  +  { GUINT_TO_POINTER (0x1E03), "/bdotaccent" },
  +  { GUINT_TO_POINTER (0x1E05), "/bdotbelow" },
  +  { GUINT_TO_POINTER (0x266C), "/beamedsixteenthnotes" },
  +  { GUINT_TO_POINTER (0x2235), "/because" },
  +  { GUINT_TO_POINTER (0x0431), "/becyrillic" },
  +  { GUINT_TO_POINTER (0x0628), "/beharabic" },
  +  { GUINT_TO_POINTER (0xFE90), "/behfinalarabic" },
  +  { GUINT_TO_POINTER (0xFE91), "/behinitialarabic" },
  +  { GUINT_TO_POINTER (0x3079), "/behiragana" },
  +  { GUINT_TO_POINTER (0xFE92), "/behmedialarabic" },
  +  { GUINT_TO_POINTER (0xFC9F), "/behmeeminitialarabic" },
  +  { GUINT_TO_POINTER (0xFC08), "/behmeemisolatedarabic" },
  +  { GUINT_TO_POINTER (0xFC6D), "/behnoonfinalarabic" },
  +  { GUINT_TO_POINTER (0x30D9), "/bekatakana" },
  +  { GUINT_TO_POINTER (0x0562), "/benarmenian" },
  +  { GUINT_TO_POINTER (0x05D1), "/bet" },
  +  { GUINT_TO_POINTER (0x03B2), "/beta" },
  +  { GUINT_TO_POINTER (0x03D0), "/betasymbolgreek" },
  +  { GUINT_TO_POINTER (0xFB31), "/betdagesh" },
  +  { GUINT_TO_POINTER (0xFB31), "/betdageshhebrew" },
  +  { GUINT_TO_POINTER (0x05D1), "/bethebrew" },
  +  { GUINT_TO_POINTER (0xFB4C), "/betrafehebrew" },
  +  { GUINT_TO_POINTER (0x09AD), "/bhabengali" },
  +  { GUINT_TO_POINTER (0x092D), "/bhadeva" },
  +  { GUINT_TO_POINTER (0x0AAD), "/bhagujarati" },
  +  { GUINT_TO_POINTER (0x0A2D), "/bhagurmukhi" },
  +  { GUINT_TO_POINTER (0x0253), "/bhook" },
  +  { GUINT_TO_POINTER (0x3073), "/bihiragana" },
  +  { GUINT_TO_POINTER (0x30D3), "/bikatakana" },
  +  { GUINT_TO_POINTER (0x0298), "/bilabialclick" },
  +  { GUINT_TO_POINTER (0x0A02), "/bindigurmukhi" },
  +  { GUINT_TO_POINTER (0x3331), "/birusquare" },
  +  { GUINT_TO_POINTER (0x25CF), "/blackcircle" },
  +  { GUINT_TO_POINTER (0x25C6), "/blackdiamond" },
  +  { GUINT_TO_POINTER (0x25BC), "/blackdownpointingtriangle" },
  +  { GUINT_TO_POINTER (0x25C4), "/blackleftpointingpointer" },
  +  { GUINT_TO_POINTER (0x25C0), "/blackleftpointingtriangle" },
  +  { GUINT_TO_POINTER (0x3010), "/blacklenticularbracketleft" },
  +  { GUINT_TO_POINTER (0xFE3B), "/blacklenticularbracketleftvertical" },
  +  { GUINT_TO_POINTER (0x3011), "/blacklenticularbracketright" },
  +  { GUINT_TO_POINTER (0xFE3C), "/blacklenticularbracketrightvertical" },
  +  { GUINT_TO_POINTER (0x25E3), "/blacklowerlefttriangle" },
  +  { GUINT_TO_POINTER (0x25E2), "/blacklowerrighttriangle" },
  +  { GUINT_TO_POINTER (0x25AC), "/blackrectangle" },
  +  { GUINT_TO_POINTER (0x25BA), "/blackrightpointingpointer" },
  +  { GUINT_TO_POINTER (0x25B6), "/blackrightpointingtriangle" },
  +  { GUINT_TO_POINTER (0x25AA), "/blacksmallsquare" },
  +  { GUINT_TO_POINTER (0x263B), "/blacksmilingface" },
  +  { GUINT_TO_POINTER (0x25A0), "/blacksquare" },
  +  { GUINT_TO_POINTER (0x2605), "/blackstar" },
  +  { GUINT_TO_POINTER (0x25E4), "/blackupperlefttriangle" },
  +  { GUINT_TO_POINTER (0x25E5), "/blackupperrighttriangle" },
  +  { GUINT_TO_POINTER (0x25B4), "/blackuppointingsmalltriangle" },
  +  { GUINT_TO_POINTER (0x25B2), "/blackuppointingtriangle" },
  +  { GUINT_TO_POINTER (0x2423), "/blank" },
  +  { GUINT_TO_POINTER (0x1E07), "/blinebelow" },
  +  { GUINT_TO_POINTER (0x2588), "/block" },
  +  { GUINT_TO_POINTER (0xFF42), "/bmonospace" },
  +  { GUINT_TO_POINTER (0x0E1A), "/bobaimaithai" },
  +  { GUINT_TO_POINTER (0x307C), "/bohiragana" },
  +  { GUINT_TO_POINTER (0x30DC), "/bokatakana" },
  +  { GUINT_TO_POINTER (0x249D), "/bparen" },
  +  { GUINT_TO_POINTER (0x33C3), "/bqsquare" },
  +  { GUINT_TO_POINTER (0xF8F4), "/braceex" },
  +  { GUINT_TO_POINTER (0x007B), "/braceleft" },
  +  { GUINT_TO_POINTER (0xF8F3), "/braceleftbt" },
  +  { GUINT_TO_POINTER (0xF8F2), "/braceleftmid" },
  +  { GUINT_TO_POINTER (0xFF5B), "/braceleftmonospace" },
  +  { GUINT_TO_POINTER (0xFE5B), "/braceleftsmall" },
  +  { GUINT_TO_POINTER (0xF8F1), "/bracelefttp" },
  +  { GUINT_TO_POINTER (0xFE37), "/braceleftvertical" },
  +  { GUINT_TO_POINTER (0x007D), "/braceright" },
  +  { GUINT_TO_POINTER (0xF8FE), "/bracerightbt" },
  +  { GUINT_TO_POINTER (0xF8FD), "/bracerightmid" },
  +  { GUINT_TO_POINTER (0xFF5D), "/bracerightmonospace" },
  +  { GUINT_TO_POINTER (0xFE5C), "/bracerightsmall" },
  +  { GUINT_TO_POINTER (0xF8FC), "/bracerighttp" },
  +  { GUINT_TO_POINTER (0xFE38), "/bracerightvertical" },
  +  { GUINT_TO_POINTER (0x005B), "/bracketleft" },
  +  { GUINT_TO_POINTER (0xF8F0), "/bracketleftbt" },
  +  { GUINT_TO_POINTER (0xF8EF), "/bracketleftex" },
  +  { GUINT_TO_POINTER (0xFF3B), "/bracketleftmonospace" },
  +  { GUINT_TO_POINTER (0xF8EE), "/bracketlefttp" },
  +  { GUINT_TO_POINTER (0x005D), "/bracketright" },
  +  { GUINT_TO_POINTER (0xF8FB), "/bracketrightbt" },
  +  { GUINT_TO_POINTER (0xF8FA), "/bracketrightex" },
  +  { GUINT_TO_POINTER (0xFF3D), "/bracketrightmonospace" },
  +  { GUINT_TO_POINTER (0xF8F9), "/bracketrighttp" },
  +  { GUINT_TO_POINTER (0x02D8), "/breve" },
  +  { GUINT_TO_POINTER (0x032E), "/brevebelowcmb" },
  +  { GUINT_TO_POINTER (0x0306), "/brevecmb" },
  +  { GUINT_TO_POINTER (0x032F), "/breveinvertedbelowcmb" },
  +  { GUINT_TO_POINTER (0x0311), "/breveinvertedcmb" },
  +  { GUINT_TO_POINTER (0x0361), "/breveinverteddoublecmb" },
  +  { GUINT_TO_POINTER (0x032A), "/bridgebelowcmb" },
  +  { GUINT_TO_POINTER (0x033A), "/bridgeinvertedbelowcmb" },
  +  { GUINT_TO_POINTER (0x00A6), "/brokenbar" },
  +  { GUINT_TO_POINTER (0x0180), "/bstroke" },
  +  { GUINT_TO_POINTER (0xF6EA), "/bsuperior" },
  +  { GUINT_TO_POINTER (0x0183), "/btopbar" },
  +  { GUINT_TO_POINTER (0x3076), "/buhiragana" },
  +  { GUINT_TO_POINTER (0x30D6), "/bukatakana" },
  +  { GUINT_TO_POINTER (0x2022), "/bullet" },
  +  { GUINT_TO_POINTER (0x25D8), "/bulletinverse" },
  +  { GUINT_TO_POINTER (0x2219), "/bulletoperator" },
  +  { GUINT_TO_POINTER (0x25CE), "/bullseye" },
  +  { GUINT_TO_POINTER (0x0063), "/c" },
  +  { GUINT_TO_POINTER (0x056E), "/caarmenian" },
  +  { GUINT_TO_POINTER (0x099A), "/cabengali" },
  +  { GUINT_TO_POINTER (0x0107), "/cacute" },
  +  { GUINT_TO_POINTER (0x091A), "/cadeva" },
  +  { GUINT_TO_POINTER (0x0A9A), "/cagujarati" },
  +  { GUINT_TO_POINTER (0x0A1A), "/cagurmukhi" },
  +  { GUINT_TO_POINTER (0x3388), "/calsquare" },
  +  { GUINT_TO_POINTER (0x0981), "/candrabindubengali" },
  +  { GUINT_TO_POINTER (0x0310), "/candrabinducmb" },
  +  { GUINT_TO_POINTER (0x0901), "/candrabindudeva" },
  +  { GUINT_TO_POINTER (0x0A81), "/candrabindugujarati" },
  +  { GUINT_TO_POINTER (0x21EA), "/capslock" },
  +  { GUINT_TO_POINTER (0x2105), "/careof" },
  +  { GUINT_TO_POINTER (0x02C7), "/caron" },
  +  { GUINT_TO_POINTER (0x032C), "/caronbelowcmb" },
  +  { GUINT_TO_POINTER (0x030C), "/caroncmb" },
  +  { GUINT_TO_POINTER (0x21B5), "/carriagereturn" },
  +  { GUINT_TO_POINTER (0x3118), "/cbopomofo" },
  +  { GUINT_TO_POINTER (0x010D), "/ccaron" },
  +  { GUINT_TO_POINTER (0x00E7), "/ccedilla" },
  +  { GUINT_TO_POINTER (0x1E09), "/ccedillaacute" },
  +  { GUINT_TO_POINTER (0x24D2), "/ccircle" },
  +  { GUINT_TO_POINTER (0x0109), "/ccircumflex" },
  +  { GUINT_TO_POINTER (0x0255), "/ccurl" },
  +  { GUINT_TO_POINTER (0x010B), "/cdot" },
  +  { GUINT_TO_POINTER (0x010B), "/cdotaccent" },
  +  { GUINT_TO_POINTER (0x33C5), "/cdsquare" },
  +  { GUINT_TO_POINTER (0x00B8), "/cedilla" },
  +  { GUINT_TO_POINTER (0x0327), "/cedillacmb" },
  +  { GUINT_TO_POINTER (0x00A2), "/cent" },
  +  { GUINT_TO_POINTER (0x2103), "/centigrade" },
  +  { GUINT_TO_POINTER (0xF6DF), "/centinferior" },
  +  { GUINT_TO_POINTER (0xFFE0), "/centmonospace" },
  +  { GUINT_TO_POINTER (0xF7A2), "/centoldstyle" },
  +  { GUINT_TO_POINTER (0xF6E0), "/centsuperior" },
  +  { GUINT_TO_POINTER (0x0579), "/chaarmenian" },
  +  { GUINT_TO_POINTER (0x099B), "/chabengali" },
  +  { GUINT_TO_POINTER (0x091B), "/chadeva" },
  +  { GUINT_TO_POINTER (0x0A9B), "/chagujarati" },
  +  { GUINT_TO_POINTER (0x0A1B), "/chagurmukhi" },
  +  { GUINT_TO_POINTER (0x3114), "/chbopomofo" },
  +  { GUINT_TO_POINTER (0x04BD), "/cheabkhasiancyrillic" },
  +  { GUINT_TO_POINTER (0x2713), "/checkmark" },
  +  { GUINT_TO_POINTER (0x0447), "/checyrillic" },
  +  { GUINT_TO_POINTER (0x04BF), "/chedescenderabkhasiancyrillic" },
  +  { GUINT_TO_POINTER (0x04B7), "/chedescendercyrillic" },
  +  { GUINT_TO_POINTER (0x04F5), "/chedieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x0573), "/cheharmenian" },
  +  { GUINT_TO_POINTER (0x04CC), "/chekhakassiancyrillic" },
  +  { GUINT_TO_POINTER (0x04B9), "/cheverticalstrokecyrillic" },
  +  { GUINT_TO_POINTER (0x03C7), "/chi" },
  +  { GUINT_TO_POINTER (0x3277), "/chieuchacirclekorean" },
  +  { GUINT_TO_POINTER (0x3217), "/chieuchaparenkorean" },
  +  { GUINT_TO_POINTER (0x3269), "/chieuchcirclekorean" },
  +  { GUINT_TO_POINTER (0x314A), "/chieuchkorean" },
  +  { GUINT_TO_POINTER (0x3209), "/chieuchparenkorean" },
  +  { GUINT_TO_POINTER (0x0E0A), "/chochangthai" },
  +  { GUINT_TO_POINTER (0x0E08), "/chochanthai" },
  +  { GUINT_TO_POINTER (0x0E09), "/chochingthai" },
  +  { GUINT_TO_POINTER (0x0E0C), "/chochoethai" },
  +  { GUINT_TO_POINTER (0x0188), "/chook" },
  +  { GUINT_TO_POINTER (0x3276), "/cieucacirclekorean" },
  +  { GUINT_TO_POINTER (0x3216), "/cieucaparenkorean" },
  +  { GUINT_TO_POINTER (0x3268), "/cieuccirclekorean" },
  +  { GUINT_TO_POINTER (0x3148), "/cieuckorean" },
  +  { GUINT_TO_POINTER (0x3208), "/cieucparenkorean" },
  +  { GUINT_TO_POINTER (0x321C), "/cieucuparenkorean" },
  +  { GUINT_TO_POINTER (0x25CB), "/circle" },
  +  { GUINT_TO_POINTER (0x2297), "/circlemultiply" },
  +  { GUINT_TO_POINTER (0x2299), "/circleot" },
  +  { GUINT_TO_POINTER (0x2295), "/circleplus" },
  +  { GUINT_TO_POINTER (0x3036), "/circlepostalmark" },
  +  { GUINT_TO_POINTER (0x25D0), "/circlewithlefthalfblack" },
  +  { GUINT_TO_POINTER (0x25D1), "/circlewithrighthalfblack" },
  +  { GUINT_TO_POINTER (0x02C6), "/circumflex" },
  +  { GUINT_TO_POINTER (0x032D), "/circumflexbelowcmb" },
  +  { GUINT_TO_POINTER (0x0302), "/circumflexcmb" },
  +  { GUINT_TO_POINTER (0x2327), "/clear" },
  +  { GUINT_TO_POINTER (0x01C2), "/clickalveolar" },
  +  { GUINT_TO_POINTER (0x01C0), "/clickdental" },
  +  { GUINT_TO_POINTER (0x01C1), "/clicklateral" },
  +  { GUINT_TO_POINTER (0x01C3), "/clickretroflex" },
  +  { GUINT_TO_POINTER (0x2663), "/club" },
  +  { GUINT_TO_POINTER (0x2663), "/clubsuitblack" },
  +  { GUINT_TO_POINTER (0x2667), "/clubsuitwhite" },
  +  { GUINT_TO_POINTER (0x33A4), "/cmcubedsquare" },
  +  { GUINT_TO_POINTER (0xFF43), "/cmonospace" },
  +  { GUINT_TO_POINTER (0x33A0), "/cmsquaredsquare" },
  +  { GUINT_TO_POINTER (0x0581), "/coarmenian" },
  +  { GUINT_TO_POINTER (0x003A), "/colon" },
  +  { GUINT_TO_POINTER (0x20A1), "/colonmonetary" },
  +  { GUINT_TO_POINTER (0xFF1A), "/colonmonospace" },
  +  { GUINT_TO_POINTER (0x20A1), "/colonsign" },
  +  { GUINT_TO_POINTER (0xFE55), "/colonsmall" },
  +  { GUINT_TO_POINTER (0x02D1), "/colontriangularhalfmod" },
  +  { GUINT_TO_POINTER (0x02D0), "/colontriangularmod" },
  +  { GUINT_TO_POINTER (0x002C), "/comma" },
  +  { GUINT_TO_POINTER (0x0313), "/commaabovecmb" },
  +  { GUINT_TO_POINTER (0x0315), "/commaaboverightcmb" },
  +  { GUINT_TO_POINTER (0xF6C3), "/commaaccent" },
  +  { GUINT_TO_POINTER (0x060C), "/commaarabic" },
  +  { GUINT_TO_POINTER (0x055D), "/commaarmenian" },
  +  { GUINT_TO_POINTER (0xF6E1), "/commainferior" },
  +  { GUINT_TO_POINTER (0xFF0C), "/commamonospace" },
  +  { GUINT_TO_POINTER (0x0314), "/commareversedabovecmb" },
  +  { GUINT_TO_POINTER (0x02BD), "/commareversedmod" },
  +  { GUINT_TO_POINTER (0xFE50), "/commasmall" },
  +  { GUINT_TO_POINTER (0xF6E2), "/commasuperior" },
  +  { GUINT_TO_POINTER (0x0312), "/commaturnedabovecmb" },
  +  { GUINT_TO_POINTER (0x02BB), "/commaturnedmod" },
  +  { GUINT_TO_POINTER (0x263C), "/compass" },
  +  { GUINT_TO_POINTER (0x2245), "/congruent" },
  +  { GUINT_TO_POINTER (0x222E), "/contourintegral" },
  +  { GUINT_TO_POINTER (0x2303), "/control" },
  +  { GUINT_TO_POINTER (0x0006), "/controlACK" },
  +  { GUINT_TO_POINTER (0x0007), "/controlBEL" },
  +  { GUINT_TO_POINTER (0x0008), "/controlBS" },
  +  { GUINT_TO_POINTER (0x0018), "/controlCAN" },
  +  { GUINT_TO_POINTER (0x000D), "/controlCR" },
  +  { GUINT_TO_POINTER (0x0011), "/controlDC1" },
  +  { GUINT_TO_POINTER (0x0012), "/controlDC2" },
  +  { GUINT_TO_POINTER (0x0013), "/controlDC3" },
  +  { GUINT_TO_POINTER (0x0014), "/controlDC4" },
  +  { GUINT_TO_POINTER (0x007F), "/controlDEL" },
  +  { GUINT_TO_POINTER (0x0010), "/controlDLE" },
  +  { GUINT_TO_POINTER (0x0019), "/controlEM" },
  +  { GUINT_TO_POINTER (0x0005), "/controlENQ" },
  +  { GUINT_TO_POINTER (0x0004), "/controlEOT" },
  +  { GUINT_TO_POINTER (0x001B), "/controlESC" },
  +  { GUINT_TO_POINTER (0x0017), "/controlETB" },
  +  { GUINT_TO_POINTER (0x0003), "/controlETX" },
  +  { GUINT_TO_POINTER (0x000C), "/controlFF" },
  +  { GUINT_TO_POINTER (0x001C), "/controlFS" },
  +  { GUINT_TO_POINTER (0x001D), "/controlGS" },
  +  { GUINT_TO_POINTER (0x0009), "/controlHT" },
  +  { GUINT_TO_POINTER (0x000A), "/controlLF" },
  +  { GUINT_TO_POINTER (0x0015), "/controlNAK" },
  +  { GUINT_TO_POINTER (0x001E), "/controlRS" },
  +  { GUINT_TO_POINTER (0x000F), "/controlSI" },
  +  { GUINT_TO_POINTER (0x000E), "/controlSO" },
  +  { GUINT_TO_POINTER (0x0002), "/controlSOT" },
  +  { GUINT_TO_POINTER (0x0001), "/controlSTX" },
  +  { GUINT_TO_POINTER (0x001A), "/controlSUB" },
  +  { GUINT_TO_POINTER (0x0016), "/controlSYN" },
  +  { GUINT_TO_POINTER (0x001F), "/controlUS" },
  +  { GUINT_TO_POINTER (0x000B), "/controlVT" },
  +  { GUINT_TO_POINTER (0x00A9), "/copyright" },
  +  { GUINT_TO_POINTER (0xF8E9), "/copyrightsans" },
  +  { GUINT_TO_POINTER (0xF6D9), "/copyrightserif" },
  +  { GUINT_TO_POINTER (0x300C), "/cornerbracketleft" },
  +  { GUINT_TO_POINTER (0xFF62), "/cornerbracketlefthalfwidth" },
  +  { GUINT_TO_POINTER (0xFE41), "/cornerbracketleftvertical" },
  +  { GUINT_TO_POINTER (0x300D), "/cornerbracketright" },
  +  { GUINT_TO_POINTER (0xFF63), "/cornerbracketrighthalfwidth" },
  +  { GUINT_TO_POINTER (0xFE42), "/cornerbracketrightvertical" },
  +  { GUINT_TO_POINTER (0x337F), "/corporationsquare" },
  +  { GUINT_TO_POINTER (0x33C7), "/cosquare" },
  +  { GUINT_TO_POINTER (0x33C6), "/coverkgsquare" },
  +  { GUINT_TO_POINTER (0x249E), "/cparen" },
  +  { GUINT_TO_POINTER (0x20A2), "/cruzeiro" },
  +  { GUINT_TO_POINTER (0x0297), "/cstretched" },
  +  { GUINT_TO_POINTER (0x22CF), "/curlyand" },
  +  { GUINT_TO_POINTER (0x22CE), "/curlyor" },
  +  { GUINT_TO_POINTER (0x00A4), "/currency" },
  +  { GUINT_TO_POINTER (0xF6D1), "/cyrBreve" },
  +  { GUINT_TO_POINTER (0xF6D2), "/cyrFlex" },
  +  { GUINT_TO_POINTER (0xF6D4), "/cyrbreve" },
  +  { GUINT_TO_POINTER (0xF6D5), "/cyrflex" },
  +  { GUINT_TO_POINTER (0x0064), "/d" },
  +  { GUINT_TO_POINTER (0x0564), "/daarmenian" },
  +  { GUINT_TO_POINTER (0x09A6), "/dabengali" },
  +  { GUINT_TO_POINTER (0x0636), "/dadarabic" },
  +  { GUINT_TO_POINTER (0x0926), "/dadeva" },
  +  { GUINT_TO_POINTER (0xFEBE), "/dadfinalarabic" },
  +  { GUINT_TO_POINTER (0xFEBF), "/dadinitialarabic" },
  +  { GUINT_TO_POINTER (0xFEC0), "/dadmedialarabic" },
  +  { GUINT_TO_POINTER (0x05BC), "/dagesh" },
  +  { GUINT_TO_POINTER (0x05BC), "/dageshhebrew" },
  +  { GUINT_TO_POINTER (0x2020), "/dagger" },
  +  { GUINT_TO_POINTER (0x2021), "/daggerdbl" },
  +  { GUINT_TO_POINTER (0x0AA6), "/dagujarati" },
  +  { GUINT_TO_POINTER (0x0A26), "/dagurmukhi" },
  +  { GUINT_TO_POINTER (0x3060), "/dahiragana" },
  +  { GUINT_TO_POINTER (0x30C0), "/dakatakana" },
  +  { GUINT_TO_POINTER (0x062F), "/dalarabic" },
  +  { GUINT_TO_POINTER (0x05D3), "/dalet" },
  +  { GUINT_TO_POINTER (0xFB33), "/daletdagesh" },
  +  { GUINT_TO_POINTER (0xFB33), "/daletdageshhebrew" },
  +  { GUINT_TO_POINTER (0x05D3), "/dalethatafpatah" },
  +  { GUINT_TO_POINTER (0x05B2), "/dalethatafpatah" },
  +  { GUINT_TO_POINTER (0x05D3), "/dalethatafpatahhebrew" },
  +  { GUINT_TO_POINTER (0x05B2), "/dalethatafpatahhebrew" },
  +  { GUINT_TO_POINTER (0x05D3), "/dalethatafsegol" },
  +  { GUINT_TO_POINTER (0x05B1), "/dalethatafsegol" },
  +  { GUINT_TO_POINTER (0x05D3), "/dalethatafsegolhebrew" },
  +  { GUINT_TO_POINTER (0x05B1), "/dalethatafsegolhebrew" },
  +  { GUINT_TO_POINTER (0x05D3), "/dalethebrew" },
  +  { GUINT_TO_POINTER (0x05D3), "/dalethiriq" },
  +  { GUINT_TO_POINTER (0x05B4), "/dalethiriq" },
  +  { GUINT_TO_POINTER (0x05D3), "/dalethiriqhebrew" },
  +  { GUINT_TO_POINTER (0x05B4), "/dalethiriqhebrew" },
  +  { GUINT_TO_POINTER (0x05D3), "/daletholam" },
  +  { GUINT_TO_POINTER (0x05B9), "/daletholam" },
  +  { GUINT_TO_POINTER (0x05D3), "/daletholamhebrew" },
  +  { GUINT_TO_POINTER (0x05B9), "/daletholamhebrew" },
  +  { GUINT_TO_POINTER (0x05D3), "/daletpatah" },
  +  { GUINT_TO_POINTER (0x05B7), "/daletpatah" },
  +  { GUINT_TO_POINTER (0x05D3), "/daletpatahhebrew" },
  +  { GUINT_TO_POINTER (0x05B7), "/daletpatahhebrew" },
  +  { GUINT_TO_POINTER (0x05D3), "/daletqamats" },
  +  { GUINT_TO_POINTER (0x05B8), "/daletqamats" },
  +  { GUINT_TO_POINTER (0x05D3), "/daletqamatshebrew" },
  +  { GUINT_TO_POINTER (0x05B8), "/daletqamatshebrew" },
  +  { GUINT_TO_POINTER (0x05D3), "/daletqubuts" },
  +  { GUINT_TO_POINTER (0x05BB), "/daletqubuts" },
  +  { GUINT_TO_POINTER (0x05D3), "/daletqubutshebrew" },
  +  { GUINT_TO_POINTER (0x05BB), "/daletqubutshebrew" },
  +  { GUINT_TO_POINTER (0x05D3), "/daletsegol" },
  +  { GUINT_TO_POINTER (0x05B6), "/daletsegol" },
  +  { GUINT_TO_POINTER (0x05D3), "/daletsegolhebrew" },
  +  { GUINT_TO_POINTER (0x05B6), "/daletsegolhebrew" },
  +  { GUINT_TO_POINTER (0x05D3), "/daletsheva" },
  +  { GUINT_TO_POINTER (0x05B0), "/daletsheva" },
  +  { GUINT_TO_POINTER (0x05D3), "/daletshevahebrew" },
  +  { GUINT_TO_POINTER (0x05B0), "/daletshevahebrew" },
  +  { GUINT_TO_POINTER (0x05D3), "/dalettsere" },
  +  { GUINT_TO_POINTER (0x05B5), "/dalettsere" },
  +  { GUINT_TO_POINTER (0x05D3), "/dalettserehebrew" },
  +  { GUINT_TO_POINTER (0x05B5), "/dalettserehebrew" },
  +  { GUINT_TO_POINTER (0xFEAA), "/dalfinalarabic" },
  +  { GUINT_TO_POINTER (0x064F), "/dammaarabic" },
  +  { GUINT_TO_POINTER (0x064F), "/dammalowarabic" },
  +  { GUINT_TO_POINTER (0x064C), "/dammatanaltonearabic" },
  +  { GUINT_TO_POINTER (0x064C), "/dammatanarabic" },
  +  { GUINT_TO_POINTER (0x0964), "/danda" },
  +  { GUINT_TO_POINTER (0x05A7), "/dargahebrew" },
  +  { GUINT_TO_POINTER (0x05A7), "/dargalefthebrew" },
  +  { GUINT_TO_POINTER (0x0485), "/dasiapneumatacyrilliccmb" },
  +  { GUINT_TO_POINTER (0xF6D3), "/dblGrave" },
  +  { GUINT_TO_POINTER (0x300A), "/dblanglebracketleft" },
  +  { GUINT_TO_POINTER (0xFE3D), "/dblanglebracketleftvertical" },
  +  { GUINT_TO_POINTER (0x300B), "/dblanglebracketright" },
  +  { GUINT_TO_POINTER (0xFE3E), "/dblanglebracketrightvertical" },
  +  { GUINT_TO_POINTER (0x032B), "/dblarchinvertedbelowcmb" },
  +  { GUINT_TO_POINTER (0x21D4), "/dblarrowleft" },
  +  { GUINT_TO_POINTER (0x21D2), "/dblarrowright" },
  +  { GUINT_TO_POINTER (0x0965), "/dbldanda" },
  +  { GUINT_TO_POINTER (0xF6D6), "/dblgrave" },
  +  { GUINT_TO_POINTER (0x030F), "/dblgravecmb" },
  +  { GUINT_TO_POINTER (0x222C), "/dblintegral" },
  +  { GUINT_TO_POINTER (0x2017), "/dbllowline" },
  +  { GUINT_TO_POINTER (0x0333), "/dbllowlinecmb" },
  +  { GUINT_TO_POINTER (0x033F), "/dbloverlinecmb" },
  +  { GUINT_TO_POINTER (0x02BA), "/dblprimemod" },
  +  { GUINT_TO_POINTER (0x2016), "/dblverticalbar" },
  +  { GUINT_TO_POINTER (0x030E), "/dblverticallineabovecmb" },
  +  { GUINT_TO_POINTER (0x3109), "/dbopomofo" },
  +  { GUINT_TO_POINTER (0x33C8), "/dbsquare" },
  +  { GUINT_TO_POINTER (0x010F), "/dcaron" },
  +  { GUINT_TO_POINTER (0x1E11), "/dcedilla" },
  +  { GUINT_TO_POINTER (0x24D3), "/dcircle" },
  +  { GUINT_TO_POINTER (0x1E13), "/dcircumflexbelow" },
  +  { GUINT_TO_POINTER (0x0111), "/dcroat" },
  +  { GUINT_TO_POINTER (0x09A1), "/ddabengali" },
  +  { GUINT_TO_POINTER (0x0921), "/ddadeva" },
  +  { GUINT_TO_POINTER (0x0AA1), "/ddagujarati" },
  +  { GUINT_TO_POINTER (0x0A21), "/ddagurmukhi" },
  +  { GUINT_TO_POINTER (0x0688), "/ddalarabic" },
  +  { GUINT_TO_POINTER (0xFB89), "/ddalfinalarabic" },
  +  { GUINT_TO_POINTER (0x095C), "/dddhadeva" },
  +  { GUINT_TO_POINTER (0x09A2), "/ddhabengali" },
  +  { GUINT_TO_POINTER (0x0922), "/ddhadeva" },
  +  { GUINT_TO_POINTER (0x0AA2), "/ddhagujarati" },
  +  { GUINT_TO_POINTER (0x0A22), "/ddhagurmukhi" },
  +  { GUINT_TO_POINTER (0x1E0B), "/ddotaccent" },
  +  { GUINT_TO_POINTER (0x1E0D), "/ddotbelow" },
  +  { GUINT_TO_POINTER (0x066B), "/decimalseparatorarabic" },
  +  { GUINT_TO_POINTER (0x066B), "/decimalseparatorpersian" },
  +  { GUINT_TO_POINTER (0x0434), "/decyrillic" },
  +  { GUINT_TO_POINTER (0x00B0), "/degree" },
  +  { GUINT_TO_POINTER (0x05AD), "/dehihebrew" },
  +  { GUINT_TO_POINTER (0x3067), "/dehiragana" },
  +  { GUINT_TO_POINTER (0x03EF), "/deicoptic" },
  +  { GUINT_TO_POINTER (0x30C7), "/dekatakana" },
  +  { GUINT_TO_POINTER (0x232B), "/deleteleft" },
  +  { GUINT_TO_POINTER (0x2326), "/deleteright" },
  +  { GUINT_TO_POINTER (0x03B4), "/delta" },
  +  { GUINT_TO_POINTER (0x018D), "/deltaturned" },
  +  { GUINT_TO_POINTER (0x09F8), "/denominatorminusonenumeratorbengali" },
  +  { GUINT_TO_POINTER (0x02A4), "/dezh" },
  +  { GUINT_TO_POINTER (0x09A7), "/dhabengali" },
  +  { GUINT_TO_POINTER (0x0927), "/dhadeva" },
  +  { GUINT_TO_POINTER (0x0AA7), "/dhagujarati" },
  +  { GUINT_TO_POINTER (0x0A27), "/dhagurmukhi" },
  +  { GUINT_TO_POINTER (0x0257), "/dhook" },
  +  { GUINT_TO_POINTER (0x0385), "/dialytikatonos" },
  +  { GUINT_TO_POINTER (0x0344), "/dialytikatonoscmb" },
  +  { GUINT_TO_POINTER (0x2666), "/diamond" },
  +  { GUINT_TO_POINTER (0x2662), "/diamondsuitwhite" },
  +  { GUINT_TO_POINTER (0x00A8), "/dieresis" },
  +  { GUINT_TO_POINTER (0xF6D7), "/dieresisacute" },
  +  { GUINT_TO_POINTER (0x0324), "/dieresisbelowcmb" },
  +  { GUINT_TO_POINTER (0x0308), "/dieresiscmb" },
  +  { GUINT_TO_POINTER (0xF6D8), "/dieresisgrave" },
  +  { GUINT_TO_POINTER (0x0385), "/dieresistonos" },
  +  { GUINT_TO_POINTER (0x3062), "/dihiragana" },
  +  { GUINT_TO_POINTER (0x30C2), "/dikatakana" },
  +  { GUINT_TO_POINTER (0x3003), "/dittomark" },
  +  { GUINT_TO_POINTER (0x00F7), "/divide" },
  +  { GUINT_TO_POINTER (0x2223), "/divides" },
  +  { GUINT_TO_POINTER (0x2215), "/divisionslash" },
  +  { GUINT_TO_POINTER (0x0452), "/djecyrillic" },
  +  { GUINT_TO_POINTER (0x2593), "/dkshade" },
  +  { GUINT_TO_POINTER (0x1E0F), "/dlinebelow" },
  +  { GUINT_TO_POINTER (0x3397), "/dlsquare" },
  +  { GUINT_TO_POINTER (0x0111), "/dmacron" },
  +  { GUINT_TO_POINTER (0xFF44), "/dmonospace" },
  +  { GUINT_TO_POINTER (0x2584), "/dnblock" },
  +  { GUINT_TO_POINTER (0x0E0E), "/dochadathai" },
  +  { GUINT_TO_POINTER (0x0E14), "/dodekthai" },
  +  { GUINT_TO_POINTER (0x3069), "/dohiragana" },
  +  { GUINT_TO_POINTER (0x30C9), "/dokatakana" },
  +  { GUINT_TO_POINTER (0x0024), "/dollar" },
  +  { GUINT_TO_POINTER (0xF6E3), "/dollarinferior" },
  +  { GUINT_TO_POINTER (0xFF04), "/dollarmonospace" },
  +  { GUINT_TO_POINTER (0xF724), "/dollaroldstyle" },
  +  { GUINT_TO_POINTER (0xFE69), "/dollarsmall" },
  +  { GUINT_TO_POINTER (0xF6E4), "/dollarsuperior" },
  +  { GUINT_TO_POINTER (0x20AB), "/dong" },
  +  { GUINT_TO_POINTER (0x3326), "/dorusquare" },
  +  { GUINT_TO_POINTER (0x02D9), "/dotaccent" },
  +  { GUINT_TO_POINTER (0x0307), "/dotaccentcmb" },
  +  { GUINT_TO_POINTER (0x0323), "/dotbelowcmb" },
  +  { GUINT_TO_POINTER (0x0323), "/dotbelowcomb" },
  +  { GUINT_TO_POINTER (0x30FB), "/dotkatakana" },
  +  { GUINT_TO_POINTER (0x0131), "/dotlessi" },
  +  { GUINT_TO_POINTER (0xF6BE), "/dotlessj" },
  +  { GUINT_TO_POINTER (0x0284), "/dotlessjstrokehook" },
  +  { GUINT_TO_POINTER (0x22C5), "/dotmath" },
  +  { GUINT_TO_POINTER (0x25CC), "/dottedcircle" },
  +  { GUINT_TO_POINTER (0xFB1F), "/doubleyodpatah" },
  +  { GUINT_TO_POINTER (0xFB1F), "/doubleyodpatahhebrew" },
  +  { GUINT_TO_POINTER (0x031E), "/downtackbelowcmb" },
  +  { GUINT_TO_POINTER (0x02D5), "/downtackmod" },
  +  { GUINT_TO_POINTER (0x249F), "/dparen" },
  +  { GUINT_TO_POINTER (0xF6EB), "/dsuperior" },
  +  { GUINT_TO_POINTER (0x0256), "/dtail" },
  +  { GUINT_TO_POINTER (0x018C), "/dtopbar" },
  +  { GUINT_TO_POINTER (0x3065), "/duhiragana" },
  +  { GUINT_TO_POINTER (0x30C5), "/dukatakana" },
  +  { GUINT_TO_POINTER (0x01F3), "/dz" },
  +  { GUINT_TO_POINTER (0x02A3), "/dzaltone" },
  +  { GUINT_TO_POINTER (0x01C6), "/dzcaron" },
  +  { GUINT_TO_POINTER (0x02A5), "/dzcurl" },
  +  { GUINT_TO_POINTER (0x04E1), "/dzeabkhasiancyrillic" },
  +  { GUINT_TO_POINTER (0x0455), "/dzecyrillic" },
  +  { GUINT_TO_POINTER (0x045F), "/dzhecyrillic" },
  +  { GUINT_TO_POINTER (0x0065), "/e" },
  +  { GUINT_TO_POINTER (0x00E9), "/eacute" },
  +  { GUINT_TO_POINTER (0x2641), "/earth" },
  +  { GUINT_TO_POINTER (0x098F), "/ebengali" },
  +  { GUINT_TO_POINTER (0x311C), "/ebopomofo" },
  +  { GUINT_TO_POINTER (0x0115), "/ebreve" },
  +  { GUINT_TO_POINTER (0x090D), "/ecandradeva" },
  +  { GUINT_TO_POINTER (0x0A8D), "/ecandragujarati" },
  +  { GUINT_TO_POINTER (0x0945), "/ecandravowelsigndeva" },
  +  { GUINT_TO_POINTER (0x0AC5), "/ecandravowelsigngujarati" },
  +  { GUINT_TO_POINTER (0x011B), "/ecaron" },
  +  { GUINT_TO_POINTER (0x1E1D), "/ecedillabreve" },
  +  { GUINT_TO_POINTER (0x0565), "/echarmenian" },
  +  { GUINT_TO_POINTER (0x0587), "/echyiwnarmenian" },
  +  { GUINT_TO_POINTER (0x24D4), "/ecircle" },
  +  { GUINT_TO_POINTER (0x00EA), "/ecircumflex" },
  +  { GUINT_TO_POINTER (0x1EBF), "/ecircumflexacute" },
  +  { GUINT_TO_POINTER (0x1E19), "/ecircumflexbelow" },
  +  { GUINT_TO_POINTER (0x1EC7), "/ecircumflexdotbelow" },
  +  { GUINT_TO_POINTER (0x1EC1), "/ecircumflexgrave" },
  +  { GUINT_TO_POINTER (0x1EC3), "/ecircumflexhookabove" },
  +  { GUINT_TO_POINTER (0x1EC5), "/ecircumflextilde" },
  +  { GUINT_TO_POINTER (0x0454), "/ecyrillic" },
  +  { GUINT_TO_POINTER (0x0205), "/edblgrave" },
  +  { GUINT_TO_POINTER (0x090F), "/edeva" },
  +  { GUINT_TO_POINTER (0x00EB), "/edieresis" },
  +  { GUINT_TO_POINTER (0x0117), "/edot" },
  +  { GUINT_TO_POINTER (0x0117), "/edotaccent" },
  +  { GUINT_TO_POINTER (0x1EB9), "/edotbelow" },
  +  { GUINT_TO_POINTER (0x0A0F), "/eegurmukhi" },
  +  { GUINT_TO_POINTER (0x0A47), "/eematragurmukhi" },
  +  { GUINT_TO_POINTER (0x0444), "/efcyrillic" },
  +  { GUINT_TO_POINTER (0x00E8), "/egrave" },
  +  { GUINT_TO_POINTER (0x0A8F), "/egujarati" },
  +  { GUINT_TO_POINTER (0x0567), "/eharmenian" },
  +  { GUINT_TO_POINTER (0x311D), "/ehbopomofo" },
  +  { GUINT_TO_POINTER (0x3048), "/ehiragana" },
  +  { GUINT_TO_POINTER (0x1EBB), "/ehookabove" },
  +  { GUINT_TO_POINTER (0x311F), "/eibopomofo" },
  +  { GUINT_TO_POINTER (0x0038), "/eight" },
  +  { GUINT_TO_POINTER (0x0668), "/eightarabic" },
  +  { GUINT_TO_POINTER (0x09EE), "/eightbengali" },
  +  { GUINT_TO_POINTER (0x2467), "/eightcircle" },
  +  { GUINT_TO_POINTER (0x2791), "/eightcircleinversesansserif" },
  +  { GUINT_TO_POINTER (0x096E), "/eightdeva" },
  +  { GUINT_TO_POINTER (0x2471), "/eighteencircle" },
  +  { GUINT_TO_POINTER (0x2485), "/eighteenparen" },
  +  { GUINT_TO_POINTER (0x2499), "/eighteenperiod" },
  +  { GUINT_TO_POINTER (0x0AEE), "/eightgujarati" },
  +  { GUINT_TO_POINTER (0x0A6E), "/eightgurmukhi" },
  +  { GUINT_TO_POINTER (0x0668), "/eighthackarabic" },
  +  { GUINT_TO_POINTER (0x3028), "/eighthangzhou" },
  +  { GUINT_TO_POINTER (0x266B), "/eighthnotebeamed" },
  +  { GUINT_TO_POINTER (0x3227), "/eightideographicparen" },
  +  { GUINT_TO_POINTER (0x2088), "/eightinferior" },
  +  { GUINT_TO_POINTER (0xFF18), "/eightmonospace" },
  +  { GUINT_TO_POINTER (0xF738), "/eightoldstyle" },
  +  { GUINT_TO_POINTER (0x247B), "/eightparen" },
  +  { GUINT_TO_POINTER (0x248F), "/eightperiod" },
  +  { GUINT_TO_POINTER (0x06F8), "/eightpersian" },
  +  { GUINT_TO_POINTER (0x2177), "/eightroman" },
  +  { GUINT_TO_POINTER (0x2078), "/eightsuperior" },
  +  { GUINT_TO_POINTER (0x0E58), "/eightthai" },
  +  { GUINT_TO_POINTER (0x0207), "/einvertedbreve" },
  +  { GUINT_TO_POINTER (0x0465), "/eiotifiedcyrillic" },
  +  { GUINT_TO_POINTER (0x30A8), "/ekatakana" },
  +  { GUINT_TO_POINTER (0xFF74), "/ekatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x0A74), "/ekonkargurmukhi" },
  +  { GUINT_TO_POINTER (0x3154), "/ekorean" },
  +  { GUINT_TO_POINTER (0x043B), "/elcyrillic" },
  +  { GUINT_TO_POINTER (0x2208), "/element" },
  +  { GUINT_TO_POINTER (0x246A), "/elevencircle" },
  +  { GUINT_TO_POINTER (0x247E), "/elevenparen" },
  +  { GUINT_TO_POINTER (0x2492), "/elevenperiod" },
  +  { GUINT_TO_POINTER (0x217A), "/elevenroman" },
  +  { GUINT_TO_POINTER (0x2026), "/ellipsis" },
  +  { GUINT_TO_POINTER (0x22EE), "/ellipsisvertical" },
  +  { GUINT_TO_POINTER (0x0113), "/emacron" },
  +  { GUINT_TO_POINTER (0x1E17), "/emacronacute" },
  +  { GUINT_TO_POINTER (0x1E15), "/emacrongrave" },
  +  { GUINT_TO_POINTER (0x043C), "/emcyrillic" },
  +  { GUINT_TO_POINTER (0x2014), "/emdash" },
  +  { GUINT_TO_POINTER (0xFE31), "/emdashvertical" },
  +  { GUINT_TO_POINTER (0xFF45), "/emonospace" },
  +  { GUINT_TO_POINTER (0x055B), "/emphasismarkarmenian" },
  +  { GUINT_TO_POINTER (0x2205), "/emptyset" },
  +  { GUINT_TO_POINTER (0x3123), "/enbopomofo" },
  +  { GUINT_TO_POINTER (0x043D), "/encyrillic" },
  +  { GUINT_TO_POINTER (0x2013), "/endash" },
  +  { GUINT_TO_POINTER (0xFE32), "/endashvertical" },
  +  { GUINT_TO_POINTER (0x04A3), "/endescendercyrillic" },
  +  { GUINT_TO_POINTER (0x014B), "/eng" },
  +  { GUINT_TO_POINTER (0x3125), "/engbopomofo" },
  +  { GUINT_TO_POINTER (0x04A5), "/enghecyrillic" },
  +  { GUINT_TO_POINTER (0x04C8), "/enhookcyrillic" },
  +  { GUINT_TO_POINTER (0x2002), "/enspace" },
  +  { GUINT_TO_POINTER (0x0119), "/eogonek" },
  +  { GUINT_TO_POINTER (0x3153), "/eokorean" },
  +  { GUINT_TO_POINTER (0x025B), "/eopen" },
  +  { GUINT_TO_POINTER (0x029A), "/eopenclosed" },
  +  { GUINT_TO_POINTER (0x025C), "/eopenreversed" },
  +  { GUINT_TO_POINTER (0x025E), "/eopenreversedclosed" },
  +  { GUINT_TO_POINTER (0x025D), "/eopenreversedhook" },
  +  { GUINT_TO_POINTER (0x24A0), "/eparen" },
  +  { GUINT_TO_POINTER (0x03B5), "/epsilon" },
  +  { GUINT_TO_POINTER (0x03AD), "/epsilontonos" },
  +  { GUINT_TO_POINTER (0x003D), "/equal" },
  +  { GUINT_TO_POINTER (0xFF1D), "/equalmonospace" },
  +  { GUINT_TO_POINTER (0xFE66), "/equalsmall" },
  +  { GUINT_TO_POINTER (0x207C), "/equalsuperior" },
  +  { GUINT_TO_POINTER (0x2261), "/equivalence" },
  +  { GUINT_TO_POINTER (0x3126), "/erbopomofo" },
  +  { GUINT_TO_POINTER (0x0440), "/ercyrillic" },
  +  { GUINT_TO_POINTER (0x0258), "/ereversed" },
  +  { GUINT_TO_POINTER (0x044D), "/ereversedcyrillic" },
  +  { GUINT_TO_POINTER (0x0441), "/escyrillic" },
  +  { GUINT_TO_POINTER (0x04AB), "/esdescendercyrillic" },
  +  { GUINT_TO_POINTER (0x0283), "/esh" },
  +  { GUINT_TO_POINTER (0x0286), "/eshcurl" },
  +  { GUINT_TO_POINTER (0x090E), "/eshortdeva" },
  +  { GUINT_TO_POINTER (0x0946), "/eshortvowelsigndeva" },
  +  { GUINT_TO_POINTER (0x01AA), "/eshreversedloop" },
  +  { GUINT_TO_POINTER (0x0285), "/eshsquatreversed" },
  +  { GUINT_TO_POINTER (0x3047), "/esmallhiragana" },
  +  { GUINT_TO_POINTER (0x30A7), "/esmallkatakana" },
  +  { GUINT_TO_POINTER (0xFF6A), "/esmallkatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x212E), "/estimated" },
  +  { GUINT_TO_POINTER (0xF6EC), "/esuperior" },
  +  { GUINT_TO_POINTER (0x03B7), "/eta" },
  +  { GUINT_TO_POINTER (0x0568), "/etarmenian" },
  +  { GUINT_TO_POINTER (0x03AE), "/etatonos" },
  +  { GUINT_TO_POINTER (0x00F0), "/eth" },
  +  { GUINT_TO_POINTER (0x1EBD), "/etilde" },
  +  { GUINT_TO_POINTER (0x1E1B), "/etildebelow" },
  +  { GUINT_TO_POINTER (0x0591), "/etnahtafoukhhebrew" },
  +  { GUINT_TO_POINTER (0x0591), "/etnahtafoukhlefthebrew" },
  +  { GUINT_TO_POINTER (0x0591), "/etnahtahebrew" },
  +  { GUINT_TO_POINTER (0x0591), "/etnahtalefthebrew" },
  +  { GUINT_TO_POINTER (0x01DD), "/eturned" },
  +  { GUINT_TO_POINTER (0x3161), "/eukorean" },
  +  { GUINT_TO_POINTER (0x20AC), "/euro" },
  +  { GUINT_TO_POINTER (0x09C7), "/evowelsignbengali" },
  +  { GUINT_TO_POINTER (0x0947), "/evowelsigndeva" },
  +  { GUINT_TO_POINTER (0x0AC7), "/evowelsigngujarati" },
  +  { GUINT_TO_POINTER (0x0021), "/exclam" },
  +  { GUINT_TO_POINTER (0x055C), "/exclamarmenian" },
  +  { GUINT_TO_POINTER (0x203C), "/exclamdbl" },
  +  { GUINT_TO_POINTER (0x00A1), "/exclamdown" },
  +  { GUINT_TO_POINTER (0xF7A1), "/exclamdownsmall" },
  +  { GUINT_TO_POINTER (0xFF01), "/exclammonospace" },
  +  { GUINT_TO_POINTER (0xF721), "/exclamsmall" },
  +  { GUINT_TO_POINTER (0x2203), "/existential" },
  +  { GUINT_TO_POINTER (0x0292), "/ezh" },
  +  { GUINT_TO_POINTER (0x01EF), "/ezhcaron" },
  +  { GUINT_TO_POINTER (0x0293), "/ezhcurl" },
  +  { GUINT_TO_POINTER (0x01B9), "/ezhreversed" },
  +  { GUINT_TO_POINTER (0x01BA), "/ezhtail" },
  +  { GUINT_TO_POINTER (0x0066), "/f" },
  +  { GUINT_TO_POINTER (0x095E), "/fadeva" },
  +  { GUINT_TO_POINTER (0x0A5E), "/fagurmukhi" },
  +  { GUINT_TO_POINTER (0x2109), "/fahrenheit" },
  +  { GUINT_TO_POINTER (0x064E), "/fathaarabic" },
  +  { GUINT_TO_POINTER (0x064E), "/fathalowarabic" },
  +  { GUINT_TO_POINTER (0x064B), "/fathatanarabic" },
  +  { GUINT_TO_POINTER (0x3108), "/fbopomofo" },
  +  { GUINT_TO_POINTER (0x24D5), "/fcircle" },
  +  { GUINT_TO_POINTER (0x1E1F), "/fdotaccent" },
  +  { GUINT_TO_POINTER (0x0641), "/feharabic" },
  +  { GUINT_TO_POINTER (0x0586), "/feharmenian" },
  +  { GUINT_TO_POINTER (0xFED2), "/fehfinalarabic" },
  +  { GUINT_TO_POINTER (0xFED3), "/fehinitialarabic" },
  +  { GUINT_TO_POINTER (0xFED4), "/fehmedialarabic" },
  +  { GUINT_TO_POINTER (0x03E5), "/feicoptic" },
  +  { GUINT_TO_POINTER (0x2640), "/female" },
  +  { GUINT_TO_POINTER (0xFB00), "/ff" },
  +  { GUINT_TO_POINTER (0xFB03), "/ffi" },
  +  { GUINT_TO_POINTER (0xFB04), "/ffl" },
  +  { GUINT_TO_POINTER (0xFB01), "/fi" },
  +  { GUINT_TO_POINTER (0x246E), "/fifteencircle" },
  +  { GUINT_TO_POINTER (0x2482), "/fifteenparen" },
  +  { GUINT_TO_POINTER (0x2496), "/fifteenperiod" },
  +  { GUINT_TO_POINTER (0x2012), "/figuredash" },
  +  { GUINT_TO_POINTER (0x25A0), "/filledbox" },
  +  { GUINT_TO_POINTER (0x25AC), "/filledrect" },
  +  { GUINT_TO_POINTER (0x05DA), "/finalkaf" },
  +  { GUINT_TO_POINTER (0xFB3A), "/finalkafdagesh" },
  +  { GUINT_TO_POINTER (0xFB3A), "/finalkafdageshhebrew" },
  +  { GUINT_TO_POINTER (0x05DA), "/finalkafhebrew" },
  +  { GUINT_TO_POINTER (0x05DA), "/finalkafqamats" },
  +  { GUINT_TO_POINTER (0x05B8), "/finalkafqamats" },
  +  { GUINT_TO_POINTER (0x05DA), "/finalkafqamatshebrew" },
  +  { GUINT_TO_POINTER (0x05B8), "/finalkafqamatshebrew" },
  +  { GUINT_TO_POINTER (0x05DA), "/finalkafsheva" },
  +  { GUINT_TO_POINTER (0x05B0), "/finalkafsheva" },
  +  { GUINT_TO_POINTER (0x05DA), "/finalkafshevahebrew" },
  +  { GUINT_TO_POINTER (0x05B0), "/finalkafshevahebrew" },
  +  { GUINT_TO_POINTER (0x05DD), "/finalmem" },
  +  { GUINT_TO_POINTER (0x05DD), "/finalmemhebrew" },
  +  { GUINT_TO_POINTER (0x05DF), "/finalnun" },
  +  { GUINT_TO_POINTER (0x05DF), "/finalnunhebrew" },
  +  { GUINT_TO_POINTER (0x05E3), "/finalpe" },
  +  { GUINT_TO_POINTER (0x05E3), "/finalpehebrew" },
  +  { GUINT_TO_POINTER (0x05E5), "/finaltsadi" },
  +  { GUINT_TO_POINTER (0x05E5), "/finaltsadihebrew" },
  +  { GUINT_TO_POINTER (0x02C9), "/firsttonechinese" },
  +  { GUINT_TO_POINTER (0x25C9), "/fisheye" },
  +  { GUINT_TO_POINTER (0x0473), "/fitacyrillic" },
  +  { GUINT_TO_POINTER (0x0035), "/five" },
  +  { GUINT_TO_POINTER (0x0665), "/fivearabic" },
  +  { GUINT_TO_POINTER (0x09EB), "/fivebengali" },
  +  { GUINT_TO_POINTER (0x2464), "/fivecircle" },
  +  { GUINT_TO_POINTER (0x278E), "/fivecircleinversesansserif" },
  +  { GUINT_TO_POINTER (0x096B), "/fivedeva" },
  +  { GUINT_TO_POINTER (0x215D), "/fiveeighths" },
  +  { GUINT_TO_POINTER (0x0AEB), "/fivegujarati" },
  +  { GUINT_TO_POINTER (0x0A6B), "/fivegurmukhi" },
  +  { GUINT_TO_POINTER (0x0665), "/fivehackarabic" },
  +  { GUINT_TO_POINTER (0x3025), "/fivehangzhou" },
  +  { GUINT_TO_POINTER (0x3224), "/fiveideographicparen" },
  +  { GUINT_TO_POINTER (0x2085), "/fiveinferior" },
  +  { GUINT_TO_POINTER (0xFF15), "/fivemonospace" },
  +  { GUINT_TO_POINTER (0xF735), "/fiveoldstyle" },
  +  { GUINT_TO_POINTER (0x2478), "/fiveparen" },
  +  { GUINT_TO_POINTER (0x248C), "/fiveperiod" },
  +  { GUINT_TO_POINTER (0x06F5), "/fivepersian" },
  +  { GUINT_TO_POINTER (0x2174), "/fiveroman" },
  +  { GUINT_TO_POINTER (0x2075), "/fivesuperior" },
  +  { GUINT_TO_POINTER (0x0E55), "/fivethai" },
  +  { GUINT_TO_POINTER (0xFB02), "/fl" },
  +  { GUINT_TO_POINTER (0x0192), "/florin" },
  +  { GUINT_TO_POINTER (0xFF46), "/fmonospace" },
  +  { GUINT_TO_POINTER (0x3399), "/fmsquare" },
  +  { GUINT_TO_POINTER (0x0E1F), "/fofanthai" },
  +  { GUINT_TO_POINTER (0x0E1D), "/fofathai" },
  +  { GUINT_TO_POINTER (0x0E4F), "/fongmanthai" },
  +  { GUINT_TO_POINTER (0x2200), "/forall" },
  +  { GUINT_TO_POINTER (0x0034), "/four" },
  +  { GUINT_TO_POINTER (0x0664), "/fourarabic" },
  +  { GUINT_TO_POINTER (0x09EA), "/fourbengali" },
  +  { GUINT_TO_POINTER (0x2463), "/fourcircle" },
  +  { GUINT_TO_POINTER (0x278D), "/fourcircleinversesansserif" },
  +  { GUINT_TO_POINTER (0x096A), "/fourdeva" },
  +  { GUINT_TO_POINTER (0x0AEA), "/fourgujarati" },
  +  { GUINT_TO_POINTER (0x0A6A), "/fourgurmukhi" },
  +  { GUINT_TO_POINTER (0x0664), "/fourhackarabic" },
  +  { GUINT_TO_POINTER (0x3024), "/fourhangzhou" },
  +  { GUINT_TO_POINTER (0x3223), "/fourideographicparen" },
  +  { GUINT_TO_POINTER (0x2084), "/fourinferior" },
  +  { GUINT_TO_POINTER (0xFF14), "/fourmonospace" },
  +  { GUINT_TO_POINTER (0x09F7), "/fournumeratorbengali" },
  +  { GUINT_TO_POINTER (0xF734), "/fouroldstyle" },
  +  { GUINT_TO_POINTER (0x2477), "/fourparen" },
  +  { GUINT_TO_POINTER (0x248B), "/fourperiod" },
  +  { GUINT_TO_POINTER (0x06F4), "/fourpersian" },
  +  { GUINT_TO_POINTER (0x2173), "/fourroman" },
  +  { GUINT_TO_POINTER (0x2074), "/foursuperior" },
  +  { GUINT_TO_POINTER (0x246D), "/fourteencircle" },
  +  { GUINT_TO_POINTER (0x2481), "/fourteenparen" },
  +  { GUINT_TO_POINTER (0x2495), "/fourteenperiod" },
  +  { GUINT_TO_POINTER (0x0E54), "/fourthai" },
  +  { GUINT_TO_POINTER (0x02CB), "/fourthtonechinese" },
  +  { GUINT_TO_POINTER (0x24A1), "/fparen" },
  +  { GUINT_TO_POINTER (0x2044), "/fraction" },
  +  { GUINT_TO_POINTER (0x20A3), "/franc" },
  +  { GUINT_TO_POINTER (0x0067), "/g" },
  +  { GUINT_TO_POINTER (0x0997), "/gabengali" },
  +  { GUINT_TO_POINTER (0x01F5), "/gacute" },
  +  { GUINT_TO_POINTER (0x0917), "/gadeva" },
  +  { GUINT_TO_POINTER (0x06AF), "/gafarabic" },
  +  { GUINT_TO_POINTER (0xFB93), "/gaffinalarabic" },
  +  { GUINT_TO_POINTER (0xFB94), "/gafinitialarabic" },
  +  { GUINT_TO_POINTER (0xFB95), "/gafmedialarabic" },
  +  { GUINT_TO_POINTER (0x0A97), "/gagujarati" },
  +  { GUINT_TO_POINTER (0x0A17), "/gagurmukhi" },
  +  { GUINT_TO_POINTER (0x304C), "/gahiragana" },
  +  { GUINT_TO_POINTER (0x30AC), "/gakatakana" },
  +  { GUINT_TO_POINTER (0x03B3), "/gamma" },
  +  { GUINT_TO_POINTER (0x0263), "/gammalatinsmall" },
  +  { GUINT_TO_POINTER (0x02E0), "/gammasuperior" },
  +  { GUINT_TO_POINTER (0x03EB), "/gangiacoptic" },
  +  { GUINT_TO_POINTER (0x310D), "/gbopomofo" },
  +  { GUINT_TO_POINTER (0x011F), "/gbreve" },
  +  { GUINT_TO_POINTER (0x01E7), "/gcaron" },
  +  { GUINT_TO_POINTER (0x0123), "/gcedilla" },
  +  { GUINT_TO_POINTER (0x24D6), "/gcircle" },
  +  { GUINT_TO_POINTER (0x011D), "/gcircumflex" },
  +  { GUINT_TO_POINTER (0x0123), "/gcommaaccent" },
  +  { GUINT_TO_POINTER (0x0121), "/gdot" },
  +  { GUINT_TO_POINTER (0x0121), "/gdotaccent" },
  +  { GUINT_TO_POINTER (0x0433), "/gecyrillic" },
  +  { GUINT_TO_POINTER (0x3052), "/gehiragana" },
  +  { GUINT_TO_POINTER (0x30B2), "/gekatakana" },
  +  { GUINT_TO_POINTER (0x2251), "/geometricallyequal" },
  +  { GUINT_TO_POINTER (0x059C), "/gereshaccenthebrew" },
  +  { GUINT_TO_POINTER (0x05F3), "/gereshhebrew" },
  +  { GUINT_TO_POINTER (0x059D), "/gereshmuqdamhebrew" },
  +  { GUINT_TO_POINTER (0x00DF), "/germandbls" },
  +  { GUINT_TO_POINTER (0x059E), "/gershayimaccenthebrew" },
  +  { GUINT_TO_POINTER (0x05F4), "/gershayimhebrew" },
  +  { GUINT_TO_POINTER (0x3013), "/getamark" },
  +  { GUINT_TO_POINTER (0x0998), "/ghabengali" },
  +  { GUINT_TO_POINTER (0x0572), "/ghadarmenian" },
  +  { GUINT_TO_POINTER (0x0918), "/ghadeva" },
  +  { GUINT_TO_POINTER (0x0A98), "/ghagujarati" },
  +  { GUINT_TO_POINTER (0x0A18), "/ghagurmukhi" },
  +  { GUINT_TO_POINTER (0x063A), "/ghainarabic" },
  +  { GUINT_TO_POINTER (0xFECE), "/ghainfinalarabic" },
  +  { GUINT_TO_POINTER (0xFECF), "/ghaininitialarabic" },
  +  { GUINT_TO_POINTER (0xFED0), "/ghainmedialarabic" },
  +  { GUINT_TO_POINTER (0x0495), "/ghemiddlehookcyrillic" },
  +  { GUINT_TO_POINTER (0x0493), "/ghestrokecyrillic" },
  +  { GUINT_TO_POINTER (0x0491), "/gheupturncyrillic" },
  +  { GUINT_TO_POINTER (0x095A), "/ghhadeva" },
  +  { GUINT_TO_POINTER (0x0A5A), "/ghhagurmukhi" },
  +  { GUINT_TO_POINTER (0x0260), "/ghook" },
  +  { GUINT_TO_POINTER (0x3393), "/ghzsquare" },
  +  { GUINT_TO_POINTER (0x304E), "/gihiragana" },
  +  { GUINT_TO_POINTER (0x30AE), "/gikatakana" },
  +  { GUINT_TO_POINTER (0x0563), "/gimarmenian" },
  +  { GUINT_TO_POINTER (0x05D2), "/gimel" },
  +  { GUINT_TO_POINTER (0xFB32), "/gimeldagesh" },
  +  { GUINT_TO_POINTER (0xFB32), "/gimeldageshhebrew" },
  +  { GUINT_TO_POINTER (0x05D2), "/gimelhebrew" },
  +  { GUINT_TO_POINTER (0x0453), "/gjecyrillic" },
  +  { GUINT_TO_POINTER (0x01BE), "/glottalinvertedstroke" },
  +  { GUINT_TO_POINTER (0x0294), "/glottalstop" },
  +  { GUINT_TO_POINTER (0x0296), "/glottalstopinverted" },
  +  { GUINT_TO_POINTER (0x02C0), "/glottalstopmod" },
  +  { GUINT_TO_POINTER (0x0295), "/glottalstopreversed" },
  +  { GUINT_TO_POINTER (0x02C1), "/glottalstopreversedmod" },
  +  { GUINT_TO_POINTER (0x02E4), "/glottalstopreversedsuperior" },
  +  { GUINT_TO_POINTER (0x02A1), "/glottalstopstroke" },
  +  { GUINT_TO_POINTER (0x02A2), "/glottalstopstrokereversed" },
  +  { GUINT_TO_POINTER (0x1E21), "/gmacron" },
  +  { GUINT_TO_POINTER (0xFF47), "/gmonospace" },
  +  { GUINT_TO_POINTER (0x3054), "/gohiragana" },
  +  { GUINT_TO_POINTER (0x30B4), "/gokatakana" },
  +  { GUINT_TO_POINTER (0x24A2), "/gparen" },
  +  { GUINT_TO_POINTER (0x33AC), "/gpasquare" },
  +  { GUINT_TO_POINTER (0x2207), "/gradient" },
  +  { GUINT_TO_POINTER (0x0060), "/grave" },
  +  { GUINT_TO_POINTER (0x0316), "/gravebelowcmb" },
  +  { GUINT_TO_POINTER (0x0300), "/gravecmb" },
  +  { GUINT_TO_POINTER (0x0300), "/gravecomb" },
  +  { GUINT_TO_POINTER (0x0953), "/gravedeva" },
  +  { GUINT_TO_POINTER (0x02CE), "/gravelowmod" },
  +  { GUINT_TO_POINTER (0xFF40), "/gravemonospace" },
  +  { GUINT_TO_POINTER (0x0340), "/gravetonecmb" },
  +  { GUINT_TO_POINTER (0x003E), "/greater" },
  +  { GUINT_TO_POINTER (0x2265), "/greaterequal" },
  +  { GUINT_TO_POINTER (0x22DB), "/greaterequalorless" },
  +  { GUINT_TO_POINTER (0xFF1E), "/greatermonospace" },
  +  { GUINT_TO_POINTER (0x2273), "/greaterorequivalent" },
  +  { GUINT_TO_POINTER (0x2277), "/greaterorless" },
  +  { GUINT_TO_POINTER (0x2267), "/greateroverequal" },
  +  { GUINT_TO_POINTER (0xFE65), "/greatersmall" },
  +  { GUINT_TO_POINTER (0x0261), "/gscript" },
  +  { GUINT_TO_POINTER (0x01E5), "/gstroke" },
  +  { GUINT_TO_POINTER (0x3050), "/guhiragana" },
  +  { GUINT_TO_POINTER (0x00AB), "/guillemotleft" },
  +  { GUINT_TO_POINTER (0x00BB), "/guillemotright" },
  +  { GUINT_TO_POINTER (0x2039), "/guilsinglleft" },
  +  { GUINT_TO_POINTER (0x203A), "/guilsinglright" },
  +  { GUINT_TO_POINTER (0x30B0), "/gukatakana" },
  +  { GUINT_TO_POINTER (0x3318), "/guramusquare" },
  +  { GUINT_TO_POINTER (0x33C9), "/gysquare" },
  +  { GUINT_TO_POINTER (0x0068), "/h" },
  +  { GUINT_TO_POINTER (0x04A9), "/haabkhasiancyrillic" },
  +  { GUINT_TO_POINTER (0x06C1), "/haaltonearabic" },
  +  { GUINT_TO_POINTER (0x09B9), "/habengali" },
  +  { GUINT_TO_POINTER (0x04B3), "/hadescendercyrillic" },
  +  { GUINT_TO_POINTER (0x0939), "/hadeva" },
  +  { GUINT_TO_POINTER (0x0AB9), "/hagujarati" },
  +  { GUINT_TO_POINTER (0x0A39), "/hagurmukhi" },
  +  { GUINT_TO_POINTER (0x062D), "/haharabic" },
  +  { GUINT_TO_POINTER (0xFEA2), "/hahfinalarabic" },
  +  { GUINT_TO_POINTER (0xFEA3), "/hahinitialarabic" },
  +  { GUINT_TO_POINTER (0x306F), "/hahiragana" },
  +  { GUINT_TO_POINTER (0xFEA4), "/hahmedialarabic" },
  +  { GUINT_TO_POINTER (0x332A), "/haitusquare" },
  +  { GUINT_TO_POINTER (0x30CF), "/hakatakana" },
  +  { GUINT_TO_POINTER (0xFF8A), "/hakatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x0A4D), "/halantgurmukhi" },
  +  { GUINT_TO_POINTER (0x0621), "/hamzaarabic" },
  +  { GUINT_TO_POINTER (0x0621), "/hamzadammaarabic" },
  +  { GUINT_TO_POINTER (0x064F), "/hamzadammaarabic" },
  +  { GUINT_TO_POINTER (0x0621), "/hamzadammatanarabic" },
  +  { GUINT_TO_POINTER (0x064C), "/hamzadammatanarabic" },
  +  { GUINT_TO_POINTER (0x0621), "/hamzafathaarabic" },
  +  { GUINT_TO_POINTER (0x064E), "/hamzafathaarabic" },
  +  { GUINT_TO_POINTER (0x0621), "/hamzafathatanarabic" },
  +  { GUINT_TO_POINTER (0x064B), "/hamzafathatanarabic" },
  +  { GUINT_TO_POINTER (0x0621), "/hamzalowarabic" },
  +  { GUINT_TO_POINTER (0x0621), "/hamzalowkasraarabic" },
  +  { GUINT_TO_POINTER (0x0650), "/hamzalowkasraarabic" },
  +  { GUINT_TO_POINTER (0x0621), "/hamzalowkasratanarabic" },
  +  { GUINT_TO_POINTER (0x064D), "/hamzalowkasratanarabic" },
  +  { GUINT_TO_POINTER (0x0621), "/hamzasukunarabic" },
  +  { GUINT_TO_POINTER (0x0652), "/hamzasukunarabic" },
  +  { GUINT_TO_POINTER (0x3164), "/hangulfiller" },
  +  { GUINT_TO_POINTER (0x044A), "/hardsigncyrillic" },
  +  { GUINT_TO_POINTER (0x21BC), "/harpoonleftbarbup" },
  +  { GUINT_TO_POINTER (0x21C0), "/harpoonrightbarbup" },
  +  { GUINT_TO_POINTER (0x33CA), "/hasquare" },
  +  { GUINT_TO_POINTER (0x05B2), "/hatafpatah" },
  +  { GUINT_TO_POINTER (0x05B2), "/hatafpatah16" },
  +  { GUINT_TO_POINTER (0x05B2), "/hatafpatah23" },
  +  { GUINT_TO_POINTER (0x05B2), "/hatafpatah2f" },
  +  { GUINT_TO_POINTER (0x05B2), "/hatafpatahhebrew" },
  +  { GUINT_TO_POINTER (0x05B2), "/hatafpatahnarrowhebrew" },
  +  { GUINT_TO_POINTER (0x05B2), "/hatafpatahquarterhebrew" },
  +  { GUINT_TO_POINTER (0x05B2), "/hatafpatahwidehebrew" },
  +  { GUINT_TO_POINTER (0x05B3), "/hatafqamats" },
  +  { GUINT_TO_POINTER (0x05B3), "/hatafqamats1b" },
  +  { GUINT_TO_POINTER (0x05B3), "/hatafqamats28" },
  +  { GUINT_TO_POINTER (0x05B3), "/hatafqamats34" },
  +  { GUINT_TO_POINTER (0x05B3), "/hatafqamatshebrew" },
  +  { GUINT_TO_POINTER (0x05B3), "/hatafqamatsnarrowhebrew" },
  +  { GUINT_TO_POINTER (0x05B3), "/hatafqamatsquarterhebrew" },
  +  { GUINT_TO_POINTER (0x05B3), "/hatafqamatswidehebrew" },
  +  { GUINT_TO_POINTER (0x05B1), "/hatafsegol" },
  +  { GUINT_TO_POINTER (0x05B1), "/hatafsegol17" },
  +  { GUINT_TO_POINTER (0x05B1), "/hatafsegol24" },
  +  { GUINT_TO_POINTER (0x05B1), "/hatafsegol30" },
  +  { GUINT_TO_POINTER (0x05B1), "/hatafsegolhebrew" },
  +  { GUINT_TO_POINTER (0x05B1), "/hatafsegolnarrowhebrew" },
  +  { GUINT_TO_POINTER (0x05B1), "/hatafsegolquarterhebrew" },
  +  { GUINT_TO_POINTER (0x05B1), "/hatafsegolwidehebrew" },
  +  { GUINT_TO_POINTER (0x0127), "/hbar" },
  +  { GUINT_TO_POINTER (0x310F), "/hbopomofo" },
  +  { GUINT_TO_POINTER (0x1E2B), "/hbrevebelow" },
  +  { GUINT_TO_POINTER (0x1E29), "/hcedilla" },
  +  { GUINT_TO_POINTER (0x24D7), "/hcircle" },
  +  { GUINT_TO_POINTER (0x0125), "/hcircumflex" },
  +  { GUINT_TO_POINTER (0x1E27), "/hdieresis" },
  +  { GUINT_TO_POINTER (0x1E23), "/hdotaccent" },
  +  { GUINT_TO_POINTER (0x1E25), "/hdotbelow" },
  +  { GUINT_TO_POINTER (0x05D4), "/he" },
  +  { GUINT_TO_POINTER (0x2665), "/heart" },
  +  { GUINT_TO_POINTER (0x2665), "/heartsuitblack" },
  +  { GUINT_TO_POINTER (0x2661), "/heartsuitwhite" },
  +  { GUINT_TO_POINTER (0xFB34), "/hedagesh" },
  +  { GUINT_TO_POINTER (0xFB34), "/hedageshhebrew" },
  +  { GUINT_TO_POINTER (0x06C1), "/hehaltonearabic" },
  +  { GUINT_TO_POINTER (0x0647), "/heharabic" },
  +  { GUINT_TO_POINTER (0x05D4), "/hehebrew" },
  +  { GUINT_TO_POINTER (0xFBA7), "/hehfinalaltonearabic" },
  +  { GUINT_TO_POINTER (0xFEEA), "/hehfinalalttwoarabic" },
  +  { GUINT_TO_POINTER (0xFEEA), "/hehfinalarabic" },
  +  { GUINT_TO_POINTER (0xFBA5), "/hehhamzaabovefinalarabic" },
  +  { GUINT_TO_POINTER (0xFBA4), "/hehhamzaaboveisolatedarabic" },
  +  { GUINT_TO_POINTER (0xFBA8), "/hehinitialaltonearabic" },
  +  { GUINT_TO_POINTER (0xFEEB), "/hehinitialarabic" },
  +  { GUINT_TO_POINTER (0x3078), "/hehiragana" },
  +  { GUINT_TO_POINTER (0xFBA9), "/hehmedialaltonearabic" },
  +  { GUINT_TO_POINTER (0xFEEC), "/hehmedialarabic" },
  +  { GUINT_TO_POINTER (0x337B), "/heiseierasquare" },
  +  { GUINT_TO_POINTER (0x30D8), "/hekatakana" },
  +  { GUINT_TO_POINTER (0xFF8D), "/hekatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x3336), "/hekutaarusquare" },
  +  { GUINT_TO_POINTER (0x0267), "/henghook" },
  +  { GUINT_TO_POINTER (0x3339), "/herutusquare" },
  +  { GUINT_TO_POINTER (0x05D7), "/het" },
  +  { GUINT_TO_POINTER (0x05D7), "/hethebrew" },
  +  { GUINT_TO_POINTER (0x0266), "/hhook" },
  +  { GUINT_TO_POINTER (0x02B1), "/hhooksuperior" },
  +  { GUINT_TO_POINTER (0x327B), "/hieuhacirclekorean" },
  +  { GUINT_TO_POINTER (0x321B), "/hieuhaparenkorean" },
  +  { GUINT_TO_POINTER (0x326D), "/hieuhcirclekorean" },
  +  { GUINT_TO_POINTER (0x314E), "/hieuhkorean" },
  +  { GUINT_TO_POINTER (0x320D), "/hieuhparenkorean" },
  +  { GUINT_TO_POINTER (0x3072), "/hihiragana" },
  +  { GUINT_TO_POINTER (0x30D2), "/hikatakana" },
  +  { GUINT_TO_POINTER (0xFF8B), "/hikatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x05B4), "/hiriq" },
  +  { GUINT_TO_POINTER (0x05B4), "/hiriq14" },
  +  { GUINT_TO_POINTER (0x05B4), "/hiriq21" },
  +  { GUINT_TO_POINTER (0x05B4), "/hiriq2d" },
  +  { GUINT_TO_POINTER (0x05B4), "/hiriqhebrew" },
  +  { GUINT_TO_POINTER (0x05B4), "/hiriqnarrowhebrew" },
  +  { GUINT_TO_POINTER (0x05B4), "/hiriqquarterhebrew" },
  +  { GUINT_TO_POINTER (0x05B4), "/hiriqwidehebrew" },
  +  { GUINT_TO_POINTER (0x1E96), "/hlinebelow" },
  +  { GUINT_TO_POINTER (0xFF48), "/hmonospace" },
  +  { GUINT_TO_POINTER (0x0570), "/hoarmenian" },
  +  { GUINT_TO_POINTER (0x0E2B), "/hohipthai" },
  +  { GUINT_TO_POINTER (0x307B), "/hohiragana" },
  +  { GUINT_TO_POINTER (0x30DB), "/hokatakana" },
  +  { GUINT_TO_POINTER (0xFF8E), "/hokatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x05B9), "/holam" },
  +  { GUINT_TO_POINTER (0x05B9), "/holam19" },
  +  { GUINT_TO_POINTER (0x05B9), "/holam26" },
  +  { GUINT_TO_POINTER (0x05B9), "/holam32" },
  +  { GUINT_TO_POINTER (0x05B9), "/holamhebrew" },
  +  { GUINT_TO_POINTER (0x05B9), "/holamnarrowhebrew" },
  +  { GUINT_TO_POINTER (0x05B9), "/holamquarterhebrew" },
  +  { GUINT_TO_POINTER (0x05B9), "/holamwidehebrew" },
  +  { GUINT_TO_POINTER (0x0E2E), "/honokhukthai" },
  +  { GUINT_TO_POINTER (0x0309), "/hookabovecomb" },
  +  { GUINT_TO_POINTER (0x0309), "/hookcmb" },
  +  { GUINT_TO_POINTER (0x0321), "/hookpalatalizedbelowcmb" },
  +  { GUINT_TO_POINTER (0x0322), "/hookretroflexbelowcmb" },
  +  { GUINT_TO_POINTER (0x3342), "/hoonsquare" },
  +  { GUINT_TO_POINTER (0x03E9), "/horicoptic" },
  +  { GUINT_TO_POINTER (0x2015), "/horizontalbar" },
  +  { GUINT_TO_POINTER (0x031B), "/horncmb" },
  +  { GUINT_TO_POINTER (0x2668), "/hotsprings" },
  +  { GUINT_TO_POINTER (0x2302), "/house" },
  +  { GUINT_TO_POINTER (0x24A3), "/hparen" },
  +  { GUINT_TO_POINTER (0x02B0), "/hsuperior" },
  +  { GUINT_TO_POINTER (0x0265), "/hturned" },
  +  { GUINT_TO_POINTER (0x3075), "/huhiragana" },
  +  { GUINT_TO_POINTER (0x3333), "/huiitosquare" },
  +  { GUINT_TO_POINTER (0x30D5), "/hukatakana" },
  +  { GUINT_TO_POINTER (0xFF8C), "/hukatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x02DD), "/hungarumlaut" },
  +  { GUINT_TO_POINTER (0x030B), "/hungarumlautcmb" },
  +  { GUINT_TO_POINTER (0x0195), "/hv" },
  +  { GUINT_TO_POINTER (0x002D), "/hyphen" },
  +  { GUINT_TO_POINTER (0xF6E5), "/hypheninferior" },
  +  { GUINT_TO_POINTER (0xFF0D), "/hyphenmonospace" },
  +  { GUINT_TO_POINTER (0xFE63), "/hyphensmall" },
  +  { GUINT_TO_POINTER (0xF6E6), "/hyphensuperior" },
  +  { GUINT_TO_POINTER (0x2010), "/hyphentwo" },
  +  { GUINT_TO_POINTER (0x0069), "/i" },
  +  { GUINT_TO_POINTER (0x00ED), "/iacute" },
  +  { GUINT_TO_POINTER (0x044F), "/iacyrillic" },
  +  { GUINT_TO_POINTER (0x0987), "/ibengali" },
  +  { GUINT_TO_POINTER (0x3127), "/ibopomofo" },
  +  { GUINT_TO_POINTER (0x012D), "/ibreve" },
  +  { GUINT_TO_POINTER (0x01D0), "/icaron" },
  +  { GUINT_TO_POINTER (0x24D8), "/icircle" },
  +  { GUINT_TO_POINTER (0x00EE), "/icircumflex" },
  +  { GUINT_TO_POINTER (0x0456), "/icyrillic" },
  +  { GUINT_TO_POINTER (0x0209), "/idblgrave" },
  +  { GUINT_TO_POINTER (0x328F), "/ideographearthcircle" },
  +  { GUINT_TO_POINTER (0x328B), "/ideographfirecircle" },
  +  { GUINT_TO_POINTER (0x323F), "/ideographicallianceparen" },
  +  { GUINT_TO_POINTER (0x323A), "/ideographiccallparen" },
  +  { GUINT_TO_POINTER (0x32A5), "/ideographiccentrecircle" },
  +  { GUINT_TO_POINTER (0x3006), "/ideographicclose" },
  +  { GUINT_TO_POINTER (0x3001), "/ideographiccomma" },
  +  { GUINT_TO_POINTER (0xFF64), "/ideographiccommaleft" },
  +  { GUINT_TO_POINTER (0x3237), "/ideographiccongratulationparen" },
  +  { GUINT_TO_POINTER (0x32A3), "/ideographiccorrectcircle" },
  +  { GUINT_TO_POINTER (0x322F), "/ideographicearthparen" },
  +  { GUINT_TO_POINTER (0x323D), "/ideographicenterpriseparen" },
  +  { GUINT_TO_POINTER (0x329D), "/ideographicexcellentcircle" },
  +  { GUINT_TO_POINTER (0x3240), "/ideographicfestivalparen" },
  +  { GUINT_TO_POINTER (0x3296), "/ideographicfinancialcircle" },
  +  { GUINT_TO_POINTER (0x3236), "/ideographicfinancialparen" },
  +  { GUINT_TO_POINTER (0x322B), "/ideographicfireparen" },
  +  { GUINT_TO_POINTER (0x3232), "/ideographichaveparen" },
  +  { GUINT_TO_POINTER (0x32A4), "/ideographichighcircle" },
  +  { GUINT_TO_POINTER (0x3005), "/ideographiciterationmark" },
  +  { GUINT_TO_POINTER (0x3298), "/ideographiclaborcircle" },
  +  { GUINT_TO_POINTER (0x3238), "/ideographiclaborparen" },
  +  { GUINT_TO_POINTER (0x32A7), "/ideographicleftcircle" },
  +  { GUINT_TO_POINTER (0x32A6), "/ideographiclowcircle" },
  +  { GUINT_TO_POINTER (0x32A9), "/ideographicmedicinecircle" },
  +  { GUINT_TO_POINTER (0x322E), "/ideographicmetalparen" },
  +  { GUINT_TO_POINTER (0x322A), "/ideographicmoonparen" },
  +  { GUINT_TO_POINTER (0x3234), "/ideographicnameparen" },
  +  { GUINT_TO_POINTER (0x3002), "/ideographicperiod" },
  +  { GUINT_TO_POINTER (0x329E), "/ideographicprintcircle" },
  +  { GUINT_TO_POINTER (0x3243), "/ideographicreachparen" },
  +  { GUINT_TO_POINTER (0x3239), "/ideographicrepresentparen" },
  +  { GUINT_TO_POINTER (0x323E), "/ideographicresourceparen" },
  +  { GUINT_TO_POINTER (0x32A8), "/ideographicrightcircle" },
  +  { GUINT_TO_POINTER (0x3299), "/ideographicsecretcircle" },
  +  { GUINT_TO_POINTER (0x3242), "/ideographicselfparen" },
  +  { GUINT_TO_POINTER (0x3233), "/ideographicsocietyparen" },
  +  { GUINT_TO_POINTER (0x3000), "/ideographicspace" },
  +  { GUINT_TO_POINTER (0x3235), "/ideographicspecialparen" },
  +  { GUINT_TO_POINTER (0x3231), "/ideographicstockparen" },
  +  { GUINT_TO_POINTER (0x323B), "/ideographicstudyparen" },
  +  { GUINT_TO_POINTER (0x3230), "/ideographicsunparen" },
  +  { GUINT_TO_POINTER (0x323C), "/ideographicsuperviseparen" },
  +  { GUINT_TO_POINTER (0x322C), "/ideographicwaterparen" },
  +  { GUINT_TO_POINTER (0x322D), "/ideographicwoodparen" },
  +  { GUINT_TO_POINTER (0x3007), "/ideographiczero" },
  +  { GUINT_TO_POINTER (0x328E), "/ideographmetalcircle" },
  +  { GUINT_TO_POINTER (0x328A), "/ideographmooncircle" },
  +  { GUINT_TO_POINTER (0x3294), "/ideographnamecircle" },
  +  { GUINT_TO_POINTER (0x3290), "/ideographsuncircle" },
  +  { GUINT_TO_POINTER (0x328C), "/ideographwatercircle" },
  +  { GUINT_TO_POINTER (0x328D), "/ideographwoodcircle" },
  +  { GUINT_TO_POINTER (0x0907), "/ideva" },
  +  { GUINT_TO_POINTER (0x00EF), "/idieresis" },
  +  { GUINT_TO_POINTER (0x1E2F), "/idieresisacute" },
  +  { GUINT_TO_POINTER (0x04E5), "/idieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x1ECB), "/idotbelow" },
  +  { GUINT_TO_POINTER (0x04D7), "/iebrevecyrillic" },
  +  { GUINT_TO_POINTER (0x0435), "/iecyrillic" },
  +  { GUINT_TO_POINTER (0x3275), "/ieungacirclekorean" },
  +  { GUINT_TO_POINTER (0x3215), "/ieungaparenkorean" },
  +  { GUINT_TO_POINTER (0x3267), "/ieungcirclekorean" },
  +  { GUINT_TO_POINTER (0x3147), "/ieungkorean" },
  +  { GUINT_TO_POINTER (0x3207), "/ieungparenkorean" },
  +  { GUINT_TO_POINTER (0x00EC), "/igrave" },
  +  { GUINT_TO_POINTER (0x0A87), "/igujarati" },
  +  { GUINT_TO_POINTER (0x0A07), "/igurmukhi" },
  +  { GUINT_TO_POINTER (0x3044), "/ihiragana" },
  +  { GUINT_TO_POINTER (0x1EC9), "/ihookabove" },
  +  { GUINT_TO_POINTER (0x0988), "/iibengali" },
  +  { GUINT_TO_POINTER (0x0438), "/iicyrillic" },
  +  { GUINT_TO_POINTER (0x0908), "/iideva" },
  +  { GUINT_TO_POINTER (0x0A88), "/iigujarati" },
  +  { GUINT_TO_POINTER (0x0A08), "/iigurmukhi" },
  +  { GUINT_TO_POINTER (0x0A40), "/iimatragurmukhi" },
  +  { GUINT_TO_POINTER (0x020B), "/iinvertedbreve" },
  +  { GUINT_TO_POINTER (0x0439), "/iishortcyrillic" },
  +  { GUINT_TO_POINTER (0x09C0), "/iivowelsignbengali" },
  +  { GUINT_TO_POINTER (0x0940), "/iivowelsigndeva" },
  +  { GUINT_TO_POINTER (0x0AC0), "/iivowelsigngujarati" },
  +  { GUINT_TO_POINTER (0x0133), "/ij" },
  +  { GUINT_TO_POINTER (0x30A4), "/ikatakana" },
  +  { GUINT_TO_POINTER (0xFF72), "/ikatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x3163), "/ikorean" },
  +  { GUINT_TO_POINTER (0x02DC), "/ilde" },
  +  { GUINT_TO_POINTER (0x05AC), "/iluyhebrew" },
  +  { GUINT_TO_POINTER (0x012B), "/imacron" },
  +  { GUINT_TO_POINTER (0x04E3), "/imacroncyrillic" },
  +  { GUINT_TO_POINTER (0x2253), "/imageorapproximatelyequal" },
  +  { GUINT_TO_POINTER (0x0A3F), "/imatragurmukhi" },
  +  { GUINT_TO_POINTER (0xFF49), "/imonospace" },
  +  { GUINT_TO_POINTER (0x2206), "/increment" },
  +  { GUINT_TO_POINTER (0x221E), "/infinity" },
  +  { GUINT_TO_POINTER (0x056B), "/iniarmenian" },
  +  { GUINT_TO_POINTER (0x222B), "/integral" },
  +  { GUINT_TO_POINTER (0x2321), "/integralbottom" },
  +  { GUINT_TO_POINTER (0x2321), "/integralbt" },
  +  { GUINT_TO_POINTER (0xF8F5), "/integralex" },
  +  { GUINT_TO_POINTER (0x2320), "/integraltop" },
  +  { GUINT_TO_POINTER (0x2320), "/integraltp" },
  +  { GUINT_TO_POINTER (0x2229), "/intersection" },
  +  { GUINT_TO_POINTER (0x3305), "/intisquare" },
  +  { GUINT_TO_POINTER (0x25D8), "/invbullet" },
  +  { GUINT_TO_POINTER (0x25D9), "/invcircle" },
  +  { GUINT_TO_POINTER (0x263B), "/invsmileface" },
  +  { GUINT_TO_POINTER (0x0451), "/iocyrillic" },
  +  { GUINT_TO_POINTER (0x012F), "/iogonek" },
  +  { GUINT_TO_POINTER (0x03B9), "/iota" },
  +  { GUINT_TO_POINTER (0x03CA), "/iotadieresis" },
  +  { GUINT_TO_POINTER (0x0390), "/iotadieresistonos" },
  +  { GUINT_TO_POINTER (0x0269), "/iotalatin" },
  +  { GUINT_TO_POINTER (0x03AF), "/iotatonos" },
  +  { GUINT_TO_POINTER (0x24A4), "/iparen" },
  +  { GUINT_TO_POINTER (0x0A72), "/irigurmukhi" },
  +  { GUINT_TO_POINTER (0x3043), "/ismallhiragana" },
  +  { GUINT_TO_POINTER (0x30A3), "/ismallkatakana" },
  +  { GUINT_TO_POINTER (0xFF68), "/ismallkatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x09FA), "/issharbengali" },
  +  { GUINT_TO_POINTER (0x0268), "/istroke" },
  +  { GUINT_TO_POINTER (0xF6ED), "/isuperior" },
  +  { GUINT_TO_POINTER (0x309D), "/iterationhiragana" },
  +  { GUINT_TO_POINTER (0x30FD), "/iterationkatakana" },
  +  { GUINT_TO_POINTER (0x0129), "/itilde" },
  +  { GUINT_TO_POINTER (0x1E2D), "/itildebelow" },
  +  { GUINT_TO_POINTER (0x3129), "/iubopomofo" },
  +  { GUINT_TO_POINTER (0x044E), "/iucyrillic" },
  +  { GUINT_TO_POINTER (0x09BF), "/ivowelsignbengali" },
  +  { GUINT_TO_POINTER (0x093F), "/ivowelsigndeva" },
  +  { GUINT_TO_POINTER (0x0ABF), "/ivowelsigngujarati" },
  +  { GUINT_TO_POINTER (0x0475), "/izhitsacyrillic" },
  +  { GUINT_TO_POINTER (0x0477), "/izhitsadblgravecyrillic" },
  +  { GUINT_TO_POINTER (0x006A), "/j" },
  +  { GUINT_TO_POINTER (0x0571), "/jaarmenian" },
  +  { GUINT_TO_POINTER (0x099C), "/jabengali" },
  +  { GUINT_TO_POINTER (0x091C), "/jadeva" },
  +  { GUINT_TO_POINTER (0x0A9C), "/jagujarati" },
  +  { GUINT_TO_POINTER (0x0A1C), "/jagurmukhi" },
  +  { GUINT_TO_POINTER (0x3110), "/jbopomofo" },
  +  { GUINT_TO_POINTER (0x01F0), "/jcaron" },
  +  { GUINT_TO_POINTER (0x24D9), "/jcircle" },
  +  { GUINT_TO_POINTER (0x0135), "/jcircumflex" },
  +  { GUINT_TO_POINTER (0x029D), "/jcrossedtail" },
  +  { GUINT_TO_POINTER (0x025F), "/jdotlessstroke" },
  +  { GUINT_TO_POINTER (0x0458), "/jecyrillic" },
  +  { GUINT_TO_POINTER (0x062C), "/jeemarabic" },
  +  { GUINT_TO_POINTER (0xFE9E), "/jeemfinalarabic" },
  +  { GUINT_TO_POINTER (0xFE9F), "/jeeminitialarabic" },
  +  { GUINT_TO_POINTER (0xFEA0), "/jeemmedialarabic" },
  +  { GUINT_TO_POINTER (0x0698), "/jeharabic" },
  +  { GUINT_TO_POINTER (0xFB8B), "/jehfinalarabic" },
  +  { GUINT_TO_POINTER (0x099D), "/jhabengali" },
  +  { GUINT_TO_POINTER (0x091D), "/jhadeva" },
  +  { GUINT_TO_POINTER (0x0A9D), "/jhagujarati" },
  +  { GUINT_TO_POINTER (0x0A1D), "/jhagurmukhi" },
  +  { GUINT_TO_POINTER (0x057B), "/jheharmenian" },
  +  { GUINT_TO_POINTER (0x3004), "/jis" },
  +  { GUINT_TO_POINTER (0xFF4A), "/jmonospace" },
  +  { GUINT_TO_POINTER (0x24A5), "/jparen" },
  +  { GUINT_TO_POINTER (0x02B2), "/jsuperior" },
  +  { GUINT_TO_POINTER (0x006B), "/k" },
  +  { GUINT_TO_POINTER (0x04A1), "/kabashkircyrillic" },
  +  { GUINT_TO_POINTER (0x0995), "/kabengali" },
  +  { GUINT_TO_POINTER (0x1E31), "/kacute" },
  +  { GUINT_TO_POINTER (0x043A), "/kacyrillic" },
  +  { GUINT_TO_POINTER (0x049B), "/kadescendercyrillic" },
  +  { GUINT_TO_POINTER (0x0915), "/kadeva" },
  +  { GUINT_TO_POINTER (0x05DB), "/kaf" },
  +  { GUINT_TO_POINTER (0x0643), "/kafarabic" },
  +  { GUINT_TO_POINTER (0xFB3B), "/kafdagesh" },
  +  { GUINT_TO_POINTER (0xFB3B), "/kafdageshhebrew" },
  +  { GUINT_TO_POINTER (0xFEDA), "/kaffinalarabic" },
  +  { GUINT_TO_POINTER (0x05DB), "/kafhebrew" },
  +  { GUINT_TO_POINTER (0xFEDB), "/kafinitialarabic" },
  +  { GUINT_TO_POINTER (0xFEDC), "/kafmedialarabic" },
  +  { GUINT_TO_POINTER (0xFB4D), "/kafrafehebrew" },
  +  { GUINT_TO_POINTER (0x0A95), "/kagujarati" },
  +  { GUINT_TO_POINTER (0x0A15), "/kagurmukhi" },
  +  { GUINT_TO_POINTER (0x304B), "/kahiragana" },
  +  { GUINT_TO_POINTER (0x04C4), "/kahookcyrillic" },
  +  { GUINT_TO_POINTER (0x30AB), "/kakatakana" },
  +  { GUINT_TO_POINTER (0xFF76), "/kakatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x03BA), "/kappa" },
  +  { GUINT_TO_POINTER (0x03F0), "/kappasymbolgreek" },
  +  { GUINT_TO_POINTER (0x3171), "/kapyeounmieumkorean" },
  +  { GUINT_TO_POINTER (0x3184), "/kapyeounphieuphkorean" },
  +  { GUINT_TO_POINTER (0x3178), "/kapyeounpieupkorean" },
  +  { GUINT_TO_POINTER (0x3179), "/kapyeounssangpieupkorean" },
  +  { GUINT_TO_POINTER (0x330D), "/karoriisquare" },
  +  { GUINT_TO_POINTER (0x0640), "/kashidaautoarabic" },
  +  { GUINT_TO_POINTER (0x0640), "/kashidaautonosidebearingarabic" },
  +  { GUINT_TO_POINTER (0x30F5), "/kasmallkatakana" },
  +  { GUINT_TO_POINTER (0x3384), "/kasquare" },
  +  { GUINT_TO_POINTER (0x0650), "/kasraarabic" },
  +  { GUINT_TO_POINTER (0x064D), "/kasratanarabic" },
  +  { GUINT_TO_POINTER (0x049F), "/kastrokecyrillic" },
  +  { GUINT_TO_POINTER (0xFF70), "/katahiraprolongmarkhalfwidth" },
  +  { GUINT_TO_POINTER (0x049D), "/kaverticalstrokecyrillic" },
  +  { GUINT_TO_POINTER (0x310E), "/kbopomofo" },
  +  { GUINT_TO_POINTER (0x3389), "/kcalsquare" },
  +  { GUINT_TO_POINTER (0x01E9), "/kcaron" },
  +  { GUINT_TO_POINTER (0x0137), "/kcedilla" },
  +  { GUINT_TO_POINTER (0x24DA), "/kcircle" },
  +  { GUINT_TO_POINTER (0x0137), "/kcommaaccent" },
  +  { GUINT_TO_POINTER (0x1E33), "/kdotbelow" },
  +  { GUINT_TO_POINTER (0x0584), "/keharmenian" },
  +  { GUINT_TO_POINTER (0x3051), "/kehiragana" },
  +  { GUINT_TO_POINTER (0x30B1), "/kekatakana" },
  +  { GUINT_TO_POINTER (0xFF79), "/kekatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x056F), "/kenarmenian" },
  +  { GUINT_TO_POINTER (0x30F6), "/kesmallkatakana" },
  +  { GUINT_TO_POINTER (0x0138), "/kgreenlandic" },
  +  { GUINT_TO_POINTER (0x0996), "/khabengali" },
  +  { GUINT_TO_POINTER (0x0445), "/khacyrillic" },
  +  { GUINT_TO_POINTER (0x0916), "/khadeva" },
  +  { GUINT_TO_POINTER (0x0A96), "/khagujarati" },
  +  { GUINT_TO_POINTER (0x0A16), "/khagurmukhi" },
  +  { GUINT_TO_POINTER (0x062E), "/khaharabic" },
  +  { GUINT_TO_POINTER (0xFEA6), "/khahfinalarabic" },
  +  { GUINT_TO_POINTER (0xFEA7), "/khahinitialarabic" },
  +  { GUINT_TO_POINTER (0xFEA8), "/khahmedialarabic" },
  +  { GUINT_TO_POINTER (0x03E7), "/kheicoptic" },
  +  { GUINT_TO_POINTER (0x0959), "/khhadeva" },
  +  { GUINT_TO_POINTER (0x0A59), "/khhagurmukhi" },
  +  { GUINT_TO_POINTER (0x3278), "/khieukhacirclekorean" },
  +  { GUINT_TO_POINTER (0x3218), "/khieukhaparenkorean" },
  +  { GUINT_TO_POINTER (0x326A), "/khieukhcirclekorean" },
  +  { GUINT_TO_POINTER (0x314B), "/khieukhkorean" },
  +  { GUINT_TO_POINTER (0x320A), "/khieukhparenkorean" },
  +  { GUINT_TO_POINTER (0x0E02), "/khokhaithai" },
  +  { GUINT_TO_POINTER (0x0E05), "/khokhonthai" },
  +  { GUINT_TO_POINTER (0x0E03), "/khokhuatthai" },
  +  { GUINT_TO_POINTER (0x0E04), "/khokhwaithai" },
  +  { GUINT_TO_POINTER (0x0E5B), "/khomutthai" },
  +  { GUINT_TO_POINTER (0x0199), "/khook" },
  +  { GUINT_TO_POINTER (0x0E06), "/khorakhangthai" },
  +  { GUINT_TO_POINTER (0x3391), "/khzsquare" },
  +  { GUINT_TO_POINTER (0x304D), "/kihiragana" },
  +  { GUINT_TO_POINTER (0x30AD), "/kikatakana" },
  +  { GUINT_TO_POINTER (0xFF77), "/kikatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x3315), "/kiroguramusquare" },
  +  { GUINT_TO_POINTER (0x3316), "/kiromeetorusquare" },
  +  { GUINT_TO_POINTER (0x3314), "/kirosquare" },
  +  { GUINT_TO_POINTER (0x326E), "/kiyeokacirclekorean" },
  +  { GUINT_TO_POINTER (0x320E), "/kiyeokaparenkorean" },
  +  { GUINT_TO_POINTER (0x3260), "/kiyeokcirclekorean" },
  +  { GUINT_TO_POINTER (0x3131), "/kiyeokkorean" },
  +  { GUINT_TO_POINTER (0x3200), "/kiyeokparenkorean" },
  +  { GUINT_TO_POINTER (0x3133), "/kiyeoksioskorean" },
  +  { GUINT_TO_POINTER (0x045C), "/kjecyrillic" },
  +  { GUINT_TO_POINTER (0x1E35), "/klinebelow" },
  +  { GUINT_TO_POINTER (0x3398), "/klsquare" },
  +  { GUINT_TO_POINTER (0x33A6), "/kmcubedsquare" },
  +  { GUINT_TO_POINTER (0xFF4B), "/kmonospace" },
  +  { GUINT_TO_POINTER (0x33A2), "/kmsquaredsquare" },
  +  { GUINT_TO_POINTER (0x3053), "/kohiragana" },
  +  { GUINT_TO_POINTER (0x33C0), "/kohmsquare" },
  +  { GUINT_TO_POINTER (0x0E01), "/kokaithai" },
  +  { GUINT_TO_POINTER (0x30B3), "/kokatakana" },
  +  { GUINT_TO_POINTER (0xFF7A), "/kokatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x331E), "/kooposquare" },
  +  { GUINT_TO_POINTER (0x0481), "/koppacyrillic" },
  +  { GUINT_TO_POINTER (0x327F), "/koreanstandardsymbol" },
  +  { GUINT_TO_POINTER (0x0343), "/koroniscmb" },
  +  { GUINT_TO_POINTER (0x24A6), "/kparen" },
  +  { GUINT_TO_POINTER (0x33AA), "/kpasquare" },
  +  { GUINT_TO_POINTER (0x046F), "/ksicyrillic" },
  +  { GUINT_TO_POINTER (0x33CF), "/ktsquare" },
  +  { GUINT_TO_POINTER (0x029E), "/kturned" },
  +  { GUINT_TO_POINTER (0x304F), "/kuhiragana" },
  +  { GUINT_TO_POINTER (0x30AF), "/kukatakana" },
  +  { GUINT_TO_POINTER (0xFF78), "/kukatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x33B8), "/kvsquare" },
  +  { GUINT_TO_POINTER (0x33BE), "/kwsquare" },
  +  { GUINT_TO_POINTER (0x006C), "/l" },
  +  { GUINT_TO_POINTER (0x09B2), "/labengali" },
  +  { GUINT_TO_POINTER (0x013A), "/lacute" },
  +  { GUINT_TO_POINTER (0x0932), "/ladeva" },
  +  { GUINT_TO_POINTER (0x0AB2), "/lagujarati" },
  +  { GUINT_TO_POINTER (0x0A32), "/lagurmukhi" },
  +  { GUINT_TO_POINTER (0x0E45), "/lakkhangyaothai" },
  +  { GUINT_TO_POINTER (0xFEFC), "/lamaleffinalarabic" },
  +  { GUINT_TO_POINTER (0xFEF8), "/lamalefhamzaabovefinalarabic" },
  +  { GUINT_TO_POINTER (0xFEF7), "/lamalefhamzaaboveisolatedarabic" },
  +  { GUINT_TO_POINTER (0xFEFA), "/lamalefhamzabelowfinalarabic" },
  +  { GUINT_TO_POINTER (0xFEF9), "/lamalefhamzabelowisolatedarabic" },
  +  { GUINT_TO_POINTER (0xFEFB), "/lamalefisolatedarabic" },
  +  { GUINT_TO_POINTER (0xFEF6), "/lamalefmaddaabovefinalarabic" },
  +  { GUINT_TO_POINTER (0xFEF5), "/lamalefmaddaaboveisolatedarabic" },
  +  { GUINT_TO_POINTER (0x0644), "/lamarabic" },
  +  { GUINT_TO_POINTER (0x03BB), "/lambda" },
  +  { GUINT_TO_POINTER (0x019B), "/lambdastroke" },
  +  { GUINT_TO_POINTER (0x05DC), "/lamed" },
  +  { GUINT_TO_POINTER (0xFB3C), "/lameddagesh" },
  +  { GUINT_TO_POINTER (0xFB3C), "/lameddageshhebrew" },
  +  { GUINT_TO_POINTER (0x05DC), "/lamedhebrew" },
  +  { GUINT_TO_POINTER (0x05DC), "/lamedholam" },
  +  { GUINT_TO_POINTER (0x05B9), "/lamedholam" },
  +  { GUINT_TO_POINTER (0x05DC), "/lamedholamdagesh" },
  +  { GUINT_TO_POINTER (0x05B9), "/lamedholamdagesh" },
  +  { GUINT_TO_POINTER (0x05BC), "/lamedholamdagesh" },
  +  { GUINT_TO_POINTER (0x05DC), "/lamedholamdageshhebrew" },
  +  { GUINT_TO_POINTER (0x05B9), "/lamedholamdageshhebrew" },
  +  { GUINT_TO_POINTER (0x05BC), "/lamedholamdageshhebrew" },
  +  { GUINT_TO_POINTER (0x05DC), "/lamedholamhebrew" },
  +  { GUINT_TO_POINTER (0x05B9), "/lamedholamhebrew" },
  +  { GUINT_TO_POINTER (0xFEDE), "/lamfinalarabic" },
  +  { GUINT_TO_POINTER (0xFCCA), "/lamhahinitialarabic" },
  +  { GUINT_TO_POINTER (0xFEDF), "/laminitialarabic" },
  +  { GUINT_TO_POINTER (0xFCC9), "/lamjeeminitialarabic" },
  +  { GUINT_TO_POINTER (0xFCCB), "/lamkhahinitialarabic" },
  +  { GUINT_TO_POINTER (0xFDF2), "/lamlamhehisolatedarabic" },
  +  { GUINT_TO_POINTER (0xFEE0), "/lammedialarabic" },
  +  { GUINT_TO_POINTER (0xFD88), "/lammeemhahinitialarabic" },
  +  { GUINT_TO_POINTER (0xFCCC), "/lammeeminitialarabic" },
  +  { GUINT_TO_POINTER (0xFEDF), "/lammeemjeeminitialarabic" },
  +  { GUINT_TO_POINTER (0xFEE4), "/lammeemjeeminitialarabic" },
  +  { GUINT_TO_POINTER (0xFEA0), "/lammeemjeeminitialarabic" },
  +  { GUINT_TO_POINTER (0xFEDF), "/lammeemkhahinitialarabic" },
  +  { GUINT_TO_POINTER (0xFEE4), "/lammeemkhahinitialarabic" },
  +  { GUINT_TO_POINTER (0xFEA8), "/lammeemkhahinitialarabic" },
  +  { GUINT_TO_POINTER (0x25EF), "/largecircle" },
  +  { GUINT_TO_POINTER (0x019A), "/lbar" },
  +  { GUINT_TO_POINTER (0x026C), "/lbelt" },
  +  { GUINT_TO_POINTER (0x310C), "/lbopomofo" },
  +  { GUINT_TO_POINTER (0x013E), "/lcaron" },
  +  { GUINT_TO_POINTER (0x013C), "/lcedilla" },
  +  { GUINT_TO_POINTER (0x24DB), "/lcircle" },
  +  { GUINT_TO_POINTER (0x1E3D), "/lcircumflexbelow" },
  +  { GUINT_TO_POINTER (0x013C), "/lcommaaccent" },
  +  { GUINT_TO_POINTER (0x0140), "/ldot" },
  +  { GUINT_TO_POINTER (0x0140), "/ldotaccent" },
  +  { GUINT_TO_POINTER (0x1E37), "/ldotbelow" },
  +  { GUINT_TO_POINTER (0x1E39), "/ldotbelowmacron" },
  +  { GUINT_TO_POINTER (0x031A), "/leftangleabovecmb" },
  +  { GUINT_TO_POINTER (0x0318), "/lefttackbelowcmb" },
  +  { GUINT_TO_POINTER (0x003C), "/less" },
  +  { GUINT_TO_POINTER (0x2264), "/lessequal" },
  +  { GUINT_TO_POINTER (0x22DA), "/lessequalorgreater" },
  +  { GUINT_TO_POINTER (0xFF1C), "/lessmonospace" },
  +  { GUINT_TO_POINTER (0x2272), "/lessorequivalent" },
  +  { GUINT_TO_POINTER (0x2276), "/lessorgreater" },
  +  { GUINT_TO_POINTER (0x2266), "/lessoverequal" },
  +  { GUINT_TO_POINTER (0xFE64), "/lesssmall" },
  +  { GUINT_TO_POINTER (0x026E), "/lezh" },
  +  { GUINT_TO_POINTER (0x258C), "/lfblock" },
  +  { GUINT_TO_POINTER (0x026D), "/lhookretroflex" },
  +  { GUINT_TO_POINTER (0x20A4), "/lira" },
  +  { GUINT_TO_POINTER (0x056C), "/liwnarmenian" },
  +  { GUINT_TO_POINTER (0x01C9), "/lj" },
  +  { GUINT_TO_POINTER (0x0459), "/ljecyrillic" },
  +  { GUINT_TO_POINTER (0xF6C0), "/ll" },
  +  { GUINT_TO_POINTER (0x0933), "/lladeva" },
  +  { GUINT_TO_POINTER (0x0AB3), "/llagujarati" },
  +  { GUINT_TO_POINTER (0x1E3B), "/llinebelow" },
  +  { GUINT_TO_POINTER (0x0934), "/llladeva" },
  +  { GUINT_TO_POINTER (0x09E1), "/llvocalicbengali" },
  +  { GUINT_TO_POINTER (0x0961), "/llvocalicdeva" },
  +  { GUINT_TO_POINTER (0x09E3), "/llvocalicvowelsignbengali" },
  +  { GUINT_TO_POINTER (0x0963), "/llvocalicvowelsigndeva" },
  +  { GUINT_TO_POINTER (0x026B), "/lmiddletilde" },
  +  { GUINT_TO_POINTER (0xFF4C), "/lmonospace" },
  +  { GUINT_TO_POINTER (0x33D0), "/lmsquare" },
  +  { GUINT_TO_POINTER (0x0E2C), "/lochulathai" },
  +  { GUINT_TO_POINTER (0x2227), "/logicaland" },
  +  { GUINT_TO_POINTER (0x00AC), "/logicalnot" },
  +  { GUINT_TO_POINTER (0x2310), "/logicalnotreversed" },
  +  { GUINT_TO_POINTER (0x2228), "/logicalor" },
  +  { GUINT_TO_POINTER (0x0E25), "/lolingthai" },
  +  { GUINT_TO_POINTER (0x017F), "/longs" },
  +  { GUINT_TO_POINTER (0xFE4E), "/lowlinecenterline" },
  +  { GUINT_TO_POINTER (0x0332), "/lowlinecmb" },
  +  { GUINT_TO_POINTER (0xFE4D), "/lowlinedashed" },
  +  { GUINT_TO_POINTER (0x25CA), "/lozenge" },
  +  { GUINT_TO_POINTER (0x24A7), "/lparen" },
  +  { GUINT_TO_POINTER (0x0142), "/lslash" },
  +  { GUINT_TO_POINTER (0x2113), "/lsquare" },
  +  { GUINT_TO_POINTER (0xF6EE), "/lsuperior" },
  +  { GUINT_TO_POINTER (0x2591), "/ltshade" },
  +  { GUINT_TO_POINTER (0x0E26), "/luthai" },
  +  { GUINT_TO_POINTER (0x098C), "/lvocalicbengali" },
  +  { GUINT_TO_POINTER (0x090C), "/lvocalicdeva" },
  +  { GUINT_TO_POINTER (0x09E2), "/lvocalicvowelsignbengali" },
  +  { GUINT_TO_POINTER (0x0962), "/lvocalicvowelsigndeva" },
  +  { GUINT_TO_POINTER (0x33D3), "/lxsquare" },
  +  { GUINT_TO_POINTER (0x006D), "/m" },
  +  { GUINT_TO_POINTER (0x09AE), "/mabengali" },
  +  { GUINT_TO_POINTER (0x00AF), "/macron" },
  +  { GUINT_TO_POINTER (0x0331), "/macronbelowcmb" },
  +  { GUINT_TO_POINTER (0x0304), "/macroncmb" },
  +  { GUINT_TO_POINTER (0x02CD), "/macronlowmod" },
  +  { GUINT_TO_POINTER (0xFFE3), "/macronmonospace" },
  +  { GUINT_TO_POINTER (0x1E3F), "/macute" },
  +  { GUINT_TO_POINTER (0x092E), "/madeva" },
  +  { GUINT_TO_POINTER (0x0AAE), "/magujarati" },
  +  { GUINT_TO_POINTER (0x0A2E), "/magurmukhi" },
  +  { GUINT_TO_POINTER (0x05A4), "/mahapakhhebrew" },
  +  { GUINT_TO_POINTER (0x05A4), "/mahapakhlefthebrew" },
  +  { GUINT_TO_POINTER (0x307E), "/mahiragana" },
  +  { GUINT_TO_POINTER (0xF895), "/maichattawalowleftthai" },
  +  { GUINT_TO_POINTER (0xF894), "/maichattawalowrightthai" },
  +  { GUINT_TO_POINTER (0x0E4B), "/maichattawathai" },
  +  { GUINT_TO_POINTER (0xF893), "/maichattawaupperleftthai" },
  +  { GUINT_TO_POINTER (0xF88C), "/maieklowleftthai" },
  +  { GUINT_TO_POINTER (0xF88B), "/maieklowrightthai" },
  +  { GUINT_TO_POINTER (0x0E48), "/maiekthai" },
  +  { GUINT_TO_POINTER (0xF88A), "/maiekupperleftthai" },
  +  { GUINT_TO_POINTER (0xF884), "/maihanakatleftthai" },
  +  { GUINT_TO_POINTER (0x0E31), "/maihanakatthai" },
  +  { GUINT_TO_POINTER (0xF889), "/maitaikhuleftthai" },
  +  { GUINT_TO_POINTER (0x0E47), "/maitaikhuthai" },
  +  { GUINT_TO_POINTER (0xF88F), "/maitholowleftthai" },
  +  { GUINT_TO_POINTER (0xF88E), "/maitholowrightthai" },
  +  { GUINT_TO_POINTER (0x0E49), "/maithothai" },
  +  { GUINT_TO_POINTER (0xF88D), "/maithoupperleftthai" },
  +  { GUINT_TO_POINTER (0xF892), "/maitrilowleftthai" },
  +  { GUINT_TO_POINTER (0xF891), "/maitrilowrightthai" },
  +  { GUINT_TO_POINTER (0x0E4A), "/maitrithai" },
  +  { GUINT_TO_POINTER (0xF890), "/maitriupperleftthai" },
  +  { GUINT_TO_POINTER (0x0E46), "/maiyamokthai" },
  +  { GUINT_TO_POINTER (0x30DE), "/makatakana" },
  +  { GUINT_TO_POINTER (0xFF8F), "/makatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x2642), "/male" },
  +  { GUINT_TO_POINTER (0x3347), "/mansyonsquare" },
  +  { GUINT_TO_POINTER (0x05BE), "/maqafhebrew" },
  +  { GUINT_TO_POINTER (0x2642), "/mars" },
  +  { GUINT_TO_POINTER (0x05AF), "/masoracirclehebrew" },
  +  { GUINT_TO_POINTER (0x3383), "/masquare" },
  +  { GUINT_TO_POINTER (0x3107), "/mbopomofo" },
  +  { GUINT_TO_POINTER (0x33D4), "/mbsquare" },
  +  { GUINT_TO_POINTER (0x24DC), "/mcircle" },
  +  { GUINT_TO_POINTER (0x33A5), "/mcubedsquare" },
  +  { GUINT_TO_POINTER (0x1E41), "/mdotaccent" },
  +  { GUINT_TO_POINTER (0x1E43), "/mdotbelow" },
  +  { GUINT_TO_POINTER (0x0645), "/meemarabic" },
  +  { GUINT_TO_POINTER (0xFEE2), "/meemfinalarabic" },
  +  { GUINT_TO_POINTER (0xFEE3), "/meeminitialarabic" },
  +  { GUINT_TO_POINTER (0xFEE4), "/meemmedialarabic" },
  +  { GUINT_TO_POINTER (0xFCD1), "/meemmeeminitialarabic" },
  +  { GUINT_TO_POINTER (0xFC48), "/meemmeemisolatedarabic" },
  +  { GUINT_TO_POINTER (0x334D), "/meetorusquare" },
  +  { GUINT_TO_POINTER (0x3081), "/mehiragana" },
  +  { GUINT_TO_POINTER (0x337E), "/meizierasquare" },
  +  { GUINT_TO_POINTER (0x30E1), "/mekatakana" },
  +  { GUINT_TO_POINTER (0xFF92), "/mekatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x05DE), "/mem" },
  +  { GUINT_TO_POINTER (0xFB3E), "/memdagesh" },
  +  { GUINT_TO_POINTER (0xFB3E), "/memdageshhebrew" },
  +  { GUINT_TO_POINTER (0x05DE), "/memhebrew" },
  +  { GUINT_TO_POINTER (0x0574), "/menarmenian" },
  +  { GUINT_TO_POINTER (0x05A5), "/merkhahebrew" },
  +  { GUINT_TO_POINTER (0x05A6), "/merkhakefulahebrew" },
  +  { GUINT_TO_POINTER (0x05A6), "/merkhakefulalefthebrew" },
  +  { GUINT_TO_POINTER (0x05A5), "/merkhalefthebrew" },
  +  { GUINT_TO_POINTER (0x0271), "/mhook" },
  +  { GUINT_TO_POINTER (0x3392), "/mhzsquare" },
  +  { GUINT_TO_POINTER (0xFF65), "/middledotkatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x00B7), "/middot" },
  +  { GUINT_TO_POINTER (0x3272), "/mieumacirclekorean" },
  +  { GUINT_TO_POINTER (0x3212), "/mieumaparenkorean" },
  +  { GUINT_TO_POINTER (0x3264), "/mieumcirclekorean" },
  +  { GUINT_TO_POINTER (0x3141), "/mieumkorean" },
  +  { GUINT_TO_POINTER (0x3170), "/mieumpansioskorean" },
  +  { GUINT_TO_POINTER (0x3204), "/mieumparenkorean" },
  +  { GUINT_TO_POINTER (0x316E), "/mieumpieupkorean" },
  +  { GUINT_TO_POINTER (0x316F), "/mieumsioskorean" },
  +  { GUINT_TO_POINTER (0x307F), "/mihiragana" },
  +  { GUINT_TO_POINTER (0x30DF), "/mikatakana" },
  +  { GUINT_TO_POINTER (0xFF90), "/mikatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x2212), "/minus" },
  +  { GUINT_TO_POINTER (0x0320), "/minusbelowcmb" },
  +  { GUINT_TO_POINTER (0x2296), "/minuscircle" },
  +  { GUINT_TO_POINTER (0x02D7), "/minusmod" },
  +  { GUINT_TO_POINTER (0x2213), "/minusplus" },
  +  { GUINT_TO_POINTER (0x2032), "/minute" },
  +  { GUINT_TO_POINTER (0x334A), "/miribaarusquare" },
  +  { GUINT_TO_POINTER (0x3349), "/mirisquare" },
  +  { GUINT_TO_POINTER (0x0270), "/mlonglegturned" },
  +  { GUINT_TO_POINTER (0x3396), "/mlsquare" },
  +  { GUINT_TO_POINTER (0x33A3), "/mmcubedsquare" },
  +  { GUINT_TO_POINTER (0xFF4D), "/mmonospace" },
  +  { GUINT_TO_POINTER (0x339F), "/mmsquaredsquare" },
  +  { GUINT_TO_POINTER (0x3082), "/mohiragana" },
  +  { GUINT_TO_POINTER (0x33C1), "/mohmsquare" },
  +  { GUINT_TO_POINTER (0x30E2), "/mokatakana" },
  +  { GUINT_TO_POINTER (0xFF93), "/mokatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x33D6), "/molsquare" },
  +  { GUINT_TO_POINTER (0x0E21), "/momathai" },
  +  { GUINT_TO_POINTER (0x33A7), "/moverssquare" },
  +  { GUINT_TO_POINTER (0x33A8), "/moverssquaredsquare" },
  +  { GUINT_TO_POINTER (0x24A8), "/mparen" },
  +  { GUINT_TO_POINTER (0x33AB), "/mpasquare" },
  +  { GUINT_TO_POINTER (0x33B3), "/mssquare" },
  +  { GUINT_TO_POINTER (0xF6EF), "/msuperior" },
  +  { GUINT_TO_POINTER (0x026F), "/mturned" },
  +  { GUINT_TO_POINTER (0x00B5), "/mu" },
  +  { GUINT_TO_POINTER (0x00B5), "/mu1" },
  +  { GUINT_TO_POINTER (0x3382), "/muasquare" },
  +  { GUINT_TO_POINTER (0x226B), "/muchgreater" },
  +  { GUINT_TO_POINTER (0x226A), "/muchless" },
  +  { GUINT_TO_POINTER (0x338C), "/mufsquare" },
  +  { GUINT_TO_POINTER (0x03BC), "/mugreek" },
  +  { GUINT_TO_POINTER (0x338D), "/mugsquare" },
  +  { GUINT_TO_POINTER (0x3080), "/muhiragana" },
  +  { GUINT_TO_POINTER (0x30E0), "/mukatakana" },
  +  { GUINT_TO_POINTER (0xFF91), "/mukatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x3395), "/mulsquare" },
  +  { GUINT_TO_POINTER (0x00D7), "/multiply" },
  +  { GUINT_TO_POINTER (0x339B), "/mumsquare" },
  +  { GUINT_TO_POINTER (0x05A3), "/munahhebrew" },
  +  { GUINT_TO_POINTER (0x05A3), "/munahlefthebrew" },
  +  { GUINT_TO_POINTER (0x266A), "/musicalnote" },
  +  { GUINT_TO_POINTER (0x266B), "/musicalnotedbl" },
  +  { GUINT_TO_POINTER (0x266D), "/musicflatsign" },
  +  { GUINT_TO_POINTER (0x266F), "/musicsharpsign" },
  +  { GUINT_TO_POINTER (0x33B2), "/mussquare" },
  +  { GUINT_TO_POINTER (0x33B6), "/muvsquare" },
  +  { GUINT_TO_POINTER (0x33BC), "/muwsquare" },
  +  { GUINT_TO_POINTER (0x33B9), "/mvmegasquare" },
  +  { GUINT_TO_POINTER (0x33B7), "/mvsquare" },
  +  { GUINT_TO_POINTER (0x33BF), "/mwmegasquare" },
  +  { GUINT_TO_POINTER (0x33BD), "/mwsquare" },
  +  { GUINT_TO_POINTER (0x006E), "/n" },
  +  { GUINT_TO_POINTER (0x09A8), "/nabengali" },
  +  { GUINT_TO_POINTER (0x2207), "/nabla" },
  +  { GUINT_TO_POINTER (0x0144), "/nacute" },
  +  { GUINT_TO_POINTER (0x0928), "/nadeva" },
  +  { GUINT_TO_POINTER (0x0AA8), "/nagujarati" },
  +  { GUINT_TO_POINTER (0x0A28), "/nagurmukhi" },
  +  { GUINT_TO_POINTER (0x306A), "/nahiragana" },
  +  { GUINT_TO_POINTER (0x30CA), "/nakatakana" },
  +  { GUINT_TO_POINTER (0xFF85), "/nakatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x0149), "/napostrophe" },
  +  { GUINT_TO_POINTER (0x3381), "/nasquare" },
  +  { GUINT_TO_POINTER (0x310B), "/nbopomofo" },
  +  { GUINT_TO_POINTER (0x00A0), "/nbspace" },
  +  { GUINT_TO_POINTER (0x0148), "/ncaron" },
  +  { GUINT_TO_POINTER (0x0146), "/ncedilla" },
  +  { GUINT_TO_POINTER (0x24DD), "/ncircle" },
  +  { GUINT_TO_POINTER (0x1E4B), "/ncircumflexbelow" },
  +  { GUINT_TO_POINTER (0x0146), "/ncommaaccent" },
  +  { GUINT_TO_POINTER (0x1E45), "/ndotaccent" },
  +  { GUINT_TO_POINTER (0x1E47), "/ndotbelow" },
  +  { GUINT_TO_POINTER (0x306D), "/nehiragana" },
  +  { GUINT_TO_POINTER (0x30CD), "/nekatakana" },
  +  { GUINT_TO_POINTER (0xFF88), "/nekatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x20AA), "/newsheqelsign" },
  +  { GUINT_TO_POINTER (0x338B), "/nfsquare" },
  +  { GUINT_TO_POINTER (0x0999), "/ngabengali" },
  +  { GUINT_TO_POINTER (0x0919), "/ngadeva" },
  +  { GUINT_TO_POINTER (0x0A99), "/ngagujarati" },
  +  { GUINT_TO_POINTER (0x0A19), "/ngagurmukhi" },
  +  { GUINT_TO_POINTER (0x0E07), "/ngonguthai" },
  +  { GUINT_TO_POINTER (0x3093), "/nhiragana" },
  +  { GUINT_TO_POINTER (0x0272), "/nhookleft" },
  +  { GUINT_TO_POINTER (0x0273), "/nhookretroflex" },
  +  { GUINT_TO_POINTER (0x326F), "/nieunacirclekorean" },
  +  { GUINT_TO_POINTER (0x320F), "/nieunaparenkorean" },
  +  { GUINT_TO_POINTER (0x3135), "/nieuncieuckorean" },
  +  { GUINT_TO_POINTER (0x3261), "/nieuncirclekorean" },
  +  { GUINT_TO_POINTER (0x3136), "/nieunhieuhkorean" },
  +  { GUINT_TO_POINTER (0x3134), "/nieunkorean" },
  +  { GUINT_TO_POINTER (0x3168), "/nieunpansioskorean" },
  +  { GUINT_TO_POINTER (0x3201), "/nieunparenkorean" },
  +  { GUINT_TO_POINTER (0x3167), "/nieunsioskorean" },
  +  { GUINT_TO_POINTER (0x3166), "/nieuntikeutkorean" },
  +  { GUINT_TO_POINTER (0x306B), "/nihiragana" },
  +  { GUINT_TO_POINTER (0x30CB), "/nikatakana" },
  +  { GUINT_TO_POINTER (0xFF86), "/nikatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0xF899), "/nikhahitleftthai" },
  +  { GUINT_TO_POINTER (0x0E4D), "/nikhahitthai" },
  +  { GUINT_TO_POINTER (0x0039), "/nine" },
  +  { GUINT_TO_POINTER (0x0669), "/ninearabic" },
  +  { GUINT_TO_POINTER (0x09EF), "/ninebengali" },
  +  { GUINT_TO_POINTER (0x2468), "/ninecircle" },
  +  { GUINT_TO_POINTER (0x2792), "/ninecircleinversesansserif" },
  +  { GUINT_TO_POINTER (0x096F), "/ninedeva" },
  +  { GUINT_TO_POINTER (0x0AEF), "/ninegujarati" },
  +  { GUINT_TO_POINTER (0x0A6F), "/ninegurmukhi" },
  +  { GUINT_TO_POINTER (0x0669), "/ninehackarabic" },
  +  { GUINT_TO_POINTER (0x3029), "/ninehangzhou" },
  +  { GUINT_TO_POINTER (0x3228), "/nineideographicparen" },
  +  { GUINT_TO_POINTER (0x2089), "/nineinferior" },
  +  { GUINT_TO_POINTER (0xFF19), "/ninemonospace" },
  +  { GUINT_TO_POINTER (0xF739), "/nineoldstyle" },
  +  { GUINT_TO_POINTER (0x247C), "/nineparen" },
  +  { GUINT_TO_POINTER (0x2490), "/nineperiod" },
  +  { GUINT_TO_POINTER (0x06F9), "/ninepersian" },
  +  { GUINT_TO_POINTER (0x2178), "/nineroman" },
  +  { GUINT_TO_POINTER (0x2079), "/ninesuperior" },
  +  { GUINT_TO_POINTER (0x2472), "/nineteencircle" },
  +  { GUINT_TO_POINTER (0x2486), "/nineteenparen" },
  +  { GUINT_TO_POINTER (0x249A), "/nineteenperiod" },
  +  { GUINT_TO_POINTER (0x0E59), "/ninethai" },
  +  { GUINT_TO_POINTER (0x01CC), "/nj" },
  +  { GUINT_TO_POINTER (0x045A), "/njecyrillic" },
  +  { GUINT_TO_POINTER (0x30F3), "/nkatakana" },
  +  { GUINT_TO_POINTER (0xFF9D), "/nkatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x019E), "/nlegrightlong" },
  +  { GUINT_TO_POINTER (0x1E49), "/nlinebelow" },
  +  { GUINT_TO_POINTER (0xFF4E), "/nmonospace" },
  +  { GUINT_TO_POINTER (0x339A), "/nmsquare" },
  +  { GUINT_TO_POINTER (0x09A3), "/nnabengali" },
  +  { GUINT_TO_POINTER (0x0923), "/nnadeva" },
  +  { GUINT_TO_POINTER (0x0AA3), "/nnagujarati" },
  +  { GUINT_TO_POINTER (0x0A23), "/nnagurmukhi" },
  +  { GUINT_TO_POINTER (0x0929), "/nnnadeva" },
  +  { GUINT_TO_POINTER (0x306E), "/nohiragana" },
  +  { GUINT_TO_POINTER (0x30CE), "/nokatakana" },
  +  { GUINT_TO_POINTER (0xFF89), "/nokatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x00A0), "/nonbreakingspace" },
  +  { GUINT_TO_POINTER (0x0E13), "/nonenthai" },
  +  { GUINT_TO_POINTER (0x0E19), "/nonuthai" },
  +  { GUINT_TO_POINTER (0x0646), "/noonarabic" },
  +  { GUINT_TO_POINTER (0xFEE6), "/noonfinalarabic" },
  +  { GUINT_TO_POINTER (0x06BA), "/noonghunnaarabic" },
  +  { GUINT_TO_POINTER (0xFB9F), "/noonghunnafinalarabic" },
  +  { GUINT_TO_POINTER (0xFEE7), "/noonhehinitialarabic" },
  +  { GUINT_TO_POINTER (0xFEEC), "/noonhehinitialarabic" },
  +  { GUINT_TO_POINTER (0xFEE7), "/nooninitialarabic" },
  +  { GUINT_TO_POINTER (0xFCD2), "/noonjeeminitialarabic" },
  +  { GUINT_TO_POINTER (0xFC4B), "/noonjeemisolatedarabic" },
  +  { GUINT_TO_POINTER (0xFEE8), "/noonmedialarabic" },
  +  { GUINT_TO_POINTER (0xFCD5), "/noonmeeminitialarabic" },
  +  { GUINT_TO_POINTER (0xFC4E), "/noonmeemisolatedarabic" },
  +  { GUINT_TO_POINTER (0xFC8D), "/noonnoonfinalarabic" },
  +  { GUINT_TO_POINTER (0x220C), "/notcontains" },
  +  { GUINT_TO_POINTER (0x2209), "/notelement" },
  +  { GUINT_TO_POINTER (0x2209), "/notelementof" },
  +  { GUINT_TO_POINTER (0x2260), "/notequal" },
  +  { GUINT_TO_POINTER (0x226F), "/notgreater" },
  +  { GUINT_TO_POINTER (0x2271), "/notgreaternorequal" },
  +  { GUINT_TO_POINTER (0x2279), "/notgreaternorless" },
  +  { GUINT_TO_POINTER (0x2262), "/notidentical" },
  +  { GUINT_TO_POINTER (0x226E), "/notless" },
  +  { GUINT_TO_POINTER (0x2270), "/notlessnorequal" },
  +  { GUINT_TO_POINTER (0x2226), "/notparallel" },
  +  { GUINT_TO_POINTER (0x2280), "/notprecedes" },
  +  { GUINT_TO_POINTER (0x2284), "/notsubset" },
  +  { GUINT_TO_POINTER (0x2281), "/notsucceeds" },
  +  { GUINT_TO_POINTER (0x2285), "/notsuperset" },
  +  { GUINT_TO_POINTER (0x0576), "/nowarmenian" },
  +  { GUINT_TO_POINTER (0x24A9), "/nparen" },
  +  { GUINT_TO_POINTER (0x33B1), "/nssquare" },
  +  { GUINT_TO_POINTER (0x207F), "/nsuperior" },
  +  { GUINT_TO_POINTER (0x00F1), "/ntilde" },
  +  { GUINT_TO_POINTER (0x03BD), "/nu" },
  +  { GUINT_TO_POINTER (0x306C), "/nuhiragana" },
  +  { GUINT_TO_POINTER (0x30CC), "/nukatakana" },
  +  { GUINT_TO_POINTER (0xFF87), "/nukatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x09BC), "/nuktabengali" },
  +  { GUINT_TO_POINTER (0x093C), "/nuktadeva" },
  +  { GUINT_TO_POINTER (0x0ABC), "/nuktagujarati" },
  +  { GUINT_TO_POINTER (0x0A3C), "/nuktagurmukhi" },
  +  { GUINT_TO_POINTER (0x0023), "/numbersign" },
  +  { GUINT_TO_POINTER (0xFF03), "/numbersignmonospace" },
  +  { GUINT_TO_POINTER (0xFE5F), "/numbersignsmall" },
  +  { GUINT_TO_POINTER (0x0374), "/numeralsigngreek" },
  +  { GUINT_TO_POINTER (0x0375), "/numeralsignlowergreek" },
  +  { GUINT_TO_POINTER (0x2116), "/numero" },
  +  { GUINT_TO_POINTER (0x05E0), "/nun" },
  +  { GUINT_TO_POINTER (0xFB40), "/nundagesh" },
  +  { GUINT_TO_POINTER (0xFB40), "/nundageshhebrew" },
  +  { GUINT_TO_POINTER (0x05E0), "/nunhebrew" },
  +  { GUINT_TO_POINTER (0x33B5), "/nvsquare" },
  +  { GUINT_TO_POINTER (0x33BB), "/nwsquare" },
  +  { GUINT_TO_POINTER (0x099E), "/nyabengali" },
  +  { GUINT_TO_POINTER (0x091E), "/nyadeva" },
  +  { GUINT_TO_POINTER (0x0A9E), "/nyagujarati" },
  +  { GUINT_TO_POINTER (0x0A1E), "/nyagurmukhi" },
  +  { GUINT_TO_POINTER (0x006F), "/o" },
  +  { GUINT_TO_POINTER (0x00F3), "/oacute" },
  +  { GUINT_TO_POINTER (0x0E2D), "/oangthai" },
  +  { GUINT_TO_POINTER (0x0275), "/obarred" },
  +  { GUINT_TO_POINTER (0x04E9), "/obarredcyrillic" },
  +  { GUINT_TO_POINTER (0x04EB), "/obarreddieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x0993), "/obengali" },
  +  { GUINT_TO_POINTER (0x311B), "/obopomofo" },
  +  { GUINT_TO_POINTER (0x014F), "/obreve" },
  +  { GUINT_TO_POINTER (0x0911), "/ocandradeva" },
  +  { GUINT_TO_POINTER (0x0A91), "/ocandragujarati" },
  +  { GUINT_TO_POINTER (0x0949), "/ocandravowelsigndeva" },
  +  { GUINT_TO_POINTER (0x0AC9), "/ocandravowelsigngujarati" },
  +  { GUINT_TO_POINTER (0x01D2), "/ocaron" },
  +  { GUINT_TO_POINTER (0x24DE), "/ocircle" },
  +  { GUINT_TO_POINTER (0x00F4), "/ocircumflex" },
  +  { GUINT_TO_POINTER (0x1ED1), "/ocircumflexacute" },
  +  { GUINT_TO_POINTER (0x1ED9), "/ocircumflexdotbelow" },
  +  { GUINT_TO_POINTER (0x1ED3), "/ocircumflexgrave" },
  +  { GUINT_TO_POINTER (0x1ED5), "/ocircumflexhookabove" },
  +  { GUINT_TO_POINTER (0x1ED7), "/ocircumflextilde" },
  +  { GUINT_TO_POINTER (0x043E), "/ocyrillic" },
  +  { GUINT_TO_POINTER (0x0151), "/odblacute" },
  +  { GUINT_TO_POINTER (0x020D), "/odblgrave" },
  +  { GUINT_TO_POINTER (0x0913), "/odeva" },
  +  { GUINT_TO_POINTER (0x00F6), "/odieresis" },
  +  { GUINT_TO_POINTER (0x04E7), "/odieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x1ECD), "/odotbelow" },
  +  { GUINT_TO_POINTER (0x0153), "/oe" },
  +  { GUINT_TO_POINTER (0x315A), "/oekorean" },
  +  { GUINT_TO_POINTER (0x02DB), "/ogonek" },
  +  { GUINT_TO_POINTER (0x0328), "/ogonekcmb" },
  +  { GUINT_TO_POINTER (0x00F2), "/ograve" },
  +  { GUINT_TO_POINTER (0x0A93), "/ogujarati" },
  +  { GUINT_TO_POINTER (0x0585), "/oharmenian" },
  +  { GUINT_TO_POINTER (0x304A), "/ohiragana" },
  +  { GUINT_TO_POINTER (0x1ECF), "/ohookabove" },
  +  { GUINT_TO_POINTER (0x01A1), "/ohorn" },
  +  { GUINT_TO_POINTER (0x1EDB), "/ohornacute" },
  +  { GUINT_TO_POINTER (0x1EE3), "/ohorndotbelow" },
  +  { GUINT_TO_POINTER (0x1EDD), "/ohorngrave" },
  +  { GUINT_TO_POINTER (0x1EDF), "/ohornhookabove" },
  +  { GUINT_TO_POINTER (0x1EE1), "/ohorntilde" },
  +  { GUINT_TO_POINTER (0x0151), "/ohungarumlaut" },
  +  { GUINT_TO_POINTER (0x01A3), "/oi" },
  +  { GUINT_TO_POINTER (0x020F), "/oinvertedbreve" },
  +  { GUINT_TO_POINTER (0x30AA), "/okatakana" },
  +  { GUINT_TO_POINTER (0xFF75), "/okatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x3157), "/okorean" },
  +  { GUINT_TO_POINTER (0x05AB), "/olehebrew" },
  +  { GUINT_TO_POINTER (0x014D), "/omacron" },
  +  { GUINT_TO_POINTER (0x1E53), "/omacronacute" },
  +  { GUINT_TO_POINTER (0x1E51), "/omacrongrave" },
  +  { GUINT_TO_POINTER (0x0950), "/omdeva" },
  +  { GUINT_TO_POINTER (0x03C9), "/omega" },
  +  { GUINT_TO_POINTER (0x03D6), "/omega1" },
  +  { GUINT_TO_POINTER (0x0461), "/omegacyrillic" },
  +  { GUINT_TO_POINTER (0x0277), "/omegalatinclosed" },
  +  { GUINT_TO_POINTER (0x047B), "/omegaroundcyrillic" },
  +  { GUINT_TO_POINTER (0x047D), "/omegatitlocyrillic" },
  +  { GUINT_TO_POINTER (0x03CE), "/omegatonos" },
  +  { GUINT_TO_POINTER (0x0AD0), "/omgujarati" },
  +  { GUINT_TO_POINTER (0x03BF), "/omicron" },
  +  { GUINT_TO_POINTER (0x03CC), "/omicrontonos" },
  +  { GUINT_TO_POINTER (0xFF4F), "/omonospace" },
  +  { GUINT_TO_POINTER (0x0031), "/one" },
  +  { GUINT_TO_POINTER (0x0661), "/onearabic" },
  +  { GUINT_TO_POINTER (0x09E7), "/onebengali" },
  +  { GUINT_TO_POINTER (0x2460), "/onecircle" },
  +  { GUINT_TO_POINTER (0x278A), "/onecircleinversesansserif" },
  +  { GUINT_TO_POINTER (0x0967), "/onedeva" },
  +  { GUINT_TO_POINTER (0x2024), "/onedotenleader" },
  +  { GUINT_TO_POINTER (0x215B), "/oneeighth" },
  +  { GUINT_TO_POINTER (0xF6DC), "/onefitted" },
  +  { GUINT_TO_POINTER (0x0AE7), "/onegujarati" },
  +  { GUINT_TO_POINTER (0x0A67), "/onegurmukhi" },
  +  { GUINT_TO_POINTER (0x0661), "/onehackarabic" },
  +  { GUINT_TO_POINTER (0x00BD), "/onehalf" },
  +  { GUINT_TO_POINTER (0x3021), "/onehangzhou" },
  +  { GUINT_TO_POINTER (0x3220), "/oneideographicparen" },
  +  { GUINT_TO_POINTER (0x2081), "/oneinferior" },
  +  { GUINT_TO_POINTER (0xFF11), "/onemonospace" },
  +  { GUINT_TO_POINTER (0x09F4), "/onenumeratorbengali" },
  +  { GUINT_TO_POINTER (0xF731), "/oneoldstyle" },
  +  { GUINT_TO_POINTER (0x2474), "/oneparen" },
  +  { GUINT_TO_POINTER (0x2488), "/oneperiod" },
  +  { GUINT_TO_POINTER (0x06F1), "/onepersian" },
  +  { GUINT_TO_POINTER (0x00BC), "/onequarter" },
  +  { GUINT_TO_POINTER (0x2170), "/oneroman" },
  +  { GUINT_TO_POINTER (0x00B9), "/onesuperior" },
  +  { GUINT_TO_POINTER (0x0E51), "/onethai" },
  +  { GUINT_TO_POINTER (0x2153), "/onethird" },
  +  { GUINT_TO_POINTER (0x01EB), "/oogonek" },
  +  { GUINT_TO_POINTER (0x01ED), "/oogonekmacron" },
  +  { GUINT_TO_POINTER (0x0A13), "/oogurmukhi" },
  +  { GUINT_TO_POINTER (0x0A4B), "/oomatragurmukhi" },
  +  { GUINT_TO_POINTER (0x0254), "/oopen" },
  +  { GUINT_TO_POINTER (0x24AA), "/oparen" },
  +  { GUINT_TO_POINTER (0x25E6), "/openbullet" },
  +  { GUINT_TO_POINTER (0x2325), "/option" },
  +  { GUINT_TO_POINTER (0x00AA), "/ordfeminine" },
  +  { GUINT_TO_POINTER (0x00BA), "/ordmasculine" },
  +  { GUINT_TO_POINTER (0x221F), "/orthogonal" },
  +  { GUINT_TO_POINTER (0x0912), "/oshortdeva" },
  +  { GUINT_TO_POINTER (0x094A), "/oshortvowelsigndeva" },
  +  { GUINT_TO_POINTER (0x00F8), "/oslash" },
  +  { GUINT_TO_POINTER (0x01FF), "/oslashacute" },
  +  { GUINT_TO_POINTER (0x3049), "/osmallhiragana" },
  +  { GUINT_TO_POINTER (0x30A9), "/osmallkatakana" },
  +  { GUINT_TO_POINTER (0xFF6B), "/osmallkatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x01FF), "/ostrokeacute" },
  +  { GUINT_TO_POINTER (0xF6F0), "/osuperior" },
  +  { GUINT_TO_POINTER (0x047F), "/otcyrillic" },
  +  { GUINT_TO_POINTER (0x00F5), "/otilde" },
  +  { GUINT_TO_POINTER (0x1E4D), "/otildeacute" },
  +  { GUINT_TO_POINTER (0x1E4F), "/otildedieresis" },
  +  { GUINT_TO_POINTER (0x3121), "/oubopomofo" },
  +  { GUINT_TO_POINTER (0x203E), "/overline" },
  +  { GUINT_TO_POINTER (0xFE4A), "/overlinecenterline" },
  +  { GUINT_TO_POINTER (0x0305), "/overlinecmb" },
  +  { GUINT_TO_POINTER (0xFE49), "/overlinedashed" },
  +  { GUINT_TO_POINTER (0xFE4C), "/overlinedblwavy" },
  +  { GUINT_TO_POINTER (0xFE4B), "/overlinewavy" },
  +  { GUINT_TO_POINTER (0x00AF), "/overscore" },
  +  { GUINT_TO_POINTER (0x09CB), "/ovowelsignbengali" },
  +  { GUINT_TO_POINTER (0x094B), "/ovowelsigndeva" },
  +  { GUINT_TO_POINTER (0x0ACB), "/ovowelsigngujarati" },
  +  { GUINT_TO_POINTER (0x0070), "/p" },
  +  { GUINT_TO_POINTER (0x3380), "/paampssquare" },
  +  { GUINT_TO_POINTER (0x332B), "/paasentosquare" },
  +  { GUINT_TO_POINTER (0x09AA), "/pabengali" },
  +  { GUINT_TO_POINTER (0x1E55), "/pacute" },
  +  { GUINT_TO_POINTER (0x092A), "/padeva" },
  +  { GUINT_TO_POINTER (0x21DF), "/pagedown" },
  +  { GUINT_TO_POINTER (0x21DE), "/pageup" },
  +  { GUINT_TO_POINTER (0x0AAA), "/pagujarati" },
  +  { GUINT_TO_POINTER (0x0A2A), "/pagurmukhi" },
  +  { GUINT_TO_POINTER (0x3071), "/pahiragana" },
  +  { GUINT_TO_POINTER (0x0E2F), "/paiyannoithai" },
  +  { GUINT_TO_POINTER (0x30D1), "/pakatakana" },
  +  { GUINT_TO_POINTER (0x0484), "/palatalizationcyrilliccmb" },
  +  { GUINT_TO_POINTER (0x04C0), "/palochkacyrillic" },
  +  { GUINT_TO_POINTER (0x317F), "/pansioskorean" },
  +  { GUINT_TO_POINTER (0x00B6), "/paragraph" },
  +  { GUINT_TO_POINTER (0x2225), "/parallel" },
  +  { GUINT_TO_POINTER (0x0028), "/parenleft" },
  +  { GUINT_TO_POINTER (0xFD3E), "/parenleftaltonearabic" },
  +  { GUINT_TO_POINTER (0xF8ED), "/parenleftbt" },
  +  { GUINT_TO_POINTER (0xF8EC), "/parenleftex" },
  +  { GUINT_TO_POINTER (0x208D), "/parenleftinferior" },
  +  { GUINT_TO_POINTER (0xFF08), "/parenleftmonospace" },
  +  { GUINT_TO_POINTER (0xFE59), "/parenleftsmall" },
  +  { GUINT_TO_POINTER (0x207D), "/parenleftsuperior" },
  +  { GUINT_TO_POINTER (0xF8EB), "/parenlefttp" },
  +  { GUINT_TO_POINTER (0xFE35), "/parenleftvertical" },
  +  { GUINT_TO_POINTER (0x0029), "/parenright" },
  +  { GUINT_TO_POINTER (0xFD3F), "/parenrightaltonearabic" },
  +  { GUINT_TO_POINTER (0xF8F8), "/parenrightbt" },
  +  { GUINT_TO_POINTER (0xF8F7), "/parenrightex" },
  +  { GUINT_TO_POINTER (0x208E), "/parenrightinferior" },
  +  { GUINT_TO_POINTER (0xFF09), "/parenrightmonospace" },
  +  { GUINT_TO_POINTER (0xFE5A), "/parenrightsmall" },
  +  { GUINT_TO_POINTER (0x207E), "/parenrightsuperior" },
  +  { GUINT_TO_POINTER (0xF8F6), "/parenrighttp" },
  +  { GUINT_TO_POINTER (0xFE36), "/parenrightvertical" },
  +  { GUINT_TO_POINTER (0x2202), "/partialdiff" },
  +  { GUINT_TO_POINTER (0x05C0), "/paseqhebrew" },
  +  { GUINT_TO_POINTER (0x0599), "/pashtahebrew" },
  +  { GUINT_TO_POINTER (0x33A9), "/pasquare" },
  +  { GUINT_TO_POINTER (0x05B7), "/patah" },
  +  { GUINT_TO_POINTER (0x05B7), "/patah11" },
  +  { GUINT_TO_POINTER (0x05B7), "/patah1d" },
  +  { GUINT_TO_POINTER (0x05B7), "/patah2a" },
  +  { GUINT_TO_POINTER (0x05B7), "/patahhebrew" },
  +  { GUINT_TO_POINTER (0x05B7), "/patahnarrowhebrew" },
  +  { GUINT_TO_POINTER (0x05B7), "/patahquarterhebrew" },
  +  { GUINT_TO_POINTER (0x05B7), "/patahwidehebrew" },
  +  { GUINT_TO_POINTER (0x05A1), "/pazerhebrew" },
  +  { GUINT_TO_POINTER (0x3106), "/pbopomofo" },
  +  { GUINT_TO_POINTER (0x24DF), "/pcircle" },
  +  { GUINT_TO_POINTER (0x1E57), "/pdotaccent" },
  +  { GUINT_TO_POINTER (0x05E4), "/pe" },
  +  { GUINT_TO_POINTER (0x043F), "/pecyrillic" },
  +  { GUINT_TO_POINTER (0xFB44), "/pedagesh" },
  +  { GUINT_TO_POINTER (0xFB44), "/pedageshhebrew" },
  +  { GUINT_TO_POINTER (0x333B), "/peezisquare" },
  +  { GUINT_TO_POINTER (0xFB43), "/pefinaldageshhebrew" },
  +  { GUINT_TO_POINTER (0x067E), "/peharabic" },
  +  { GUINT_TO_POINTER (0x057A), "/peharmenian" },
  +  { GUINT_TO_POINTER (0x05E4), "/pehebrew" },
  +  { GUINT_TO_POINTER (0xFB57), "/pehfinalarabic" },
  +  { GUINT_TO_POINTER (0xFB58), "/pehinitialarabic" },
  +  { GUINT_TO_POINTER (0x307A), "/pehiragana" },
  +  { GUINT_TO_POINTER (0xFB59), "/pehmedialarabic" },
  +  { GUINT_TO_POINTER (0x30DA), "/pekatakana" },
  +  { GUINT_TO_POINTER (0x04A7), "/pemiddlehookcyrillic" },
  +  { GUINT_TO_POINTER (0xFB4E), "/perafehebrew" },
  +  { GUINT_TO_POINTER (0x0025), "/percent" },
  +  { GUINT_TO_POINTER (0x066A), "/percentarabic" },
  +  { GUINT_TO_POINTER (0xFF05), "/percentmonospace" },
  +  { GUINT_TO_POINTER (0xFE6A), "/percentsmall" },
  +  { GUINT_TO_POINTER (0x002E), "/period" },
  +  { GUINT_TO_POINTER (0x0589), "/periodarmenian" },
  +  { GUINT_TO_POINTER (0x00B7), "/periodcentered" },
  +  { GUINT_TO_POINTER (0xFF61), "/periodhalfwidth" },
  +  { GUINT_TO_POINTER (0xF6E7), "/periodinferior" },
  +  { GUINT_TO_POINTER (0xFF0E), "/periodmonospace" },
  +  { GUINT_TO_POINTER (0xFE52), "/periodsmall" },
  +  { GUINT_TO_POINTER (0xF6E8), "/periodsuperior" },
  +  { GUINT_TO_POINTER (0x0342), "/perispomenigreekcmb" },
  +  { GUINT_TO_POINTER (0x22A5), "/perpendicular" },
  +  { GUINT_TO_POINTER (0x2030), "/perthousand" },
  +  { GUINT_TO_POINTER (0x20A7), "/peseta" },
  +  { GUINT_TO_POINTER (0x338A), "/pfsquare" },
  +  { GUINT_TO_POINTER (0x09AB), "/phabengali" },
  +  { GUINT_TO_POINTER (0x092B), "/phadeva" },
  +  { GUINT_TO_POINTER (0x0AAB), "/phagujarati" },
  +  { GUINT_TO_POINTER (0x0A2B), "/phagurmukhi" },
  +  { GUINT_TO_POINTER (0x03C6), "/phi" },
  +  { GUINT_TO_POINTER (0x03D5), "/phi1" },
  +  { GUINT_TO_POINTER (0x327A), "/phieuphacirclekorean" },
  +  { GUINT_TO_POINTER (0x321A), "/phieuphaparenkorean" },
  +  { GUINT_TO_POINTER (0x326C), "/phieuphcirclekorean" },
  +  { GUINT_TO_POINTER (0x314D), "/phieuphkorean" },
  +  { GUINT_TO_POINTER (0x320C), "/phieuphparenkorean" },
  +  { GUINT_TO_POINTER (0x0278), "/philatin" },
  +  { GUINT_TO_POINTER (0x0E3A), "/phinthuthai" },
  +  { GUINT_TO_POINTER (0x03D5), "/phisymbolgreek" },
  +  { GUINT_TO_POINTER (0x01A5), "/phook" },
  +  { GUINT_TO_POINTER (0x0E1E), "/phophanthai" },
  +  { GUINT_TO_POINTER (0x0E1C), "/phophungthai" },
  +  { GUINT_TO_POINTER (0x0E20), "/phosamphaothai" },
  +  { GUINT_TO_POINTER (0x03C0), "/pi" },
  +  { GUINT_TO_POINTER (0x3273), "/pieupacirclekorean" },
  +  { GUINT_TO_POINTER (0x3213), "/pieupaparenkorean" },
  +  { GUINT_TO_POINTER (0x3176), "/pieupcieuckorean" },
  +  { GUINT_TO_POINTER (0x3265), "/pieupcirclekorean" },
  +  { GUINT_TO_POINTER (0x3172), "/pieupkiyeokkorean" },
  +  { GUINT_TO_POINTER (0x3142), "/pieupkorean" },
  +  { GUINT_TO_POINTER (0x3205), "/pieupparenkorean" },
  +  { GUINT_TO_POINTER (0x3174), "/pieupsioskiyeokkorean" },
  +  { GUINT_TO_POINTER (0x3144), "/pieupsioskorean" },
  +  { GUINT_TO_POINTER (0x3175), "/pieupsiostikeutkorean" },
  +  { GUINT_TO_POINTER (0x3177), "/pieupthieuthkorean" },
  +  { GUINT_TO_POINTER (0x3173), "/pieuptikeutkorean" },
  +  { GUINT_TO_POINTER (0x3074), "/pihiragana" },
  +  { GUINT_TO_POINTER (0x30D4), "/pikatakana" },
  +  { GUINT_TO_POINTER (0x03D6), "/pisymbolgreek" },
  +  { GUINT_TO_POINTER (0x0583), "/piwrarmenian" },
  +  { GUINT_TO_POINTER (0x002B), "/plus" },
  +  { GUINT_TO_POINTER (0x031F), "/plusbelowcmb" },
  +  { GUINT_TO_POINTER (0x2295), "/pluscircle" },
  +  { GUINT_TO_POINTER (0x00B1), "/plusminus" },
  +  { GUINT_TO_POINTER (0x02D6), "/plusmod" },
  +  { GUINT_TO_POINTER (0xFF0B), "/plusmonospace" },
  +  { GUINT_TO_POINTER (0xFE62), "/plussmall" },
  +  { GUINT_TO_POINTER (0x207A), "/plussuperior" },
  +  { GUINT_TO_POINTER (0xFF50), "/pmonospace" },
  +  { GUINT_TO_POINTER (0x33D8), "/pmsquare" },
  +  { GUINT_TO_POINTER (0x307D), "/pohiragana" },
  +  { GUINT_TO_POINTER (0x261F), "/pointingindexdownwhite" },
  +  { GUINT_TO_POINTER (0x261C), "/pointingindexleftwhite" },
  +  { GUINT_TO_POINTER (0x261E), "/pointingindexrightwhite" },
  +  { GUINT_TO_POINTER (0x261D), "/pointingindexupwhite" },
  +  { GUINT_TO_POINTER (0x30DD), "/pokatakana" },
  +  { GUINT_TO_POINTER (0x0E1B), "/poplathai" },
  +  { GUINT_TO_POINTER (0x3012), "/postalmark" },
  +  { GUINT_TO_POINTER (0x3020), "/postalmarkface" },
  +  { GUINT_TO_POINTER (0x24AB), "/pparen" },
  +  { GUINT_TO_POINTER (0x227A), "/precedes" },
  +  { GUINT_TO_POINTER (0x211E), "/prescription" },
  +  { GUINT_TO_POINTER (0x02B9), "/primemod" },
  +  { GUINT_TO_POINTER (0x2035), "/primereversed" },
  +  { GUINT_TO_POINTER (0x220F), "/product" },
  +  { GUINT_TO_POINTER (0x2305), "/projective" },
  +  { GUINT_TO_POINTER (0x30FC), "/prolongedkana" },
  +  { GUINT_TO_POINTER (0x2318), "/propellor" },
  +  { GUINT_TO_POINTER (0x2282), "/propersubset" },
  +  { GUINT_TO_POINTER (0x2283), "/propersuperset" },
  +  { GUINT_TO_POINTER (0x2237), "/proportion" },
  +  { GUINT_TO_POINTER (0x221D), "/proportional" },
  +  { GUINT_TO_POINTER (0x03C8), "/psi" },
  +  { GUINT_TO_POINTER (0x0471), "/psicyrillic" },
  +  { GUINT_TO_POINTER (0x0486), "/psilipneumatacyrilliccmb" },
  +  { GUINT_TO_POINTER (0x33B0), "/pssquare" },
  +  { GUINT_TO_POINTER (0x3077), "/puhiragana" },
  +  { GUINT_TO_POINTER (0x30D7), "/pukatakana" },
  +  { GUINT_TO_POINTER (0x33B4), "/pvsquare" },
  +  { GUINT_TO_POINTER (0x33BA), "/pwsquare" },
  +  { GUINT_TO_POINTER (0x0071), "/q" },
  +  { GUINT_TO_POINTER (0x0958), "/qadeva" },
  +  { GUINT_TO_POINTER (0x05A8), "/qadmahebrew" },
  +  { GUINT_TO_POINTER (0x0642), "/qafarabic" },
  +  { GUINT_TO_POINTER (0xFED6), "/qaffinalarabic" },
  +  { GUINT_TO_POINTER (0xFED7), "/qafinitialarabic" },
  +  { GUINT_TO_POINTER (0xFED8), "/qafmedialarabic" },
  +  { GUINT_TO_POINTER (0x05B8), "/qamats" },
  +  { GUINT_TO_POINTER (0x05B8), "/qamats10" },
  +  { GUINT_TO_POINTER (0x05B8), "/qamats1a" },
  +  { GUINT_TO_POINTER (0x05B8), "/qamats1c" },
  +  { GUINT_TO_POINTER (0x05B8), "/qamats27" },
  +  { GUINT_TO_POINTER (0x05B8), "/qamats29" },
  +  { GUINT_TO_POINTER (0x05B8), "/qamats33" },
  +  { GUINT_TO_POINTER (0x05B8), "/qamatsde" },
  +  { GUINT_TO_POINTER (0x05B8), "/qamatshebrew" },
  +  { GUINT_TO_POINTER (0x05B8), "/qamatsnarrowhebrew" },
  +  { GUINT_TO_POINTER (0x05B8), "/qamatsqatanhebrew" },
  +  { GUINT_TO_POINTER (0x05B8), "/qamatsqatannarrowhebrew" },
  +  { GUINT_TO_POINTER (0x05B8), "/qamatsqatanquarterhebrew" },
  +  { GUINT_TO_POINTER (0x05B8), "/qamatsqatanwidehebrew" },
  +  { GUINT_TO_POINTER (0x05B8), "/qamatsquarterhebrew" },
  +  { GUINT_TO_POINTER (0x05B8), "/qamatswidehebrew" },
  +  { GUINT_TO_POINTER (0x059F), "/qarneyparahebrew" },
  +  { GUINT_TO_POINTER (0x3111), "/qbopomofo" },
  +  { GUINT_TO_POINTER (0x24E0), "/qcircle" },
  +  { GUINT_TO_POINTER (0x02A0), "/qhook" },
  +  { GUINT_TO_POINTER (0xFF51), "/qmonospace" },
  +  { GUINT_TO_POINTER (0x05E7), "/qof" },
  +  { GUINT_TO_POINTER (0xFB47), "/qofdagesh" },
  +  { GUINT_TO_POINTER (0xFB47), "/qofdageshhebrew" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofhatafpatah" },
  +  { GUINT_TO_POINTER (0x05B2), "/qofhatafpatah" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofhatafpatahhebrew" },
  +  { GUINT_TO_POINTER (0x05B2), "/qofhatafpatahhebrew" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofhatafsegol" },
  +  { GUINT_TO_POINTER (0x05B1), "/qofhatafsegol" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofhatafsegolhebrew" },
  +  { GUINT_TO_POINTER (0x05B1), "/qofhatafsegolhebrew" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofhebrew" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofhiriq" },
  +  { GUINT_TO_POINTER (0x05B4), "/qofhiriq" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofhiriqhebrew" },
  +  { GUINT_TO_POINTER (0x05B4), "/qofhiriqhebrew" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofholam" },
  +  { GUINT_TO_POINTER (0x05B9), "/qofholam" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofholamhebrew" },
  +  { GUINT_TO_POINTER (0x05B9), "/qofholamhebrew" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofpatah" },
  +  { GUINT_TO_POINTER (0x05B7), "/qofpatah" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofpatahhebrew" },
  +  { GUINT_TO_POINTER (0x05B7), "/qofpatahhebrew" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofqamats" },
  +  { GUINT_TO_POINTER (0x05B8), "/qofqamats" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofqamatshebrew" },
  +  { GUINT_TO_POINTER (0x05B8), "/qofqamatshebrew" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofqubuts" },
  +  { GUINT_TO_POINTER (0x05BB), "/qofqubuts" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofqubutshebrew" },
  +  { GUINT_TO_POINTER (0x05BB), "/qofqubutshebrew" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofsegol" },
  +  { GUINT_TO_POINTER (0x05B6), "/qofsegol" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofsegolhebrew" },
  +  { GUINT_TO_POINTER (0x05B6), "/qofsegolhebrew" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofsheva" },
  +  { GUINT_TO_POINTER (0x05B0), "/qofsheva" },
  +  { GUINT_TO_POINTER (0x05E7), "/qofshevahebrew" },
  +  { GUINT_TO_POINTER (0x05B0), "/qofshevahebrew" },
  +  { GUINT_TO_POINTER (0x05E7), "/qoftsere" },
  +  { GUINT_TO_POINTER (0x05B5), "/qoftsere" },
  +  { GUINT_TO_POINTER (0x05E7), "/qoftserehebrew" },
  +  { GUINT_TO_POINTER (0x05B5), "/qoftserehebrew" },
  +  { GUINT_TO_POINTER (0x24AC), "/qparen" },
  +  { GUINT_TO_POINTER (0x2669), "/quarternote" },
  +  { GUINT_TO_POINTER (0x05BB), "/qubuts" },
  +  { GUINT_TO_POINTER (0x05BB), "/qubuts18" },
  +  { GUINT_TO_POINTER (0x05BB), "/qubuts25" },
  +  { GUINT_TO_POINTER (0x05BB), "/qubuts31" },
  +  { GUINT_TO_POINTER (0x05BB), "/qubutshebrew" },
  +  { GUINT_TO_POINTER (0x05BB), "/qubutsnarrowhebrew" },
  +  { GUINT_TO_POINTER (0x05BB), "/qubutsquarterhebrew" },
  +  { GUINT_TO_POINTER (0x05BB), "/qubutswidehebrew" },
  +  { GUINT_TO_POINTER (0x003F), "/question" },
  +  { GUINT_TO_POINTER (0x061F), "/questionarabic" },
  +  { GUINT_TO_POINTER (0x055E), "/questionarmenian" },
  +  { GUINT_TO_POINTER (0x00BF), "/questiondown" },
  +  { GUINT_TO_POINTER (0xF7BF), "/questiondownsmall" },
  +  { GUINT_TO_POINTER (0x037E), "/questiongreek" },
  +  { GUINT_TO_POINTER (0xFF1F), "/questionmonospace" },
  +  { GUINT_TO_POINTER (0xF73F), "/questionsmall" },
  +  { GUINT_TO_POINTER (0x0022), "/quotedbl" },
  +  { GUINT_TO_POINTER (0x201E), "/quotedblbase" },
  +  { GUINT_TO_POINTER (0x201C), "/quotedblleft" },
  +  { GUINT_TO_POINTER (0xFF02), "/quotedblmonospace" },
  +  { GUINT_TO_POINTER (0x301E), "/quotedblprime" },
  +  { GUINT_TO_POINTER (0x301D), "/quotedblprimereversed" },
  +  { GUINT_TO_POINTER (0x201D), "/quotedblright" },
  +  { GUINT_TO_POINTER (0x2018), "/quoteleft" },
  +  { GUINT_TO_POINTER (0x201B), "/quoteleftreversed" },
  +  { GUINT_TO_POINTER (0x201B), "/quotereversed" },
  +  { GUINT_TO_POINTER (0x2019), "/quoteright" },
  +  { GUINT_TO_POINTER (0x0149), "/quoterightn" },
  +  { GUINT_TO_POINTER (0x201A), "/quotesinglbase" },
  +  { GUINT_TO_POINTER (0x0027), "/quotesingle" },
  +  { GUINT_TO_POINTER (0xFF07), "/quotesinglemonospace" },
  +  { GUINT_TO_POINTER (0x0072), "/r" },
  +  { GUINT_TO_POINTER (0x057C), "/raarmenian" },
  +  { GUINT_TO_POINTER (0x09B0), "/rabengali" },
  +  { GUINT_TO_POINTER (0x0155), "/racute" },
  +  { GUINT_TO_POINTER (0x0930), "/radeva" },
  +  { GUINT_TO_POINTER (0x221A), "/radical" },
  +  { GUINT_TO_POINTER (0xF8E5), "/radicalex" },
  +  { GUINT_TO_POINTER (0x33AE), "/radoverssquare" },
  +  { GUINT_TO_POINTER (0x33AF), "/radoverssquaredsquare" },
  +  { GUINT_TO_POINTER (0x33AD), "/radsquare" },
  +  { GUINT_TO_POINTER (0x05BF), "/rafe" },
  +  { GUINT_TO_POINTER (0x05BF), "/rafehebrew" },
  +  { GUINT_TO_POINTER (0x0AB0), "/ragujarati" },
  +  { GUINT_TO_POINTER (0x0A30), "/ragurmukhi" },
  +  { GUINT_TO_POINTER (0x3089), "/rahiragana" },
  +  { GUINT_TO_POINTER (0x30E9), "/rakatakana" },
  +  { GUINT_TO_POINTER (0xFF97), "/rakatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x09F1), "/ralowerdiagonalbengali" },
  +  { GUINT_TO_POINTER (0x09F0), "/ramiddlediagonalbengali" },
  +  { GUINT_TO_POINTER (0x0264), "/ramshorn" },
  +  { GUINT_TO_POINTER (0x2236), "/ratio" },
  +  { GUINT_TO_POINTER (0x3116), "/rbopomofo" },
  +  { GUINT_TO_POINTER (0x0159), "/rcaron" },
  +  { GUINT_TO_POINTER (0x0157), "/rcedilla" },
  +  { GUINT_TO_POINTER (0x24E1), "/rcircle" },
  +  { GUINT_TO_POINTER (0x0157), "/rcommaaccent" },
  +  { GUINT_TO_POINTER (0x0211), "/rdblgrave" },
  +  { GUINT_TO_POINTER (0x1E59), "/rdotaccent" },
  +  { GUINT_TO_POINTER (0x1E5B), "/rdotbelow" },
  +  { GUINT_TO_POINTER (0x1E5D), "/rdotbelowmacron" },
  +  { GUINT_TO_POINTER (0x203B), "/referencemark" },
  +  { GUINT_TO_POINTER (0x2286), "/reflexsubset" },
  +  { GUINT_TO_POINTER (0x2287), "/reflexsuperset" },
  +  { GUINT_TO_POINTER (0x00AE), "/registered" },
  +  { GUINT_TO_POINTER (0xF8E8), "/registersans" },
  +  { GUINT_TO_POINTER (0xF6DA), "/registerserif" },
  +  { GUINT_TO_POINTER (0x0631), "/reharabic" },
  +  { GUINT_TO_POINTER (0x0580), "/reharmenian" },
  +  { GUINT_TO_POINTER (0xFEAE), "/rehfinalarabic" },
  +  { GUINT_TO_POINTER (0x308C), "/rehiragana" },
  +  { GUINT_TO_POINTER (0x0631), "/rehyehaleflamarabic" },
  +  { GUINT_TO_POINTER (0xFEF3), "/rehyehaleflamarabic" },
  +  { GUINT_TO_POINTER (0xFE8E), "/rehyehaleflamarabic" },
  +  { GUINT_TO_POINTER (0x0644), "/rehyehaleflamarabic" },
  +  { GUINT_TO_POINTER (0x30EC), "/rekatakana" },
  +  { GUINT_TO_POINTER (0xFF9A), "/rekatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x05E8), "/resh" },
  +  { GUINT_TO_POINTER (0xFB48), "/reshdageshhebrew" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshhatafpatah" },
  +  { GUINT_TO_POINTER (0x05B2), "/reshhatafpatah" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshhatafpatahhebrew" },
  +  { GUINT_TO_POINTER (0x05B2), "/reshhatafpatahhebrew" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshhatafsegol" },
  +  { GUINT_TO_POINTER (0x05B1), "/reshhatafsegol" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshhatafsegolhebrew" },
  +  { GUINT_TO_POINTER (0x05B1), "/reshhatafsegolhebrew" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshhebrew" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshhiriq" },
  +  { GUINT_TO_POINTER (0x05B4), "/reshhiriq" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshhiriqhebrew" },
  +  { GUINT_TO_POINTER (0x05B4), "/reshhiriqhebrew" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshholam" },
  +  { GUINT_TO_POINTER (0x05B9), "/reshholam" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshholamhebrew" },
  +  { GUINT_TO_POINTER (0x05B9), "/reshholamhebrew" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshpatah" },
  +  { GUINT_TO_POINTER (0x05B7), "/reshpatah" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshpatahhebrew" },
  +  { GUINT_TO_POINTER (0x05B7), "/reshpatahhebrew" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshqamats" },
  +  { GUINT_TO_POINTER (0x05B8), "/reshqamats" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshqamatshebrew" },
  +  { GUINT_TO_POINTER (0x05B8), "/reshqamatshebrew" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshqubuts" },
  +  { GUINT_TO_POINTER (0x05BB), "/reshqubuts" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshqubutshebrew" },
  +  { GUINT_TO_POINTER (0x05BB), "/reshqubutshebrew" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshsegol" },
  +  { GUINT_TO_POINTER (0x05B6), "/reshsegol" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshsegolhebrew" },
  +  { GUINT_TO_POINTER (0x05B6), "/reshsegolhebrew" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshsheva" },
  +  { GUINT_TO_POINTER (0x05B0), "/reshsheva" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshshevahebrew" },
  +  { GUINT_TO_POINTER (0x05B0), "/reshshevahebrew" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshtsere" },
  +  { GUINT_TO_POINTER (0x05B5), "/reshtsere" },
  +  { GUINT_TO_POINTER (0x05E8), "/reshtserehebrew" },
  +  { GUINT_TO_POINTER (0x05B5), "/reshtserehebrew" },
  +  { GUINT_TO_POINTER (0x223D), "/reversedtilde" },
  +  { GUINT_TO_POINTER (0x0597), "/reviahebrew" },
  +  { GUINT_TO_POINTER (0x0597), "/reviamugrashhebrew" },
  +  { GUINT_TO_POINTER (0x2310), "/revlogicalnot" },
  +  { GUINT_TO_POINTER (0x027E), "/rfishhook" },
  +  { GUINT_TO_POINTER (0x027F), "/rfishhookreversed" },
  +  { GUINT_TO_POINTER (0x09DD), "/rhabengali" },
  +  { GUINT_TO_POINTER (0x095D), "/rhadeva" },
  +  { GUINT_TO_POINTER (0x03C1), "/rho" },
  +  { GUINT_TO_POINTER (0x027D), "/rhook" },
  +  { GUINT_TO_POINTER (0x027B), "/rhookturned" },
  +  { GUINT_TO_POINTER (0x02B5), "/rhookturnedsuperior" },
  +  { GUINT_TO_POINTER (0x03F1), "/rhosymbolgreek" },
  +  { GUINT_TO_POINTER (0x02DE), "/rhotichookmod" },
  +  { GUINT_TO_POINTER (0x3271), "/rieulacirclekorean" },
  +  { GUINT_TO_POINTER (0x3211), "/rieulaparenkorean" },
  +  { GUINT_TO_POINTER (0x3263), "/rieulcirclekorean" },
  +  { GUINT_TO_POINTER (0x3140), "/rieulhieuhkorean" },
  +  { GUINT_TO_POINTER (0x313A), "/rieulkiyeokkorean" },
  +  { GUINT_TO_POINTER (0x3169), "/rieulkiyeoksioskorean" },
  +  { GUINT_TO_POINTER (0x3139), "/rieulkorean" },
  +  { GUINT_TO_POINTER (0x313B), "/rieulmieumkorean" },
  +  { GUINT_TO_POINTER (0x316C), "/rieulpansioskorean" },
  +  { GUINT_TO_POINTER (0x3203), "/rieulparenkorean" },
  +  { GUINT_TO_POINTER (0x313F), "/rieulphieuphkorean" },
  +  { GUINT_TO_POINTER (0x313C), "/rieulpieupkorean" },
  +  { GUINT_TO_POINTER (0x316B), "/rieulpieupsioskorean" },
  +  { GUINT_TO_POINTER (0x313D), "/rieulsioskorean" },
  +  { GUINT_TO_POINTER (0x313E), "/rieulthieuthkorean" },
  +  { GUINT_TO_POINTER (0x316A), "/rieultikeutkorean" },
  +  { GUINT_TO_POINTER (0x316D), "/rieulyeorinhieuhkorean" },
  +  { GUINT_TO_POINTER (0x221F), "/rightangle" },
  +  { GUINT_TO_POINTER (0x0319), "/righttackbelowcmb" },
  +  { GUINT_TO_POINTER (0x22BF), "/righttriangle" },
  +  { GUINT_TO_POINTER (0x308A), "/rihiragana" },
  +  { GUINT_TO_POINTER (0x30EA), "/rikatakana" },
  +  { GUINT_TO_POINTER (0xFF98), "/rikatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x02DA), "/ring" },
  +  { GUINT_TO_POINTER (0x0325), "/ringbelowcmb" },
  +  { GUINT_TO_POINTER (0x030A), "/ringcmb" },
  +  { GUINT_TO_POINTER (0x02BF), "/ringhalfleft" },
  +  { GUINT_TO_POINTER (0x0559), "/ringhalfleftarmenian" },
  +  { GUINT_TO_POINTER (0x031C), "/ringhalfleftbelowcmb" },
  +  { GUINT_TO_POINTER (0x02D3), "/ringhalfleftcentered" },
  +  { GUINT_TO_POINTER (0x02BE), "/ringhalfright" },
  +  { GUINT_TO_POINTER (0x0339), "/ringhalfrightbelowcmb" },
  +  { GUINT_TO_POINTER (0x02D2), "/ringhalfrightcentered" },
  +  { GUINT_TO_POINTER (0x0213), "/rinvertedbreve" },
  +  { GUINT_TO_POINTER (0x3351), "/rittorusquare" },
  +  { GUINT_TO_POINTER (0x1E5F), "/rlinebelow" },
  +  { GUINT_TO_POINTER (0x027C), "/rlongleg" },
  +  { GUINT_TO_POINTER (0x027A), "/rlonglegturned" },
  +  { GUINT_TO_POINTER (0xFF52), "/rmonospace" },
  +  { GUINT_TO_POINTER (0x308D), "/rohiragana" },
  +  { GUINT_TO_POINTER (0x30ED), "/rokatakana" },
  +  { GUINT_TO_POINTER (0xFF9B), "/rokatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x0E23), "/roruathai" },
  +  { GUINT_TO_POINTER (0x24AD), "/rparen" },
  +  { GUINT_TO_POINTER (0x09DC), "/rrabengali" },
  +  { GUINT_TO_POINTER (0x0931), "/rradeva" },
  +  { GUINT_TO_POINTER (0x0A5C), "/rragurmukhi" },
  +  { GUINT_TO_POINTER (0x0691), "/rreharabic" },
  +  { GUINT_TO_POINTER (0xFB8D), "/rrehfinalarabic" },
  +  { GUINT_TO_POINTER (0x09E0), "/rrvocalicbengali" },
  +  { GUINT_TO_POINTER (0x0960), "/rrvocalicdeva" },
  +  { GUINT_TO_POINTER (0x0AE0), "/rrvocalicgujarati" },
  +  { GUINT_TO_POINTER (0x09C4), "/rrvocalicvowelsignbengali" },
  +  { GUINT_TO_POINTER (0x0944), "/rrvocalicvowelsigndeva" },
  +  { GUINT_TO_POINTER (0x0AC4), "/rrvocalicvowelsigngujarati" },
  +  { GUINT_TO_POINTER (0xF6F1), "/rsuperior" },
  +  { GUINT_TO_POINTER (0x2590), "/rtblock" },
  +  { GUINT_TO_POINTER (0x0279), "/rturned" },
  +  { GUINT_TO_POINTER (0x02B4), "/rturnedsuperior" },
  +  { GUINT_TO_POINTER (0x308B), "/ruhiragana" },
  +  { GUINT_TO_POINTER (0x30EB), "/rukatakana" },
  +  { GUINT_TO_POINTER (0xFF99), "/rukatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x09F2), "/rupeemarkbengali" },
  +  { GUINT_TO_POINTER (0x09F3), "/rupeesignbengali" },
  +  { GUINT_TO_POINTER (0xF6DD), "/rupiah" },
  +  { GUINT_TO_POINTER (0x0E24), "/ruthai" },
  +  { GUINT_TO_POINTER (0x098B), "/rvocalicbengali" },
  +  { GUINT_TO_POINTER (0x090B), "/rvocalicdeva" },
  +  { GUINT_TO_POINTER (0x0A8B), "/rvocalicgujarati" },
  +  { GUINT_TO_POINTER (0x09C3), "/rvocalicvowelsignbengali" },
  +  { GUINT_TO_POINTER (0x0943), "/rvocalicvowelsigndeva" },
  +  { GUINT_TO_POINTER (0x0AC3), "/rvocalicvowelsigngujarati" },
  +  { GUINT_TO_POINTER (0x0073), "/s" },
  +  { GUINT_TO_POINTER (0x09B8), "/sabengali" },
  +  { GUINT_TO_POINTER (0x015B), "/sacute" },
  +  { GUINT_TO_POINTER (0x1E65), "/sacutedotaccent" },
  +  { GUINT_TO_POINTER (0x0635), "/sadarabic" },
  +  { GUINT_TO_POINTER (0x0938), "/sadeva" },
  +  { GUINT_TO_POINTER (0xFEBA), "/sadfinalarabic" },
  +  { GUINT_TO_POINTER (0xFEBB), "/sadinitialarabic" },
  +  { GUINT_TO_POINTER (0xFEBC), "/sadmedialarabic" },
  +  { GUINT_TO_POINTER (0x0AB8), "/sagujarati" },
  +  { GUINT_TO_POINTER (0x0A38), "/sagurmukhi" },
  +  { GUINT_TO_POINTER (0x3055), "/sahiragana" },
  +  { GUINT_TO_POINTER (0x30B5), "/sakatakana" },
  +  { GUINT_TO_POINTER (0xFF7B), "/sakatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0xFDFA), "/sallallahoualayhewasallamarabic" },
  +  { GUINT_TO_POINTER (0x05E1), "/samekh" },
  +  { GUINT_TO_POINTER (0xFB41), "/samekhdagesh" },
  +  { GUINT_TO_POINTER (0xFB41), "/samekhdageshhebrew" },
  +  { GUINT_TO_POINTER (0x05E1), "/samekhhebrew" },
  +  { GUINT_TO_POINTER (0x0E32), "/saraaathai" },
  +  { GUINT_TO_POINTER (0x0E41), "/saraaethai" },
  +  { GUINT_TO_POINTER (0x0E44), "/saraaimaimalaithai" },
  +  { GUINT_TO_POINTER (0x0E43), "/saraaimaimuanthai" },
  +  { GUINT_TO_POINTER (0x0E33), "/saraamthai" },
  +  { GUINT_TO_POINTER (0x0E30), "/saraathai" },
  +  { GUINT_TO_POINTER (0x0E40), "/saraethai" },
  +  { GUINT_TO_POINTER (0xF886), "/saraiileftthai" },
  +  { GUINT_TO_POINTER (0x0E35), "/saraiithai" },
  +  { GUINT_TO_POINTER (0xF885), "/saraileftthai" },
  +  { GUINT_TO_POINTER (0x0E34), "/saraithai" },
  +  { GUINT_TO_POINTER (0x0E42), "/saraothai" },
  +  { GUINT_TO_POINTER (0xF888), "/saraueeleftthai" },
  +  { GUINT_TO_POINTER (0x0E37), "/saraueethai" },
  +  { GUINT_TO_POINTER (0xF887), "/saraueleftthai" },
  +  { GUINT_TO_POINTER (0x0E36), "/sarauethai" },
  +  { GUINT_TO_POINTER (0x0E38), "/sarauthai" },
  +  { GUINT_TO_POINTER (0x0E39), "/sarauuthai" },
  +  { GUINT_TO_POINTER (0x3119), "/sbopomofo" },
  +  { GUINT_TO_POINTER (0x0161), "/scaron" },
  +  { GUINT_TO_POINTER (0x1E67), "/scarondotaccent" },
  +  { GUINT_TO_POINTER (0x015F), "/scedilla" },
  +  { GUINT_TO_POINTER (0x0259), "/schwa" },
  +  { GUINT_TO_POINTER (0x04D9), "/schwacyrillic" },
  +  { GUINT_TO_POINTER (0x04DB), "/schwadieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x025A), "/schwahook" },
  +  { GUINT_TO_POINTER (0x24E2), "/scircle" },
  +  { GUINT_TO_POINTER (0x015D), "/scircumflex" },
  +  { GUINT_TO_POINTER (0x0219), "/scommaaccent" },
  +  { GUINT_TO_POINTER (0x1E61), "/sdotaccent" },
  +  { GUINT_TO_POINTER (0x1E63), "/sdotbelow" },
  +  { GUINT_TO_POINTER (0x1E69), "/sdotbelowdotaccent" },
  +  { GUINT_TO_POINTER (0x033C), "/seagullbelowcmb" },
  +  { GUINT_TO_POINTER (0x2033), "/second" },
  +  { GUINT_TO_POINTER (0x02CA), "/secondtonechinese" },
  +  { GUINT_TO_POINTER (0x00A7), "/section" },
  +  { GUINT_TO_POINTER (0x0633), "/seenarabic" },
  +  { GUINT_TO_POINTER (0xFEB2), "/seenfinalarabic" },
  +  { GUINT_TO_POINTER (0xFEB3), "/seeninitialarabic" },
  +  { GUINT_TO_POINTER (0xFEB4), "/seenmedialarabic" },
  +  { GUINT_TO_POINTER (0x05B6), "/segol" },
  +  { GUINT_TO_POINTER (0x05B6), "/segol13" },
  +  { GUINT_TO_POINTER (0x05B6), "/segol1f" },
  +  { GUINT_TO_POINTER (0x05B6), "/segol2c" },
  +  { GUINT_TO_POINTER (0x05B6), "/segolhebrew" },
  +  { GUINT_TO_POINTER (0x05B6), "/segolnarrowhebrew" },
  +  { GUINT_TO_POINTER (0x05B6), "/segolquarterhebrew" },
  +  { GUINT_TO_POINTER (0x0592), "/segoltahebrew" },
  +  { GUINT_TO_POINTER (0x05B6), "/segolwidehebrew" },
  +  { GUINT_TO_POINTER (0x057D), "/seharmenian" },
  +  { GUINT_TO_POINTER (0x305B), "/sehiragana" },
  +  { GUINT_TO_POINTER (0x30BB), "/sekatakana" },
  +  { GUINT_TO_POINTER (0xFF7E), "/sekatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x003B), "/semicolon" },
  +  { GUINT_TO_POINTER (0x061B), "/semicolonarabic" },
  +  { GUINT_TO_POINTER (0xFF1B), "/semicolonmonospace" },
  +  { GUINT_TO_POINTER (0xFE54), "/semicolonsmall" },
  +  { GUINT_TO_POINTER (0x309C), "/semivoicedmarkkana" },
  +  { GUINT_TO_POINTER (0xFF9F), "/semivoicedmarkkanahalfwidth" },
  +  { GUINT_TO_POINTER (0x3322), "/sentisquare" },
  +  { GUINT_TO_POINTER (0x3323), "/sentosquare" },
  +  { GUINT_TO_POINTER (0x0037), "/seven" },
  +  { GUINT_TO_POINTER (0x0667), "/sevenarabic" },
  +  { GUINT_TO_POINTER (0x09ED), "/sevenbengali" },
  +  { GUINT_TO_POINTER (0x2466), "/sevencircle" },
  +  { GUINT_TO_POINTER (0x2790), "/sevencircleinversesansserif" },
  +  { GUINT_TO_POINTER (0x096D), "/sevendeva" },
  +  { GUINT_TO_POINTER (0x215E), "/seveneighths" },
  +  { GUINT_TO_POINTER (0x0AED), "/sevengujarati" },
  +  { GUINT_TO_POINTER (0x0A6D), "/sevengurmukhi" },
  +  { GUINT_TO_POINTER (0x0667), "/sevenhackarabic" },
  +  { GUINT_TO_POINTER (0x3027), "/sevenhangzhou" },
  +  { GUINT_TO_POINTER (0x3226), "/sevenideographicparen" },
  +  { GUINT_TO_POINTER (0x2087), "/seveninferior" },
  +  { GUINT_TO_POINTER (0xFF17), "/sevenmonospace" },
  +  { GUINT_TO_POINTER (0xF737), "/sevenoldstyle" },
  +  { GUINT_TO_POINTER (0x247A), "/sevenparen" },
  +  { GUINT_TO_POINTER (0x248E), "/sevenperiod" },
  +  { GUINT_TO_POINTER (0x06F7), "/sevenpersian" },
  +  { GUINT_TO_POINTER (0x2176), "/sevenroman" },
  +  { GUINT_TO_POINTER (0x2077), "/sevensuperior" },
  +  { GUINT_TO_POINTER (0x2470), "/seventeencircle" },
  +  { GUINT_TO_POINTER (0x2484), "/seventeenparen" },
  +  { GUINT_TO_POINTER (0x2498), "/seventeenperiod" },
  +  { GUINT_TO_POINTER (0x0E57), "/seventhai" },
  +  { GUINT_TO_POINTER (0x00AD), "/sfthyphen" },
  +  { GUINT_TO_POINTER (0x0577), "/shaarmenian" },
  +  { GUINT_TO_POINTER (0x09B6), "/shabengali" },
  +  { GUINT_TO_POINTER (0x0448), "/shacyrillic" },
  +  { GUINT_TO_POINTER (0x0651), "/shaddaarabic" },
  +  { GUINT_TO_POINTER (0xFC61), "/shaddadammaarabic" },
  +  { GUINT_TO_POINTER (0xFC5E), "/shaddadammatanarabic" },
  +  { GUINT_TO_POINTER (0xFC60), "/shaddafathaarabic" },
  +  { GUINT_TO_POINTER (0x0651), "/shaddafathatanarabic" },
  +  { GUINT_TO_POINTER (0x064B), "/shaddafathatanarabic" },
  +  { GUINT_TO_POINTER (0xFC62), "/shaddakasraarabic" },
  +  { GUINT_TO_POINTER (0xFC5F), "/shaddakasratanarabic" },
  +  { GUINT_TO_POINTER (0x2592), "/shade" },
  +  { GUINT_TO_POINTER (0x2593), "/shadedark" },
  +  { GUINT_TO_POINTER (0x2591), "/shadelight" },
  +  { GUINT_TO_POINTER (0x2592), "/shademedium" },
  +  { GUINT_TO_POINTER (0x0936), "/shadeva" },
  +  { GUINT_TO_POINTER (0x0AB6), "/shagujarati" },
  +  { GUINT_TO_POINTER (0x0A36), "/shagurmukhi" },
  +  { GUINT_TO_POINTER (0x0593), "/shalshelethebrew" },
  +  { GUINT_TO_POINTER (0x3115), "/shbopomofo" },
  +  { GUINT_TO_POINTER (0x0449), "/shchacyrillic" },
  +  { GUINT_TO_POINTER (0x0634), "/sheenarabic" },
  +  { GUINT_TO_POINTER (0xFEB6), "/sheenfinalarabic" },
  +  { GUINT_TO_POINTER (0xFEB7), "/sheeninitialarabic" },
  +  { GUINT_TO_POINTER (0xFEB8), "/sheenmedialarabic" },
  +  { GUINT_TO_POINTER (0x03E3), "/sheicoptic" },
  +  { GUINT_TO_POINTER (0x20AA), "/sheqel" },
  +  { GUINT_TO_POINTER (0x20AA), "/sheqelhebrew" },
  +  { GUINT_TO_POINTER (0x05B0), "/sheva" },
  +  { GUINT_TO_POINTER (0x05B0), "/sheva115" },
  +  { GUINT_TO_POINTER (0x05B0), "/sheva15" },
  +  { GUINT_TO_POINTER (0x05B0), "/sheva22" },
  +  { GUINT_TO_POINTER (0x05B0), "/sheva2e" },
  +  { GUINT_TO_POINTER (0x05B0), "/shevahebrew" },
  +  { GUINT_TO_POINTER (0x05B0), "/shevanarrowhebrew" },
  +  { GUINT_TO_POINTER (0x05B0), "/shevaquarterhebrew" },
  +  { GUINT_TO_POINTER (0x05B0), "/shevawidehebrew" },
  +  { GUINT_TO_POINTER (0x04BB), "/shhacyrillic" },
  +  { GUINT_TO_POINTER (0x03ED), "/shimacoptic" },
  +  { GUINT_TO_POINTER (0x05E9), "/shin" },
  +  { GUINT_TO_POINTER (0xFB49), "/shindagesh" },
  +  { GUINT_TO_POINTER (0xFB49), "/shindageshhebrew" },
  +  { GUINT_TO_POINTER (0xFB2C), "/shindageshshindot" },
  +  { GUINT_TO_POINTER (0xFB2C), "/shindageshshindothebrew" },
  +  { GUINT_TO_POINTER (0xFB2D), "/shindageshsindot" },
  +  { GUINT_TO_POINTER (0xFB2D), "/shindageshsindothebrew" },
  +  { GUINT_TO_POINTER (0x05C1), "/shindothebrew" },
  +  { GUINT_TO_POINTER (0x05E9), "/shinhebrew" },
  +  { GUINT_TO_POINTER (0xFB2A), "/shinshindot" },
  +  { GUINT_TO_POINTER (0xFB2A), "/shinshindothebrew" },
  +  { GUINT_TO_POINTER (0xFB2B), "/shinsindot" },
  +  { GUINT_TO_POINTER (0xFB2B), "/shinsindothebrew" },
  +  { GUINT_TO_POINTER (0x0282), "/shook" },
  +  { GUINT_TO_POINTER (0x03C3), "/sigma" },
  +  { GUINT_TO_POINTER (0x03C2), "/sigma1" },
  +  { GUINT_TO_POINTER (0x03C2), "/sigmafinal" },
  +  { GUINT_TO_POINTER (0x03F2), "/sigmalunatesymbolgreek" },
  +  { GUINT_TO_POINTER (0x3057), "/sihiragana" },
  +  { GUINT_TO_POINTER (0x30B7), "/sikatakana" },
  +  { GUINT_TO_POINTER (0xFF7C), "/sikatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x05BD), "/siluqhebrew" },
  +  { GUINT_TO_POINTER (0x05BD), "/siluqlefthebrew" },
  +  { GUINT_TO_POINTER (0x223C), "/similar" },
  +  { GUINT_TO_POINTER (0x05C2), "/sindothebrew" },
  +  { GUINT_TO_POINTER (0x3274), "/siosacirclekorean" },
  +  { GUINT_TO_POINTER (0x3214), "/siosaparenkorean" },
  +  { GUINT_TO_POINTER (0x317E), "/sioscieuckorean" },
  +  { GUINT_TO_POINTER (0x3266), "/sioscirclekorean" },
  +  { GUINT_TO_POINTER (0x317A), "/sioskiyeokkorean" },
  +  { GUINT_TO_POINTER (0x3145), "/sioskorean" },
  +  { GUINT_TO_POINTER (0x317B), "/siosnieunkorean" },
  +  { GUINT_TO_POINTER (0x3206), "/siosparenkorean" },
  +  { GUINT_TO_POINTER (0x317D), "/siospieupkorean" },
  +  { GUINT_TO_POINTER (0x317C), "/siostikeutkorean" },
  +  { GUINT_TO_POINTER (0x0036), "/six" },
  +  { GUINT_TO_POINTER (0x0666), "/sixarabic" },
  +  { GUINT_TO_POINTER (0x09EC), "/sixbengali" },
  +  { GUINT_TO_POINTER (0x2465), "/sixcircle" },
  +  { GUINT_TO_POINTER (0x278F), "/sixcircleinversesansserif" },
  +  { GUINT_TO_POINTER (0x096C), "/sixdeva" },
  +  { GUINT_TO_POINTER (0x0AEC), "/sixgujarati" },
  +  { GUINT_TO_POINTER (0x0A6C), "/sixgurmukhi" },
  +  { GUINT_TO_POINTER (0x0666), "/sixhackarabic" },
  +  { GUINT_TO_POINTER (0x3026), "/sixhangzhou" },
  +  { GUINT_TO_POINTER (0x3225), "/sixideographicparen" },
  +  { GUINT_TO_POINTER (0x2086), "/sixinferior" },
  +  { GUINT_TO_POINTER (0xFF16), "/sixmonospace" },
  +  { GUINT_TO_POINTER (0xF736), "/sixoldstyle" },
  +  { GUINT_TO_POINTER (0x2479), "/sixparen" },
  +  { GUINT_TO_POINTER (0x248D), "/sixperiod" },
  +  { GUINT_TO_POINTER (0x06F6), "/sixpersian" },
  +  { GUINT_TO_POINTER (0x2175), "/sixroman" },
  +  { GUINT_TO_POINTER (0x2076), "/sixsuperior" },
  +  { GUINT_TO_POINTER (0x246F), "/sixteencircle" },
  +  { GUINT_TO_POINTER (0x09F9), "/sixteencurrencydenominatorbengali" },
  +  { GUINT_TO_POINTER (0x2483), "/sixteenparen" },
  +  { GUINT_TO_POINTER (0x2497), "/sixteenperiod" },
  +  { GUINT_TO_POINTER (0x0E56), "/sixthai" },
  +  { GUINT_TO_POINTER (0x002F), "/slash" },
  +  { GUINT_TO_POINTER (0xFF0F), "/slashmonospace" },
  +  { GUINT_TO_POINTER (0x017F), "/slong" },
  +  { GUINT_TO_POINTER (0x1E9B), "/slongdotaccent" },
  +  { GUINT_TO_POINTER (0x263A), "/smileface" },
  +  { GUINT_TO_POINTER (0xFF53), "/smonospace" },
  +  { GUINT_TO_POINTER (0x05C3), "/sofpasuqhebrew" },
  +  { GUINT_TO_POINTER (0x00AD), "/softhyphen" },
  +  { GUINT_TO_POINTER (0x044C), "/softsigncyrillic" },
  +  { GUINT_TO_POINTER (0x305D), "/sohiragana" },
  +  { GUINT_TO_POINTER (0x30BD), "/sokatakana" },
  +  { GUINT_TO_POINTER (0xFF7F), "/sokatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x0338), "/soliduslongoverlaycmb" },
  +  { GUINT_TO_POINTER (0x0337), "/solidusshortoverlaycmb" },
  +  { GUINT_TO_POINTER (0x0E29), "/sorusithai" },
  +  { GUINT_TO_POINTER (0x0E28), "/sosalathai" },
  +  { GUINT_TO_POINTER (0x0E0B), "/sosothai" },
  +  { GUINT_TO_POINTER (0x0E2A), "/sosuathai" },
  +  { GUINT_TO_POINTER (0x0020), "/space" },
  +  { GUINT_TO_POINTER (0x2660), "/spade" },
  +  { GUINT_TO_POINTER (0x2660), "/spadesuitblack" },
  +  { GUINT_TO_POINTER (0x2664), "/spadesuitwhite" },
  +  { GUINT_TO_POINTER (0x24AE), "/sparen" },
  +  { GUINT_TO_POINTER (0x033B), "/squarebelowcmb" },
  +  { GUINT_TO_POINTER (0x33C4), "/squarecc" },
  +  { GUINT_TO_POINTER (0x339D), "/squarecm" },
  +  { GUINT_TO_POINTER (0x25A9), "/squarediagonalcrosshatchfill" },
  +  { GUINT_TO_POINTER (0x25A4), "/squarehorizontalfill" },
  +  { GUINT_TO_POINTER (0x338F), "/squarekg" },
  +  { GUINT_TO_POINTER (0x339E), "/squarekm" },
  +  { GUINT_TO_POINTER (0x33CE), "/squarekmcapital" },
  +  { GUINT_TO_POINTER (0x33D1), "/squareln" },
  +  { GUINT_TO_POINTER (0x33D2), "/squarelog" },
  +  { GUINT_TO_POINTER (0x338E), "/squaremg" },
  +  { GUINT_TO_POINTER (0x33D5), "/squaremil" },
  +  { GUINT_TO_POINTER (0x339C), "/squaremm" },
  +  { GUINT_TO_POINTER (0x33A1), "/squaremsquared" },
  +  { GUINT_TO_POINTER (0x25A6), "/squareorthogonalcrosshatchfill" },
  +  { GUINT_TO_POINTER (0x25A7), "/squareupperlefttolowerrightfill" },
  +  { GUINT_TO_POINTER (0x25A8), "/squareupperrighttolowerleftfill" },
  +  { GUINT_TO_POINTER (0x25A5), "/squareverticalfill" },
  +  { GUINT_TO_POINTER (0x25A3), "/squarewhitewithsmallblack" },
  +  { GUINT_TO_POINTER (0x33DB), "/srsquare" },
  +  { GUINT_TO_POINTER (0x09B7), "/ssabengali" },
  +  { GUINT_TO_POINTER (0x0937), "/ssadeva" },
  +  { GUINT_TO_POINTER (0x0AB7), "/ssagujarati" },
  +  { GUINT_TO_POINTER (0x3149), "/ssangcieuckorean" },
  +  { GUINT_TO_POINTER (0x3185), "/ssanghieuhkorean" },
  +  { GUINT_TO_POINTER (0x3180), "/ssangieungkorean" },
  +  { GUINT_TO_POINTER (0x3132), "/ssangkiyeokkorean" },
  +  { GUINT_TO_POINTER (0x3165), "/ssangnieunkorean" },
  +  { GUINT_TO_POINTER (0x3143), "/ssangpieupkorean" },
  +  { GUINT_TO_POINTER (0x3146), "/ssangsioskorean" },
  +  { GUINT_TO_POINTER (0x3138), "/ssangtikeutkorean" },
  +  { GUINT_TO_POINTER (0xF6F2), "/ssuperior" },
  +  { GUINT_TO_POINTER (0x00A3), "/sterling" },
  +  { GUINT_TO_POINTER (0xFFE1), "/sterlingmonospace" },
  +  { GUINT_TO_POINTER (0x0336), "/strokelongoverlaycmb" },
  +  { GUINT_TO_POINTER (0x0335), "/strokeshortoverlaycmb" },
  +  { GUINT_TO_POINTER (0x2282), "/subset" },
  +  { GUINT_TO_POINTER (0x228A), "/subsetnotequal" },
  +  { GUINT_TO_POINTER (0x2286), "/subsetorequal" },
  +  { GUINT_TO_POINTER (0x227B), "/succeeds" },
  +  { GUINT_TO_POINTER (0x220B), "/suchthat" },
  +  { GUINT_TO_POINTER (0x3059), "/suhiragana" },
  +  { GUINT_TO_POINTER (0x30B9), "/sukatakana" },
  +  { GUINT_TO_POINTER (0xFF7D), "/sukatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x0652), "/sukunarabic" },
  +  { GUINT_TO_POINTER (0x2211), "/summation" },
  +  { GUINT_TO_POINTER (0x263C), "/sun" },
  +  { GUINT_TO_POINTER (0x2283), "/superset" },
  +  { GUINT_TO_POINTER (0x228B), "/supersetnotequal" },
  +  { GUINT_TO_POINTER (0x2287), "/supersetorequal" },
  +  { GUINT_TO_POINTER (0x33DC), "/svsquare" },
  +  { GUINT_TO_POINTER (0x337C), "/syouwaerasquare" },
  +  { GUINT_TO_POINTER (0x0074), "/t" },
  +  { GUINT_TO_POINTER (0x09A4), "/tabengali" },
  +  { GUINT_TO_POINTER (0x22A4), "/tackdown" },
  +  { GUINT_TO_POINTER (0x22A3), "/tackleft" },
  +  { GUINT_TO_POINTER (0x0924), "/tadeva" },
  +  { GUINT_TO_POINTER (0x0AA4), "/tagujarati" },
  +  { GUINT_TO_POINTER (0x0A24), "/tagurmukhi" },
  +  { GUINT_TO_POINTER (0x0637), "/taharabic" },
  +  { GUINT_TO_POINTER (0xFEC2), "/tahfinalarabic" },
  +  { GUINT_TO_POINTER (0xFEC3), "/tahinitialarabic" },
  +  { GUINT_TO_POINTER (0x305F), "/tahiragana" },
  +  { GUINT_TO_POINTER (0xFEC4), "/tahmedialarabic" },
  +  { GUINT_TO_POINTER (0x337D), "/taisyouerasquare" },
  +  { GUINT_TO_POINTER (0x30BF), "/takatakana" },
  +  { GUINT_TO_POINTER (0xFF80), "/takatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x0640), "/tatweelarabic" },
  +  { GUINT_TO_POINTER (0x03C4), "/tau" },
  +  { GUINT_TO_POINTER (0x05EA), "/tav" },
  +  { GUINT_TO_POINTER (0xFB4A), "/tavdages" },
  +  { GUINT_TO_POINTER (0xFB4A), "/tavdagesh" },
  +  { GUINT_TO_POINTER (0xFB4A), "/tavdageshhebrew" },
  +  { GUINT_TO_POINTER (0x05EA), "/tavhebrew" },
  +  { GUINT_TO_POINTER (0x0167), "/tbar" },
  +  { GUINT_TO_POINTER (0x310A), "/tbopomofo" },
  +  { GUINT_TO_POINTER (0x0165), "/tcaron" },
  +  { GUINT_TO_POINTER (0x02A8), "/tccurl" },
  +  { GUINT_TO_POINTER (0x0163), "/tcedilla" },
  +  { GUINT_TO_POINTER (0x0686), "/tcheharabic" },
  +  { GUINT_TO_POINTER (0xFB7B), "/tchehfinalarabic" },
  +  { GUINT_TO_POINTER (0xFB7C), "/tchehinitialarabic" },
  +  { GUINT_TO_POINTER (0xFB7D), "/tchehmedialarabic" },
  +  { GUINT_TO_POINTER (0xFB7C), "/tchehmeeminitialarabic" },
  +  { GUINT_TO_POINTER (0xFEE4), "/tchehmeeminitialarabic" },
  +  { GUINT_TO_POINTER (0x24E3), "/tcircle" },
  +  { GUINT_TO_POINTER (0x1E71), "/tcircumflexbelow" },
  +  { GUINT_TO_POINTER (0x0163), "/tcommaaccent" },
  +  { GUINT_TO_POINTER (0x1E97), "/tdieresis" },
  +  { GUINT_TO_POINTER (0x1E6B), "/tdotaccent" },
  +  { GUINT_TO_POINTER (0x1E6D), "/tdotbelow" },
  +  { GUINT_TO_POINTER (0x0442), "/tecyrillic" },
  +  { GUINT_TO_POINTER (0x04AD), "/tedescendercyrillic" },
  +  { GUINT_TO_POINTER (0x062A), "/teharabic" },
  +  { GUINT_TO_POINTER (0xFE96), "/tehfinalarabic" },
  +  { GUINT_TO_POINTER (0xFCA2), "/tehhahinitialarabic" },
  +  { GUINT_TO_POINTER (0xFC0C), "/tehhahisolatedarabic" },
  +  { GUINT_TO_POINTER (0xFE97), "/tehinitialarabic" },
  +  { GUINT_TO_POINTER (0x3066), "/tehiragana" },
  +  { GUINT_TO_POINTER (0xFCA1), "/tehjeeminitialarabic" },
  +  { GUINT_TO_POINTER (0xFC0B), "/tehjeemisolatedarabic" },
  +  { GUINT_TO_POINTER (0x0629), "/tehmarbutaarabic" },
  +  { GUINT_TO_POINTER (0xFE94), "/tehmarbutafinalarabic" },
  +  { GUINT_TO_POINTER (0xFE98), "/tehmedialarabic" },
  +  { GUINT_TO_POINTER (0xFCA4), "/tehmeeminitialarabic" },
  +  { GUINT_TO_POINTER (0xFC0E), "/tehmeemisolatedarabic" },
  +  { GUINT_TO_POINTER (0xFC73), "/tehnoonfinalarabic" },
  +  { GUINT_TO_POINTER (0x30C6), "/tekatakana" },
  +  { GUINT_TO_POINTER (0xFF83), "/tekatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x2121), "/telephone" },
  +  { GUINT_TO_POINTER (0x260E), "/telephoneblack" },
  +  { GUINT_TO_POINTER (0x05A0), "/telishagedolahebrew" },
  +  { GUINT_TO_POINTER (0x05A9), "/telishaqetanahebrew" },
  +  { GUINT_TO_POINTER (0x2469), "/tencircle" },
  +  { GUINT_TO_POINTER (0x3229), "/tenideographicparen" },
  +  { GUINT_TO_POINTER (0x247D), "/tenparen" },
  +  { GUINT_TO_POINTER (0x2491), "/tenperiod" },
  +  { GUINT_TO_POINTER (0x2179), "/tenroman" },
  +  { GUINT_TO_POINTER (0x02A7), "/tesh" },
  +  { GUINT_TO_POINTER (0x05D8), "/tet" },
  +  { GUINT_TO_POINTER (0xFB38), "/tetdagesh" },
  +  { GUINT_TO_POINTER (0xFB38), "/tetdageshhebrew" },
  +  { GUINT_TO_POINTER (0x05D8), "/tethebrew" },
  +  { GUINT_TO_POINTER (0x04B5), "/tetsecyrillic" },
  +  { GUINT_TO_POINTER (0x059B), "/tevirhebrew" },
  +  { GUINT_TO_POINTER (0x059B), "/tevirlefthebrew" },
  +  { GUINT_TO_POINTER (0x09A5), "/thabengali" },
  +  { GUINT_TO_POINTER (0x0925), "/thadeva" },
  +  { GUINT_TO_POINTER (0x0AA5), "/thagujarati" },
  +  { GUINT_TO_POINTER (0x0A25), "/thagurmukhi" },
  +  { GUINT_TO_POINTER (0x0630), "/thalarabic" },
  +  { GUINT_TO_POINTER (0xFEAC), "/thalfinalarabic" },
  +  { GUINT_TO_POINTER (0xF898), "/thanthakhatlowleftthai" },
  +  { GUINT_TO_POINTER (0xF897), "/thanthakhatlowrightthai" },
  +  { GUINT_TO_POINTER (0x0E4C), "/thanthakhatthai" },
  +  { GUINT_TO_POINTER (0xF896), "/thanthakhatupperleftthai" },
  +  { GUINT_TO_POINTER (0x062B), "/theharabic" },
  +  { GUINT_TO_POINTER (0xFE9A), "/thehfinalarabic" },
  +  { GUINT_TO_POINTER (0xFE9B), "/thehinitialarabic" },
  +  { GUINT_TO_POINTER (0xFE9C), "/thehmedialarabic" },
  +  { GUINT_TO_POINTER (0x2203), "/thereexists" },
  +  { GUINT_TO_POINTER (0x2234), "/therefore" },
  +  { GUINT_TO_POINTER (0x03B8), "/theta" },
  +  { GUINT_TO_POINTER (0x03D1), "/theta1" },
  +  { GUINT_TO_POINTER (0x03D1), "/thetasymbolgreek" },
  +  { GUINT_TO_POINTER (0x3279), "/thieuthacirclekorean" },
  +  { GUINT_TO_POINTER (0x3219), "/thieuthaparenkorean" },
  +  { GUINT_TO_POINTER (0x326B), "/thieuthcirclekorean" },
  +  { GUINT_TO_POINTER (0x314C), "/thieuthkorean" },
  +  { GUINT_TO_POINTER (0x320B), "/thieuthparenkorean" },
  +  { GUINT_TO_POINTER (0x246C), "/thirteencircle" },
  +  { GUINT_TO_POINTER (0x2480), "/thirteenparen" },
  +  { GUINT_TO_POINTER (0x2494), "/thirteenperiod" },
  +  { GUINT_TO_POINTER (0x0E11), "/thonangmonthothai" },
  +  { GUINT_TO_POINTER (0x01AD), "/thook" },
  +  { GUINT_TO_POINTER (0x0E12), "/thophuthaothai" },
  +  { GUINT_TO_POINTER (0x00FE), "/thorn" },
  +  { GUINT_TO_POINTER (0x0E17), "/thothahanthai" },
  +  { GUINT_TO_POINTER (0x0E10), "/thothanthai" },
  +  { GUINT_TO_POINTER (0x0E18), "/thothongthai" },
  +  { GUINT_TO_POINTER (0x0E16), "/thothungthai" },
  +  { GUINT_TO_POINTER (0x0482), "/thousandcyrillic" },
  +  { GUINT_TO_POINTER (0x066C), "/thousandsseparatorarabic" },
  +  { GUINT_TO_POINTER (0x066C), "/thousandsseparatorpersian" },
  +  { GUINT_TO_POINTER (0x0033), "/three" },
  +  { GUINT_TO_POINTER (0x0663), "/threearabic" },
  +  { GUINT_TO_POINTER (0x09E9), "/threebengali" },
  +  { GUINT_TO_POINTER (0x2462), "/threecircle" },
  +  { GUINT_TO_POINTER (0x278C), "/threecircleinversesansserif" },
  +  { GUINT_TO_POINTER (0x0969), "/threedeva" },
  +  { GUINT_TO_POINTER (0x215C), "/threeeighths" },
  +  { GUINT_TO_POINTER (0x0AE9), "/threegujarati" },
  +  { GUINT_TO_POINTER (0x0A69), "/threegurmukhi" },
  +  { GUINT_TO_POINTER (0x0663), "/threehackarabic" },
  +  { GUINT_TO_POINTER (0x3023), "/threehangzhou" },
  +  { GUINT_TO_POINTER (0x3222), "/threeideographicparen" },
  +  { GUINT_TO_POINTER (0x2083), "/threeinferior" },
  +  { GUINT_TO_POINTER (0xFF13), "/threemonospace" },
  +  { GUINT_TO_POINTER (0x09F6), "/threenumeratorbengali" },
  +  { GUINT_TO_POINTER (0xF733), "/threeoldstyle" },
  +  { GUINT_TO_POINTER (0x2476), "/threeparen" },
  +  { GUINT_TO_POINTER (0x248A), "/threeperiod" },
  +  { GUINT_TO_POINTER (0x06F3), "/threepersian" },
  +  { GUINT_TO_POINTER (0x00BE), "/threequarters" },
  +  { GUINT_TO_POINTER (0xF6DE), "/threequartersemdash" },
  +  { GUINT_TO_POINTER (0x2172), "/threeroman" },
  +  { GUINT_TO_POINTER (0x00B3), "/threesuperior" },
  +  { GUINT_TO_POINTER (0x0E53), "/threethai" },
  +  { GUINT_TO_POINTER (0x3394), "/thzsquare" },
  +  { GUINT_TO_POINTER (0x3061), "/tihiragana" },
  +  { GUINT_TO_POINTER (0x30C1), "/tikatakana" },
  +  { GUINT_TO_POINTER (0xFF81), "/tikatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x3270), "/tikeutacirclekorean" },
  +  { GUINT_TO_POINTER (0x3210), "/tikeutaparenkorean" },
  +  { GUINT_TO_POINTER (0x3262), "/tikeutcirclekorean" },
  +  { GUINT_TO_POINTER (0x3137), "/tikeutkorean" },
  +  { GUINT_TO_POINTER (0x3202), "/tikeutparenkorean" },
  +  { GUINT_TO_POINTER (0x02DC), "/tilde" },
  +  { GUINT_TO_POINTER (0x0330), "/tildebelowcmb" },
  +  { GUINT_TO_POINTER (0x0303), "/tildecmb" },
  +  { GUINT_TO_POINTER (0x0303), "/tildecomb" },
  +  { GUINT_TO_POINTER (0x0360), "/tildedoublecmb" },
  +  { GUINT_TO_POINTER (0x223C), "/tildeoperator" },
  +  { GUINT_TO_POINTER (0x0334), "/tildeoverlaycmb" },
  +  { GUINT_TO_POINTER (0x033E), "/tildeverticalcmb" },
  +  { GUINT_TO_POINTER (0x2297), "/timescircle" },
  +  { GUINT_TO_POINTER (0x0596), "/tipehahebrew" },
  +  { GUINT_TO_POINTER (0x0596), "/tipehalefthebrew" },
  +  { GUINT_TO_POINTER (0x0A70), "/tippigurmukhi" },
  +  { GUINT_TO_POINTER (0x0483), "/titlocyrilliccmb" },
  +  { GUINT_TO_POINTER (0x057F), "/tiwnarmenian" },
  +  { GUINT_TO_POINTER (0x1E6F), "/tlinebelow" },
  +  { GUINT_TO_POINTER (0xFF54), "/tmonospace" },
  +  { GUINT_TO_POINTER (0x0569), "/toarmenian" },
  +  { GUINT_TO_POINTER (0x3068), "/tohiragana" },
  +  { GUINT_TO_POINTER (0x30C8), "/tokatakana" },
  +  { GUINT_TO_POINTER (0xFF84), "/tokatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x02E5), "/tonebarextrahighmod" },
  +  { GUINT_TO_POINTER (0x02E9), "/tonebarextralowmod" },
  +  { GUINT_TO_POINTER (0x02E6), "/tonebarhighmod" },
  +  { GUINT_TO_POINTER (0x02E8), "/tonebarlowmod" },
  +  { GUINT_TO_POINTER (0x02E7), "/tonebarmidmod" },
  +  { GUINT_TO_POINTER (0x01BD), "/tonefive" },
  +  { GUINT_TO_POINTER (0x0185), "/tonesix" },
  +  { GUINT_TO_POINTER (0x01A8), "/tonetwo" },
  +  { GUINT_TO_POINTER (0x0384), "/tonos" },
  +  { GUINT_TO_POINTER (0x3327), "/tonsquare" },
  +  { GUINT_TO_POINTER (0x0E0F), "/topatakthai" },
  +  { GUINT_TO_POINTER (0x3014), "/tortoiseshellbracketleft" },
  +  { GUINT_TO_POINTER (0xFE5D), "/tortoiseshellbracketleftsmall" },
  +  { GUINT_TO_POINTER (0xFE39), "/tortoiseshellbracketleftvertical" },
  +  { GUINT_TO_POINTER (0x3015), "/tortoiseshellbracketright" },
  +  { GUINT_TO_POINTER (0xFE5E), "/tortoiseshellbracketrightsmall" },
  +  { GUINT_TO_POINTER (0xFE3A), "/tortoiseshellbracketrightvertical" },
  +  { GUINT_TO_POINTER (0x0E15), "/totaothai" },
  +  { GUINT_TO_POINTER (0x01AB), "/tpalatalhook" },
  +  { GUINT_TO_POINTER (0x24AF), "/tparen" },
  +  { GUINT_TO_POINTER (0x2122), "/trademark" },
  +  { GUINT_TO_POINTER (0xF8EA), "/trademarksans" },
  +  { GUINT_TO_POINTER (0xF6DB), "/trademarkserif" },
  +  { GUINT_TO_POINTER (0x0288), "/tretroflexhook" },
  +  { GUINT_TO_POINTER (0x25BC), "/triagdn" },
  +  { GUINT_TO_POINTER (0x25C4), "/triaglf" },
  +  { GUINT_TO_POINTER (0x25BA), "/triagrt" },
  +  { GUINT_TO_POINTER (0x25B2), "/triagup" },
  +  { GUINT_TO_POINTER (0x02A6), "/ts" },
  +  { GUINT_TO_POINTER (0x05E6), "/tsadi" },
  +  { GUINT_TO_POINTER (0xFB46), "/tsadidagesh" },
  +  { GUINT_TO_POINTER (0xFB46), "/tsadidageshhebrew" },
  +  { GUINT_TO_POINTER (0x05E6), "/tsadihebrew" },
  +  { GUINT_TO_POINTER (0x0446), "/tsecyrillic" },
  +  { GUINT_TO_POINTER (0x05B5), "/tsere" },
  +  { GUINT_TO_POINTER (0x05B5), "/tsere12" },
  +  { GUINT_TO_POINTER (0x05B5), "/tsere1e" },
  +  { GUINT_TO_POINTER (0x05B5), "/tsere2b" },
  +  { GUINT_TO_POINTER (0x05B5), "/tserehebrew" },
  +  { GUINT_TO_POINTER (0x05B5), "/tserenarrowhebrew" },
  +  { GUINT_TO_POINTER (0x05B5), "/tserequarterhebrew" },
  +  { GUINT_TO_POINTER (0x05B5), "/tserewidehebrew" },
  +  { GUINT_TO_POINTER (0x045B), "/tshecyrillic" },
  +  { GUINT_TO_POINTER (0xF6F3), "/tsuperior" },
  +  { GUINT_TO_POINTER (0x099F), "/ttabengali" },
  +  { GUINT_TO_POINTER (0x091F), "/ttadeva" },
  +  { GUINT_TO_POINTER (0x0A9F), "/ttagujarati" },
  +  { GUINT_TO_POINTER (0x0A1F), "/ttagurmukhi" },
  +  { GUINT_TO_POINTER (0x0679), "/tteharabic" },
  +  { GUINT_TO_POINTER (0xFB67), "/ttehfinalarabic" },
  +  { GUINT_TO_POINTER (0xFB68), "/ttehinitialarabic" },
  +  { GUINT_TO_POINTER (0xFB69), "/ttehmedialarabic" },
  +  { GUINT_TO_POINTER (0x09A0), "/tthabengali" },
  +  { GUINT_TO_POINTER (0x0920), "/tthadeva" },
  +  { GUINT_TO_POINTER (0x0AA0), "/tthagujarati" },
  +  { GUINT_TO_POINTER (0x0A20), "/tthagurmukhi" },
  +  { GUINT_TO_POINTER (0x0287), "/tturned" },
  +  { GUINT_TO_POINTER (0x3064), "/tuhiragana" },
  +  { GUINT_TO_POINTER (0x30C4), "/tukatakana" },
  +  { GUINT_TO_POINTER (0xFF82), "/tukatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x3063), "/tusmallhiragana" },
  +  { GUINT_TO_POINTER (0x30C3), "/tusmallkatakana" },
  +  { GUINT_TO_POINTER (0xFF6F), "/tusmallkatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x246B), "/twelvecircle" },
  +  { GUINT_TO_POINTER (0x247F), "/twelveparen" },
  +  { GUINT_TO_POINTER (0x2493), "/twelveperiod" },
  +  { GUINT_TO_POINTER (0x217B), "/twelveroman" },
  +  { GUINT_TO_POINTER (0x2473), "/twentycircle" },
  +  { GUINT_TO_POINTER (0x5344), "/twentyhangzhou" },
  +  { GUINT_TO_POINTER (0x2487), "/twentyparen" },
  +  { GUINT_TO_POINTER (0x249B), "/twentyperiod" },
  +  { GUINT_TO_POINTER (0x0032), "/two" },
  +  { GUINT_TO_POINTER (0x0662), "/twoarabic" },
  +  { GUINT_TO_POINTER (0x09E8), "/twobengali" },
  +  { GUINT_TO_POINTER (0x2461), "/twocircle" },
  +  { GUINT_TO_POINTER (0x278B), "/twocircleinversesansserif" },
  +  { GUINT_TO_POINTER (0x0968), "/twodeva" },
  +  { GUINT_TO_POINTER (0x2025), "/twodotenleader" },
  +  { GUINT_TO_POINTER (0x2025), "/twodotleader" },
  +  { GUINT_TO_POINTER (0xFE30), "/twodotleadervertical" },
  +  { GUINT_TO_POINTER (0x0AE8), "/twogujarati" },
  +  { GUINT_TO_POINTER (0x0A68), "/twogurmukhi" },
  +  { GUINT_TO_POINTER (0x0662), "/twohackarabic" },
  +  { GUINT_TO_POINTER (0x3022), "/twohangzhou" },
  +  { GUINT_TO_POINTER (0x3221), "/twoideographicparen" },
  +  { GUINT_TO_POINTER (0x2082), "/twoinferior" },
  +  { GUINT_TO_POINTER (0xFF12), "/twomonospace" },
  +  { GUINT_TO_POINTER (0x09F5), "/twonumeratorbengali" },
  +  { GUINT_TO_POINTER (0xF732), "/twooldstyle" },
  +  { GUINT_TO_POINTER (0x2475), "/twoparen" },
  +  { GUINT_TO_POINTER (0x2489), "/twoperiod" },
  +  { GUINT_TO_POINTER (0x06F2), "/twopersian" },
  +  { GUINT_TO_POINTER (0x2171), "/tworoman" },
  +  { GUINT_TO_POINTER (0x01BB), "/twostroke" },
  +  { GUINT_TO_POINTER (0x00B2), "/twosuperior" },
  +  { GUINT_TO_POINTER (0x0E52), "/twothai" },
  +  { GUINT_TO_POINTER (0x2154), "/twothirds" },
  +  { GUINT_TO_POINTER (0x0075), "/u" },
  +  { GUINT_TO_POINTER (0x00FA), "/uacute" },
  +  { GUINT_TO_POINTER (0x0289), "/ubar" },
  +  { GUINT_TO_POINTER (0x0989), "/ubengali" },
  +  { GUINT_TO_POINTER (0x3128), "/ubopomofo" },
  +  { GUINT_TO_POINTER (0x016D), "/ubreve" },
  +  { GUINT_TO_POINTER (0x01D4), "/ucaron" },
  +  { GUINT_TO_POINTER (0x24E4), "/ucircle" },
  +  { GUINT_TO_POINTER (0x00FB), "/ucircumflex" },
  +  { GUINT_TO_POINTER (0x1E77), "/ucircumflexbelow" },
  +  { GUINT_TO_POINTER (0x0443), "/ucyrillic" },
  +  { GUINT_TO_POINTER (0x0951), "/udattadeva" },
  +  { GUINT_TO_POINTER (0x0171), "/udblacute" },
  +  { GUINT_TO_POINTER (0x0215), "/udblgrave" },
  +  { GUINT_TO_POINTER (0x0909), "/udeva" },
  +  { GUINT_TO_POINTER (0x00FC), "/udieresis" },
  +  { GUINT_TO_POINTER (0x01D8), "/udieresisacute" },
  +  { GUINT_TO_POINTER (0x1E73), "/udieresisbelow" },
  +  { GUINT_TO_POINTER (0x01DA), "/udieresiscaron" },
  +  { GUINT_TO_POINTER (0x04F1), "/udieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x01DC), "/udieresisgrave" },
  +  { GUINT_TO_POINTER (0x01D6), "/udieresismacron" },
  +  { GUINT_TO_POINTER (0x1EE5), "/udotbelow" },
  +  { GUINT_TO_POINTER (0x00F9), "/ugrave" },
  +  { GUINT_TO_POINTER (0x0A89), "/ugujarati" },
  +  { GUINT_TO_POINTER (0x0A09), "/ugurmukhi" },
  +  { GUINT_TO_POINTER (0x3046), "/uhiragana" },
  +  { GUINT_TO_POINTER (0x1EE7), "/uhookabove" },
  +  { GUINT_TO_POINTER (0x01B0), "/uhorn" },
  +  { GUINT_TO_POINTER (0x1EE9), "/uhornacute" },
  +  { GUINT_TO_POINTER (0x1EF1), "/uhorndotbelow" },
  +  { GUINT_TO_POINTER (0x1EEB), "/uhorngrave" },
  +  { GUINT_TO_POINTER (0x1EED), "/uhornhookabove" },
  +  { GUINT_TO_POINTER (0x1EEF), "/uhorntilde" },
  +  { GUINT_TO_POINTER (0x0171), "/uhungarumlaut" },
  +  { GUINT_TO_POINTER (0x04F3), "/uhungarumlautcyrillic" },
  +  { GUINT_TO_POINTER (0x0217), "/uinvertedbreve" },
  +  { GUINT_TO_POINTER (0x30A6), "/ukatakana" },
  +  { GUINT_TO_POINTER (0xFF73), "/ukatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x0479), "/ukcyrillic" },
  +  { GUINT_TO_POINTER (0x315C), "/ukorean" },
  +  { GUINT_TO_POINTER (0x016B), "/umacron" },
  +  { GUINT_TO_POINTER (0x04EF), "/umacroncyrillic" },
  +  { GUINT_TO_POINTER (0x1E7B), "/umacrondieresis" },
  +  { GUINT_TO_POINTER (0x0A41), "/umatragurmukhi" },
  +  { GUINT_TO_POINTER (0xFF55), "/umonospace" },
  +  { GUINT_TO_POINTER (0x005F), "/underscore" },
  +  { GUINT_TO_POINTER (0x2017), "/underscoredbl" },
  +  { GUINT_TO_POINTER (0xFF3F), "/underscoremonospace" },
  +  { GUINT_TO_POINTER (0xFE33), "/underscorevertical" },
  +  { GUINT_TO_POINTER (0xFE4F), "/underscorewavy" },
  +  { GUINT_TO_POINTER (0x222A), "/union" },
  +  { GUINT_TO_POINTER (0x2200), "/universal" },
  +  { GUINT_TO_POINTER (0x0173), "/uogonek" },
  +  { GUINT_TO_POINTER (0x24B0), "/uparen" },
  +  { GUINT_TO_POINTER (0x2580), "/upblock" },
  +  { GUINT_TO_POINTER (0x05C4), "/upperdothebrew" },
  +  { GUINT_TO_POINTER (0x03C5), "/upsilon" },
  +  { GUINT_TO_POINTER (0x03CB), "/upsilondieresis" },
  +  { GUINT_TO_POINTER (0x03B0), "/upsilondieresistonos" },
  +  { GUINT_TO_POINTER (0x028A), "/upsilonlatin" },
  +  { GUINT_TO_POINTER (0x03CD), "/upsilontonos" },
  +  { GUINT_TO_POINTER (0x031D), "/uptackbelowcmb" },
  +  { GUINT_TO_POINTER (0x02D4), "/uptackmod" },
  +  { GUINT_TO_POINTER (0x0A73), "/uragurmukhi" },
  +  { GUINT_TO_POINTER (0x016F), "/uring" },
  +  { GUINT_TO_POINTER (0x045E), "/ushortcyrillic" },
  +  { GUINT_TO_POINTER (0x3045), "/usmallhiragana" },
  +  { GUINT_TO_POINTER (0x30A5), "/usmallkatakana" },
  +  { GUINT_TO_POINTER (0xFF69), "/usmallkatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x04AF), "/ustraightcyrillic" },
  +  { GUINT_TO_POINTER (0x04B1), "/ustraightstrokecyrillic" },
  +  { GUINT_TO_POINTER (0x0169), "/utilde" },
  +  { GUINT_TO_POINTER (0x1E79), "/utildeacute" },
  +  { GUINT_TO_POINTER (0x1E75), "/utildebelow" },
  +  { GUINT_TO_POINTER (0x098A), "/uubengali" },
  +  { GUINT_TO_POINTER (0x090A), "/uudeva" },
  +  { GUINT_TO_POINTER (0x0A8A), "/uugujarati" },
  +  { GUINT_TO_POINTER (0x0A0A), "/uugurmukhi" },
  +  { GUINT_TO_POINTER (0x0A42), "/uumatragurmukhi" },
  +  { GUINT_TO_POINTER (0x09C2), "/uuvowelsignbengali" },
  +  { GUINT_TO_POINTER (0x0942), "/uuvowelsigndeva" },
  +  { GUINT_TO_POINTER (0x0AC2), "/uuvowelsigngujarati" },
  +  { GUINT_TO_POINTER (0x09C1), "/uvowelsignbengali" },
  +  { GUINT_TO_POINTER (0x0941), "/uvowelsigndeva" },
  +  { GUINT_TO_POINTER (0x0AC1), "/uvowelsigngujarati" },
  +  { GUINT_TO_POINTER (0x0076), "/v" },
  +  { GUINT_TO_POINTER (0x0935), "/vadeva" },
  +  { GUINT_TO_POINTER (0x0AB5), "/vagujarati" },
  +  { GUINT_TO_POINTER (0x0A35), "/vagurmukhi" },
  +  { GUINT_TO_POINTER (0x30F7), "/vakatakana" },
  +  { GUINT_TO_POINTER (0x05D5), "/vav" },
  +  { GUINT_TO_POINTER (0xFB35), "/vavdagesh" },
  +  { GUINT_TO_POINTER (0xFB35), "/vavdagesh65" },
  +  { GUINT_TO_POINTER (0xFB35), "/vavdageshhebrew" },
  +  { GUINT_TO_POINTER (0x05D5), "/vavhebrew" },
  +  { GUINT_TO_POINTER (0xFB4B), "/vavholam" },
  +  { GUINT_TO_POINTER (0xFB4B), "/vavholamhebrew" },
  +  { GUINT_TO_POINTER (0x05F0), "/vavvavhebrew" },
  +  { GUINT_TO_POINTER (0x05F1), "/vavyodhebrew" },
  +  { GUINT_TO_POINTER (0x24E5), "/vcircle" },
  +  { GUINT_TO_POINTER (0x1E7F), "/vdotbelow" },
  +  { GUINT_TO_POINTER (0x0432), "/vecyrillic" },
  +  { GUINT_TO_POINTER (0x06A4), "/veharabic" },
  +  { GUINT_TO_POINTER (0xFB6B), "/vehfinalarabic" },
  +  { GUINT_TO_POINTER (0xFB6C), "/vehinitialarabic" },
  +  { GUINT_TO_POINTER (0xFB6D), "/vehmedialarabic" },
  +  { GUINT_TO_POINTER (0x30F9), "/vekatakana" },
  +  { GUINT_TO_POINTER (0x2640), "/venus" },
  +  { GUINT_TO_POINTER (0x007C), "/verticalbar" },
  +  { GUINT_TO_POINTER (0x030D), "/verticallineabovecmb" },
  +  { GUINT_TO_POINTER (0x0329), "/verticallinebelowcmb" },
  +  { GUINT_TO_POINTER (0x02CC), "/verticallinelowmod" },
  +  { GUINT_TO_POINTER (0x02C8), "/verticallinemod" },
  +  { GUINT_TO_POINTER (0x057E), "/vewarmenian" },
  +  { GUINT_TO_POINTER (0x028B), "/vhook" },
  +  { GUINT_TO_POINTER (0x30F8), "/vikatakana" },
  +  { GUINT_TO_POINTER (0x09CD), "/viramabengali" },
  +  { GUINT_TO_POINTER (0x094D), "/viramadeva" },
  +  { GUINT_TO_POINTER (0x0ACD), "/viramagujarati" },
  +  { GUINT_TO_POINTER (0x0983), "/visargabengali" },
  +  { GUINT_TO_POINTER (0x0903), "/visargadeva" },
  +  { GUINT_TO_POINTER (0x0A83), "/visargagujarati" },
  +  { GUINT_TO_POINTER (0xFF56), "/vmonospace" },
  +  { GUINT_TO_POINTER (0x0578), "/voarmenian" },
  +  { GUINT_TO_POINTER (0x309E), "/voicediterationhiragana" },
  +  { GUINT_TO_POINTER (0x30FE), "/voicediterationkatakana" },
  +  { GUINT_TO_POINTER (0x309B), "/voicedmarkkana" },
  +  { GUINT_TO_POINTER (0xFF9E), "/voicedmarkkanahalfwidth" },
  +  { GUINT_TO_POINTER (0x30FA), "/vokatakana" },
  +  { GUINT_TO_POINTER (0x24B1), "/vparen" },
  +  { GUINT_TO_POINTER (0x1E7D), "/vtilde" },
  +  { GUINT_TO_POINTER (0x028C), "/vturned" },
  +  { GUINT_TO_POINTER (0x3094), "/vuhiragana" },
  +  { GUINT_TO_POINTER (0x30F4), "/vukatakana" },
  +  { GUINT_TO_POINTER (0x0077), "/w" },
  +  { GUINT_TO_POINTER (0x1E83), "/wacute" },
  +  { GUINT_TO_POINTER (0x3159), "/waekorean" },
  +  { GUINT_TO_POINTER (0x308F), "/wahiragana" },
  +  { GUINT_TO_POINTER (0x30EF), "/wakatakana" },
  +  { GUINT_TO_POINTER (0xFF9C), "/wakatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x3158), "/wakorean" },
  +  { GUINT_TO_POINTER (0x308E), "/wasmallhiragana" },
  +  { GUINT_TO_POINTER (0x30EE), "/wasmallkatakana" },
  +  { GUINT_TO_POINTER (0x3357), "/wattosquare" },
  +  { GUINT_TO_POINTER (0x301C), "/wavedash" },
  +  { GUINT_TO_POINTER (0xFE34), "/wavyunderscorevertical" },
  +  { GUINT_TO_POINTER (0x0648), "/wawarabic" },
  +  { GUINT_TO_POINTER (0xFEEE), "/wawfinalarabic" },
  +  { GUINT_TO_POINTER (0x0624), "/wawhamzaabovearabic" },
  +  { GUINT_TO_POINTER (0xFE86), "/wawhamzaabovefinalarabic" },
  +  { GUINT_TO_POINTER (0x33DD), "/wbsquare" },
  +  { GUINT_TO_POINTER (0x24E6), "/wcircle" },
  +  { GUINT_TO_POINTER (0x0175), "/wcircumflex" },
  +  { GUINT_TO_POINTER (0x1E85), "/wdieresis" },
  +  { GUINT_TO_POINTER (0x1E87), "/wdotaccent" },
  +  { GUINT_TO_POINTER (0x1E89), "/wdotbelow" },
  +  { GUINT_TO_POINTER (0x3091), "/wehiragana" },
  +  { GUINT_TO_POINTER (0x2118), "/weierstrass" },
  +  { GUINT_TO_POINTER (0x30F1), "/wekatakana" },
  +  { GUINT_TO_POINTER (0x315E), "/wekorean" },
  +  { GUINT_TO_POINTER (0x315D), "/weokorean" },
  +  { GUINT_TO_POINTER (0x1E81), "/wgrave" },
  +  { GUINT_TO_POINTER (0x25E6), "/whitebullet" },
  +  { GUINT_TO_POINTER (0x25CB), "/whitecircle" },
  +  { GUINT_TO_POINTER (0x25D9), "/whitecircleinverse" },
  +  { GUINT_TO_POINTER (0x300E), "/whitecornerbracketleft" },
  +  { GUINT_TO_POINTER (0xFE43), "/whitecornerbracketleftvertical" },
  +  { GUINT_TO_POINTER (0x300F), "/whitecornerbracketright" },
  +  { GUINT_TO_POINTER (0xFE44), "/whitecornerbracketrightvertical" },
  +  { GUINT_TO_POINTER (0x25C7), "/whitediamond" },
  +  { GUINT_TO_POINTER (0x25C8), "/whitediamondcontainingblacksmalldiamond" },
  +  { GUINT_TO_POINTER (0x25BF), "/whitedownpointingsmalltriangle" },
  +  { GUINT_TO_POINTER (0x25BD), "/whitedownpointingtriangle" },
  +  { GUINT_TO_POINTER (0x25C3), "/whiteleftpointingsmalltriangle" },
  +  { GUINT_TO_POINTER (0x25C1), "/whiteleftpointingtriangle" },
  +  { GUINT_TO_POINTER (0x3016), "/whitelenticularbracketleft" },
  +  { GUINT_TO_POINTER (0x3017), "/whitelenticularbracketright" },
  +  { GUINT_TO_POINTER (0x25B9), "/whiterightpointingsmalltriangle" },
  +  { GUINT_TO_POINTER (0x25B7), "/whiterightpointingtriangle" },
  +  { GUINT_TO_POINTER (0x25AB), "/whitesmallsquare" },
  +  { GUINT_TO_POINTER (0x263A), "/whitesmilingface" },
  +  { GUINT_TO_POINTER (0x25A1), "/whitesquare" },
  +  { GUINT_TO_POINTER (0x2606), "/whitestar" },
  +  { GUINT_TO_POINTER (0x260F), "/whitetelephone" },
  +  { GUINT_TO_POINTER (0x3018), "/whitetortoiseshellbracketleft" },
  +  { GUINT_TO_POINTER (0x3019), "/whitetortoiseshellbracketright" },
  +  { GUINT_TO_POINTER (0x25B5), "/whiteuppointingsmalltriangle" },
  +  { GUINT_TO_POINTER (0x25B3), "/whiteuppointingtriangle" },
  +  { GUINT_TO_POINTER (0x3090), "/wihiragana" },
  +  { GUINT_TO_POINTER (0x30F0), "/wikatakana" },
  +  { GUINT_TO_POINTER (0x315F), "/wikorean" },
  +  { GUINT_TO_POINTER (0xFF57), "/wmonospace" },
  +  { GUINT_TO_POINTER (0x3092), "/wohiragana" },
  +  { GUINT_TO_POINTER (0x30F2), "/wokatakana" },
  +  { GUINT_TO_POINTER (0xFF66), "/wokatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x20A9), "/won" },
  +  { GUINT_TO_POINTER (0xFFE6), "/wonmonospace" },
  +  { GUINT_TO_POINTER (0x0E27), "/wowaenthai" },
  +  { GUINT_TO_POINTER (0x24B2), "/wparen" },
  +  { GUINT_TO_POINTER (0x1E98), "/wring" },
  +  { GUINT_TO_POINTER (0x02B7), "/wsuperior" },
  +  { GUINT_TO_POINTER (0x028D), "/wturned" },
  +  { GUINT_TO_POINTER (0x01BF), "/wynn" },
  +  { GUINT_TO_POINTER (0x0078), "/x" },
  +  { GUINT_TO_POINTER (0x033D), "/xabovecmb" },
  +  { GUINT_TO_POINTER (0x3112), "/xbopomofo" },
  +  { GUINT_TO_POINTER (0x24E7), "/xcircle" },
  +  { GUINT_TO_POINTER (0x1E8D), "/xdieresis" },
  +  { GUINT_TO_POINTER (0x1E8B), "/xdotaccent" },
  +  { GUINT_TO_POINTER (0x056D), "/xeharmenian" },
  +  { GUINT_TO_POINTER (0x03BE), "/xi" },
  +  { GUINT_TO_POINTER (0xFF58), "/xmonospace" },
  +  { GUINT_TO_POINTER (0x24B3), "/xparen" },
  +  { GUINT_TO_POINTER (0x02E3), "/xsuperior" },
  +  { GUINT_TO_POINTER (0x0079), "/y" },
  +  { GUINT_TO_POINTER (0x334E), "/yaadosquare" },
  +  { GUINT_TO_POINTER (0x09AF), "/yabengali" },
  +  { GUINT_TO_POINTER (0x00FD), "/yacute" },
  +  { GUINT_TO_POINTER (0x092F), "/yadeva" },
  +  { GUINT_TO_POINTER (0x3152), "/yaekorean" },
  +  { GUINT_TO_POINTER (0x0AAF), "/yagujarati" },
  +  { GUINT_TO_POINTER (0x0A2F), "/yagurmukhi" },
  +  { GUINT_TO_POINTER (0x3084), "/yahiragana" },
  +  { GUINT_TO_POINTER (0x30E4), "/yakatakana" },
  +  { GUINT_TO_POINTER (0xFF94), "/yakatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x3151), "/yakorean" },
  +  { GUINT_TO_POINTER (0x0E4E), "/yamakkanthai" },
  +  { GUINT_TO_POINTER (0x3083), "/yasmallhiragana" },
  +  { GUINT_TO_POINTER (0x30E3), "/yasmallkatakana" },
  +  { GUINT_TO_POINTER (0xFF6C), "/yasmallkatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x0463), "/yatcyrillic" },
  +  { GUINT_TO_POINTER (0x24E8), "/ycircle" },
  +  { GUINT_TO_POINTER (0x0177), "/ycircumflex" },
  +  { GUINT_TO_POINTER (0x00FF), "/ydieresis" },
  +  { GUINT_TO_POINTER (0x1E8F), "/ydotaccent" },
  +  { GUINT_TO_POINTER (0x1EF5), "/ydotbelow" },
  +  { GUINT_TO_POINTER (0x064A), "/yeharabic" },
  +  { GUINT_TO_POINTER (0x06D2), "/yehbarreearabic" },
  +  { GUINT_TO_POINTER (0xFBAF), "/yehbarreefinalarabic" },
  +  { GUINT_TO_POINTER (0xFEF2), "/yehfinalarabic" },
  +  { GUINT_TO_POINTER (0x0626), "/yehhamzaabovearabic" },
  +  { GUINT_TO_POINTER (0xFE8A), "/yehhamzaabovefinalarabic" },
  +  { GUINT_TO_POINTER (0xFE8B), "/yehhamzaaboveinitialarabic" },
  +  { GUINT_TO_POINTER (0xFE8C), "/yehhamzaabovemedialarabic" },
  +  { GUINT_TO_POINTER (0xFEF3), "/yehinitialarabic" },
  +  { GUINT_TO_POINTER (0xFEF4), "/yehmedialarabic" },
  +  { GUINT_TO_POINTER (0xFCDD), "/yehmeeminitialarabic" },
  +  { GUINT_TO_POINTER (0xFC58), "/yehmeemisolatedarabic" },
  +  { GUINT_TO_POINTER (0xFC94), "/yehnoonfinalarabic" },
  +  { GUINT_TO_POINTER (0x06D1), "/yehthreedotsbelowarabic" },
  +  { GUINT_TO_POINTER (0x3156), "/yekorean" },
  +  { GUINT_TO_POINTER (0x00A5), "/yen" },
  +  { GUINT_TO_POINTER (0xFFE5), "/yenmonospace" },
  +  { GUINT_TO_POINTER (0x3155), "/yeokorean" },
  +  { GUINT_TO_POINTER (0x3186), "/yeorinhieuhkorean" },
  +  { GUINT_TO_POINTER (0x05AA), "/yerahbenyomohebrew" },
  +  { GUINT_TO_POINTER (0x05AA), "/yerahbenyomolefthebrew" },
  +  { GUINT_TO_POINTER (0x044B), "/yericyrillic" },
  +  { GUINT_TO_POINTER (0x04F9), "/yerudieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x3181), "/yesieungkorean" },
  +  { GUINT_TO_POINTER (0x3183), "/yesieungpansioskorean" },
  +  { GUINT_TO_POINTER (0x3182), "/yesieungsioskorean" },
  +  { GUINT_TO_POINTER (0x059A), "/yetivhebrew" },
  +  { GUINT_TO_POINTER (0x1EF3), "/ygrave" },
  +  { GUINT_TO_POINTER (0x01B4), "/yhook" },
  +  { GUINT_TO_POINTER (0x1EF7), "/yhookabove" },
  +  { GUINT_TO_POINTER (0x0575), "/yiarmenian" },
  +  { GUINT_TO_POINTER (0x0457), "/yicyrillic" },
  +  { GUINT_TO_POINTER (0x3162), "/yikorean" },
  +  { GUINT_TO_POINTER (0x262F), "/yinyang" },
  +  { GUINT_TO_POINTER (0x0582), "/yiwnarmenian" },
  +  { GUINT_TO_POINTER (0xFF59), "/ymonospace" },
  +  { GUINT_TO_POINTER (0x05D9), "/yod" },
  +  { GUINT_TO_POINTER (0xFB39), "/yoddagesh" },
  +  { GUINT_TO_POINTER (0xFB39), "/yoddageshhebrew" },
  +  { GUINT_TO_POINTER (0x05D9), "/yodhebrew" },
  +  { GUINT_TO_POINTER (0x05F2), "/yodyodhebrew" },
  +  { GUINT_TO_POINTER (0xFB1F), "/yodyodpatahhebrew" },
  +  { GUINT_TO_POINTER (0x3088), "/yohiragana" },
  +  { GUINT_TO_POINTER (0x3189), "/yoikorean" },
  +  { GUINT_TO_POINTER (0x30E8), "/yokatakana" },
  +  { GUINT_TO_POINTER (0xFF96), "/yokatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x315B), "/yokorean" },
  +  { GUINT_TO_POINTER (0x3087), "/yosmallhiragana" },
  +  { GUINT_TO_POINTER (0x30E7), "/yosmallkatakana" },
  +  { GUINT_TO_POINTER (0xFF6E), "/yosmallkatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x03F3), "/yotgreek" },
  +  { GUINT_TO_POINTER (0x3188), "/yoyaekorean" },
  +  { GUINT_TO_POINTER (0x3187), "/yoyakorean" },
  +  { GUINT_TO_POINTER (0x0E22), "/yoyakthai" },
  +  { GUINT_TO_POINTER (0x0E0D), "/yoyingthai" },
  +  { GUINT_TO_POINTER (0x24B4), "/yparen" },
  +  { GUINT_TO_POINTER (0x037A), "/ypogegrammeni" },
  +  { GUINT_TO_POINTER (0x0345), "/ypogegrammenigreekcmb" },
  +  { GUINT_TO_POINTER (0x01A6), "/yr" },
  +  { GUINT_TO_POINTER (0x1E99), "/yring" },
  +  { GUINT_TO_POINTER (0x02B8), "/ysuperior" },
  +  { GUINT_TO_POINTER (0x1EF9), "/ytilde" },
  +  { GUINT_TO_POINTER (0x028E), "/yturned" },
  +  { GUINT_TO_POINTER (0x3086), "/yuhiragana" },
  +  { GUINT_TO_POINTER (0x318C), "/yuikorean" },
  +  { GUINT_TO_POINTER (0x30E6), "/yukatakana" },
  +  { GUINT_TO_POINTER (0xFF95), "/yukatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x3160), "/yukorean" },
  +  { GUINT_TO_POINTER (0x046B), "/yusbigcyrillic" },
  +  { GUINT_TO_POINTER (0x046D), "/yusbigiotifiedcyrillic" },
  +  { GUINT_TO_POINTER (0x0467), "/yuslittlecyrillic" },
  +  { GUINT_TO_POINTER (0x0469), "/yuslittleiotifiedcyrillic" },
  +  { GUINT_TO_POINTER (0x3085), "/yusmallhiragana" },
  +  { GUINT_TO_POINTER (0x30E5), "/yusmallkatakana" },
  +  { GUINT_TO_POINTER (0xFF6D), "/yusmallkatakanahalfwidth" },
  +  { GUINT_TO_POINTER (0x318B), "/yuyekorean" },
  +  { GUINT_TO_POINTER (0x318A), "/yuyeokorean" },
  +  { GUINT_TO_POINTER (0x09DF), "/yyabengali" },
  +  { GUINT_TO_POINTER (0x095F), "/yyadeva" },
  +  { GUINT_TO_POINTER (0x007A), "/z" },
  +  { GUINT_TO_POINTER (0x0566), "/zaarmenian" },
  +  { GUINT_TO_POINTER (0x017A), "/zacute" },
  +  { GUINT_TO_POINTER (0x095B), "/zadeva" },
  +  { GUINT_TO_POINTER (0x0A5B), "/zagurmukhi" },
  +  { GUINT_TO_POINTER (0x0638), "/zaharabic" },
  +  { GUINT_TO_POINTER (0xFEC6), "/zahfinalarabic" },
  +  { GUINT_TO_POINTER (0xFEC7), "/zahinitialarabic" },
  +  { GUINT_TO_POINTER (0x3056), "/zahiragana" },
  +  { GUINT_TO_POINTER (0xFEC8), "/zahmedialarabic" },
  +  { GUINT_TO_POINTER (0x0632), "/zainarabic" },
  +  { GUINT_TO_POINTER (0xFEB0), "/zainfinalarabic" },
  +  { GUINT_TO_POINTER (0x30B6), "/zakatakana" },
  +  { GUINT_TO_POINTER (0x0595), "/zaqefgadolhebrew" },
  +  { GUINT_TO_POINTER (0x0594), "/zaqefqatanhebrew" },
  +  { GUINT_TO_POINTER (0x0598), "/zarqahebrew" },
  +  { GUINT_TO_POINTER (0x05D6), "/zayin" },
  +  { GUINT_TO_POINTER (0xFB36), "/zayindagesh" },
  +  { GUINT_TO_POINTER (0xFB36), "/zayindageshhebrew" },
  +  { GUINT_TO_POINTER (0x05D6), "/zayinhebrew" },
  +  { GUINT_TO_POINTER (0x3117), "/zbopomofo" },
  +  { GUINT_TO_POINTER (0x017E), "/zcaron" },
  +  { GUINT_TO_POINTER (0x24E9), "/zcircle" },
  +  { GUINT_TO_POINTER (0x1E91), "/zcircumflex" },
  +  { GUINT_TO_POINTER (0x0291), "/zcurl" },
  +  { GUINT_TO_POINTER (0x017C), "/zdot" },
  +  { GUINT_TO_POINTER (0x017C), "/zdotaccent" },
  +  { GUINT_TO_POINTER (0x1E93), "/zdotbelow" },
  +  { GUINT_TO_POINTER (0x0437), "/zecyrillic" },
  +  { GUINT_TO_POINTER (0x0499), "/zedescendercyrillic" },
  +  { GUINT_TO_POINTER (0x04DF), "/zedieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x305C), "/zehiragana" },
  +  { GUINT_TO_POINTER (0x30BC), "/zekatakana" },
  +  { GUINT_TO_POINTER (0x0030), "/zero" },
  +  { GUINT_TO_POINTER (0x0660), "/zeroarabic" },
  +  { GUINT_TO_POINTER (0x09E6), "/zerobengali" },
  +  { GUINT_TO_POINTER (0x0966), "/zerodeva" },
  +  { GUINT_TO_POINTER (0x0AE6), "/zerogujarati" },
  +  { GUINT_TO_POINTER (0x0A66), "/zerogurmukhi" },
  +  { GUINT_TO_POINTER (0x0660), "/zerohackarabic" },
  +  { GUINT_TO_POINTER (0x2080), "/zeroinferior" },
  +  { GUINT_TO_POINTER (0xFF10), "/zeromonospace" },
  +  { GUINT_TO_POINTER (0xF730), "/zerooldstyle" },
  +  { GUINT_TO_POINTER (0x06F0), "/zeropersian" },
  +  { GUINT_TO_POINTER (0x2070), "/zerosuperior" },
  +  { GUINT_TO_POINTER (0x0E50), "/zerothai" },
  +  { GUINT_TO_POINTER (0xFEFF), "/zerowidthjoiner" },
  +  { GUINT_TO_POINTER (0x200C), "/zerowidthnonjoiner" },
  +  { GUINT_TO_POINTER (0x200B), "/zerowidthspace" },
  +  { GUINT_TO_POINTER (0x03B6), "/zeta" },
  +  { GUINT_TO_POINTER (0x3113), "/zhbopomofo" },
  +  { GUINT_TO_POINTER (0x056A), "/zhearmenian" },
  +  { GUINT_TO_POINTER (0x04C2), "/zhebrevecyrillic" },
  +  { GUINT_TO_POINTER (0x0436), "/zhecyrillic" },
  +  { GUINT_TO_POINTER (0x0497), "/zhedescendercyrillic" },
  +  { GUINT_TO_POINTER (0x04DD), "/zhedieresiscyrillic" },
  +  { GUINT_TO_POINTER (0x3058), "/zihiragana" },
  +  { GUINT_TO_POINTER (0x30B8), "/zikatakana" },
  +  { GUINT_TO_POINTER (0x05AE), "/zinorhebrew" },
  +  { GUINT_TO_POINTER (0x1E95), "/zlinebelow" },
  +  { GUINT_TO_POINTER (0xFF5A), "/zmonospace" },
  +  { GUINT_TO_POINTER (0x305E), "/zohiragana" },
  +  { GUINT_TO_POINTER (0x30BE), "/zokatakana" },
  +  { GUINT_TO_POINTER (0x24B5), "/zparen" },
  +  { GUINT_TO_POINTER (0x0290), "/zretroflexhook" },
  +  { GUINT_TO_POINTER (0x01B6), "/zstroke" },
  +  { GUINT_TO_POINTER (0x305A), "/zuhiragana" },
  +  { GUINT_TO_POINTER (0x30BA), "/zukatakana" },
  +  { NULL, NULL }
  +};
  +
  +/*! \brief Initializes the glyph translation table.
  + *  \par Function Description
  + *  Initializes the glyph translation table
  + *
  + *  \return 0
  + */
  +int f_print_initialize_glyph_table(void)
  +{
  +  struct glyph_list *g;
  +
  +  /* Is the hash already intialized? */
  +  if(unicode_char_to_glyph != NULL) return 0;
  +
  +  /* No, allocate hash table */
  +  unicode_char_to_glyph = g_hash_table_new_full (g_direct_hash,
  +						 g_direct_equal,
  +						 NULL,
  +						 NULL);
  +
  +  /* insert all the entries, from glyph name mapping table */
  +  for(g = glyphs; g->name != NULL; g++) {
  +    g_hash_table_insert(unicode_char_to_glyph, g->key, g->name);
  +  }
  +
  +  return 0;
  +}
  
  
  
  1.11      +106 -95   eda/geda/gaf/libgeda/src/g_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: g_basic.c
  ===================================================================
  RCS file: g_basic.c
  diff -N g_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ g_basic.c	5 Jul 2006 03:13:38 -0000	1.11
  @@ -0,0 +1,186 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <sys/stat.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_ASSERT_H
  +#include <assert.h>
  +#endif
  +
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/* The following code was contributed by thi (with formating changes
  + * by Ales) Thanks!
  + * Later updated by spe
  + *
  + * This `load()' is modeled after libguile/load.c, load().
  + * Additionally, the most recent form read is saved in case something
  + * goes wrong.
  + */
  +
  +/*! \brief */
  +static SCM most_recently_read_form = SCM_BOOL_F;
  +
  +/*! \todo Finish function description!!!
  + *  \brief Loads a scheme file.
  + *  \par Function Description
  + *  Loads a scheme file.
  + *
  + *  \param [in] data  ????
  + *  \return SCM_BOOL_T always.
  + */
  +static SCM load (void *data)
  +{
  +	SCM load_port = (SCM)data;
  +	SCM form;
  +	int eof_found = 0;
  +
  +	while (!eof_found) {
  +		form = scm_read(load_port);
  +		if (SCM_EOF_OBJECT_P(form)) {
  +			eof_found = 1;
  +		} else {
  +			most_recently_read_form = form;
  +#ifdef HAVE_SCM_EVAL_X_MODULE
  +  			scm_eval_x (form, scm_current_module() );
  +#else
  +			scm_eval_x (form);
  +#endif
  +		}
  +	}
  +
  +	most_recently_read_form = SCM_BOOL_F;
  +
  +	return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function description!!!
  + *  \brief The error handler for load.
  + *  \par Function Description
  + *  The error handler for load
  + *
  + *  \param [in] data
  + *  \param [in] tag
  + *  \param [in] throw_args
  + *  \return SCM_BOOL_F always.
  + */
  +static SCM load_error_handler(void *data, SCM tag, SCM throw_args)
  +{
  +	SCM cur_out = scm_current_output_port ();
  +	SCM load_port = (SCM)data;
  +	SCM filename  = scm_port_filename(load_port);
  +
  +	/*
  +	 * If misc-error the column and line pointers points
  +	 * to end of file. Not necessary to confuse user.
  +	 */
  +
  +    if (!scm_eq_p (tag, scm_str2symbol ("misc-error"))) {
  +               scm_display(scm_makfrom0str("Error : "), cur_out);
  +		scm_display(tag, cur_out);
  +			
  +		scm_display(scm_makfrom0str(" [C:"), cur_out);
  +		scm_display(scm_port_column(load_port), cur_out );
  +		scm_display(scm_makfrom0str(" L:"), cur_out);
  +		scm_display(scm_port_line(load_port), cur_out );
  +		scm_display(scm_makfrom0str("]"), cur_out);
  +	} else {
  +		scm_display(scm_makfrom0str("Probably parenthesis mismatch"), 
  +			    cur_out);
  +
  +	}
  +
  +	scm_display(scm_makfrom0str(" in "), cur_out);
  +	scm_display(filename, cur_out);
  +	scm_newline(cur_out);
  +
  +	if (most_recently_read_form != SCM_BOOL_F) {
  +		scm_display(scm_makfrom0str ("Most recently read form: "),
  +			    cur_out);
  +		scm_display(most_recently_read_form, cur_out);
  +		scm_newline(cur_out);
  +	}
  +
  +	return SCM_BOOL_F;
  +}
  +
  +
  +/*! \brief Start reading a scheme file
  + *  \par Function Description
  + *  Start reading a scheme file
  + *
  + *  \param [in] filename  The file name to start reading from.
  + *  \return 0 on success, -1 on failure.
  + */
  +int g_read_file(const gchar *filename)
  +{
  +	SCM port;
  +	SCM eval_result = SCM_BOOL_F;
  +	char * full_filename;
  +
  +	if (filename == NULL) {
  +		return(-1);
  +	}
  +
  +	/* get full, absolute path to file */
  +	full_filename = f_normalize_filename(filename);
  +	if (full_filename == NULL) {
  +		return(-1);
  +	}
  +	
  +	if (access(full_filename, R_OK) != 0) {
  +		s_log_message("Could not find [%s] for interpretion\n",
  +			      full_filename);
  +		return(-1);
  +  	}
  +
  +	port = scm_open_file(scm_makfrom0str(full_filename), scm_makfrom0str("r"));
  +
  +	eval_result = scm_internal_catch (SCM_BOOL_T,
  +                                      (scm_t_catch_body)load,
  +                                      (void*)port,
  +                                      (scm_t_catch_handler)load_error_handler,
  +                                      (void*)port);
  +
  +	scm_close_port(port);
  +	
  +	free(full_filename);
  +
  +	return (eval_result == SCM_BOOL_T);
  +}
  
  
  
  1.1                  eda/geda/gaf/libgeda/src/g_rc.c
  
  Index: g_rc.c
  ===================================================================
  /* gEDA - GPL Electronic Design Automation
   * libgeda - gEDA's Library
   * Copyright (C) 1998-2000 Ales V. Hvezda
   *
   * 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.
   *
   * This program 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 this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
   */
  #include <config.h>
  
  #include <stdio.h>
  #include <sys/stat.h>
  #include <ctype.h>
  #ifdef HAVE_STRING_H
  #include <string.h>
  #endif
  #ifdef HAVE_DIRENT_H
  #include <dirent.h>
  #endif
  #ifdef HAVE_STDLIB_H
  #include <stdlib.h>
  #endif
  #ifdef HAVE_UNISTD_H
  #include <unistd.h>
  #endif
  
  #include <gtk/gtk.h>
  #include <libguile.h>
  
  #include "defines.h"
  #include "struct.h"
  #include "globals.h"
  #include "o_types.h"
  #include "colors.h"
  
  #include "../include/i_vars.h"
  #include "../include/papersizes.h"
  #include "../include/prototype.h"
  
  #ifdef HAVE_LIBDMALLOC
  #include <dmalloc.h>
  #endif
  
  extern GHashTable *font_char_to_file;
  
  /*! \brief Reads the gafrc file.
   *  \par Function Description
   *  This is the function which actually reads in the RC file.
   *  First, it looks in a list of previously read RC files.  If the file has
   *  already been read, it just says OK.  After reading the file, it places
   *  the filename in the list of read files.
   *
   *  \param [in] w_current  The TOPLEVEL object.
   *  \param [in] fname      RC file name to read.
   *  \param [in] ok_msg     Message to print if file is read ok.
   *  \param [in] err_msg    Message to print if file read error occurs
   *  \return 1 on success, 0 otherwise.
   */
  gint g_rc_parse_general(TOPLEVEL *w_current,
  			const gchar *fname, 
  			const gchar *ok_msg, const gchar *err_msg)
  {
    gint found_rc = FALSE;
    GList *found_rc_filename_element;
  
    /* First see if fname is in list of previously read RC files. */
    found_rc_filename_element = g_list_find_custom(w_current->RC_list, 
                                                   (gconstpointer) fname,
                                                   (GCompareFunc) strcmp);
    if (found_rc_filename_element != NULL) {
      /* We've already read this one in. */
      s_log_message("RC file [%s] already read in.\n", fname);
      return 0;
    }
  
    /* Now try to read in contents of RC file.  */
    if (access (fname, R_OK) == 0) {
      g_read_file (fname);
      found_rc = 1;
      /* Everything was OK.  Now add this file to list of read RC files. */
      w_current->RC_list = g_list_append (w_current->RC_list,
                                          g_strdup (fname));
      s_log_message (ok_msg, fname);
    } else {
      found_rc = 0;
      s_log_message (err_msg, fname);
    }
  
    return found_rc;
  }
  
  
  /*! \brief Read gEDA root path from RC file.
   *  \par Function Description
   *  This function will read the RC file and parse the root path for gEDA.
   *
   *  \return String containing rc root path
   *
   *  \warning Do not free the returned character string.
   */
  const gchar* g_rc_parse_path(void)
  {
    const gchar *rc_path;
    
    if (g_strcasecmp (GEDARCDIR, "none") == 0) {
      /* rc dir not specified at configure time, so search for config in */
      /* the normal GEDADATA directory */
      rc_path = g_getenv ("GEDADATA");
    } else {
      /* rc path specified at configure time, always return specified path */
      rc_path = GEDARCDIR;
    }
  
    return(rc_path);
  }
  
  /*! \brief Parses a system RC file.
   *  \par Function Description
   *  This function wil open and parse a system rc file.
   *
   *  \param [in] w_current  The TOPLEVEL object.
   *  \param [in] rcname     System RC file name to parse.
   *  \return 1 on success, 0 on failure.
   */
  gint g_rc_parse_system_rc(TOPLEVEL *w_current, const gchar *rcname)
  {
    const gchar *geda_data = g_getenv ("GEDADATA");
    gint found_rc;
    gchar *tmp;
    char *filename;
    gchar *ok_msg, *err_msg;
  
    if (geda_data == NULL) {
      fprintf(stderr, "You must set the GEDADATA environment variable!\n");
      exit(-1);
    }
  
    tmp = g_strconcat (g_rc_parse_path (),
                       G_DIR_SEPARATOR_S,
                       "system-", rcname,
                       NULL);
    filename = f_normalize_filename(tmp);
    if (filename == NULL) {
      return 0;
    }
  
    ok_msg  = g_strdup_printf ("Read system-%s file [%%s]\n",
                               rcname);
    err_msg = g_strdup_printf ("Did not find required system-%s file [%%s]\n",
                               rcname);  
    found_rc = g_rc_parse_general(w_current, filename, ok_msg, err_msg);
  
    g_free (ok_msg);
    g_free (err_msg);  
    g_free (tmp);
    free(filename);
  
    return found_rc;
  }
  
  /*! \brief Parse a RC file in users home directory.
   *  \par Function Description
   *  This function will open and parse a RC file in the users home directory.
   *
   *  \param [in] w_current  The TOPLEVEL object.
   *  \param [in] rcname     User's RC file name.
   *  \return 1 on success, 0 on failure.
   */
  gint g_rc_parse_home_rc(TOPLEVEL *w_current, const gchar *rcname)
  {
    const gchar *home = g_getenv ("HOME");
    gint found_rc;
    gchar *tmp;
    char *filename;
    gchar *ok_msg, *err_msg;
  
    if (home == NULL) {
      return 0;
    }
  
    tmp = g_strconcat (home,
                       G_DIR_SEPARATOR_S,
                       ".gEDA",
                       G_DIR_SEPARATOR_S,
                       rcname,
                       NULL);
    filename = f_normalize_filename(tmp);
    if (filename == NULL) {
      return 0;
    }
  
    ok_msg  = g_strdup_printf ("Read ~/.gEDA/%s file [%%s]\n",
                               rcname);
    err_msg = g_strdup_printf ("Did not find optional ~/.gEDA/%s file [%%s]\n",
                               rcname);  
    found_rc = g_rc_parse_general(w_current, filename, ok_msg, err_msg);
    
    g_free (ok_msg);
    g_free (err_msg);
    g_free (tmp);
    free(filename);
  
    return found_rc;
  }
  
  /*! \brief Parse rc file in current working directory.
   *  \par Function Description
   *  This function will open and parse a RC file in the current working directory.
   *
   *  \param [in] w_current  The TOPLEVEL object.
   *  \param [in] rcname     Local directory RC file name.
   *  \return 1 on success, 0 on failure.
   */
  gint g_rc_parse_local_rc(TOPLEVEL *w_current, const gchar *rcname)
  {
    gint found_rc;
    gchar *tmp;
    char *filename;
    gchar *ok_msg;
    gchar *err_msg;
  
    tmp = g_strconcat (".", G_DIR_SEPARATOR_S, rcname, NULL);
    filename = f_normalize_filename (tmp);
    if (filename == NULL) {
      return 0;
    }
  
    ok_msg  = g_strdup_printf ("Read local %s file [%%s]\n",
                               rcname);
    err_msg = g_strdup_printf ("Did not find optional local %s file [%%s]\n",
                               rcname);  
    found_rc = g_rc_parse_general(w_current, filename, ok_msg, err_msg);
  
    g_free (ok_msg);
    g_free (err_msg);
    g_free (tmp);
    free(filename);
  
    return found_rc;
  }
  
  /*! \brief Parse a RC file from a specified location.
   *  \par Function Description
   *  This function will open and parse a RC file from a specified location.
   *
   *  \param [in] w_current  The TOPLEVEL object.
   *  \param [in] rcname     Specified location RC file name.
   *  \return 1 on success, 0 on failure.
   */
  gint g_rc_parse_specified_rc(TOPLEVEL *w_current, const gchar *rcname)
  {
    gint found_rc = 0;
    char *filename;
    gchar *ok_msg;
    gchar *err_msg;
  
    if (rcname == NULL) {
      return 0;
    }
  
    filename = f_normalize_filename (rcname);
  
    ok_msg  = g_strdup_printf ("Read specified %s file [%%s]\n",
                               rcname);
    err_msg = g_strdup_printf ("Did not find specified %s file [%%s]\n",
                               rcname);  
    found_rc = g_rc_parse_general(w_current, filename, ok_msg, err_msg);
    
    g_free(ok_msg);
    g_free(err_msg);
    free(filename);
  
    return found_rc;
  }
  
  /*! \brief General RC file parsing function.
   *  \par Function Description
   *  This function will check for System, HOME and Local RC files matching
   *  the rcname input parameter.  If none of those three are found it will
   *  search for the specified_rc_filename.  When none are found it will
   *  call exit(-1) to terminate the program.
   *
   *  \param [in] w_current              The TOPLEVEL object.
   *  \param [in] rcname                 RC file name.
   *  \param [in] specified_rc_filename  Specific location RC file name.
   *  \return calls exit(-1) when no RC file matching either rcname or
   *          specified_rc_filename is found.
   */
  void g_rc_parse(TOPLEVEL *w_current,
  		const gchar *rcname, const gchar *specified_rc_filename)
  {
    gint found_rc = 0;
    char *rc_path;
    char *geda_rcdata;
  
    /* set the GEDADATARC environment variable so that the rc files */
    /* know where to look for others */
    rc_path = f_normalize_filename (g_rc_parse_path ());
    /* Reversion to putenv inspired by W. Hoch, 2.17.2005 */
    /*  g_setenv ("GEDADATARC", rc_path, TRUE); */  /*requires glib 2.4.x*/
    geda_rcdata = g_strdup_printf("GEDADATARC=%s", rc_path);
    putenv(geda_rcdata);
    free (rc_path);
    
    /* visit rc files in order */
    /* Changed by SDB 1.2.2005 in response to Peter Kaiser's bug report.
     * Read gafrc files first */
    found_rc |= g_rc_parse_system_rc(w_current, "gafrc");
    found_rc |= g_rc_parse_home_rc(w_current, "gafrc");
    found_rc |= g_rc_parse_local_rc(w_current, "gafrc");
    /* continue support for individual rc files for each program.  */
    found_rc |= g_rc_parse_system_rc(w_current, rcname);
    found_rc |= g_rc_parse_home_rc(w_current, rcname);
    found_rc |= g_rc_parse_local_rc(w_current, rcname);
  
    /* New fcn introduced by SDB to consolidate this & make it available 
     * for other programs */
    found_rc |= g_rc_parse_specified_rc(w_current, specified_rc_filename);
  
    /* Oh well, I couldn't find any rcfile, exit! */
    if (!found_rc) {
      /*! \todo these two are basically the
       * same. Inefficient!
       */
      s_log_message("Could not find any %s file!\n", rcname);
      fprintf(stderr, "Could not find a %s file\n", rcname);
      exit(-1);
    }
  }
  
  /*! \brief
   *  \par Function Description
   *
   *  \param [in] path  
   *  \return SCM_BOOL_T on success, SCM_BOOL_F otherwise.
   */
  SCM g_rc_component_library(SCM path)
  {
    char *string;
  
    SCM_ASSERT (SCM_NIMP (path) && SCM_STRINGP (path), path,
                SCM_ARG1, "component-library");
    
    string = g_strdup (SCM_STRING_CHARS (path));
    /* take care of any shell variables */
    string = expand_env_variables(string);
  
    /* invalid path? */
    if (!g_file_test (string, G_FILE_TEST_IS_DIR)) {
      fprintf(stderr,
              "Invalid path [%s] passed to component-library\n",
              string);
      free (string);
      return SCM_BOOL_F;
    }
  
    if (g_path_is_absolute (string)) {
      s_clib_add_directory (string);
    } else {
      gchar *cwd = g_get_current_dir ();
      gchar *temp;
  #ifdef __MINGW32__
      u_basic_strip_trailing(cwd, G_DIR_SEPARATOR);
  #endif
      temp = g_strconcat (cwd, G_DIR_SEPARATOR_S, string, NULL);
      s_clib_add_directory (temp);
      g_free (temp);
      g_free (cwd);
    }
  
    if (string) {
      free(string);
    }
  
    return SCM_BOOL_T;
  }
  
  /*! \todo Finish function description!!!
   *  \brief
   *  \par Function Description
   *
   *  \param [in] path  
   *  \return SCM_BOOL_T on success, SCM_BOOL_F otherwise.
   */
  SCM g_rc_component_library_search(SCM path)
  {
    char *string;
    GDir *dir;
    const gchar *entry;
    
    SCM_ASSERT (SCM_NIMP (path) && SCM_STRINGP (path), path,
                SCM_ARG1, "component-library-search");
  
    string = g_strdup (SCM_STRING_CHARS (path));
    /* take care of any shell variables */
    string = expand_env_variables(string);
  
    /* invalid path? */
    if (!g_file_test (string, G_FILE_TEST_IS_DIR)) {
      fprintf (stderr,
               "Invalid path [%s] passed to component-library-search\n",
               string);
      free (string);
      return SCM_BOOL_F;
    }
  
    dir = g_dir_open (string, 0, NULL);
    if (dir == NULL) {
      fprintf (stderr,
               "Invalid path [%s] passed to component-library-search\n",
               string);
      free (string);
      return SCM_BOOL_F;
    }
  
    while ((entry = g_dir_read_name (dir))) {
      /* don't do . and .. and special case font */
      if ((g_strcasecmp (entry, ".")    != 0) && 
          (g_strcasecmp (entry, "..")   != 0) &&
          (g_strcasecmp (entry, "font") != 0))
      {
        gchar *fullpath = g_strconcat (string,
                                       G_DIR_SEPARATOR_S,
                                       entry,
                                       NULL);
  
        if (g_file_test (fullpath, G_FILE_TEST_IS_DIR)) {
          if (g_path_is_absolute (fullpath)) {
            s_clib_add_directory (fullpath);
          } else {
            gchar *cwd = g_get_current_dir ();
            gchar *temp;
  #ifdef __MINGW32__
            u_basic_strip_trailing(cwd, G_DIR_SEPARATOR);
  #endif
            temp = g_strconcat (cwd,
                                G_DIR_SEPARATOR_S,
                                fullpath,
                                NULL);
            s_clib_add_directory (temp);
            g_free (temp);
            g_free (cwd);
          }
        }
        g_free (fullpath);
      }
    }
  
    if (string) {
      free(string);
    }
  
    return SCM_BOOL_T;
  }
  
  /*! \todo Finish function description!!!
   *  \brief
   *  \par Function Description
   *
   *  \param [in] path  
   *  \return SCM_BOOL_T on success, SCM_BOOL_F otherwise.
   */
  SCM g_rc_source_library(SCM path)
  {
    char *string;
    
    SCM_ASSERT (SCM_NIMP (path) && SCM_STRINGP (path), path,
                SCM_ARG1, "source-library");
  
    string = g_strdup (SCM_STRING_CHARS (path));
    /* take care of any shell variables */
    string = expand_env_variables(string);
    
    /* invalid path? */
    if (!g_file_test (string, G_FILE_TEST_IS_DIR)) {
      fprintf (stderr,
               "Invalid path [%s] passed to source-library\n",
               string);
      free (string);
      return SCM_BOOL_F;
    }
  
    if (g_path_is_absolute (string)) {
      s_slib_add_entry (string);
    } else {
      gchar *cwd = g_get_current_dir ();
      gchar *temp;
  #ifdef __MINGW32__
      u_basic_strip_trailing(cwd, G_DIR_SEPARATOR);
  #endif
      temp = g_strconcat (cwd,
                          G_DIR_SEPARATOR_S,
                          string,
                          NULL);
      s_slib_add_entry (temp);
      g_free (temp);
      g_free (cwd);
    }
    
    if (string) {
      free (string);
    }
    
    return SCM_BOOL_T;
  }
  
  /*! \todo Finish function description!!!
   *  \brief
   *  \par Function Description
   *
   *  \param [in] path  
   *  \return SCM_BOOL_T on success, SCM_BOOL_F otherwise.
   */
  SCM g_rc_source_library_search(SCM path)
  {
    char *string;
    GDir *dir;
    const gchar *entry;
    
    SCM_ASSERT (SCM_NIMP (path) && SCM_STRINGP (path), path,
                SCM_ARG1, "source-library-search");
  
    string = g_strdup (SCM_STRING_CHARS (path));
    /* take care of any shell variables */
    string = expand_env_variables(string);
  
    /* invalid path? */
    if (!g_file_test (string, G_FILE_TEST_IS_DIR)) {
      fprintf (stderr,
               "Invalid path [%s] passed to source-library-search\n",
               string);
      free (string);
      return SCM_BOOL_F;
    }
  
    dir = g_dir_open (string, 0, NULL);
    if (dir == NULL) {
      fprintf (stderr,
               "Invalid path [%s] passed to source-library-search\n",
               string);
      if (string) {
        free (string);
      }
      return SCM_BOOL_F;
    }
  
    while ((entry = g_dir_read_name (dir))) {
      /* don't do . and .. and special case font */
      if ((g_strcasecmp (entry, ".")    != 0) && 
          (g_strcasecmp (entry, "..")   != 0) &&
          (g_strcasecmp (entry, "font") != 0))
      {
        gchar *fullpath = g_strconcat (string,
                                       G_DIR_SEPARATOR_S,
                                       entry,
                                       NULL);
  
        if (g_file_test (fullpath, G_FILE_TEST_IS_DIR)) {
          if (s_slib_uniq (fullpath)) {
            if (g_path_is_absolute (fullpath)) {
              s_slib_add_entry (fullpath);
            } else {
              gchar *cwd = g_get_current_dir ();
              gchar *temp;
  #ifdef __MINGW32__
              u_basic_strip_trailing(cwd, G_DIR_SEPARATOR);
  #endif
              temp = g_strconcat (cwd,
                                  G_DIR_SEPARATOR_S,
                                  fullpath,
                                  NULL);
              s_slib_add_entry (temp);
              g_free (temp);
              g_free (cwd);
            }
          }
        }
        g_free (fullpath);
      }
    }
  
    if (string) {
      free (string);
    }
  
    return SCM_BOOL_T;
  }
  
  /*! \todo Finish function description!!!
   *  \brief
   *  \par Function Description
   *
   *  \param [in] width   
   *  \param [in] height  
   *  \param [in] border  
   *  \return SCM_BOOL_T always.
   */
  SCM g_rc_world_size(SCM width, SCM height, SCM border)
  #define FUNC_NAME "world-size"
  {
    int i_width, i_height, i_border;
    int init_right, init_bottom;
  
    SCM_ASSERT (SCM_NIMP (width) && SCM_REALP (width), width,
                SCM_ARG1, FUNC_NAME);
    SCM_ASSERT (SCM_NIMP (height) && SCM_REALP (height), height,
                SCM_ARG2, FUNC_NAME);
    SCM_ASSERT (SCM_NIMP (border) && SCM_REALP (border), border,
                SCM_ARG3, FUNC_NAME);
    
    /* yes this is legit, we are casing the resulting double to an int */
    i_width  = (int) (SCM_NUM2DOUBLE (0, width)  * MILS_PER_INCH);
    i_height = (int) (SCM_NUM2DOUBLE (0, height) * MILS_PER_INCH);
    i_border = (int) (SCM_NUM2DOUBLE (0, border) * MILS_PER_INCH);
  
    PAPERSIZEtoWORLD(i_width, i_height, i_border,
                     &init_right, &init_bottom);
  
  #if DEBUG
    printf("%d %d\n", i_width, i_height);
    printf("%d %d\n", init_right, init_bottom);
  #endif
  
    default_init_right  = init_right;
    default_init_bottom = init_bottom;
  
    return SCM_BOOL_T;
  }
  #undef FUNC_NAME
  
  /*! \todo Finish function description!!!
   *  \brief
   *  \par Function Description
   *
   *  \param [in] name
   *  \return SCM_BOOL_T always.
   */
  SCM g_rc_default_series_name(SCM name)
  {
    SCM_ASSERT (SCM_NIMP (name) && SCM_STRINGP (name), name,
                SCM_ARG1, "default-series-name");
  
    if (default_series_name) {
      free (default_series_name);
    }
  
    default_series_name = g_strdup (SCM_STRING_CHARS (name));
  
    return SCM_BOOL_T;
  }
  
  /*! \todo Finish function description!!!
   *  \brief
   *  \par Function Description
   *
   *  \param [in] name  
   *  \return SCM_BOOL_T always.
   */
  SCM g_rc_untitled_name(SCM name)
  {
    SCM_ASSERT (SCM_NIMP (name) && SCM_STRINGP (name), name,
                SCM_ARG1, "untitled-name");
  
    if (default_untitled_name) {
      free (default_untitled_name);
    }
  
    default_untitled_name = g_strdup (SCM_STRING_CHARS (name));
  
    return SCM_BOOL_T;
  }
  
  /*! \todo Finish function description!!!
   *  \brief
   *  \par Function Description
   *
   *  \param [in] path  
   *  \return SCM_BOOL_T on success, SCM_BOOL_F otherwise.
   */
  SCM g_rc_font_directory(SCM path)
  {
    char *string;
  
    SCM_ASSERT (SCM_NIMP (path) && SCM_STRINGP (path), path,
                SCM_ARG1, "font-directory");
  
    string = g_strdup (SCM_STRING_CHARS (path));
    /* take care of any shell variables */
    string = expand_env_variables(string);
  
    /* invalid path? */
    if (!g_file_test (string, G_FILE_TEST_IS_DIR)) {
      fprintf (stderr,
               "Invalid path [%s] passed to font-directory\n",
               string);
      if (string) {
        free (string);
      }
      return SCM_BOOL_F;
    }
  
    if (default_font_directory) {
      free (default_font_directory);
    }
    default_font_directory = string;
  
    return SCM_BOOL_T;
  }
  
  /*! \todo Finish function description!!!
   *  \brief
   *  \par Function Description
   *
   *  \param [in] path  
   *  \return SCM_BOOL_T on success, SCM_BOOL_F otherwise.
   */
  SCM g_rc_scheme_directory(SCM path)
  {
    char *string;
  
    SCM_ASSERT (SCM_NIMP (path) && SCM_STRINGP (path), path,
                SCM_ARG1, "scheme-directory");
  
    string = g_strdup (SCM_STRING_CHARS (path));
    /* take care of any shell variables */
    string = expand_env_variables(string);
  
    /* invalid path? */
    if (!g_file_test (string, G_FILE_TEST_IS_DIR)) {
      fprintf (stderr,
               "Invalid path [%s] passed to scheme-directory\n",
               string);
      if (string) {
        free (string);
      }
      return SCM_BOOL_F;
    }
  
    if (default_scheme_directory) {
      free (default_scheme_directory);
    }
    default_scheme_directory = string;
  
    return SCM_BOOL_T;
  }
  
  /*! \todo Finish function description!!!
   *  \brief
   *  \par Function Description
   *
   *  \param [in] path  
   *  \return SCM_BOOL_T on success, SCM_BOOL_F otherwise.
   */
  SCM g_rc_bitmap_directory(SCM path)
  {
    char *string;
  
    SCM_ASSERT (SCM_NIMP (path) && SCM_STRINGP (path), path,
                SCM_ARG1, "bitmap-directory");
    
    string = g_strdup (SCM_STRING_CHARS (path));
    /* take care of any shell variables */
    string = expand_env_variables(string);
  
    /* invalid path? */
    if (!g_file_test (string, G_FILE_TEST_IS_DIR)) {
      fprintf (stderr,
               "Invalid path [%s] passed to bitmap-directory\n",
               string);
      if (string) {
        free (string);
      }
      return SCM_BOOL_F;
    }
  
    if (default_bitmap_directory) {
      free (default_bitmap_directory);
    }
    default_bitmap_directory = string;
  
    return SCM_BOOL_T;
  }
  
  /*! \todo Finish function description!!!
   *  \brief
   *  \par Function Description
   *
   *  \param [in] scmsymname  
   *  \return SCM_BOOL_T always.
   */
  SCM g_rc_bus_ripper_symname(SCM scmsymname)
  {
    SCM_ASSERT (SCM_NIMP (scmsymname) && SCM_STRINGP (scmsymname), scmsymname,
                SCM_ARG1, "bus-ripper-symname");
  
    if (default_bus_ripper_symname) {
      free (default_bus_ripper_symname);
    }
    default_bus_ripper_symname = g_strdup (SCM_STRING_CHARS (scmsymname));
  
    return SCM_BOOL_T;
  }
  
  /*! \todo Finish function description!!!
   *  \brief
   *  \par Function Description
   *
   *  \param [in] scmsymname  
   *  \return SCM_BOOL_T always.
   */
  SCM g_rc_postscript_prolog(SCM scmsymname)
  {
    char *string;
    
    SCM_ASSERT (SCM_NIMP (scmsymname) && SCM_STRINGP (scmsymname), scmsymname,
                SCM_ARG1, "postsript-prolog");
  
    if (default_postscript_prolog) {
      free (default_postscript_prolog);
    }
  
    string = g_strdup (SCM_STRING_CHARS (scmsymname));
    /* take care of any shell variables */
    string = expand_env_variables(string);
  
    default_postscript_prolog = g_strdup (string);
  
    return SCM_BOOL_T;
  }
  
  /*! \todo Finish function description!!!
   *  \brief
   *  \par Function Description
   *
   *  \return SCM_BOOL_T always.
   */
  SCM g_rc_reset_component_library(void)
  {
    s_clib_init();
    
    return SCM_BOOL_T;
  }
  
  /*! \todo Finish function description!!!
   *  \brief
   *  \par Function Description
   *
   *  \return SCM_BOOL_T always.
   */
  SCM g_rc_reset_source_library(void)
  {
    s_slib_free();
    s_slib_init();
    
    return SCM_BOOL_T;
  }
  
  /*! \todo Finish function description!!!
   *  \brief
   *  \par Function Description
   *
   *  \param [in] scmcharstr   
   *  \param [in] scmfilename  
   *  \return SCM_BOOL_T on success, SCM_BOOL_F otherwise.
   */
  SCM g_rc_map_font_character_to_file(SCM scmcharstr, SCM scmfilename)
  {
    gchar *charstr, *filename;
    gunichar character;
  
    SCM_ASSERT (SCM_STRINGP (scmcharstr), scmcharstr,
                SCM_ARG1, "map-font-character-to-file");
    SCM_ASSERT (SCM_STRINGP (scmfilename), scmfilename,
                SCM_ARG2, "map-font-character-to-file");
  
    charstr  = SCM_STRING_CHARS (scmcharstr);
    filename = SCM_STRING_CHARS (scmfilename);
    
    if (charstr == NULL || filename == NULL) {
      fprintf(stderr,
              "%s requires two strings as parameters\n",
              "map-font-character-to-file"
              );
      return SCM_BOOL_F;
    }
  
    /* take care of expansion of any shell variables in filename */
    filename = expand_env_variables (g_strdup (filename));
  
    character = g_utf8_get_char_validated (charstr, -1);
    
    /* insert the new character declaration in the hash table */
    g_hash_table_insert (font_char_to_file,
                         GUINT_TO_POINTER ((guint)character),
                         filename);
  
    return SCM_BOOL_T;
  }
  
  /*! \todo Finish function description!!!
   *  \brief
   *  \par Function Description
   *
   *  \param [in] scmsymname  
   *  \return SCM_BOOL_T always.
   */
  SCM g_rc_always_promote_attributes(SCM scmsymname)
  {
    SCM_ASSERT (SCM_NIMP (scmsymname) && SCM_STRINGP (scmsymname), scmsymname,
                SCM_ARG1, "always-promote-attributes");
  
    if (default_always_promote_attributes) {
      free (default_always_promote_attributes);
    }
    default_always_promote_attributes = 
      g_strdup_printf(" %s ", SCM_STRING_CHARS (scmsymname));
  
    return SCM_BOOL_T;
  }
  
  
  
  1.1                  eda/geda/gaf/libgeda/src/g_register.c
  
  Index: g_register.c
  ===================================================================
  /* gEDA - GPL Electronic Design Automation
   * libgeda - gEDA's Library
   * Copyright (C) 1998-2004 Ales V. Hvezda
   *
   * 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.
   *
   * This program 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 this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
   */
  
  #include <config.h>
  
  #include <stdio.h>
  #include <sys/stat.h>
  #ifdef HAVE_STDLIB_H
  #include <stdlib.h>
  #endif
  #ifdef HAVE_ASSERT_H
  #include <assert.h>
  #endif
  #ifdef HAVE_UNISTD_H
  #include <unistd.h>
  #endif
  
  #include <gtk/gtk.h>
  #include <libguile.h>
  
  #include "defines.h"
  #include "struct.h"
  #include "globals.h"
  #include "o_types.h"
  #include "colors.h"
  #include "i_vars.h"
  #include "prototype.h"
  
  #ifdef HAVE_LIBDMALLOC
  #include <dmalloc.h>
  #endif
  
  /*! \brief */
  struct gsubr_t {
    char* name;
    int req;
    int opt;
    int rst;
    SCM (*fnc)();
  };
  
  /*! \brief */
  static struct gsubr_t libgeda_funcs[] = {
    { "component-library",        1, 0, 0, g_rc_component_library },
    { "component-library-search", 1, 0, 0, g_rc_component_library_search },
    { "source-library",           1, 0, 0, g_rc_source_library },
    { "source-library-search",    1, 0, 0, g_rc_source_library_search },
    
    { "world-size",               3, 0, 0, g_rc_world_size },
    
    { "reset-component-library",  0, 0, 0, g_rc_reset_component_library },
    { "reset-source-library",     0, 0, 0, g_rc_reset_source_library },
    
    { "default-series-name",      1, 0, 0, g_rc_default_series_name },
    { "untitled-name",            1, 0, 0, g_rc_untitled_name },
    { "scheme-directory",         1, 0, 0, g_rc_scheme_directory },
    { "bitmap-directory",         1, 0, 0, g_rc_bitmap_directory },
    { "font-directory",           1, 0, 0, g_rc_font_directory },
    { "bus-ripper-symname",       1, 0, 0, g_rc_bus_ripper_symname },
    { "postscript-prolog",        1, 0, 0, g_rc_postscript_prolog },
    { "map-font-character-to-file", 2, 0, 0, g_rc_map_font_character_to_file },
    { "always-promote-attributes",1, 0, 0, g_rc_always_promote_attributes },
    { NULL,                       0, 0, 0, NULL } };
  
  /*! \brief Register all libgeda functions with scheme.
   *  \par Function Description
   *  Creates g_subr_t objects to make g_rc_* functions that are defined
   *  in g_rc.c visible to Scheme.
   */
  void g_register_libgeda_funcs (void)
  {
    struct gsubr_t *tmp = libgeda_funcs;
    
    while (tmp->name != NULL) {
      scm_c_define_gsubr (tmp->name, tmp->req, tmp->opt, tmp->rst, tmp->fnc);
      tmp++;
    }
    
  }
  
  
  
  1.6       +343 -114  eda/geda/gaf/libgeda/src/g_smob.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: g_smob.c
  ===================================================================
  RCS file: g_smob.c
  diff -N g_smob.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ g_smob.c	5 Jul 2006 03:13:38 -0000	1.6
  @@ -0,0 +1,412 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <math.h>
  +#include <stdio.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +static long attrib_smob_tag; /*! Attribute SMOB tag */
  +static long object_smob_tag; /*! Object SMOB tag */
  +
  +/*! \brief Free attribute smob memory.
  + *  \par Function Description
  + *  Free the memory allocated by the attribute smob and return its size.
  + *
  + *  \param [in] attrib_smob  The attribute smob to free.
  + *  \return Size of attribute smob.
  + */
  +static scm_sizet g_free_attrib_smob(SCM attrib_smob)
  +{
  +  struct st_attrib_smob *attribute = 
  +  (struct st_attrib_smob *)SCM_CDR(attrib_smob);
  +  scm_sizet size = sizeof(struct st_attrib_smob);
  +
  +  free(attribute);
  +  return size;
  +}
  +
  +/*! \brief Prints attribute smob to port.
  + *  \par Function Description
  + *  This function prints the given attribute smob to the port.
  + *  It just prints a string showing it is an attribute and its string.
  + *
  + *  \param [in] attrib_smob  The attribute smob.
  + *  \param [in] port         The port to print to.
  + *  \param [in] pstate       Unused.
  + *  \return non-zero means success.
  + */
  +static int g_print_attrib_smob(SCM attrib_smob, SCM port,
  +			       scm_print_state *pstate)
  +{
  +  struct st_attrib_smob *attribute = 
  +  (struct st_attrib_smob *)SCM_CDR(attrib_smob);
  +
  +  if (attribute &&
  +      attribute->attribute &&
  +      attribute->attribute->object &&
  +      attribute->attribute->object->text &&
  +      attribute->attribute->object->text->string ) {
  +    scm_puts("#<attribute ", port);
  +    scm_display (scm_makfrom0str (attribute->attribute->object->text->string),
  +                 port);
  +    scm_puts(">", port);
  +  }
  +	
  +  /* non-zero means success */
  +  return 1;
  +}
  +
  +
  +/*! \brief Creates a name-value smob
  + *  \par Function Description
  + *  This function Creates and returns a new attribute smob,
  + *  based on the given TOPLEVEL curr_w and attribute curr_attr.
  + *
  + *  \param [in] curr_w     The current TOPLEVEL object.
  + *  \param [in] curr_attr  The current attribute.
  + *  \return SCM
  + */
  +SCM g_make_attrib_smob(TOPLEVEL *curr_w, ATTRIB *curr_attr)
  +{
  +  struct st_attrib_smob *smob_attribute;
  +
  +  smob_attribute = (struct st_attrib_smob *)
  +    			scm_must_malloc(sizeof(struct st_attrib_smob),
  +					"attribute");
  +
  +  smob_attribute->world     = curr_w;
  +  smob_attribute->attribute = curr_attr;
  +
  +  /* Assumes Guile version >= 1.3.2 */
  +  SCM_RETURN_NEWSMOB(attrib_smob_tag, smob_attribute);
  +}
  +
  +/*! \brief Get name and value of attribute.
  + *  \par Function Description
  + *  Returns a list with the name and value of the given attribute smob
  + *  
  + *  \param [in] attrib_smob  The attribute smob to get name and value from.
  + *  \return A list containing the name and value of the attribute.
  + */
  +SCM g_get_attrib_name_value(SCM attrib_smob)
  +{
  +  struct st_attrib_smob *attribute;
  +  char *name = NULL;
  +  char *value = NULL;
  +  SCM returned = SCM_EOL;
  +
  +  SCM_ASSERT ( SCM_NIMP(attrib_smob) && 
  +               ((long) SCM_CAR(attrib_smob) == attrib_smob_tag),
  +               attrib_smob, SCM_ARG1, "get-attribute-name-value");
  +
  +  attribute = (struct st_attrib_smob *)SCM_CDR(attrib_smob);
  +
  +  if (attribute &&
  +      attribute->attribute &&
  +      attribute->attribute->object &&
  +      attribute->attribute->object->text->string ) {
  +    o_attrib_get_name_value(attribute->attribute->object->text->string, 
  +                            &name, &value );
  +    returned = scm_cons (scm_makfrom0str (name),
  +                         scm_makfrom0str (value));
  +    if (name) free(name);
  +    if (value) free(value);
  +  }
  +
  +  return returned;
  +}
  +
  +/*! \brief Set the attribute value.
  + *  \par Function Description
  + *  This function puts the attribute smob name into a new_string and
  + *  the new scm_value (attribute=value format). It also returns the
  + *  TOPLEVEL and OBJECT pointers.
  + *
  + *  \param [in]     attrib_smob  The attribute to update.
  + *  \param [in]     scm_value    The new value of the attribute.
  + *  \param [in,out] world        The TOPLEVEL object.
  + *  \param [in,out] o_attrib     Pointer to the updated attribute smob.
  + *  \param [in]     new_string   Returns the attribute=value format string for the
  + *                               updated attribute.
  + *  \return Always SCM_UNDEFINED
  + */
  +SCM g_set_attrib_value_internal(SCM attrib_smob, SCM scm_value, 
  +				TOPLEVEL **world, OBJECT **o_attrib,
  +				char *new_string[])
  +{
  +  struct st_attrib_smob *attribute;
  +  char *name = NULL;
  +  char *value = NULL;
  +  char *old_value = NULL;
  +
  +  SCM_ASSERT ( SCM_NIMP(attrib_smob) && 
  +               ((long) SCM_CAR(attrib_smob) == attrib_smob_tag),
  +               attrib_smob, SCM_ARG1, "set-attribute-value!");
  +  SCM_ASSERT ( SCM_NIMP(scm_value) && SCM_STRINGP(scm_value),
  +               scm_value, SCM_ARG2, "set-attribute-value!");
  +
  +  attribute = (struct st_attrib_smob *)SCM_CDR(attrib_smob);
  +  value = SCM_STRING_CHARS (scm_value);
  +
  +  if (attribute &&
  +      attribute->attribute &&
  +      attribute->attribute->object &&
  +      attribute->attribute->object->text &&
  +      attribute->attribute->object->text->string ) {
  +
  +    o_attrib_get_name_value(attribute->attribute->object->text->string, 
  +                            &name, &old_value );
  +
  +    *new_string = g_strconcat (name, "=", value, NULL);
  +		
  +    *world = attribute->world;
  +    *o_attrib = attribute->attribute->object;
  +
  +    if (name) free(name);
  +    if (old_value) free(old_value);
  +  }
  +
  +  return SCM_UNDEFINED;
  +}
  +
  +/*! \brief Initialize the framework to support an attribute smob.
  + *  \par Function Description
  + *  Initialize the framework to support an attribute smob.
  + *
  + */
  +void g_init_attrib_smob(void)
  +{
  +
  +  attrib_smob_tag = scm_make_smob_type("attribute",
  +				       sizeof (struct st_attrib_smob));
  +  scm_set_smob_mark(attrib_smob_tag, 0);
  +  scm_set_smob_free(attrib_smob_tag, g_free_attrib_smob);
  +  scm_set_smob_print(attrib_smob_tag, g_print_attrib_smob);
  +
  +  scm_c_define_gsubr("get-attribute-name-value", 1, 0, 0,
  +		     g_get_attrib_name_value);
  +
  +  return;
  +}
  +
  +/*! \brief Free object smob memory.
  + *  \par Function Description
  + *  Free the memory allocated by the object smob and return its size.
  + *
  + *  \param [in] object_smob  The object smob to free.
  + *  \return Size of object smob.
  + */
  +static scm_sizet g_free_object_smob(SCM object_smob)
  +{
  +  struct st_object_smob *object = 
  +  (struct st_object_smob *)SCM_CDR(object_smob);
  +  scm_sizet size = sizeof(struct st_object_smob);
  +
  +  free(object);
  +  return size;
  +}
  +
  +/*! \brief Prints object smob to port.
  + *  \par Function Description
  + *  This function prints the given object smob to the port.
  + *  It just prints a string showing it is an object and the object name.
  + *
  + *  \param [in] object_smob  The object smob.
  + *  \param [in] port         The port to print to.
  + *  \param [in] pstate       Unused.
  + *  \return non-zero means success.
  + */
  +static int g_print_object_smob(SCM object_smob, SCM port,
  +			       scm_print_state *pstate)
  +{
  +  struct st_object_smob *object = 
  +  (struct st_object_smob *)SCM_CDR(object_smob);
  +
  +  if (object &&
  +      object->object &&
  +      object->object->name) {
  +    scm_puts("#<object ", port);
  +    scm_display (scm_makfrom0str (object->object->name),
  +                 port);
  +    scm_puts(">", port);
  +  }
  +	
  +  /* non-zero means success */
  +  return 1;
  +}
  +
  +/*! \brief Creates a object smob
  + *  \par Function Description
  + *  This function creates and returns a new object smob,
  + *  from the given TOPLEVEL curr_w and object pointers.
  + *
  + *  \param [in] curr_w  The current TOPLEVEL object.
  + *  \param [in] object  The current object.
  + *  \return SCM
  + */
  +SCM g_make_object_smob(TOPLEVEL *curr_w, OBJECT *object)
  +{
  +  struct st_object_smob *smob_object;
  +
  +  smob_object = (struct st_object_smob *)
  +    scm_must_malloc(sizeof(struct st_object_smob), "object");
  +
  +  smob_object->world  = curr_w;
  +  smob_object->object = object;
  +
  +  /* Assumes Guile version >= 1.3.2 */
  +  SCM_RETURN_NEWSMOB(object_smob_tag, smob_object);
  +}
  +
  +/*! \brief Get all object attributes in a list.
  + *  \par Function Description
  + *  This function returns a list with all the attributes of a given object smob.
  + *
  + *  \param [in] object_smob  The object smob to get attributes from.
  + *  \return A list of attributes associated with this object smob.
  + */
  +SCM g_get_object_attributes(SCM object_smob)
  +{
  +  TOPLEVEL *w_current;
  +  struct st_object_smob *object;
  +  SCM returned = SCM_EOL;
  +
  +  SCM_ASSERT ( SCM_NIMP(object_smob) && 
  +               ((long) SCM_CAR(object_smob) == object_smob_tag),
  +               object_smob, SCM_ARG1, "get-object-attributes");
  +
  +  object = (struct st_object_smob *)SCM_CDR(object_smob);
  +
  +  if (object &&
  +      object->object) {
  +    ATTRIB *pointer;
  +    
  +    pointer = object->object->attribs;
  +    w_current = object->world;
  +    while (pointer != NULL) {
  +      if (pointer->object &&
  +	  pointer->object->text) {
  +	returned = scm_cons (g_make_attrib_smob (w_current, pointer), returned);
  +      }
  +      pointer = pointer->next;
  +    }     
  +  }
  +
  +  return returned;
  +}
  +
  +/*! \brief Initialize the framework to support an object smob.
  + *  \par Function Description
  + *  Initialize the framework to support an object smob.
  + *
  + */
  +void g_init_object_smob(void)
  +{
  +
  +  object_smob_tag = scm_make_smob_type("object", sizeof (struct st_object_smob));
  +  scm_set_smob_mark(object_smob_tag, 0);
  +  scm_set_smob_free(object_smob_tag, g_free_object_smob);
  +  scm_set_smob_print(object_smob_tag, g_print_object_smob);
  +
  +  scm_c_define_gsubr("get-object-attributes", 1, 0, 0, g_get_object_attributes);
  +
  +  return;
  +}
  +
  +#if 0
  +/*! \brief Gets the OBJECT data from the object smob.
  + *  \par Function Description
  + *  Get the OBJECT data from the object smob.
  + *
  + *  \param [in] object_smob  The object smob to get the OBJECT data from.
  + *  \return The OBJECT data.
  + *  \deprecated
  + *  \todo check and remove?
  + */
  +OBJECT *g_get_object_from_object_smob(SCM object_smob)
  +{
  +  
  +  SCM_ASSERT ( SCM_NIMP(object_smob) && 
  +               (SCM_CAR(object_smob) == object_smob_tag),
  +               object_smob, SCM_ARG1, "get_object_from_object_smob");
  +  return ((OBJECT *) (((struct st_object_smob *)SCM_CDR(object_smob))->object));
  +}
  +
  +/*! \brief Get the TOPLEVEL data from the object smob.
  + *  \par Function Description
  + *  Get the TOPLEVEL data from the object smob.
  + *
  + *  \param [in] object_smob  The object smob to get the TOPLEVEL data from.
  + *  \return The TOPLEVEL data.
  + *  \deprecated
  + *  \todo check and remove?
  + */
  +TOPLEVEL *g_get_toplevel_from_object_smob(SCM object_smob)
  +{
  +  
  +  SCM_ASSERT ( SCM_NIMP(object_smob) && 
  +               (SCM_CAR(object_smob) == object_smob_tag),
  +               object_smob, SCM_ARG1, "get_toplevel_from_object_smob");
  +  return ((TOPLEVEL *) (((struct st_object_smob *)SCM_CDR(object_smob))->world));
  +}
  +#endif
  +
  +/*! \brief Get the TOPLEVEL and OBJECT data from an object smob.
  + *  \par Function Description
  + *  Get the TOPLEVEL and OBJECT data from an object smob.
  + *
  + *  \param [in]  object_smob  The object smob to get data from.
  + *  \param [out] toplevel     The TOPLEVEL to write data to.
  + *  \param [out] object       The OBJECT to write data to.
  + *  \return TRUE on success, FALSE otherwise
  + */
  +gboolean g_get_data_from_object_smob(SCM object_smob, TOPLEVEL **toplevel, 
  +				     OBJECT **object)
  +{
  +  
  +  if ( (!SCM_NIMP(object_smob)) || 
  +       ((long) SCM_CAR(object_smob) != object_smob_tag) ) {
  +    return(FALSE);
  +  }
  +  if (toplevel != NULL) {
  +    *toplevel = (TOPLEVEL *) 
  +    (((struct st_object_smob *)SCM_CDR(object_smob))->world);
  +  }
  +  if (object != NULL) {
  +    *object = (OBJECT *) 
  +    (((struct st_object_smob *)SCM_CDR(object_smob))->object);
  +  }
  +  return (TRUE);
  +}
  
  
  
  1.1                  eda/geda/gaf/libgeda/src/gdk-pixbuf-hacks.c
  
  Index: gdk-pixbuf-hacks.c
  ===================================================================
  /* Functions gdk_pixbuf_rotate and gdk_pixbuf_add are taken from gtkam,
     and is covered by this copyright. */
  /*
   * Copyright © 2001 Lutz Müller <lutz@xxxxxxxxxxxx>
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2 of the License, or (at your option) any later version.
   *
   * This library 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
   * Lesser General Public License for more details. 
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the
   * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   * Boston, MA 02111-1307, USA.
   */
  
  /* Taken from gtkam's sources */
  #include "config.h"
  #ifndef HAS_GTK12
  #include <gdk-pixbuf/gdk-pixbuf.h>
  #endif
  
  #ifndef HAS_GTK12
  /*! \def COPY90 */
  #define COPY90                                                          \
          if ((r2 < h1) && (c2 < w1)) {                                   \
            if ((w1 <= h1) && (r1 < h2))                                  \
              for (i = 0; i < c; i++)                                     \
                new_pixels[r1 * rs2 + c1 * c + i] =                      	\
                  pixels[r2 * rs1 + c2 * c + i];                  	\
            if ((w1 > h1) && (c1 > (w1 - h2)))                            \
              for (i = 0; i < c; i++)                                     \
                new_pixels[r1 * rs2 + (c1 - (w1 - h1)) * c + i] =        	\
                  pixels[r2 * rs1 + c2 * c + i];                  	\
          }
  
  /*! \def COPY270 */
  #define COPY270                                                         \
          if ((r2 < h1) && (c2 < w1)) {                                   \
            if ((h1 > w1) && (r1 > (h1 - w1)))                            \
              for (i = 0; i < c; i++)                                     \
                new_pixels[(r1 - (h1 - w1)) * rs2 + c1 * c + i] =        	\
                  pixels[r2 * rs1 + c2 * c + i];                  	\
            if ((h1 <= w1) && (c1 < w2))                                  \
              for (i = 0; i < c; i++)                                     \
                new_pixels[r1 * rs2 + c1 * c + i] =               	\
                  pixels[r2 * rs1 + c2 * c + i];                  	\
          }
  
  
  /*! \brief Rotate a GdkPixbuf by a given angle
   *  \par Function Description
   *  This function will take a GdkPixbuf and rotate it by the specified angle.
   *
   *  \param [in] pixbuf  The pixel buffer to rotate.
   *  \param [in] angle   The rotation angle.
   *  \return The rotated pixbuf.
   */
  GdkPixbuf *gdk_pixbuf_rotate (GdkPixbuf *pixbuf, guint angle)
  {
          GdkPixbuf *new = NULL;
          guint row, col, w1, h1, w2, h2;
          guint r1, r2, c1, c2;
          guint rs1, rs2;
          guint c;
          guint i;
  	guchar *pixels, *new_pixels;
  
  	if (pixbuf == NULL) {
  	  return NULL;
  	}	
          g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
  	
  	/* Swapped original definitions, so the picture turns counter-clockwise */
  	if (angle == 90)
  	  angle = 270;
  	else  if (angle == 270)
  	  angle = 90;
  
          switch (angle) {
          case 0:
                  return (gdk_pixbuf_copy (pixbuf));
          case 180:
                  new = gdk_pixbuf_new (
  			gdk_pixbuf_get_colorspace (pixbuf),
  			gdk_pixbuf_get_has_alpha (pixbuf),
  			gdk_pixbuf_get_bits_per_sample (pixbuf),
  			gdk_pixbuf_get_width (pixbuf),
  			gdk_pixbuf_get_height (pixbuf));
                  break;
          case 90:
          case 270:
                  new = gdk_pixbuf_new (
  			gdk_pixbuf_get_colorspace (pixbuf),
  			gdk_pixbuf_get_has_alpha (pixbuf),
  			gdk_pixbuf_get_bits_per_sample (pixbuf),
  			gdk_pixbuf_get_height (pixbuf),
  			gdk_pixbuf_get_width (pixbuf));
                  break;
          default:
                  g_warning ("Rotation by %i not implemented.", angle);
                  break;
          }
  
          rs1 = gdk_pixbuf_get_rowstride (pixbuf);
          rs2 = gdk_pixbuf_get_rowstride (new);
  
          c = gdk_pixbuf_get_has_alpha (pixbuf) ? 4 : 3;
  
          w1 = gdk_pixbuf_get_width (pixbuf);
          h1 = gdk_pixbuf_get_height (pixbuf);
          w2 = gdk_pixbuf_get_width (new);
          h2 = gdk_pixbuf_get_height (new);
  
  	pixels = gdk_pixbuf_get_pixels (pixbuf);
  	new_pixels = gdk_pixbuf_get_pixels (new);
  
          /*
           * For rotation by 90 or 270, we assume the pixbuf to be a
           * square and move (r2,c2) to (r1,c1):
           */
          switch (angle) {
          case 90:
                  for (row = 0; row < MAX (w1, h1) / 2; row++) {
                          for (col = row; col < MAX (w1, h1) - row - 1; col++) {
                                  r1 = row;
                                  c1 = col;
                                  r2 = MAX (w1, h1) - col - 1;
                                  c2 = row;
                                  COPY90;
                                  r1 = r2;
                                  c1 = c2;
                                  r2 = MAX (w1, h1) - row - 1;
                                  c2 = MAX (w1, h1) - col - 1;
                                  COPY90;
                                  r1 = r2;
                                  c1 = c2;
                                  r2 = col;
                                  c2 = MAX (w1, h1) - row - 1;
                                  COPY90;
                                  r1 = r2;
                                  c1 = c2;
                                  r2 = row;
                                  c2 = col;
                                  COPY90;
                          }
                  }
                  break;
          case 270:
                  for (row = 0; row < MAX (w1, h1) / 2; row++) {
                          for (col = row; col < MAX (w1, h1) - row - 1; col++) {
                                  r1 = row;
                                  c1 = col;
                                  r2 = col;
                                  c2 = MAX (w1, h1) - row - 1;
                                  COPY270;
                                  r1 = r2;
                                  c1 = c2;
                                  r2 = MAX (w1, h1) - row - 1;
                                  c2 = MAX (w1, h1) - col - 1;
                                  COPY270;
                                  r1 = r2;
                                  c1 = c2;
                                  r2 = MAX (w1, h1) - col - 1;
                                  c2 = row;
                                  COPY270;
                                  r1 = r2;
                                  c1 = c2;
                                  r2 = row;
                                  c2 = col;
                                  COPY270;
                          }
                  }
                  break;
          case 180:
                  for (row = 0; row < h1; row++) {
                          for (col = 0; col < w1; col++) {
                                  r1 = row;
                                  c1 = col;
                                  r2 = h1 - row - 1;
                                  c2 = w1 - col - 1;
                                  for (i = 0; i < c; i++) {
                                    new_pixels[r2 * rs2 + c2 * c + i] =
                                      pixels[r1 * rs1 + c1 * c + i];
                                  }
                          }
                  }
                  break;
          default:
                  g_warning ("Rotation by %i not implemented.", angle);
                  break;
          }
  
          return (new);
  }
  
  /*! \brief Maps a GdkPixbuf at a given offset onto another GdkPixbuf.
   *  \par Function Description
   *  This function will take a GdkPixbuf and map it onto an existing one
   *  at the given x/y offset.
   *
   *  \param [in,out] pixbuf         The GdkPixbuf to map onto.
   *  \param [in]     offset_x       The x offset to start map operation.
   *  \param [in]     offset_y       The y offset to start map operation.
   *  \param [in]     pixbuf_to_add  The GdkPixbuf to map onto pixbuf.
   *  \return Updated GdkPixbuf is returned in pixbuf.
   */
  void gdk_pixbuf_add (GdkPixbuf *pixbuf, int offset_x, int offset_y,
  		     GdkPixbuf *pixbuf_to_add)
  {
  	guchar *p1, *p2, a1, a2;
  	guint w1, h1, w2, h2, r1, r2;
  	guint row, col, i, pos1, pos2;
  
  	g_return_if_fail (pixbuf != NULL);
  	g_return_if_fail (pixbuf_to_add != NULL);
  
  	w1 = gdk_pixbuf_get_width (pixbuf);
  	h1 = gdk_pixbuf_get_height (pixbuf);
  	w2 = gdk_pixbuf_get_width (pixbuf_to_add);
  	h2 = gdk_pixbuf_get_height (pixbuf_to_add);
  	g_return_if_fail (w1 >= offset_x + w2);
  	g_return_if_fail (h1 >= offset_y + h2);
  
  	p1 = gdk_pixbuf_get_pixels (pixbuf);
  	p2 = gdk_pixbuf_get_pixels (pixbuf_to_add);
  	r1 = gdk_pixbuf_get_rowstride (pixbuf);
  	r2 = gdk_pixbuf_get_rowstride (pixbuf_to_add);
  	for (row = 0; row < h2; row++) {
  		for (col = 0; col < w2; col++) {
  			pos1 = (row + offset_y) * r1 + (col + offset_x) * 4;
  			pos2 = row * r2 + col * 4;
  			a1 = p1[pos1 + 3];
  			a2 = p2[pos2 + 3];
  
  			for (i = 0; i < 3; i++) {
  				p1[pos1 + i] *=
  					((gfloat) (0xff - a2) / (gfloat) 0xff);
  				p1[pos1 + i] += (p2[pos2 + i] * 
  					((gfloat) a2 / (gfloat) 0xff));
  			}
  			p1[pos1 + 3] = MAX (a1, a2);
  		}
  	}
  }
  
  /*! \note
   *  The following function was taken from GQview, and is covered by this copyright. 
   *  The name of the function was changed from pixbuf_copy_mirror to 
   *  gdk_pixbuf_mirror_rotate.
   *
   * GQview
   * (C) 2002 John Ellis
   *
   * Author: John Ellis
   *
   * This software is released under the GNU General Public License (GNU GPL).
   * Please read the included file COPYING for more information.
   * This software comes with no warranty of any kind, use at your own risk!
   */
  
  /*! \brief Mirror and flip a GdkPixbuf.
   *  \par Function Description
   *  This function will mirror and/or flip the source GdkPixbuf.
   *  To do a 180 degree rotation, set both mirror and flip to TRUE.
   *  If mirror and flip are FALSE, the source image is copied.
   *
   *  \param [in] src     Source image to operate on.
   *  \param [in] mirror  Mirror image if set to TRUE.
   *  \param [in] flip    Flipped image if set to TRUE.
   *  \return Updated copy of source image with operations performed.
   */
  GdkPixbuf *gdk_pixbuf_mirror_flip(GdkPixbuf *src, gint mirror, gint flip)
  {
  	GdkPixbuf *dest;
  	gint has_alpha;
  	gint w, h, srs;
  	gint drs;
  	guchar *s_pix;
          guchar *d_pix;
  	guchar *sp;
          guchar *dp;
  	gint i, j;
  	gint a;
  
  	if (!src) return NULL;
  
  	w = gdk_pixbuf_get_width(src);
  	h = gdk_pixbuf_get_height(src);
  	has_alpha = gdk_pixbuf_get_has_alpha(src);
  	srs = gdk_pixbuf_get_rowstride(src);
  	s_pix = gdk_pixbuf_get_pixels(src);
  
  	dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB, has_alpha, 8, w, h);
  	drs = gdk_pixbuf_get_rowstride(dest);
  	d_pix = gdk_pixbuf_get_pixels(dest);
  
  	a = has_alpha ? 4 : 3;
  
  	for (i = 0; i < h; i++)
  		{
  		sp = s_pix + (i * srs);
  		if (flip)
  			{
  			dp = d_pix + ((h - i - 1) * drs);
  			}
  		else
  			{
  			dp = d_pix + (i * drs);
  			}
  		if (mirror)
  			{
  			dp += (w - 1) * a;
  			for (j = 0; j < w; j++)
  				{
  				*(dp++) = *(sp++);	/* r */
  				*(dp++) = *(sp++);	/* g */
  				*(dp++) = *(sp++);	/* b */
  				if (has_alpha) *(dp) = *(sp++);	/* a */
  				dp -= (a + 3);
  				}
  			}
  		else
  			{
  			for (j = 0; j < w; j++)
  				{
  				*(dp++) = *(sp++);	/* r */
  				*(dp++) = *(sp++);	/* g */
  				*(dp++) = *(sp++);	/* b */
  				if (has_alpha) *(dp++) = *(sp++);	/* a */
  				}
  			}
  		}
  
  	return dest;
  }
  #endif
  
  
  
  1.1                  eda/geda/gaf/libgeda/src/i_vars.c
  
  Index: i_vars.c
  ===================================================================
  /* gEDA - GPL Electronic Design Automation
   * libgeda - gEDA's Library
   * Copyright (C) 1998-2000 Ales V. Hvezda
   *
   * 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.
   *
   * This program 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 this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
   */
  #include <config.h>
  #include <stdio.h>
  
  #include <gtk/gtk.h>
  #include <libguile.h>
  
  #include "defines.h"
  #include "struct.h"
  #include "globals.h"
  #include "o_types.h"
  #include "colors.h"
  #include "papersizes.h"
  #include "i_vars.h"
  
  #include "../include/prototype.h"
  
  #ifdef HAVE_LIBDMALLOC
  #include <dmalloc.h>
  #endif
  
  /*! \def INIT_STR(w, name, str) */
  #define INIT_STR(w, name, str) {                                        \
          if ((w)->name) {                                                \
                  free((w)->name);                                        \
          }                                                               \
          (w)->name = g_strdup(((default_ ## name) != NULL) ?             \
                               (default_ ## name) : (str));               \
  }
  
  /* \note 
   * Kazu Hirata <kazu@xxxxxxxx> on July 16, 1999 - Added these absolute
   * defaults used when default_... is NULL.
   */
  #define DEFAULT_SERIES_NAME      "untitled"
  #define DEFAULT_UNTITLED_NAME    "untitled"
  #define DEFAULT_SCHEME_DIRECTORY "./"
  #define DEFAULT_FONT_DIRECTORY   "../lib/sym/font"
  #define DEFAULT_BITMAP_DIRECTORY "../lib/bitmaps"
  #define DEFAULT_BUS_RIPPER_SYMNAME "busripper-1.sym"
  #define DEFAULT_POSTSCRIPT_PROLOG  "prolog.ps"
  #define DEFAULT_ALWAYS_PROMOTE_ATTRIBUTES ""
  
  int   default_init_right = WIDTH_C;
  int   default_init_bottom = HEIGHT_C;
  char *default_series_name = NULL;
  char *default_untitled_name = NULL;
  char *default_font_directory = NULL;
  char *default_scheme_directory = NULL;
  char *default_bitmap_directory = NULL;
  char *default_bus_ripper_symname = NULL;
  char *default_postscript_prolog = NULL;
  char *default_always_promote_attributes = NULL;
  
  /*! \brief Initialize variables in TOPLEVEL object
   *  \par Function Description
   *  This function will initialize variables to default values.
   *
   *  \param [out] w_current  The TOPLEVEL object to be updated.
   *
   */
  void i_vars_libgeda_set(TOPLEVEL *w_current)
  {
    w_current->init_right   = default_init_right;
    w_current->init_bottom  = default_init_bottom;
  
    /* you cannot free the default* strings here since new windows */
    /* need them */
    INIT_STR(w_current, series_name     , DEFAULT_SERIES_NAME     );
    INIT_STR(w_current, untitled_name   , DEFAULT_UNTITLED_NAME   );
    INIT_STR(w_current, font_directory  , DEFAULT_FONT_DIRECTORY  );
    INIT_STR(w_current, scheme_directory, DEFAULT_SCHEME_DIRECTORY);
    INIT_STR(w_current, bitmap_directory, DEFAULT_BITMAP_DIRECTORY);
    INIT_STR(w_current, bus_ripper_symname, DEFAULT_BUS_RIPPER_SYMNAME);
    INIT_STR(w_current, postscript_prolog,  DEFAULT_POSTSCRIPT_PROLOG);
    INIT_STR(w_current, always_promote_attributes, DEFAULT_ALWAYS_PROMOTE_ATTRIBUTES);
  
  }
  
  /*! \brief Set all names in TOPLEVEL object to default.
   *  \par Function Description
   *  This function will set all of the names in the TOPLEVEL w_current variable
   *  to their default.
   *
   *  \param [out] w_current  The TOPLEVEL object to set to defaults.
   *
   */
  void i_vars_setnames(TOPLEVEL *w_current)
  {
    w_current->series_name        = g_strdup (DEFAULT_SERIES_NAME     );
    w_current->untitled_name      = g_strdup (DEFAULT_UNTITLED_NAME   );
    w_current->font_directory     = g_strdup (DEFAULT_FONT_DIRECTORY  );
    w_current->scheme_directory   = g_strdup (DEFAULT_SCHEME_DIRECTORY);
    w_current->bitmap_directory   = g_strdup (DEFAULT_BITMAP_DIRECTORY);
    w_current->bus_ripper_symname = g_strdup (DEFAULT_BUS_RIPPER_SYMNAME);
    w_current->always_promote_attributes = g_strdup (DEFAULT_ALWAYS_PROMOTE_ATTRIBUTES);
  }
  
  /*! \brief Free default names
   *  \par Function Description
   *  This function will free all of the default variables for libgeda.
   *
   */
  void i_vars_freenames()
  {
    free(default_series_name);
    free(default_untitled_name);
    free(default_font_directory);
    free(default_scheme_directory);
    free(default_bitmap_directory);
    free(default_bus_ripper_symname);
    free(default_postscript_prolog);
    free(default_always_promote_attributes);
  }
  
  
  
  1.1                  eda/geda/gaf/libgeda/src/libgeda.c
  
  Index: libgeda.c
  ===================================================================
  /* gEDA - GPL Electronic Design Automation
   * libgeda - gEDA's library
   * Copyright (C) 1998, 1999, 2000 Kazu Hirata / Ales Hvezda
   *
   * 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.
   *
   * This program 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 this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
   */
  #include <config.h>
  
  #include <stdio.h>
  #ifdef HAVE_STRING_H
  #include <string.h>
  #endif
  #ifdef HAVE_STRARG_H
  #include <stdarg.h>
  #endif
  #ifdef HAVE_STDLIB_H
  #include <stdlib.h>
  #endif
  
  #include <gtk/gtk.h>
  #include <libguile.h>
  
  #include "defines.h"
  #include "struct.h"
  #include "globals.h"
  
  #include "../include/prototype.h"
  
  #ifdef HAVE_LIBDMALLOC
  #include <dmalloc.h>
  #endif
  
  /*! \brief Perform runtime initialization of libgeda library.
   *  \par Function Description
   *  This function is responsible for making sure that any runtime
   *  initialization is done for all the libgeda routines.  It should
   *  be called before any other libgeda functions are called.
   *
   */
  void libgeda_init(void)
  {
    char *new_data=NULL;
    char *geda_data = getenv("GEDADATA");
  
    /* This stuff reverted on 2.17.2005 by SDB in response to W. Hoch. */
    if (geda_data == NULL) {
      new_data = g_strdup_printf("GEDADATA=%s", GEDADATADIR);
      putenv(new_data);
      /*free(new_data); putenv takes over the memory? */
  
      /* We'll use this someday. . . . . */
      /* g_setenv ("GEDADATA", GEDADATADIR, FALSE); */ /* requires glib-2.4.* */
    }
  
    s_toplevel_init ();
    s_clib_init();
    s_slib_init();
    s_menu_init();
    s_attrib_init();
    s_color_init();
  
    o_text_init(); 
  
    g_register_libgeda_funcs();
  }
  
  
  
  
  
  1.12      +879 -678  eda/geda/gaf/libgeda/src/m_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: m_basic.c
  ===================================================================
  RCS file: m_basic.c
  diff -N m_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ m_basic.c	5 Jul 2006 03:13:38 -0000	1.12
  @@ -0,0 +1,1105 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h" /* why should I include these hack, just for prototype ? */
  +#include "globals.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \brief Convert a x coordinate to mils.
  + *  \par Function Description
  + *  Convert a x coordinate to mils.
  + *
  + *  \param [in] w_current  The TOPLEVEL object
  + *  \param [in] val        The x coordinate to convert
  + *  \return The coordinate value in mils.
  + */
  +int mil_x(TOPLEVEL *w_current, int val)
  +{
  +  double i;
  +  double fval;
  +  int j;
  +
  +#if 0 /* removed for speed improvements */
  +  double fw0,fw1,fw,fval;
  +  fw1 = w_current->page_current->right;
  +  fw0 = w_current->page_current->left;
  +  fw  = w_current->width;
  +#endif
  +
  +  fval = val;
  +  i = fval * w_current->page_current->to_world_x_constant + 
  +  w_current->page_current->left;
  +
  +  /* i -= mil_x_tw2;
  +     i = ((i) / 100 ) * 100; I don't think we need this 
  +     i += mil_x_tw1;*/
  +
  +
  +#ifdef HAS_RINT
  +  j = rint(i);
  +#else
  +  j = i;
  +#endif
  +
  +  return(j);
  +}
  +
  +/*! \brief Convert a y coordinate to mils
  + *  \par Function Description
  + *  Convert a y coordinate to mils
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] val        The y coordinate to convert.
  + *  \return The coordinate value in mils.
  + */
  +int mil_y(TOPLEVEL *w_current, int val)
  +{
  +  double i;
  +  double fval;
  +  int j;
  +
  +#if 0 /* removed for speed improvements */
  +  double fw0,fw1,fw,fval;
  +  fw1 = w_current->page_current->bottom;
  +  fw0 = w_current->page_current->top;
  +  fw  = w_current->height;
  +#endif
  +
  +  fval = w_current->height - val; 
  +  i = fval * w_current->page_current->to_world_y_constant +
  +  w_current->page_current->top;
  +
  +  /* i = ((i) / 100 ) * 100; I don't think we need this */
  +  /* i += mil_y_tw1; or this*/
  +
  +#ifdef HAS_RINT
  +  j = rint(i);
  +#else
  +  j = i;
  +#endif
  +
  +  return(j);
  +}
  +
  +/*! \brief Convert a x coordinate to pixels.
  + *  \par Function Description
  + *  Convert a x coordinate to pixels.
  + *
  + *  \param [in] w_current  The TOPLEVEL object
  + *  \param [in] val        The x coordinate to convert
  + *  \return The coordinate value in pixels.
  + */
  +int pix_x(TOPLEVEL *w_current, int val)
  +{
  +
  +  double i;
  +  int j;
  +
  +#if 0 /* removed for speed */
  +  double fs,f0,f1,f;
  +  f0 = w_current->page_current->left;
  +  f1 = w_current->page_current->right;
  +  fs = w_current->width;
  +  f = w_current->width / (f1 - f0);
  +#endif
  +
  +
  +  i = w_current->page_current->to_screen_x_constant * 
  +  (double)(val - w_current->page_current->left);
  +
  +#ifdef HAS_RINT
  +  j = rint(i);
  +#else
  +  j = i;
  +#endif
  +
  +  /* this is a temp solution to fix the wrapping associated with */
  +  /* X coords being greated/less than than 2^15 */
  +  if (j >= 32768) {
  +    j = 32767;
  +  }
  +  if (j <= -32768) {
  +    j = -32767;
  +  }
  +
  +  return(j);
  +}
  +
  +/*! \brief Convert a y coordinate to pixels.
  + *  \par Function Description
  + *  Convert a y coordinate to pixels.
  + *
  + *  \param [in] w_current  The TOPLEVEL object
  + *  \param [in] val        The y coordinate to convert
  + *  \return The coordinate value in pixels.
  + */
  +int pix_y(TOPLEVEL *w_current, int val)
  +{
  +  double i;
  +  int j;
  +
  +#if 0 /* removed for speed */
  +  double fs,f0,f1,f;
  +  f0 = w_current->page_current->top;
  +  f1 = w_current->page_current->bottom;
  +  fs = w_current->height;
  +  f = fs / (f1 - f0); /* fs was w_current->height */
  +#endif
  +  i = w_current->height - (
  +                           w_current->page_current->to_screen_y_constant * 
  +                           (double)(val - w_current->page_current->top)); 
  +
  +#ifdef HAS_RINT
  +  j = rint(i);
  +#else
  +  j = i;
  +#endif
  +
  +  /* this is a temp solution to fix the wrapping associated with */
  +  /* X coords being greated/less than than 2^15 */
  +  if (j >= 32768) {
  +    j = 32767;
  +  }
  +  if (j <= -32768) {
  +    j = -32767;
  +  }
  +
  +  return(j);
  +}
  +
  +/*! \brief Transform WORLD coordinates to SCREEN coordinates
  + *  \par Function Description
  + *  This function takes in WORLD x/y coordinates and
  + *  transforms them to SCREEN x/y coordinates.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  x          The x coordinate in WORLD units.
  + *  \param [in]  y          The y coordinate in WORLD units.
  + *  \param [out] mil_x      The x coordinate in SCREEN units.
  + *  \param [out] mil_y      The y coordinate in SCREEN units.
  + *  \note Question: why are we returning in mil_x and mil_y
  + *                  if this is WORLD to SCREEN shouldn't SCREEN
  + *                  coordinates be returned in x and y?
  + */
  +void WORLDtoSCREEN(TOPLEVEL *w_current, int x, int y, int *mil_x, int *mil_y)
  +{
  +  *mil_x = pix_x(w_current, x);
  +  *mil_y = pix_y(w_current, y);
  +}
  +
  +/*! \brief Transform WORLD coordinates to WORLD coordinates
  + *  \par Function Description
  + *  This function takes in SCREEN x/y coordinates and
  + *  transforms them to WORLD x/y coordinates.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  mx         The x coordinate in SCREEN units.
  + *  \param [in]  my         The y coordinate in SCREEN units.
  + *  \param [out] x          The x coordinate in WORLD units.
  + *  \param [out] y          The y coordinate in WORLD units.
  + *  \note Question: why are we returning in x and y
  + *                  if this is SCREEN to WORLD shouldn't WORLD
  + *                  coordinates be returned in mx and my?
  + */
  +void SCREENtoWORLD(TOPLEVEL *w_current, int mx, int my, int *x, int *y)      
  +{
  +  if (w_current->snap) { 
  +    *x = snap_grid(w_current, mil_x(w_current, mx));
  +    *y = snap_grid(w_current, mil_y(w_current, my));
  +  } else {
  +    *x = mil_x(w_current, mx);
  +    *y = mil_y(w_current, my);
  +  }
  +
  +#if 0
  +  *x = mil_x(w_current, mx);
  +  *y = mil_y(w_current, my);
  +#endif
  +
  +}
  +
  +/*! \brief Find the closest grid coordinate.
  + *  \par Function Description
  + *  This function snaps the current input coordinate to the
  + *  closest grid coordinate.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] input      The coordinate to snap.
  + *  \return The closest grid coordinate to the input.
  + */
  +int snap_grid(TOPLEVEL *w_current, int input)
  +{
  +  int p, m, n;
  +  int sign, value, snap_grid;
  +	
  +  if (!w_current->snap) {
  +    return(input);
  +  }
  +
  +		
  +  snap_grid = w_current->snap_size;
  +
  +  /* this code was inspired from killustrator, it's much simpler than mine */
  +  sign = ( input < 0 ? -1 : 1 );
  +  value = abs(input);
  +
  +  p = value / snap_grid;
  +  m = value % snap_grid;
  +  n = p * snap_grid;
  +  if (m > snap_grid / 2)
  +  n += snap_grid;
  +
  +#if DEBUG 
  +  printf("p: %d\n", p);
  +  printf("m: %d\n", m);
  +  printf("m > snap_grid / 2: %d\n", (m > snap_grid / 2));
  +  printf("n: %d\n", n);
  +  printf("n*s: %d\n", n*sign);
  +#endif
  +
  +  return(sign*n);
  +
  +#if 0 /* working snap code, crude, slow */
  +  int interm; 
  +  int final;
  +  int power;
  +  int itop;
  +	
  +  power = snap_grid;
  +  itop = input / power;
  +  interm = abs(input % power);
  +
  +  if (interm > 0 && interm < snap_grid/2) {	
  +    interm = 0;
  +  } else if (interm >= snap_grid/2 && interm <= snap_grid) {
  +    interm = snap_grid;
  +  }
  +
  +  if (input >= 0) {	
  +    final = itop*snap_grid+interm;
  +  } else if (input < 0) {
  +    final = itop*snap_grid-interm;
  +  }
  +
  +  return(final);
  +#endif
  +
  +}                               
  +
  +/*! \brief Get absolute SCREEN coordinate.
  + *  \par Function Description
  + *  Get absolute SCREEN coordinate.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] val        The coordinate to convert.
  + *  \return The converted SCREEN coordinate.
  + */
  +int SCREENabs(TOPLEVEL *w_current, int val)
  +{
  +  double fs,f0,f1,f;
  +
  +  double i;
  +  int j;
  +
  +  f0 = w_current->page_current->left;
  +  f1 = w_current->page_current->right;
  +  fs = w_current->width;
  +  f = w_current->width / (f1 - f0);
  +  i = f * (double)(val);
  +
  +#ifdef HAS_RINT
  +  j = rint(i);
  +#else
  +  j = i;
  +#endif
  +
  +  return(j);
  +
  +}
  +
  +/*! \brief Get absolute WORLD coordinate.
  + *  \par Function Description
  + *  Get absolute WORLD coordinate.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] val        The coordinate to convert.
  + *  \return The converted WORLD coordinate.
  + */
  +int WORLDabs(TOPLEVEL *w_current, int val)
  +{
  +  double fw0,fw1,fw,fval;
  +
  +  double i;
  +  int j;
  +
  +  fw1 = w_current->page_current->right;
  +  fw0 = w_current->page_current->left;
  +  fw  = w_current->width;
  +  fval = val;
  +  i = fval * (fw1 - fw0) / fw;
  +
  +  /* i -= mil_x_tw2;
  +     i = ((i) / 100 ) * 100; I don't think we need this 
  +     i += mil_x_tw1;*/
  +
  +
  +#ifdef HAS_RINT
  +  j = rint(i);
  +#else
  +  j = i;
  +#endif
  +
  +  return(j);
  +}
  +
  +/*! \brief Set the contraints for the current page.
  + *  \par Function Description
  + *  This function will set the current page constraints.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in,out] page       The PAGE object to set constraints on.
  + *  \param [in]     xmin       The minimum x coordinate for the page.
  + *  \param [in]     xmax       The maximum x coordinate for the page.
  + *  \param [in]     ymin       The minimum y coordinate for the page.
  + *  \param [in]     ymax       The maximum y coordinate for the page.
  + */
  +void set_window(TOPLEVEL *w_current, PAGE *page,
  +                int xmin, int xmax, int ymin, int ymax)
  +{
  +  double fs,f0,f1;
  +  double fw0,fw1,fw;
  +
  +  page->left   = xmin;
  +  page->right  = xmax;
  +  page->top    = ymin; 
  +  page->bottom = ymax;
  +
  +  /* now do the constant setups */
  +
  +  /* pix_x */
  +  f0 = page->left;
  +  f1 = page->right;
  +  fs = w_current->width;
  +  page->to_screen_x_constant = fs / (f1 - f0);
  +
  +  /* pix_y */
  +  f0 = page->top;
  +  f1 = page->bottom;
  +  fs = w_current->height;
  +  page->to_screen_y_constant = fs / (f1 - f0); 
  +
  +  /* mil_x */
  +  fw1 = page->right;
  +  fw0 = page->left;
  +  fw  = w_current->width;
  +  page->to_world_x_constant = (fw1 - fw0) / fw;
  +
  +  /* mil_y */
  +  fw1 = page->bottom;
  +  fw0 = page->top;
  +  fw  = w_current->height;
  +  page->to_world_y_constant = (fw1 - fw0) / fw;
  +}
  +
  +
  +/*! \brief Get the grid x coordinate for snap.
  + *  \par Function Description
  + *  Get the grid x coordinate for snap.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] in         The x coordinate.
  + *  \return The closest grid coordinate to in.
  + */
  +int fix_x(TOPLEVEL *w_current, int in)
  +{
  +  int value;
  +  int ret;
  +
  +  if (in > w_current->width) { 
  +    in = w_current->width;
  +  }
  +	
  +  if (!w_current->snap)
  +  return(in);
  +
  +  value = mil_x(w_current, in);	
  +
  +  ret = pix_x(w_current, snap_grid(w_current, value));
  +  return(ret);
  +}
  +
  +/*! \brief Get the grid y coordinate for snap.
  + *  \par Function Description
  + *  Get the grid y coordinate for snap.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] in         The y coordinate.
  + *  \return The closest grid coordinate to in.
  + */
  +int fix_y(TOPLEVEL *w_current, int in)
  +{
  +  int value;
  +  int ret;
  +
  +  if (in > w_current->height) { 
  +    in = w_current->height;
  +  }
  +
  +  if (!w_current->snap)
  +  return(in);
  +
  +
  +  value = mil_y(w_current, in);	
  +  ret = pix_y(w_current, snap_grid(w_current, value));
  +  return(ret);
  +}
  +
  +/*! \brief Checks if a point is snapped.
  + *  \par Function Description
  + *  This function checks if a point is snapped.
  + *
  + *  \param [in] val  The point to check.
  + *  \return 0 if point (x) is snapped, non-zero otherwise
  + *
  + *  \note This function is unused for now.
  + */
  +int on_snap(int val)
  +{
  +  return( (val / 100)*100 - val);
  +}
  +
  +/*! \brief */
  +typedef struct st_halfspace HALFSPACE;
  +/*! \brief */
  +typedef struct st_point sPOINT;
  +
  +/*! \brief */
  +struct st_halfspace {
  +  int left; /* these are booleans */
  +  int top;
  +  int right; 
  +  int bottom; 
  +};
  +
  +/*! \brief */
  +struct st_point {
  +	int x, y;
  +};
  +
  +/* \note 
  + * encode_halfspace and clip are part of the cohen-sutherland clipping
  + * algorithm.  They are used to determine if an object is visible or not 
  + */
  +/*! \brief Encode SCREEN coordinates as halfspace matrix.
  + *  \par Function Description
  + *  This function takes a point and checks if it is in the bounds
  + *  of the current TOPLEVEL object's page coordinates. It
  + *  handles points with SCREEN coordinates.
  + *  
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  point      The point in SCREEN coordinates to be checked.
  + *  \param [out] halfspace  The created HALFSPACE structure.
  + *
  + *  \warning halfspace must be allocated before this function is called
  + */
  +static void SCREENencode_halfspace(TOPLEVEL *w_current, sPOINT *point, HALFSPACE *halfspace)
  +{
  +  halfspace->left = point->x < 0;
  +  halfspace->right = point->x > w_current->width;
  +  halfspace->bottom = point->y > w_current->height;
  +  halfspace->top = point->y < 0;
  +}
  +
  +/*! \brief Encode WORLD coordinates as halfspace matrix.
  + *  \par Function Description
  + *  This function takes a point and checks if it is in the bounds
  + *  of the current TOPLEVEL object's page coordinates. It
  + *  handles points with WORLD coordinates.
  + *  
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  point      The point in WORLD coordinates to be checked.
  + *  \param [out] halfspace  The created HALFSPACE structure.
  + *
  + *  \warning halfspace must be allocated before this function is called
  + */
  +static void WORLDencode_halfspace(TOPLEVEL *w_current, sPOINT *point, HALFSPACE *halfspace)
  +{
  +  halfspace->left = point->x < w_current->page_current->left;
  +  halfspace->right = point->x > w_current->page_current->right;
  +  halfspace->bottom = point->y > w_current->page_current->bottom;
  +  halfspace->top = point->y < w_current->page_current->top;
  +}
  +
  +/*! \brief Calculate the cliping region for a set of coordinates.
  + *  \par Function Description
  + *  This function will check the provided set of coordinates to see if
  + *  they fall within a clipping region.  If they do the coordinates will
  + *  be changed to reflect only the region no covered by the clipping window.
  + *  All coordinates should be in SCREEN units.
  + *
  + *  \param [in] w_current  The current TOPLEVEL object.
  + *  \param [in,out] x1     x coordinate of the first screen point.
  + *  \param [in,out] y1     y coordinate of the first screen point.
  + *  \param [in,out] x2     x coordinate of the second screen point.
  + *  \param [in,out] y2     y coordinate of the second screen point.
  + *  \return TRUE if coordinates are now visible, FALSE otherwise.
  + */
  +int SCREENclip_change(TOPLEVEL *w_current,int *x1, int *y1, int *x2, int *y2)
  +{
  +  HALFSPACE half1, half2; 
  +  HALFSPACE tmp_half;
  +  sPOINT tmp_point;
  +  sPOINT point1, point2;
  +  float slope;
  +  int in1, in2, done;
  +  int visible;
  +  int w_l, w_t, w_r, w_b;
  +
  +  point1.x = *x1;
  +  point1.y = *y1;
  +  point2.x = *x2;
  +  point2.y = *y2;
  +
  +
  +  w_l = 0;
  +  w_t = 0;
  +  w_r = w_current->width;
  +  w_b = w_current->height;
  +
  +
  +  done = FALSE;
  +  visible = FALSE;
  +
  +  do {
  +    SCREENencode_halfspace(w_current, &point1, &half1);
  +    SCREENencode_halfspace(w_current, &point2, &half2);
  +
  +#if DEBUG
  +    printf("starting loop\n");
  +    printf("1 %d %d %d %d\n", half1.left, half1.top, half1.right, half1.bottom);
  +    printf("2 %d %d %d %d\n", half2.left, half2.top, half2.right, half2.bottom);
  +#endif
  +
  +    in1 = (!half1.left) && 
  +      (!half1.top) && 
  +      (!half1.right) && 
  +      (!half1.bottom);
  +
  +    in2 = (!half2.left) &&  
  +      (!half2.top) && 
  +      (!half2.right) && 
  +      (!half2.bottom);
  +
  +
  +    if (in1 && in2) { /* trivally accept */
  +      done = TRUE;
  +      visible = TRUE;
  +    } else if ( ((half1.left && half2.left) || 
  +                 (half1.right && half2.right)) ||
  +                ((half1.top && half2.top) || 
  +                 (half1.bottom && half2.bottom)) ) {
  +      done = TRUE; /* trivially reject */
  +      visible = FALSE;
  +    } else { /* at least one point outside */
  +      if (in1) {
  +        tmp_half = half1;
  +        half1 = half2; 
  +        half2 = tmp_half;
  +
  +        tmp_point = point1; 
  +        point1 = point2; 
  +        point2 = tmp_point;
  +      }
  +
  +      if (point2.x == point1.x) { /* vertical line */
  +        if (half1.top) {
  +          point1.y = w_t;
  +        } else if (half1.bottom) {
  +          point1.y = w_b;
  +        }
  +      } else { /* not a vertical line */
  +
  +				/* possible fix for alpha core dumping */
  +				/* assume the object is visible */
  +        if ((point2.x - point1.x) == 0) {
  +          return(TRUE);
  +        }
  +
  +        slope = (float) (point2.y - point1.y) / 
  +          (float) (point2.x - point1.x); 
  +
  +				/* possible fix for alpha core dumping */
  +				/* assume the object is visible */
  +        if (slope == 0.0) {
  +          return(TRUE);
  +        }
  +
  +        if (half1.left) {
  +          point1.y = point1.y + 
  +            (w_l - point1.x) * slope;
  +          point1.x = w_l;
  +        } else if (half1.right) {
  +          point1.y = point1.y + 
  +            (w_r - point1.x) * slope;
  +          point1.x = w_r;
  +        } else if (half1.bottom) {
  +          point1.x = point1.x +
  +            (w_b - point1.y) / slope;
  +          point1.y = w_b;
  +        } else if (half1.top) {
  +          point1.x = point1.x + 
  +            (w_t - point1.y) / slope;
  +          point1.y = w_t;
  +        }
  +      } /* end of not a vertical line */
  +    } /* end of at least one outside */
  +  } while (!done);
  +
  +  /*printf("after: %d %d %d %d\n", point1.x, point1.y, point2.x, point2.y);*/
  +  *x1 = point1.x;
  +  *y1 = point1.y;
  +  *x2 = point2.x;
  +  *y2 = point2.y;
  +  return(visible);
  +}
  +
  +/*! \brief Check if a set of coordinates are within a clipping region
  + *  \par Function Description
  + *  This function will check if the given set of coordinates
  + *  are within a clipping region. No action will be taken to change
  + *  the coordinates.
  + *
  + *  \param [in] w_current  The current TOPLEVEL object.
  + *  \param [in,out] x1     x coordinate of the first screen point.
  + *  \param [in,out] y1     y coordinate of the first screen point.
  + *  \param [in,out] x2     x coordinate of the second screen point.
  + *  \param [in,out] y2     y coordinate of the second screen point.
  + *  \return TRUE if coordinates are now visible, FALSE otherwise.
  + */
  +int clip_nochange(TOPLEVEL *w_current,int x1, int y1, int x2, int y2)
  +{
  +  HALFSPACE half1, half2; 
  +  HALFSPACE tmp_half;
  +  sPOINT tmp_point;
  +  sPOINT point1, point2;
  +  float slope;
  +  int in1, in2, done;
  +  int visible;
  +  int w_l, w_t, w_r, w_b;
  +
  +  point1.x = x1;
  +  point1.y = y1;
  +  point2.x = x2;
  +  point2.y = y2;
  +
  +  /*printf("before: %d %d %d %d\n", x1, y1, x2, y2);*/
  +
  +  w_l = w_current->page_current->left;
  +  w_t = w_current->page_current->top;
  +  w_r = w_current->page_current->right;
  +  w_b = w_current->page_current->bottom;
  +
  +  done = FALSE;
  +  visible = FALSE;
  +
  +  do {
  +    WORLDencode_halfspace(w_current, &point1, &half1);
  +    WORLDencode_halfspace(w_current, &point2, &half2);
  +
  +#if DEBUG
  +    printf("starting loop\n");
  +    printf("1 %d %d %d %d\n", half1.left, half1.top, half1.right, half1.bottom);
  +    printf("2 %d %d %d %d\n", half2.left, half2.top, half2.right, half2.bottom);
  +#endif
  +
  +    in1 = (!half1.left) && 
  +      (!half1.top) && 
  +      (!half1.right) && 
  +      (!half1.bottom);
  +
  +    in2 = (!half2.left) &&  
  +      (!half2.top) && 
  +      (!half2.right) && 
  +      (!half2.bottom);
  +
  +
  +    if (in1 && in2) { /* trivally accept */
  +      done = TRUE;
  +      visible = TRUE;
  +    } else if ( ((half1.left && half2.left) || 
  +                 (half1.right && half2.right)) ||
  +                ((half1.top && half2.top) || 
  +                 (half1.bottom && half2.bottom)) ) {
  +      done = TRUE; /* trivially reject */
  +      visible = FALSE;
  +    } else { /* at least one point outside */
  +      if (in1) {
  +        tmp_half = half1;
  +        half1 = half2; 
  +        half2 = tmp_half;
  +
  +        tmp_point = point1; 
  +        point1 = point2; 
  +        point2 = tmp_point;
  +      }
  +
  +      if (point2.x == point1.x) { /* vertical line */
  +        if (half1.top) {
  +          point1.y = w_t;
  +        } else if (half1.bottom) {
  +          point1.y = w_b;
  +        }
  +      } else { /* not a vertical line */
  +
  +				/* possible fix for alpha core dumping */
  +				/* assume the object is visible */
  +        if ((point2.x - point1.x) == 0) {
  +          return(TRUE);
  +        }
  +
  +        slope = (float) (point2.y - point1.y) / 
  +          (float) (point2.x - point1.x); 
  +
  +				/* possible fix for alpha core dumping */
  +				/* assume the object is visible */
  +        if (slope == 0.0) {
  +          return(TRUE);
  +        }
  +
  +        if (half1.left) {
  +          point1.y = point1.y + 
  +            (w_l - point1.x) * slope;
  +          point1.x = w_l;
  +        } else if (half1.right) {
  +          point1.y = point1.y + 
  +            (w_r - point1.x) * slope;
  +          point1.x = w_r;
  +        } else if (half1.bottom) {
  +          point1.x = point1.x +
  +            (w_b - point1.y) / slope;
  +          point1.y = w_b;
  +        } else if (half1.top) {
  +          point1.x = point1.x + 
  +            (w_t - point1.y) / slope;
  +          point1.y = w_t;
  +        }
  +      } /* end of not a vertical line */
  +    } /* end of at least one outside */
  +  } while (!done);
  +
  +  return(visible);
  +}
  +
  +/*! \brief Check if a bounding box is visible on the screen.
  + *  \par Function Description
  + *  This function checks if a given bounding box is visible on the screen.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] wleft      Left coordinate of the bounding box.
  + *  \param [in] wtop       Top coordinate of the bounding box.
  + *  \param [in] wright     Right coordinate of the bounding box.
  + *  \param [in] wbottom    Bottom coordinate of the bounding box.
  + *  \return TRUE if bounding box is visible, FALSE otherwise
  + */
  +int visible(TOPLEVEL *w_current, int wleft, int wtop, int wright, int wbottom)
  +{
  +  int visible=FALSE;
  +
  +  /* don't do object clipping if this is false */
  +  if (!w_current->object_clipping) {
  +    return(TRUE);
  +  }
  +
  +  visible = clip_nochange(w_current, wleft, wtop, wright, wtop);
  +
  +#if DEBUG 
  +  printf("vis1 %d\n", visible);
  +#endif
  +
  +  if (!visible) {
  +    visible = clip_nochange(w_current, wleft, wbottom, wright, wbottom);
  +  } else {
  +    return(visible);
  +  } 
  +
  +#if DEBUG
  +  printf("vis2 %d\n", visible);
  +#endif
  +
  +  if (!visible) {
  +    visible = clip_nochange(w_current, wleft, wtop, wleft, wbottom);
  +  } else {
  +    return(visible);
  +  } 
  +
  +#if DEBUG 
  +  printf("vis3 %d\n", visible);
  +#endif
  +
  +  if (!visible) {
  +    visible = clip_nochange(w_current, wright, wtop, wright, wbottom);
  +  } else {
  +    return(visible);
  +  } 
  +
  +#if DEBUG 
  +  printf("vis4 %d\n", visible);
  +#endif
  +
  +#if DEBUG
  +  printf("%d %d %d\n", wleft, w_current->page_current->top, wright);
  +  printf("%d %d %d\n", wtop, w_current->page_current->top, wbottom);
  +  printf("%d %d %d\n", wleft, w_current->page_current->right, wright);
  +  printf("%d %d %d\n", wtop, w_current->page_current->bottom, wbottom);
  +#endif
  +
  +  /* now check to see if bounding box encompasses the entire viewport */
  +  if (w_current->page_current->left >= wleft && 
  +      w_current->page_current->left <= wright  &&
  +      w_current->page_current->top <= wtop &&
  +      w_current->page_current->top >= wbottom ) {
  +    /*w_current->page_current->right >= wleft &&
  +      w_current->page_current->right <= wright &&
  +      w_current->page_current->bottom <= wtop &&
  +      w_current->page_current->bottom >= wbottom ) {*/
  +    visible = 1;
  +  } 
  +
  +#if DEBUG 
  +  printf("vis5 %d\n", visible);
  +#endif
  +
  +  return(visible);
  +}
  +
  +/*! \brief Rotate a point by an arbitrary angle.
  + *  \par Function Description
  + *  This function will rotate a point coordinate by an arbitrary angle
  + *  and return the new coordinate in the newx and newy parameters.
  + *
  + *  \param [in]  x      Input point x coordinate.
  + *  \param [in]  y      Input point y coordinate.
  + *  \param [in]  angle  Angle to rotate in degrees.
  + *  \param [out] newx   Output point x coordinate.
  + *  \param [out] newy   Output point y coordinate.
  + */
  +void rotate_point(int x, int y, int angle, int *newx, int *newy)
  +{
  +  double costheta, sintheta;
  +  double rad;
  +
  +  rad = angle*M_PI/180;
  +
  +  costheta = cos(rad);
  +  sintheta = sin(rad);
  +
  +  *newx = x * costheta - y * sintheta;
  +  *newy = x * sintheta + y * costheta;
  +}
  +
  +/*! \brief Rotate point in 90 degree increments only.
  + *  \par Function Description
  + *  This function takes a point coordinate and rotates it by
  + *  90 degrees at a time.  The new point coordinate is returned
  + *  in newx and newy.
  + *
  + *  \param [in]  x      Input point x coordinate.
  + *  \param [in]  y      Input point y coordinate.
  + *  \param [in]  angle  Angle to rotate by (90 degree increments only).
  + *  \param [out] newx   Output point x coordinate.
  + *  \param [out] newy   Output point y coordinate.
  + */
  +void rotate_point_90(int x, int y, int angle, int *newx, int *newy)
  +{
  +  double costheta=1; 
  +  double sintheta=0;
  +
  +  /* I could have used sine/cosine for this, but I want absolute 
  +   * accuracy */
  +  switch(angle) {
  +
  +    case(0):
  +      *newx = x;
  +      *newy = y; 
  +      return;
  +      break;
  +		
  +    case(90):
  +      costheta = 0;
  +      sintheta = 1;
  +      break;
  +		
  +    case(180):
  +      costheta = -1;
  +      sintheta = 0;
  +      break;
  +		
  +    case(270):
  +      costheta = 0;
  +      sintheta = -1;
  +      break;
  +  }
  +
  +  *newx = x * costheta - y * sintheta;
  +  *newy = x * sintheta + y * costheta;
  +
  +#if 0 /* fixed rotation */
  +
  +  *newx = -y ; 
  +  *newy = x ;
  +#endif
  +
  +}
  +
  +/*! \brief Convert Paper size to World coordinates.
  + *  \par Function Description
  + *  This function takes the paper size and converts it to
  + *  world coordinates. It supports landscape with a fixed aspect ratio.
  + *
  + *  \param [in]  width   Paper width. (units?)
  + *  \param [in]  height  Paper height. (units?)
  + *  \param [in]  border  Paper border size. (units?)
  + *  \param [out] right   Right world coordinate. (units?)
  + *  \param [out] bottom  Bottom world coordinate. (units?)
  + *
  + *  \todo Support more modes than just landscape only mode.
  + */
  +void PAPERSIZEtoWORLD(int width, int height, int border, int *right, int *bottom)
  +{
  +  float aspect;
  +
  +  aspect = (float) width / (float) height;
  +
  +#if DEBUG	
  +  printf("%f\n", aspect);
  +#endif
  +
  +  if (aspect < 1.333333333) {
  +    /* is this rint really needed? */
  +#ifdef HAS_RINT
  +    *right = (int) rint(width+border + 
  +			((height+border)*1.33333333 - (width+border)));
  +#else 
  +    *right = (int) width+border + 
  +      ((height+border)*1.33333333 - (width+border));
  +#endif
  +    *bottom = height+border;
  +  } else {
  +    *right = (int) width+border;	
  +    *bottom = (int) height+border + ((width+border)/1.33333333 - (height+border));
  +  }
  +	
  +#if DEBUG
  +  aspect = (float) *right / (float) *bottom;
  +  printf("%f\n", aspect);
  +#endif
  +
  +}
  +
  +/*! \deprecated
  + *  \brief Get the number of zoom's done.
  + *  \par Function Description
  + *  This function returns the number of zoom's that have been done.
  + *  It is computed from the zoom_factor since, the zoom_factor is
  + *  actually the magnification level.
  + *
  + *  \param [in] zoom_factor The current zoom factor being used.
  + *  \return The number of zoom's done so far.
  + */
  +#if 0 /* no longer used at all */
  +int return_zoom_number(int zoom_factor)
  +{
  +  double check=0;
  +  double factor;
  +  int i=0;
  +	
  +  if (zoom_factor != 0) {
  +    factor = zoom_factor;
  +    check = pow(2, i);
  +    while( check != factor && check < factor) {
  +      i++;
  +      check = pow(2, i);
  +    }
  +  } else {
  +    return(0);
  +  }
  +	
  +  return(i);
  +
  +#if 0 /* delete eventually */
  +  if (zoom_factor > 0) {
  +    return(log(zoom_factor)+2);
  +    /* return(log(zoom_factor+1));*/
  +  } else {
  +    return(1);
  +  }
  +#endif
  +}
  +#endif
  +
  +/*! \brief Rounds numbers by a power of 10.
  + *  \par Function Description
  + *  This function will round numbers using a power of 10 method.
  + *  For example:
  + *                1235 rounds to 1000
  + *                 670 rounds to  500
  + *               0.234 rounds to  0.2
  + *  integer values would be enough if there are no numbers smaller than 1 (hw)
  + *
  + *  \param [in] unrounded  The number to be rounded.
  + *  \return The rounded number.
  + */
  +/* rounds for example 1235 to 1000, 670 to 500, 0.234 to 0.2 ...
  +int would be enough if there are no numbers smaller 1 (hw)*/
  +double round_5_2_1(double unrounded)
  +{
  +  int digits;
  +  double betw_1_10;
  +	
  +  /*only using the automatic cast */
  +  digits = log10(unrounded);
  +  /* creates numbers between 1 and 10 */
  +  betw_1_10 = unrounded / pow(10,digits);
  +	
  +  if (betw_1_10 < 1.5) {
  +    return(pow(10,digits));
  +  }
  +  if (betw_1_10 > 1.4 && betw_1_10 < 3.5 ) {
  +    return(2*pow(10,digits));
  +  }
  +  if (betw_1_10 > 3.4 && betw_1_10 < 7.5 ) {
  +    return(5*pow(10,digits));
  +  }
  +  else {
  +    return(10*pow(10,digits));
  +  }
  +}
  
  
  
  1.27      +1508 -1107eda/geda/gaf/libgeda/src/o_arc_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_arc_basic.c
  ===================================================================
  RCS file: o_arc_basic.c
  diff -N o_arc_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_arc_basic.c	5 Jul 2006 03:13:38 -0000	1.27
  @@ -0,0 +1,1636 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#ifdef HAS_LIBGDGEDA
  +#include <gdgeda/gd.h>
  +#endif
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +#include "funcs.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \brief
  + *  \par Function Description
  + *  The function creates a new object of type arc and links it
  + *  with the object pointed by parameter object_list. As the
  + *  new object is then the last object of the list, its pointer
  + *  is returned to update the end of list pointer in the calling function.
  + *  The arc is defined by its center in parameters x and y.
  + *  The radius parameter specifies the radius of the arc. The start
  + *  angle is given by start_angle and the end angle by end_angle.
  + *  The line and fill type of the created arc are set to default.
  + *
  + *  All dimensions are in world unit, except start_angle and
  + *  end_angle in degrees.
  + *  
  + *  A new object of type OBJECT is allocated. Its type and color
  + *  are initilized. The description of the arc characteristics
  + *  are stored in a new ARC structure.
  + *
  + *  Now fixed for world coordinates.
  + *
  + *  \param [in] w_current    The TOPLEVEL object.
  + *  \param [in] object_list  
  + *  \param [in] type
  + *  \param [in] color
  + *  \param [in] x
  + *  \param [in] y
  + *  \param [in] radius
  + *  \param [in] start_angle
  + *  \param [in] end_angle
  + *  \return
  + */
  +OBJECT *o_arc_add(TOPLEVEL *w_current, OBJECT *object_list,
  +		  char type, int color,
  +		  int x, int y, int radius, int start_angle, int end_angle)
  +{
  +
  +  OBJECT *new_node;
  +
  +  new_node = s_basic_init_object("arc");
  +  new_node->type = type;
  +  new_node->color = color;
  +
  +  new_node->arc = (ARC *) malloc(sizeof(ARC));
  +
  +  /*! \note
  +   *  The ARC structure is initialized with the parameters.
  +   *  A default initialization is performed for the line and
  +   *  fill type to avoid misunderstood.
  +   *
  +   *  The functions relative to the use of the object are sets.
  +   */
  +
  +  /* World coordinates */
  +  new_node->arc->x      = x; 
  +  new_node->arc->y      = y; 
  +  new_node->arc->width  = 2 * radius;
  +  new_node->arc->height = 2 * radius;
  +
  +  /* PB : must check the sign of start_angle, end_angle ... */
  +  if(end_angle < 0) {
  +    start_angle = start_angle + end_angle;
  +    end_angle = -end_angle;
  +  }
  +  if(start_angle < 0) start_angle = 360 + start_angle;
  +  
  +  new_node->arc->start_angle = start_angle;
  +  new_node->arc->end_angle   = end_angle;
  +
  +  /* Default init */
  +  o_set_line_options(w_current, new_node,
  +                     END_NONE, TYPE_SOLID, 0, -1, -1);
  +  o_set_fill_options(w_current, new_node,
  +                     FILLING_HOLLOW, -1, -1, -1, -1, -1);
  +	
  +  o_arc_recalc(w_current, new_node);
  +
  +  /* new_node->graphical = arc; eventually */
  +	
  +  /* \todo questionable cast */
  +  new_node->draw_func = (void *) arc_draw_func;  
  +  /* \todo questionable cast */
  +  new_node->sel_func = (void *) select_func;
  +
  +  /* \note
  +   * The new object is linked to the object given in parameter object_list
  +   * and then returned as a pointer to the calling function.
  +   */
  +
  +  object_list = (OBJECT *) s_basic_link_object(new_node, object_list);
  +	
  +  return(object_list);
  +}
  +
  +/*! \brief 
  + *  \par Function Description
  + *  This function creates a new object representing an arc.
  + *
  + *  The values of the <B>o_current</B> pointed OBJECT are then copied to the new object.
  + *
  + *  The arc, the line options are initialized whereas the fill options are
  + *  initialized to passive values - as an arc can not be filled.
  + *
  + *  The new object is added to the end of the object list given by <B>list_tail</B>.
  + *  A pointer on it is returned for update purpose in the calling function.
  + *
  + *  \param [in] w_current  The TOPLEVEL object
  + *  \param [in] list_tail
  + *  \param [in] o_current
  + *  \return
  + */
  +OBJECT *o_arc_copy(TOPLEVEL *w_current, OBJECT *list_tail,
  +		   OBJECT *o_current)
  +{
  +  OBJECT *new_obj;
  +  ATTRIB *a_current;
  +  int color;
  +
  +  if (o_current->saved_color == -1) {
  +    color = o_current->color;
  +  } else {
  +    color = o_current->saved_color;
  +  }
  +
  +  new_obj = o_arc_add(w_current, list_tail, OBJ_ARC, color,
  +                      o_current->arc->x, o_current->arc->y, 
  +                      o_current->arc->width / 2,
  +                      o_current->arc->start_angle,
  +                      o_current->arc->end_angle);
  +  o_set_line_options(w_current, new_obj,
  +                     o_current->line_end, o_current->line_type,
  +                     o_current->line_width,
  +                     o_current->line_length, o_current->line_space);
  +  o_set_fill_options(w_current, new_obj,
  +                     FILLING_HOLLOW, -1, -1, -1, -1, -1);
  +	
  +  a_current = o_current->attribs;
  +  if (a_current) {
  +    while (a_current) {
  +
  +      /* head attrib node has prev = NULL */
  +      if (a_current->prev != NULL) {
  +        a_current->copied_to = new_obj;
  +      }
  +      a_current = a_current->next;
  +    }
  +  }
  +
  +  return(new_obj);
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *  This function modifies the internal values of the arc object
  + *  *object according to the whichone parameter.
  + *
  + *  The new values are given by <B>x</B> and/or <B>y</B>. Their meaning depends on the value of whichone.
  + *
  + *  If <B>whichone</B> is equal to #ARC_CENTER, the (<B>x</B>,<B>y</B>) point is taken as the new center
  + *  of the arc in world unit.
  + *
  + *  If <B>whichone</B> is equal to #ARC_RADIUS, the <B>x</B> parameter is taken to be the radius
  + *  of the arc in world unit. The <B>y</B> parameter is ignored.
  + *
  + *  If <B>whichone</B> is equal to #ARC_START_ANGLE, the <B>x</B> parameter is the starting angle of the arc.
  + *  <B>x</B> is in degrees. <B>y</B> is ignored.
  + *
  + *  If <B>whichone</B> is equal to #ARC_END_ANGLE, the <B>x</B> parameter is the ending angle of the arc.
  + *  <B>x</B> is in degrees. <B>y</B> is ignored.
  + *
  + *  The screen coordinates of the arc and its bounding box are computed again
  + *  after the change in world coordinates.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in,out] object     
  + *  \param [in]     x
  + *  \param [in]     y
  + *  \param [in]     whichone
  + */
  +void o_arc_modify(TOPLEVEL *w_current, OBJECT *object, 
  +		  int x, int y, int whichone)
  +{
  +
  +	switch(whichone) {
  +		case ARC_CENTER:
  +		/* modify the center of arc object */
  +		object->arc->x = x;
  +		object->arc->y = y;
  +		break;
  +		
  +		case ARC_RADIUS:
  +		/* modify the radius of arc object */
  +		object->arc->width  = 2 * x;
  +		object->arc->height = 2 * x;
  +		break;
  +
  +		case ARC_START_ANGLE:
  +		/* modify the start angle of the arc object */
  +		object->arc->start_angle = x;
  +		break;
  +
  +		case ARC_END_ANGLE:
  +		/* modify the end angle of the arc object */
  +		object->arc->end_angle = x;
  +		break;
  +
  +		default:
  +		break;
  +	}
  +
  +	/* update the screen coords and the bounding box */
  +	o_arc_recalc(w_current, object);
  +	
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *  This function reads a formatted text buffer describing an arc
  + *  in the gEDA file format and initializes the corresponding object.
  + *  This arc is linked to the end of the <B>object_list</B> pointed list.
  + *  Depending on the version of the file format the data extraction is
  + *  performed differently : currently pre-20000704 and 20000704 on one
  + *  hand and post-20000704 file format version on the other hand are supported.
  + *  The version is specified in string pointed by <B>fileformat_ver</B>.
  + *
  + *  To get information on the various file formats have a
  + *  look to the fileformats.html document.
  + *  
  + *  The object is initialized with the functions #o_set_line_options() and #o_set_fill_options().
  + *  The second one is only used to put initialize unused values for an arc as an arc can not be filled.
  + * 
  + *  The arc is allocated initialized and linked with the function #o_arc_add().
  + * 
  + *  A negative or null radius is not allowed.
  + *
  + *  \param [in] w_current    The TOPLEVEL object.
  + *  \param [in] object_list  
  + *  \param [in] buf
  + *  \param [in] release_ver
  + *  \param [in] fileformat_ver
  + *  \return
  + */
  +OBJECT *o_arc_read(TOPLEVEL *w_current, OBJECT *object_list, char buf[],
  +		   unsigned int release_ver, unsigned int fileformat_ver)
  +{
  +  char type; 
  +  int x1, y1;
  +  int radius;
  +  int start_angle, end_angle;
  +  int color;
  +  int arc_width, arc_length, arc_space;
  +  int arc_type;
  +  int arc_end;
  +
  +  /*! \note
  +   *  Depending on the version of the file format used to describe this arc,
  +   *  the buffer is parsed differently. The unknown parameters of the less
  +   *  restrictive - the oldest - file format are set to common values
  +   */
  +  if(release_ver <= VERSION_20000704) {
  +    sscanf(buf, "%c %d %d %d %d %d %d", &type,
  +           &x1, &y1, &radius, &start_angle, &end_angle, &color);
  +
  +    arc_width = 0;
  +    arc_end   = END_NONE;
  +    arc_type  = TYPE_SOLID;
  +    arc_space = -1;
  +    arc_length= -1;
  +  } else {
  +    sscanf(buf, "%c %d %d %d %d %d %d %d %d %d %d %d", &type,
  +           &x1, &y1, &radius, &start_angle, &end_angle, &color,
  +           &arc_width, &arc_end, &arc_type, &arc_length, &arc_space);
  +
  +  }
  +
  +  /* Error check */
  +  if (radius <= 0) {
  +    fprintf(stderr,
  +            "Found a zero radius arc [ %c %d, %d, %d, %d, %d, %d ]\n",
  +            type, x1, y1, radius, start_angle, end_angle, color);
  +    s_log_message
  +      ("Found a zero radius arc [ %c %d, %d, %d, %d, %d, %d ]\n",
  +       type, x1, y1, radius, start_angle, end_angle, color);
  +  }
  +	
  +  if (color < 0 || color > MAX_COLORS) {
  +    fprintf(stderr, "Found an invalid color [ %s ]\n", buf);
  +    s_log_message("Found an invalid color [ %s ]\n", buf);
  +    s_log_message("Setting color to WHITE\n");
  +    color = WHITE;
  +  }
  +
  +  /* Allocation and initialization */
  +  object_list = o_arc_add(w_current, object_list, OBJ_ARC, color,
  +                          x1, y1, radius, start_angle, end_angle);
  +  o_set_line_options(w_current, object_list,
  +                     arc_end, arc_type, arc_width, arc_length,
  +                     arc_space);
  +  o_set_fill_options(w_current, object_list,
  +                     FILLING_HOLLOW, -1, -1, -1,
  +                     -1, -1);
  +
  +  return(object_list);
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *  This function formats a string in the buffer <B>*buff</B> to describe
  + *  the arc object <B>*object</B>.
  + *  It follows the post-20000704 release file format that handle the
  + *  line type and filling options.
  + *  A pointer to the new allocated and formated string is returned.
  + *  The string must be freed at some point.
  + *
  + *  \param [in] object
  + *  \return
  + *
  + *  \todo EEK! there is a nasty non-snap bug here!
  + *        Basically the center isn't being snapped
  + *        in complex objects only it seems...
  + */
  +char *o_arc_save(OBJECT *object)
  +{
  +  int color;
  +  int x, y, radius, start_angle, end_angle;
  +  int arc_width, arc_length, arc_space;
  +  char *buf;
  +  OBJECT_END arc_end;
  +  OBJECT_TYPE arc_type;
  +
  +  /* radius, center and angles of the arc */
  +  radius      = object->arc->width / 2;
  +  x           = object->arc->x;
  +  y           = object->arc->y;
  +  start_angle = object->arc->start_angle;
  +  end_angle   = object->arc->end_angle;
  +
  +  /* line type parameters */
  +  arc_width  = object->line_width;
  +  arc_end    = object->line_end;
  +  arc_type   = object->line_type;
  +  arc_length = object->line_length;
  +  arc_space  = object->line_space;
  +
  +  /* Save the right color */
  +  if (object->saved_color == -1) {
  +    color = object->color;
  +  } else {
  +    color = object->saved_color;
  +  }
  +
  +  /* Describe a circle with post-20000704 file format */
  +  buf = g_strdup_printf("%c %d %d %d %d %d %d %d %d %d %d %d", object->type,
  +			x, y, radius, start_angle, end_angle, color,
  +			arc_width, arc_end, arc_type, arc_length, arc_space);
  +
  +  return(buf);
  +}
  +
  +
  +/*! \brief
  + *  \par Function Description
  + *  This function translates the arc described in the <B>object</B>
  + *  pointed structure by <B>dx</B> horizontally and <B>dy</B> vertically.
  + *  <B>dx</B> and <B>dy</B> are in screen unit.
  + *
  + *  The translation vector is converted in world unit. The translation
  + *  is made with <B>o_arc_translate_world()</B> that also updates the
  + *  screen coordinates and the bounding box.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] dx         
  + *  \param [in] dy         
  + *  \param [in] object
  + */
  +void o_arc_translate(TOPLEVEL *w_current, int dx, int dy, OBJECT *object)
  +{
  +  int world_dx, world_dy;
  +  
  +  if (object == NULL) {
  +    return;
  +  }
  +
  +  /* convert the translation vector in world unit */
  +  world_dx = SCREENabs(w_current, dx);
  +  world_dy = SCREENabs(w_current, dy);
  +  
  +  /* translate the arc */
  +  o_arc_translate_world(w_current, world_dx, world_dy, object);
  +
  +  /* screen coords and boundings are updated by _translate_world() */
  +	
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *  This function applies a translation of (<B>dx</B>,<B>dy</B>)
  + *  to the arc described in <B>*object</B>. <B>dx</B> and <B>dy</B> are in world unit.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] dx
  + *  \param [in] dy
  + *  \param [in] object
  + */
  +void o_arc_translate_world(TOPLEVEL *w_current, int dx, int dy,
  +			   OBJECT *object)
  +{
  +  if (object == NULL) {
  +    return;
  +  }
  +
  +  /* Do world coords */
  +  object->arc->x = object->arc->x + dx;
  +  object->arc->y = object->arc->y + dy;
  +
  +
  +  /* Recalculate screen coords from new world coords */
  +  o_arc_recalc(w_current, object);
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *  This function applies a rotation of center (<B>centerx</B>,<B>centery</B>)
  + *  and angle <B>angle</B> to the arc object <B>*object</B>.
  + *  The coordinates of the rotation center are in screen units.
  + *  The angle is in degree.
  + *
  + *  The rotation is made with th <B>o_arc_rotate_world()</B> function
  + *  that perform a rotation of <B>angle</B> and center
  + *  (<B>world_centerx</B>,<B>world_centery</B>) in world unit.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] centerx
  + *  \param [in] centery
  + *  \param [in] angle
  + *  \param [in] object
  + */
  +void o_arc_rotate(TOPLEVEL *w_current,
  +		  int centerx, int centery, int angle,
  +		  OBJECT *object)
  +{
  +  int world_centerx, world_centery;
  +
  +  /* convert the center of rotation to world unit */
  +  SCREENtoWORLD(w_current,
  +				centerx, centery,
  +                &world_centerx, &world_centery);
  +
  +  /* rotate the arc */
  +  o_arc_rotate_world(w_current,
  +					 world_centerx, world_centery, angle,
  +					 object);
  +
  +  /* screen coords and boundings are updated by _rotate_world() */
  +  
  +}                                   
  +
  +/*! \brief
  + *  \par Function Description
  + *  This function rotates the world coordinates of an arc of an angle
  + *  specified by <B>angle</B>. The center of the rotation is given by
  + *  (<B>world_centerx</B>,<B>world_centery</B>).
  + *
  + *  The arc is translated in order to put the center of the rotation
  + *  on the origin. The center of the arc is then rotated of the angle
  + *  specified by <B>angle</B>. The start angle of the arc is incremented by <B>angle</B>.
  + *
  + *  The arc is finally back translated to its previous location on the page.
  + *
  + *  <B>world_centerx</B> and <B>world_centery</B> are in world units, <B>angle</B> is in degrees.
  + *
  + *  \param [in] w_current      The TOPLEVEL object.
  + *  \param [in] world_centerx
  + *  \param [in] world_centery
  + *  \param [in] angle
  + *  \param [in] object
  + */
  +void o_arc_rotate_world(TOPLEVEL *w_current,
  +			int world_centerx, int world_centery, int angle,
  +			OBJECT *object)
  +{
  +  int x, y, newx, newy;
  +
  +  /* translate object to origin */
  +  object->arc->x -= world_centerx;
  +  object->arc->y -= world_centery;
  +
  +  /* get center, and rotate center */
  +  x = object->arc->x;
  +  y = object->arc->y;
  +  if(angle % 90 == 0) {
  +	  rotate_point_90(x, y, angle % 360, &newx, &newy);
  +  } else {
  +	  rotate_point(x, y, angle % 360, &newx, &newy);
  +  }
  +  object->arc->x = newx;
  +  object->arc->y = newy;
  +
  +  /* apply rotation to angles */
  +  object->arc->start_angle = (object->arc->start_angle + angle) % 360;
  +  /* end_angle is unchanged as it is the sweep of the arc */
  +  /* object->arc->end_angle = (object->arc->end_angle); */
  +
  +  /* translate object to its previous place */
  +  object->arc->x += world_centerx;
  +  object->arc->y += world_centery;
  +
  +  /* update the screen coords and the bounding box */
  +  o_arc_recalc(w_current, object);
  +  
  +}                                   
  +
  +/*! \brief
  + *  \par Function Description
  + *  This function mirrors the screen coordinates of an arc.
  + *  The symetry axis is given by the vertical line going
  + *  through the point (<B>centerx</B>,<B>centery</B>).
  + *  
  + *  <B>centerx</B> and <B>centery</B> are in screen unit.
  + *
  + *  The arc is translated in order to put the point (<B>centerx</B>,<B>centery</B>)
  + *  on the origin. The center of the arc is then mirrored. The start angle of
  + *  the arc and the sweep of the arc are also mirrored.
  + * 
  + *  The arc is finally back translated to its previous location on the page.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] centerx
  + *  \param [in] centery
  + *  \param [in] object
  + */
  +void o_arc_mirror(TOPLEVEL *w_current,
  +		  int centerx, int centery,
  +		  OBJECT *object)
  +{
  +  int world_centerx, world_centery;
  +
  +  /* convert mirror origin in world unit */
  +  SCREENtoWORLD(w_current, centerx, centery,
  +                &world_centerx, &world_centery);
  +
  +  /* mirror the arc */
  +  o_arc_mirror_world(w_current, world_centerx, world_centery, object);
  +
  +  /* screen coords and boundings are updated by _rotate_world() */
  +  
  +}
  +
  +/*! \brief Mirror the WORLD coordinates of an ARC.
  + *  \par Function Description
  + *  This function mirrors the world coordinates of an arc.
  + *  The symetry axis is given by the vertical line going through the point (<B>world_centerx</B>,<B>world_centery</B>).
  + *
  + *  The arc is translated in order to put the point (<B>world_centerx</B>,<B>world_centery</B>)
  + *  on the origin. The center of the arc is then mirrored. The start angle of the arc
  + *  and the sweep of the arc are also mirrored.
  + *
  + *  The arc is finally back translated to its previous location on the page.
  + *
  + *  \param [in] w_current      The TOPLEVEL object.
  + *  \param [in] world_centerx
  + *  \param [in] world_centery
  + *  \param [in] object
  + */
  +void o_arc_mirror_world(TOPLEVEL *w_current,
  +			int world_centerx, int world_centery,
  +			OBJECT *object)
  +{
  +  /* translate object to origin */
  +  object->arc->x -= world_centerx;
  +  object->arc->y -= world_centery;
  +
  +  /* get center, and mirror it (vertical mirror) */
  +  object->arc->x = -object->arc->x;
  +  object->arc->y =  object->arc->y;
  +
  +  /* apply mirror to angles (vertical mirror) */
  +  object->arc->start_angle = (180 - object->arc->start_angle) % 360;
  +  /* pb20011125 - start_angle *MUST* be positive */
  +  if(object->arc->start_angle < 0) object->arc->start_angle += 360;
  +  object->arc->end_angle = -object->arc->end_angle;
  +	
  +  /* translate object back to its previous position */
  +  object->arc->x += world_centerx;
  +  object->arc->y += world_centery;
  +
  +  /* update the screen coords and bounding box */
  +  o_arc_recalc(w_current, object);
  +	
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *  This function recalculates internal parameters in screen units
  + *  of an object containing an arc. The object is given as parameters <B>o_current</B>.
  + *  The calculation is done according to the zoom factor detailed in the <B>w_current</B>
  + *  pointed structure.
  + *  It also recalculates the <B>OBJECT</B> specific fields and the bounding box of the arc.
  + *  
  + *  The <B>OBJECT</B> specific fields are handled by the function <B>o_object_recalc()</B>
  + *  whereas bounding box - in screen units - is recalculated with the <B>get_arc_bounds()</B> function.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current
  + */
  +void o_arc_recalc(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int screen_x1, screen_y1, screen_x2, screen_y2;	
  +  int left, right, top, bottom;
  +	
  +  if (o_current->arc == NULL) {
  +    return;
  +  }
  +
  +  /* update the screen_x and screen_y fields of the arc */
  +  WORLDtoSCREEN(w_current, o_current->arc->x, o_current->arc->y, 
  +                &screen_x1, &screen_y1);  
  +
  +  o_current->arc->screen_x = screen_x1; /* x coord */
  +  o_current->arc->screen_y = screen_y1; /* y coord */
  +
  +  /* update the screen_width and screen_height fields of the arc */
  +  WORLDtoSCREEN(w_current,
  +                o_current->arc->x + o_current->arc->width,
  +                o_current->arc->y - o_current->arc->height, 
  +                &screen_x2, &screen_y2);  
  +
  +  o_current->arc->screen_width  = screen_x2 - screen_x1; /* width */
  +  o_current->arc->screen_height = screen_y2 - screen_y1; /* height */
  +
  +  /* recalculates the line type information in o_current */
  +  o_object_recalc(w_current, o_current);
  +
  +  /* recalculates the bounding box */
  +  get_arc_bounds(w_current, o_current, &left, &top, &right, &bottom);
  +  o_current->left   = left;
  +  o_current->top    = top;
  +  o_current->right  = right;
  +  o_current->bottom = bottom;
  +
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *  This function calculates the smallest rectangle the arc can be drawn into.
  + *  The <B>OBJECT</B> pointed by object is assumed to be an arc.
  + *  The <B>left</B>, <B>top</B>, <B>right</B> and <B>bottom</B> pointed integers define
  + *  this rectangle at the end of the function. It is expressed in screen units.
  + *
  + *  The process is divided into two steps : the first step is to calculate the
  + *  coordinates of the two ends of the arc and the coordinates of the center.
  + *  They form a first rectangle but (depending on the start angle and the sweep
  + *  of the arc) not the right.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  object
  + *  \param [out] left
  + *  \param [out] top
  + *  \param [out] right
  + *  \param [out] bottom
  + */
  +void get_arc_bounds(TOPLEVEL *w_current, OBJECT *object,
  +		    int *left, int *top, int *right, int *bottom)
  +{
  +  int x1, y1, x2, y2, x3, y3;
  +  int radius, start_angle, end_angle;
  +  int i, angle;
  +
  +  radius      = object->arc->screen_width / 2;
  +  start_angle = object->arc->start_angle % 360;
  +  end_angle   = object->arc->end_angle   % 360;
  +
  +  x1 = object->arc->screen_x;
  +  y1 = object->arc->screen_y;
  +  x2 = x1 + radius * cos(start_angle * M_PI / 180);
  +  y2 = y1 - radius * sin(start_angle * M_PI / 180);
  +  x3 = x1 + radius * cos((start_angle + end_angle) * M_PI / 180);
  +  y3 = y1 - radius * sin((start_angle + end_angle) * M_PI / 180);
  +
  +  *left   = (x1 < x2) ? ((x1 < x3) ? x1 : x3) : ((x2 < x3) ? x2 : x3);
  +  *right  = (x1 > x2) ? ((x1 > x3) ? x1 : x3) : ((x2 > x3) ? x2 : x3);
  +  *top    = (y1 < y2) ? ((y1 < y3) ? y1 : y3) : ((y2 < y3) ? y2 : y3);
  +  *bottom = (y1 > y2) ? ((y1 > y3) ? y1 : y3) : ((y2 > y3) ? y2 : y3);
  +
  +  /*! \note
  +   *  The previous rectangle is extended to the final one by checking
  +   *  whether the arc is over a main axis (vertical or horizontal).
  +   *  If so, the rectangle is extended in these directions.
  +   */
  +  angle = ((int) (start_angle / 90)) * 90;
  +  for(i = 0; i < 4; i++) {
  +    angle = angle + 90;
  +    if(angle < start_angle + end_angle) {
  +      if(angle % 360 == 0)   *right  = x1 + radius;
  +      if(angle % 360 == 90)  *top    = y1 - radius;
  +      if(angle % 360 == 180) *left   = x1 - radius;
  +      if(angle % 360 == 270) *bottom = y1 + radius;
  +    } else {
  +      break;
  +    }
  +  }
  +
  +  /* PB : bounding box has to take into account the width of the line it is
  +     composed with, ie adding/substracting half the width to this box */
  +  /* PB : but width is unknown here */	
  +   
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *  This function calculates the smallest rectangle the arc can be drawn into.
  + *  The <B>OBJECT</B> pointed by object is assumed to be an arc.
  + *  The <B>left</B>, <B>top</B>, <B>right</B> and <B>bottom</B> pointed integers define
  + *  this rectangle at the end of the function. It is expressed in world units.
  + *  The process is divided into two steps : the first step is to calculate the
  + *  coordinates of the two ends of the arc and the coordinates of the center.
  + *  They forms a first rectangle but (depending on the start angle and the
  + *  sweep of the arc) not the right.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  object
  + *  \param [out] left
  + *  \param [out] top
  + *  \param [out] right
  + *  \param [out] bottom
  + */
  +void world_get_arc_bounds(TOPLEVEL *w_current, OBJECT *object, int *left,
  +			  int *top, int *right, int *bottom)
  +{
  +  int x1, y1, x2, y2, x3, y3;
  +  int radius, start_angle, end_angle;
  +  int i, angle;
  +
  +  radius      = object->arc->width / 2;
  +  start_angle = object->arc->start_angle % 360;
  +  end_angle   = object->arc->end_angle   % 360;
  +
  +  x1 = object->arc->x;
  +  y1 = object->arc->y;
  +  x2 = x1 + radius * cos(start_angle * M_PI / 180);
  +  y2 = y1 + radius * sin(start_angle * M_PI / 180);
  +  x3 = x1 + radius * cos((start_angle + end_angle) * M_PI / 180);
  +  y3 = y1 + radius * sin((start_angle + end_angle) * M_PI / 180);
  +
  +  *left   = (x1 < x2) ? ((x1 < x3) ? x1 : x3) : ((x2 < x3) ? x2 : x3);
  +  *right  = (x1 > x2) ? ((x1 > x3) ? x1 : x3) : ((x2 > x3) ? x2 : x3);
  +  *bottom = (y1 < y2) ? ((y1 < y3) ? y1 : y3) : ((y2 < y3) ? y2 : y3);
  +  *top    = (y1 > y2) ? ((y1 > y3) ? y1 : y3) : ((y2 > y3) ? y2 : y3);
  +
  +  /*! \note
  +   *  The previous rectangle is extended to the final one
  +   *  by checking whether the arc is over a main axis (vertical or horizontal).
  +   *  If so, the rectangle is extended in these directions.
  +   */
  +  angle = ((int) (start_angle / 90)) * 90;
  +  for(i = 0; i < 4; i++) {
  +    angle = angle + 90;
  +    if(angle < start_angle + end_angle) {
  +      if(angle % 360 == 0)   *right  = x1 + radius;
  +      if(angle % 360 == 90)  *top    = y1 + radius;
  +      if(angle % 360 == 180) *left   = x1 - radius;
  +      if(angle % 360 == 270) *bottom = y1 - radius;
  +    } else {
  +      break;
  +    }
  +  }
  +
  +  /* PB : same problem as above */
  +}
  +
  +
  +/*! \brief
  + *  \par Function Description
  + *  This function writes in a postscript file the arc described by
  + *  the <B>o_current</B> pointed object.
  + *  The postscript resulting file is described by the <B>fp</B> file pointer.
  + *  
  + *  Parameters of the arc are extracted from object pointed by <B>o_current</B>
  + *  and formatted to suit future calls to specialized arc printing functions.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] fp         The postscript document to print to.
  + *  \param [in] o_current
  + *  \param [in] origin_x
  + *  \param [in] origin_y
  + */
  +void o_arc_print(TOPLEVEL *w_current, FILE *fp, OBJECT *o_current, 
  +		 int origin_x, int origin_y)
  +{
  +  int x, y, radius, start_angle, end_angle;
  +  int color;
  +  int arc_width, space, length;
  +  void (*outl_func)() = NULL;
  +
  +  if (o_current == NULL) {
  +    printf("got null in o_arc_print\n");
  +    return;
  +  }
  +	
  +  x      = o_current->arc->x;
  +  y      = o_current->arc->y;
  +  radius = o_current->arc->width / 2;
  +  start_angle = o_current->arc->start_angle;
  +  end_angle   = o_current->arc->end_angle;
  +  color  = o_current->color;
  +
  +  /*! \note
  +   *  Depending on the type of the line for this particular arc, the
  +   *  appropriate function is chosen among #o_arc_print_solid(),
  +   *  #o_arc_print_dotted(), #o_arc_print_dashed(), #o_arc_print_center() and #o_arc_print_phantom().
  +   *
  +   *  The needed parameters for each of these types are extracted from the <B>o_current</B> object.
  +   *  Depending on the type, unused parameters are set to -1.
  +   *  
  +   *  In the eventuality of a length and/or space null, the arc is printed solid to avoid and
  +   *  endless loop produced by other functions.
  +   */
  +
  +#if 0  /* was causing arcs which are solid to be much thinner compared to */
  +  /* lines, boxes, also of zero width */
  +  if (o_current->line_width > 0) {
  +    arc_width = o_current->line_width;
  +  } else {
  +    arc_width = 1;
  +  }
  +#endif
  +  arc_width = o_current->line_width;	/* Added instead of above */
  +  if (arc_width <= 2) arc_width = 2;
  +  length = o_current->line_length;
  +  space  = o_current->line_space;
  +	
  +  switch(o_current->line_type) {
  +    case(TYPE_SOLID):
  +      length = -1; space = -1;
  +      outl_func = (void *) o_arc_print_solid;
  +      break;
  +			
  +    case(TYPE_DOTTED):
  +      length = -1;
  +      outl_func = (void *) o_arc_print_dotted;
  +      break;
  +			
  +    case(TYPE_DASHED):
  +      outl_func = (void *) o_arc_print_dashed;
  +      break;
  +			
  +    case(TYPE_CENTER):
  +      outl_func = (void *) o_arc_print_center;
  +      break;
  +			
  +    case(TYPE_PHANTOM):
  +      outl_func = (void *) o_arc_print_phantom;
  +      break;
  +			
  +    case(TYPE_ERASE):
  +      /* Unused for now, print it solid */
  +      length = -1; space = -1;
  +      outl_func = (void *) o_arc_print_solid;
  +      break;
  +  }
  +
  +  if((space == 0) || (length == 0)) {
  +    length = -1; space = -1;
  +    outl_func = (void *) o_arc_print_solid;
  +  }
  +
  +  (*outl_func)(w_current, fp,
  +               x - origin_x, y - origin_x, radius,
  +               start_angle, end_angle,
  +               color, arc_width, length, space, origin_x, origin_y);
  +}
  +
  +
  +/*! \brief
  + *  \par Function Description
  + *  This function prints an arc when a solid line type is required.
  + *  The arc is defined by its center in <B>x</B> and <B>y</B>, its radius
  + *  in <B>radius</B> and the start and end angles of the arc on the circle.
  + *  The postscript file is defined by the file pointer <B>fp</B>.
  + *
  + *  The parameters <B>length</B> and <B>space</B> are ignored
  + *  whereas <B>arc_width</B> specifies the width of the printed line.
  + *
  + *  All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] fp         FILE pointer to postscript document.
  + *  \param [in] x
  + *  \param [in] y
  + *  \param [in] radius
  + *  \param [in] angle1
  + *  \param [in] angle2
  + *  \param [in] color
  + *  \param [in] arc_width
  + *  \param [in] length
  + *  \param [in] space
  + *  \param [in] origin_x
  + *  \param [in] origin_y
  + */
  +void o_arc_print_solid(TOPLEVEL *w_current, FILE *fp,
  +		       int x, int y, int radius,
  +		       int angle1, int angle2,
  +		       int color,
  +		       int arc_width, int length, int space,
  +		       int origin_x, int origin_y)
  +{
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +
  +  /* PB/AVH inverting angle2 if < 0 and changing angle1 accordingly */
  +  if (angle2 < 0) {
  +    angle1 = angle1 + angle2;
  +    angle2 = -angle2;
  +  }
  +
  +  fprintf(fp, "%d %d %d %d %d %d darc\n",
  +	  x,y, radius, angle1, angle1 + angle2,
  +	  arc_width);
  +
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *  This function prints an arc when a dotted line type is required.
  + *  The arc is defined by its center in <B>x</B> and <B>y</B>, its
  + *  radius in <B>radius</B> and the start and end angles of the arc on the circle.
  + *  The postscript file is defined by the file pointer <B>fp</B>.
  + *  The parameter <B>length</B> is ignored whereas <B>arc_width</B> specifies
  + *  the diameter of the dots of the printed line and <B>space</B> the distance
  + *  between two dots.
  + *  
  + *  A negative value for <B>space</B> leads to an endless loop.
  + *
  + *  All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
  + *
  + *  The function sets the color the line will be printed with.
  + * 
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] fp         FILE pointer to postscript document.
  + *  \param [in] x
  + *  \param [in] y
  + *  \param [in] radius
  + *  \param [in] angle1
  + *  \param [in] angle2
  + *  \param [in] color
  + *  \param [in] arc_width
  + *  \param [in] length
  + *  \param [in] space
  + *  \param [in] origin_x
  + *  \param [in] origin_y
  + */
  +void o_arc_print_dotted(TOPLEVEL *w_current, FILE *fp,
  +			int x, int y, int radius,
  +			int angle1, int angle2,
  +			int color,				   
  +			int arc_width, int length, int space,
  +			int origin_x, int origin_y)
  +{
  +  int da, d;
  +
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +
  +  /*! \note
  +   *  Depending on the radius of the arc, the <B>space</B> parameter is
  +   *  changed into a small angle <B>da</B>.
  +   *  Starting from <B>angle1</B> - the start angle - the dots are printed
  +   *  along the arc by increments of this new angle.
  +   *
  +   *  As <B>da</B> is rounded as an integer, it can take a null value which
  +   *  will make the function enter an endless loop. In such a case, the arc
  +   *  is printed solid. The <B>da</B> variable should never be negative
  +   *  except if <B>space</B> is negative.
  +   */
  +
  +  /* Inverting angle2 if < 0 and changing angle1 accordingly */
  +  /* the loop test assume that da > 0 */
  +  if (angle2 < 0) {
  +    angle1 = angle1 + angle2;
  +    angle2 = -angle2;
  +  }
  +  da = (int) ((space * 180) / (M_PI * ((double) radius)));
  +
  +	/* If da or db too small for arc to be displayed as dotted,
  +           draw a solid arc */
  +  if (da <= 0) {
  +    o_arc_print_solid(w_current, fp,
  +                      x, y, radius,
  +                      angle1, angle2,
  +                      color,
  +                      arc_width, length, space, origin_x, origin_y);
  +    return;
  +  }
  +
  +  fprintf(fp,"[");
  +  d = angle1;
  +  while (d < (angle2 + angle1)) {
  +    /*xa = ((double) x) + ((double) radius) * cos(d * M_PI / 180);
  +    ya = ((double) y) + ((double) radius) * sin(d * M_PI / 180);
  +    */
  +    fprintf(fp,"[%d] ",d);
  +
  +
  +#if 0 
  +    /*! \note
  +     *  A dot is represented by a filled circle.
  +     *  Position of the circle is (<B>xa</B>, <B>ya</B>) and its radius is the <B>arc_width</B> parameter.
  +     */
  +    /* PB : problem corrected : diameter of printed dots */
  +    /* 
  +      fprintf(fp, "newpath\n");
  +      fprintf(fp, "%d mils %d mils\n", (int) xa, (int) ya);
  +      if (arc_width <= 1) {
  +        fprintf(fp, "2 mils\n");
  +      } else {
  +        fprintf(fp, "%d mils\n", (int) arc_width/2);
  +      }
  +      fprintf(fp, "0 360 arc\n");
  +      fprintf(fp, "fill\n");
  +    */
  +    /* PB : end */		
  +#endif
  +    d = d + da;
  +  }
  +  fprintf(fp,"] %d %d %d %d dashedarc %% dotted\n",
  +	  x,y, radius, arc_width);
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *  This function prints an arc when a dashed line type is required.
  + *  The arc is defined by its center in <B>x</B> and <B>y</B>, its radius
  + *  in <B>radius</B> and the start and end angles of the arc on the circle.
  + *  The postscript file is defined by the file pointer <B>fp</B>.
  + *  The parameter <B>arc_width</B> specifies the diameter of the dots of the printed line.
  + *
  + *  A negative value for <B>space</B> or <B>length</B> leads to an endless loop.
  + *
  + *  All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
  + *
  + *  The function sets the color the line will be printed with.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] fp         FILE pointer to postscript document.
  + *  \param [in] x
  + *  \param [in] y
  + *  \param [in] radius
  + *  \param [in] angle1
  + *  \param [in] angle2
  + *  \param [in] color
  + *  \param [in] arc_width
  + *  \param [in] length
  + *  \param [in] space
  + *  \param [in] origin_x
  + *  \param [in] origin_y
  + */
  +void o_arc_print_dashed(TOPLEVEL *w_current, FILE *fp,
  +			int x, int y, int radius,
  +			int angle1, int angle2,
  +			int color,				   
  +			int arc_width, int length, int space,
  +			int origin_x, int origin_y)
  +{
  +  int da, db, a1, a2, d;
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +  
  +  /*! \note
  +   *  Depending on the radius of the arc, the <B>space</B> (resp. <B>length</B>)
  +   *  parameter is changed into a small angle <B>da</B> (resp. <B>db</B>).
  +   *  Starting from <B>angle1</B> - the start angle - the dashes are printed
  +   *  along the arc by increments of these new angles.
  +   *
  +   *  As <B>da</B> (resp. <B>db</B>) is rounded as an integer, it can take a
  +   *  null value which will make the function enter an endless loop. In such a case,
  +   *  the arc is printed solid. The <B>da</B> (resp. <B>db</B>) variable should never
  +   *  be negative except if <B>space</B> (resp. <B>length</B>) is negative.
  +   *
  +   *  It prints as many dashes of length <B>length</B> as possible.
  +   */
  +
  +  /* Inverting angle2 if < 0 and changing angle1 accordingly */
  +  /* the loop test assume that da > 0 */
  +  if (angle2 < 0) {
  +    angle1 = angle1 + angle2;
  +    angle2 = -angle2;
  +  }
  +  da = (int) ((length * 180) / (M_PI * ((double) radius)));
  +  db = (int) ((space  * 180) / (M_PI * ((double) radius)));
  +
  +  /* If da or db too small for arc to be displayed as dotted,
  +           draw a solid arc */
  +  if ((da <= 0) || (db <= 0)) {
  +    o_arc_print_solid(w_current, fp,
  +                      x, y, radius, 
  +                      angle1, angle2,
  +                      color,
  +                      arc_width, length, space, origin_x, origin_y);
  +    return;
  +  }
  +  
  +  fprintf(fp,"[");
  +  d = angle1;
  +  while ((d + da + db) < (angle1 + angle2)) {
  +    a1 = d;
  +    d = d + da;
  +
  +    fprintf(fp,"[%d %d] ",
  +	    a1, a1+da);
  +
  +    d = d + db;
  +  }
  +  /*! \note
  +   *  When the above condition is no more satisfied, then it is not
  +   *  possible to print a dash of length <B>length</B> and the following <B>space</B>.
  +   *  However it may be possible to print the complete dash or a shorter one.
  +   */
  +
  +  if ((d + da) < (angle1 + angle2)) {
  +    a1 = d;
  +    a2 = da;
  +  } else {
  +    a1 = d;
  +    a2 = (angle1 + angle2) - d;
  +  }
  +
  +  fprintf(fp,"[%d %d] ",
  +	  a1, a1+da);
  +
  +
  +  fprintf(fp,"] %d %d %d %d dashedarc %% dashed\n",
  +	  x,y, radius, arc_width);
  +
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *  This function prints an arc when a centered line type is required.
  + *  The arc is defined by its center in <B>x</B> and <B>y</B>, its radius in
  + *  <B>radius</B> and the start and end angles of the arc on the circle.
  + *  The postscript file is defined by the file pointer <B>fp</B>.
  + *  The parameter <B>arc_width</B> specifies the diameter of the dots and the width of the dashes of the printed line.
  + *
  + *  A negative value for <B>space</B> or <B>length</B> leads to an endless loop.
  + *
  + *  All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
  + *
  + *  The function sets the color in which the line will be printed with.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] fp         FILE pointer to postscript document.
  + *  \param [in] x
  + *  \param [in] y
  + *  \param [in] radius
  + *  \param [in] angle1
  + *  \param [in] angle2
  + *  \param [in] color
  + *  \param [in] arc_width
  + *  \param [in] length
  + *  \param [in] space
  + *  \param [in] origin_x
  + *  \param [in] origin_y
  + */
  +void o_arc_print_center(TOPLEVEL *w_current, FILE *fp,
  +			int x, int y, int radius, 
  +			int angle1, int angle2,
  +			int color,				   
  +			int arc_width, int length, int space,
  +			int origin_x, int origin_y)
  +{
  +  int da, db, a1, a2, d;
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +
  +  /*! \note
  +   *  Depending on the radius of the arc, the <B>space</B> (resp. <B>length</B>)
  +   *  parameter is changed into a small angle <B>da</B> (resp. <B>db</B>).
  +   *  Starting from <B>angle1</B> - the start angle - the dashes are printed
  +   *  along the arc by increments of these new angles.
  +   *
  +   *  As <B>da</B> (resp. <B>db</B>) is rounded as an integer, it can take a null
  +   *  value which will make the function enter an endless loop. In such a case,
  +   *  the arc is printed solid. The <B>da</B> (resp. <B>db</B>) variable should never
  +   *  be negative except if <B>space</B> (resp. <B>length</B>) is negative.
  +   *
  +   *  It prints as many sets of dash-dot as possible.
  +   */
  +
  +  /* Inverting angle2 if < 0 and changing angle1 accordingly */
  +  /* the loop test assume that da > 0 */
  +  if (angle2 < 0) {
  +    angle1 = angle1 + angle2;
  +    angle2 = -angle2;
  +  }
  +
  +  da = (int) ((length * 180) / (M_PI * ((double) radius)));
  +  db = (int) ((space  * 180) / (M_PI * ((double) radius)));
  +
  +  /* If da or db too small to be displayed, draw an arc */
  +  if ((da <= 0) || (db <= 0)) {
  +    o_arc_print_solid(w_current, fp,
  +		      x, y, radius,
  +		      angle1, angle2,
  +		      color,
  +		      arc_width, length, space, origin_x, origin_y);
  +    return;
  +  }
  +  
  +  fprintf(fp, "[");
  +  d = angle1;
  +  while ((d + da + 2 * db) < (angle1 + angle2)) {
  +    a1 = d;
  +    d = d + da;
  +    fprintf(fp,"[%d %d] ",(int) a1, (int) a1 + da);
  +    
  +    d = d + db;
  +    /*
  +      xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
  +      ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
  +    */
  +    fprintf(fp,"[%d] ",d);
  +    d = d + db;
  +  }
  +  /*! \note
  +   *  When the above condition is no more satisfied, then it is not
  +   *  possible to print a dash of length <B>length</B>. However two cases are possible :
  +   *  <DL>
  +   *      <DT>*</DT><DD>it is possible to print the dash and the dot
  +   *      <DT>*</DT><DD>it is possible to print the dash or a part of the original dash
  +   *  </DL>
  +   */
  +  
  +  if ((d + da) < (angle1 + angle2)) {
  +    a1 = d;
  +    a2 = da;
  +    
  +    d = d + da;
  +  } else {
  +    a1 = d;
  +    a2 = (angle1 + angle2) - d;
  +    
  +    d = d + da;
  +  }
  +  
  +  fprintf(fp,"[%d %d] ",(int) a1, (int) a1 + da);
  +
  +	
  +  if ((d + db) < (angle1 + angle2)) {
  +    /*
  +      xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
  +      ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
  +    */
  +    fprintf(fp,"[%d] ",d);
  +    
  +  }
  +  
  +  fprintf(fp,"] %d %d %d %d dashedarc %% center\n",
  +	  x,y, radius, arc_width);
  +}
  +
  +/*! \note
  + *  A dot is represented by a filled circle. Position of the circle is (<B>xa</B>, <B>ya</B>)
  + *  and its radius is the <B>arc_width</B> parameter.
  + */
  +
  +/*! \brief
  + *  \par Function Description
  + *  This function prints an arc when a phantom line type is required.
  + *  The arc is defined by its center in <B>x</B> and <B>y</B>, its radius
  + *  in <B>radius</B> and the start and end angles of the arc on the circle.
  + *  The postscript file is defined by the file pointer <B>fp</B>.
  + *  The parameter <B>arc_width</B> specifies the diameter of the dots and the width of the dashes of the printed line.
  + *
  + *  A negative value for <B>space</B> or <B>length</B> leads to an endless loop.
  + *
  + *  All dimensions are in mils, except <B>angle1</B> and <B>angle2</B> in degrees.
  + *
  + * The function sets the color in which the line will be printed with.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] fp         FILE pointer to postscript document.
  + *  \param [in] x
  + *  \param [in] y
  + *  \param [in] radius
  + *  \param [in] angle1
  + *  \param [in] angle2
  + *  \param [in] color
  + *  \param [in] arc_width
  + *  \param [in] length
  + *  \param [in] space
  + *  \param [in] origin_x
  + *  \param [in] origin_y
  + */
  +void o_arc_print_phantom(TOPLEVEL *w_current, FILE *fp,
  +			 int x, int y, int radius,
  +			 int angle1, int angle2,
  +			 int color,
  +			 int arc_width, int length, int space,
  +			 int origin_x, int origin_y)
  +{
  +  int da, db, a1, a2, d;
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +
  +  /*! \note
  +   *  Depending on the radius of the arc, the <B>space</B> (resp. <B>length</B>)
  +   *  parameter is changed into a small angle <B>da</B> (resp. <B>db</B>).
  +   *  Starting from <B>angle1</B> - the start angle - the dashes are printed
  +   *  along the arc by increments of these new angles.
  +   *
  +   *  As <B>da</B> (resp. <B>db</B>) is rounded as an integer, it can take a
  +   *  null value which will make the function enter an endless loop. In such
  +   *  a case, the arc is printed solid. The <B>da</B> (resp. <B>db</B>) variable
  +   *  should never be negative except if <B>space</B> (resp. <B>length</B>) is negative.
  +   *
  +   *  It prints as many sets of dash-dot-dot as possible.
  +   */
  +
  +  /* Inverting angle2 if < 0 and changing angle1 accordingly */
  +  /* the loop test assume that da > 0 */
  +  if (angle2 < 0) {
  +    angle1 = angle1 + angle2;
  +    angle2 = -angle2;
  +  }
  +  da = (int) ((length * 180) / (((double) radius) * M_PI));
  +  db = (int) ((space  * 180) / (((double) radius) * M_PI));
  +  
  +  /* If da or db too small for arc to be displayed as dotted,
  +     draw a solid arc */
  +  if ((da <= 0) || (db <= 0)) {
  +    o_arc_print_solid(w_current, fp,
  +		      x, y, radius,
  +		      angle1, angle2,
  +		      color,						  
  +		      arc_width, length, space, origin_x, origin_y);
  +    return;
  +  }
  +  
  +  fprintf(fp,"[");
  +  
  +  d = angle1;
  +  while ((d + da + 3 * db) < (angle1 + angle2)) {
  +    a1 = d;
  +    d = d + da;
  +    
  +    fprintf(fp,"[%d %d] ",(int) a1, (int) a1 + da);
  +    
  +    d = d + db;
  +    /*
  +      xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
  +      ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
  +    */
  +    fprintf(fp,"[%d] ",d);
  +    
  +    d = d + db;
  +    
  +    /*
  +      xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
  +      ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
  +    */
  +    fprintf(fp,"[%d] ",d);
  +    
  +    d = d + db;
  +  }
  +
  +  /*! \note
  +   *  When the above condition is no more satisfied, then it is not
  +   *  possible to print a dash of length <B>length</B>.
  +   *  However three cases are possible :
  +   *  <DL>
  +   *    <DT>*</DT><DD>it is possible to print a dash and a dot and a dot
  +   *    <DT>*</DT><DD>it is possible to print a dash and a dot
  +   *    <DT>*</DT><DD>it is possible to print the dash or a part of the original dash
  +   *  </DL>
  +   */
  +
  +  if ((d + da) < (angle1 + angle2)) {
  +    a1 = d;
  +    a2 = da;
  +    d = d + da;
  +  } else {
  +    a1 = d;
  +    a2 = (angle1 + angle2) - d;
  +    d = d + da;
  +  }
  +  
  +  fprintf(fp,"[%d %d] ",(int) a1, (int) a1 + da);
  +  
  +  if ((d + db) < (angle1 + angle2)) {
  +    d = d + db;
  +    
  +    /*
  +      xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
  +      ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
  +    */
  +    fprintf(fp,"[%d] ",d);
  +    
  +  }
  +  
  +  if ((d + db) < (angle1 + angle2)) {
  +    d = d + db;
  +    
  +    /*
  +      xa = ((double) x) + ((double) radius) * cos(d * (M_PI / 180));
  +      ya = ((double) y) + ((double) radius) * sin(d * (M_PI / 180));
  +    */
  +    
  +    fprintf(fp,"[%d] ",d);
  +    
  +    
  +  }
  +  
  +  fprintf(fp,"] %d %d %d %d dashedarc %% phantom\n",
  +	  x,y, radius, arc_width);
  +}
  +
  +
  +#if 0 /* original way of printing arcs, no longer used */
  +
  +/*! \deprecated
  + *  \brief Print solid arc in a Postscript file.
  + *  \par Function Description
  + *  This function prints a solid arc in a Postscript file indepedentely of its line type.
  + *  It is basically the old way to manage the arc printing.
  + *  This function is now replaced by the #o_arc_print() function.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] fp         FILE pointer to postscript document.
  + *  \param [in] o_current
  + *  \param [in] origin_x
  + *  \param [in] origin_y
  + */
  +void o_arc_print_old(TOPLEVEL *w_current, FILE *fp, OBJECT *o_current, 
  +		     int origin_x, int origin_y)
  +{
  +  int radius;
  +  int start_angle, end_angle;
  +  int awidth, aheight;
  +  int x, y;
  +
  +  if (o_current == NULL) {
  +    printf("got null in o_arc_print\n");
  +    return;
  +  }
  +
  +  fprintf(fp, "gsave\n");
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, o_current->color);
  +  }
  +
  +  f_print_set_line_width(fp, o_current->line_width);
  +
  +  awidth = o_current->arc->width;
  +  aheight = o_current->arc->height;
  +
  +  radius = abs(aheight - o_current->arc->y)/2;
  +
  +  /* hack hack hack */
  +  /* the snap_grid here is a safety for arcs inside complex objects */
  +  /* which are not snapped to the grid */
  +  /* ALL arcs centers will be snapped to the center */
  +  /* hack hack hack */
  +  /* Geee I wish there was a better solution */
  +  /* well for now, if you print the complex structure that's in memory */
  +  /* then the arc will be properly snapped */
  +  /*x = snap_grid(w_current, o_current->x+radius);
  +    y = snap_grid(w_current, o_current->y-radius);*/
  +
  +  x = (o_current->arc->x+radius);
  +  y = (o_current->arc->y-radius);
  +
  +  start_angle = o_current->arc->start_angle/64;
  +  end_angle = o_current->arc->end_angle/64;
  +
  +  if ( end_angle < 0) {
  +		
  +    if (end_angle >= 180) {
  +      start_angle = (start_angle - (end_angle)) % 360;
  +    } else {
  +      start_angle = (start_angle + (end_angle)) % 360;
  +    }
  +
  +    end_angle = abs(end_angle);
  +		
  +  }
  +
  +  end_angle = start_angle + end_angle;
  +		
  +
  +  fprintf(fp, "newpath\n");
  +  fprintf(fp, "%d %d\n", x-origin_x, y-origin_y);
  +  fprintf(fp, "%d\n", radius);
  +  fprintf(fp, "%d %d arc\n", start_angle, end_angle);
  +  fprintf(fp, "stroke\n");
  +  fprintf(fp, "grestore\n");
  +}
  +#endif
  +
  +/*! \brief Draw an arc in an image.
  + *  \par Function Description
  + *  This function draws an arc in an image with the libgdgeda function <B>gdImageArc()</B>.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current
  + *  \param [in] origin_x
  + *  \param [in] origin_y
  + *  \param [in] color_mode
  + */
  +void
  +o_arc_image_write(TOPLEVEL *w_current, OBJECT *o_current,
  +                  int origin_x, int origin_y, int color_mode)
  +{
  +  int start_angle, end_angle;
  +  int width, height;
  +  int color;
  +  int x, y;
  +
  +  if (o_current == NULL) {
  +    printf("got null in o_arc_image_write\n");
  +    return;
  +  }
  +
  +  if (color_mode == TRUE) {
  +    color = o_image_geda2gd_color(o_current->color);
  +  } else {
  +    color = image_black;
  +  }
  +
  +  start_angle = o_current->arc->start_angle;
  +  end_angle   = o_current->arc->end_angle;
  +
  +  if ( end_angle < 0) {
  +
  +    if (end_angle >= 180) {
  +      start_angle = (start_angle - (end_angle)) % 360;
  +    } else {
  +      start_angle = (start_angle + (end_angle)) % 360;
  +    }
  +
  +    end_angle = abs(end_angle);
  +
  +  }
  +
  +  end_angle = start_angle + end_angle;
  +
  +
  +
  +#if DEBUG
  +  printf("%d %d -- %d %d -- %d %d\n", 
  +         o_current->arc->screen_x, o_current->arc->screen_y,
  +         o_current->arc->screen_width-o_current->arc->screen_x,
  +         o_current->arc->screen_height-o_current->arc->screen_y,
  +         start_angle, end_angle);
  +#endif
  +
  +  if (start_angle < end_angle) {
  +
  +    start_angle = start_angle + 360;
  +  }
  +
  +#if DEBUG
  +  printf("%d %d -- %d %d -- %d %d\n", 
  +         o_current->arc->screen_x, o_current->arc->screen_y,
  +         o_current->arc->screen_width-o_current->arc->screen_x,
  +         o_current->arc->screen_height-o_current->arc->screen_y,
  +         start_angle, end_angle);
  +#endif
  +
  +
  +  width  = o_current->arc->screen_width;
  +  height = o_current->arc->screen_height;
  +
  +  x = o_current->arc->screen_x;
  +  y = o_current->arc->screen_y;
  +	
  +#ifdef HAS_LIBGDGEDA
  +
  +  gdImageSetThickness(current_im_ptr, SCREENabs(w_current,
  +                                                o_current->line_width));
  +
  +  gdImageArc(current_im_ptr, 
  +             x, y, width, height, start_angle, end_angle, color);
  +#endif
  +	
  +}
  
  
  
  1.35      +2132 -1668eda/geda/gaf/libgeda/src/o_attrib.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_attrib.c
  ===================================================================
  RCS file: o_attrib.c
  diff -N o_attrib.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_attrib.c	5 Jul 2006 03:13:38 -0000	1.35
  @@ -0,0 +1,2492 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +#include <math.h>
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! Basic string splitting delimiters */
  +#define DELIMITERS ",; "
  +
  +/*! \note
  + *  No special type for attributes
  + *  You can only edit text attributes
  + *
  + *  be sure in o_copy o_move o_delete you maintain the attributes
  + *  delete is a bare, because you will have to unattach the other end
  + *  and in o_save o_read as well
  + *  and in o_select when selecting objects, select the attributes
  + *
  + *  \todo there needs to be a modifier (in struct.h, such as a flag) which
  + *        signifies that this is an attribute (really? why?) 
  + *
  + *  \note
  + *  return pointer from attrib_list
  + */
  +
  +/*! \brief Update an attribute's uref.
  + *  \par Function Description
  + *  Update an attribute's uref.
  + *
  + *  \param [in] w_current  The TOPLEVEL object
  + *  \param [in] o_current  The object to update.
  + *
  + *  \note
  + *   Martin Benes' auto uref renumber code
  + */
  +void o_attrib_update_urefBM (TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  OBJECT *list_head,*obj;
  +  char *uref;
  +  int i = -1, name_conflict,len;
  +  char *index_list;
  +  int index_list_len=1;
  +
  +  if (strncmp(o_current->text->string,"uref=",5))  /* deprecated */
  +    return;
  +
  +  len=strlen(o_current->text->string);
  +  uref=malloc(len+10);
  +  strcpy(uref,o_current->text->string);
  +
  +  while (o_current->text->string[len-1]<='9' && 
  +	 o_current->text->string[len-1]>='0')
  +    --len;
  +
  +  list_head=return_head(o_current);
  +  for (obj=list_head->next;obj;obj=obj->next) {
  +    if (obj->type==OBJ_TEXT && obj->attribute)
  +      ++index_list_len;
  +  }
  +
  +  index_list=calloc(index_list_len,1);
  +  name_conflict=0;
  +
  +  for (obj=list_head->next;obj;obj=obj->next) {
  +    if (obj->type==OBJ_TEXT && obj->attribute && obj!=o_current) {
  +      if (strncmp(uref,obj->text->string,len)==0) {
  +	if (strcmp(uref+len,obj->text->string+len)==0) {
  +	  name_conflict=1;
  +	}
  +	i=atoi(obj->text->string+len);
  +	if (i<index_list_len)
  +	  index_list[i]=1;
  +      }
  +    }
  +  }
  +
  +  if (name_conflict) {
  +    for (i=0;index_list[i];++i);
  +    sprintf(uref+len,"%d", i);
  +    free(o_current->text->string);
  +    o_current->text->string=uref;
  +    o_text_recreate(w_current, o_current);
  +  }
  +
  +  free(index_list);
  +}
  +
  +/*! \brief Search for an item in an attribute list.
  + *  \par Function Description
  + *  Search for an item in an attribute list.
  + *
  + *  \param [in] list  ATTRIB pointer to the list to be searched.
  + *  \param [in] item  item to be found.
  + */
  +ATTRIB *o_attrib_search(ATTRIB *list, OBJECT *item)
  +{
  +  ATTRIB *a_current;
  +
  +  if (item == NULL) {
  +    return(NULL);
  +  }
  +
  +  a_current = list;
  +
  +  while(a_current != NULL) {
  +    if (a_current->object != NULL) {
  +      if (item->sid == a_current->object->sid) {	
  +        return(a_current);	
  +      }
  +    }
  +
  +    a_current = a_current->next;
  +  }
  +
  +  return(NULL);
  +}
  +
  +/*! \brief Get the last attribute in the list.
  + *  \par Function Description
  + *  Get the last attribute in the list.
  + *
  + *  \param [in] head  ATTRIB pointer to beginning of list.
  + *  \return Returns an ATTRIB pointer to the last attribute in the list.
  + */
  +ATTRIB *o_attrib_return_tail(ATTRIB *head) 
  +{
  +  ATTRIB *a_current=NULL;
  +  ATTRIB *current=NULL;
  +
  +  a_current = head;
  +  while ( a_current != NULL ) { /* goto end of list */
  +    current = a_current;
  +    a_current = a_current->next;
  +  }
  +  return(current); 
  +}
  +
  +/*! \brief Create an attribute list head item.
  + *  \par Function Description
  + *  Create an attribute list head item.
  + *
  + *  \param [in] parent  OBJECT pointer that will become the parent
  + *                      of this new head item.
  + *  \return Returns an ATTRIB pointer to the newly created head item.
  + *
  + *  \todo Rename this function to be consistant.
  + */
  +ATTRIB *add_attrib_head(OBJECT *parent)
  +{
  +  ATTRIB *head = NULL;
  +
  +  head = (ATTRIB *) malloc(sizeof(ATTRIB));
  +  head->next = NULL;
  +
  +  /* highly experimental hack */
  +  head->object = parent; 
  +  head->copied_to = NULL;
  +  head->prev = NULL;
  +
  +  /* \todo
  +   * why the grief? well everywhere a attribute is refered to
  +   * you have to skip over the head, you really ought to robustify
  +   * all references to this object pointer when talking to attributes
  +   * hack of course I think this is okay now though
  +   */
  +
  +  return(head);
  +}
  +
  +/*! \brief Add an attribute to an existing attribute list.
  + *  \par Function Description
  + *  Add an attribute to an exsiting attribute list.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in,out] list_head  The list where you want to add item to.
  + *  \param [in]     item       The item you want to add as an attribute.
  + *  \return An ATTRIB pointer to the newly created attribute.
  + */
  +ATTRIB *o_attrib_add(TOPLEVEL *w_current, ATTRIB *list_head, OBJECT *item)
  +{
  +  ATTRIB *end = NULL;
  +  ATTRIB *new = NULL;
  +
  +  /* get tail of list_head */
  +  end = o_attrib_return_tail(list_head);
  +
  +  /* create an new st_attrib object */
  +  new = (ATTRIB *) malloc(sizeof(ATTRIB));
  +
  +  /* fill item with correct data (mainly item) */
  +  new->next = NULL;
  +  new->prev = end;
  +  new->object = item;
  +  new->copied_to = NULL;
  +  new->object->attribute = 1; /* Set the attribute to true, hack define */
  +  /* Show that that item is an attribute */
  +  new->object->color = w_current->attribute_color; 
  +
  +  if (new->object->type == OBJ_TEXT) {
  +    o_complex_set_color(new->object->text->prim_objs,
  +                        new->object->color);
  +  } else if (new->object->type == OBJ_COMPLEX || 
  +             new->object->type == OBJ_PLACEHOLDER) {
  +    o_complex_set_color(new->object->complex->prim_objs,
  +                        new->object->color);
  +  }
  +
  +  /* Add link from item to attrib listing */
  +  new->object->attached_to = new;
  +
  +  /* set next of tail of end->attrib to item */
  +  if (end) {
  +    end->next = new;
  +    return(new);
  +  } else {
  +    return(new);
  +  }
  +}
  +
  +/*! \brief Free single item in attribute list.
  + *  \par Function Description
  + *  Free single item in attribute list.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] current    ATTRIB pointer to free.
  + *
  + *  \note
  + *  this routine is not nice to next and prev
  + *  this routine is only called from free_all
  + */
  +void o_attrib_free(TOPLEVEL *w_current, ATTRIB *current)
  +{
  +  if (current != NULL) {
  +
  +    /* \todo this makes me nervous... very nervous */
  +    if (current->object != NULL && current->prev != NULL) {
  +      current->object->attribute = 0;	
  +      current->object->attached_to=NULL;
  +      current->object->color = w_current->detachedattr_color;	
  +
  +      if (current->object->type == OBJ_TEXT) {
  +        o_complex_set_color(current->object->text->prim_objs, 
  +                            current->object->color);
  +      } else {
  +        printf("Tried to set the color on a complex!\nlibgeda/src/o_attrib_free 1\n");
  +      }
  +
  +      /* \todo not sure on this */
  +      if (current->object->saved_color != -1) {
  +        if (current->object->type == OBJ_TEXT) {
  +          o_complex_set_saved_color_only(
  +                                         current->object->text->prim_objs, 
  +                                         w_current->detachedattr_color);
  +        } else {
  +          printf("Tried to set the color on a complex!\nlibgeda/src/o_attrib_free 2\n");
  +        }
  +        current->object->saved_color = w_current->
  +        detachedattr_color;
  +      }
  +    }
  +
  +    /* \todo were do we detach the object->attached_to? above */
  +    current->object=NULL;
  +
  +    free(current);
  +
  +  }
  +}
  +
  +/*! \brief Attach existing attribute to an object.
  + *  \par Function Description
  + *  Attach existing attribute to an object.
  + *
  + *  \param [in]  w_current    The TOPLEVEL object.
  + *  \param [in]  parent_list  List where actual attribute objects live.
  + *  \param [in]  text_object  The attribute to be added.
  + *  \param [out] object       The object where you want to add item as an attribute.
  + *
  + *  \par IMPORTANT:
  + *  Lists first then specific single item.
  + *
  + *  \note
  + *  typically parent_list is object_parent (object_head), but it is
  + *  overridden in o_complex_add so that it points to head node of the complex
  + *  
  + */
  +void o_attrib_attach(TOPLEVEL *w_current, OBJECT *parent_list, 
  +		     OBJECT *text_object, OBJECT *object)
  +{
  +  OBJECT *o_current = NULL;
  +
  +  ATTRIB *found = NULL;
  +  OBJECT *found2 = NULL; /* object in main list */
  +
  +  o_current = text_object; 
  +
  +  if (object == NULL) {
  +    printf("ah.. object was not found in the parent list!\n");
  +    return;
  +  }
  +
  +  /* is the object already part of the list ? */
  +  found = o_attrib_search(object->attribs, o_current);
  +  if (!found) { /* no it's not, add it to the list */
  +		
  +    found2 = (OBJECT *) o_list_search(parent_list, o_current);	
  +
  +    /* check to see if found2 is not null hack */
  +    if (found2) {
  +      if (found2->type == OBJ_TEXT) {
  +
  +        if (object->attribs == NULL) {
  +          object->attribs = 
  +            add_attrib_head(object);
  +        }
  +
  +
  +        if (found2->attached_to) {
  +          fprintf(stderr, "You cannot attach this attribute [%s] to more than one object\n", found2->text->string);
  +        } else {
  +
  +          o_attrib_add(w_current, 
  +                       object->attribs, 
  +                       found2);
  +
  +          o_current->color = w_current->
  +            attribute_color; 
  +
  +          o_complex_set_color(
  +                              o_current->text->prim_objs,
  +                              o_current->color);
  +
  +          if (o_current->saved_color != -1) {
  +            o_complex_set_saved_color_only(
  +                                           o_current->text->prim_objs, 
  +                                           o_current->color);
  +            o_current->saved_color = 
  +              o_current->color;
  +          }
  +          /* can't do this here since just selecting something */
  +          /* will cause this to be set */
  +          /* w_current->page_current->CHANGED=1;*/
  +
  +#ifdef MARTIN_BENES
  +          o_attrib_update_urefBM (w_current, o_current);
  +#endif
  +        }
  +      } else {
  +        fprintf(stderr, "You cannot attach non text items as attributes!\n");
  +      }	
  +    }
  +  } else {
  +    if (o_current->text->string) { 	
  +      printf("Attribute [%s] already attached\n", 
  +             o_current->text->string);
  +    }
  +  }
  +}
  +
  +/*! \todo Empty function.
  + *  \brief
  + *  \par Function Description
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] list
  + *  \param [in] items
  + */
  +void
  +o_attrib_detach_test(TOPLEVEL *w_current, OBJECT *list, OBJECT *items) 
  +{
  +
  +/* this all needs to be rethought out */
  +	/* loop over items till NULL */
  +		/* Search for item in object->attrib */
  +		/* o_attrib_search(list->attribs, current_item) */
  +			/* if found */
  +				/*call o_attrib_remove(object->attributes, current_item->attrib_struct);*/
  +			/* if not found */
  +				/* do nothing */
  +
  +}
  +
  +/*! \todo Empty function.
  + *  \brief
  + *  \par Function Description
  + *
  + *  \param [in] list
  + *  \param [in] item
  + */
  +/* only can edit a text, special case of edit text */
  +void o_attrib_edit(OBJECT *list, OBJECT *item)
  +{
  +
  +}
  +
  +/*! \todo Empty function.
  + *  \brief
  + *  \par Function Description
  + *
  + *  \param [in] list
  + *
  + *  \note
  + *  should this be st_attrib or st_object?
  + */
  +void o_attrib_select_draw(ATTRIB *list)
  +{
  +  /* draw list */
  +  /* either white */
  +  /* or a white bounding box? */
  +}
  +
  +/*! \todo Empty function.
  + *  \brief
  + *  \par Function Description
  + *
  + *  \param [in] list
  + *
  + *  \note
  + *  should this be st_attrib or st_object?
  + */
  +void o_attrib_unselect_draw(ATTRIB *list)
  +{
  +  /* draw list */
  +  /* either white */
  +  /* or a white bounding box? */
  +
  +}
  +
  +/*! \brief Free all attribute items in a list.
  + *  \par Function Description
  + *  Free all attribute items in a list.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in,out] list       The list to free.
  + *
  + *  \note
  + *  this routine uses o_attrib_free (which isn't nice to next, prev)
  + *  so it should only be used when an object is being destroyed
  + *  goes backwards
  + */
  +void o_attrib_free_all(TOPLEVEL *w_current, ATTRIB *list)
  +{
  +  ATTRIB *a_current; 
  +  ATTRIB *a_next;
  +
  +  a_current = list;
  +
  +  while (a_current != NULL) {
  +    a_next = a_current->next;
  +    o_attrib_free(w_current, a_current);
  +    a_current = a_next;
  +  }
  +}
  +
  +/*! \brief Print all attributes to a Postscript document.
  + *  \par Function Description
  + *  Print all attributes to a Postscript document.
  + *
  + *  \param [in] attributes  List of attributes to print.
  + */
  +void o_attrib_print(ATTRIB *attributes) 
  +{
  +  ATTRIB *a_current;
  +
  +  a_current = attributes;
  +
  +  while (a_current != NULL) {
  +    printf("Attribute points to: %s\n", a_current->object->name);
  +    if (a_current->object && a_current->object->text) {
  +      printf("\tText is: %s\n", a_current->object->text->string);
  +    }
  +
  +    if (!a_current->object) {
  +      printf("oops found a null attrib object\n");
  +    }
  +    a_current = a_current->next;
  +  }
  +}
  +
  +/*! \brief Print all attributes in reverse order to a Postscript document.
  + *  \par Function Description
  + *  Print all attributes in reverse order to a Postscript document.
  + *
  + *  \param [in] attributes  List of attributes to print.
  + */
  +void o_attrib_print_reverse(ATTRIB *attributes) 
  +{
  +  ATTRIB *a_current;
  +
  +  a_current = o_attrib_return_tail(attributes);
  +
  +  while (a_current != NULL) {
  +    printf("Attribute points to: %s\n", a_current->object->name);
  +    if (a_current->object && a_current->object->text) {
  +      printf("\tText is: %s\n", a_current->object->text->string);
  +    }
  +
  +    if (!a_current->object) {
  +      printf("oops found a null attrib object\n");
  +    }
  +    a_current = a_current->prev;
  +  }
  +}
  +
  +/*! \todo Empty function.
  + *  \brief
  + *  \par Function Description
  + *
  + *  \param [in] list  The attribute list to copy.
  + *  \return Always NULL.
  + *
  + *  \note
  + *  very hard, I don't think we need it though
  + */
  +ATTRIB *o_attrib_copy(ATTRIB *list)
  +{
  +  return(NULL);
  +}
  +
  +/*! \brief Delete an attribute.
  + *  \par Function Description
  + *  This function goes out and removes the current attribute,
  + *  while preserving the next, prev pointers.
  + *  This function should be used when detaching an attribute.
  + *
  + *  \param [in] a_current  The attribute to be deleted.
  + */
  +void o_attrib_delete(ATTRIB *a_current)
  +{
  +  if (a_current != NULL) {
  +
  +    if (a_current->next)
  +    a_current->next->prev = a_current->prev;
  +    else
  +    a_current->next = NULL;
  +
  +    if (a_current->prev)
  +    a_current->prev->next = a_current->next;
  +    else
  +    a_current->prev = NULL;
  +
  +    if (a_current->object) {
  +      a_current->object->attribute=0;
  +      a_current->object->attached_to=NULL;
  +    }
  +    a_current->object = NULL;
  +
  +    free(a_current);
  +  }
  +}
  +
  +/*! \todo Finish function.
  + *  \brief Remove an attribute item from an attribute list.
  + *  \par Function Description
  + *  This function goes out and removes an attribute from a list.
  + *  It searches for the attribute and then removes it using the
  + *  good #o_attrib_delete() routine.
  + *
  + *  \param [in] list    ATTRIB list to remove attribute from.
  + *  \param [in] remove  The ATTRIB to remove from list.
  + *
  + *  \note
  + *  This function is the detach_all routine.
  + *  It is not currently being used.
  + *  It is not even done.
  + */
  +void o_attrib_remove(ATTRIB *list, ATTRIB *remove) 
  +{
  +  ATTRIB *a_current;
  +
  +  a_current = list;
  +
  +  while (a_current != NULL) {
  +	
  +    if (a_current == remove) {
  +			
  +    }	
  +    a_current = a_current->next;
  +  }
  +}
  +
  +/*! \todo Is this function used?
  + *  \deprecated
  + *  \brief Detach all attributes from a list.
  + *  \par Function Description
  + *  Detach all attributes from a list.
  + *
  + *  \param [in] w_current    The TOPLEVEL object.
  + *  \param [in] object_list  Attribute list to delete.
  + *  \param [in] main_head    The head of the attribute list.
  + */
  +void o_attrib_detach_all(TOPLEVEL *w_current, OBJECT *object_list, OBJECT *main_head)
  +{
  +#if 0 /* not used */
  +  OBJECT *o_current=NULL;
  +
  +  o_current = object_list;
  +
  +  while(o_current != NULL) {
  +
  +    X = (OBJECT *) o_list_search(main_head, o_current);
  +
  +    if (X) {
  +      if (X->attribs != NULL) {
  +        o_attrib_free_all(w_current, X->attribs);
  +        X->attribs = NULL; /* leak possible? */
  +        w_current->page_current->CHANGED=1;
  +      }
  +    }
  +    o_current = o_current->next;
  +  }
  +#endif
  +}
  +
  +/*! \brief Read attributes from a file.
  + *  \par Function Description
  + *  Read attributes from a file.
  + *
  + *  \param [in]  w_current              The TOPLEVEL object.
  + *  \param [in]  fp                     FILE pointer to read from.
  + *  \param [out] object_to_get_attribs  Storage for attributes.
  + *  \param [in]  release_ver            libgeda release version number.
  + *  \param [in]  fileformat_ver         file format version number.
  + *  \return Pointer to object_to_get_attribs.
  + */
  +OBJECT *o_read_attribs(TOPLEVEL *w_current, FILE *fp, OBJECT *object_to_get_attribs,
  +		       unsigned int release_ver, unsigned int fileformat_ver)
  +{
  +  OBJECT *object_list=NULL;
  +  char buf[1024];
  +  char objtype;
  +  int ATTACH=FALSE;
  +  int saved_color = -1;
  +
  +  object_list = object_to_get_attribs;
  +
  +  while ( fgets(buf, 1024, fp) != NULL) {
  +
  +    sscanf(buf, "%c", &objtype);
  +    switch (objtype) {
  +
  +      case(OBJ_LINE):
  +        object_list = (OBJECT *) o_line_read(w_current, 
  +                                             object_list,
  +                                             buf, 
  +                                             release_ver, fileformat_ver);
  +        break;
  +
  +
  +      case(OBJ_NET):
  +        object_list = (OBJECT *) o_net_read(w_current, 
  +                                            object_list, 
  +                                            buf, 
  +                                            release_ver, fileformat_ver);
  +        break;
  +
  +      case(OBJ_BUS):
  +        object_list = (OBJECT *) o_bus_read(w_current, 
  +                                            object_list, 
  +                                            buf, 
  +                                            release_ver, fileformat_ver);
  +        break;
  +
  +      case(OBJ_BOX):
  +        object_list = (OBJECT *) o_box_read(w_current, 
  +                                            object_list, 
  +                                            buf, 
  +                                            release_ver, fileformat_ver);
  +        break;
  +		
  +      case(OBJ_CIRCLE):
  +        object_list = (OBJECT *) o_circle_read(
  +                                               w_current, 
  +                                               object_list, 
  +                                               buf, 
  +                                               release_ver, fileformat_ver);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +			
  +        object_list = (OBJECT *) o_complex_read(
  +                                                w_current, 
  +                                                object_list, 
  +                                                buf, 
  +                                                release_ver, fileformat_ver);
  +
  +				/* this is necessary because complex may add
  +				   attributes which float */
  +				/* still needed? */
  +        object_list = (OBJECT *) return_tail(
  +                                             object_list);
  +        break;
  +
  +      case(OBJ_PIN):
  +        object_list = (OBJECT *) o_pin_read(w_current, 
  +                                            object_list, 
  +                                            buf, 
  +                                            release_ver, fileformat_ver);
  +        break;
  +
  +      case(OBJ_ARC):
  +        object_list = (OBJECT *) o_arc_read(w_current, 
  +                                            object_list, 
  +                                            buf, 
  +                                            release_ver, fileformat_ver);
  +        break;
  +
  +      case(OBJ_TEXT):
  +        /* fgets(string, 1024, fp); text strings are now read inside: */
  +        object_list = (OBJECT *) o_text_read(w_current,
  +                                             object_list, 
  +                                             buf, 
  +                                             fp, 
  +                                             release_ver, fileformat_ver);
  +        saved_color = object_list->color;
  +        ATTACH=TRUE;
  +		
  +        break;
  +
  +      case(ENDATTACH_ATTR): 
  +        return(object_list);
  +        break;	
  +
  +    }
  +
  +    if (ATTACH) {
  +      o_attrib_attach(w_current, 
  +                      w_current->page_current->object_parent, 
  +                      object_list, object_to_get_attribs);
  +      /* check color to set it to the right value */
  +      if (object_list->color != saved_color) {
  +        object_list->color = saved_color;
  +
  +        if (object_list->type == OBJ_TEXT) {	
  +          o_complex_set_color(
  +                              object_list->text->prim_objs,
  +                              object_list->color);
  +        } else {
  +          printf("Tried to set the color on a complex in libgeda/src/o_read_attribs\n");
  +        }
  +      }
  +      ATTACH=FALSE;
  +    } else {
  +      fprintf(stderr, "Tried to attach a non-text item as an attribute\n");
  +    }
  +  }
  +  return(object_list);
  +}
  +
  +/*! \brief Save attributes to a file.
  + *  \par Function Description
  + *  Save attributes to a file.
  + *
  + *  \param [in] fp       FILE pointer to write attributes to.
  + *  \param [in] attribs  attributes to write.
  + *  \todo
  + *  this should be trimmed down to only save attributes which are text items
  + */
  +void o_save_attribs(FILE *fp, ATTRIB *attribs)
  +{
  +  ATTRIB *a_current=NULL;
  +  OBJECT *o_current=NULL;
  +  char *out;
  +
  +  a_current = attribs;
  +
  +  fprintf(fp, "{\n");
  +	
  +  while ( a_current != NULL ) {
  +
  +    o_current = a_current->object;	
  +
  +    if (o_current->type != OBJ_HEAD) {
  +
  +#if DEBUG
  +      printf("type: %d %c  ref: %d %c\n", o_current->type, o_current->type,
  +             OBJ_PIN, OBJ_PIN);
  +#endif
  +      
  +      switch (o_current->type) {
  +
  +        case(OBJ_LINE):
  +          out = (char *) o_line_save(o_current);
  +          break;
  +
  +        case(OBJ_NET):
  +          out = (char *) o_net_save(o_current);
  +          break;
  +
  +        case(OBJ_BUS):
  +          out = (char *) o_bus_save(o_current);
  +          break;
  +
  +        case(OBJ_BOX):
  +          out = (char *) o_box_save(o_current);
  +          break;
  +		
  +        case(OBJ_CIRCLE):
  +          out = (char *) o_circle_save(o_current);
  +          break;
  +
  +        case(OBJ_COMPLEX):
  +        case(OBJ_PLACEHOLDER):  /* new type -- SDB 1.20.2005 */
  +          out = (char *) o_complex_save(o_current);
  +          break;
  +
  +        case(OBJ_TEXT):
  +          out = (char *) o_text_save(o_current);
  +          break;
  +
  +        case(OBJ_PIN):
  +          out = (char *) o_pin_save(o_current);
  +          break;
  +
  +        case(OBJ_ARC):
  +          out = (char *) o_arc_save(o_current);
  +          break;
  +
  +  	case(OBJ_PICTURE):
  +	  out = (char *) o_picture_save(o_current); 
  +	  break;
  +
  +        default:
  +          fprintf(stderr, "Error type!\n");
  +          exit(-1);
  +          break;
  +      }
  +      /* output the line */
  +      fprintf(fp, "%s\n", out);
  +      free(out);
  +    }
  +    a_current = a_current->next;
  +  } 
  +
  +  fprintf(fp, "}\n");
  +}
  +
  +/*! \brief Get name and value from name=value attribute.
  + *  \par Function Description
  + *  Get name and value from a name=value attribute.
  + *
  + *  \param [in]  string     String to split into name/value pair.
  + *  \param [out] name_ptr   Name if found in string, NULL otherwise.
  + *  \param [out] value_ptr  Value if found in string, NULL otherwise.
  + *  \return TRUE if string had equals in it, FALSE otherwise.
  + *
  + *  \note
  + *  both name and value must be pre allocated
  + *  And if you get an invalid attribute (improper) with a name and no
  + *  value, then it is NOT an attribute.
  + *  Also, there cannot be any spaces beside the equals sign
  + *  Changed: now it allocates memory for name and value strings.
  + *  \warning
  + *  Caller must free these strings when not needed.
  + */
  +int o_attrib_get_name_value(char *string, char **name_ptr, char **value_ptr )
  +{
  +  char *equal_ptr;
  +#ifdef HAS_GTK22
  +  char **str_array;
  +#else
  +  int attribute_found=FALSE;
  +  int i, j;
  +  char *name, *value;
  +#endif
  +
  +  if (name_ptr == NULL || value_ptr == NULL) {
  +    return(FALSE);
  +  }
  +
  +  *name_ptr = NULL;  /* force these values to null */
  +  *value_ptr = NULL;
  +
  +  if (!string) {
  +    return(FALSE);
  +  }
  +
  +  /* make sure there are no spaces in between equals */
  +  equal_ptr = strchr(string, '=');
  +  if (equal_ptr == NULL) {
  +    return(FALSE);
  +  }
  +
  +  if ( (*(equal_ptr + 1) == ' ') || (*(equal_ptr - 1) == ' ') ) {
  +     /* sometimes you have text with an ='s in it, it shouldn't be */
  +
  +#if DEBUG 
  +    /* treated like an attribute */
  +    s_log_message("Found attrib/text with spaces beside the ='s [%s]\n", 
  +	          string);
  +    s_log_message("You can ignore the above message if the text is not intended to be an attribute\n");
  +    fprintf(stderr, "Found an attribute with spaces beside the ='s [%s]\n", 
  +            string);
  +#endif
  +
  +    return(FALSE);
  +  }
  +
  +#ifdef HAS_GTK22  
  +
  +  /* can't use g_strsplit under glib/gtk+ 1.2 since it splits strings */
  +  /* incorrectly! */
  +  str_array = g_strsplit (string, "=", 2);
  +  
  +  *name_ptr = g_strdup(str_array[0]);
  +  *value_ptr = g_strdup(str_array[1]);
  +  g_strfreev(str_array);
  +
  +#else
  +
  +  /* larger than needed... but this is okay for now. */
  +  *name_ptr  = g_strdup (string);
  +  *value_ptr = g_strdup (string);
  +
  +  /* for convenience sake */
  +  name = *name_ptr;
  +  value = *value_ptr;
  +
  +  /* get the name */
  +  i = 0;
  +  while(string[i] != '\0' && !attribute_found) {
  +    if (string[i] == '=') {
  +      attribute_found = TRUE;
  +    } else {
  +      name[i] = string[i];
  +      i++;
  +    }
  +  }
  +
  +  /* no = found */
  +  if (!attribute_found) {
  +    free(*name_ptr); *name_ptr = NULL; 
  +    free(*value_ptr); *value_ptr = NULL;
  +    return(FALSE);
  +  }
  +
  +  name[i] = '\0';
  +  i++; /* skip over the ='s */
  +
  +  j = 0;
  +  while(string[i] != '\0') {
  +    value[j] = string[i];
  +    i++;
  +    j++;
  +  }
  +
  +  value[j] = '\0';
  +
  +#endif
  +  
  +  if (*value_ptr && (*value_ptr)[0] == '\0') {
  +    s_log_message("Found an improper attribute: _%s_\n", string);
  +#if 0 /* for now leak this memory till this is verified correct everywhere */
  +    free(*name_ptr); *name_ptr = NULL;
  +    free(*value_ptr); *value_ptr = NULL;
  +#endif
  +    return(FALSE);
  +  } else {
  +    return(TRUE);
  +  }
  +}
  +
  +/*! \brief Free the currently selected attribute.
  + *  \par Function Description
  + *  Free the currently selected attribute.
  + *
  + *  \param [in] w_current  The TOPLEVEL object containing current attribute.
  + *
  + */
  +void o_attrib_free_current(TOPLEVEL *w_current)
  +{
  +  if (w_current->current_attribute) {
  +    free(w_current->current_attribute);
  +  }
  +  w_current->current_attribute=NULL;
  +}
  +
  +/*! \brief Set current show flag.
  + *  \par Function Description
  + *  Set current show flag.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] flag       Any value which show_name_value takes.
  + *                         #SHOW_NAME_VALUE
  + *                         #SHOW_VALUE
  + *                         #SHOW_NAME
  + */
  +void o_attrib_set_show(TOPLEVEL *w_current, int flag)
  +{
  +  w_current->current_show = flag;
  +}
  +
  +/*! \brief Set current visibility flag.
  + *  \par Function Description
  + *  Set current visibility flag.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] flag       Allowed values are:
  + *                         #VISIBLE
  + *                         #INVISIBLE
  + */
  +void
  +o_attrib_set_visible(TOPLEVEL *w_current, int flag)
  +{
  +  w_current->current_visible = flag;
  +}
  +
  +/*! \brief Set an attribute's string.
  + *  \par Function Description
  + *  Set an attribute's string.
  + *
  + *  \param [in] w_current  The TOPLEVEL object that holds the attribute.
  + *  \param [in] string     The value to set attribute string to.
  + *
  + *  \note
  + *  The user of this function must free the
  + *  <B>w_current->current_attribute</B> string after done using it.
  + *  They must also free the input string.
  + */
  +void o_attrib_set_string(TOPLEVEL *w_current, char *string)
  +{
  +  int len;
  +
  +  /* need to put an error messages here */
  +  if (string == NULL)  {
  +    fprintf(stderr, "error! string in set_string was NULL\n");
  +    return;
  +  }
  +
  +  if (w_current->current_attribute != NULL) {
  +    free(w_current->current_attribute);
  +    w_current->current_attribute=NULL;
  +  }
  +
  +  len = strlen(string);
  +
  +  w_current->current_attribute = (char *) 
  +  malloc(sizeof(char)*len+1);
  +
  +  strcpy(w_current->current_attribute,string);
  +	
  +  /* be sure to free this string somewhere and free the input string */
  +}
  +
  +/*! \brief Get the parent OBJECT of an attribute.
  + *  \par Function Description
  + *  Get the parent OBJECT of an attribute.
  + *
  + *  \param [in] attribute  ATTRIB pointer to get parent of.
  + *  \return The parent OBJECT if it exists, otherwise NULL.
  + */
  +OBJECT *o_attrib_return_parent(ATTRIB *attribute) 
  +{
  +  ATTRIB *a_current;
  +
  +  a_current = attribute;
  +
  +  if (!a_current) {
  +    return(NULL);
  +  }
  +  
  +  while (a_current->prev != NULL) {
  +    a_current = a_current->prev;	
  +  }	
  +
  +  /* should be pointing to the parent */
  +	
  +  return(a_current->object);	
  +}
  +
  +/*! \brief Copy all attributes.
  + *  \par Function Description
  + *  This function will copy all attributes from the provided list
  + *  by attaching them to the provided OBJECT list.
  + *
  + *  \param [in]  w_current    The TOPLEVEL object.
  + *  \param [out] attached_to  OBJECT list to copy attributes to.
  + *  \param [in]  attributes   ATTRIB list to copy attributes from.
  + *  \return new attribute list.
  + */
  +ATTRIB *o_attrib_copy_all(TOPLEVEL *w_current, OBJECT *attached_to,
  +			  ATTRIB *attributes) 
  +{
  +  ATTRIB *a_current=NULL;
  +  ATTRIB *a_head=NULL;
  +  ATTRIB *a_new=NULL;
  +  ATTRIB *a_prev=NULL;
  +
  +  a_current = attributes;
  +
  +  while (a_current != NULL) {
  +	
  +    a_new = (ATTRIB *) malloc(sizeof(ATTRIB));
  +	
  +    /* in the case of the head attrib node, object points to 
  +     * the parent which the attributes are attached to */	
  +    if (a_head == NULL) {
  +      a_new->object = attached_to;
  +    } else {
  +      a_new->object = a_current->object;  
  +    }
  +		
  +
  +		
  +    /* object is not null and a_start is not null (ie we are not 
  +     * messing with the head attrib node) 
  +     */
  +    if (a_new->object && a_head != NULL)  {
  +      a_new->object->attached_to = a_new;
  +    }
  +
  +    a_new->copied_to = a_current->copied_to;  
  +
  +    a_new->prev = a_prev; 
  +	
  +    /* set previous's next pointer */
  +    /* if it's null that means we are at the first attrib */
  +    if (a_prev) {
  +      a_prev->next = a_new;
  +    } else {
  +      a_head = a_new;
  +    }
  +	
  +    a_new->next = NULL;
  +    a_prev = a_new;
  +    a_current = a_current->next;	
  +  }	
  +
  +  /* should be pointing to the head node */
  +  return(a_head);	
  +}
  +
  +/*! \brief Reattach attributes.
  + *  \par Function Description
  + *  Reattach attributes.
  + *
  + *  \param [in] attributes  ATTRIB list to reattach.
  + */
  +void o_attrib_reattach(ATTRIB *attributes) 
  +{
  +  ATTRIB *a_current=NULL;
  +
  +  a_current = attributes;
  +	
  +  /* skip over head node */
  +  if (a_current)
  +  a_current = a_current->next;
  +
  +  while (a_current != NULL) {
  +    if (a_current->object)  {
  +      a_current->object->attached_to = a_current;
  +      a_current->object->attribute = 1;
  +    }
  +    a_current = a_current->next;	
  +  }
  +}
  +
  +/*! \brief Set attribute color
  + *  \par Function Description
  + *  This function sets all attribute objects to the right
  + *  color (attribute_color).
  + *
  + *  \param [in]     w_current   The TOPLEVEL object.
  + *  \param [in,out] attributes  ATTRIB list to set colors on.
  + *
  + */
  +void o_attrib_set_color(TOPLEVEL *w_current, ATTRIB *attributes) 
  +{
  +  ATTRIB *a_current;
  +
  +  a_current = attributes;
  +
  +  /* skip over head */
  +  if (a_current) 
  +  a_current = a_current->next;
  +
  +  while (a_current != NULL) {
  +
  +    if (a_current->object) {	
  +			
  +      if (a_current->object->type == OBJ_TEXT &&
  +          a_current->object->text->prim_objs) {
  +
  +				/* I'm not terribly happy with this */
  +		
  +        if (a_current->object->saved_color != -1) {
  +
  +          /* if the object is selected, make */
  +          /* sure it it say selected */
  +          o_complex_set_color(
  +                              a_current->object->text->prim_objs,
  +                              SELECT_COLOR);
  +          a_current->object->color = 
  +            SELECT_COLOR;
  +
  +          o_complex_set_saved_color_only(
  +                                         a_current->object->text->prim_objs,
  +                                         w_current->attribute_color); 
  +          a_current->object->saved_color = w_current->
  +            attribute_color;
  +
  +        } else {
  +          o_complex_set_color(
  +                              a_current->object->text->prim_objs,
  +                              w_current->attribute_color); 
  +          a_current->object->color = 
  +            w_current->attribute_color;
  +        }
  +      }	
  +
  +      a_current = a_current->next;	
  +    }
  +  }
  +}
  +
  +/*! \brief Search for attibute by name.
  + *  \par Function Description
  + *  Search for attribute by name.
  + *
  + *  \warning
  + *  The list is the top level list. Do not pass it an object_head list
  + *  unless you know what you are doing.
  + *  
  + *  Counter is the n'th occurance of the attribute, and starts searching
  + *  from zero.  Zero is the first occurance of an attribute.
  + *
  + *  \param [in] list     OBJECT list to search.
  + *  \param [in] name     Character string with attribute name to search for.
  + *  \param [in] counter  Which occurance to return.
  + *  \return Character string with attribute value, NULL otherwise.
  + *
  + *  \warning
  + *  Caller must free returned character string.
  + */
  +char *o_attrib_search_name(OBJECT *list, char *name, int counter) 
  +{
  +  OBJECT *o_current;
  +  ATTRIB *a_current;
  +  OBJECT *found;
  +  int val;
  +  int internal_counter=0;
  +  char *found_name = NULL;
  +  char *found_value = NULL;
  +  char *return_string = NULL;
  +
  +  o_current = list;
  +
  +  while(o_current != NULL) {
  +    if (o_current->attribs != NULL) {
  +      a_current = o_current->attribs;
  +
  +      while(a_current != NULL) {
  +        found = a_current->object;
  +        if (found != NULL) {
  +          if (found->type == OBJ_TEXT) {
  +            val = o_attrib_get_name_value(found->text->string, 
  +                                          &found_name, &found_value);
  +
  +            if (val) {
  +              if (strcmp(name, found_name) == 0) {
  +                if (counter != internal_counter) {
  +                  internal_counter++;	
  +                } else {
  +                  return_string = (char *) 
  +                    malloc(sizeof(char)*strlen(found_value)+1);
  +                  strcpy(return_string, found_value);
  +		  if (found_name) free(found_name);
  +		  if (found_value) free(found_value);
  +                  return(return_string);
  +                }
  +              }
  +	      if (found_name) { free(found_name); found_name = NULL; }
  +	      if (found_value) { free(found_value); found_value = NULL; }
  +            }	
  +
  +#if DEBUG 
  +            printf("0 _%s_\n", found->text->string);
  +            printf("1 _%s_\n", found_name);
  +            printf("2 _%s_\n", found_value);
  +#endif
  +          }
  +        }
  +        a_current=a_current->next;
  +      }	
  +    }
  +
  +    /* search for attributes outside */
  +
  +    if (o_current->type == OBJ_TEXT) {
  +      if (found_name) free(found_name);
  +      if (found_value) free(found_value);
  +      val = o_attrib_get_name_value(o_current->text->string, 
  +                                    &found_name, &found_value);
  +      if (val) {
  +        if (strcmp(name, found_name) == 0) {
  +          if (counter != internal_counter) {
  +            internal_counter++;	
  +          } else {
  +            return_string = (char *) 
  +              malloc(
  +                     sizeof(char)*
  +                     strlen(found_value)+1);
  +            strcpy(return_string, found_value);
  +	    if (found_name) free(found_name);
  +	    if (found_value) free(found_value);
  +            return(return_string);
  +          }
  +        }
  +	if (found_name) { free(found_name); found_name = NULL; }
  +	if (found_value) { free(found_value); found_value = NULL; }
  +      }	
  +    }
  +
  +    o_current=o_current->next;
  +  }
  +	
  +  if (found_name) free(found_name);
  +  if (found_value) free(found_value);
  +  return (NULL);
  +} 
  +
  +/*! \brief Search list for text string.
  + *  \par Function Description
  + *  Search list for text string.
  + *
  + *  \warning
  + *  The list is the top level list. Do not pass it an object_head list
  + *  unless you know what you are doing.
  + *  
  + *  \param [in] list    OBJECT list to search.
  + *  \param [in] string  Character string to search for.
  + *  \return A matching OBJECT if found, NULL otherwise.
  + */
  +OBJECT *o_attrib_search_string_list(OBJECT *list, char *string)
  +{
  +  OBJECT *o_current;
  +  ATTRIB *a_current;
  +  OBJECT *found;
  +
  +  o_current = list;
  +
  +  while(o_current != NULL) {
  +    /* first search attribute list */
  +    if (o_current->attribs != NULL) {
  +      a_current = o_current->attribs;
  +
  +      while(a_current != NULL) {
  +        found = a_current->object;
  +        if (found != NULL) {
  +          if (found->type == OBJ_TEXT) {
  +            if (strcmp(string, found->text->string) == 0) {
  +              return(found);
  +            }
  +          }	
  +        }
  +        a_current=a_current->next;
  +      }
  +    }	
  +  
  +    /* search for attributes outside (ie the actual object) */
  +    if (o_current->type == OBJ_TEXT) {
  +      if (strcmp(string, o_current->text->string) == 0) {
  +        return(o_current);
  +      }
  +    }
  +    
  +    o_current=o_current->next;
  +  }
  +
  +  return (NULL);
  +} 
  +
  +/*! \brief Search list for partial string match.
  + *  \par Function Description
  + *  Search list for partial string match.
  + *
  + *  Counter is the n'th occurance of the attribute, and starts searching
  + *  from zero.  Zero is the first occurance of an attribute.
  + *
  + *  \param [in] object      The OBJECT list to search.
  + *  \param [in] search_for  Partial character string to search for.
  + *  \param [in] counter     Which occurance to return.
  + *  \return Matching object value if found, NULL otherwise.
  + *
  + *  \warning
  + *  Caller must free returned character string.
  + */
  +char *o_attrib_search_string_partial(OBJECT *object, char *search_for,
  +				     int counter) 
  +{
  +  OBJECT *o_current;
  +  int val;
  +  int internal_counter=0;
  +  char *found_name = NULL;
  +  char *found_value = NULL;
  +  char *return_string = NULL;
  +
  +  o_current = object;
  +
  +  if (o_current == NULL) {
  +    return(NULL);
  +  }
  +
  +  if (o_current->type == OBJ_TEXT) {
  +    if (strstr(o_current->text->string, search_for)) {
  +      if (counter != internal_counter) {
  +        internal_counter++;	
  +      } else {
  +        val = o_attrib_get_name_value(o_current->text->string, 
  +                                      &found_name, &found_value);
  +        if (val) {
  +          return_string = g_strdup(found_value);
  +	  if (found_name) free(found_name);
  +	  if (found_value) free(found_value);
  +	  return(return_string);
  +        }
  +      }
  +    }
  +  }	
  +	
  +  if (found_name) free(found_name);
  +  if (found_value) free(found_value);
  +  return (NULL);
  +} 
  +
  +/*! \brief Check if object matches string.
  + *  \par Function Description
  + *  This function will check if the text->string value of
  + *  the passed OBJECT matches the <B>search_for</B> parameter.
  + *
  + *  \param [in] object      The OBJECT to compare.
  + *  \param [in] search_for  Character string to compare against.
  + *  \return The OBJECT passed in <B>object</B> parameter, NULL otherwise.
  + */
  +OBJECT *o_attrib_search_string_single(OBJECT *object, char *search_for)
  +{
  +  OBJECT *o_current;
  +
  +  o_current = object;
  +
  +  if (o_current == NULL) {
  +    return(NULL);
  +  }
  +
  +  if (o_current->type == OBJ_TEXT) {
  +    if (strcmp(o_current->text->string, search_for) == 0) {
  +      return(o_current);
  +    }
  +  }	
  +	
  +  return (NULL);
  +} 
  +
  +/*! \brief Search for attribute by value and name.
  + *  \par Function Description
  + *  Search for attribute by value and name.
  + *  
  + *  Counter is the n'th occurance of the attribute, and starts searching
  + *  from zero.  Zero is the first occurance of an attribute.
  + *
  + *  The value is the primary search key, but name is checked before
  + *  an OBJECT is returned to ensure the correct OBJECT has been found.
  + *
  + *  \param [in] list     The ATTRIB list to search.
  + *  \param [in] value    Character string with value to search for.
  + *  \param [in] name     Character string with name to compare.
  + *  \param [in] counter  Which occurance to return.
  + *  \return The attribute OBJECT if found, NULL otherwise.
  + *
  + */
  +OBJECT *o_attrib_search_attrib_value(ATTRIB *list, char *value, char *name, 
  +				     int counter) 
  +{
  +  OBJECT *found;
  +  ATTRIB *a_current;
  +  int val;
  +  int internal_counter=0;
  +  char *found_name = NULL;
  +  char *found_value = NULL;
  +
  +  a_current = list;
  +	
  +  if (!value) 
  +  return(NULL);
  +
  +  if (!name) 
  +  return(NULL);
  +
  +  while(a_current != NULL) {
  +    found = a_current->object;
  +    if (found != NULL) {
  +      if (found->type == OBJ_TEXT) {
  +        val = o_attrib_get_name_value(found->text->string, 
  +                                      &found_name, &found_value);
  +
  +        if (val) {
  +#if DEBUG
  +          printf("found value: %s\n", found_value);
  +          printf("looking for: %s\n", value);
  +#endif
  +          if (strcmp(value, found_value) == 0) {
  +            if (counter != internal_counter) {
  +              internal_counter++;	
  +            } else {
  +              if (strstr(found_name, name)) {
  +		if (found_name) free(found_name);
  +		if (found_value) free(found_value);
  +                return(found);
  +              }
  +            }
  +          }
  +	  if (found_name) { free(found_name); found_name = NULL; }
  +	  if (found_value) { free(found_value); found_value = NULL; }
  +        }	
  +
  +      }
  +    }
  +    a_current=a_current->next;
  +  }
  +
  +  if (found_name) free(found_name);
  +  if (found_value) free(found_value);
  +  return (NULL);
  +} 
  +
  +/*! \brief Search for an attribute by name.
  + *  \par Function Description
  + *  Search for an attribute by name.
  + *
  + *  Counter is the n'th occurance of the attribute, and starts searching
  + *  from zero.  Zero is the first occurance of an attribute.
  + *
  + *  \param [in] list     ATTRIB list to search.
  + *  \param [in] name     Character string with attribute name to search for.
  + *  \param [in] counter  Which occurance to return.
  + *  \return Character string with attribute value, NULL otherwise.
  + *
  + *  \warning
  + *  Caller must free returned character string.
  + */
  +char *
  +o_attrib_search_attrib_name(ATTRIB *list, char *name, int counter) 
  +{
  +  OBJECT *found;
  +  ATTRIB *a_current;
  +  int val;
  +  int internal_counter=0;
  +  char *found_name = NULL;
  +  char *found_value = NULL;
  +  char *return_string = NULL;
  +
  +  a_current = list;
  +
  +  while(a_current != NULL) {
  +    found = a_current->object;
  +    if (found != NULL) {
  +      if (found->type == OBJ_TEXT) {
  +        val = o_attrib_get_name_value(found->text->string, 
  +                                      &found_name, &found_value);
  +
  +        if (val) {
  +#if DEBUG
  +          printf("found name: %s\n", found_name);
  +          printf("looking for: %s\n", name);
  +#endif
  +          if (strcmp(name, found_name) == 0) {
  +            if (counter != internal_counter) {
  +              internal_counter++;	
  +            } else {
  +              return_string = (char *) 
  +                malloc(sizeof(char)*
  +                       strlen(found_value)+1);
  +              strcpy(return_string, found_value);
  +	      if (found_name) free(found_name);
  +	      if (found_value) free(found_value);
  +              return(return_string);
  +            }
  +          }
  +	  if (found_name) { free(found_name); found_name = NULL; }
  +	  if (found_value) { free(found_value); found_value = NULL; }
  +        }	
  +      }
  +    }
  +    a_current=a_current->next;
  +  }
  +
  +  if (found_name) free(found_name);
  +  if (found_value) free(found_value);
  +  return (NULL);
  +} 
  +
  +/*! \brief Search TOPLEVEL attributes.
  + *  \par Function Description
  + *  This function should only be used to search for TOPLEVEL attributes.
  + *  \warning
  + *  The list is the top level list. Do not pass it an object_head list
  + *  unless you know what you are doing.
  + *  
  + *  Counter is the n'th occurance of the attribute, and starts searching
  + *  from zero.  Zero is the first occurance of an attribute.
  + * 
  + *  \param [in] list     The OBJECT list to search (TOPLEVEL only).
  + *  \param [in] name     Character string of attribute name to search for.
  + *  \param [in] counter  Which occurance to return.
  + *  \return Character string with attribute value, NULL otherwise.
  + *
  + *  \warning
  + *  Caller must free returned character string.
  + */
  +char *o_attrib_search_toplevel(OBJECT *list, char *name, int counter) 
  +{
  +  OBJECT *o_current;
  +  int val;
  +  int internal_counter=0;
  +  char *found_name = NULL;
  +  char *found_value = NULL;
  +  char *return_string = NULL;
  +
  +  o_current = list;
  +
  +  while(o_current != NULL) {
  +
  +    /* search for attributes outside */
  +
  +    if (o_current->type == OBJ_TEXT) {
  +      val = o_attrib_get_name_value(o_current->text->string, 
  +                                    &found_name, &found_value);
  +      if (val) {
  +        if (strcmp(name, found_name) == 0) {
  +          if (counter != internal_counter) {
  +            internal_counter++;	
  +          } else {
  +            return_string = (char *) 
  +              malloc(sizeof(char)*
  +                     strlen(found_value)+1);
  +            strcpy(return_string, found_value);
  +	    if (found_name) free(found_name);
  +	    if (found_value) free(found_value);
  +            return(return_string);
  +          }
  +        }
  +	if (found_name) { free(found_name); found_name = NULL; }
  +	if (found_value) { free(found_value); found_value = NULL; }
  +      }	
  +    }
  +
  +    o_current=o_current->next;
  +  }
  +	
  +  if (found_name) free(found_name);
  +  if (found_value) free(found_value);
  +  return (NULL);
  +} 
  +
  +/*! \brief Search for special attributes.
  + *  \par Function Description
  + *  This function will search an OBJECT list for the special
  + *  attributes <EM>"gnd"</EM> and <EM>"vdd"</EM>.
  + *
  + *  \param [in] o_current  The OBJECT list to search.
  + *  \return Character string with attribute value, NULL otherwise.
  + *
  + *  \warning
  + *  Caller must free returned character string.
  + */
  +/* be sure caller free's return value */
  +char *o_attrib_search_special(OBJECT *o_current) 
  +{
  +  char *return_value;
  +
  +  return_value = o_attrib_search_name(o_current->complex->prim_objs, 
  +                                      "gnd", 0);
  +
  +  if (return_value) {
  +    return(return_value);
  +  }
  +
  +  return_value = o_attrib_search_name(o_current->complex->prim_objs, 
  +                                      "vdd", 0);
  +
  +  if (return_value) {
  +    return(return_value);
  +  }
  +
  +  return(NULL);
  +}
  +
  +#line 1849 "../noweb/o_attrib.nw"
  +/*! \brief Search for first occurance of a named attribute.
  + *  \par Function Description
  + *  Search for first occurance of a named attribute.
  + *
  + *  \param [in]  object        The OBJECT list to search.
  + *  \param [in]  name          Character string of attribute name to search for.
  + *  \param [out] return_found  Contains attribute OBJECT if found, NULL otherwise.
  + *  \return Character string with attribute value, NULL otherwise.
  + *
  + *  \warning
  + *  Caller must free returned character string.
  + */
  +char *o_attrib_search_name_single(OBJECT *object, char *name,
  +				  OBJECT **return_found) 
  +{
  +  OBJECT *o_current;
  +  ATTRIB *a_current;
  +  OBJECT *found=NULL;
  +  int val;
  +  char *found_name = NULL;
  +  char *found_value = NULL;
  +  char *return_string = NULL;
  +
  +  o_current = object;
  +
  +  if (o_current == NULL) {
  +    return(NULL);
  +  }
  +
  +  if (o_current->attribs != NULL) {
  +    a_current = o_current->attribs;
  +
  +    while(a_current != NULL) {
  +      found = a_current->object;
  +      if (found != NULL) {
  +        if (found->type == OBJ_TEXT) {
  +          val = o_attrib_get_name_value(found->text->string, 
  +					&found_name, &found_value);
  +
  +          if (val) {
  +            if (strcmp(name, found_name) == 0) {
  +              return_string = (char *) 
  +                malloc(sizeof(char)*
  +                       strlen(found_value)+1);
  +              strcpy(return_string, found_value);
  +              if (return_found) {
  +                *return_found = found;
  +              }
  +	      if (found_name) free(found_name);
  +	      if (found_value) free(found_value);
  +              return(return_string);
  +            }
  +	    if (found_name) { free(found_name); found_name = NULL; }
  +	    if (found_value) { free(found_value); found_value = NULL; }
  +          }
  +
  +#if DEBUG
  +          printf("0 _%s_\n", found->text->string);
  +          printf("1 _%s_\n", found_name);
  +          printf("2 _%s_\n", found_value);
  +#endif
  +        }
  +      }
  +      a_current=a_current->next;
  +    }	
  +  }
  +  /* search for attributes outside */
  +
  +  if (o_current->type == OBJ_TEXT) {
  +    if (found_name) free(found_name);
  +    if (found_value) free(found_value);
  +    val = o_attrib_get_name_value(o_current->text->string, 
  +                                  &found_name, &found_value);
  +
  +    if (val) {
  +      if (strcmp(name, found_name) == 0) {
  +        return_string = (char *) 
  +          malloc(sizeof(char)*
  +                 strlen(found_value)+1);
  +        strcpy(return_string, found_value);
  +        if (return_found) {
  +          *return_found = found;
  +        }
  +	if (found_name) free(found_name);
  +	if (found_value) free(found_value);
  +        return(return_string);
  +      }
  +      if (found_name) { free(found_name); found_name = NULL; }
  +      if (found_value) { free(found_value); found_value = NULL; }
  +    }	
  +  }
  +
  +  if (return_found) {
  +    *return_found = NULL;
  +  }
  +  
  +  if (found_name) free(found_name);
  +  if (found_value) free(found_value);
  +  return (NULL);
  +} 
  +
  +/*! \brief Search for N'th occurance of a named attribute.
  + *  \par Function Description
  + *  Search for N'th occurance of a named attribute.
  + *
  + *  \param [in] object   The OBJECT list to search.
  + *  \param [in] name     Character string of attribute name to search for.
  + *  \param [in] counter  Which occurance to return.
  + *  \return Character string with attribute value, NULL otherwise.
  + *  
  + *  \warning
  + *  Caller must free returned character string.
  + */
  +/* be sure caller free's return value */
  +/* this function is like above, except that it returns the n'th occurance */
  +/* of the attribute.  counter starts counting at zero */
  +char *o_attrib_search_name_single_count(OBJECT *object, char *name, 
  +					int counter) 
  +{
  +  OBJECT *o_current;
  +  ATTRIB *a_current;
  +  OBJECT *found=NULL;
  +  int val;
  +  char *found_name = NULL;
  +  char *found_value = NULL;
  +  char *return_string = NULL;
  +  int internal_counter=0;
  +	
  +
  +  o_current = object;
  +
  +  if (o_current == NULL) {
  +    return(NULL);
  +  }
  +
  +  if (o_current->attribs != NULL) {
  +    a_current = o_current->attribs;
  +
  +    while(a_current != NULL) {
  +      found = a_current->object;
  +      if (found != NULL) {
  +        if (found->type == OBJ_TEXT) {
  +          val = o_attrib_get_name_value(found->text->string, 
  +					&found_name, &found_value);
  +
  +          if (val) {
  +            if (strcmp(name, found_name) == 0) {
  +              if (counter != internal_counter) {
  +                internal_counter++;
  +              } else {
  +                return_string = (char *) 
  +                  malloc(sizeof(char)*
  +                         strlen(found_value)+1);
  +                strcpy(return_string, found_value);
  +		if (found_name) free(found_name);
  +		if (found_value) free(found_value);
  +                return(return_string);
  +              }
  +            }
  +            if (found_name) { free(found_name); found_name = NULL; }
  +            if (found_value) { free(found_value); found_value = NULL; }
  +          }
  +
  +#if DEBUG 
  +          printf("0 _%s_\n", found->text->string);
  +          printf("1 _%s_\n", found_name);
  +          printf("2 _%s_\n", found_value);
  +#endif
  +        }
  +      }
  +      a_current=a_current->next;
  +    }	
  +
  +  }
  +  /* search for attributes outside */
  +
  +  if (o_current->type == OBJ_TEXT) {
  +    if (found_name) free(found_name);
  +    if (found_value) free(found_value);
  +    val = o_attrib_get_name_value(o_current->text->string, 
  +                                  &found_name, &found_value);
  +
  +    if (val) {
  +      if (strcmp(name, found_name) == 0) {
  +        if (counter != internal_counter) {
  +          internal_counter++;
  +        } else {
  +          return_string = (char *) 
  +            malloc(sizeof(char)*
  +                   strlen(found_value)+1);
  +          strcpy(return_string, found_value);
  +	  if (found_name) free(found_name);
  +	  if (found_value) free(found_value);
  +          return(return_string);
  +        }
  +      }
  +      if (found_name) { free(found_name); found_name = NULL; }
  +      if (found_value) { free(found_value); found_value = NULL; }
  +    }
  +  }	
  +  
  +  if (found_name) free(found_name);
  +  if (found_value) free(found_value);
  +  return (NULL);
  +} 
  +
  +/*! \brief Search for slot attribute.
  + *  \par Function Description
  + *  Search for slot attribute.
  + *
  + *  \param [in] object        OBJECT list to search.
  + *  \param [in] return_found  slot attribute if found, NULL otherwise.
  + *  \return Character string with attribute value, NULL otherwise.
  + *
  + *  \warning
  + *  Caller must free returned character string
  + */
  +char *o_attrib_search_slot(OBJECT *object, OBJECT **return_found)
  +{
  +  char *return_value;
  +
  +  /* search for default value attribute buried inside the complex */
  +  return_value = o_attrib_search_name_single(object, "slot", return_found);
  +
  +  /* I'm confused here does the next if get ever called? */
  +  if (return_value) {
  +    return(return_value);
  +  }
  +
  +  if (return_found) {
  +    *return_found = NULL;
  +  }
  +  return(NULL);
  +}
  +
  +/*! \brief Search for numslots attribute.
  + *  \par Function Description
  + *  Search for numslots attribute.
  + *
  + *  \param [in] object        OBJECT to search.
  + *  \param [in] return_found  numslots attribute if found, NULL otherwise.
  + *  \return Character string with attribute value, NULL otherwise.
  + *
  + *  \note
  + *  Caller must free returned character string.
  + */
  +char *o_attrib_search_numslots(OBJECT *object, OBJECT **return_found)
  +{
  +  char *return_value;
  +
  +  /* search for numslots attribute buried inside the complex */
  +  return_value = o_attrib_search_name(object->complex->prim_objs, 
  +                                      "numslots", 0);
  +
  +  if (return_value) {
  +    return(return_value);
  +  }
  +
  +  if (return_found) {
  +    *return_found = NULL;
  +  }
  +  return(NULL);
  +}
  +
  +/*! \brief Search for default slot attribute.
  + *  \par Function Description
  + *  Search for default slot attribute.
  + *
  + *  \param [in] object  OBJECT list to search.
  + *  \return Character string with attribute value, NULL otherwise.
  + *
  + *  \warning
  + *  Caller must free returned character string.
  + */
  +char *o_attrib_search_default_slot(OBJECT *object)
  +{
  +  char *return_value;
  +
  +  /* search for default value attribute buried inside the complex */
  +  return_value = o_attrib_search_name(object->complex->prim_objs, 
  +                                      "slot", 0);
  +
  +  if (return_value) {
  +    return(return_value);
  +  }
  +
  +  return(NULL);
  +}
  +
  +/*! \brief Search pinseq attribute.
  + *  \par Function Description
  + *  Search pinseq attribute.
  + *
  + *  \param [in] list        OBJECT list to search.
  + *  \param [in] pin_number  pin number to search for.
  + *  \return OBJECT containing pinseq data, NULL otherwise.
  + */
  +OBJECT *o_attrib_search_pinseq(OBJECT *list, int pin_number)
  +{
  +  OBJECT *pinseq_text_object;
  +  char *search_for;
  +
  +  /* The 9 is the number of digits plus null */
  +  search_for = (char *) malloc(sizeof(char)*(strlen("pinseq=")+9));
  +  sprintf(search_for, "pinseq=%d", pin_number);
  +
  +  pinseq_text_object = o_attrib_search_string_list(list, search_for);
  +  free(search_for);
  +  
  +  if (pinseq_text_object && pinseq_text_object->attached_to) {
  +    return(o_attrib_return_parent(pinseq_text_object->attached_to));
  +  }
  +  
  +  return(NULL);
  +}
  +
  +/*! \brief Search for slotdef attribute.
  + *  \par Function Description
  + *  Search for slotdef attribute.
  + *
  + *  \param [in] object      The OBJECT list to search.
  + *  \param [in] slotnumber  The slot number to search for.
  + *  \return Character string with attribute value, NULL otherwise.
  + *
  + *  \warning
  + *  Caller must free returned character string.
  + */
  +char *o_attrib_search_slotdef(OBJECT *object, int slotnumber)
  +{
  +  char *return_value=NULL;
  +  char *search_for=NULL;
  +  OBJECT *o_current;
  +
  +  /* The 9 is the number of digits plus null */
  +  search_for = (char *) malloc(sizeof(char)*(strlen("slotdef=:")+9));
  +
  +  sprintf(search_for, "slotdef=%d:", slotnumber);
  +
  +  o_current = object->complex->prim_objs;
  +  while (o_current != NULL) {
  +    return_value = o_attrib_search_string_partial(o_current, search_for, 0);
  +    if (return_value) {
  +	break;
  +    }
  +    o_current = o_current->next; 
  +  }
  +  free(search_for);
  +  
  +  if (return_value) {
  +    return(return_value);
  +  }
  +
  +  return(NULL);
  +}
  +
  +/*! \brief Search for component.
  + *  \par Function Description
  + *  Search for component.
  + *
  + *  \param [in] object  The OBJECT list to search.
  + *  \param [in] name    Character string containing component name to match.
  + *  \return Character string with the component value, NULL otherwise.
  + */
  +char *o_attrib_search_component(OBJECT *object, char *name)
  +{
  +  char *return_value = NULL;
  +
  +  if (!name) {
  +    return(NULL);
  +  }
  +
  +  if (object->type != OBJ_COMPLEX && object->type != OBJ_PLACEHOLDER) {
  +    return(NULL);
  +  }
  +
  +  /* first look inside the complex object */
  +  return_value = o_attrib_search_name(object->complex->prim_objs, 
  +                                      name, 0);
  +
  +  if (return_value) {
  +    return(return_value);
  +  }
  +
  +  /* now look outside to see if it was attached externally */
  +  return_value = o_attrib_search_name_single(object, name, NULL);
  +
  +  if (return_value) {
  +    return(return_value);
  +  }
  +
  +  return(NULL);
  +}
  +
  +/*! \brief Update all slot attributes in an object.
  + *  \par Function Description
  + *  Update all slot attributes in an object.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in,out] object     The OBJECT to update.
  + */
  +void o_attrib_slot_update(TOPLEVEL *w_current, OBJECT *object)
  +{
  +  OBJECT *o_current;
  +  OBJECT *o_slot_attrib;
  +  OBJECT *o_pin_object;
  +  OBJECT *o_pinnum_object;
  +  char *string;
  +  char *slotdef;
  +  int slot;
  +  int pin_counter;
  +  char* current_pin;
  +  char* cptr;
  +
  +  o_current = object;
  +	
  +  string = o_attrib_search_slot(o_current, &o_slot_attrib);
  +	
  +  if (!string) {
  +    /* s_log_message("Did not find slot= attribute\n"); */
  +    /* not a serious error */
  +    return;
  +  } 
  +  slot = atoi(string);
  +  free(string);
  +  
  +  slotdef = o_attrib_search_slotdef(o_current, slot);
  +  
  +  if (!slotdef) {
  +    s_log_message("Did not find slotdef=#:#,#,#... attribute\n");
  +    return;
  +  }
  +
  +  if (!strstr(slotdef, ":")) {
  +    /*! \todo didn't proper slotdef=#:... TODO into log*/
  +    return;
  +  }
  +
  +  /* skip over slotdef number */
  +  /* slotdef is in the form #:#,#,# */
  +  /* this code skips first #: */
  +  cptr = slotdef;
  +  while (*cptr != '\0' && *cptr != ':') {
  +    cptr++;
  +  }
  +  cptr++; /* skip colon */
  +
  +  if (*cptr == '\0') {
  +    s_log_message("Did not find proper slotdef=#:#,#,#... attribute\n");
  +    return;
  +  }
  +  
  +  pin_counter = 1;
  +  current_pin = strtok(cptr, DELIMITERS);
  +  while(current_pin != NULL) {
  +
  +    o_pin_object = o_attrib_search_pinseq(o_current->complex->prim_objs, 
  +                                          pin_counter);
  +
  +    if (o_pin_object) {
  +
  +      string = o_attrib_search_name_single(o_pin_object, "pinnumber",
  +                                           &o_pinnum_object);
  +  
  +      if (string && o_pinnum_object && o_pinnum_object->type == OBJ_TEXT &&
  +          o_pinnum_object->text->string) {
  +        free(string);
  +        free(o_pinnum_object->text->string);
  +
  +        /* 9 is the size of one number plus null character */
  +        o_pinnum_object->text->string = (char *)
  +          malloc(sizeof(char)*(strlen("pinnumber=")+strlen(current_pin)+9));
  +
  +        /* removed _int from current_pin */
  +        sprintf(o_pinnum_object->text->string, "pinnumber=%s", current_pin);
  +        
  +        o_text_recreate(w_current, o_pinnum_object);
  +      }
  +      
  +      pin_counter++;
  +    } else {
  +      s_log_message("component missing pinseq= attribute\n");
  +    }
  +    
  +    current_pin = strtok(NULL, DELIMITERS);
  +  } 
  +  
  +  free(slotdef);
  +}
  +
  +/*! \brief Copy attributes from OBJECT to OBJECT.
  + *  \par Function Description
  + *  This function will perform a slot copy of the <B>original</B> OBJECT
  + *  to the <B>target</B> OBJECT.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  original   The original OBJECT to slot copy from.
  + *  \param [out] target     The target OBJECT to slot copy to.
  + */
  +void o_attrib_slot_copy(TOPLEVEL *w_current, OBJECT *original, OBJECT *target)
  +{
  +
  +  OBJECT *o_current;
  +  OBJECT *o_slot_attrib;
  +  OBJECT *o_pin_object;
  +  OBJECT *o_pinnum_object;
  +  char *string;
  +  char *slotdef;
  +  int slot;
  +  int pin_counter;
  +  char* current_pin;
  +  char* cptr;
  +
  +  o_current = original;
  +	
  +  string = o_attrib_search_slot(o_current, &o_slot_attrib);
  +	
  +  if (!string) {
  +    /* s_log_message("Did not find slot= attribute\n"); */
  +    /* not a serious error */
  +    return;
  +  } 
  +  slot = atoi(string);
  +  free(string);
  +  
  +  slotdef = o_attrib_search_slotdef(o_current, slot);
  + 
  +  if (!slotdef) {
  +    s_log_message("Did not find slotdef=#:#,#,#... attribute\n");
  +    return;
  +  }
  +
  +  if (!strstr(slotdef, ":")) {
  +    /*! \todo didn't proper slotdef=#:... TODO into log*/
  +    return;
  +  }
  +
  +  /* skip over slotdef number */
  +  /* slotdef is in the form #:#,#,# */
  +  /* this code skips first #: */
  +  cptr = slotdef;
  +  while (*cptr != '\0' && *cptr != ':') {
  +    cptr++;
  +  }
  +  cptr++; /* skip colon */
  +
  +  if (*cptr == '\0') {
  +    s_log_message("Did not find proper slotdef=#:#,#,#... attribute\n");
  +    return;
  +  }
  +  
  +  pin_counter = 1;
  +  current_pin = strtok(cptr, DELIMITERS);
  +  while(current_pin != NULL) {
  +
  +    o_pin_object = o_attrib_search_pinseq(target->complex->prim_objs, 
  +                                          pin_counter);
  +
  +    if (o_pin_object) {
  +
  +      string = o_attrib_search_name_single(o_pin_object, "pinnumber",
  +                                           &o_pinnum_object);
  +  
  +      if (string && o_pinnum_object && o_pinnum_object->type == OBJ_TEXT &&
  +          o_pinnum_object->text->string) {
  +
  +        free(string);
  +        free(o_pinnum_object->text->string);
  +
  +        /* 9 is the size of one number plus null character */
  +        o_pinnum_object->text->string = (char *)
  +          malloc(sizeof(char)*(strlen("pinnumber=")+strlen(current_pin)+9));
  +
  +        /* removed _int from current_pin */
  +        sprintf(o_pinnum_object->text->string, "pinnumber=%s", current_pin);
  +        
  +        o_text_recreate(w_current, o_pinnum_object);
  +      }
  +      
  +      pin_counter++;
  +    } else {
  +      s_log_message("component missing pinseq= attribute\n");
  +    }
  +    
  +    current_pin = strtok(NULL, DELIMITERS);
  +  } 
  +  
  +  free(slotdef);
  +}
  +
  +/*! \brief Get the number of TOPLEVEL attributes in all loaded pages.
  + *  \par Function Description
  + *  This function will return the number of TOPLEVEL attributes
  + *  in all loaded pages.
  + *
  + *  \param [in] w_current  The TOPLEVEL object to search.
  + *  \param [in] name       Attribute name to search for.
  + *  \return Count of TOPLEVEL attributes in all loaded pages.
  + */
  +/* returns the number of toplevel attributes in all loaded pages */
  +int o_attrib_count_toplevel(TOPLEVEL *w_current, char *name)
  +{
  +  int ret_value=0;
  +  int counter=0;
  +  PAGE *p_current;
  +  char *string;
  +
  +  p_current = w_current->page_head;
  +
  +  while(p_current != NULL) {
  +
  +    counter = 0;
  +    string = o_attrib_search_name(p_current->object_head, 
  +                                  name, counter); 
  +    printf("%s %d\n", name, counter);
  +    while(string) {
  +      printf("inside\n");
  +      ret_value++;
  +      free(string);
  +      string=NULL;
  +      counter++;
  +
  +      string = o_attrib_search_name(p_current->object_head, 
  +                                    name, counter); 
  +    }
  +
  +    p_current=p_current->next;
  +  }
  +  return(ret_value);
  +}
  +
  +/*! \brief Search for first TOPLEVEL attribute.
  + *  \par Function Description
  + *  This function searches all loaded pages for the first
  + *  TOPLEVEL attribute found.
  + *  The caller is responsible for freeing the returned value.
  + *  See #o_attrib_search_toplevel() for other comments.
  + *
  + *  \param [in] page_head  PAGE head object to search through.
  + *  \param [in] name       Character string name to search for.
  + *  \return Character string from the found attribute, NULL otherwise.
  + */
  +char *o_attrib_search_toplevel_all(PAGE *page_head, char *name)
  +{
  +  PAGE *p_current;
  +  char *ret_value=NULL;
  +
  +  p_current = page_head;
  +
  +  while (p_current != NULL) {
  +
  +
  +    /* don't look into the head of page_head */
  +    if (p_current->pid != -1) {
  +
  +      /* only look for first occurrance of the attribute */
  +      ret_value = o_attrib_search_toplevel(
  +                                           p_current->object_head, 
  +                                           name, 0);
  +    }
  +
  +    if (ret_value != NULL) {
  +      return(ret_value);
  +    }
  +		
  +    p_current = p_current->next;
  +  }
  +
  +  return(NULL);
  +}
  +
  +/*! \brief Get all attached attributes to specified OBJECT.
  + *  \par Function Description
  + *  This function returns all attached attribute objects to the
  + *  specified object.
  + *  The returned list is an array of objects and should be freed using the
  + *  #o_attrib_free_returned() function.
  + *  This function will only look for attached attributes and not
  + *  unattached free floating attribs.
  + *
  + *  \param [in] object_list  OBJECT list to search.
  + *  \param [in] sel_object   OBJECT to search for.
  + *  \return An array of objects that matched sel_object, NULL otherwise.
  + */
  +OBJECT ** o_attrib_return_attribs(OBJECT *object_list, OBJECT *sel_object) 
  +{
  +  OBJECT **found_objects;
  +  int num_attribs=0;
  +  int i=0;
  +  ATTRIB *a_current;	
  +  OBJECT *o_current;
  +  OBJECT *object;
  +
  +  object = (OBJECT *) o_list_search(object_list, sel_object);
  +
  +  if (!object) {
  +    return(NULL);	
  +  }
  +
  +  if (!object->attribs) {
  +    return(NULL);
  +  }
  +
  +  if (!object->attribs->next) {
  +    return(NULL);
  +  }
  +
  +
  +  /* first go through and count the number of attribs */
  +  a_current = object->attribs->next;	
  +  while(a_current != NULL) {
  +    num_attribs++;
  +    a_current = a_current->next;
  +  }
  +
  +  found_objects = (OBJECT **) malloc(sizeof(OBJECT *)*(num_attribs+1));
  +
  +  /* now actually fill the array of objects */
  +  a_current = object->attribs->next;	
  +  while(a_current != NULL) {
  +    if (a_current->object != NULL) {
  +      o_current = a_current->object;
  +      if (o_current->type == OBJ_TEXT && 
  +          o_current->text->string) {
  +        found_objects[i] = o_current;
  +        i++;
  +      }
  +    }
  +    a_current = a_current->next;
  +  }
  +
  +  found_objects[i] = NULL;
  +
  +#if DEBUG 
  +  i=0;
  +  while(found_objects[i] != NULL) {
  +    /*for (i = 0 ; i < num_attribs; i++) {*/
  +    printf("%d : %s\n", i, found_objects[i]->text->string);
  +    i++;
  +  }
  +#endif
  +
  +  return(found_objects);
  +}
  +
  +/*! \brief Free attached attribute list.
  + *  \par Function Description
  + *  Free attached attribute list. Use only on a list created
  + *  by #o_attrib_return_attribs().
  + *
  + *  \param [in] found_objects  List returned by #o_attrib_return_attribs().
  + */
  +void o_attrib_free_returned(OBJECT **found_objects)
  +{
  +  int i=0;
  +
  +  if (!found_objects) {
  +    return;
  +  }
  +
  +  /* don't free the insides of found_objects, since the contents are */
  +  /* just pointers into the real object list */
  +  while(found_objects[i] != NULL) {
  +    found_objects[i] = NULL;
  +    i++;	
  +  }
  +
  +  free(found_objects);
  +}
  
  
  
  1.14      +213 -116  eda/geda/gaf/libgeda/src/o_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_basic.c
  ===================================================================
  RCS file: o_basic.c
  diff -N o_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_basic.c	5 Jul 2006 03:13:38 -0000	1.14
  @@ -0,0 +1,279 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +
  +/* instrumentation code */
  +#if 0
  +#include <sys/time.h>
  +#include <unistd.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/* \todo 
  + * Lots of Gross code... needs lots of cleanup
  + * mainly readability issues
  + */
  +
  +/*! \brief Check if point is inside a region
  + *  \par Function Description
  + *  This function takes a rectangular region and a point.  It will check
  + *  if the point is located in the region or not.
  + *
  + *  \param [in] left    Left coordinate of the region.
  + *  \param [in] top     Top coordinate of the region.
  + *  \param [in] right   Right coordinate of the region.
  + *  \param [in] bottom  Bottom coordinate of the region.
  + *  \param [in] x       x coordinate of the point to check.
  + *  \param [in] y       y coordinate of the point to check.
  + *  \return 1 if the point is inside the region, 0 otherwise.
  + */
  +int inside_region(int left, int top, int right, int bottom, int x, int y)
  +{
  +  return ((x >= left && x <= right && y >= top && y <= bottom) ? 1 : 0);
  +}
  +
  +/*! \brief Redraw an object on the screen.
  + *  \par Function Description
  + *  This function will redraw a single object on the screen.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  The OBJECT to redraw.
  + *
  + */
  +void o_redraw_single(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  if (o_current == NULL)
  +  return;
  +	
  +  if (w_current->DONT_REDRAW) /* highly experimental */
  +  return;
  +
  +  if (o_current->draw_func != NULL && o_current->type != OBJ_HEAD) {
  +    w_current->inside_redraw = 1;
  +    (*o_current->draw_func)(w_current, o_current);
  +    w_current->inside_redraw = 0;
  +  }
  +}
  +
  +/*! \brief Recalculate position of all objects.
  + *  \par Function Description
  + *  This function will take a list of objects and recalculate their
  + *  positions on the screen.
  + *
  + *  \param [in]     w_current    The TOPLEVEL object.
  + *  \param [in,out] object_list  OBJECT list to recalculate.
  + *
  + */
  +void o_recalc(TOPLEVEL *w_current, OBJECT *object_list)
  +{
  +  OBJECT *o_current;
  +
  +  if (object_list == NULL)
  +  return;
  +	
  +  o_current = object_list;
  +  while (o_current != NULL) {
  +    switch(o_current->type) {
  +
  +      case(OBJ_LINE):
  +        o_line_recalc(w_current, o_current);
  +        break;
  +
  +      case(OBJ_NET):
  +        o_net_recalc(w_current, o_current);
  +        break;
  +
  +      case(OBJ_BUS):
  +        o_bus_recalc(w_current, o_current);
  +        break;
  +
  +      case(OBJ_BOX):
  +        o_box_recalc(w_current, o_current);
  +        break;
  +
  +      case(OBJ_PICTURE):
  +        o_picture_recalc(w_current, o_current);
  +        break;
  +
  +      case(OBJ_CIRCLE):
  +        o_circle_recalc(w_current, o_current);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +        o_complex_recalc(w_current, o_current);
  +        break;
  +
  +      case(OBJ_PIN):
  +        o_pin_recalc(w_current, o_current);
  +        break;
  +
  +      case(OBJ_ARC):
  +        o_arc_recalc(w_current, o_current);
  +        break;
  +    }
  +
  +    o_current = o_current->next;
  +  }
  +}
  +
  +/*! \brief Set an #OBJECT's line options.
  + *  \par Function Description
  + *  This function allows a line's end, type, width, length and space to be set.
  + *  See #OBJECT_END and #OBJECT_TYPE for information on valid
  + *  object end and type values.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in,out] o_current  OBJECT to set line options on.
  + *  \param [in]     end        An OBJECT_END.
  + *  \param [in]     type       An OBJECT_TYPE.
  + *  \param [in]     width      Line width.
  + *  \param [in]     length     Line length.
  + *  \param [in]     space      Spacing between dashes/dots. Cannot be negative.
  + *
  + *  \todo Make space an unsigned int and check for a max value instead.
  + *        If a max value is not required, then it would simplify the code.
  + */
  +void o_set_line_options(TOPLEVEL *w_current, OBJECT *o_current,
  +			OBJECT_END end, OBJECT_TYPE type,
  +			int width, int length, int space) 
  +{
  +  if(o_current == NULL) {
  +    return;
  +  }
  +
  +  /* do some error checking / correcting */
  +  switch(type) {
  +    case(TYPE_DOTTED):
  +    if (space < 1) {
  +      space = 100;
  +      s_log_message ("Invalid space specified, setting to 100\n");
  +    }
  +    break;
  +    case(TYPE_DASHED):
  +    case(TYPE_CENTER):
  +    case(TYPE_PHANTOM):
  +    if (length < 1) {
  +      length = 100;
  +      s_log_message ("Invalid length specified, setting to 100\n");
  +    }
  +    if (space < 1) {
  +      space = 100;
  +      s_log_message ("Invalid space specified, setting to 100\n");
  +    }
  +    break;
  +    default:
  +    
  +    break;
  +  }
  +  
  +  o_current->line_width = width;
  +  o_current->line_end   = end;
  +  o_current->line_type  = type;
  +
  +  o_current->line_length = length;
  +  o_current->line_space  = space;
  +}
  +
  +/*! \brief Set #OBJECT's fill options.
  + *  \par Function Description
  + *  This function allows an #OBJECT's fill options to be configured.
  + *  See #OBJECT_FILLING for information on valid fill types.
  + *
  + *  \param [in]      w_current  The TOPLEVEL object.
  + *  \param [in,out]  o_current  OBJECT to be updated.
  + *  \param [in]      type       OBJECT_FILLING type.
  + *  \param [in]      width      fill width.
  + *  \param [in]      pitch1     cross hatch???.
  + *  \param [in]      angle1     cross hatch???.
  + *  \param [in]      pitch2     cross hatch???.
  + *  \param [in]      angle2     cross hatch???.
  + *
  + */
  +void o_set_fill_options(TOPLEVEL *w_current, OBJECT *o_current,
  +			OBJECT_FILLING type, int width,
  +			int pitch1, int angle1,
  +			int pitch2, int angle2) 
  +{
  +  if(o_current == NULL) {
  +    return;
  +  }
  +
  +  o_current->fill_type = type;
  +  o_current->fill_width = width;
  +
  +  o_current->fill_pitch1 = pitch1;
  +  o_current->fill_angle1 = angle1;
  +
  +  o_current->fill_pitch2 = pitch2;
  +  o_current->fill_angle2 = angle2;
  +	
  +}
  +
  +/*! \brief Recalculate a single OBJECT in screen coordinates.
  + *  \par Function Description
  + *  This function takes an OBJECT and converts it to SCREEN coordinates.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in,out] o_current  OBJECT to recalculate.
  + *
  + */
  +void o_object_recalc(TOPLEVEL *w_current, OBJECT *o_current) 
  +{
  +  int width, length, space, pitch;
  +	
  +  if(o_current == NULL) {
  +    return;
  +  }
  +
  +  width = SCREENabs(w_current, o_current->line_width);
  +  o_current->screen_line_width = width;
  +
  +  length = SCREENabs(w_current, o_current->line_length);
  +  o_current->screen_line_length = length;
  +
  +  space = SCREENabs(w_current, o_current->line_space);
  +  o_current->screen_line_space = space;
  +
  +  width = SCREENabs(w_current, o_current->fill_width);
  +  o_current->screen_fill_width = width;
  +  pitch = SCREENabs(w_current, o_current->fill_pitch1);
  +  o_current->screen_fill_pitch1 = pitch;
  +  pitch = SCREENabs(w_current, o_current->fill_pitch2);
  +  o_current->screen_fill_pitch2 = pitch;
  +
  +}
  +
  +
  
  
  
  1.22      +1479 -1021eda/geda/gaf/libgeda/src/o_box_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_box_basic.c
  ===================================================================
  RCS file: o_box_basic.c
  diff -N o_box_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_box_basic.c	5 Jul 2006 03:13:38 -0000	1.22
  @@ -0,0 +1,1703 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +#include <math.h>
  +#include <stdio.h>
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#ifdef HAS_LIBGDGEDA
  +#include <gdgeda/gd.h>
  +#endif
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +#include "funcs.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/* Kazu on July 16, 1999 - Added these macros to simplify the code */
  +/*! \brief Returns the box width.
  + *  Returns the box width.
  + */
  +#define GET_BOX_WIDTH(w)                        \
  +        abs((w)->last_x - (w)->start_x)
  +/*! \brief Returns the box height.
  + *  Returns the box height.
  + */
  +#define GET_BOX_HEIGHT(w)                       \
  +	        abs((w)->last_y - (w)->start_y)
  +/*! \brief Returns the box left coordinate.
  + *  Returns the box left coordinate.
  + */
  +#define GET_BOX_LEFT(w)                         \
  +	        min((w)->start_x, (w)->last_x);
  +/*! \brief Returns the box left coordinate.
  + *  Returns the box left coordinate.
  + */
  +#define GET_BOX_TOP(w)                          \
  +		min((w)->start_y, (w)->last_y);
  +
  +/*! \brief Create a BOX and add it to a list.
  + *  \par Function Description
  + *  This function creates a new object representing a box.
  + *  This object is added to the end of the list <B>object_list</B>
  + *  pointed object belongs to.
  + *  The box is described by its upper left corner - <B>x1</B>, <B>y1</B> - and
  + *  its lower right corner - <B>x2</B>, <B>y2</B>.
  + *  The <B>type</B> parameter must be equal to <B>OBJ_BOX</B>. The <B>color</B>
  + *  corresponds to the color the box will be drawn with.
  + *  The <B>OBJECT</B> structure is allocated with the #s_basic_init_object()
  + *  function. The structure describing the box is allocated and initialized
  + *  with the parameters given to the function.
  + *
  + *  Both the line type and the filling type are set to default values : solid
  + *  line type with a width of 0, and no filling. It can be changed after
  + *  with the #o_set_line_options() and #o_set_fill_options().
  + *
  + *  The object is added to the end of the list described by the <B>object_list</B>
  + *  parameter by the #s_basic_link_object().
  + *
  + *  \param [in]     w_current    The TOPLEVEL object.
  + *  \param [in,out] object_list  OBJECT list to add box to.
  + *  \param [in]     type         Box type.
  + *  \param [in]     color        Box border color.
  + *  \param [in]     x1           Upper x coordinate.
  + *  \param [in]     y1           Upper y coordinate.
  + *  \param [in]     x2           Lower x coordinate.
  + *  \param [in]     y2           Lower y coordinate.
  + *  \return A new pointer on the end of the <B>object_list</B>
  + */
  +OBJECT *o_box_add(TOPLEVEL *w_current, OBJECT *object_list,
  +		  char type, int color,
  +		  int x1, int y1, int x2, int y2)
  +{
  +  OBJECT *new_node;
  +  BOX *box;
  +
  +  /* create the object */
  +  new_node        = s_basic_init_object("box");
  +  new_node->type  = type;
  +  new_node->color = color;
  +
  +  box = (BOX *) malloc(sizeof(BOX));
  +  new_node->box   = box;
  +
  +  /* describe the box with its upper left and lower right corner */
  +  box->upper_x = x1;
  +  box->upper_y = y1;
  +  box->lower_x = x2;
  +  box->lower_y = y2;
  +
  +  /* line type and filling initialized to default */
  +  o_set_line_options(w_current, new_node,
  +		     END_NONE, TYPE_SOLID, 0, -1, -1);
  +  o_set_fill_options(w_current, new_node,
  +		     FILLING_HOLLOW, -1, -1, -1, -1, -1);
  +
  +  /* \todo questionable cast */     
  +  new_node->draw_func = (void *) box_draw_func; 
  +  /* \todo questionable cast */     
  +  new_node->sel_func  = (void *) select_func;  
  +
  +  /* compute the bounding box */
  +  o_box_recalc(w_current, new_node);
  +
  +  /* add the object to the list */
  +  object_list = (OBJECT *) s_basic_link_object(new_node, object_list);
  +
  +  return(object_list);
  +}
  +
  +/*! \brief Copy a box to a list.
  + *  \par Function Description
  + *  The function #o_box_copy() creates a verbatim copy of the object
  + *  pointed by <B>o_current</B> describing a box. The new object is added at
  + *  the end of the list, following the <B>list_tail</B> pointed object.
  + *
  + *  \param [in]      w_current  The TOPLEVEL object.
  + *  \param [in,out]  list_tail  OBJECT list to copy to.
  + *  \param [in]      o_current  BOX OBJECT to copy.
  + *  \return A new pointer on the end of the OBJECT <B>list_tail</B>.
  + */
  +OBJECT *o_box_copy(TOPLEVEL *w_current, OBJECT *list_tail, OBJECT *o_current)
  +{
  +  OBJECT *new_obj;
  +  ATTRIB *a_current;
  +  int color;
  +	
  +  if (o_current->saved_color == -1) {
  +    color = o_current->color;
  +  } else {
  +    color = o_current->saved_color;
  +  }
  +
  +  /* 
  +   * A new box object is added at the end of the object list with
  +   * #o_box_add(). Values for its fields are default and need to
  +   * be modified.
  +   */
  +
  +  /* create and link a new box object */	
  +  new_obj = o_box_add(w_current, list_tail,
  +		      OBJ_BOX, color,
  +		      0, 0, 0, 0);
  +
  +  /*
  +   * The dimensions of the new box are set with the ones of the original box.
  +   * The two boxes have the same line type and the same filling options.
  +   *
  +   * The coordinates and the values in screen unit are computed with
  +   *  #o_box_recalc().
  +   */
  +
  +  /* modifying */
  +  /* pb20011002 - have to check if o_current is a box object */
  +  new_obj->box->upper_x = o_current->box->upper_x;
  +  new_obj->box->upper_y = o_current->box->upper_y;
  +  new_obj->box->lower_x = o_current->box->lower_x;
  +  new_obj->box->lower_y = o_current->box->lower_y;
  +	
  +  o_set_line_options(w_current, new_obj, o_current->line_end,
  +		     o_current->line_type, o_current->line_width,
  +		     o_current->line_length, o_current->line_space);
  +  o_set_fill_options(w_current, new_obj,
  +		     o_current->fill_type, o_current->fill_width,
  +		     o_current->fill_pitch1, o_current->fill_angle1,
  +		     o_current->fill_pitch2, o_current->fill_angle2);
  +
  +  o_box_recalc(w_current, new_obj);
  +
  +  /* new_obj->attribute = 0;*/
  +  a_current = o_current->attribs;
  +  if (a_current) {
  +    while ( a_current ) {
  +      
  +      /* head attrib node has prev = NULL */
  +      if (a_current->prev != NULL) {
  +	a_current->copied_to = new_obj;
  +      }
  +      a_current = a_current->next;
  +    }
  +  }
  +
  +  /* return the new tail of the object list */
  +  return(new_obj);
  +} 
  +
  +/*! \brief Modify a BOX OBJECT's coordinates.
  + *  \par Function Description
  + *  This function modifies the coordinates of one of the four corner of
  + *  the box. The new coordinates of the corner identified by <B>whichone</B>
  + *  are given by <B>x</B> and <B>y</B> in world unit.
  + *
  + *  The coordinates of the corner is modified in the world coordinate system.
  + *  Screen coordinates and boundings are then updated.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in,out] object     BOX OBJECT to be modified.
  + *  \param [in]     x          x coordinate.
  + *  \param [in]     y          y coordinate.
  + *  \param [in]     whichone   coordinate to change.
  + *
  + *  \note
  + *  <B>whichone</B> can take the following values:
  + *  <DL>
  + *    <DT>*</DT><DD>BOX_UPPER_LEFT
  + *    <DT>*</DT><DD>BOX_LOWER_LEFT
  + *    <DT>*</DT><DD>BOX_UPPER_RIGHT
  + *    <DT>*</DT><DD>BOX_LOWER_RIGHT
  + *  </DL>
  + *
  + *  \par Author's Note:
  + *  pb20011002 - rewritten : old one did not used <B>x</B>, <B>y</B> and
  + *                           <B>whichone</B>
  + */
  +void o_box_modify(TOPLEVEL *w_current, OBJECT *object, 
  +		  int x, int y, int whichone)
  +{
  +	int tmp;
  +	
  +	/* change the position of the selected corner */
  +	switch(whichone) {
  +		case BOX_UPPER_LEFT:
  +			object->box->upper_x = x;
  +			object->box->upper_y = y;
  +			break;
  +			
  +		case BOX_LOWER_LEFT:
  +			object->box->upper_x = x;
  +			object->box->lower_y = y;
  +			break;
  +			
  +		case BOX_UPPER_RIGHT:
  +			object->box->lower_x = x;
  +			object->box->upper_y = y;
  +			break;
  +			
  +		case BOX_LOWER_RIGHT:
  +			object->box->lower_x = x;
  +			object->box->lower_y = y;
  +			break;
  +			
  +		default:
  +			return;
  +	}
  +	
  +	/* need to update the upper left and lower right corners */
  +	if(object->box->upper_x > object->box->lower_x) {
  +		tmp                  = object->box->upper_x;
  +		object->box->upper_x = object->box->lower_x;
  +		object->box->lower_x = tmp;
  +	}
  +	
  +	if(object->box->upper_y < object->box->lower_y) {
  +		tmp                  = object->box->upper_y;
  +		object->box->upper_y = object->box->lower_y;
  +		object->box->lower_y = tmp;
  +	}
  +	
  +	/* recalculate the screen coords and the boundings */
  +	o_box_recalc(w_current, object);
  +  
  +}
  +
  +/*! \brief Create a box from a character string.
  + *  \par Function Description
  + *  This function gets the description of a box from the <B>*buf</B> character
  + *  string. The new box is then added to the list of object of which
  + *  <B>*object_list</B> is the last element before the call.
  + *
  + *  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 20000704 release
  + *    <DT>*</DT><DD>the file format used for the releases after 2000704.
  + *  </DL>
  + *
  + *  \param [in]     w_current       The TOPLEVEL object.
  + *  \param [in,out] object_list     BOX OBJECT list to add new BOX to.
  + *  \param [in]     buf             Character string with box description.
  + *  \param [in]     release_ver     libgeda release version number.
  + *  \param [in]     fileformat_ver  libgeda file format version number.
  + *  \return The BOX OBJECT that was created.
  + */
  +OBJECT *o_box_read(TOPLEVEL *w_current, OBJECT *object_list, char buf[],
  +		   unsigned int release_ver, unsigned int fileformat_ver)
  +{
  +  char type; 
  +  int x1, y1;
  +  int width, height; 
  +  int d_x1, d_y1;
  +  int d_x2, d_y2;
  +  int color;
  +  int box_width, box_space, box_length;
  +  int fill_width, angle1, pitch1, angle2, pitch2;
  +  int box_end;
  +  int box_type;
  +  int box_filling;
  +  
  +  if(release_ver <= VERSION_20000704) {
  +
  +  /*! \note
  +   *  The old geda file format, i.e. releases 20000704 and older, does not
  +   *  handle the line type and the filling of the box object. They are set
  +   *  to default.
  +   */
  +
  +    sscanf(buf, "%c %d %d %d %d %d\n",
  +	   &type, &x1, &y1, &width, &height, &color);
  +
  +    box_width   = 0;
  +    box_end     = END_NONE;
  +    box_type    = TYPE_SOLID;
  +    box_length  = -1;
  +    box_space   = -1;
  +    
  +    box_filling = FILLING_HOLLOW;		
  +    fill_width  = 0;
  +    angle1      = -1;
  +    pitch1      = -1;
  +    angle2      = -1;
  +    pitch2      = -1;
  +			  
  +  } else {
  +
  +    /*! \note
  +     *  The current line format to describe a box is a space separated list of
  +     *  characters and numbers in plain ASCII on a single line. The meaning of
  +     *  each item is described in the file format documentation.
  +     */
  +    sscanf(buf, "%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
  +	   &type, &x1, &y1, &width, &height, &color,
  +	   &box_width, &box_end, &box_type, &box_length, 
  +	   &box_space, &box_filling,
  +	   &fill_width, &angle1, &pitch1, &angle2, &pitch2);
  +  }
  +
  +  if (width == 0 || height == 0) {
  +    fprintf(stderr, "Found a zero width/height box [ %c %d %d %d %d %d ]\n",
  +            type, x1, y1, width, height, color);
  +    s_log_message("Found a zero width/height box [ %c %d %d %d %d %d ]\n",
  +                  type, x1, y1, width, height, color);
  +  }
  +
  +  if (color < 0 || color > MAX_COLORS) {
  +    fprintf(stderr, "Found an invalid color [ %s ]\n", buf);
  +    s_log_message("Found an invalid color [ %s ]\n", buf);
  +    s_log_message("Setting color to WHITE\n");
  +    color = WHITE;
  +  }
  +  
  +  /*! \note
  +   *  A box is internally described by its lower right and upper left corner
  +   *  whereas the line describe it with the lower left corner and the width
  +   *  and height.
  +   *
  +   *  A new object is allocated, initialized and added to the object list.
  +   *  Its filling and line type are set according to the values of the field
  +   *  on the line.
  +   */
  +
  +  /* upper left corner of the box */
  +  d_x1 = x1;
  +  d_y1 = y1+height; /* move box origin to top left */
  +  
  +  /* lower right corner of the box */
  +  d_x2 = x1+width; /* end points of the box */
  +  d_y2 = y1;
  +  
  +  /* create and add the box to the list */
  +  object_list = (OBJECT *) o_box_add(w_current, object_list,
  +				     type, color,
  +				     d_x1, d_y1, d_x2, d_y2);
  +  /* set its line options */
  +  o_set_line_options(w_current, object_list,
  +		     box_end, box_type, box_width, 
  +		     box_length, box_space);
  +  /* set its fill options */
  +  o_set_fill_options(w_current, object_list,
  +		     box_filling, fill_width,
  +		     pitch1, angle1, pitch2, angle2);
  +  return(object_list);
  +}
  +
  +/*! \brief Create a character string representation of a BOX.
  + *  \par Function Description
  + *  This function formats a string in the buffer <B>*buff</B> to describe the
  + *  box object <B>*object</B>.
  + *  It follows the post-20000704 release file format that handle the line type
  + *  and fill options. 
  + *
  + *  \param [in] object  The BOX OBJECT to create string from.
  + *  \return A pointer to the BOX character string.
  + *
  + *  \warning
  + *  Caller must free returned character string.
  + */
  +char *o_box_save(OBJECT *object)
  +{
  +  int x1, y1; 
  +  int width, height;
  +  int color;
  +  int box_width, box_space, box_length;
  +  int fill_width, angle1, pitch1, angle2, pitch2;
  +  OBJECT_END box_end;
  +  OBJECT_TYPE box_type;
  +  OBJECT_FILLING box_fill;
  +  char *buf;
  +
  +  /*! \note
  +   *  A box is internally represented by its lower right and upper left corner
  +   *  whereas it is described in the file format as its lower left corner and
  +   *  its width and height.
  +   */
  +
  +  /* calculate the width and height of the box */
  +  width  = abs(object->box->lower_x - object->box->upper_x); 
  +  height = abs(object->box->upper_y - object->box->lower_y);
  +
  +  /* calculate the lower left corner of the box */
  +  x1 = object->box->upper_x;
  +  y1 = object->box->upper_y - height; /* move the origin to 0, 0*/
  +
  +#if DEBUG
  +  printf("box: %d %d %d %d\n", x1, y1, width, height);
  +#endif
  +
  +  /* description of the line type for the outline */
  +  box_end    = object->line_end;
  +  box_width  = object->line_width;
  +  box_type   = object->line_type;
  +  box_length = object->line_length;
  +  box_space  = object->line_space;
  +  
  +  /* description of the filling of the box */
  +  box_fill   = object->fill_type;
  +  fill_width = object->fill_width;
  +  angle1     = object->fill_angle1;
  +  pitch1     = object->fill_pitch1;
  +  angle2     = object->fill_angle2;
  +  pitch2     = object->fill_pitch2;
  +
  +  /* Use the right color */
  +  if (object->saved_color == -1) {
  +    color = object->color;
  +  } else {
  +    color = object->saved_color;
  +  }
  +
  +
  +  buf = g_strdup_printf("%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", 
  +			object->type,
  +			x1, y1, width, height, color,
  +			box_width, box_end, box_type, box_length, box_space, 
  +			box_fill,
  +			fill_width, angle1, pitch1, angle2, pitch2);
  +			
  +  return(buf);
  +}
  +
  +/*! \brief Translate a BOX position by a delta.
  + *  \par Function Description
  + *  This function applies a translation of (<B>dx</B>,<B>dy</B>) to the box
  + *  described by <B>*object</B>. <B>dx</B> and <B>dy</B> are in screen unit.
  + *
  + *  \param [in]     w_current   The TOPLEVEL object.
  + *  \param [in]     dx          x distance to move.
  + *  \param [in]     dy          y distance to move.
  + *  \param [in,out] object      BOX OBJECT to translate.
  + */
  +void o_box_translate(TOPLEVEL *w_current, int dx, int dy, OBJECT *object)
  +{
  +  int world_dx, world_dy;
  +
  +  if (object == NULL) printf("bt NO!\n");
  +
  +  /* convert the translation vector in world unit */
  +  world_dx = SCREENabs(w_current, dx);
  +  world_dy = SCREENabs(w_current, dy);
  +
  +  /* translate the box */
  +  o_box_translate_world(w_current, world_dx, world_dy, object);
  +
  +  /* screen coords and boundings are updated by _translate_world */
  +  
  +}
  +
  +/*! \brief Translate a BOX position in WORLD coordinates by a delta.
  + *  \par Function Description
  + *  This function applies a translation of (<B>x1</B>,<B>y1</B>) to the box
  + *  described by <B>*object</B>. <B>x1</B> and <B>y1</B> are in world unit.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in]     x1         x distance to move.
  + *  \param [in]     y1         y distance to move.
  + *  \param [in,out] object     BOX OBJECT to translate.
  + */
  +void o_box_translate_world(TOPLEVEL *w_current, int x1, int y1, OBJECT *object)
  +{
  +  if (object == NULL) printf("btw NO!\n");
  +
  +  /* Do world coords */
  +  object->box->upper_x = object->box->upper_x + x1;
  +  object->box->upper_y = object->box->upper_y + y1;
  +  object->box->lower_x = object->box->lower_x + x1;
  +  object->box->lower_y = object->box->lower_y + y1;     
  +
  +  /* recalc the screen coords and the bounding box */
  +  o_box_recalc(w_current, object);
  +}
  +
  +/*! \brief Rotate a BOX OBJECT.
  + *  \par Function Description
  + *  This function applies a rotation of center (<B>centerx</B>, <B>centery</B>) and
  + *  angle <B>angle</B> to the box object <B>*object</B>.
  + *  The coordinates of the rotation center are in screen units. 
  + *  <B>angle</B> must be a 90 degree multiple. If not, no rotation is applied.
  + *
  + *  The rotation is made with the #o_box_rotate_world() function that
  + *  perform a rotation of angle <B>angle</B> and center (<B>world_centerx</B>,
  + *  <B>world_centery</B>) in world unit.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in]     centerx    Rotation center x coordinate in SCREEN units.
  + *  \param [in]     centery    Rotation center y coordinate in SCREEN units.
  + *  \param [in]     angle      Rotation angle in degrees (unused).
  + *  \param [in,out] object     BOX OBJECT to rotate.
  + *
  + *  \note
  + *  takes in screen coordinates for the centerx,y, and then does the rotate 
  + *  in world space
  + *  also ignores angle argument... for now, rotate only in 90 degree 
  + *  increments
  + *  fixed to 90 degrees... it's *not* general now
  + */
  +void o_box_rotate(TOPLEVEL *w_current,
  +		  int centerx, int centery, int angle,
  +		  OBJECT *object)
  +{
  +  int world_centerx, world_centery;
  +
  +  /* convert the center of rotation to world unit */
  +  SCREENtoWORLD(w_current,
  +				centerx, centery, 
  +                &world_centerx, &world_centery);  
  +
  +  /* rotate the box */
  +  /* the check of the rotation angle is in o_box_rotate_world() */
  +  o_box_rotate_world(w_current,
  +					 world_centerx, world_centery, angle,
  +					 object);
  +
  +  /* screen coords and boundings are updated by _rotate_world() */
  +  
  +}
  +
  +/*! \brief Rotate BOX OBJECT using WORLD coordinates. 
  + *  \par Function Description
  + *  The function #o_box_rotate_world() rotate the box described by
  + *  <B>*object</B> around the (<B>world_centerx</B>, <B>world_centery</B>) point by
  + *  <B>angle</B> degrees.
  + *  The center of rotation is in world unit.
  + *
  + *  \param [in]      w_current      The TOPLEVEL object.
  + *  \param [in]      world_centerx  Rotation center x coordinate in WORLD units.
  + *  \param [in]      world_centery  Rotation center y coordinate in WORLD units.
  + *  \param [in]      angle          Rotation angle in degrees (See note below).
  + *  \param [in,out]  object         BOX OBJECT to rotate.
  + *
  + */
  +void o_box_rotate_world(TOPLEVEL *w_current, 
  +			int world_centerx, int world_centery, int angle,
  +			OBJECT *object)
  +{
  +  int newx1, newy1;
  +  int newx2, newy2;
  +
  +  /*! \note
  +   *  Only 90 degree multiple and positive angles are allowed.
  +   */
  +
  +  /* angle must be positive */
  +  if(angle < 0) angle = -angle;
  +  /* angle must be a 90 multiple or no rotation performed */
  +  if((angle % 90) != 0) return;
  +
  +  /*! \note
  +   *  The center of rotation (<B>world_centerx</B>, <B>world_centery</B>) is
  +   *  translated to the origin. The rotation of the upper left and lower right
  +   *  corner are then performed. Finally, the rotated box is translated back
  +   *  to its previous location.
  +   */
  +  /* translate object to origin */
  +  object->box->upper_x -= world_centerx;
  +  object->box->upper_y -= world_centery;
  +  object->box->lower_x -= world_centerx;
  +  object->box->lower_y -= world_centery;
  +  
  +  /* rotate the upper left corner of the box */
  +  rotate_point_90(object->box->upper_x, object->box->upper_y, angle,
  +		  &newx1, &newy1);
  +  
  +  /* rotate the lower left corner of the box */
  +  rotate_point_90(object->box->lower_x, object->box->lower_y, angle,
  +		  &newx2, &newy2);
  +  
  +  /* reorder the corners after rotation */
  +  object->box->upper_x = min(newx1,newx2);
  +  object->box->upper_y = max(newy1,newy2);
  +  object->box->lower_x = max(newx1,newx2);
  +  object->box->lower_y = min(newy1,newy2);
  +  
  +  /* translate object back to normal position */
  +  object->box->upper_x += world_centerx;
  +  object->box->upper_y += world_centery;
  +  object->box->lower_x += world_centerx;
  +  object->box->lower_y += world_centery;
  +  
  +  /* recalc boundings and screen coords */
  +  o_box_recalc(w_current, object);
  +}
  +
  +/*! \brief Mirror a BOX.
  + *  \par Function Description
  + *  This function mirrors the box from the point (<B>centerx</B>,<B>centery</B>) in
  + *  screen unit.
  + *
  + *  The origin of the mirror in screen unit is converted in world unit. The
  + *  box is mirrored with the function #o_box_mirror_world() for which the
  + *  origin of the mirror must be given in world unit.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in]     centerx    Origin x coordinate in WORLD units.
  + *  \param [in]     centery    Origin y coordinate in WORLD units.
  + *  \param [in,out] object     BOX OBJECT to mirror.
  + */
  +void o_box_mirror(TOPLEVEL *w_current,
  +		  int centerx, int centery,
  +		  OBJECT *object)
  +{
  +  int world_centerx, world_centery;
  +
  +  /* convert the origin of mirror */
  +  SCREENtoWORLD(w_current, centerx, centery, 
  +                &world_centerx,
  +                &world_centery);  
  +
  +  /* apply the mirror in world coords */
  +  o_box_mirror_world(w_current,
  +		     world_centerx, world_centery,
  +		     object);
  +  
  +  /* screen coords and boundings are updated by _mirror_world() */
  +  
  +}
  +
  +/*! \brief Mirror BOX using WORLD coordinates.
  + *  \par Function Description
  + *  This function mirrors the box from the point
  + *  (<B>world_centerx</B>,<B>world_centery</B>) in world unit.
  + *
  + *  The box is first translated to the origin, then mirrored and finally
  + *  translated back at its previous position.
  + *
  + *  \param [in]     w_current      The TOPLEVEL object.
  + *  \param [in]     world_centerx  Origin x coordinate in WORLD units.
  + *  \param [in]     world_centery  Origin y coordinate in WORLD units.
  + *  \param [in,out] object         BOX OBJECT to mirror.
  + */
  +void o_box_mirror_world(TOPLEVEL *w_current,
  +			int world_centerx, int world_centery,
  +			OBJECT *object)
  +{
  +  int newx1, newy1;
  +  int newx2, newy2;
  +
  +  /* translate object to origin */
  +  object->box->upper_x -= world_centerx;
  +  object->box->upper_y -= world_centery;
  +  object->box->lower_x -= world_centerx;
  +  object->box->lower_y -= world_centery;
  +
  +  /* mirror the corners */
  +  newx1 = -object->box->upper_x;
  +  newy1 = object->box->upper_y;
  +  newx2 = -object->box->lower_x;
  +  newy2 = object->box->lower_y;
  +
  +  /* reorder the corners */
  +  object->box->upper_x = min(newx1,newx2);
  +  object->box->upper_y = max(newy1,newy2);
  +  object->box->lower_x = max(newx1,newx2);
  +  object->box->lower_y = min(newy1,newy2);
  +
  +  /* translate back in position */
  +  object->box->upper_x += world_centerx;
  +  object->box->upper_y += world_centery;
  +  object->box->lower_x += world_centerx;
  +  object->box->lower_y += world_centery;
  +
  +  /* recalc boundings and screen coords */
  +  o_box_recalc(w_current, object);
  +  
  +}
  +
  +/*! \brief Recalculate BOX coordinates in SCREEN units.
  + *  \par Function Description
  + *  This function recalculates the screen coords of the <B>o_current</B> pointed
  + *  box object from its world coords.
  + *
  + *  The box coordinates and its bounding are recalculated as well as the
  + *  OBJECT specific fields (line width, filling ...).
  + *
  + *  \param [in] w_current      The TOPLEVEL object.
  + *  \param [in,out] o_current  BOX OBJECT to be recalculated.
  + */
  +void o_box_recalc(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int left, top, right, bottom;
  +  int screen_x1, screen_y1;
  +  int screen_x2, screen_y2;
  +
  +  if (o_current->box == NULL) {
  +    return;
  +  }
  +
  +  /* update the screen coords of the upper left corner of the box */
  +  WORLDtoSCREEN(w_current,
  +		o_current->box->upper_x, o_current->box->upper_y, 
  +		&screen_x1, &screen_y1);  
  +  o_current->box->screen_upper_x = screen_x1;
  +  o_current->box->screen_upper_y = screen_y1;
  +
  +  /* update the screen coords of the lower right corner of the box */
  +  WORLDtoSCREEN(w_current,
  +		o_current->box->lower_x, o_current->box->lower_y, 
  +		&screen_x2, &screen_y2);  
  +  o_current->box->screen_lower_x = screen_x2;
  +  o_current->box->screen_lower_y = screen_y2;
  +
  +  /* update the bounding box - screen unit */
  +  get_box_bounds(w_current, o_current->box, &left, &top, &right, &bottom);
  +  o_current->left   = left;
  +  o_current->top    = top;
  +  o_current->right  = right;
  +  o_current->bottom = bottom;
  +  
  +  /* recalc OBJECT specific parameters */
  +  o_object_recalc(w_current, o_current);
  +}
  +
  +/*! \brief Get BOX bounding rectangle.
  + *  \par Function Description
  + *  This function sets the <B>left</B>, <B>top</B>, <B>right</B> and <B>bottom</B>
  + *  parameters to the bounding rectangle of the box object described in
  + *  <B>*box</B> in SCREEN units.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  box        BOX OBJECT to read coordinates from.
  + *  \param [out] left       Left box coordinate in SCREEN units.
  + *  \param [out] top        Top box coordinate in SCREEN units.
  + *  \param [out] right      Right box coordinate in SCREEN units.
  + *  \param [out] bottom     Bottom box coordinate in SCREEN units.
  + */
  +void get_box_bounds(TOPLEVEL *w_current, BOX *box,
  +		    int *left, int *top, int *right, int *bottom)
  +{
  +  *left   = box->screen_upper_x;
  +  *top    = box->screen_upper_y;
  +  *right  = box->screen_lower_x;
  +  *bottom = box->screen_lower_y;
  +
  +  /* PB : bounding box has to take into account the width of the line */
  +  /* PB : but line width is unknown here */
  +	
  +  *left   = *left   - 4;
  +  *top    = *top    - 4;
  +  *right  = *right  + 4;
  +  *bottom = *bottom + 4;
  +}
  +
  +/*! \brief Get BOX bounding rectangle in WORLD coordinates.
  + *  \par Function Description
  + *  This function sets the <B>left</B>, <B>top</B>, <B>right</B> and <B>bottom</B>
  + *  parameters to the boundings of the box object described in <B>*box</B>
  + *  in world units.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  box        BOX OBJECT to read coordinates from.
  + *  \param [out] left       Left box coordinate in WORLD units.
  + *  \param [out] top        Top box coordinate in WORLD units.
  + *  \param [out] right      Right box coordinate in WORLD units.
  + *  \param [out] bottom     Bottom box coordinate in WORLD units.
  + */
  +void world_get_box_bounds(TOPLEVEL *w_current, BOX *box,
  +			  int *left, int *top, int *right, int *bottom)
  +{
  +  /* pb20011002 - why using min and max here and not above ? */
  +  *left   = min(box->upper_x, box->lower_x);
  +  *top    = min(box->upper_y, box->lower_y);
  +  *right  = max(box->upper_x, box->lower_x);
  +  *bottom = max(box->upper_y, box->lower_y);
  +  
  +  /* PB : same as above here for width of edges */	
  +
  +#if DEBUG 
  +  printf("box: %d %d %d %d\n", *left, *top, *right, *bottom);
  +#endif
  +	
  +}
  +                 
  +/*! \brief Print BOX to Postscript document.
  + *  \par Function Description
  + *  This function prints the box described by the <B>o_current</B>
  + *  parameter to a Postscript document. It takes into account its line
  + *  type and fill type.
  + *  The Postscript document is descibed by the file pointer <B>fp</B>.
  + *
  + *  The validity of the <B>o_current</B> parameter is verified : a null pointer
  + *  causes an error message and a return.
  + *
  + *  The description of the box is extracted from
  + *  the <B>o_current</B> parameter :
  + *  the coordinates of the box - upper left corner and width and
  + *  height of the box -, its line type, its fill type.
  + *
  + *  The outline and the inside of the box are successively handled by two
  + *  differend sets of functions.
  + *  
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] fp         FILE pointer to Postscript document.
  + *  \param [in] o_current  BOX OBJECT to write to document.
  + *  \param [in] origin_x   Page x coordinate to place BOX OBJECT.
  + *  \param [in] origin_y   Page y coordinate to place BOX OBJECT.
  + */
  +void o_box_print(TOPLEVEL *w_current, FILE *fp, OBJECT *o_current, 
  +		 int origin_x, int origin_y)
  +{
  +  int x, y, width, height;
  +  int color;
  +  int line_width, length, space;
  +  int fill_width, angle1, pitch1, angle2, pitch2;
  +  void (*outl_func)() = NULL;
  +  void (*fill_func)() = NULL;
  +
  +  if (o_current == NULL) {
  +    printf("got null in o_box_print\n");
  +    return;
  +  }
  +
  +  x = o_current->box->upper_x;
  +  y = o_current->box->upper_y;
  +  width  = abs(o_current->box->lower_x - o_current->box->upper_x);
  +  height = abs(o_current->box->lower_y - o_current->box->upper_y);
  +  color  = o_current->color;
  +
  +  /*! \note
  +   *  Depending on the type of the line for this particular box, the
  +   *  appropriate function is chosen among #o_box_print_solid(),
  +   *  #o_box_print_dotted(), #o_box_print_dashed(),
  +   *  #o_box_print_center() and #o_box_print_phantom().
  +   *
  +   *  The needed parameters for each of these type is extracted from the
  +   *  <B>o_current</B> object. Depending on the type, unused parameters are
  +   *  set to -1.
  +   *
  +   *  In the eventuality of a length and/or space null, the line is printed
  +   *  solid to avoid and endless loop produced by other functions in such a
  +   *  case.
  +   */
  +  line_width = o_current->line_width;
  +  if(line_width <=2) line_width=2;
  +  length = o_current->line_length;
  +  space  = o_current->line_space;
  +
  +  switch(o_current->line_type) {
  +    case(TYPE_SOLID):
  +      length = -1; space  = -1;
  +      outl_func = (void *) o_box_print_solid;
  +      break;
  +      
  +    case(TYPE_DOTTED):
  +      length = -1;
  +      outl_func = (void *) o_box_print_dotted;
  +      break;
  +		
  +    case(TYPE_DASHED):
  +      outl_func = (void *) o_box_print_dashed;
  +      break;
  +      
  +    case(TYPE_CENTER):
  +      outl_func = (void *) o_box_print_center;
  +      break;
  +		
  +    case(TYPE_PHANTOM):
  +      outl_func = (void *) o_box_print_phantom;
  +      break;
  +		
  +    case(TYPE_ERASE):
  +      /* Unused for now, print it solid */
  +      length = -1; space  = -1;
  +      outl_func = (void *) o_box_print_solid;
  +      break;
  +  }
  +
  +  if((length == 0) || (space == 0)) {
  +    length = -1; space  = -1;
  +    outl_func = (void *) o_box_print_solid;
  +  }
  +
  +  (*outl_func)(w_current, fp,
  +	       x, y, width, height,
  +	       color,
  +	       line_width,
  +	       length, space,
  +	       origin_x, origin_y);
  +
  +  /*! \note
  +   *  If the filling type of the box is not <B>HOLLOW</B>, the appropriate
  +   *  function is chosen among #o_box_print_filled(), #o_box_print_mesh()
  +   *  and #o_box_print_hatch(). The corresponding parameters are extracted
  +   *  from the <B>o_current</B> object and corrected afterward.
  +   *
  +   *  The case where <B>pitch1</B> and <B>pitch2</B> are null or negative is
  +   *  avoided as it leads to an endless loop in most of the called functions.
  +   *  In such a case, the box is printed filled. Unused parameters for each of
  +   *  these functions are set to -1 or any passive value.
  +   */
  +  if(o_current->fill_type != FILLING_HOLLOW) {
  +    fill_width = o_current->fill_width;
  +    angle1     = o_current->fill_angle1;
  +    pitch1     = o_current->fill_pitch1;
  +    angle2     = o_current->fill_angle2;
  +    pitch2     = o_current->fill_pitch2;
  +	
  +    switch(o_current->fill_type) {
  +      case(FILLING_FILL):
  +	angle1 = -1; pitch1 = 1;
  +	angle2 = -1; pitch2 = 1;
  +	fill_width = -1;
  +	fill_func = (void *) o_box_print_filled;
  +	break;
  +			
  +      case(FILLING_MESH):
  +	fill_func = (void *) o_box_print_mesh;
  +	break;
  +			
  +      case(FILLING_HATCH):
  +	angle2 = -1; pitch2 = 1;
  +	fill_func = (void *) o_box_print_hatch;
  +	break;
  +			
  +      case(FILLING_VOID):
  +	/* Unused for now, print it filled */
  +	angle1 = -1; pitch1 = 1;
  +	angle2 = -1; pitch2 = 1;
  +	fill_width = -1;
  +	fill_func = (void *) o_box_print_filled;
  +	break;
  +      case(FILLING_HOLLOW):
  +	/* nop */
  +	break;
  +	
  +    }
  +    
  +    if((pitch1 <= 0) || (pitch2 <= 0)) {
  +      angle1 = -1; pitch1 = 1;
  +      angle2 = -1; pitch2 = 1;
  +      fill_func = (void *) o_box_print_filled;
  +    }
  +    
  +    (*fill_func)(w_current, fp,
  +                 x, y, width, height,
  +                 color,
  +                 fill_width,
  +                 angle1, pitch1, angle2, pitch2,
  +                 origin_x, origin_y);
  +  }
  +}
  +
  +/*! \brief Print a solid BOX to Postscript document.
  + *  \par Function Description
  + *  This function prints the outline of a box when a solid line type is
  + *  required. The box is defined by the coordinates of its upper left corner
  + *  in (<B>x</B>,<B>y</B>) and its width and height given by the <B>width</B> and
  + *  <B>height</B> parameters. 
  + *  The postscript file is defined by the file pointer <B>fp</B>.
  + *  The parameters <B>length</B> and <B>space</B> are ignored.
  + *
  + *  It uses the function #o_line_print_solid() to print the outline.
  + *  It performs four calls to this function, one for each of its side.
  + *
  + *  All dimensions are in mils.
  + *
  + *  \param [in] w_current   The TOPLEVEL object.
  + *  \param [in] fp          FILE pointer to Postscript document.
  + *  \param [in] x           Upper x coordinate of BOX.
  + *  \param [in] y           Upper y coordinate of BOX.
  + *  \param [in] width       Width of BOX.
  + *  \param [in] height      Height of BOX.
  + *  \param [in] color       BOX color.
  + *  \param [in] line_width  BOX Line width.
  + *  \param [in] length      Dashed line length.
  + *  \param [in] space       Amount of space between dashes.
  + *  \param [in] origin_x    Page x coordinate to place BOX OBJECT.
  + *  \param [in] origin_y    Page y coordinate to place BOX OBJECT.
  + *
  + *  \par Author's Note
  + *   PB : parameter filled removed
  + */
  +void
  +o_box_print_solid(TOPLEVEL *w_current, FILE *fp,
  +                  int x, int y,
  +                  int width, int height,
  +                  int color,
  +                  int line_width, int length, int space, 
  +                  int origin_x, int origin_y)
  +{
  +  int x1, y1;
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +
  +  x1 = x;
  +  y1 = y - height; /* move the origin to 0, 0*/
  +
  +  o_line_print_solid(w_current, fp,
  +                     x1, y1, x1 + width, y1,
  +                     color,
  +                     line_width, length, space,
  +                     origin_x, origin_y);
  +  o_line_print_solid(w_current, fp,
  +                     x1 + width, y1, x1 + width, y1 + height,
  +                     color,
  +                     line_width, length, space,
  +                     origin_x, origin_y);
  +  o_line_print_solid(w_current, fp,
  +                     x1 + width, y1 + height, x1, y1 + height,
  +                     color,
  +                     line_width, length, space,
  +                     origin_x, origin_y);
  +  o_line_print_solid(w_current, fp,
  +                     x1, y1 + height, x1, y1,
  +                     color,
  +                     line_width, length, space,
  +                     origin_x, origin_y);
  +}
  +
  +/*! \brief Print a dotted BOX to Postscript document.
  + *  \par Function Description
  + *  This function prints the outline of a box when a dotted line type is
  + *  required. The box is defined by the coordinates of its upper left corner
  + *  in (<B>x</B>,<B>y</B>) and its width and height given by the <B>width</B> and
  + *  <B>height</B> parameters. 
  + *  The postscript file is defined by the file pointer <B>fp</B>.
  + *  The parameters <B>length</B> is ignored.
  + *
  + *  It uses the function #o_line_print_dotted() to print the outline.
  + *  It performs four calls to this function, one for each of its side.
  + *
  + *  All dimensions are in mils.
  + *
  + *  \param [in] w_current   The TOPLEVEL object.
  + *  \param [in] fp          FILE pointer to Postscript document.
  + *  \param [in] x           Upper x coordinate of BOX.
  + *  \param [in] y           Upper y coordinate of BOX.
  + *  \param [in] width       Width of BOX.
  + *  \param [in] height      Height of BOX.
  + *  \param [in] color       BOX color.
  + *  \param [in] line_width  BOX Line width.
  + *  \param [in] length      Dashed line length.
  + *  \param [in] space       Amount of space between dashes.
  + *  \param [in] origin_x    Page x coordinate to place BOX OBJECT.
  + *  \param [in] origin_y    Page y coordinate to place BOX OBJECT.
  + *
  + *  \par Author's Note
  + *  PB : parameter filled removed
  + *  PB : parameter o_current removed
  + */
  +void o_box_print_dotted(TOPLEVEL *w_current, FILE *fp,
  +			int x, int y,
  +			int width, int height,
  +			int color,
  +			int line_width, int length, int space, 
  +			int origin_x, int origin_y)
  +{
  +  int x1, y1;
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +
  +  x1 = x;
  +  y1 = y - height; /* move the origin to 0, 0*/
  +
  +  o_line_print_dotted(w_current, fp,
  +                      x1, y1, x1 + width, y1,
  +                      color,
  +                      line_width, length, space,
  +                      origin_x, origin_y);
  +  o_line_print_dotted(w_current, fp,
  +                      x1 + width, y1, x1 + width, y1 + height,
  +                      color,
  +                      line_width, length, space,
  +                      origin_x, origin_y);
  +  o_line_print_dotted(w_current, fp,
  +                      x1 + width, y1 + height, x1, y1 + height,
  +                      color,
  +                      line_width, length, space,
  +                      origin_x, origin_y);
  +  o_line_print_dotted(w_current, fp,
  +                      x1, y1 + height, x1, y1,
  +                      color,
  +                      line_width, length, space,
  +                      origin_x, origin_y);
  +}
  +
  +/*! \brief Print a dashed BOX to Postscript document.
  + *  \par Function Description
  + *  This function prints the outline of a box when a dashed line type is
  + *  required. The box is defined by the coordinates of its upper left corner
  + *  in (<B>x</B>,<B>y</B>) and its width and height given by the <B>width</B> and
  + *  <B>height</B> parameters. 
  + *  The postscript file is defined by the file pointer <B>fp</B>.
  + *
  + *  It uses the function #o_line_print_dashed() to print the outline.
  + *  It performs four calls to this function, one for each of its side.
  + *
  + *  All dimensions are in mils.
  + *
  + *  \param [in] w_current   The TOPLEVEL object.
  + *  \param [in] fp          FILE pointer to Postscript document.
  + *  \param [in] x           Upper x coordinate of BOX.
  + *  \param [in] y           Upper y coordinate of BOX.
  + *  \param [in] width       Width of BOX.
  + *  \param [in] height      Height of BOX.
  + *  \param [in] color       BOX color.
  + *  \param [in] line_width  BOX Line width.
  + *  \param [in] length      Dashed line length.
  + *  \param [in] space       Amount of space between dashes.
  + *  \param [in] origin_x    Page x coordinate to place BOX OBJECT.
  + *  \param [in] origin_y    Page y coordinate to place BOX OBJECT.
  + * 
  + *  \par Author's Note
  + *  PB : parameter filled removed
  + *  PB : parameter o_current removed
  + */
  +void o_box_print_dashed(TOPLEVEL *w_current, FILE *fp,
  +			int x, int y,
  +			int width, int height,
  +			int color,
  +			int line_width, int length, int space, 
  +			int origin_x, int origin_y)
  +{
  +  int x1, y1;
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +
  +  
  +  x1 = x;
  +  y1 = y - height; /* move the origin to 0, 0*/
  +
  +  o_line_print_dashed(w_current, fp,
  +                      x1, y1, x1 + width, y1,
  +                      color,
  +                      line_width, length, space,
  +                      origin_x, origin_y);
  +  o_line_print_dashed(w_current, fp,
  +                      x1 + width, y1, x1 + width, y1 + height,
  +                      color,
  +                      line_width, length, space,
  +                      origin_x, origin_y);
  +  o_line_print_dashed(w_current, fp,
  +                      x1 + width, y1 + height, x1, y1 + height,
  +                      color,
  +                      line_width, length, space,
  +                      origin_x, origin_y);
  +  o_line_print_dashed(w_current, fp,
  +                      x1, y1 + height, x1, y1,
  +                      color,
  +                      line_width, length, space,
  +                      origin_x, origin_y);
  +}
  +
  +/*! \brief Print centered line type BOX to Postscript document.
  + *  \par Function Description
  + *  This function prints the outline of a box when a centered line type is
  + *  required. The box is defined by the coordinates of its upper left corner
  + *  in (<B>x</B>,<B>y</B>) and its width and height given by the <B>width</B> and
  + *  <B>height</B> parameters. 
  + *  The postscript file is defined by the file pointer <B>fp</B>.
  + *
  + *  It uses the function #o_line_print_center() to print the outline.
  + *  It performs four calls to this function, one for each of its side.
  + *
  + *  All dimensions are in mils.
  + *
  + *  \param [in] w_current   The TOPLEVEL object.
  + *  \param [in] fp          FILE pointer to Postscript document.
  + *  \param [in] x           Upper x coordinate of BOX.
  + *  \param [in] y           Upper y coordinate of BOX.
  + *  \param [in] width       Width of BOX.
  + *  \param [in] height      Height of BOX.
  + *  \param [in] color       BOX color.
  + *  \param [in] line_width  BOX Line width.
  + *  \param [in] length      Dashed line length.
  + *  \param [in] space       Amount of space between dashes.
  + *  \param [in] origin_x    Page x coordinate to place BOX OBJECT.
  + *  \param [in] origin_y    Page y coordinate to place BOX OBJECT.
  + *
  + *  \par Author's note
  + * PB : parameter filled removed
  + * PB : parameter o_current removed
  + */
  +void o_box_print_center(TOPLEVEL *w_current, FILE *fp,
  +			int x, int y,
  +			int width, int height,
  +			int color,
  +			int line_width, int length, int space, 
  +			int origin_x, int origin_y)
  +{
  +  int x1, y1;
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +
  +  x1 = x;
  +  y1 = y - height; /* move the origin to 0, 0*/
  +
  +  o_line_print_center(w_current, fp,
  +                      x1, y1, x1 + width, y1,
  +                      color,
  +                      line_width, length, space,
  +                      origin_x, origin_y);
  +  o_line_print_center(w_current, fp,
  +                      x1 + width, y1, x1 + width, y1 + height,
  +                      color,
  +                      line_width, length, space,
  +                      origin_x, origin_y);
  +  o_line_print_center(w_current, fp,
  +                      x1 + width, y1 + height, x1, y1 + height,
  +                      color,
  +                      line_width, length, space,
  +                      origin_x, origin_y);
  +  o_line_print_center(w_current, fp,
  +                      x1, y1 + height, x1, y1,
  +                      color,
  +                      line_width, length, space,
  +                      origin_x, origin_y);
  +}
  +
  +/*! \brief Print phantom line type BOX to Postscript document.
  + *  \par Function Description
  + *  This function prints the outline of a box when a phantom line type is
  + *  required. The box is defined by the coordinates of its upper left corner
  + *  in (<B>x</B>,<B>y</B>) and its width and height given by the <B>width</B> and
  + *  <B>height</B> parameters. 
  + *  The postscript file is defined by the file pointer <B>fp</B>.
  + *
  + *  It uses the function #o_line_print_phantom() to print the outline.
  + *  It performs four calls to this function, one for each of its side.
  + *
  + *  All dimensions are in mils.
  + *  
  + *  \param [in] w_current   The TOPLEVEL object.
  + *  \param [in] fp          FILE pointer to Postscript document.
  + *  \param [in] x           Upper x coordinate of BOX.
  + *  \param [in] y           Upper y coordinate of BOX.
  + *  \param [in] width       Width of BOX.
  + *  \param [in] height      Height of BOX.
  + *  \param [in] color       BOX color.
  + *  \param [in] line_width  BOX Line width.
  + *  \param [in] length      Dashed line length.
  + *  \param [in] space       Amount of space between dashes.
  + *  \param [in] origin_x    Page x coordinate to place BOX OBJECT.
  + *  \param [in] origin_y    Page y coordinate to place BOX OBJECT.
  + *
  + *  \par Author's note
  + *  PB : parameter filled removed
  + *  PB : parameter o_current removed
  + */
  +void o_box_print_phantom(TOPLEVEL *w_current, FILE *fp,
  +			 int x, int y,
  +			 int width, int height,
  +			 int color,
  +			 int line_width, int length, int space, 
  +			 int origin_x, int origin_y)
  +{
  +  int x1, y1;
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +
  +  x1 = x;
  +  y1 = y - height; /* move the origin to 0, 0*/
  +
  +  o_line_print_phantom(w_current, fp,
  +                       x1, y1, x1 + width, y1,
  +                       color,
  +                       line_width, length, space,
  +                       origin_x, origin_y);
  +  o_line_print_phantom(w_current, fp,
  +                       x1 + width, y1, x1 + width, y1 + height,
  +                       color,
  +                       line_width, length, space,
  +                       origin_x, origin_y);
  +  o_line_print_phantom(w_current, fp,
  +                       x1 + width, y1 + height, x1, y1 + height,
  +                       color,
  +                       line_width, length, space,
  +                       origin_x, origin_y);
  +  o_line_print_phantom(w_current, fp,
  +                       x1, y1 + height, x1, y1,
  +                       color,
  +                       line_width, length, space,
  +                       origin_x, origin_y);
  +}
  +
  +/*! \brief Print a solid pattern BOX to Postscript document.
  + *  \par Function Description
  + *  The function prints a filled box with a solid pattern. No outline is
  + *  printed. 
  + *  The box is defined by the coordinates of its upper left corner in
  + *  (<B>x</B>,<B>y</B>) and its width and height given by the <B>width</B> and
  + *  <B>height</B> parameters. The postscript file is defined by the file
  + *  pointer <B>fp</B>.
  + *  <B>fill_width</B>, <B>angle1</B> and <B>pitch1</B>, <B>angle2</B> and <B>pitch2</B>
  + *  parameters are ignored in this functions but kept for compatibility
  + *  with other fill functions.
  + *
  + *  It uses the fbox postscript function defined in the prolog to
  + *  specify a filled box.
  + * 
  + *  All dimensions are in mils.
  + *
  + *  \param [in] w_current   The TOPLEVEL object.
  + *  \param [in] fp          FILE pointer to Postscript document.
  + *  \param [in] x           Upper x coordinate of BOX.
  + *  \param [in] y           Upper y coordinate of BOX.
  + *  \param [in] width       Width of BOX.
  + *  \param [in] height      Height of BOX.
  + *  \param [in] color       BOX color.
  + *  \param [in] fill_width  BOX fill width. (unused).
  + *  \param [in] angle1      (unused).
  + *  \param [in] pitch1      (unused).
  + *  \param [in] angle2      (unused).
  + *  \param [in] pitch2      (unused).
  + *  \param [in] origin_x    Page x coordinate to place BOX OBJECT.
  + *  \param [in] origin_y    Page y coordinate to place BOX OBJECT.
  + */
  +void o_box_print_filled(TOPLEVEL *w_current, FILE *fp,
  +			int x, int y,
  +			int width, int height,
  +			int color,
  +			int fill_width,
  +			int angle1, int pitch1,
  +			int angle2, int pitch2,
  +			int origin_x, int origin_y)
  +{
  +  int x1, y1;
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +
  +  x1 = x;
  +  y1 = y-height; /* move the origin to 0, 0*/
  +  fprintf(fp, "%d %d %d %d fbox\n",
  +	  width, height,
  +	  x1-origin_x, y1-origin_y);
  +	  
  +}
  +
  +/*! \brief Print a mesh pattern BOX to Postscript document.
  + *  \par Function Description
  + *  This function prints a meshed box. No outline is printed. The box is
  + *  defined by the coordinates of its upper left corner in (<B>x</B>,<B>y</B>) and
  + *  its width and height given by the <B>width</B> and <B>height</B> parameters.
  + *  The postscript file is defined by the file pointer <B>fp</B>.
  + *
  + *  The inside mesh is achieved by two successive call to the
  + *  #o_box_print_hatch() function, given <B>angle1</B> and <B>pitch1</B> the first
  + *  time and <B>angle2</B> and <B>pitch2</B> the second time.
  + *
  + *  Negative or null values for <B>pitch1</B> and/or <B>pitch2</B> are not allowed
  + *  as it leads to an endless loop in #o_box_print_hatch().
  + * 
  + *  All dimensions are in mils.
  + *
  + *  \param [in] w_current   The TOPLEVEL object.
  + *  \param [in] fp          FILE pointer to Postscript document.
  + *  \param [in] x           Upper x coordinate of BOX.
  + *  \param [in] y           Upper y coordinate of BOX.
  + *  \param [in] width       Width of BOX.
  + *  \param [in] height      Height of BOX.
  + *  \param [in] color       BOX color.
  + *  \param [in] fill_width  BOX fill width.
  + *  \param [in] angle1      1st angle for mesh pattern.
  + *  \param [in] pitch1      1st pitch for mesh pattern.
  + *  \param [in] angle2      2nd angle for mesh pattern.
  + *  \param [in] pitch2      2nd pitch for mesh pattern.
  + *  \param [in] origin_x    Page x coordinate to place BOX OBJECT.
  + *  \param [in] origin_y    Page y coordinate to place BOX OBJECT.
  + */
  +void o_box_print_mesh(TOPLEVEL *w_current, FILE *fp,
  +		      int x, int y,
  +		      int width, int height,
  +		      int color,
  +		      int fill_width,
  +		      int angle1, int pitch1,
  +		      int angle2, int pitch2,
  +		      int origin_x, int origin_y)
  +{
  +  o_box_print_hatch(w_current, fp,
  +                    x, y, width, height,
  +                    color,
  +                    fill_width,
  +                    angle1, pitch1, -1, -1,
  +                    origin_x, origin_y);
  +  o_box_print_hatch(w_current, fp,
  +                    x, y, width, height,
  +                    color,
  +                    fill_width,
  +                    angle2, pitch2, -1, -1,
  +                    origin_x, origin_y);
  +
  +}
  +
  +/*! \brief Print a hatch pattern BOX to Postscript document.
  + *  \par Function Description
  + *  The function prints a hatched box. No outline is printed. The box is
  + *  defined by the coordinates of its upper left corner in (<B>x</B>,<B>y</B>) and
  + *  its width and height given by the <B>width</B> and <B>height</B> parameters.
  + *  The postscript file is defined by the file pointer <B>fp</B>. 
  + *  <B>fill_width</B>, <B>angle1</B>, <B>pitch1</B> parameters define the way the box
  + *  has to be hatched.
  + *  <B>angle2</B> and <B>pitch2</B> parameters are unused but kept for compatibility
  + *  with other fill functions.
  + *
  + *  Negative or null values for <B>pitch1</B> are not allowed as it leads to an
  + *  endless loop.
  + *
  + *  All dimensions are in mils.
  + *
  + *  \param [in] w_current   The TOPLEVEL object.
  + *  \param [in] fp          FILE pointer to Postscript document.
  + *  \param [in] x           Upper x coordinate of BOX.
  + *  \param [in] y           Upper y coordinate of BOX.
  + *  \param [in] width       Width of BOX.
  + *  \param [in] height      Height of BOX.
  + *  \param [in] color       BOX color.
  + *  \param [in] fill_width  BOX fill width.
  + *  \param [in] angle1      Angle of hatch pattern.
  + *  \param [in] pitch1      Pitch of hatch pattern.
  + *  \param [in] angle2      (unused).
  + *  \param [in] pitch2      (unused).
  + *  \param [in] origin_x    Page x coordinate to place BOX OBJECT.
  + *  \param [in] origin_y    Page y coordinate to place BOX OBJECT.
  + */
  +void o_box_print_hatch(TOPLEVEL *w_current, FILE *fp,
  +		       int x, int y,
  +		       int width, int height,
  +		       int color,
  +		       int fill_width,
  +		       int angle1, int pitch1,
  +		       int angle2, int pitch2,
  +		       int origin_x, int origin_y)
  +{
  +  int x3, y3, x4, y4;
  +  double cos_a_, sin_a_;
  +  double x0, y0, r;
  +  double x1, y1, x2, y2;
  +  double amin, amax, a[4], min1, min2, max1, max2;
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +
  +  /* Avoid printing line widths too small */
  +  if (fill_width <= 1) fill_width = 2;
  +
  +  /* The cosinus and sinus of <B>angle1</B> are computed once and reused later. */
  +  cos_a_ = cos(((double) angle1) * M_PI/180);
  +  sin_a_ = sin(((double) angle1) * M_PI/180);
  +
  +  /*! \note
  +   *  The function considers the smallest circle around the box. Its radius
  +   *  is given by the following relation. Its center is given by the point
  +   *  at the middle of the box horizontally and vertically (intersection of
  +   *  its two diagonals).
  +   */
  +  r = sqrt((double) (pow(width, 2) + pow(height, 2))) / 2;
  +
  +  /*
  +   *  When drawing a line in a circle there is two intersections. With the
  +   *  previously described circle, these intersections are out of the box.
  +   *  They can be easily calculated, the first by resolution of an equation
  +   *  and the second one by symetry in relation to the vertical axis going
  +   *  through the center of the circle.
  +   *
  +   *  These two points are then rotated of angle <B>angle1</B> using the matrix
  +   *  previously mentioned.
  +   */
  +  y0 = 0;
  +  while(y0 < r) {
  +    x0 = pow(r, 2) - pow(y0, 2);
  +    x0 = sqrt(x0);
  +
  +    x1 = (x0*cos_a_ - y0*sin_a_);
  +    y1 = (x0*sin_a_ + y0*cos_a_);
  +    x2 = ((-x0)*cos_a_ - y0*sin_a_);
  +    y2 = ((-x0)*sin_a_ + y0*cos_a_);
  +  
  +    /*
  +     * It now parametrizes the segment : first intersection is given the
  +     * value of 0 and the second is given the value of 1. The four values for
  +     * each intersection of the segment and the four sides (vertical or
  +     * horizontal) of the box are given by the following relations :
  +     */                                                             
  +    if((int) (x2 - x1) != 0) {
  +      a[0] = ((-width/2) - x1) / (x2 - x1);
  +      a[1] = ((width/2)  - x1) / (x2 - x1);
  +    } else {
  +      a[0] = 0; a[1] = 1;
  +    }
  +    
  +    if((int) (y2 - y1) != 0) {
  +      a[2] = ((-height/2) - y1) / (y2 - y1);
  +      a[3] = ((height/2)  - y1) / (y2 - y1);
  +    } else {
  +      a[2] = 0; a[3] = 1;
  +    }
  +
  +    /*
  +     * It now has to check which of these four values are for intersections
  +     * with the sides of the box (some values may be for intersections out of
  +     * the box). This is made by a min/max function.
  +     */
  +    if(a[0] < a[1]) {
  +      min1 = a[0]; max1 = a[1];
  +    } else {
  +      min1 = a[1]; max1 = a[0];
  +    }
  +    
  +    if(a[2] < a[3]) {
  +      min2 = a[2]; max2 = a[3];
  +    } else {
  +      min2 = a[3]; max2 = a[2];
  +    }
  +    
  +    amin = (min1 < min2) ? min2 : min1;
  +    amin = (amin < 0) ? 0 : amin;
  +    
  +    amax = (max1 < max2) ? max1 : max2;
  +    amax = (amax < 1) ? amax : 1;
  +
  +    /*
  +     * If the segment really go through the box it prints the line. It also
  +     * takes the opportunity of the symetry in the box in relation to its
  +     * center to print the second line at the same time.
  +     *
  +     * If there is no intersection of the segment with any of the sides, then
  +     * there is no need to continue : there would be no more segment in the
  +     * box to print.
  +     */
  +    if((amax > amin) && (amax != 1) && (amin != 0)) {
  +      /* There is intersection between the line and the box edges */
  +      x3 = (int) (x1 + amin*(x2 - x1));
  +      y3 = (int) (y1 + amin*(y2 - y1));
  +      
  +      x4 = (int) (x1 + amax*(x2 - x1));
  +      y4 = (int) (y1 + amax*(y2 - y1));
  +      
  +      fprintf(fp,"%d %d %d %d %d line\n",
  +	      x3 + (x + width/2), y3 + (y - height/2),
  +	      x4 + (x + width/2), y4 + (y - height/2),
  +	      fill_width);
  +      
  +      fprintf(fp,"%d %d %d %d %d line\n",
  +	      -x3 + (x + width/2), -y3 + (y - height/2),
  +	      -x4 + (x + width/2), -y4 + (y - height/2),
  +	      fill_width);
  +      
  +    } else {
  +      break;
  +    }
  +    
  +    y0 = y0 + pitch1;
  +  }
  +}
  +
  +#if 0 /* original way of printing box, no longer used */
  +/*! \brief Print BOX to Postscript document using old method.
  + *  \par Function Description
  + *  This function is the old function to print a box. It does not handle line
  + *  type and filling of a box.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] fp         FILE pointer to Postscript document.
  + *  \param [in] origin_x   Page x coordinate to place BOX OBJECT.
  + *  \param [in] origin_y   Page x coordinate to place BOX OBJECT.
  + */
  +void o_box_print_old(TOPLEVEL *w_current, FILE *fp,
  +		     int origin_x, int origin_y)
  +{
  +  int width, height;
  +  int x1, y1;
  +  if (o_current == NULL) {
  +    printf("got null in o_box_print\n");
  +    return;
  +  }
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, o_current->color);
  +  }
  +
  +
  +  width = abs(o_current->line_points->x2 - o_current->line_points->x1); 
  +  height = abs(o_current->line_points->y1 - o_current->line_points->y2);
  +
  +  x1 = o_current->line_points->x1;
  +  y1 = o_current->line_points->y1-height; /* move the origin to 0, 0*/
  +
  +  fprintf(fp, "newpath\n");
  +  fprintf(fp, "%d mils %d mils moveto\n", x1-origin_x, y1-origin_y);
  +  fprintf(fp, "%d mils %d mils box\n", width, height);
  +
  +}
  +#endif
  +
  +/*! \brief Draw a box in an image.
  + *  \par Function Description
  + *  This function draws a box in an image with the libgdgeda function
  + *  #gdImageRectangle().
  + *
  + *  \param [in] w_current   The TOPLEVEL object.
  + *  \param [in] o_current   BOX OBJECT to draw.
  + *  \param [in] origin_x    (unused).
  + *  \param [in] origin_y    (unused).
  + *  \param [in] color_mode  Draw box in color if TRUE, B/W otherwise.
  + */
  +void o_box_image_write(TOPLEVEL *w_current, OBJECT *o_current, 
  +		       int origin_x, int origin_y, int color_mode)
  +{
  +  int color;
  +
  +
  +  if (o_current == NULL) {
  +    printf("got null in o_box_image_write\n");
  +    return;
  +  }
  +
  +
  +  if (color_mode == TRUE) {
  +    color = o_image_geda2gd_color(o_current->color);
  +  } else {
  +    color = image_black;
  +  }
  +
  +  /* assumes screen coords are already calculated correctly */
  +#ifdef HAS_LIBGDGEDA
  +
  +  gdImageSetThickness(current_im_ptr, SCREENabs(w_current,
  +                                                o_current->line_width));
  +
  +  gdImageRectangle(current_im_ptr, 
  +                   o_current->box->screen_upper_x,
  +                   o_current->box->screen_upper_y,
  +                   o_current->box->screen_lower_x,
  +                   o_current->box->screen_lower_y, 
  +                   color);
  +#endif
  +
  +}
  
  
  
  1.13      +598 -523  eda/geda/gaf/libgeda/src/o_bus_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_bus_basic.c
  ===================================================================
  RCS file: o_bus_basic.c
  diff -N o_bus_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_bus_basic.c	5 Jul 2006 03:13:38 -0000	1.13
  @@ -0,0 +1,841 @@
  +/*! \todo No comments found in o_bus_basic.nw
  + *        Finish file comments.
  + */
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#ifdef HAS_LIBGDGEDA
  +#include <gdgeda/gd.h>
  +#endif
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +#include "funcs.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +void get_bus_bounds(TOPLEVEL *w_current, LINE *line, int *left, int *top,
  +		    int *right, int *bottom)
  +{
  +  *left = w_current->width;
  +  *top = w_current->height;
  +  *right = 0;
  +  *bottom = 0;
  +
  +  if (line->screen_x[0] < *left) *left = line->screen_x[0];
  +  if (line->screen_x[0] > *right) *right = line->screen_x[0];
  +  if (line->screen_y[0] < *top) *top = line->screen_y[0];
  +  if (line->screen_y[0] > *bottom) *bottom = line->screen_y[0];
  +
  +  if (line->screen_x[1] < *left) *left = line->screen_x[1];
  +  if (line->screen_x[1] > *right) *right = line->screen_x[1];
  +  if (line->screen_y[1] < *top) *top = line->screen_y[1];
  +  if (line->screen_y[1] > *bottom) *bottom = line->screen_y[1];
  +
  +  *left = *left - 4;
  +  *top = *top - 4;
  +
  +  *right = *right + 4;
  +  *bottom = *bottom + 4;
  +}
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +void world_get_bus_bounds(TOPLEVEL *w_current, LINE *line, int *left, int *top,
  +			  int *right, int *bottom)
  +{
  +  *left = w_current->init_right;
  +  *top = w_current->init_bottom;
  +  *right = 0;
  +  *bottom = 0;
  +
  +  if (line->x[0] < *left) *left = line->x[0];
  +  if (line->x[0] > *right) *right = line->x[0];
  +  if (line->y[0] < *top) *top = line->y[0];
  +  if (line->y[0] > *bottom) *bottom = line->y[0];
  +
  +  if (line->x[1] < *left) *left = line->x[1];
  +  if (line->x[1] > *right) *right = line->x[1];
  +  if (line->y[1] < *top) *top = line->y[1];
  +  if (line->y[1] > *bottom) *bottom = line->y[1];
  +
  +}
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +OBJECT *o_bus_add(TOPLEVEL *w_current, OBJECT *object_list,
  +		  char type, int color,
  +		  int x1, int y1, int x2, int y2,
  +		  int bus_ripper_direction)
  +{
  +  int screen_x, screen_y;
  +  int left, right, top, bottom;
  +  OBJECT *new_node;
  +
  +  new_node = s_basic_init_object("bus");
  +  new_node->type = type;
  +  new_node->color = color;
  +
  +  new_node->line = (LINE *) malloc(sizeof(LINE));
  +  /* check for null */	
  +
  +  new_node->line->x[0] = x1;
  +  new_node->line->y[0] = y1;
  +  new_node->line->x[1] = x2;
  +  new_node->line->y[1] = y2;
  +
  +  WORLDtoSCREEN(w_current, 
  +                new_node->line->x[0], new_node->line->y[0], 
  +                &screen_x,
  +                &screen_y);  
  +	
  +  new_node->line->screen_x[0] = screen_x;
  +  new_node->line->screen_y[0] = screen_y;
  +
  +  WORLDtoSCREEN(w_current, 
  +                new_node->line->x[1], new_node->line->y[1], 
  +                &screen_x,
  +                &screen_y);  
  +
  +  new_node->line->screen_x[1] = screen_x;
  +  new_node->line->screen_y[1] = screen_y;
  +
  +  new_node->bus_ripper_direction = bus_ripper_direction;
  +
  +  get_bus_bounds(w_current, new_node->line, &left, &top, &right, &bottom);
  +	
  +  new_node->left = left;
  +  new_node->top = top;
  +  new_node->right = right;
  +  new_node->bottom = bottom;	
  +
  +  /*! \todo questionable cast */
  +  new_node->draw_func = (void *) bus_draw_func;  
  +  /*! \todo questionable cast */
  +  new_node->sel_func = (void *) select_func;  
  +
  +  object_list = (OBJECT *) s_basic_link_object(new_node, object_list);
  +
  +  s_tile_add_object(w_current, object_list, 
  +                    new_node->line->x[0], new_node->line->y[0], 
  +                    new_node->line->x[1], new_node->line->y[1]);
  +
  +  if (!w_current->ADDING_SEL) {
  +    s_conn_update_object(w_current, object_list);
  +  }
  +
  +  return(object_list);
  +}
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +void o_bus_recalc(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int screen_x1, screen_y1;
  +  int screen_x2, screen_y2;	
  +  int left, right, top, bottom;
  +
  +  if (o_current == NULL) {
  +    return;
  +  }
  +
  +  if (o_current->line == NULL) {
  +    return;
  +  }
  +
  +  WORLDtoSCREEN(w_current, o_current->line->x[0], 
  +                o_current->line->y[0], 
  +                &screen_x1,
  +                &screen_y1);  
  +
  +  o_current->line->screen_x[0] = screen_x1;
  +  o_current->line->screen_y[0] = screen_y1;
  +
  +  WORLDtoSCREEN(w_current, o_current->line->x[1], 
  +                o_current->line->y[1], 
  +                &screen_x2,
  +                &screen_y2);  
  +
  +  o_current->line->screen_x[1] = screen_x2;
  +  o_current->line->screen_y[1] = screen_y2;
  +
  +
  +  get_bus_bounds(w_current, o_current->line, &left, &top, &right, &bottom);
  +
  +  o_current->left = left;
  +  o_current->top = top;
  +  o_current->right = right;
  +  o_current->bottom = bottom;
  +
  +
  +}
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +OBJECT *o_bus_read(TOPLEVEL *w_current, OBJECT *object_list, char buf[],
  +		   unsigned int release_ver, unsigned int fileformat_ver)
  +{
  +  char type; 
  +  int x1, y1;
  +  int x2, y2;
  +  int d_x1, d_y1;
  +  int d_x2, d_y2;
  +  int color;
  +  int ripper_dir;
  +
  +  if(release_ver <= VERSION_20020825) {
  +    sscanf(buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color);
  +    ripper_dir = 0;
  +  } else {
  +    sscanf(buf, "%c %d %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color,
  +           &ripper_dir);
  +  }
  +    
  +  d_x1 = x1; 
  +  d_y1 = y1; 
  +  d_x2 = x2; 
  +  d_y2 = y2; 
  +
  +  if (x1 == x2 && y1 == y2) {
  +    fprintf(stderr, "Found a zero length bus [ %c %d %d %d %d %d ]\n", type, x1, y1, x2, y2, color);
  +    s_log_message("Found a zero length bus [ %c %d %d %d %d %d ]\n", type, x1, y1, x2, y2, color);
  +  }
  +
  +  if (w_current->override_bus_color != -1) {
  +    color = w_current->override_bus_color;
  +  }
  +
  +  if (color < 0 || color > MAX_COLORS) {
  +    fprintf(stderr, "Found an invalid color [ %s ]\n", buf);
  +    s_log_message("Found an invalid color [ %s ]\n", buf);
  +    s_log_message("Setting color to WHITE\n");
  +    color = WHITE;
  +  }
  +
  +  if (ripper_dir < -1 || ripper_dir > 1) {
  +    fprintf(stderr, "Found an invalid bus ripper direction [ %s ]\n", buf);
  +    s_log_message("Found an invalid bus ripper direction [ %s ]\n", buf);
  +    s_log_message("Resetting direction to neutral (no direction)\n");
  +    ripper_dir = 0;
  +  }
  +
  +  object_list = o_bus_add(w_current, object_list, type, color,
  +                          d_x1, d_y1, d_x2, d_y2, ripper_dir);
  +  return(object_list);
  +}
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +char *o_bus_save(OBJECT *object)
  +{
  +  int x1, x2, y1, y2;
  +  int color;
  +  char *buf;
  +
  +  x1 = object->line->x[0];
  +  y1 = object->line->y[0];
  +  x2 = object->line->x[1];
  +  y2 = object->line->y[1];
  +
  +  /* Use the right color */
  +  if (object->saved_color == -1) {
  +    color = object->color;
  +  } else {
  +    color = object->saved_color;
  +  }
  +
  +  buf = g_strdup_printf("%c %d %d %d %d %d %d", object->type,
  +          x1, y1, x2, y2, color, object->bus_ripper_direction);
  +  return(buf);
  +}
  +       
  +/* \brief
  + * \par Function Description
  + *
  + */
  +void o_bus_translate(TOPLEVEL *w_current, int dx, int dy, OBJECT *object)
  +{
  +  int x, y;
  +
  +  if (object == NULL) printf("nt NO!\n");
  +
  +
  +  /* Do world coords */
  +  object->line->screen_x[0] = object->line->screen_x[0] + dx;
  +  object->line->screen_y[0] = object->line->screen_y[0] + dy;
  +  object->line->screen_x[1] = object->line->screen_x[1] + dx;
  +  object->line->screen_y[1] = object->line->screen_y[1] + dy;
  +
  +  /* do we want snap grid here? */
  +  SCREENtoWORLD(w_current, object->line->screen_x[0], 
  +                object->line->screen_y[0], 
  +                &x,
  +                &y);  
  +	
  +  object->line->x[0] = snap_grid(w_current, x);
  +  object->line->y[0] = snap_grid(w_current, y);
  +	
  +  SCREENtoWORLD(w_current, object->line->screen_x[1], 
  +                object->line->screen_y[1], 
  +                &x,
  +                &y);  
  +	
  +  object->line->x[1] = snap_grid(w_current, x);
  +  object->line->y[1] = snap_grid(w_current, y);
  +
  +  s_tile_update_object(w_current, object);
  +}
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +void o_bus_translate_world(TOPLEVEL *w_current, int x1, int y1, OBJECT *object)
  +{
  +  int screen_x1, screen_y1;
  +  int screen_x2, screen_y2;	
  +  int left, right, top, bottom;
  +
  +  if (object == NULL) printf("btw NO!\n");
  +
  +
  +  /* Do world coords */
  +  object->line->x[0] = object->line->x[0] + x1;
  +  object->line->y[0] = object->line->y[0] + y1;
  +  object->line->x[1] = object->line->x[1] + x1;
  +  object->line->y[1] = object->line->y[1] + y1;
  +
  +  /* update screen coords */
  +  WORLDtoSCREEN(w_current, object->line->x[0], 
  +                object->line->y[0], 
  +                &screen_x1,
  +                &screen_y1);  
  +
  +  object->line->screen_x[0] = screen_x1;
  +  object->line->screen_y[0] = screen_y1;
  +
  +  WORLDtoSCREEN(w_current, object->line->x[1], 
  +                object->line->y[1], 
  +                &screen_x2,
  +                &screen_y2);  
  +
  +  object->line->screen_x[1] = screen_x2;
  +  object->line->screen_y[1] = screen_y2;
  +
  +  /* update bounding box */
  +  get_bus_bounds(w_current, object->line, &left, &top, &right, &bottom);
  +
  +  object->left = left;
  +  object->top = top;
  +  object->right = right;
  +  object->bottom = bottom;
  +
  +  s_tile_update_object(w_current, object);
  +}
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +OBJECT *o_bus_copy(TOPLEVEL *w_current, OBJECT *list_tail, OBJECT *o_current)
  +{
  +  OBJECT *new_obj;
  +  ATTRIB *a_current;
  +  int color;
  +
  +  if (o_current->saved_color == -1) {
  +    color = o_current->color;
  +  } else {
  +    color = o_current->saved_color;
  +  }
  +
  +  /* make sure you fix this in pin and bus as well */
  +  /* still doesn't work... you need to pass in the new values */
  +  /* or don't update and update later */
  +  /* I think for now I'll disable the update and manually update */
  +  new_obj = o_bus_add(w_current, list_tail, OBJ_BUS, color, 
  +                      o_current->line->x[0], o_current->line->y[0],
  +                      o_current->line->x[1], o_current->line->y[1],
  +                      o_current->bus_ripper_direction);
  +
  +  new_obj->line->screen_x[0] = o_current->line->screen_x[0];
  +  new_obj->line->screen_y[0] = o_current->line->screen_y[0];
  +  new_obj->line->screen_x[1] = o_current->line->screen_x[1];
  +  new_obj->line->screen_y[1] = o_current->line->screen_y[1];
  +
  +  new_obj->line->x[0] = o_current->line->x[0];
  +  new_obj->line->y[0] = o_current->line->y[0];
  +  new_obj->line->x[1] = o_current->line->x[1];
  +  new_obj->line->y[1] = o_current->line->y[1];
  +
  +  a_current = o_current->attribs;
  +
  +  if (a_current) {
  +    while ( a_current ) {
  +
  +      /* head attrib node has prev = NULL */
  +      if (a_current->prev != NULL) {
  +        a_current->copied_to = new_obj;
  +      }
  +      a_current = a_current->next;
  +    }
  +  }
  +
  +  return(new_obj);
  +}
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +/* need to make this bus specific */
  +void o_bus_print(TOPLEVEL *w_current, FILE *fp, OBJECT *o_current,
  +		 int origin_x, int origin_y)
  +{
  +  int offset, offset2;
  +  int cross, bus_width;
  +  int x1, y1;
  +  int x2, y2;
  +
  +  if (o_current == NULL) {
  +    printf("got null in o_bus_print\n");
  +    return;
  +  }
  +
  +  offset = 7*6;
  +  offset2 = 7;  
  +
  +  cross = offset;
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, o_current->color);
  +  }
  +
  +  bus_width = 2;
  +  if (w_current->bus_style == THICK) {
  +    bus_width = BUS_WIDTH;	
  +  }
  +
  +  x1 = o_current->line->x[0]-origin_x,
  +  y1 = o_current->line->y[0]-origin_y;
  +  x2 = o_current->line->x[1]-origin_x,
  +  y2 = o_current->line->y[1]-origin_y;
  +
  +  fprintf(fp, "%d %d %d %d %d line\n",
  +	  x1,y1,x2,y2,bus_width);
  +
  +}
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +void o_bus_image_write(TOPLEVEL *w_current, OBJECT *o_current,
  +		       int origin_x, int origin_y, int color_mode)
  +{
  +  int offset, offset2;
  +  int cross;
  +  int x1, y1;
  +  int x2, y2;
  +  int color;
  +
  +  if (o_current == NULL) {
  +    printf("got null in o_bus_image_write\n");
  +    return;
  +  }
  +
  +  if (color_mode == TRUE) {
  +    color = o_image_geda2gd_color(o_current->color);
  +  } else {
  +    color = image_black;
  +  }
  +
  +  offset = SCREENabs(w_current, BUS_WIDTH);
  +
  +  /* 
  +     offset = 7 * (float) w_current->height/ (float) w_current->width;
  +     offset2 = 7 * (float) w_current->height/ (float) w_current->width*2;  
  +
  +     printf("%f %d %d\n", (float) ( (float) w_current->height/ (float) w_current->width), 
  +     offset, offset2);
  +  */
  +
  +  offset2 = offset*2;
  +
  +  cross = offset;
  +
  +  x1 = o_current->line->screen_x[0];
  +  y1 = o_current->line->screen_y[0];
  +  x2 = o_current->line->screen_x[1];
  +  y2 = o_current->line->screen_y[1];
  +
  +  /* assumes screen coords are already calculated correctly */
  +#ifdef HAS_LIBGDGEDA
  +
  +  gdImageSetThickness(current_im_ptr, SCREENabs(w_current, BUS_WIDTH));
  +
  +  gdImageLine(current_im_ptr, x1, y1, x2, y2, color);
  +
  +#endif
  +
  +}
  +
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +/* takes in screen coordinates for the centerx,y, and then does the rotate 
  + * in world space */
  +/* also ignores angle argument... for now, rotate only in 90 degree 
  + * increments */
  +/* fully functional */
  +void o_bus_rotate(TOPLEVEL *w_current, int centerx, int centery, int angle,
  +		  OBJECT *object)
  +{
  +  int world_centerx, world_centery;
  +  int newx, newy;
  +
  +  SCREENtoWORLD(w_current, centerx, centery, 
  +                &world_centerx,
  +                &world_centery);  
  +
  +  /* change the bus ripper orientation when the rotation is 90 degrees */
  +  /* yes it's okay to use o_net_orientation */
  +  if (o_net_orientation(object) == VERTICAL && angle == 90) {
  +    object->bus_ripper_direction = -object->bus_ripper_direction;
  +  }
  +  
  +  /* translate object to origin */
  +  o_bus_translate_world(w_current, -world_centerx, -world_centery, object);
  +
  +  rotate_point_90(object->line->x[0], object->line->y[0], angle,
  +                  &newx, &newy);
  +
  +  object->line->x[0] = newx;
  +  object->line->y[0] = newy;
  +
  +  rotate_point_90(object->line->x[1], object->line->y[1], angle,
  +                  &newx, &newy);
  +
  +  object->line->x[1] = newx;
  +  object->line->y[1] = newy;
  +
  +  o_bus_translate_world(w_current, world_centerx, world_centery, object);
  +
  +}
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +void o_bus_rotate_world(TOPLEVEL *w_current, 
  +			int world_centerx, int world_centery, int angle,
  +			OBJECT *object)
  +{
  +  int newx, newy;
  +
  +  if (angle == 0)
  +  return;
  +
  +  /* translate object to origin */
  +  o_bus_translate_world(w_current, -world_centerx, -world_centery, object);
  +
  +  rotate_point_90(object->line->x[0], object->line->y[0], angle,
  +                  &newx, &newy);
  +
  +  object->line->x[0] = newx;
  +  object->line->y[0] = newy;
  +
  +  rotate_point_90(object->line->x[1], object->line->y[1], angle,
  +                  &newx, &newy);
  +
  +  object->line->x[1] = newx;
  +  object->line->y[1] = newy;
  +
  +  o_bus_translate_world(w_current, world_centerx, world_centery, object);
  +}
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +void o_bus_mirror(TOPLEVEL *w_current,
  +		  int centerx, int centery, OBJECT *object)
  +{
  +  int world_centerx, world_centery;
  +
  +  SCREENtoWORLD(w_current, centerx, centery, 
  +                &world_centerx,
  +                &world_centery);  
  +
  +  /* translate object to origin */
  +  o_bus_translate_world(w_current, -world_centerx, -world_centery, object);
  +
  +  object->line->x[0] = -object->line->x[0];
  +
  +  object->line->x[1] = -object->line->x[1];
  +
  +  o_bus_translate_world(w_current, world_centerx, world_centery, object);
  +}
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +void o_bus_mirror_world(TOPLEVEL *w_current,
  +			int world_centerx, int world_centery, OBJECT *object)
  +{
  +  /* translate object to origin */
  +  o_bus_translate_world(w_current, -world_centerx, -world_centery, object);
  +
  +  object->line->x[0] = -object->line->x[0];
  +
  +  object->line->x[1] = -object->line->x[1];
  +
  +  o_bus_translate_world(w_current, world_centerx, world_centery, object);
  +}
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +int o_bus_orientation(OBJECT *object)
  +{
  +  if (object->line->y[0] == object->line->y[1]) {
  +    return(HORIZONTAL);
  +  }
  +
  +  if (object->line->x[0] == object->line->x[1]) {
  +    return(VERTICAL);
  +  }
  +
  +  return(NEITHER);	
  +}
  +
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +/* this function does the actual work of making one net segment out of two */
  +/* connected segments */
  +/* The second object (del_object) is the object that should be deleted */
  +/* needs to be bus specific */
  +void o_bus_consolidate_lowlevel(OBJECT *object, OBJECT *del_object,
  +				int orient) 
  +{
  +  int temp1, temp2;
  +  int final1, final2;
  +  int changed=0;
  +  ATTRIB *tail;
  +
  +#if DEBUG
  +  printf("o %d %d %d %d\n", object->line->x[0], object->line->y[0], object->line->x[1], object->line->y[1]);
  +  printf("d %d %d %d %d\n", del_object->line->x[0], del_object->line->y[0], del_object->line->x[1], del_object->line->y[1]);
  +#endif
  +
  +
  +  if (orient == HORIZONTAL) {
  +
  +    temp1 = min(object->line->x[0], 
  +                del_object->line->x[0]);
  +    temp2 = min(object->line->x[1], 
  +                del_object->line->x[1]);
  +
  +    final1 = min(temp1, temp2);
  +
  +    temp1 = max(object->line->x[0], 
  +                del_object->line->x[0]);
  +    temp2 = max(object->line->x[1], 
  +                del_object->line->x[1]);
  +
  +    final2 = max(temp1, temp2);
  +
  +    object->line->x[0] = final1;
  +    object->line->x[1] = final2;
  +    changed=1;
  +  }
  +
  +  if (orient == VERTICAL) {
  +    temp1 = min(object->line->y[0], 
  +                del_object->line->y[0]);
  +    temp2 = min(object->line->y[1], 
  +                del_object->line->y[1]);
  +
  +    final1 = min(temp1, temp2);
  +
  +    temp1 = max(object->line->y[0], 
  +                del_object->line->y[0]);
  +    temp2 = max(object->line->y[1], 
  +                del_object->line->y[1]);
  +
  +    final2 = max(temp1, temp2);
  +
  +    object->line->y[0] = final1;
  +    object->line->y[1] = final2;
  +    changed=1;
  +  }
  +
  +#if DEBUG
  +  printf("fo %d %d %d %d\n", object->line->x[0], object->line->y[0], object->line->x[1], object->line->y[1]);
  +#endif
  +
  +  if (changed) {
  +
  +    /* first check for attributes */
  +    if (del_object->attribs) {
  +      printf("yeah... del object has attributes\n");
  +      printf("reconnecting them to the right place\n");
  +      if (object->attribs) {
  +
  +        printf("object DID have attributes\n");
  +
  +#if 0
  +	printf("object->attribs\n");
  +	o_attrib_print(object->attribs);
  +	printf("--\n");
  +	printf("del_object->attribs\n");
  +	o_attrib_print(del_object->attribs);
  +	printf("--\n");
  +#endif
  +        tail = o_attrib_return_tail(object->attribs);
  +
  +				/* skip over old attrib head */
  +        tail->next = del_object->attribs->next;
  +
  +				/* step prev object to point to last object */
  +        tail->next->prev = tail; 
  +
  +
  +				/* delete old attrib head */
  +				/* and nothing else */
  +        del_object->attribs->object=NULL;
  +        del_object->attribs->next=NULL;
  +        del_object->attribs->prev=NULL;
  +        o_attrib_delete(del_object->attribs);
  +
  +				/* you don't need to free the attribs list */
  +				/* since it's been relinked into object's */
  +				/* attribs list */
  +
  +        del_object->attribs = NULL;
  +#if 0
  +	printf("\n\nfinal object->attribs\n");
  +	o_attrib_print(object->attribs);
  +	printf("--\n");
  +#endif
  +
  +      } else {
  +
  +        printf("object didn't have any attributes\n");
  +        object->attribs = del_object->attribs;
  +        /*! \todo what should this be? */
  +        object->attribs->prev = NULL;
  +
  +				/* setup parent attribute */
  +        object->attribs->object = object;
  +
  +				/* you don't need to free the attribs list */
  +				/* since it's been used by object */
  +				
  +        del_object->attribs = NULL;
  +      }	
  +    }
  +  }
  +
  +}
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +/* needs to be bus specific */
  +int o_bus_consolidate_segments(TOPLEVEL *w_current, OBJECT *object)
  +{
  +
  +  return(0);
  +}
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +void o_bus_consolidate(TOPLEVEL *w_current)
  +{
  +
  +}
  +
  +/* \brief
  + * \par Function Description
  + *
  + */
  +void o_bus_modify(TOPLEVEL *w_current, OBJECT *object, 
  +		  int x, int y, int whichone)
  +{
  +  int screen_x, screen_y;
  +  int left, right, top, bottom;
  +
  +  object->line->x[whichone] = x;
  +  object->line->y[whichone] = y;
  +
  +  WORLDtoSCREEN(w_current, 
  +                object->line->x[whichone], 
  +                object->line->y[whichone], 
  +                &screen_x, &screen_y);  
  +	
  +  object->line->screen_x[whichone] = screen_x;
  +  object->line->screen_y[whichone] = screen_y;
  +
  +  get_bus_bounds(w_current, object->line, &left, &top, &right, &bottom);
  +	
  +  object->left = left;
  +  object->top = top;
  +  object->right = right;
  +  object->bottom = bottom;	
  +}
  +
  +
  
  
  
  1.23      +1269 -863 eda/geda/gaf/libgeda/src/o_circle_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_circle_basic.c
  ===================================================================
  RCS file: o_circle_basic.c
  diff -N o_circle_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_circle_basic.c	5 Jul 2006 03:13:38 -0000	1.23
  @@ -0,0 +1,1424 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#ifdef HAS_LIBGDGEDA
  +#include <gdgeda/gd.h>
  +#endif
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +
  +#include "colors.h"
  +#include "funcs.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +int dist(int x1, int y1, int x2, int y2)
  +{
  +  int dx1, dy1;
  +  int dx2, dy2;
  +  int ret;
  +
  +  dx1 = x1;
  +  dy1 = y1;
  +  dx2 = x2;
  +  dy2 = y2;
  +
  +  ret =  sqrt(pow(dx1-dx2,2)+pow(dy1-dy2,2)) ;
  +  return( ret );
  +}
  +
  +/*! \brief Create and add circle OBJECT to list.
  + *  \par Function Description
  + *  This function creates a new object representing a circle. This object is
  + *  added to the end of the list <B>object_list</B> pointed object belongs to.
  + *  The circle is described by its center (<B>x</B>,<B>y</B>) and its radius
  + *  <B>radius</B>.
  + *  The <B>type</B> parameter must be equal to <B>OBJ_CIRCLE</B>. The <B>color</B>
  + *  corresponds to the color the box will be drawn with.
  + *
  + *  The <B>OBJECT</B> structure is allocated with the #s_basic_init_object()
  + *  function. The structure describing the circle is allocated and initialized
  + *  with the parameters given to the function.
  + *
  + *  Both the line type and the filling type are set to default values : solid
  + *  line type with a width of 0, and no filling. It can be changed after
  + *  with #o_set_line_options() and #o_set_fill_options().
  + *
  + *  The object is added to the end of the list described by the
  + *  <B>object_list</B> parameter with #s_basic_link_object().
  + *
  + *  \param [in]     w_current    The TOPLEVEL object.
  + *  \param [in,out] object_list  OBJECT list to add circle to.
  + *  \param [in]     type         Must be OBJ_CIRCLE.
  + *  \param [in]     color        Circle line color.
  + *  \param [in]     x            Center x coordinate.
  + *  \param [in]     y            Center y coordinate.
  + *  \param [in]     radius       Radius of new circle.
  + *  \return A pointer to the new end of the object list.
  + */
  +OBJECT *o_circle_add(TOPLEVEL *w_current, OBJECT *object_list,
  +		     char type, int color,
  +		     int x, int y, int radius)
  +{
  +  OBJECT *new_node;	
  +
  +  /* create the object */
  +  new_node         = s_basic_init_object("circle");
  +  new_node->type   = type;
  +  new_node->color  = color;
  +  
  +  new_node->circle = (CIRCLE *) malloc(sizeof(CIRCLE));
  +  
  +  /* describe the circle with its center and radius */
  +  new_node->circle->center_x = x;
  +  new_node->circle->center_y = y;
  +  new_node->circle->radius   = radius;
  +  
  +  /* line type and filling initialized to default */
  +  o_set_line_options(w_current, new_node,
  +		     END_NONE, TYPE_SOLID, 0, -1, -1);
  +  o_set_fill_options(w_current, new_node,
  +		     FILLING_HOLLOW, -1, -1, -1, -1, -1);
  +  
  +  /* \todo questionable cast */
  +  new_node->draw_func = (void *) circle_draw_func;  
  +  /* \todo questionable cast */
  +  new_node->sel_func = (void *) select_func;  
  +  
  +  /* compute the bounding box and screen coords */
  +  o_circle_recalc(w_current, new_node);
  +  
  +  /* add the object to the list */
  +  object_list = (OBJECT *) s_basic_link_object(new_node, object_list);
  +
  +  return(object_list);
  +}
  +
  +/*! \brief Create a copy of a circle.
  + *  \par Function Description
  + *  The function #o_circle_copy() creates a verbatim copy of the object
  + *  pointed by <B>o_current</B> describing a circle. The new object is added at
  + *  the end of the list, following the <B>list_tail</B> pointed object.
  + *
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [out] list_tail  OBJECT list to copy to.
  + *  \param [in]  o_current  Circle OBJECT to copy.
  + *  \return A new pointer to the end of the object list.
  + */
  +OBJECT *o_circle_copy(TOPLEVEL *w_current, OBJECT *list_tail,
  +		      OBJECT *o_current)
  +{
  +  OBJECT *new_obj;
  +  ATTRIB *a_current;
  +  int color;
  +
  +  if (o_current->saved_color == -1) {
  +    color = o_current->color;
  +  } else {
  +    color = o_current->saved_color;
  +  }
  +
  +  /*
  +   * A new circle object is added at the end of the object list with
  +   * #o_circle_add(). Values for its fields are default and need to be
  +   * modified.
  +   */
  +  /* create and link a new circle object */
  +  new_obj = o_circle_add(w_current, list_tail, OBJ_CIRCLE, 
  +			 color, 
  +			 0, 0, 0);
  +  
  +  /*
  +   * The parameters of the new circle are set with the ones of the original
  +   * circle. The two circle have the same line type and the same filling
  +   * options.
  +   *
  +   * The coordinates and the values in screen unit are computed with
  +   * #o_circle_recalc().
  +   */
  +  /* modify */
  +  new_obj->circle->center_x = o_current->circle->center_x;
  +  new_obj->circle->center_y = o_current->circle->center_y;
  +  new_obj->circle->radius   = o_current->circle->radius;
  +  
  +  o_set_line_options(w_current, new_obj, o_current->line_end,
  +		     o_current->line_type, o_current->line_width,
  +		     o_current->line_length, o_current->line_space);
  +  o_set_fill_options(w_current, new_obj,
  +		     o_current->fill_type, o_current->fill_width,
  +		     o_current->fill_pitch1, o_current->fill_angle1,
  +		     o_current->fill_pitch2, o_current->fill_angle2);
  +  
  +  o_circle_recalc(w_current, new_obj);
  +
  +  /*	new_obj->attribute = 0;*/
  +  a_current = o_current->attribs;
  +  if (a_current) {
  +    while ( a_current ) {
  +      
  +      /* head attrib node has prev = NULL */
  +      if (a_current->prev != NULL) {
  +	a_current->copied_to = new_obj;
  +      }
  +      a_current = a_current->next;
  +    }
  +  }
  +  
  +  return(new_obj);
  +}
  +
  +/*! \brief Modify the description of a circle OBJECT.
  + *  \par Function Description
  + *  This function modifies the description of the circle object <B>*object</B>
  + *  depending on <B>whichone</B> that give the meaning of the <B>x</B> and <B>y</B>
  + *  parameters.
  + *
  + *  If <B>whichone</B> is equal to <B>CIRCLE_CENTER</B>, the new center of the
  + *  circle is given by (<B>x</B>,<B>y</B>) where <B>x</B> and <B>y</B> are in world units.
  + *
  + *  If <B>whichone</B> is equal to <B>CIRCLE_RADIUS</B>, the radius is given by
  + *  <B>x</B> - in world units. <B>y</B> is ignored.
  + *
  + *  The screen coords and the bounding box of the circle object are updated
  + *  after the modification of its parameters.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in,out] object     Circle OBJECT to modify.
  + *  \param [in]     x          New center x coordinate, or radius value.
  + *  \param [in]     y          New center y coordinate.
  + *                             Unused if radius is being modified.
  + *  \param [in]     whichone   Which circle parameter to modify.
  + *
  + *  <B>whichone</B> can have the following values:
  + *  <DL>
  + *    <DT>*</DT><DD>CIRCLE_CENTER
  + *    <DT>*</DT><DD>CIRCLE_RADIUS
  + *  </DL>
  + */
  +void o_circle_modify(TOPLEVEL *w_current, OBJECT *object, 
  +		     int x, int y, int whichone)
  +{
  +  switch(whichone) {
  +    case CIRCLE_CENTER:
  +      /* modify the center of the circle */
  +      object->circle->center_x = x;
  +      object->circle->center_y = y;
  +      break;
  +    case CIRCLE_RADIUS:
  +      /* modify the radius of the circle */
  +      if (x == 0) {
  +	s_log_message("Null radius circles are not allowed\n");
  +	return;
  +      }
  +      object->circle->radius = x;
  +      break;
  +    default:
  +      break;
  +  }
  +
  +  /* recalculate the screen coords and the boundings */
  +  o_circle_recalc(w_current, object);
  +  
  +}
  +
  +/*! \brief Create circle OBJECT from character string.
  + *  \par Function Description
  + *  The #o_circle_read() function gets from the character string <B>*buff</B> the
  + *  description of a circle. The new circle is then added to the list of
  + *  objects of which <B>*object_list</B> is the last element before the call.
  + *
  + *  Depending on <B>*version</B>, the right file format is considered.
  + *  Currently two file format revisions are supported :
  + *  <DL>
  + *    <DT>*</DT><DD>the file format used until 2000704 release.
  + *    <DT>*</DT><DD>the file format used for the releases after 20000704.
  + *  </DL>
  + *
  + *  \param [in]  w_current       The TOPLEVEL object.
  + *  \param [out] object_list     OBJECT list to create circle in.
  + *  \param [in]  buf             Character string with circle description.
  + *  \param [in]  release_ver     libgeda release version number.
  + *  \param [in]  fileformat_ver  libgeda file format version number.
  + *  \return A pointer to the new circle object.
  + */
  +OBJECT *o_circle_read(TOPLEVEL *w_current, OBJECT *object_list, char buf[],
  +		      unsigned int release_ver, unsigned int fileformat_ver)
  +{
  +  char type; 
  +  int x1, y1;
  +  int radius;
  +  int color;
  +  int circle_width, circle_space, circle_length;
  +  int fill_width, angle1, pitch1, angle2, pitch2;
  +  int circle_end;
  +  int circle_type;
  +  int circle_fill;
  +
  +  if(release_ver <= VERSION_20000704) {
  +    /*
  +     * The old geda file format, i.e. releases 20000704 and older, does not
  +     * handle the line type and the filling of the box object. They are set
  +     * to default.
  +     */
  +    sscanf(buf, "%c %d %d %d %d\n", &type, &x1, &y1, &radius, &color);
  +
  +    circle_width = 0;
  +    circle_end   = END_NONE;
  +    circle_type  = TYPE_SOLID;
  +    circle_length= -1;
  +    circle_space = -1;
  +    
  +    circle_fill  = FILLING_HOLLOW;
  +    fill_width  = 0;
  +    angle1      = -1;
  +    pitch1      = -1;
  +    angle2      = -1;
  +    pitch2      = -1;
  +			
  +  } else {
  +	
  +    /*
  +     * The current line format to describe a circle is a space separated
  +     * list of characters and numbers in plain ASCII on a single line. The
  +     * meaning of each item is described in the file format documentation.
  +     */  
  +    sscanf(buf, "%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
  +	   &type, &x1, &y1, &radius, &color,
  +	   &circle_width, &circle_end, &circle_type,
  +	   &circle_length, &circle_space, &circle_fill,
  +	   &fill_width, &angle1, &pitch1, &angle2, &pitch2);
  +  }
  +
  +
  +  if (radius == 0) {
  +    fprintf(stderr, "Found a zero radius circle [ %c %d %d %d %d ]\n",
  +            type, x1, y1, radius, color);
  +    s_log_message("Found a zero radius circle [ %c %d %d %d %d ]\n",
  +                  type, x1, y1, radius, color);
  +	
  +  }
  +  
  +  if (color < 0 || color > MAX_COLORS) {
  +    fprintf(stderr, "Found an invalid color [ %s ]\n", buf);
  +    s_log_message("Found an invalid color [ %s ]\n", buf);
  +    s_log_message("Setting color to WHITE\n");
  +    color = WHITE;
  +  }
  +
  +  /* 
  +   * A circle is internally described by its center and its radius.
  +   *
  +   * A new object is allocated, initialized and added to the object list.
  +   * Its filling and line type are set according to the values of the field
  +   * on the line.
  +   */
  +  object_list = (OBJECT *) o_circle_add(w_current, object_list,
  +					type, color, x1, y1, radius);
  +  o_set_line_options(w_current, object_list,
  +		     circle_end, circle_type, circle_width, 
  +		     circle_length, circle_space);
  +  o_set_fill_options(w_current, object_list,
  +		     circle_fill, fill_width, pitch1, angle1, pitch2, angle2);
  +  
  +  return(object_list);
  +}
  +
  +/*! \brief Create a character string representation of a circle OBJECT.
  + *  \par Function Description
  + *  This function formats a string in the buffer <B>*buff</B> to describe the
  + *  circle object <B>*object</B>.
  + *  It follows the post-20000704 release file format that handle the line
  + *  type and fill options.
  + *
  + *  \param [in] object  Circle OBJECT to create string from.
  + *  \return A pointer to the circle OBJECT character string.
  + *
  + *  \note
  + *  Caller must free returned character string.
  + *
  + */
  +char *o_circle_save(OBJECT *object)
  +{
  +  int x,y;
  +  int radius;
  +  int color;
  +  int circle_width, circle_space, circle_length;
  +  int fill_width, angle1, pitch1, angle2, pitch2;
  +  char *buf;
  +  OBJECT_END circle_end;
  +  OBJECT_TYPE circle_type;
  +  OBJECT_FILLING circle_fill;
  +
  +  /* circle center and radius */
  +  x = object->circle->center_x;
  +  y = object->circle->center_y;
  +  radius = object->circle->radius;
  +  
  +  /* line type parameters */
  +  circle_width = object->line_width;
  +  circle_end   = object->line_end;
  +  circle_type  = object->line_type;
  +  circle_length= object->line_length;
  +  circle_space = object->line_space;
  +  
  +  /* filling parameters */
  +  circle_fill  = object->fill_type;
  +  fill_width   = object->fill_width;
  +  angle1       = object->fill_angle1;
  +  pitch1       = object->fill_pitch1;
  +  angle2       = object->fill_angle2;
  +  pitch2       = object->fill_pitch2;
  +  
  +  /* Use the right color */
  +  if (object->saved_color == -1) {
  +    color = object->color;
  +  } else {
  +    color = object->saved_color;
  +  }
  +  
  +#if 0 /* old system */
  +  radius = abs(x2 - x1)/2;
  +  if (radius == 0) {
  +    radius = abs(y2 - y1)/2;
  +  }
  +  
  +  x = x1 + radius; 
  +  y = y1 - radius; /* careful */
  +#endif
  +  
  +  buf = g_strdup_printf("%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", 
  +			object->type, x, y, radius, color,
  +			circle_width, circle_end, circle_type, circle_length, 
  +			circle_space, circle_fill,
  +			fill_width, angle1, pitch1, angle2, pitch2);
  +  return(buf);
  +}
  +           
  +/*! \brief Translate a circle position by a delta.
  + *  \par Function Description
  + *  This function applies a translation of (<B>dx</B>,<B>dy</B> to the circle
  + *  described by <B>*object</B>. <B>dx</B> and <B>dy</B> are in screen unit.
  + *
  + *  The translation vector is converted in world unit. The translation is
  + *  made with #o_circle_translate_world().
  + *
  + *  \param [in]     w_current   The TOPLEVEL object.
  + *  \param [in]     dx          x distance to move.
  + *  \param [in]     dy          y distance to move.
  + *  \param [in,out] object      Circle OBJECT to translate.
  + */
  +void o_circle_translate(TOPLEVEL *w_current, int dx, int dy, OBJECT *object)
  +{
  +	int world_dx, world_dy;
  +	
  +	if (object == NULL) printf("ct NO!\n");
  +	
  +	/* convert the translation vector in world unit */
  +	world_dx = SCREENabs(w_current, dx);
  +	world_dy = SCREENabs(w_current, dy);
  +	
  +	/* translate the circle */
  +	o_circle_translate_world(w_current, world_dx, world_dy, object);
  +	
  +	/* screen coords and boundings are updated by _translate_world() */
  +  
  +}
  +
  +/*! \brief Translate a circle position in WORLD coordinates by a delta.
  + *  \par Function Description
  + *  This function applies a translation of (<B>x1</B>,<B>y1</B>) to the circle
  + *  described by <B>*object</B>. <B>x1</B> and <B>y1</B> are in world unit. 
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in]     x1         x distance to move.
  + *  \param [in]     y1         y distance to move.
  + *  \param [in,out] object     Circle OBJECT to translate.
  + */
  +void o_circle_translate_world(TOPLEVEL *w_current,
  +			      int x1, int y1, OBJECT *object)
  +{
  +  if (object == NULL) printf("ctw NO!\n");
  +
  +  /* Do world coords */
  +  object->circle->center_x = object->circle->center_x + x1;
  +  object->circle->center_y = object->circle->center_y + y1;
  +  
  +  /* recalc the screen coords and the bounding box */
  +  o_circle_recalc(w_current, object);
  +  
  +}
  +
  +/*! \brief Rotate a Circle OBJECT.
  + *  \par Function Description
  + *  The function #o_circle_rotate_world() rotate the circle described by
  + *  <B>*object</B> around the (<B>world_centerx</B>,<B>world_centery</B>) point by
  + *  angle <B>angle</B> degrees.
  + *  The center of rotation is in world unit.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in]     centerx    Rotation center x coordinate in SCREEN units.
  + *  \param [in]     centery    Rotation center y coordinate in SCREEN units.
  + *  \param [in]     angle      Rotation angle in degrees (unused).
  + *  \param [in,out] object     Circle OBJECT to rotate.
  + *
  + *  \note
  + *  takes in screen coordinates for the centerx,y, and then does the rotate 
  + *  in world space
  + *  also ignores angle argument... for now, rotate only in 90 degree 
  + *  increments
  + */
  +void o_circle_rotate(TOPLEVEL *w_current,
  +		     int centerx, int centery, int angle,
  +		     OBJECT *object)
  +{
  +  int world_centerx, world_centery;
  +
  +  /* convert the center of rotation to world unit */
  +  SCREENtoWORLD(w_current,
  +				centerx, centery, 
  +                &world_centerx, &world_centery);  
  +
  +  /* rotate the circle */
  +  o_circle_rotate_world(w_current,
  +			world_centerx, world_centery, angle,
  +			object);
  +  
  +  /* screen coords and boundings are updated by _rotate_world() */
  +  
  +}
  +
  +/*! \brief Rotate Circle OBJECT using WORLD coordinates. 
  + *  \par Function Description
  + *  The function #o_circle_rotate_world() rotate the circle described by
  + *  <B>*object</B> around the (<B>world_centerx</B>,<B>world_centery</B>) point by
  + *  angle <B>angle</B> degrees.
  + *  The center of rotation is in world unit.
  + *
  + *  \param [in]      w_current      The TOPLEVEL object.
  + *  \param [in]      world_centerx  Rotation center x coordinate in WORLD units.
  + *  \param [in]      world_centery  Rotation center y coordinate in WORLD units.
  + *  \param [in]      angle          Rotation angle in degrees (See note below).
  + *  \param [in,out]  object         Circle OBJECT to rotate.
  + */
  +void o_circle_rotate_world(TOPLEVEL *w_current, 
  +			   int world_centerx, int world_centery, int angle,
  +			   OBJECT *object)
  +{
  +  int newx, newy;
  +  int x, y;
  +
  +  /* Only 90 degree multiple and positive angles are allowed. */
  +  /* angle must be positive */
  +  if(angle < 0) angle = -angle;
  +  /* angle must be a 90 multiple or no rotation performed */
  +  if((angle % 90) != 0) return;
  +  
  +  /*
  +   * The center of rotation (<B>world_centerx</B>,<B>world_centery</B>) is
  +   * translated to the origin. The rotation of the center around the origin
  +   * is then performed. Finally, the rotated circle is translated back to
  +   * its previous location.
  +   */
  +
  +  /* translate object to origin */
  +  object->circle->center_x -= world_centerx;
  +  object->circle->center_y -= world_centery;
  +  
  +  /* rotate the center of the circle around the origin */
  +  x = object->circle->center_x;
  +  y = object->circle->center_y;
  +  rotate_point_90(x, y, angle, &newx, &newy);
  +  object->circle->center_x = newx;
  +  object->circle->center_y = newy;
  +  
  +  /* translate back in position */
  +  object->circle->center_x += world_centerx;
  +  object->circle->center_y += world_centery;
  +
  +  o_circle_recalc(w_current, object);
  +  
  +}
  +
  +/*! \brief Mirror a Circle.
  + *  \par Function Description
  + *  This function mirrors the circle from the point (<B>centerx</B>,<B>centery</B>)
  + *  in screen unit.
  + *
  + *  The origin of the mirror in screen unit is converted in world unit.
  + *  The circle is mirrored with the function #o_circle_mirror_world()
  + *  for which the origin of the mirror must be given in world unit.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in]     centerx    Origin x coordinate in WORLD units.
  + *  \param [in]     centery    Origin y coordinate in WORLD units.
  + *  \param [in,out] object     Circle OBJECT to mirror.
  + */
  +void o_circle_mirror(TOPLEVEL *w_current,
  +		     int centerx, int centery,
  +		     OBJECT *object)
  +{
  +  int world_centerx, world_centery;
  +
  +  /* convert the origin of mirror */
  +  SCREENtoWORLD(w_current,
  +		centerx, centery, 
  +                &world_centerx, &world_centery);  
  +
  +  /* apply the mirror in world coords */
  +  o_circle_mirror_world(w_current,
  +			world_centerx, world_centery,
  +			object);
  +  
  +  /* screen coords and boundings are updated by _mirror_world() */
  +}
  +
  +/*! \brief Mirror circle using WORLD coordinates.
  + *  \par Function Description
  + *  This function recalculates the screen coords of the <B>o_current</B> pointed
  + *  circle object from its world coords.
  + *
  + *  The circle coordinates and its bounding are recalculated as well as the
  + *  OBJECT specific (line width, filling ...).
  + *
  + *  \param [in]     w_current      The TOPLEVEL object.
  + *  \param [in]     world_centerx  Origin x coordinate in WORLD units.
  + *  \param [in]     world_centery  Origin y coordinate in WORLD units.
  + *  \param [in,out] object         Circle OBJECT to mirror.
  + */
  +void o_circle_mirror_world(TOPLEVEL *w_current,
  +			   int world_centerx, int world_centery,
  +			   OBJECT *object)
  +{
  +  /* translate object to origin */
  +  object->circle->center_x -= world_centerx;
  +  object->circle->center_y -= world_centery;
  +
  +  /* mirror the center of the circle */
  +  object->circle->center_x = -object->circle->center_x;
  +  object->circle->center_y =  object->circle->center_y;
  +
  +  /* translate back in position */
  +  object->circle->center_x += world_centerx;
  +  object->circle->center_y += world_centery;
  +
  +  /* recalc boundings and screen coords */
  +  o_circle_recalc(w_current, object);
  +  
  +}
  +
  +/*! \brief Recalculate circle coordinates in SCREEN units.
  + *  \par Function Description
  + *  This function recalculates the screen coords of the <B>o_current</B> pointed
  + *  circle object from its world coords.
  + *
  + *  The circle coordinates and its bounding are recalculated as well as the
  + *  OBJECT specific (line width, filling ...).
  + *
  + *  \param [in] w_current      The TOPLEVEL object.
  + *  \param [in,out] o_current  Circle OBJECT to be recalculated.
  + */
  +void o_circle_recalc(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int screen_x1, screen_y1;
  +  int left, right, top, bottom;
  +
  +  if (o_current->circle == NULL) {
  +    return;
  +  }
  +
  +#if DEBUG
  +  printf("drawing circle\n");
  +#endif
  +
  +  
  +  /* update the screen coords of the center of the circle */
  +  WORLDtoSCREEN(w_current,
  +		o_current->circle->center_x, o_current->circle->center_y, 
  +		&screen_x1, &screen_y1);  
  +  o_current->circle->screen_x = screen_x1;
  +  o_current->circle->screen_y = screen_y1;
  +
  +  /* update the value of the radius in screen unit */
  +  o_current->circle->screen_radius = SCREENabs(w_current, 
  +					       o_current->circle->radius);
  +
  +  /* update the bounding box - screen unit */
  +  get_circle_bounds(w_current, o_current->circle,
  +		    &left, &top, &right, &bottom);
  +  o_current->left   = left;
  +  o_current->top    = top;
  +  o_current->right  = right;
  +  o_current->bottom = bottom;
  +
  +  /* recalc OBJECT specific parameters */
  +  o_object_recalc(w_current, o_current);
  +  
  +}
  +
  +/*! \brief Get circle bounding rectangle.
  + *  \par Function Description
  + *  This function sets the <B>left</B>, <B>top</B>, <B>right</B>
  + *  and <B>bottom</B> pointed variables to the boundings of the circle object
  + *  described in <B>*circle</B> in screen unit.
  + *
  + *  The function finds the smallest rectangle that cover this circle.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  circle     Circle OBJECT to read coordinates from.
  + *  \param [out] left       Left circle coordinate in SCREEN units.
  + *  \param [out] top        Top circle coordinate in SCREEN units.
  + *  \param [out] right      Right circle coordinate in SCREEN units.
  + *  \param [out] bottom     Bottom circle coordinate in SCREEN units.
  + */
  +void get_circle_bounds(TOPLEVEL *w_current, CIRCLE *circle,
  +		       int *left, int *top,
  +		       int *right, int *bottom)
  +{
  +  *left   = circle->screen_x - circle->screen_radius;
  +  *top    = circle->screen_y - circle->screen_radius;
  +  *right  = circle->screen_x + circle->screen_radius;
  +  *bottom = circle->screen_y + circle->screen_radius;
  +  
  +  /* PB : need to take into account the width of the line */
  +  
  +  /* out temp  
  +   *left = *left - 4;
  +   *top = *top - 4;
  +   
  +   *right = *right + 4;
  +   *bottom = *bottom + 4;
  +   */
  +}
  +
  +/*! \brief Get circle bounding rectangle in WORLD coordinates.
  + *  \par Function Description
  + *  This function sets the <B>left</B>, <B>top</B>, <B>right</B> and <B>bottom</B>
  + *  parameters to the boundings of the circle object described in <B>*circle</B>
  + *  in world units.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  circle     Circle OBJECT to read coordinates from.
  + *  \param [out] left       Left circle coordinate in WORLD units.
  + *  \param [out] top        Top circle coordinate in WORLD units.
  + *  \param [out] right      Right circle coordinate in WORLD units.
  + *  \param [out] bottom     Bottom circle coordinate in WORLD units.
  + */
  +void world_get_circle_bounds(TOPLEVEL *w_current, CIRCLE *circle, int *left,
  +			     int *top, int *right, int *bottom)
  +{
  +
  +  *left   = w_current->init_right;
  +  *top    = w_current->init_bottom;
  +  *right  = 0;
  +  *bottom = 0;
  +
  +
  +  *left   = circle->center_x - circle->radius;
  +  *top    = circle->center_y - circle->radius;
  +  *right  = circle->center_x + circle->radius;
  +  *bottom = circle->center_y + circle->radius;
  +
  +  /*
  +   *left = points->x1;
  +   *top = points->y1;
  +   *right = points->x1+(temp);
  +   *bottom = points->y1-(temp); 
  +   */
  +
  +  /* 
  +   *left = min(circle->x1, circle->x1+temp);
  +   *top = min(circle->y1, circle->y1-temp);
  +   *right = max(circle->x1, circle->x1+temp);
  +   *bottom = max(circle->y1, circle->y1-temp);*/
  +
  +#if DEBUG 
  +  printf("circle: %d %d %d %d\n", *left, *top, *right, *bottom);
  +#endif
  +
  +}
  +
  +/*! \brief Print circle to Postscript document.
  + *  \par Function Description
  + *  This function prints the circle described by the <B>o_current</B>
  + *  parameter to a Postscript document. It takes into account its line type
  + *  and fill type.
  + *  The Postscript document is descibed by the file pointer <B>fp</B>.
  + *
  + *  The validity of the <B>o_current</B> pointer is checked :
  + *  a null pointer causes an error message and a return.
  + *
  + *  The description of the circle is extracted from the <B>o_current</B>
  + *  parameter : the coordinates of the center of the circle, its radius,
  + *  its line type, its fill type.
  + *
  + *  The outline and the inside of the circle are successively handled by
  + *  two differend sets of functions.
  + *  
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] fp         FILE pointer to Postscript document.
  + *  \param [in] o_current  Circle OBJECT to write to document.
  + *  \param [in] origin_x   Page x coordinate to place circle OBJECT.
  + *  \param [in] origin_y   Page y coordinate to place circle OBJECT.
  + */
  +void o_circle_print(TOPLEVEL *w_current, FILE *fp, OBJECT *o_current, 
  +		    int origin_x, int origin_y)
  +{
  +  int x, y, radius;
  +  int color;
  +  int circle_width, length, space;
  +  int fill_width, angle1, pitch1, angle2, pitch2;
  +  void (*outl_func)() = NULL;
  +  void (*fill_func)() = NULL;
  +
  +  if (o_current == NULL) {
  +    printf("got null in o_circle_print\n");
  +    return;
  +  }
  +
  +  x      = o_current->circle->center_x; 
  +  y      = o_current->circle->center_y;
  +  radius = o_current->circle->radius;
  +
  +  color  = o_current->color;
  +
  +  /*
  +   * Depending on the type of the line for this particular circle, the
  +   * appropriate function is chosen among #o_circle_print_solid(),
  +   * #o_circle_print_dotted(), #o_circle_print_dashed(),
  +   * #o_circle_print_center() and #o_circle_print_phantom().
  +   *
  +   * The needed parameters for each of these type is extracted from the
  +   * <B>o_current</B> object. Depending on the type, unused parameters are
  +   * set to -1.
  +   *
  +   * In the eventuality of a length and/or space null, the line is
  +   * printed solid to avoid and endless loop produced by other functions
  +   * in such a case.
  +   */
  +  circle_width = o_current->line_width;
  +  if(circle_width <= 2) circle_width=2;
  +  length       = o_current->line_length;
  +  space        = o_current->line_space;
  +
  +  switch(o_current->line_type) {
  +    case(TYPE_SOLID):
  +      length = -1; space  = -1;
  +      outl_func = (void *) o_circle_print_solid;
  +      break;
  +
  +    case(TYPE_DOTTED):
  +      length = -1;
  +      outl_func = (void *) o_circle_print_dotted;
  +      break;
  +
  +    case(TYPE_DASHED):
  +      outl_func = (void *) o_circle_print_dashed;
  +      break;
  +
  +    case(TYPE_CENTER):
  +      outl_func = (void *) o_circle_print_center;
  +      break;
  +
  +    case(TYPE_PHANTOM):
  +      outl_func = (void *) o_circle_print_phantom;
  +      break;
  +
  +    case(TYPE_ERASE):
  +      /* Unused for now print it solid */
  +      length = -1; space  = -1;
  +      outl_func = (void *) o_circle_print_solid;
  +      break;
  +  }
  +
  +  if((length == 0) || (space == 0)) {
  +    length = -1; space  = -1;
  +    outl_func = (void *) o_circle_print_solid;
  +  }
  +
  +  (*outl_func)(w_current, fp,
  +               x - origin_x, y - origin_y,
  +               radius,
  +               color,
  +               circle_width, length, space,
  +               origin_x, origin_y);
  +
  +  /*
  +   * If the filling type of the circle is not <B>HOLLOW</B>, the appropriate
  +   * function is chosen among #o_circle_print_filled(), #o_circle_print_mesh()
  +   * and #o_circle_print_hatch(). The corresponding parameters are extracted
  +   * from the <B>o_current</B> object and corrected afterward.
  +   *
  +   * The case where <B>pitch1</B> and <B>pitch2</B> are null or negative is
  +   * avoided as it leads to an endless loop in most of the called functions.
  +   * In such a case, the circle is printed filled. Unused parameters for
  +   * each of these functions are set to -1 or any passive value.
  +   */
  +  if(o_current->fill_type != FILLING_HOLLOW) {
  +    fill_width = o_current->fill_width;
  +    angle1     = o_current->fill_angle1;
  +    pitch1     = o_current->fill_pitch1;
  +    angle2     = o_current->fill_angle2;
  +    pitch2     = o_current->fill_pitch2;
  +		
  +    switch(o_current->fill_type) {
  +      case(FILLING_FILL):
  +        angle1 = -1; pitch1 = 1;
  +        angle2 = -1; pitch2 = 1;
  +        fill_width = -1;
  +        fill_func = (void *) o_circle_print_filled;
  +        break;
  +			
  +      case(FILLING_MESH):
  +        fill_func = (void *) o_circle_print_mesh;
  +        break;
  +				
  +      case(FILLING_HATCH):
  +        angle2 = -1; pitch2 = 1;
  +        fill_func = (void *) o_circle_print_hatch;
  +        break;
  +				
  +      case(FILLING_VOID):
  +				/* Unused for now, print it filled */
  +        angle1 = -1; pitch1 = 1;
  +        angle2 = -1; pitch2 = 1;
  +        fill_width = -1;
  +        fill_func = (void *) o_circle_print_filled;
  +        break;
  +        
  +      case(FILLING_HOLLOW):
  +        /* nop */
  +        break;
  +    }
  +
  +    if((pitch1 <= 0) || (pitch2 <= 0)) {
  +      angle1 = -1; pitch1 = 1;
  +      angle2 = -1; pitch2 = 1;
  +      fill_func = (void *) o_circle_print_filled;
  +    }
  +		
  +    (*fill_func)(w_current, fp,
  +                 x, y, radius,
  +                 color,
  +                 fill_width,
  +                 angle1, pitch1, angle2, pitch2,
  +                 origin_x, origin_y);
  +  }
  +}
  +
  +/*! \brief Print a solid circle to Postscript document.
  + *  \par Function Description
  + *  This function prints the outline of a circle when a solid line type
  + *  is required. The circle is defined by its center in (<B>x</B>, <B>y</B>)
  + *  and its radius in <B>radius</B>. It is printed with the color given
  + *  in <B>color</B>.
  + *  The parameters <B>length</B> and <B>space</B> are ignored.
  + *
  + *  It uses the function #o_arc_print_solid() to print the outline.
  + *  Therefore it acts as an interface between the way a circle is defined
  + *  and the way an arc is defined.
  + *
  + *  All dimensions are in mils.
  + *
  + *  \param [in] w_current     The TOPLEVEL object.
  + *  \param [in] fp            FILE pointer to Postscript document.
  + *  \param [in] x             Center x coordinate of circle.
  + *  \param [in] y             Center y coordinate of circle.
  + *  \param [in] radius        Circle radius.
  + *  \param [in] color         Circle color.
  + *  \param [in] circle_width  Width of circle.
  + *  \param [in] length        (unused).
  + *  \param [in] space         (unused).
  + *  \param [in] origin_x      Page x coordinate to place circle OBJECT.
  + *  \param [in] origin_y      Page y coordinate to place circle OBJECT.
  + */
  +void o_circle_print_solid(TOPLEVEL *w_current, FILE *fp,
  +			  int x, int y, int radius,
  +			  int color,
  +			  int circle_width, int length, int space,
  +			  int origin_x, int origin_y)
  +{
  +
  +  o_arc_print_solid(w_current, fp,
  +                    x, y, radius,
  +                    0, FULL_CIRCLE / 64,
  +                    color,
  +                    circle_width, -1, -1,
  +                    origin_x, origin_y);
  +
  +}
  +
  +
  +/*! \brief Print a dotted circle to Postscript document.
  + *  \par Function Description
  + *  This function prints the outline of a circle when a dotted line
  + *  type is required. The circle is defined by its center
  + *  in (<B>x</B>, <B>y</B>) and its radius in <B>radius</B>. It is printed
  + *  with the color given in <B>color</B>.
  + *  The parameter <B>length</B> is ignored.
  + *
  + *  It uses the function #o_arc_print_dotted() to print the outline.
  + *  Therefore it acts as an interface between the way a circle is
  + *  defined and the way an arc is defined.
  + *
  + *  All dimensions are in mils.
  + *
  + *  \param [in] w_current     The TOPLEVEL object.
  + *  \param [in] fp            FILE pointer to Postscript document.
  + *  \param [in] x             Center x coordinate of circle.
  + *  \param [in] y             Center y coordinate of circle.
  + *  \param [in] radius        Circle radius.
  + *  \param [in] color         Circle color.
  + *  \param [in] circle_width  Width of circle.
  + *  \param [in] length        (unused).
  + *  \param [in] space         Space between dots.
  + *  \param [in] origin_x      Page x coordinate to place circle OBJECT.
  + *  \param [in] origin_y      Page y coordinate to place circle OBJECT.
  + */
  +void o_circle_print_dotted(TOPLEVEL *w_current, FILE *fp,
  +			   int x, int y, int radius,
  +			   int color,
  +			   int circle_width, int length, int space,
  +			   int origin_x, int origin_y)
  +{
  +
  +  o_arc_print_dotted(w_current, fp,
  +                     x, y, radius,
  +                     0, FULL_CIRCLE / 64,
  +                     color,
  +                     circle_width, -1, space,
  +                     origin_x, origin_y);
  +
  +}
  +
  +/*! \brief Print a dashed circle to Postscript document.
  + *  \par Function Description
  + *  This function prints the outline of a circle when a dashed line type
  + *  is required. The circle is defined by its center in
  + *  (<B>x</B>, <B>y</B>) and its radius in <B>radius</B>. It is printed with the
  + *  color given in <B>color</B>.
  + *
  + *  It uses the function #o_arc_print_dashed() to print the outline.
  + *  Therefore it acts as an interface between the way a circle is
  + *  defined and the way an arc is defined.
  + *
  + *  All dimensions are in mils.
  + *
  + *  \param [in] w_current     The TOPLEVEL object.
  + *  \param [in] fp            FILE pointer to Postscript document.
  + *  \param [in] x             Center x coordinate of circle.
  + *  \param [in] y             Center y coordinate of circle.
  + *  \param [in] radius        Circle radius.
  + *  \param [in] color         Circle color.
  + *  \param [in] circle_width  Width of circle.
  + *  \param [in] length        Length of dashed lines.
  + *  \param [in] space         Space between dashes.
  + *  \param [in] origin_x      Page x coordinate to place circle OBJECT.
  + *  \param [in] origin_y      Page y coordinate to place circle OBJECT.
  + */
  +void o_circle_print_dashed(TOPLEVEL *w_current, FILE *fp,
  +			   int x, int y,
  +			   int radius,
  +			   int color,
  +			   int circle_width, int length, int space,
  +			   int origin_x, int origin_y)
  +{
  +
  +  o_arc_print_dashed(w_current, fp,
  +                     x, y, radius,
  +                     0, FULL_CIRCLE / 64,
  +                     color,
  +                     circle_width, length, space,
  +                     origin_x, origin_y);
  +
  +}
  +
  +/*! \brief Print a centered line type circle to Postscript document.
  + *  \par Function Description
  + *  This function prints the outline of a circle when a centered line
  + *  type is required. The circle is defined by its center in
  + *  (<B>x</B>, <B>y</B>) and its radius in <B>radius</B>. It is printed with the
  + *  color given in <B>color</B>.
  + *
  + *  It uses the function #o_arc_print_center() to print the outline.
  + *  Therefore it acts as an interface between the way a circle is
  + *  defined and the way an arc is defined.
  + *
  + *  All dimensions are in mils.
  + *
  + *  \param [in] w_current     The TOPLEVEL object.
  + *  \param [in] fp            FILE pointer to Postscript document.
  + *  \param [in] x             Center x coordinate of circle.
  + *  \param [in] y             Center y coordinate of circle.
  + *  \param [in] radius        Circle radius.
  + *  \param [in] color         Circle color.
  + *  \param [in] circle_width  Width of circle.
  + *  \param [in] length        Length of dashed lines.
  + *  \param [in] space         Space between dashes.
  + *  \param [in] origin_x      Page x coordinate to place circle OBJECT.
  + *  \param [in] origin_y      Page y coordinate to place circle OBJECT.
  + */
  +void o_circle_print_center(TOPLEVEL *w_current, FILE *fp,
  +			   int x, int y,
  +			   int radius,
  +			   int color,
  +			   int circle_width, int length, int space,
  +			   int origin_x, int origin_y)
  +{
  +	
  +  o_arc_print_center(w_current, fp,
  +                     x, y, radius,
  +                     0, FULL_CIRCLE / 64,
  +                     color,
  +                     circle_width, length, space,
  +                     origin_x, origin_y);
  +
  +}
  +
  +/*! \brief Print a phantom line type circle to Postscript document.
  + *  \par Function Description
  + *  This function prints the outline of a circle when a phantom line type
  + *  is required. The circle is defined by its center in
  + *  (<B>x</B>, <B>y</B>) and its radius in <B>radius</B>. It is printed with the
  + *  color given in <B>color</B>.
  + *
  + *  It uses the function #o_arc_print_phantom() to print the outline.
  + *  Therefore it acts as an interface between the way a circle is defined
  + *  and the way an arc is defined.
  + *
  + *  All dimensions are in mils.
  + *
  + *  \param [in] w_current     The TOPLEVEL object.
  + *  \param [in] fp            FILE pointer to Postscript document.
  + *  \param [in] x             Center x coordinate of circle.
  + *  \param [in] y             Center y coordinate of circle.
  + *  \param [in] radius        Circle radius.
  + *  \param [in] color         Circle color.
  + *  \param [in] circle_width  Width of circle.
  + *  \param [in] length        Length of dashed lines.
  + *  \param [in] space         Space between dashes.
  + *  \param [in] origin_x      Page x coordinate to place circle OBJECT.
  + *  \param [in] origin_y      Page y coordinate to place circle OBJECT.
  + */
  +void o_circle_print_phantom(TOPLEVEL *w_current, FILE *fp,
  +			    int x, int y,
  +			    int radius,
  +			    int color,
  +			    int circle_width, int length, int space,
  +			    int origin_x, int origin_y)
  +{
  +
  +  o_arc_print_phantom(w_current, fp,
  +                      x, y, radius,
  +                      0, FULL_CIRCLE / 64,
  +                      color,
  +                      circle_width, length, space,
  +                      origin_x, origin_y);
  +
  +}
  +
  +/*! \brief Print a solid pattern circle to Postscript document.
  + *  \par Function Description
  + *  The function prints a filled circle with a solid pattern.
  + *  No outline is printed. 
  + *  The circle is defined by the coordinates of its center in
  + *  (<B>x</B>,<B>y</B>) and its radius given by the <B>radius</B> parameter. 
  + *  The postscript file is defined by the file pointer <B>fp</B>.
  + *  <B>fill_width</B>, <B>angle1</B> and <B>pitch1</B>, <B>angle2</B>
  + *  and <B>pitch2</B> parameters are ignored in this functions but
  + *  kept for compatibility with other fill functions.
  + *
  + *  All dimensions are in mils (except <B>angle1</B> and <B>angle2</B> in degree). 
  + *
  + *  \param [in] w_current   The TOPLEVEL object.
  + *  \param [in] fp          FILE pointer to Postscript document.
  + *  \param [in] x           Center x coordinate of circle.
  + *  \param [in] y           Center y coordinate of circle.
  + *  \param [in] radius      Radius of circle.
  + *  \param [in] color       Circle color.
  + *  \param [in] fill_width  Circle fill width. (unused).
  + *  \param [in] angle1      (unused).
  + *  \param [in] pitch1      (unused).
  + *  \param [in] angle2      (unused).
  + *  \param [in] pitch2      (unused).
  + *  \param [in] origin_x    Page x coordinate to place circle OBJECT.
  + *  \param [in] origin_y    Page y coordinate to place circle OBJECT.
  + */
  +void o_circle_print_filled(TOPLEVEL *w_current, FILE *fp,
  +			   int x, int y, int radius,
  +			   int color,
  +			   int fill_width,
  +			   int angle1, int pitch1,
  +			   int angle2, int pitch2,
  +			   int origin_x, int origin_y)
  +{
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +
  +  fprintf(fp, "%d %d %d dot\n",
  +	  x-origin_x, y-origin_y,
  +	  radius);
  +	
  +}
  +
  +/*! \brief Print a mesh pattern circle to Postscript document.
  + *  \par Function Description
  + *  This function prints a meshed circle. No outline is printed. 
  + *  The circle is defined by the coordinates of its center in
  + *  (<B>x</B>,<B>y</B>) and its radius by the <B>radius</B> parameter. 
  + *  The Postscript document is defined by the file pointer <B>fp</B>. 
  + *
  + *  The inside mesh is achieved by two successive call to the
  + *  #o_circle_print_hatch() function, given <B>angle1</B> and <B>pitch1</B>
  + *  the first time and <B>angle2</B> and <B>pitch2</B> the second time.
  + *
  + *  Negative or null values for <B>pitch1</B> and/or <B>pitch2</B> are
  + *  not allowed as it leads to an endless loop in #o_circle_print_hatch().
  + *
  + *  All dimensions are in mils (except <B>angle1</B> and <B>angle2</B> in degree).
  + *
  + *  \param [in] w_current   The TOPLEVEL object.
  + *  \param [in] fp          FILE pointer to Postscript document.
  + *  \param [in] x           Center x coordinate of circle.
  + *  \param [in] y           Center y coordinate of circle.
  + *  \param [in] radius      Radius of circle.
  + *  \param [in] color       Circle color.
  + *  \param [in] fill_width  Circle fill width.
  + *  \param [in] angle1      1st angle for mesh pattern.
  + *  \param [in] pitch1      1st pitch for mesh pattern.
  + *  \param [in] angle2      2nd angle for mesh pattern.
  + *  \param [in] pitch2      2nd pitch for mesh pattern.
  + *  \param [in] origin_x    Page x coordinate to place circle OBJECT.
  + *  \param [in] origin_y    Page y coordinate to place circle OBJECT.
  + */
  +void o_circle_print_mesh(TOPLEVEL *w_current, FILE *fp,
  +			 int x, int y, int radius,
  +			 int color,
  +			 int fill_width,
  +			 int angle1, int pitch1,
  +			 int angle2, int pitch2,
  +			 int origin_x, int origin_y)
  +{
  +  o_circle_print_hatch(w_current, fp,
  +                       x, y, radius,
  +                       color,
  +                       fill_width,
  +                       angle1, pitch1,
  +                       -1, -1,
  +                       origin_x, origin_y);
  +  o_circle_print_hatch(w_current, fp,
  +                       x, y, radius,
  +                       color,
  +                       fill_width,
  +                       angle2, pitch2,
  +                       -1, -1,
  +                       origin_x, origin_y);
  +	
  +}
  +
  +/*! \brief Print a hatch pattern circle to Postscript document.
  + *  \par Function Description
  + *  The function prints a hatched circle. No outline is printed. 
  + *  The circle is defined by the coordinates of its center in
  + *  (<B>x</B>,<B>y</B>) and its radius by the <B>radius</B> parameter. 
  + *  The Postscript document is defined by the file pointer <B>fp</B>. 
  + *  <B>angle2</B> and <B>pitch2</B> parameters are ignored in this
  + *  functions but kept for compatibility with other fill functions.
  + *
  + *  The only attribute of line here is its width from the parameter <B>width</B>.
  + *
  + *  Negative or null values for <B>pitch1</B> is not allowed as it
  + *  leads to an endless loop.
  + *
  + *  All dimensions are in mils (except <B>angle1</B> is in degrees).
  + *
  + *  \param [in] w_current   The TOPLEVEL object.
  + *  \param [in] fp          FILE pointer to Postscript document.
  + *  \param [in] x           Center x coordinate of circle.
  + *  \param [in] y           Center y coordinate of circle.
  + *  \param [in] radius      Radius of circle.
  + *  \param [in] color       Circle color.
  + *  \param [in] fill_width  Circle fill width.
  + *  \param [in] angle1      Angle for hatch pattern.
  + *  \param [in] pitch1      Pitch for hatch pattern.
  + *  \param [in] angle2      (unused).
  + *  \param [in] pitch2      (unused).
  + *  \param [in] origin_x    Page x coordinate to place circle OBJECT.
  + *  \param [in] origin_y    Page y coordinate to place circle OBJECT.
  + */
  +void o_circle_print_hatch(TOPLEVEL *w_current, FILE *fp,
  +			  int x, int y, int radius,
  +			  int color,
  +			  int fill_width,
  +			  int angle1, int pitch1,
  +			  int angle2, int pitch2,
  +			  int origin_x, int origin_y)
  +{
  +  double x0, y0, x1, y1, x2, y2;
  +  double cos_a_, sin_a_;
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +
  +  /* 
  +   * The values of the cosinus and sinus of the angle
  +   * <B>angle1</B> are calculated for future usage (repetitive).
  +   */
  +  cos_a_ = cos(((double) angle1) * M_PI/180);
  +  sin_a_ = sin(((double) angle1) * M_PI/180);
  +
  +  /*
  +   * When printing a line in a circle there is two intersections.
  +   * It looks for the coordinates of one of these points when the
  +   * line is horizontal. The second one can be easily obtained by
  +   * symmetry in relation to the vertical axis going through the
  +   * centre of the circle.
  +   *
  +   * These two points are therefore rotated of angle <B>angle1</B>
  +   * using the elements previously computed.
  +   *
  +   * The corresponding line can be printed providing that the
  +   * coordinates are rounded.
  +   *
  +   * These operations are repeated for every horizontal line that
  +   * can fit in the upper half of the circle (using and incrementing
  +   * the variable #y0).
  +   */
  +  y0 = 0;
  +  while(y0 < (double) radius) {
  +    x0 = pow((double) radius, 2) - pow(y0, 2);
  +    x0 = sqrt(x0);
  +
  +    x1 = (x0*cos_a_ - y0*sin_a_) + x;
  +    y1 = y + (x0*sin_a_ + y0*cos_a_);
  +    x2 = ((-x0)*cos_a_ - y0*sin_a_) + x;
  +    y2 = y + ((-x0)*sin_a_ + y0*cos_a_);
  +
  +    fprintf(fp, "%d %d %d %d %d line\n",
  +	    (int) x1, (int) y1, (int) x2, (int) y2, fill_width);
  +
  +    /*
  +     * The function uses the symetry in relation to the centre of the
  +     * circle. It avoid repetitive computation for the second half of
  +     * the surface of the circle.
  +     */
  +    x1 = x + (x0*cos_a_ - (-y0)*sin_a_);
  +    y1 = y + (x0*sin_a_ + (-y0)*cos_a_);
  +    x2 = x + ((-x0)*cos_a_ - (-y0)*sin_a_);
  +    y2 = y + ((-x0)*sin_a_ + (-y0)*cos_a_);
  +    
  +    fprintf(fp, "%d %d %d %d %d line\n",
  +	    (int) x1, (int) y1, (int) x2, (int) y2, fill_width);
  +    
  +    y0 = y0 + pitch1;
  +  }
  +}
  +
  +#if 0 /* original way of printing circle, no longer used */
  +/*! \brief Print Circle to Postscript document using old method.
  + *  \par Function Description
  + *  This function is the old function to print a circle.
  + *  It does not handle line type and filling of a circle.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] fp         FILE pointer to Postscript document.
  + *  \param [in] o_current  Circle object to print.
  + *  \param [in] origin_x   Page x coordinate to place circle OBJECT.
  + *  \param [in] origin_y   Page x coordinate to place circle OBJECT.
  + */
  +void o_circle_print_old(TOPLEVEL *w_current, FILE *fp, OBJECT *o_current,
  +			int origin_x, int origin_y)
  +{
  +  if (o_current == NULL) {
  +    printf("got null in o_circle_print\n");
  +    return;
  +  }
  +
  +  o_arc_print_solid(w_current, fp,
  +                    o_current->circle->center_x, 
  +		    o_current->circle->center_y,
  +		    o_current->circle->radius,
  +                    0, FULL_CIRCLE / 64,
  +                    o_current->color),
  +                    o_current->line_width, -1, -1,
  +                    origin_x, origin_y);
  +
  +}
  +#endif
  +
  +/*! \brief Draw a circle in an image.
  + *  \par Function Description
  + *  This function draws a circle in an image with the libgdgeda function
  + *  #gdImageArc().
  + *
  + *  \param [in] w_current   The TOPLEVEL object.
  + *  \param [in] o_current   Circle OBJECT to draw.
  + *  \param [in] origin_x    (unused).
  + *  \param [in] origin_y    (unused).
  + *  \param [in] color_mode  Draw circle in color if TRUE, B/W otherwise.
  + */
  +void o_circle_image_write(TOPLEVEL *w_current, OBJECT *o_current,
  +			  int origin_x, int origin_y, int color_mode)
  +{
  +  int color;
  +
  +  if (o_current == NULL) {
  +    printf("got null in o_circle_image_write\n");
  +    return;
  +  }
  +
  +  if (color_mode == TRUE) {
  +    color = o_image_geda2gd_color(o_current->color);
  +  } else {
  +    color = image_black;
  +  }
  +
  +#ifdef HAS_LIBGDGEDA
  +
  +  gdImageSetThickness(current_im_ptr, SCREENabs(w_current,
  +                                                o_current->line_width));
  +
  +  gdImageArc(current_im_ptr, 
  +             o_current->circle->screen_x, 
  +             o_current->circle->screen_y,
  +             SCREENabs(w_current, o_current->circle->radius)*2,
  +             SCREENabs(w_current, o_current->circle->radius)*2,
  +             0, 360, 
  +             color);
  +#endif
  +}
  
  
  
  1.24      +1582 -1091eda/geda/gaf/libgeda/src/o_complex_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_complex_basic.c
  ===================================================================
  RCS file: o_complex_basic.c
  diff -N o_complex_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_complex_basic.c	5 Jul 2006 03:13:38 -0000	1.24
  @@ -0,0 +1,1794 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +#include "funcs.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +void get_complex_bounds(TOPLEVEL *w_current, OBJECT *complex, 
  +			int *left, int *top, int *right, int *bottom)
  +{
  +  OBJECT *o_current=NULL;
  +  int rleft, rtop, rright, rbottom;
  +	
  +  *left = rleft = 999999;
  +  *top = rtop = 9999999;
  +  *right = rright = 0;
  +  *bottom = rbottom = 0;
  +	
  +
  +
  +  o_current = complex;
  +	
  +  while ( o_current != NULL ) {
  +    switch(o_current->type) {
  +      case(OBJ_LINE):
  +        get_line_bounds(w_current, o_current->line, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_NET):
  +        /* same as a line (diff name)*/
  +        get_net_bounds(w_current, o_current->line, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_BUS):
  +        /* same as a line (diff name)*/
  +        get_bus_bounds(w_current, o_current->line, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +	
  +      case(OBJ_BOX):
  +        get_box_bounds(w_current, o_current->box, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_PICTURE):
  +#ifndef HAS_GTK12
  +        get_picture_bounds(w_current, o_current->picture, &rleft, &rtop, &rright, &rbottom);
  +#endif
  +        break;
  +
  +      case(OBJ_CIRCLE):
  +        get_circle_bounds(w_current, o_current->circle, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +        /* recursive objects ?*/
  +        get_complex_bounds(w_current, o_current->complex->prim_objs, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_TEXT):
  +        /* only do bounding boxes for visible or doing show_hidden_text*/
  +        /* you might lose some attrs though */
  +        if (o_current->visibility == VISIBLE ||
  +            (o_current->visibility == INVISIBLE && w_current->show_hidden_text)) {
  +          get_text_bounds(w_current, o_current, &rleft, &rtop, &rright, &rbottom);
  +        }
  +        break;
  +
  +      case(OBJ_PIN):
  +        get_pin_bounds(w_current, o_current->line, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_ARC):
  +        get_arc_bounds(w_current, o_current, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      default:
  +        break;
  +    }
  +
  +    if (rleft < *left) *left = rleft;
  +    if (rtop < *top) *top = rtop;
  +    if (rright > *right) *right = rright;
  +    if (rbottom > *bottom) *bottom = rbottom;
  +	
  +
  +    o_current=o_current->next;
  +  }
  +
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +void get_complex_bounds_selection(TOPLEVEL *w_current, SELECTION *head, 
  +				  int *left, int *top, int *right, int *bottom)
  +{
  +  SELECTION *s_current=NULL;
  +  OBJECT *o_current=NULL;
  +  int rleft, rtop, rright, rbottom;
  +	
  +  *left = rleft = 999999;
  +  *top = rtop = 9999999;
  +  *right = rright = 0;
  +  *bottom = rbottom = 0;
  +	
  +  s_current = head;
  +	
  +  while ( s_current != NULL ) {
  +
  +    o_current = s_current->selected_object;
  +
  +    if (!o_current) {
  +      fprintf(stderr, "Got NULL in get_complex_bounds_selection\n");
  +      exit(-1);
  +    }
  +
  +    switch(o_current->type) {
  +      case(OBJ_LINE):
  +        get_line_bounds(w_current, o_current->line, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_NET):
  +        /* same as a line (diff name)*/
  +        get_net_bounds(w_current, o_current->line, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_BUS):
  +        /* same as a line (diff name)*/
  +        get_bus_bounds(w_current, o_current->line, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +	
  +      case(OBJ_BOX):
  +        get_box_bounds(w_current, o_current->box, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_PICTURE):
  +#ifndef HAS_GTK12
  +        get_picture_bounds(w_current, o_current->picture, &rleft, &rtop, &rright, &rbottom);
  +#endif
  +        break;
  +
  +      case(OBJ_CIRCLE):
  +        get_circle_bounds(w_current, o_current->circle, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +        /* recursive objects ?*/
  +        get_complex_bounds(w_current, o_current->complex->prim_objs, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_TEXT):
  +        /* only do bounding boxes for visible or doing show hidden text */
  +        /* you might lose some attrs though */
  +        if (o_current->visibility == VISIBLE ||
  +            (o_current->visibility == INVISIBLE && w_current->show_hidden_text)) {
  +          get_text_bounds(w_current, o_current, &rleft, &rtop, &rright, &rbottom);
  +        }
  +        break;
  +
  +      case(OBJ_PIN):
  +        get_pin_bounds(w_current, o_current->line, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_ARC):
  +        get_arc_bounds(w_current, o_current, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      default:
  +        break;
  +    }
  +
  +    if (rleft < *left) *left = rleft;
  +    if (rtop < *top) *top = rtop;
  +    if (rright > *right) *right = rright;
  +    if (rbottom > *bottom) *bottom = rbottom;
  +	
  +
  +    s_current=s_current->next;
  +  }
  +
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +void world_get_complex_bounds(TOPLEVEL *w_current, OBJECT *complex, 
  +			      int *left, int *top, int *right, int *bottom)
  +{
  +  OBJECT *o_current=NULL;
  +  int rleft, rtop, rright, rbottom;
  +	
  +  *left = rleft = w_current->init_right;
  +  *top = rtop = w_current->init_bottom;;
  +  *right = rright = 0;
  +  *bottom = rbottom = 0;
  +	
  +  o_current = complex;
  +	
  +  while ( o_current != NULL ) {
  +    switch(o_current->type) {
  +      case(OBJ_LINE):
  +        world_get_line_bounds(w_current, o_current->line, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_NET):
  +        /* same as a line (diff name)*/
  +        world_get_net_bounds(w_current, o_current->line, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_BUS):
  +        /* same as a line (diff name)*/
  +        world_get_bus_bounds(w_current, o_current->line, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +	
  +	
  +      case(OBJ_BOX):
  +        world_get_box_bounds(w_current, o_current->box, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_PICTURE):
  +#ifndef HAS_GTK12
  +        world_get_picture_bounds(w_current, o_current->picture, &rleft, &rtop, &rright, &rbottom);
  +#endif
  +        break;
  +
  +      case(OBJ_CIRCLE):
  +        world_get_circle_bounds(w_current, o_current->circle, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +        /* recursive objects ?*/
  +        world_get_complex_bounds(w_current, o_current->complex->prim_objs, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_TEXT):
  +        /* only do bounding boxes for visible or doing show hidden text */
  +        /* you might lose some attrs though */
  +        if (o_current->visibility == VISIBLE ||
  +            (o_current->visibility == INVISIBLE && w_current->show_hidden_text)) {
  +          world_get_text_bounds(w_current, o_current, &rleft, &rtop, &rright, &rbottom);
  +        }
  +        break;
  +
  +      case(OBJ_PIN):
  +        world_get_pin_bounds(w_current, o_current->line, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      case(OBJ_ARC):
  +        world_get_arc_bounds(w_current, o_current, &rleft, &rtop, &rright, &rbottom);
  +        break;
  +
  +      default:
  +        break;
  +    }
  +
  +    if (rleft < *left) *left = rleft;
  +    if (rtop < *top) *top = rtop;
  +    if (rright > *right) *right = rright;
  +    if (rbottom > *bottom) *bottom = rbottom;
  +	
  +
  +    o_current=o_current->next;
  +  }
  +
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *add_head(void)
  +{
  +  OBJECT *new_node=NULL;
  +
  +  new_node = s_basic_init_object("complex_head"); 
  +
  +  new_node->type = OBJ_HEAD; /* make this of head type hack */
  +
  +  /* don't need to do this for head nodes */
  +  /* ret = (OBJECT *) s_basic_link_object(new_node, NULL);*/
  +  return(new_node);
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +/* The promote_invisible flag is either TRUE or FALSE */
  +/* It controls if invisible text is promoted (TRUE) or not (FALSE) */
  +int o_complex_is_eligible_attribute (TOPLEVEL *w_current, OBJECT *object,
  +				     int promote_invisible) 
  +{
  +  char *name = NULL;
  +  char *value = NULL;
  +  char *padded_name = NULL;
  +  int promotableAttribute = FALSE;
  +  char *ptr;
  +
  +  if (object->type != OBJ_TEXT || object->attribute || object->attached_to)
  +  {
  +    return FALSE; /* not a text item or is already attached */
  +  }
  +
  +  /* Make sure text item is an attribute */
  +  ptr = strchr(object->text->string, '=');
  +  if (!ptr || ptr[1] == '\0' || ptr[1] == ' ')
  +  {
  +    return FALSE;  /* not an attribute */
  +  }
  +
  +  /* always promote symversion= attribute, even if it is invisible */
  +  if (strncmp(object->text->string, "symversion=", 11) == 0)
  +  {
  +    return TRUE;
  +  }
  +
  +  /* check list against attributes which can be promoted */
  +  if (w_current->always_promote_attributes &&
  +      (strlen(w_current->always_promote_attributes) != 0))
  +  {
  +    if (o_attrib_get_name_value(object->text->string, &name, &value))
  +    {
  +      padded_name = g_strdup_printf(" %s ", name);
  +      if (strstr(w_current->always_promote_attributes, padded_name))
  +      {
  +	/* Yes the name of the attribute was in the always promote */
  +        /* attributes list */
  +        promotableAttribute = TRUE;
  +      }
  +      
  +      g_free(padded_name);
  +      if (name) g_free(name);
  +      if (value) g_free(value);
  +      if (promotableAttribute)
  +	return TRUE;
  +    }
  +  }
  +
  +  /* object is invisible and we do not want to promote invisible text */
  +  if (object->visibility == INVISIBLE && promote_invisible == FALSE)
  +  {
  +    return FALSE; /* attribute not eligible for promotion */
  +  }
  +
  +  /* yup, attribute can be promoted */
  +  return TRUE;
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +int o_complex_is_embedded(OBJECT *o_current)
  +{
  +  if(o_current->complex == NULL)
  +  return 0;
  +
  +  if (o_current->complex_clib && 
  +      strncmp(o_current->complex_clib, "EMBEDDED", 8) == 0) {
  +    return 1;
  +  } else {
  +    return 0;
  +  }
  +
  +}
  +
  +/* Done */
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *o_complex_add(TOPLEVEL *w_current, OBJECT *object_list, char type,
  +		      int color, int x, int y, int angle,
  +		      int mirror, char *clib,
  +		      char *basename, int selectable,
  +		      int attribute_promotion)
  +{
  +  OBJECT *new_node=NULL;
  +  OBJECT *prim_objs=NULL;
  +  OBJECT *temp_tail=NULL;
  +  OBJECT *temp_parent=NULL;
  +  int save_adding_sel = 0;
  +  int loaded_normally = FALSE;
  +	
  +  char *filename;
  +
  +  new_node = s_basic_init_object("complex");
  +  new_node->type = type;
  +
  +  new_node->complex_basename = strdup(basename);
  +  if (clib)
  +    new_node->complex_clib = strdup(clib);
  +  else
  +    new_node->complex_clib = NULL;
  +
  +  new_node->color = color;
  +	
  +  new_node->complex = (COMPLEX *) malloc(sizeof(COMPLEX));
  +	
  +  new_node->complex->angle = angle;
  +  new_node->complex->mirror = mirror;
  +
  +  new_node->complex->x = x;
  +  new_node->complex->y = y;
  +  WORLDtoSCREEN(w_current, x, y, 
  +                &new_node->complex->screen_x, 
  +                &new_node->complex->screen_y);    
  +
  +  /*! \todo questionable caste? */
  +  new_node->draw_func = (void *) complex_draw_func;  
  +
  +  if (selectable) { 
  +    new_node->sel_func = (void *) select_func;
  +  } else {
  +    new_node->sel_func = NULL;
  +  }
  +
  +  /* this was at the beginning and p_complex was = to complex */
  +  prim_objs = (OBJECT *) add_head();
  +	
  +  /* set the parent field now */
  +  prim_objs->complex_parent = new_node;
  +
  +  /* is the bit with the temp and object_tail needed? */
  +  /* I don't like this at all hack */
  +  /* careful whenever you select, you get a read from disk */
  +  /* for the objects, UGG! there foreattribs are being copied */
  +  /* you need to override them if there are attached ones */
  +  /* on the main list */
  +  temp_tail = w_current->page_current->object_tail;
  +  temp_parent = w_current->page_current->object_parent;	
  +  w_current->page_current->object_parent = prim_objs;
  +  /* reason this works is because it has a head, see add_head above */
  +
  +  /* check for validity */
  +  if (clib && basename)
  +    filename = g_strdup_printf("%s%c%s", clib, G_DIR_SEPARATOR, basename);
  +  else 
  +    filename = g_strdup("unknown");
  +
  +  save_adding_sel = w_current->ADDING_SEL;
  +  w_current->ADDING_SEL = 1;	/* name is hack, don't want to */
  +
  +  if (access(filename, R_OK)) {
  +
  +    OBJECT *save_prim_objs;
  +    char *not_found_text = NULL;
  +    int left, right, top, bottom;
  +    int x_offset, y_offset;
  +
  +    if (clib == NULL) {
  +      s_log_message("Component library was not found or specified\n");
  +    } else if (basename == NULL) {
  +      s_log_message("Basename (component) was not found or specified\n");
  +    } else {
  +      s_log_message("Could not open symbol file [%s]\n", filename); 
  +    } 
  +
  +    /* filename was NOT found */
  +    loaded_normally = FALSE;
  +
  +    /* save the prim_objs pointer, since the following code modifies it */
  +    save_prim_objs = prim_objs;
  +
  +    /* Put placeholder into object list.  Changed by SDB on
  +     * 1.19.2005 to fix problem that symbols were silently
  +     * deleted by gattrib when RC files were messed up.  */
  +    new_node->type = OBJ_PLACEHOLDER;
  +
  +    /* Mark the origin of the missing component */
  +    prim_objs = o_line_add(w_current, prim_objs, OBJ_LINE, 
  +                           DETACHED_ATTRIBUTE_COLOR,
  +                           x - 50, y, x + 50, y);
  +    prim_objs = o_line_add(w_current, prim_objs, OBJ_LINE, 
  +                           DETACHED_ATTRIBUTE_COLOR,
  +                           x, y + 50, x, y - 50); 
  +
  +    /* Add some useful text */
  +    not_found_text = 
  +      g_strdup_printf ("Component not found:\n %s", basename);
  +    prim_objs = o_text_add(w_current, prim_objs,
  +                           OBJ_TEXT, DETACHED_ATTRIBUTE_COLOR, 
  +                           x + NOT_FOUND_TEXT_X, 
  +                           y + NOT_FOUND_TEXT_Y, LOWER_LEFT, 0, 
  +                           not_found_text, 8,
  +                           VISIBLE, SHOW_NAME_VALUE);
  +    free(not_found_text);
  +
  +    /* figure out where to put the hazard triangle */
  +    world_get_text_bounds(w_current, prim_objs,
  +                          &left, &top, &right, &bottom);
  +    x_offset = (right - left) / 4;  
  +    y_offset = bottom - top + 100;  /* 100 is just an additional offset */
  +
  +    /* add hazard triangle */
  +    prim_objs = o_line_add(w_current, prim_objs, OBJ_LINE, 
  +                           DETACHED_ATTRIBUTE_COLOR,
  +                           x + NOT_FOUND_TEXT_X + x_offset, 
  +                           y + NOT_FOUND_TEXT_Y + y_offset, 
  +                           x + NOT_FOUND_TEXT_X + x_offset + 600, 
  +                           y + NOT_FOUND_TEXT_Y + y_offset); 
  +    o_set_line_options(w_current, prim_objs, END_ROUND, TYPE_SOLID, 
  +                       50, -1, -1);
  +    prim_objs = o_line_add(w_current, prim_objs, OBJ_LINE, 
  +                           DETACHED_ATTRIBUTE_COLOR,
  +                           x + NOT_FOUND_TEXT_X + x_offset, 
  +                           y + NOT_FOUND_TEXT_Y + y_offset, 
  +                           x + NOT_FOUND_TEXT_X + x_offset + 300, 
  +                           y + NOT_FOUND_TEXT_Y + y_offset + 500); 
  +    o_set_line_options(w_current, prim_objs, END_ROUND, TYPE_SOLID, 
  +                       50, -1, -1);
  +    prim_objs = o_line_add(w_current, prim_objs, OBJ_LINE, 
  +                           DETACHED_ATTRIBUTE_COLOR,
  +                           x + NOT_FOUND_TEXT_X + x_offset + 300, 
  +                           y + NOT_FOUND_TEXT_Y + y_offset + 500, 
  +                           x + NOT_FOUND_TEXT_X + x_offset + 600, 
  +                           y + NOT_FOUND_TEXT_Y + y_offset); 
  +    o_set_line_options(w_current, prim_objs, END_ROUND, TYPE_SOLID, 
  +                       50, -1, -1);
  +    prim_objs = o_text_add(w_current, prim_objs,
  +                           OBJ_TEXT, DETACHED_ATTRIBUTE_COLOR, 
  +                           x + NOT_FOUND_TEXT_X + x_offset + 270, 
  +                           y + NOT_FOUND_TEXT_Y + y_offset + 90, 
  +                           LOWER_LEFT, 0, "!", 18,
  +                           VISIBLE, SHOW_NAME_VALUE);
  +    prim_objs = save_prim_objs;
  +
  +  } else {
  +
  +    /* filename was found */
  +    loaded_normally = TRUE;
  +    
  +    /* add connections till translated */
  +    o_read(w_current, prim_objs, filename);
  +    
  +  }
  +  w_current->ADDING_SEL = save_adding_sel;
  +
  +  if (w_current->attribute_promotion) { /* controlled through rc file */
  +
  +    OBJECT *tmp,*next;
  +
  +    for (tmp=prim_objs->next;tmp;tmp=next) {
  +
  +      next=tmp->next;
  +
  +      /* valid floating attrib? */
  +      if (o_complex_is_eligible_attribute(w_current, tmp,
  +                                          w_current->promote_invisible))
  +      {
  +        /* Is attribute promotion called for? (passed in parameter) */
  +        if (attribute_promotion)
  +        {
  +          /* remove tmp from the complex list */
  +          if (tmp->next)
  +            tmp->next->prev=tmp->prev;
  +          if (tmp->prev)
  +            tmp->prev->next=tmp->next;
  +
  +          /* Isolate tmp completely, now that it's removed from list */
  +          tmp->next=tmp->prev=NULL;
  +		
  +          object_list = (OBJECT *) s_basic_link_object(tmp, object_list);
  +          o_attrib_attach (w_current, object_list, tmp, new_node);
  +          o_text_translate_world(w_current, x, y, tmp);
  +
  +        } else { /* not promoting now, but deal with floating attribs */
  +
  +          if (w_current->keep_invisible == TRUE) {  
  +            /* if we are not promoting invisible attribs, keep them */
  +            /* around */
  +            tmp->visibility = INVISIBLE;
  +          } else {
  +            /* else do the default behavior of deleting the original */
  +            /* object */
  +            s_delete(w_current, tmp);
  +          }
  +
  +        }
  +      }
  +    }
  +  }
  +
  +  w_current->page_current->object_tail = temp_tail;
  +  w_current->page_current->object_parent = temp_parent;
  +
  +  object_list = (OBJECT *) s_basic_link_object(new_node, object_list);
  +  object_list->complex->prim_objs = prim_objs;
  +
  +
  +  /* do not mirror/rotate/translate/connect the primitive objects if the
  +   * component was not loaded via o_read 
  +   */
  +  if (loaded_normally == TRUE) {
  +    if (mirror) {
  +      o_complex_mirror_lowlevel(w_current, x, y, object_list);
  +    } 
  +
  +    o_complex_rotate_lowlevel(w_current, x, y, angle, angle, object_list); 
  +    o_complex_world_translate(w_current, x, y, prim_objs);
  +
  +    if (!w_current->ADDING_SEL) {
  +     s_conn_update_complex(w_current, prim_objs);
  +    }
  +  }
  +
  +  free(filename);
  +  return(object_list);
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *o_complex_add_embedded(TOPLEVEL *w_current, OBJECT *object_list,
  +			       char type, int color, int x, int y, int angle,
  +			       char *clib, char *basename, int selectable)
  +{
  +  OBJECT *prim_objs=NULL;
  +  OBJECT *new_node=NULL;
  +
  +  new_node = s_basic_init_object("complex");
  +  new_node->type = type;
  +
  +  new_node->complex = (COMPLEX *) malloc(sizeof(COMPLEX));
  +  new_node->complex->x = x;
  +  new_node->complex->y = y;
  +  WORLDtoSCREEN(w_current, x, y, 
  +                &new_node->complex->screen_x, 
  +                &new_node->complex->screen_y);    
  +
  +  new_node->complex->angle = angle;
  +  new_node->complex->mirror = 0;
  +	
  +  new_node->complex_basename = strdup(basename);
  +  if (clib)
  +    new_node->complex_clib = strdup(clib);
  +  else
  +    new_node->complex_clib = NULL;
  +
  +  new_node->color = color;
  +
  +  /*! \todo questionable cast */
  +  new_node->draw_func = (void *) complex_draw_func;  
  +
  +  /* (for a title block) an object that isn't selectable */
  +  if (selectable) { 
  +    new_node->sel_func = (void *) select_func;
  +  } else {
  +    new_node->sel_func = NULL;
  +  }
  +
  +  object_list = (OBJECT *) s_basic_link_object(new_node, object_list);
  +
  +  /* this was at the beginning and p_complex was = to complex */
  +  prim_objs = (OBJECT *) add_head();
  +  object_list->complex->prim_objs = prim_objs;
  +	
  +  /* set the parent field now */
  +  prim_objs->complex_parent = object_list;
  +
  +  /* don't have to translate/rotate/mirror here at all since the */
  +  /* object is in place */
  +  return(object_list);
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_recalc(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int left, right, top, bottom;
  +
  +  /* realc routine Add this somewhere */
  +  /* libhack */
  +  /* o_recalc(w_current, o_current->complex);*/
  +
  +  get_complex_bounds(w_current, o_current->complex->prim_objs, &left, &top, &right, &bottom);
  +  o_current->left = left;
  +  o_current->top = top;
  +  o_current->right = right;
  +  o_current->bottom = bottom;
  +
  +  WORLDtoSCREEN(w_current, 
  +                o_current->complex->x, 
  +                o_current->complex->y,
  +                &o_current->complex->screen_x, 
  +                &o_current->complex->screen_y);
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *o_complex_read(TOPLEVEL *w_current, OBJECT *object_list,
  +		       char buf[], unsigned int release_ver,
  +		       unsigned int fileformat_ver)
  +{
  +  char type; 
  +  int x1, y1;
  +  int angle;
  +
  +  char basename[256]; /* hack */
  +  char *clib=NULL;
  +	
  +  int selectable;
  +  int mirror;
  +
  +  sscanf(buf, "%c %d %d %d %d %d %s\n",
  +         &type, &x1, &y1, &selectable, &angle, &mirror, basename);
  +
  +  switch(angle) {
  +
  +    case(0):
  +    case(90):
  +    case(180):
  +    case(270):
  +      break;
  +
  +    default:
  +      fprintf(stderr, "Found a component with an invalid rotation [ %c %d %d %d %d %d %s ]\n", type, x1, y1, selectable, angle, mirror, basename); 
  +      s_log_message("Found a component with an invalid rotation [ %c %d %d %d %d %d %s ]\n", type, x1, y1, selectable, angle, mirror, basename); 
  +      break;
  +  }
  +
  +  switch(mirror) {
  +
  +    case(0):
  +    case(1):
  +
  +      break;
  +		
  +    default:
  +      fprintf(stderr, "Found a component with an invalid mirror flag [ %c %d %d %d %d %d %s ]\n", type, x1, y1, selectable, angle, mirror, basename); 
  +      s_log_message("Found a component with an invalid mirror flag [ %c %d %d %d %d %d %s ]\n", type, x1, y1, selectable, angle, mirror, basename); 
  +      break;
  +  }
  +  if (strncmp(basename, "EMBEDDED", 8) == 0) {
  +    
  +  object_list = o_complex_add_embedded(w_current, 
  +                                       object_list, type, 
  +                                       WHITE, x1, y1, angle,
  +                                       "EMBEDDED", basename, 
  +                                       selectable);
  +  } else {
  +    const GSList *clibs = s_clib_search_basename (basename);
  +    if (clibs == NULL) {
  +      s_log_message("Component [%s] was not found in any component library\n", 
  +		    basename);
  +      fprintf(stderr,
  +	      "Component [%s] was not found in any component library\n", 
  +	      basename);
  +      clib = NULL;
  +    } else {
  +      if (g_slist_next (clibs)) {
  +	s_log_message ("More than one component found with name [%s]\n",
  +		       basename);
  +	/* PB: for now, use the first directory in clibs */
  +	/* PB: maybe open a dialog to select the right one? */
  +      }
  +      clib = (gchar*)clibs->data;
  +    }
  +    
  +    object_list = o_complex_add(w_current, object_list, type, 
  +				WHITE, 
  +				x1, y1, 
  +				angle, mirror,
  +				clib, basename, selectable, FALSE);
  +  }
  +
  +  return object_list;
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +char *o_complex_save(OBJECT *object)
  +{
  +  int selectable;
  +  char *buf = NULL;
  +
  +  if (object->sel_func != NULL) 
  +  selectable = 1;
  +  else 
  +  selectable = 0;
  +
  +  if (object->type == OBJ_COMPLEX) {
  +    buf = g_strdup_printf("%c %d %d %d %d %d %s", object->type,
  +	    		  object->complex->x, object->complex->y, selectable, 
  +			  object->complex->angle, object->complex->mirror, 
  +			  object->complex_basename);
  +  } else if (object->type == OBJ_PLACEHOLDER) {
  +    buf = g_strdup_printf("C %d %d %d %d %d %s",
  +	    		  object->complex->x, object->complex->y, selectable, 
  +			  object->complex->angle, object->complex->mirror, 
  +			  object->complex_basename);  /* write 'C' manually */
  +  }
  +
  +  return(buf);
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_set_filename(TOPLEVEL *w_current, char *clib, char *basename) 
  +{
  +  int len;
  +
  +  if (basename == NULL) {
  +    fprintf(stderr, "Got NULL basename in o_complex_set_filename!\n");
  +    exit(-1);
  +  }
  +
  +  if (clib == NULL) {
  +    fprintf(stderr, "Got NULL clib in o_complex_set_filename!\n");
  +    exit(-1);
  +  }
  +
  +  if (w_current->internal_basename) {
  +    free(w_current->internal_basename);
  +  }
  +
  +  if (w_current->internal_clib) {
  +    free(w_current->internal_clib);
  +  }
  +
  +  len = strlen(basename);
  +  w_current->internal_basename = (char *) malloc(sizeof(char)*len+1);
  +
  +  len = strlen(clib) + 1;	
  +  w_current->internal_clib = (char *) malloc(sizeof(char)*len+1);
  +
  +  strcpy(w_current->internal_basename, basename);	
  +  strcpy(w_current->internal_clib, clib);	
  +} 
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_free_filename(TOPLEVEL *w_current)
  +{
  +  if (w_current->internal_basename) {
  +    free(w_current->internal_basename);
  +  }
  +
  +  if (w_current->internal_clib) {
  +    free(w_current->internal_clib);
  +  }
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +/* now I think it works fine */
  +/* no there is a bug with snap locking.  Basically if you don't snap/lock in */
  +/* PCtoW, then this doesn't work... :(  I don't know why yet */
  +void o_complex_translate(TOPLEVEL *w_current, int dx, int dy, OBJECT *object)
  +{
  +  int x, y;
  +  int prevx, prevy;
  +
  +  if (object == NULL) {
  +    printf("cmpt NO!\n");
  +    return;
  +  }
  +
  +  object->complex->screen_x = object->complex->screen_x + dx;
  +  object->complex->screen_y = object->complex->screen_y + dy;
  +
  +
  +  /* this fixing makes me nervious hack */
  +  SCREENtoWORLD(w_current, object->complex->screen_x,
  +                object->complex->screen_y, &x, &y);
  +
  +  prevx = object->complex->x;
  +  prevy = object->complex->y;
  +  object->complex->x = snap_grid(w_current, x);
  +  object->complex->y = snap_grid(w_current, y);
  +
  +  o_complex_world_translate(w_current, x - prevx,y - prevy, 
  +                            object->complex->prim_objs);
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +/* this needs work remove display stuff */
  +/* libhack */
  +/* and recalc stuff */
  +/* this function takes in a complex list */
  +void o_complex_world_translate(TOPLEVEL *w_current, int x1, int y1, 
  +			       OBJECT *prim_objs)
  +{
  +  OBJECT *o_current=NULL;
  +  OBJECT *one=NULL;
  +  OBJECT *two=NULL;
  +  unsigned long temp_color;
  +
  +  o_current = prim_objs;
  +
  +  while ( o_current != NULL ) {
  +    switch(o_current->type) {
  +      case(OBJ_LINE):
  +        o_line_translate_world(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_NET):
  +				/* same as a line, don't do this */
  +        o_line_translate_world(w_current, x1, y1, o_current);
  +        temp_color = w_current->override_color;
  +        w_current->override_color = -1;
  +        o_redraw_single(w_current, one); /* trying loop? hack*/
  +        o_redraw_single(w_current, two);
  +        w_current->override_color = temp_color;
  +        break;
  +
  +      case(OBJ_BUS):
  +				/* same as a line, don't do this */
  +        o_line_translate_world(w_current, x1, y1, o_current);
  +        temp_color = w_current->override_color;
  +        w_current->override_color = -1;
  +        o_redraw_single(w_current, one); /* trying loop? hack*/
  +        o_redraw_single(w_current, two);
  +        w_current->override_color = temp_color;
  +        break;
  +	
  +      case(OBJ_BOX):
  +        o_box_translate_world(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_PICTURE):
  +        o_picture_translate_world(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_CIRCLE):
  +        o_circle_translate_world(w_current, x1, y1, o_current);
  +        break;
  +	
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +        o_complex_world_translate_toplevel(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_TEXT):
  +        o_text_translate_world(w_current, x1, y1, o_current);
  +        break;
  +
  +        /* same note as above */
  +      case(OBJ_PIN):
  +        o_pin_translate_world(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_ARC):
  +        o_arc_translate_world(w_current, x1, y1, o_current);
  +        break;
  +    }
  +    o_current=o_current->next;
  +  }
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +/* this function takes the toplevel object and then also translates the
  + * complex */
  +void o_complex_world_translate_toplevel(TOPLEVEL *w_current,
  +					int x1, int y1, OBJECT *object)
  +{
  +  int left, right, top, bottom;
  +
  +  object->complex->x = object->complex->x + x1;
  +  object->complex->y = object->complex->y + y1;
  +
  +  WORLDtoSCREEN(w_current, object->complex->x,
  +                object->complex->y,
  +                &object->complex->screen_x,
  +                &object->complex->screen_y);
  +
  +  o_complex_world_translate(w_current, x1, y1, 
  +                            object->complex->prim_objs);
  +
  +  get_complex_bounds(w_current, object->complex->prim_objs, 
  +                     &left, &top, &right, &bottom);
  +	
  +  object->left = left;
  +  object->top = top;
  +  object->right = right;
  +  object->bottom = bottom;
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *o_complex_copy(TOPLEVEL *w_current, OBJECT *list_tail,
  +		       OBJECT *o_current)
  +{
  +  OBJECT *new_obj=NULL;
  +  ATTRIB *a_current;
  +  int color;
  +  int selectable;
  +
  +  if (o_current->saved_color == -1) {
  +    color = o_current->color;
  +  } else {
  +    color = o_current->saved_color;
  +  }
  +	
  +  if (o_current->sel_func) {
  +    selectable = TRUE;	
  +  } else {
  +    selectable = FALSE;	
  +  }
  +
  +  new_obj = o_complex_add(w_current, list_tail, o_current->type, color,
  +                          o_current->complex->x, o_current->complex->y, 
  +                          o_current->complex->angle, o_current->complex->mirror,
  +                          o_current->complex_clib, o_current->complex_basename, 
  +                          selectable, FALSE); 
  +
  +  o_attrib_slot_copy(w_current, o_current, new_obj);
  +
  +  /* deal with stuff that has changed */
  +
  +  /* here you need to create a list of attributes which need to be 
  +   * connected to the new list, probably make an attribute list and
  +   * fill it with sid's of the attributes */
  +  a_current = o_current->attribs;
  +  if (a_current) {
  +    while ( a_current ) {
  +
  +      /* head attrib node has prev = NULL */	
  +      if (a_current->prev != NULL) {
  +        a_current->copied_to = new_obj;	
  +      }
  +	
  +      a_current = a_current->next;
  +    }
  +  }
  +
  +  return(new_obj);
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *o_complex_copy_embedded(TOPLEVEL *w_current, OBJECT *list_tail,
  +				OBJECT *o_current)
  +{
  +  OBJECT *new_obj=NULL;
  +  OBJECT *temp_list;
  +  ATTRIB *a_current;
  +  int color;
  +  int selectable;
  +
  +  if (o_current->saved_color == -1) {
  +    color = o_current->color;
  +  } else {
  +    color = o_current->saved_color;
  +  }
  +
  +  if (o_current->sel_func) {
  +    selectable = TRUE;	
  +  } else {
  +    selectable = FALSE;	
  +  }
  +
  +  new_obj = o_complex_add_embedded(w_current, list_tail, o_current->type, 
  +                                   color,
  +                                   o_current->complex->x, o_current->complex->y, 
  +                                   o_current->complex->angle, 
  +                                   o_current->complex_clib, 
  +                                   o_current->complex_basename, 
  +                                   selectable); 
  +  /* deal with stuff that has changed */
  +	
  +  temp_list = o_list_copy_all(w_current,
  +                              o_current->complex->prim_objs->next,
  +                              new_obj->complex->prim_objs, 
  +                              NORMAL_FLAG);
  +	
  +  new_obj->complex->prim_objs = return_head(temp_list);
  +
  +  /* here you need to create a list of attributes which need to be 
  +   * connected to the new list, probably make an attribute list and
  +   * fill it with sid's of the attributes */
  +  a_current = o_current->attribs;
  +  if (a_current) {
  +    while ( a_current ) {
  +
  +      /* head attrib node has prev = NULL */	
  +      if (a_current->prev != NULL) {
  +        a_current->copied_to = new_obj;	
  +      }
  +	
  +      a_current = a_current->next;
  +    }
  +  }
  +
  +  return(new_obj);
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_delete(TOPLEVEL *w_current, OBJECT *delete)
  +{
  +  /* first remove complex pointer */
  +  if (delete->complex) {
  +    if (delete->complex->prim_objs) {
  +      s_delete_list_fromstart(w_current, 
  +                              delete->complex->prim_objs);
  +    }
  +    delete->complex->prim_objs = NULL;
  +  }
  +
  +  /* then remove the actual node */	
  +  s_delete(w_current, delete);
  +  delete = NULL;
  +  w_current->page_current->object_tail = (OBJECT *) 
  +  return_tail(w_current->page_current->object_head);
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_set_color(OBJECT *prim_objs, int color)
  +{
  +  OBJECT *o_current=NULL;
  +
  +  o_current = prim_objs;
  +
  +  while ( o_current != NULL ) {
  +    switch(o_current->type) {
  +      case(OBJ_LINE):
  +      case(OBJ_NET):
  +      case(OBJ_BUS):
  +      case(OBJ_BOX):
  +      case(OBJ_PICTURE):
  +      case(OBJ_CIRCLE):
  +      case(OBJ_PIN):
  +      case(OBJ_ARC):
  +        o_current->color = color;
  +        break;
  +
  +      case(OBJ_TEXT):
  +        o_current->color = color;
  +        o_complex_set_color(o_current->text->prim_objs, color);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +        o_current->color = color;
  +        o_complex_set_color(o_current->complex->prim_objs, color);
  +        break;
  +
  +    }
  +    o_current=o_current->next;
  +  }
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_set_color_single(OBJECT *o_current, int color)
  +{
  +  switch(o_current->type) {
  +    case(OBJ_LINE):
  +    case(OBJ_NET):
  +    case(OBJ_BUS):
  +    case(OBJ_BOX):
  +    case(OBJ_PICTURE):
  +    case(OBJ_CIRCLE):
  +    case(OBJ_PIN):
  +    case(OBJ_ARC):
  +    o_current->color = color;
  +    break;
  +
  +    case(OBJ_TEXT):
  +    o_current->color = color;
  +    o_complex_set_color(o_current->text->prim_objs, color);
  +    break;
  +
  +    case(OBJ_COMPLEX):
  +    case(OBJ_PLACEHOLDER):
  +    o_current->color = color;
  +    o_complex_set_color(o_current->complex->prim_objs, 
  +                        color);
  +    break;
  +
  +  }
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_set_color_save(OBJECT *complex, int color)
  +{
  +  OBJECT *o_current=NULL;
  +
  +  o_current = complex;
  +
  +  while ( o_current != NULL ) {
  +    switch(o_current->type) {
  +      case(OBJ_LINE):
  +      case(OBJ_NET):
  +      case(OBJ_BUS):
  +      case(OBJ_BOX):
  +      case(OBJ_PICTURE):
  +      case(OBJ_CIRCLE):
  +      case(OBJ_PIN):
  +      case(OBJ_ARC):
  +        o_current->saved_color = o_current->color;
  +        o_current->color = color;
  +        break;
  +
  +      case(OBJ_TEXT):
  +        o_current->saved_color = o_current->color;
  +        o_current->color = color;
  +        o_complex_set_color_save(
  +                                 o_current->text->prim_objs, 
  +                                 color);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +        o_current->saved_color = o_current->color;
  +        o_current->color = color;
  +        o_complex_set_color_save(o_current->complex->
  +                                 prim_objs,
  +                                 color);
  +        break;
  +
  +    }
  +    o_current=o_current->next;
  +  }
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_unset_color(OBJECT *complex)
  +{
  +  OBJECT *o_current=NULL;
  +
  +  o_current = complex;
  +
  +  while ( o_current != NULL ) {
  +    switch(o_current->type) {
  +      case(OBJ_LINE):
  +      case(OBJ_NET):
  +      case(OBJ_BUS):
  +      case(OBJ_BOX):
  +      case(OBJ_PICTURE):
  +      case(OBJ_CIRCLE):
  +      case(OBJ_PIN):
  +      case(OBJ_ARC):
  +        o_current->color = o_current->saved_color;
  +        o_current->saved_color = -1;
  +        break;
  +
  +      case(OBJ_TEXT):
  +        o_current->color = o_current->saved_color;
  +        o_current->saved_color = -1;
  +        o_complex_unset_color(o_current->text->prim_objs);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +        o_current->color = o_current->saved_color;
  +        o_current->saved_color = -1;
  +        o_complex_unset_color(o_current->complex->
  +                              prim_objs);
  +
  +        break;
  +
  +    }
  +    o_current=o_current->next;
  +  }
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_unset_color_single(OBJECT *o_current)
  +{
  +  switch(o_current->type) {
  +    case(OBJ_LINE):
  +    case(OBJ_NET):
  +    case(OBJ_BUS):
  +    case(OBJ_BOX):
  +    case(OBJ_PICTURE):
  +    case(OBJ_CIRCLE):
  +    case(OBJ_PIN):
  +    case(OBJ_ARC):
  +    o_current->color = o_current->saved_color;
  +    o_current->saved_color = -1;
  +    break;
  +
  +    case(OBJ_TEXT):
  +    o_current->color = o_current->saved_color;
  +    o_current->saved_color = -1;
  +    o_complex_unset_color(o_current->text->prim_objs);
  +    break;
  +
  +    case(OBJ_COMPLEX):
  +    case(OBJ_PLACEHOLDER):
  +    o_current->color = o_current->saved_color;
  +    o_current->saved_color = -1;
  +    o_complex_unset_color(o_current->complex->prim_objs);
  +
  +    break;
  +  }
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_set_saved_color_only(OBJECT *complex, int color)
  +{
  +  OBJECT *o_current=NULL;
  +
  +  o_current = complex;
  +
  +  while ( o_current != NULL ) {
  +    switch(o_current->type) {
  +      case(OBJ_LINE):
  +      case(OBJ_NET):
  +      case(OBJ_BUS):
  +      case(OBJ_BOX):
  +      case(OBJ_PICTURE):
  +      case(OBJ_CIRCLE):
  +      case(OBJ_PIN):
  +      case(OBJ_ARC):
  +        o_current->saved_color = color;
  +        break;
  +
  +      case(OBJ_TEXT):
  +        o_current->saved_color = color;
  +        o_complex_set_saved_color_only(o_current->text->prim_objs, color);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +        o_current->saved_color = color;
  +        o_complex_set_saved_color_only(o_current->complex->prim_objs, color);
  +        break;
  +
  +    }
  +    o_current=o_current->next;
  +  }
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +/* returns the counter'th pin in o_list */
  +/* NULL if there is no more pins */
  +OBJECT *o_complex_return_nth_pin(OBJECT *o_list, int counter)
  +{
  +  OBJECT *o_current;
  +  int internal_counter=0;
  +	
  +  o_current = o_list;
  +	
  +  while (o_current != NULL) {
  +    if (o_current->type == OBJ_PIN) {
  +			
  +      if (counter == internal_counter) {
  +        return(o_current);
  +      } else {
  +        internal_counter++;	
  +      }
  +    }	
  +    o_current = o_current->next;
  +  }
  +	
  +  return(NULL);
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +/* pass in top level object */
  +void o_complex_rotate_lowlevel(TOPLEVEL *w_current, int world_centerx, 
  +			       int world_centery, 
  +			       int angle,
  +			       int angle_change,
  +			       OBJECT *object)
  +{
  +  OBJECT *o_current=NULL;
  +
  +#if DEBUG 
  +  printf("------- a %d ac %d\n", angle, angle_change);
  +#endif
  +
  +  /* do individual complex objects */
  +  o_current = object->complex->prim_objs;
  +
  +  while ( o_current != NULL ) {
  +    switch(o_current->type) {
  +      case(OBJ_LINE):
  +        o_line_rotate_world(w_current, 0, 0, angle_change, o_current);
  +        break;
  +
  +      case(OBJ_NET):
  +        o_net_rotate_world(w_current, 0, 0, angle_change, o_current);
  +        break;
  +
  +      case(OBJ_BUS):
  +        o_bus_rotate_world(w_current, 0, 0, angle_change, o_current);
  +        break;
  +	
  +      case(OBJ_BOX):
  +        o_box_rotate_world(w_current, 0, 0, angle_change, o_current);
  +        break;
  +
  +      case(OBJ_PICTURE):
  +#ifndef HAS_GTK12
  +        o_picture_rotate_world(w_current, 0, 0, angle_change, o_current);
  +#endif
  +        break;
  +
  +      case(OBJ_CIRCLE):
  +        o_circle_rotate_world(w_current, 0, 0, angle_change, o_current);
  +        break;
  +
  +      case(OBJ_PIN):
  +        o_pin_rotate_world(w_current, 0, 0, angle_change, o_current);
  +        break;
  +
  +      case(OBJ_ARC):
  +        o_arc_rotate_world(w_current, 0, 0, angle_change, o_current);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +	o_complex_rotate_lowlevel(w_current, 0, 0, angle, angle_change, o_current);
  +        break; 
  +
  +      case(OBJ_TEXT):
  +        o_text_rotate_world(w_current, 0, 0, angle, angle_change, o_current);
  +        break;
  +
  +    }
  +    o_current=o_current->next;
  +  }
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +/* pass in top level object */
  +void o_complex_mirror_lowlevel(TOPLEVEL *w_current, 
  +			       int world_centerx, int world_centery,
  +			       OBJECT *object)
  +{
  +  OBJECT *o_current=NULL;
  +
  +  /* do individual complex objects */
  +  o_current = object->complex->prim_objs;
  +
  +  while ( o_current != NULL ) {
  +    switch(o_current->type) {
  +      case(OBJ_LINE):
  +        o_line_mirror_world(w_current, 0, 0, o_current);
  +        break;
  +
  +      case(OBJ_NET):
  +        o_net_mirror_world(w_current, 0, 0, o_current);
  +        break;
  +
  +      case(OBJ_BUS):
  +        o_bus_mirror_world(w_current, 0, 0, o_current);
  +        break;
  +	
  +      case(OBJ_BOX):
  +        o_box_mirror_world(w_current, 0, 0, o_current);
  +        break;
  +
  +      case(OBJ_PICTURE):
  +#ifndef HAS_GTK12
  +        o_picture_mirror_world(w_current, 0, 0, o_current);
  +#endif
  +        break;
  +
  +      case(OBJ_CIRCLE):
  +        o_circle_mirror_world(w_current, 0, 0, o_current);
  +        break;
  +
  +      case(OBJ_PIN):
  +        o_pin_mirror_world(w_current, 0, 0, o_current);
  +        break;
  +
  +      case(OBJ_ARC):
  +        o_arc_mirror_world(w_current, 0, 0, o_current);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +	o_complex_mirror_lowlevel(w_current, 0, 0, o_current);
  +	break;
  +
  +      case(OBJ_TEXT):
  +        o_text_mirror_world(w_current, 0, 0, o_current);
  +        break;
  +
  +    }
  +    o_current=o_current->next;
  +  }
  +
  +  /* mirror origin point */
  +  /*	object->x = -object->x;*/
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +/* pass in top level object */
  +OBJECT *o_complex_return_pin_object(OBJECT *object, char *pin) 
  +{
  +  OBJECT *o_current=NULL;
  +  OBJECT *found;
  +
  +  /* go inside complex objects */
  +  o_current = object->complex->prim_objs;
  +
  +  while ( o_current != NULL ) {
  +    switch(o_current->type) {
  +      case(OBJ_PIN):
  +
  +        /* Search for the pin making sure that */
  +        /* any found attribute starts with "pinnumber" */
  +        found = o_attrib_search_attrib_value(o_current->attribs, pin,
  +                                             "pinnumber", 0);
  +        if (found) {
  +#if DEBUG
  +          printf("%s: %s\n", found->name,
  +                 found->text->string);
  +#endif
  +          return(o_current);
  +        }
  +        break;
  +    }
  +    o_current=o_current->next;
  +  }
  +  return(NULL);
  +}
  +
  +#line 1849 "../noweb/o_complex_basic.nw"
  +void
  +o_complex_check_symversion(TOPLEVEL* w_current, OBJECT* object) 
  +{
  +  char *inside = NULL;
  +  char *outside = NULL;
  +  char *refdes = NULL;
  +  double inside_value = -1.0;
  +  double outside_value = -1.0;
  +  char *err_check = NULL;
  +  int inside_present = FALSE;
  +  int outside_present = FALSE;
  +  double inside_major, inside_minor;
  +  double outside_major, outside_minor;
  +  
  +  if (object->type != OBJ_COMPLEX && object->type != OBJ_PLACEHOLDER)
  +  {
  +    return;
  +  }
  +
  +  /* first look on the inside for the symversion= attribute */
  +  inside = o_attrib_search_name(object->complex->prim_objs, "symversion", 0);
  +
  +  /* now look for the symversion= attached to object */
  +  outside = o_attrib_search_attrib_name(object->attribs, "symversion", 0);
  +
  +  /* get the uref for future use */
  +  refdes = o_attrib_search_attrib_name(object->attribs, "refdes", 0);
  +  if (!refdes)
  +  {
  +    refdes = g_strdup ("unknown");
  +  }
  +  
  +  if (inside)
  +  {
  +    inside_value = strtod(inside, &err_check);
  +    if (inside_value == 0 && inside == err_check)
  +    {
  +      if (inside)
  +      { 
  +        s_log_message("WARNING: Symbol version parse error on refdes %s:\n"
  +                    "\tCould not parse symbol file symversion=%s\n",
  +                     refdes, inside);
  +      } else {
  +        s_log_message("WARNING: Symbol version parse error on refdes %s:\n"
  +                    "\tCould not parse symbol file symversion=\n",
  +                     refdes);
  +      }
  +      goto done;
  +    }
  +    inside_present = TRUE;
  +  } else {
  +    inside_present = FALSE;  /* attribute not inside */
  +  }
  +
  +  if (outside)
  +  {
  +    outside_value = strtod(outside, &err_check);
  +    if (outside_value == 0 && outside == err_check)
  +    {
  +      s_log_message("WARNING: Symbol version parse error on refdes %s:\n"
  +                    "\tCould not parse attached symversion=%s\n",
  +                    refdes, outside);
  +      goto done;
  +    }
  +    outside_present = TRUE; 
  +  } else {
  +    outside_present = FALSE;  /* attribute not outside */
  +  }
  +
  +#if DEBUG
  +  printf("%s:\n\tinside: %.1f outside: %.1f\n\n", object->name,
  +         inside_value, outside_value);
  +#endif
  +  
  +  /* symversion= is not present anywhere */
  +  if (!inside_present && !outside_present)
  +  {
  +    /* symbol is legacy and versioned okay */
  +    goto done;
  +  }
  +
  +  /* No symversion inside, but a version is outside, this is a weird case */
  +  if (!inside_present && outside_present)
  +  {
  +    s_log_message("WARNING: Symbol version oddity on refdes %s:\n"
  +                  "\tsymversion=%s attached to instantiated symbol, "
  +                  "but no symversion= inside symbol file\n",
  +                  refdes, outside);
  +    goto done;
  +  }
  +
  +  /* inside & not outside is a valid case, means symbol in library is newer */
  +  /* also if inside_value is greater than outside_value, then symbol in */
  +  /* library is newer */
  +  if ((inside_present && !outside_present) ||
  +      ((inside_present && outside_present) && (inside_value > outside_value)))
  +  {
  +    
  +    fprintf(stderr, "WARNING: Symbol version mismatch on refdes %s (%s):\n"
  +            "\tSymbol in library is newer than "
  +            "instantiated symbol\n",
  +            refdes, object->complex_basename);
  +    s_log_message("WARNING: Symbol version mismatch on refdes %s (%s):\n"
  +                  "\tSymbol in library is newer than "
  +                  "instantiated symbol\n",
  +                  refdes, object->complex_basename);
  +
  +    /* break up the version values into major.minor numbers */
  +    inside_major = floor(inside_value);
  +    inside_minor = inside_value - inside_major;
  +
  +    if (outside_present)
  +    {
  +      outside_major = floor(outside_value);
  +      outside_minor = outside_value - outside_major;
  +    } else {
  +      /* symversion was not attached to the symbol, set all to zero */
  +      outside_major = 0.0;
  +      outside_minor = 0.0;
  +      outside_value = 0.0;
  +    }
  +
  +#if DEBUG
  +    printf("i: %f %f %f\n", inside_value, inside_major, inside_minor);
  +    printf("o: %f %f %f\n", outside_value, outside_major, outside_minor);
  +#endif
  +    
  +    if (inside_major > outside_major)
  +    {
  +      char* refdes_copy;
  +      fprintf(stderr, "\tMAJOR VERSION CHANGE (file %.3f, "
  +              "instantiated %.3f, %s)!\n",
  +              inside_value, outside_value, refdes);
  +      s_log_message("\tMAJOR VERSION CHANGE (file %.3f, "
  +                    "instantiated %.3f)!\n",
  +                    inside_value, outside_value);
  +
  +      /* add the refdes to the major_changed_refdes GList */
  +      /* make sure refdes_copy is freed somewhere */
  +      refdes_copy = g_strconcat (refdes, " (",
  +                                 object->complex_basename,
  +                                 ")", NULL);
  +      w_current->major_changed_refdes =
  +        g_list_append(w_current->major_changed_refdes, refdes_copy);
  +
  +      /* don't bother checking minor changes if there are major ones*/
  +      goto done; 
  +    }
  +
  +    if (inside_minor > outside_minor)
  +    {
  +      fprintf(stderr, "\tMinor version change (file %.3f, "
  +              "instantiated %.3f)\n",
  +              inside_value, outside_value);
  +      s_log_message("\tMinor version change (file %.3f, "
  +                    "instantiated %.3f)\n",
  +                    inside_value, outside_value);
  +    }
  +
  +    goto done;
  +  }
  +
  +  /* outside value is greater than inside value, this is weird case */
  +  if ((inside_present && outside_present) && (outside_value > inside_value))
  +  {
  +    s_log_message("WARNING: Symbol version oddity on refdes %s:\n"
  +                  "\tInstanciated symbol is newer than "
  +                  "symbol in library\n",
  +                  refdes);
  +    goto done;
  +  }
  +
  +  /* if inside_value and outside_value match, then symbol versions are okay */
  +
  +done:
  +  if (inside) free(inside);
  +  if (outside) free(outside);
  +  if (refdes) free(refdes);
  +}
  
  
  
  1.19      +76 -59    eda/geda/gaf/libgeda/src/o_image.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_image.c
  ===================================================================
  RCS file: o_image.c
  diff -N o_image.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_image.c	5 Jul 2006 03:13:38 -0000	1.19
  @@ -0,0 +1,159 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#ifdef HAS_LIBGDGEDA
  +#include <gdgeda/gd.h>
  +#endif
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "funcs.h"
  +#include "colors.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +int image_black;
  +int image_white;
  +#if 0
  +int image_red;
  +int image_green;
  +int image_blue;
  +int image_yellow;
  +int image_cyan;
  +int image_grey;
  +#endif
  +
  +#ifdef HAS_LIBGDGEDA
  +
  +extern COLOR colors[MAX_COLORS];
  +
  +/*! \brief
  + *
  + */
  +gdImagePtr current_im_ptr;
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +void o_image_init(void)
  +{
  +
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + *  \param [in] x
  + *  \param [in] y
  + *  \param [in] color_mode
  + */
  +/* background color ? */
  +void o_image_create(int x, int y, int color_mode)
  +{
  +  gdImagePtr im_ptr;
  +
  +  im_ptr = gdImageCreate(x, y);
  +
  +  if (color_mode == TRUE) {
  +    /* You can change the background color which is outputed */
  +    if (colors[BACKGROUND_COLOR].image_red != -1 && 
  +        colors[BACKGROUND_COLOR].image_green != -1 &&
  +        colors[BACKGROUND_COLOR].image_blue != -1) {
  +      image_black = gdImageColorAllocate(im_ptr, 
  +                                         colors[BACKGROUND_COLOR].image_red,
  +                                         colors[BACKGROUND_COLOR].image_green,
  +                                         colors[BACKGROUND_COLOR].image_blue);
  +    } else {
  +      image_black = gdImageColorAllocate(im_ptr, 0, 0, 0);
  +    }
  +    image_white = gdImageColorAllocate(im_ptr, 255, 255, 255);
  +  } else {
  +    /* set the background to white */
  +    image_white = gdImageColorAllocate(im_ptr, 255, 255, 255);
  +    image_black = gdImageColorAllocate(im_ptr, 0, 0, 0);
  +  }
  +
  +  current_im_ptr = im_ptr;
  +
  +  s_color_gdcolor_init();
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +void o_image_close(void)
  +{
  +  gdImageDestroy(current_im_ptr);
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +int o_image_write(const char *filename)
  +{
  +  FILE *out;
  +
  +  if (filename == NULL) {
  +    return(-1);
  +  }
  +
  +  gdImageInterlace(current_im_ptr, 1);
  +
  +  out = fopen(filename, "wb");
  +
  +  if (out == NULL) {
  +    s_log_message("Could not open [%s] for image writting\n", filename);
  +    return(-1);
  +  }
  +
  +  gdImagePng(current_im_ptr, out);
  +
  +  fclose(out);
  +  return(0);
  +}
  +#endif
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + */
  +/* this can stay in even if libgdgeda doesn't exist */
  +int o_image_geda2gd_color(int color) 
  +{
  +  int value;
  +  value = s_color_image_int(color);
  +  return(value);
  +}
  +
  +
  
  
  
  1.22      +1308 -1008eda/geda/gaf/libgeda/src/o_line_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_line_basic.c
  ===================================================================
  RCS file: o_line_basic.c
  diff -N o_line_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_line_basic.c	5 Jul 2006 03:13:38 -0000	1.22
  @@ -0,0 +1,1531 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#ifdef HAS_LIBGDGEDA
  +#include <gdgeda/gd.h>
  +#endif
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +#include "funcs.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \brief Create and add line OBJECT to list.
  + *  \par Function Description
  + *  This function creates a new object representing a line.
  + *  This object is added to the end of the list <B>object_list</B>
  + *  pointed object belongs to.
  + *  The line is described by its two ends - <B>x1</B>,<B>y1</B> and
  + *  <B>x2</B>,<B>y2</B>.
  + *  The <B>type</B> parameter must be equal to #OBJ_LINE.
  + *  The <B>color</B> parameter corresponds to the color the box
  + *  will be drawn with.
  + *
  + *  The #OBJECT structure is allocated with the
  + *  #s_basic_init_object() function. The structure describing
  + *  the line is allocated and initialized with the parameters given
  + *  to the function.
  + *
  + *  Both the line type and the filling type are set to default
  + *  values : solid line type with a width of 0, and no filling.
  + *  It can be changed after with the #o_set_line_options() and
  + *  #o_set_fill_options().
  + *
  + *  The object is added to the end of the list described by the 
  + *  <B>object_list</B> parameter by the #s_basic_link_object().
  + *
  + *  \param [in]     w_current    The TOPLEVEL object.
  + *  \param [in,out] object_list  OBJECT list to add line to.
  + *  \param [in]     type         Must be OBJ_LINE.
  + *  \param [in]     color        Circle line color.
  + *  \param [in]     x1           Upper x coordinate.
  + *  \param [in]     y1           Upper y coordinate.
  + *  \param [in]     x2           Lower x coordinate.
  + *  \param [in]     y2           Lower y coordinate.
  + *  \return A pointer to the new end of the object list.
  + */
  +OBJECT *o_line_add(TOPLEVEL *w_current, OBJECT *object_list,
  +		   char type, int color, 
  +		   int x1, int y1, int x2, int y2)
  +{
  +  OBJECT *new_node;
  +
  +  /* create the object */
  +  new_node        = s_basic_init_object("line");
  +  new_node->type  = type;
  +  new_node->color = color;
  +  
  +  new_node->line  = (LINE *) malloc(sizeof(LINE));
  +  
  +  /* describe the line with its two ends */
  +  new_node->line->x[0] = x1;
  +  new_node->line->y[0] = y1;
  +  new_node->line->x[1] = x2;
  +  new_node->line->y[1] = y2;
  +  
  +  /* line type and filling initialized to default */
  +  o_set_line_options(w_current, new_node,
  +		     END_NONE, TYPE_SOLID, 0, -1, -1);
  +  o_set_fill_options(w_current, new_node,
  +		     FILLING_HOLLOW, -1, -1, -1, -1, -1);
  +  
  +  /* \todo questionable cast */
  +  new_node->draw_func = (void *) line_draw_func;
  +  /* \todo questionable cast */
  +  new_node->sel_func = (void *) select_func;  
  +  
  +  /* compute bounding box and screen coords */
  +  o_line_recalc(w_current, new_node);
  +  
  +  object_list = (OBJECT *) s_basic_link_object(new_node, object_list);
  +    
  +  return(object_list);
  +}
  +
  +/*! \brief Create a copy of a line.
  + *  \par Function Description
  + *  This function creates a verbatim copy of the
  + *  object pointed by <B>o_current</B> describing a line. The new object
  + *  is added at the end of the list following the <B>list_tail</B>
  + *  parameter.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [out] list_tail  OBJECT list to copy to.
  + *  \param [in]  o_current  Line OBJECT to copy.
  + *  \return A new pointer to the end of the object list.
  + */
  +OBJECT *o_line_copy(TOPLEVEL *w_current, OBJECT *list_tail, OBJECT *o_current)
  +{
  +  OBJECT *new_obj;
  +  ATTRIB *a_current;
  +  int color;
  +
  +  if (o_current->saved_color == -1) {
  +    color = o_current->color;
  +  } else {
  +    color = o_current->saved_color;
  +  }
  +
  +  /*
  +   * A new line object is added a the end of the object list with
  +   * #o_line_add(). Values for its fields are default and need to
  +   * be modified.
  +   */
  +  new_obj = o_line_add(w_current, list_tail,
  +		       OBJ_LINE, color,
  +		       0, 0, 0, 0);
  +
  +  /*
  +   * The coordinates of the ends of the new line are set with the ones
  +   * of the original line. The two lines have the sale line type and
  +   * filling options.
  +   *
  +   * The coordinates and the values in screen unit are computed with
  +   * #o_line_recalc().
  +   */
  +
  +  /* modify the line ends of the new line */
  +  new_obj->line->x[0] = o_current->line->x[0];
  +  new_obj->line->y[0] = o_current->line->y[0];
  +  new_obj->line->x[1] = o_current->line->x[1];
  +  new_obj->line->y[1] = o_current->line->y[1];
  +  
  +  /* copy the line type and filling options */
  +  o_set_line_options(w_current, new_obj, o_current->line_end,
  +		     o_current->line_type, o_current->line_width,
  +		     o_current->line_length, o_current->line_space);
  +  o_set_fill_options(w_current, new_obj,
  +		     o_current->fill_type, o_current->fill_width,
  +		     o_current->fill_pitch1, o_current->fill_angle1,
  +		     o_current->fill_pitch2, o_current->fill_angle2);
  +  
  +  /* calc the screen coords */
  +  o_line_recalc(w_current, o_current);
  +  
  +  /* new_obj->attribute = 0;*/
  +  a_current = o_current->attribs;
  +  if (a_current) {
  +    while ( a_current ) {
  +      /* head attrib node has prev = NULL */
  +      if (a_current->prev != NULL) {
  +	a_current->copied_to = new_obj;
  +      }
  +      a_current = a_current->next;
  +    }
  +  }
  +  
  +  /* return the new tail of the object list */
  +  return(new_obj);
  +}
  +
  +/*! \brief Modify the description of a line OBJECT.
  + *  \par Function Description
  + *  This function modifies the coordinates of one of the two ends of
  + *  the line described by <B>*object</B>. The new coordinates of this end,
  + *  identified by <B>whichone</B>, are given by <B>x</B> and <B>y</B>
  + *  in world unit.
  + *
  + *  The coordinates of the end of line is modified in the world
  + *  coordinate system. Screen coordinates and boundings are then updated.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in,out] object     Line OBJECT to modify.
  + *  \param [in]     x          New x coordinate.
  + *  \param [in]     y          New y coordinate.
  + *  \param [in]     whichone   Which line parameter to modify.
  + *
  + *  <B>whichone</B> can have the following values:
  + *  <DL>
  + *    <DT>*</DT><DD>LINE_END1
  + *    <DT>*</DT><DD>LINE_END2
  + *  </DL>
  + *
  + *  \par Author's note
  + *  pb20011009 - modified
  + */
  +void o_line_modify(TOPLEVEL *w_current, OBJECT *object, 
  +		   int x, int y, int whichone)
  +{
  +	/* change one of the end of the line */
  +	switch(whichone) {
  +		case LINE_END1:
  +		object->line->x[0] = x;
  +		object->line->y[0] = y;
  +		break;
  +		
  +		case LINE_END2:
  +		object->line->x[1] = x;
  +		object->line->y[1] = y;
  +		break;
  +		
  +		default:
  +		return;
  +	}
  +	
  +	/* recalculate the screen coords and the boundings */
  +	o_line_recalc(w_current, object);
  +	
  +}
  +
  +/*! \brief Create line OBJECT from character string.
  + *  \par Function Description
  + *  This function creates a line OBJECT from the character string
  + *  <B>*buf</B> the description of a box. The new box is added to the
  + *  list of objects of which <B>*object_list</B> is the last element
  + *  before the call.
  + *  The function returns a pointer on the new last element, that is
  + *  the added line object.
  + *
  + *  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]  w_current       The TOPLEVEL object.
  + *  \param [out] object_list     OBJECT list to create line in.
  + *  \param [in]  buf             Character string with line description.
  + *  \param [in]  release_ver     libgeda release version number.
  + *  \param [in]  fileformat_ver  libgeda file format version number.
  + *  \return A pointer to the new line object.
  + */
  +OBJECT *o_line_read(TOPLEVEL *w_current, OBJECT *object_list, char buf[],
  +		    unsigned int release_ver, unsigned int fileformat_ver)
  +{
  +  char type; 
  +  int x1, y1;
  +  int x2, y2;
  +  int d_x1, d_y1;
  +  int d_x2, d_y2;
  +  int line_width, line_space, line_length;
  +  int line_end;
  +  int line_type;
  +  int color;
  +
  +  if(release_ver <= VERSION_20000704) {
  +    /*
  +     * The old geda file format, i.e. releases 20000704 and older, does
  +     * not handle the line type and the filling - here filling is irrelevant.
  +     * They are set to default.
  +     */
  +    sscanf(buf, "%c %d %d %d %d %d\n", &type,
  +	   &x1, &y1, &x2, &y2, &color);
  +
  +    line_width = 0;
  +    line_end   = END_NONE;
  +    line_type  = TYPE_SOLID;
  +    line_length= -1;
  +    line_space = -1;
  +  } else {
  +    /*
  +     * The current line format to describe a line is a space separated
  +     * list of characters and numbers in plain ASCII on a single line.
  +     * The meaning of each item is described in the file format documentation.
  +     */
  +    sscanf(buf, "%c %d %d %d %d %d %d %d %d %d %d\n", &type,
  +	   &x1, &y1, &x2, &y2, &color,
  +	   &line_width, &line_end, &line_type, &line_length, &line_space);
  +  }
  +  
  +  d_x1 = x1; /* \todo PB : Needed ? */
  +  d_y1 = y1; 
  +  d_x2 = x2; 
  +  d_y2 = y2; 
  +    
  +  /*
  +   * Null length line are not allowed. If such a line is detected a
  +   * message is issued.
  +   *
  +   * It also checks is the required color is valid.
  +   */
  +  if (x1 == x2 && y1 == y2) {
  +    fprintf(stderr, "Found a zero length line [ %c %d %d %d %d %d ]\n",
  +            type, x1, y1, x2, y2, color);
  +    s_log_message("Found a zero length line [ %c %d %d %d %d %d ]\n",
  +                  type, x1, y1, x2, y2, color);
  +  }
  +  
  +  if (color < 0 || color > MAX_COLORS) {
  +    fprintf(stderr, "Found an invalid color [ %s ]\n", buf);
  +    s_log_message("Found an invalid color [ %s ]\n", buf);
  +    s_log_message("Setting color to WHITE\n");
  +    color = WHITE;
  +  }
  +
  +  /*
  +   * A line is internally described by its two ends. A new object is
  +   * allocated, initialized and added to the list of objects. Its line
  +   * type is set according to the values of the fields on the line.
  +   */
  +  /* create and add the line to the list */
  +  object_list = o_line_add(w_current, object_list,
  +			   type, color, d_x1, d_y1, d_x2, d_y2);
  +  /* set its line options */
  +  o_set_line_options(w_current, object_list,
  +		     line_end, line_type, line_width, line_length, 
  +		     line_space);
  +  /* filling is irrelevant for line, just set to default */
  +  o_set_fill_options(w_current, object_list,
  +		     FILLING_HOLLOW, -1, -1, -1, -1, -1);
  +
  +  return(object_list);
  +}
  +
  +/*! \brief Create a character string representation of a line OBJECT.
  + *  \par Function Description
  + *  The function formats a string in the buffer <B>*buff</B> to describe
  + *  the box object <B>*object</B>.
  + *  It follows the post-20000704 release file format that handle the
  + *  line type and fill options - filling is irrelevant here.
  + *
  + *  \param [in] object  Line OBJECT to create string from.
  + *  \return A pointer to the line OBJECT character string.
  + *
  + *  \note
  + *  Caller must free returned character string.
  + *
  + */
  +char *o_line_save(OBJECT *object)
  +{
  +  int x1, x2, y1, y2;
  +  int color;
  +  int line_width, line_space, line_length;
  +  char *buf;
  +  OBJECT_END line_end;
  +  OBJECT_TYPE line_type;
  +
  +  /* get the two ends */
  +  x1 = object->line->x[0];
  +  y1 = object->line->y[0];
  +  x2 = object->line->x[1];
  +  y2 = object->line->y[1];
  +  
  +  /* description of the line type */
  +  line_width = object->line_width;
  +  line_end   = object->line_end;
  +  line_type  = object->line_type;
  +  line_length= object->line_length;
  +  line_space = object->line_space;
  +  
  +  /* Use the right color */
  +  if (object->saved_color == -1) {
  +    color = object->color;
  +  } else {
  +    color = object->saved_color;
  +  }
  +  
  +  buf = g_strdup_printf("%c %d %d %d %d %d %d %d %d %d %d", object->type,
  +			x1, y1, x2, y2, color,
  +			line_width, line_end, line_type,
  +			line_length, line_space);
  +
  +  return(buf);
  +}
  +      
  +/*! \brief Translate a line position by a delta.
  + *  \par Function Description
  + *  This function applies a translation of (<B>dx</B>,<B>dy</B>) to the
  + *  line described by <B>*object</B>. <B>dx</B> and <B>dy</B> are in
  + *  screen unit.
  + *
  + *  \param [in]     w_current   The TOPLEVEL object.
  + *  \param [in]     dx          x distance to move.
  + *  \param [in]     dy          y distance to move.
  + *  \param [in,out] object      Line OBJECT to translate.
  + */
  +void o_line_translate(TOPLEVEL *w_current, int dx, int dy, OBJECT *object)
  +{
  +  int x, y;
  +
  +  if (object == NULL) printf("lt NO!\n");
  +
  +  /* Do screen coords */
  +  object->line->screen_x[0] = object->line->screen_x[0] + dx;
  +  object->line->screen_y[0] = object->line->screen_y[0] + dy;
  +  object->line->screen_x[1] = object->line->screen_x[1] + dx;
  +  object->line->screen_y[1] = object->line->screen_y[1] + dy;
  +  
  +  /* do we want snap grid here? hack */
  +  SCREENtoWORLD(w_current,
  +		object->line->screen_x[0], object->line->screen_y[0], 
  +		&x, &y);  
  +  object->line->x[0] = snap_grid(w_current, x);
  +  object->line->y[0] = snap_grid(w_current, y);
  +  
  +  SCREENtoWORLD(w_current,
  +		object->line->screen_x[1], object->line->screen_y[1], 
  +		&x, &y);  
  +  object->line->x[1] = snap_grid(w_current, x);
  +  object->line->y[1] = snap_grid(w_current, y);
  +  
  +}
  +
  +/*! \brief Translate a line position in WORLD coordinates by a delta.
  + *  \par Function Description
  + *  This function applies a translation of (<B>x1</B>,<B>y1</B>) to the line
  + *  described by <B>*object</B>. <B>x1</B> and <B>y1</B> are in world unit.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in]     x1         x distance to move.
  + *  \param [in]     y1         y distance to move.
  + *  \param [in,out] object     Line OBJECT to translate.
  + */
  +void o_line_translate_world(TOPLEVEL *w_current,
  +			    int x1, int y1, OBJECT *object)
  +{
  +  int screen_x1, screen_y1;
  +  int screen_x2, screen_y2;	
  +  int left, right, top, bottom;
  +
  +  if (object == NULL) printf("ltw NO!\n");
  +
  +  /* Do world coords */
  +  object->line->x[0] = object->line->x[0] + x1;
  +  object->line->y[0] = object->line->y[0] + y1;
  +  object->line->x[1] = object->line->x[1] + x1;
  +  object->line->y[1] = object->line->y[1] + y1;
  +  
  +  /* update screen coords */
  +  WORLDtoSCREEN(w_current, object->line->x[0], 
  +		object->line->y[0], 
  +		&screen_x1,
  +		&screen_y1);  
  +  object->line->screen_x[0] = screen_x1;
  +  object->line->screen_y[0] = screen_y1;
  +  
  +  WORLDtoSCREEN(w_current, object->line->x[1], 
  +		object->line->y[1], 
  +		&screen_x2,
  +		&screen_y2);  
  +  object->line->screen_x[1] = screen_x2;
  +  object->line->screen_y[1] = screen_y2;
  +  
  +  /* update bounding box */
  +  get_line_bounds(w_current, object->line, &left, &top, &right, &bottom);
  +  
  +  object->left   = left;
  +  object->top    = top;
  +  object->right  = right;
  +  object->bottom = bottom;
  +    
  +}
  +
  +/*! \brief Rotate a line OBJECT.
  + *  \par Function Description
  + *  This function applies a rotation of center (<B>centerx</B>,<B>centery</B>)
  + *  and angle <B>angle</B> to the line object <B>*object</B>.
  + *  The coordinates of the rotation center are in screen units.
  + *  <B>angle</B> mst be a 90 degree multiple. If not, no rotation is applied.
  + *
  + *  The rotation is made by the #o_line_rotate_world() function
  + *  that perform a rotation of angle <B>angle</B> and center
  + *  (<B>world_centerx</B>,<B>world_centery</B>) in world unit.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in]     centerx    Rotation center x coordinate in SCREEN units.
  + *  \param [in]     centery    Rotation center y coordinate in SCREEN units.
  + *  \param [in]     angle      Rotation angle in degrees (unused).
  + *  \param [in,out] object     Line OBJECT to rotate.
  + *
  + *  \note
  + *  takes in screen coordinates for the centerx,y, and then does the rotate 
  + *  in world space
  + *  also ignores angle argument... for now, rotate only in 90 degree 
  + *  increments
  + */
  +void o_line_rotate(TOPLEVEL *w_current, int centerx, int centery, int angle,
  +		   OBJECT *object)
  +{
  +  int world_centerx, world_centery;
  +
  +  /* convert the center of rotation to world unit */
  +  SCREENtoWORLD(w_current, centerx, centery, 
  +                &world_centerx,
  +                &world_centery);  
  +
  +  /* rotate the line */
  +  /* the check on the rotation angle is in o_line_rotate_world() */
  +  o_line_rotate_world(w_current,
  +					  world_centerx, world_centery, angle,
  +					  object);
  +  
  +}
  +
  +/*! \brief Rotate Line OBJECT using WORLD coordinates. 
  + *  \par Function Description 
  + *  This function rotates the line described by
  + *  <B>*object</B> around the (<B>world_centerx</B>,<B>world_centery</B>)
  + *  point by <B>angle</B> degrees.
  + *  The center of rotation is in world units.
  + *
  + *  \param [in]      w_current      The TOPLEVEL object.
  + *  \param [in]      world_centerx  Rotation center x coordinate in WORLD units.
  + *  \param [in]      world_centery  Rotation center y coordinate in WORLD units.
  + *  \param [in]      angle          Rotation angle in degrees (See note below).
  + *  \param [in,out]  object         Line OBJECT to rotate.
  + */
  +void o_line_rotate_world(TOPLEVEL *w_current, 
  +			 int world_centerx, int world_centery, int angle,
  +			 OBJECT *object)
  +{
  +  int newx, newy;
  +	
  +  if (angle == 0) 
  +  return;
  +
  +  /* angle must be positive */
  +  if(angle < 0) angle = -angle;
  +  /* angle must be 90 multiple or no rotation performed */
  +  if((angle % 90) != 0) return;
  +
  +  /*
  +   * The center of rotation (<B>world_centerx</B>,<B>world_centery</B>)
  +   * is translated to the origin. The rotation of the two ends of
  +   * the line is performed. FInally, the rotated line is translated
  +   * back to its previous location.
  +   */
  +  /* translate object to origin */
  +  o_line_translate_world(w_current, -world_centerx, -world_centery, object);
  +
  +  /* rotate line end 1 */
  +  rotate_point_90(object->line->x[0], object->line->y[0], angle,
  +		  &newx, &newy);
  +
  +  object->line->x[0] = newx;
  +  object->line->y[0] = newy;
  +  
  +  /* rotate line end 2 */
  +  rotate_point_90(object->line->x[1], object->line->y[1], angle,
  +		  &newx, &newy);
  +  
  +  object->line->x[1] = newx;
  +  object->line->y[1] = newy;
  +
  +  /* translate object back to normal position */
  +  o_line_translate_world(w_current, world_centerx, world_centery, object);
  +  
  +}
  +
  +/*! \brief Mirror a Line.
  + *  \par Function Description
  + *  This function mirrors the line from the point
  + *  (<B>centerx</B>,<B>centery</B>) in screen unit.
  + *
  + *  The origin of the mirror in screen unit is converted in world unit.
  + *  The line is mirrored with the function #o_line_mirror_world()
  + *  for which the origin of the mirror must be given in world unit.
  + *
  + *  \param [in]     w_current  The TOPLEVEL object.
  + *  \param [in]     centerx    Origin x coordinate in WORLD units.
  + *  \param [in]     centery    Origin y coordinate in WORLD units.
  + *  \param [in,out] object     Line OBJECT to mirror.
  + */
  +void o_line_mirror(TOPLEVEL *w_current,
  +		   int centerx, int centery,
  +		   OBJECT *object)
  +{
  +  int world_centerx, world_centery;
  +
  +  /* convert the origin of mirror */
  +  SCREENtoWORLD(w_current, centerx, centery, 
  +                &world_centerx,
  +                &world_centery);  
  +
  +  /* apply the mirror in world coords */
  +  o_line_mirror_world(w_current,
  +					  world_centerx, world_centery,
  +					  object);
  +  
  +}
  +
  +/*! \brief Mirror a line using WORLD coordinates.
  + *  \par Function Description
  + *  This function mirrors the line from the point
  + *  (<B>world_centerx</B>,<B>world_centery</B>) in world unit.
  + *
  + *  The line if first translated to the origin, then mirrored
  + *  and finally translated back at its previous position.
  + *
  + *  \param [in]     w_current      The TOPLEVEL object.
  + *  \param [in]     world_centerx  Origin x coordinate in WORLD units.
  + *  \param [in]     world_centery  Origin y coordinate in WORLD units.
  + *  \param [in,out] object         Line OBJECT to mirror.
  + */
  +void o_line_mirror_world(TOPLEVEL *w_current, int world_centerx,
  +			 int world_centery, OBJECT *object)
  +{
  +  /* translate object to origin */
  +  o_line_translate_world(w_current, -world_centerx, -world_centery, object);
  +
  +  /* mirror the line ends */
  +  object->line->x[0] = -object->line->x[0];
  +  object->line->x[1] = -object->line->x[1];
  +
  +  /* translate back in position */
  +  o_line_translate_world(w_current, world_centerx, world_centery, object);
  +  
  +}
  +
  +/*! \brief Recalculate line coordinates in SCREEN units.
  + *  \par Function Description
  + *  This function recalculate the screen coords of the <B>o_current</B>
  + *  pointed line object from its world coords.
  + *
  + *  The line ends coordinates and its bounding box are recalculated
  + *  as well as the OBJECT specific fields (line width, filling ...).
  + *
  + *  \param [in] w_current      The TOPLEVEL object.
  + *  \param [in,out] o_current  Line OBJECT to be recalculated.
  + */
  +void o_line_recalc(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int screen_x1, screen_y1;
  +  int screen_x2, screen_y2;
  +  int left, right, top, bottom;
  +
  +  if (o_current->line == NULL) {
  +    return;
  +  }
  +
  +  /* update the screen coords of end 1 of the line */
  +  WORLDtoSCREEN(w_current,
  +		o_current->line->x[0], o_current->line->y[0], 
  +		&screen_x1, &screen_y1);  
  +  o_current->line->screen_x[0] = screen_x1;
  +  o_current->line->screen_y[0] = screen_y1;
  +  
  +  /* update the screen coords of end 2 of the line */
  +  WORLDtoSCREEN(w_current,
  +		o_current->line->x[1], o_current->line->y[1], 
  +		&screen_x2, &screen_y2);  
  +  o_current->line->screen_x[1] = screen_x2;
  +  o_current->line->screen_y[1] = screen_y2;
  +  
  +  /* update the bounding box - screen unit */
  +  get_line_bounds(w_current, o_current->line, 
  +		  &left, &top, &right, &bottom);
  +  o_current->left   = left;
  +  o_current->top    = top;
  +  o_current->right  = right;
  +  o_current->bottom = bottom;
  +  
  +  /* recalc OBJECT specific parameters */
  +  o_object_recalc(w_current, o_current);
  +  
  +}
  +
  +/*! \brief Get line bounding rectangle.
  + *  \par Function Description 
  + *  This function sets the <B>left</B>, <B>top</B>, <B>right</B> and
  + *  <B>bottom</B> parameters to the boundings of the line object described
  + *  by <B>*line</B> in screen units.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  line       line OBJECT to read coordinates from.
  + *  \param [out] left       Left line coordinate in SCREEN units.
  + *  \param [out] top        Top line coordinate in SCREEN units.
  + *  \param [out] right      Right line coordinate in SCREEN units.
  + *  \param [out] bottom     Bottom line coordinate in SCREEN units.
  + */
  +void get_line_bounds(TOPLEVEL *w_current, LINE *line, int *left, int *top,
  +		     int *right, int *bottom)
  +{
  +  *left   = w_current->width;
  +  *top    = w_current->height;
  +  *right  = 0;
  +  *bottom = 0;
  +	
  +  if (line->screen_x[0] < *left)   *left   = line->screen_x[0];
  +  if (line->screen_x[0] > *right)  *right  = line->screen_x[0];
  +  if (line->screen_y[0] < *top)    *top    = line->screen_y[0];
  +  if (line->screen_y[0] > *bottom) *bottom = line->screen_y[0];
  +
  +  if (line->screen_x[1] < *left)   *left   = line->screen_x[1];
  +  if (line->screen_x[1] > *right)  *right  = line->screen_x[1];
  +  if (line->screen_y[1] < *top)    *top    = line->screen_y[1];
  +  if (line->screen_y[1] > *bottom) *bottom = line->screen_y[1];
  +
  +  /* PB : bounding box has to take into account the width of the line */
  +  /* PB : but line width is unknown here */
  +	
  +  *left   = *left   - 4;
  +  *top    = *top    - 4;
  +  *right  = *right  + 4;
  +  *bottom = *bottom + 4;
  +}
  +
  +/*! \brief Get line bounding rectangle in WORLD coordinates.
  + *  \par Function Description
  + *  This function sets the <B>left</B>, <B>top</B>, <B>right</B> and
  + *  <B>bottom</B> parameters to the boundings of the line object described
  + *  in <B>*line</B> in world units.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  line       Line OBJECT to read coordinates from.
  + *  \param [out] left       Left line coordinate in WORLD units.
  + *  \param [out] top        Top line coordinate in WORLD units.
  + *  \param [out] right      Right line coordinate in WORLD units.
  + *  \param [out] bottom     Bottom line coordinate in WORLD units.
  + */
  +void world_get_line_bounds(TOPLEVEL *w_current, LINE *line,
  +			   int *left, int *top, int *right, int *bottom)
  +{
  +  *left   = w_current->init_right;
  +  *top    = w_current->init_bottom;
  +  *right  = 0;
  +  *bottom = 0;
  +	
  +  if (line->x[0] < *left)   *left   = line->x[0];
  +  if (line->x[0] > *right)  *right  = line->x[0];
  +  if (line->y[0] < *top)    *top    = line->y[0];
  +  if (line->y[0] > *bottom) *bottom = line->y[0];
  +
  +  if (line->x[1] < *left)   *left   = line->x[1];
  +  if (line->x[1] > *right)  *right  = line->x[1];
  +  if (line->y[1] < *top)    *top    = line->y[1];
  +  if (line->y[1] > *bottom) *bottom = line->y[1];
  +  
  +}
  +
  +/*! \brief Print line to Postscript document.
  + *  \par Function Description
  + *  This function prints the line described by the <B>o_current</B>
  + *  parameter to a Postscript document.
  + *  The Postscript document is described by the <B>fp</B> file pointer.
  + *
  + *  Parameters of the line are extracted from object pointed by
  + *  <B>o_current</B>.
  + *  
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] fp         FILE pointer to Postscript document.
  + *  \param [in] o_current  Line OBJECT to write to document.
  + *  \param [in] origin_x   Page x coordinate to place line OBJECT.
  + *  \param [in] origin_y   Page y coordinate to place line OBJECT.
  + */
  +void o_line_print(TOPLEVEL *w_current, FILE *fp, OBJECT *o_current, 
  +		  int origin_x, int origin_y)
  +{
  +  int x1, y1, x2, y2;
  +  int color;
  +  int line_width, length, space;
  +  void (*outl_func)() = NULL;
  +	
  +  if (o_current == NULL) {
  +    printf("got null in o_line_print\n");
  +    return;
  +  }
  +
  +  x1    = o_current->line->x[0];
  +  y1    = o_current->line->y[0];
  +  x2    = o_current->line->x[1];
  +  y2    = o_current->line->y[1];
  +  color = o_current->color;
  +
  +  /*
  +   * Depending on the type of the line for this particular line, the
  +   * appropriate function is chosen among
  +   * #o_line_print_solid(), #o_line_print_dotted()#, #o_line_print_dashed(),
  +   * #o_line_print_center() and #o_line_print_phantom().
  +   *
  +   * The needed parameters for each of these types are extracted from the
  +   * <B>o_current</B> object. Depending on the type, unused parameters are
  +   * set to -1.
  +   *
  +   * In the eventuality of a length and/or space null, the line is printed
  +   * solid to avoid and endless loop produced by other functions.
  +   */
  +  line_width = o_current->line_width;
  +  if(line_width <= 2) line_width = 2;
  +  length = o_current->line_length;
  +  space  = o_current->line_space;
  +  
  +  switch(o_current->line_type) {
  +    case(TYPE_SOLID):
  +      length = -1; space = -1;
  +      outl_func = (void *) o_line_print_solid;
  +      break;
  +      
  +    case(TYPE_DOTTED):
  +      length = -1;
  +      outl_func = (void *) o_line_print_dotted;
  +      break;
  +      
  +    case(TYPE_DASHED):
  +      outl_func = (void *) o_line_print_dashed;
  +      break;
  +      
  +    case(TYPE_CENTER):
  +      outl_func = (void *) o_line_print_center;
  +      break;
  +      
  +    case(TYPE_PHANTOM):
  +      outl_func = (void *) o_line_print_phantom;
  +      break;
  +      
  +    case(TYPE_ERASE):
  +      /* Unused for now, print it solid */
  +      length = -1; space = -1;
  +      outl_func = (void *) o_line_print_solid;
  +      break;
  +  }
  +
  +  if((length == 0) || (space == 0)) {
  +    length = -1; space = -1;
  +    outl_func = (void *) o_line_print_solid;
  +  }
  +  
  +  (*outl_func)(w_current, fp,
  +	       x1 - origin_x, y1 - origin_y,
  +	       x2 - origin_x, y2 - origin_y,
  +	       color,
  +	       line_width, length, space,
  +	       origin_x, origin_y);
  +}
  +
  +/*! \brief Print a solid line to Postscript document.
  + *  \par Function Description
  + *  This function prints a line when a solid line type is required.
  + *  The line is defined by the coordinates of its two ends in
  + *  (<B>x1</B>,<B>y1</B>) and (<B>x2</B>,<B>y2</B>).
  + *  The Postscript document is defined by the file pointer <B>fp</B>.
  + *  The parameters <B>length</B> and <B>space</B> are ignored whereas
  + *  <B>line_width</B> specifies the width of the printed line.
  + *
  + *  \param [in] w_current     The TOPLEVEL object.
  + *  \param [in] fp            FILE pointer to Postscript document.
  + *  \param [in] x1            Upper x coordinate.
  + *  \param [in] y1            Upper y coordinate.
  + *  \param [in] x2            Lower x coordinate.
  + *  \param [in] y2            Lower y coordinate.
  + *  \param [in] color         Line color.
  + *  \param [in] line_width    Width of line.
  + *  \param [in] length        (unused).
  + *  \param [in] space         (unused).
  + *  \param [in] origin_x      Page x coordinate to place line OBJECT.
  + *  \param [in] origin_y      Page y coordinate to place line OBJECT.
  + */
  +void o_line_print_solid(TOPLEVEL *w_current, FILE *fp,
  +			int x1, int y1, int x2, int y2,
  +			int color,
  +			int line_width, int length, int space,
  +			int origin_x, int origin_y)
  +{
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +  
  +  fprintf(fp,"%d %d %d %d %d line\n",
  +	  x1,y1,x2,y2, line_width);
  +}
  +
  +/*! \brief Print a dotted line to Postscript document.
  + *  \par Function Description
  + *  This function prints a line when a dotted line type is required.
  + *  The line is defined by the coordinates of its two ends in
  + *  (<B>x1</B>,<B>y1</B>) and (<B>x2</B>,<B>y2</B>).
  + *  The Postscript document is defined by the file pointer <B>fp</B>.
  + *  The parameter <B>length</B> is ignored whereas <B>line_width</B>
  + *  specifies the diameter of the dots and <B>space</B> the distance
  + *  between two dots.
  + *
  + *  A negative value for <B>space</B> leads to an endless loop.
  + *
  + *  All dimensions are in mils.
  + *
  + *  The function sets the color in which the line will be printed with.
  + *
  + *  \param [in] w_current     The TOPLEVEL object.
  + *  \param [in] fp            FILE pointer to Postscript document.
  + *  \param [in] x1            Upper x coordinate.
  + *  \param [in] y1            Upper y coordinate.
  + *  \param [in] x2            Lower x coordinate.
  + *  \param [in] y2            Lower y coordinate.
  + *  \param [in] color         Line color.
  + *  \param [in] line_width    Width of line.
  + *  \param [in] length        (unused).
  + *  \param [in] space         Space between dots.
  + *  \param [in] origin_x      Page x coordinate to place line OBJECT.
  + *  \param [in] origin_y      Page y coordinate to place line OBJECT.
  + */
  +void o_line_print_dotted(TOPLEVEL *w_current, FILE *fp,
  +			 int x1, int y1, int x2, int y2,
  +			 int color,
  +			 int line_width, int length, int space,
  +			 int origin_x, int origin_y)
  +{
  +  double dx, dy, l, d;
  +  double dx1, dy1;
  +  double xa, ya;
  +  
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +  
  +  /* The dotted line command takes an array of dots so print out the
  +   * beginnings of the array 
  +   */
  +  fprintf(fp,"[");
  +  /* PB : is the width relevant for a dot (circle) ? */
  +  /* f_print_set_line_width(fp, line_width); */
  +  
  +  /*
  +   * Depending on the slope of the line the space parameter is
  +   * projected on each of the two directions x and y resulting
  +   * in <B>dx1</B> and <B>dy1</B>. Starting from one end by increments
  +   * of space the dots are printed.
  +   *
  +   * A dot is represented by a filled circle. Position of the
  +   * circle is (<B>xa</B>, <B>ya</B>) and its radius is the <B>line_width</B>
  +   * parameter.
  +   */
  +  
  +  dx = (double) (x2 - x1);
  +  dy = (double) (y2 - y1);
  +  l = sqrt((dx * dx) + (dy * dy));
  +  
  +  dx1 = (dx * space) / l;
  +  dy1 = (dy * space) / l;
  +  
  +  d = 0;
  +  xa = x1; ya = y1;
  +  while(d < l) {
  +    
  +    fprintf(fp,"[%d %d] ",
  +	    (int)xa, (int)ya);
  +    d = d + space;
  +    xa = xa + dx1;
  +    ya = ya + dy1;
  +  }
  +  
  +  fprintf(fp,"] %d dashed\n",line_width);
  +  
  +}
  +
  +
  +/*! \brief Print a dashed line to Postscript document.
  + *  \par Function Description
  + *  This function prints a line when a dashed line type is required.
  + *  The line is defined by the coordinates of its two ends in
  + *  (<B>x1</B>,<B>y1</B>) and (<B>x2</B>,<B>y2</B>).
  + *  The postscript file is defined by the file pointer <B>fp</B>.
  + *
  + *  A negative value for <B>space</B> or <B>length</B> leads to an
  + *  endless loop.
  + *
  + *  All dimensions are in mils.
  + *
  + *  The function sets the color in which the line will be printed and
  + *  the width of the line - that is the width of the dashes.
  + *
  + *  \param [in] w_current     The TOPLEVEL object.
  + *  \param [in] fp            FILE pointer to Postscript document.
  + *  \param [in] x1            Upper x coordinate.
  + *  \param [in] y1            Upper y coordinate.
  + *  \param [in] x2            Lower x coordinate.
  + *  \param [in] y2            Lower y coordinate.
  + *  \param [in] color         Line color.
  + *  \param [in] line_width    Width of line.
  + *  \param [in] length        Length of a dash.
  + *  \param [in] space         Space between dashes.
  + *  \param [in] origin_x      Page x coordinate to place line OBJECT.
  + *  \param [in] origin_y      Page y coordinate to place line OBJECT.
  + */
  +void o_line_print_dashed(TOPLEVEL *w_current, FILE *fp,
  +			 int x1, int y1, int x2, int y2,
  +			 int color,
  +			 int line_width, int length, int space,
  +			 int origin_x, int origin_y)
  +{
  +  double dx, dy, l, d;
  +  double dx1, dy1, dx2, dy2;
  +  double xa, ya, xb, yb;
  +  
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +  
  +  /* the dashed line function takes an array of start-finish pairs
  +   * output the beginnings of the array now
  +   */
  +  fprintf(fp,"[");
  +  
  +  /*
  +   * Depending on the slope of the line the <B>length</B> (resp. <B>space</B>)
  +   * parameter is projected on each of the two directions x and y
  +   * resulting in <B>dx1</B> and <B>dy1</B> (resp. <B>dx2</B> and <B>dy2</B>).
  +   * Starting from one end and incrementing alternatively by <B>space</B>
  +   * and <B>length</B> the dashes are printed.
  +   *
  +   * It prints as many dashes of length <B>length</B> as possible.
  +   */
  +  dx = (double) (x2 - x1);
  +  dy = (double) (y2 - y1);
  +  l = sqrt((dx * dx) + (dy * dy));
  +  
  +  dx1 = (dx * length) / l;
  +  dy1 = (dy * length) / l;
  +  
  +  dx2 = (dx * space) / l;
  +  dy2 = (dy * space) / l;
  +  
  +  d = 0;
  +  xa = x1; ya = y1;
  +  while((d + length + space) < l) {
  +    d = d + length;
  +    xb = xa + dx1;
  +    yb = ya + dy1;
  +    
  +    fprintf(fp, "[%d %d %d %d] ", 
  +	    (int) xa, (int) ya,
  +	    (int) xb, (int) yb);
  +    
  +    d = d + space;
  +    xa = xb + dx2;
  +    ya = yb + dy2;
  +  }
  +  /*
  +   * When the above condition is no more satisfied, then it is not possible
  +   * to print a dash of length <B>length</B>. However it may be possible to
  +   * print the complete dash or a shorter one.
  +   */
  +
  +  if((d + length) < l) {
  +    d = d + length;
  +    xb = xa + dx1;
  +    yb = ya + dy1;
  +  } else {
  +    xb = x2;
  +    yb = y2;
  +  }
  +	
  +  fprintf(fp, "[%d %d %d %d] ", 
  +	  (int) xa, (int) ya,
  +	  (int) xb, (int) yb);
  +
  +  fprintf(fp,"] %d dashed\n", line_width);
  +}
  +
  +
  +/*! \brief Print a centered line type line to Postscript document.
  + *  \par Function Description
  + *  This function prints a line when a centered line type is required.
  + *  The line is defined by the coordinates of its two ends in
  + *  (<B>x1</B>,<B>y1</B>) and (<B>x2</B>,<B>y2</B>).
  + *  The Postscript document is defined by the file pointer <B>fp</B>.
  + *
  + *  A negative value for <B>space</B> or <B>length</B> leads to an
  + *  endless loop.
  + *
  + *  All dimensions are in mils.
  + *
  + *  The function sets the color in which the line will be printed and the
  + *  width of the line - that is the width of the dashes and the diameter
  + *  of the dots.
  + *
  + *  \param [in] w_current     The TOPLEVEL object.
  + *  \param [in] fp            FILE pointer to Postscript document.
  + *  \param [in] x1            Upper x coordinate.
  + *  \param [in] y1            Upper y coordinate.
  + *  \param [in] x2            Lower x coordinate.
  + *  \param [in] y2            Lower y coordinate.
  + *  \param [in] color         Line color.
  + *  \param [in] line_width    Width of line.
  + *  \param [in] length        Length of a dash.
  + *  \param [in] space         Space between dashes.
  + *  \param [in] origin_x      Page x coordinate to place line OBJECT.
  + *  \param [in] origin_y      Page y coordinate to place line OBJECT.
  + */
  +void o_line_print_center(TOPLEVEL *w_current, FILE *fp,
  +			 int x1, int y1, int x2, int y2,
  +			 int color,
  +			 int line_width, int length, int space,
  +			 int origin_x, int origin_y)
  +{
  +  double dx, dy, l, d;
  +  double dx1, dy1, dx2, dy2;
  +  double xa, ya, xb, yb;
  +  
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +  
  +  fprintf(fp, "[");
  +
  +  /*
  +   * Depending on the slope of the line the <B>length</B> (resp. <B>space</B>)
  +   * parameter is projected on each of the two directions x and y resulting
  +   * in <B>dx1</B> and <B>dy1</B> (resp. <B>dx2</B> and <B>dy2</B>).
  +   * Starting from one end and incrementing alternatively by <B>space</B>
  +   * and <B>length</B> the dashes and dots are printed.
  +   *
  +   * It prints as many sets of dash and dot as possible.
  +   */
  +  dx = (double) (x2 - x1);
  +  dy = (double) (y2 - y1);
  +  l = sqrt((dx * dx) + (dy * dy));
  +  
  +  dx1 = (dx * length) / l;
  +  dy1 = (dy * length) / l;
  +  
  +  dx2 = (dx * space) / l;
  +  dy2 = (dy * space) / l;
  +  
  +  d = 0;
  +  xa = x1; ya = y1;
  +  while((d + length + 2 * space) < l) {
  +    d = d + length;
  +    xb = xa + dx1;
  +    yb = ya + dy1;
  +    
  +    fprintf(fp, "[%d %d %d %d] ", 
  +	    (int) xa, (int) ya,
  +	    (int) xb, (int) yb);
  +    
  +    d = d + space;
  +    xa = xb + dx2;
  +    ya = yb + dy2;
  +    
  +    fprintf(fp,"[%d %d] ",(int) xa, (int) ya);
  +    
  +    d = d + space;
  +    xa = xa + dx2;
  +    ya = ya + dy2;
  +  }
  +  /*
  +   * When the above condition is no more satisfied, then it is not possible
  +   * to print a dash of length <B>length</B>.
  +   * However two cases are possible :
  +   * <DL>
  +   *   <DT>*</DT><DD>it is possible to print the dash and the dot.
  +   *   <DT>*</DT><DD>it is possible to print the dash or a part
  +   *                 of the original dash.
  +   * </DL>
  +   */
  +
  +  if((d + length + space) < l) {
  +    d = d + length;
  +    xb = xa + dx1;
  +    yb = ya + dy1;
  +    
  +    fprintf(fp, "[%d %d %d %d] ", 
  +	    (int) xa, (int) ya,
  +	    (int) xb, (int) yb);
  +    
  +    d = d + space;
  +    xa = xb + dx2;
  +    ya = yb + dy2;
  +    
  +    fprintf(fp,"[%d %d] ",(int) xa, (int) ya);
  +    
  +  } else {
  +    if(d + length < l) {
  +      xb = xa + dx1;
  +      yb = ya + dy1;
  +    } else {
  +      xb = x2;
  +      yb = y2;
  +    }
  +    
  +    fprintf(fp, "[%d %d %d %d] ", 
  +	    (int) xa, (int) ya,
  +	    (int) xb, (int) yb);
  +    
  +  }
  +  
  +  fprintf(fp,"] %d dashed\n", line_width);
  +
  +  /*
  +   * A dot is represented by a filled circle. Position of the circle is
  +   * (<B>xa</B>, <B>ya</B>) and its radius by the <B>line_width</B> parameter.
  +   */
  +}
  +
  +/*! \brief Print a phantom line type line to Postscript document.
  + *  \par Function Description
  + *  This function prints a line when a phantom line type is required.
  + *  The line is defined by the coordinates of its two ends in 
  + *  (<B>x1</B>,<B>y1</B>) and (<B>x2</B>,<B>y2</B>).
  + *  The Postscript document is defined by the file pointer <B>fp</B>.
  + *
  + *  A negative value for <B>space</B> or <B>length</B> leads to an
  + *  endless loop.
  + *
  + *  All dimensions are in mils.
  + *
  + *  The function sets the color in which the line will be printed and the
  + *  width of the line - that is the width of the dashes and the diameter
  + *  of the dots.
  + *
  + *  \param [in] w_current     The TOPLEVEL object.
  + *  \param [in] fp            FILE pointer to Postscript document.
  + *  \param [in] x1            Upper x coordinate.
  + *  \param [in] y1            Upper y coordinate.
  + *  \param [in] x2            Lower x coordinate.
  + *  \param [in] y2            Lower y coordinate.
  + *  \param [in] color         Line color.
  + *  \param [in] line_width    Width of line.
  + *  \param [in] length        Length of a dash.
  + *  \param [in] space         Space between dashes.
  + *  \param [in] origin_x      Page x coordinate to place line OBJECT.
  + *  \param [in] origin_y      Page y coordinate to place line OBJECT.
  + */
  +void o_line_print_phantom(TOPLEVEL *w_current, FILE *fp,
  +			  int x1, int y1, int x2, int y2,
  +			  int color,
  +			  int line_width, int length, int space,
  +			  int origin_x, int origin_y)
  +{
  +  double dx, dy, l, d;
  +  double dx1, dy1, dx2, dy2;
  +  double xa, ya, xb, yb;
  +  
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, color);
  +  }
  +  
  +  fprintf(fp,"[");
  +
  +  /*
  +   * Depending on the slope of the line the <B>length</B> (resp. <B>space</B>)
  +   * parameter is projected on each of the two directions x and y resulting
  +   * in <B>dx1</B> and <B>dy1</B> (resp. <B>dx2</B> and <B>dy2</B>).
  +   * Starting from one end and incrementing alternatively by <B>space</B>
  +   * and <B>length</B> the dashes and dots are printed.
  +   *
  +   * It prints as many sets of dash-dot-dot as possible.
  +   */
  +  dx = (double) (x2 - x1);
  +  dy = (double) (y2 - y1);
  +  l = sqrt((dx * dx) + (dy * dy));
  +  
  +  dx1 = (dx * length) / l;
  +  dy1 = (dy * length) / l;
  +  
  +  dx2 = (dx * space) / l;
  +  dy2 = (dy * space) / l;
  +  
  +  d = 0;
  +  xa = x1; ya = y1;
  +  while((d + length + 3 * space) < l) {
  +    d = d + length;
  +    xb = xa + dx1;
  +    yb = ya + dy1;
  +    
  +    fprintf(fp,"[%d %d %d %d] ",
  +	    (int) xa, (int)ya,
  +	    (int) xb, (int)yb);
  +    
  +    d = d + space;
  +    xa = xb + dx2;
  +    ya = yb + dy2;
  +    
  +    fprintf(fp,"[%d %d] ",(int) xa, (int) ya);
  +    
  +    d = d + space;
  +    xa = xa + dx2;
  +    ya = ya + dy2;
  +    
  +    fprintf(fp,"[%d %d] ",(int) xa, (int) ya);
  +    
  +    d = d + space;
  +    xa = xa + dx2;
  +    ya = ya + dy2;
  +  }
  +  /*
  +   * When the above condition is no more satisfied, then it is not possible
  +   * to print a complete set of dash-dot-dot.
  +   * However three cases are possible :
  +   * <DL>
  +   *   <DT>*</DT><DD>it is possible to print a dash and a dot and a dot.
  +   *   <DT>*</DT><DD>it is possible to print a dash and a dot.
  +   *   <DT>*</DT><DD>it is possible to print the dash or a part
  +   *                 of the original dash.
  +   * </DL>
  +   */
  +
  +  if((d + length + 2 * space) < l) {
  +    d = d + length;
  +    xb = xa + dx1;
  +    yb = ya + dy1;
  +    
  +    fprintf(fp,"[%d %d %d %d] ",
  +	    (int) xa, (int)ya,
  +	    (int) xb, (int)yb);
  +    
  +    d = d + space;
  +    xa = xb + dx2;
  +    ya = yb + dy2;
  +    
  +    fprintf(fp,"[%d %d] ",(int) xa, (int)ya);
  +    
  +    d = d + space;
  +    xa = xb + dx2;
  +    ya = yb + dy2;
  +    
  +    fprintf(fp,"[%d %d] ",(int) xa, (int)ya);
  +    
  +  } else {
  +    if(d + length + space < l) {
  +      d = d + length;
  +      xb = xa + dx1;
  +      yb = ya + dy1;
  +      
  +      fprintf(fp,"[%d %d %d %d] ",
  +	      (int) xa, (int)ya,
  +	      (int) xb, (int)yb);
  +      
  +      d = d + space;
  +      xa = xb + dx2;
  +      ya = yb + dy2;
  +      
  +      fprintf(fp,"[%d %d] ",(int) xa, (int)ya);
  +      
  +    } else {
  +      if(d + length < l) {
  +	xb = xa + dx1;
  +	yb = ya + dy1;
  +      } else {
  +	xb = x2;
  +	yb = y2;
  +      }
  +      
  +      fprintf(fp,"[%d %d %d %d] ",
  +	      (int) xa, (int)ya,
  +	      (int) xb, (int)yb);
  +      
  +    }
  +  }
  +  
  +  fprintf(fp,"] %d dashed\n", line_width);
  +}
  +
  +#if 0 /* original way of printing line, no longer used */
  +/*! \brief Print line to Postscript document using old method.
  + *  \par Function Description
  + *  This function is the old function to print a line.
  + *  It does not handle line type.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] fp         FILE pointer to Postscript document.
  + *  \param [in] o_current  Line object to print.
  + *  \param [in] origin_x   Page x coordinate to place line OBJECT.
  + *  \param [in] origin_y   Page x coordinate to place line OBJECT.
  + */
  +void o_line_print_old(TOPLEVEL *w_current, FILE *fp, OBJECT *o_current, 
  +		      int origin_x, int origin_y)
  +{
  +  if (o_current == NULL) {
  +    printf("got null in o_line_print\n");
  +    return;
  +  }
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, o_current->color);
  +  }
  +
  +  fprintf(fp, "newpath\n");
  +
  +  fprintf(fp, "%d mils %d mils moveto\n",
  +          o_current->line_points->x1-origin_x,
  +          o_current->line_points->y1-origin_y);
  +  fprintf(fp, "%d mils %d mils lineto\n", 
  +          o_current->line_points->x2-origin_x,
  +          o_current->line_points->y2-origin_y);
  +  fprintf(fp, "stroke\n");
  +
  +}
  +#endif
  +
  +/*! \brief Draw a line in an image.
  + *  \par Function Description
  + *  This function draws a line in an image with the libgdgeda function
  + *  #gdImageLine().
  + *
  + *  \param [in] w_current   The TOPLEVEL object.
  + *  \param [in] o_current   Line OBJECT to draw.
  + *  \param [in] origin_x    (unused).
  + *  \param [in] origin_y    (unused).
  + *  \param [in] color_mode  Draw line in color if TRUE, B/W otherwise.
  + */
  +
  +void o_line_image_write(TOPLEVEL *w_current, OBJECT *o_current, 
  +			int origin_x, int origin_y, int color_mode)
  +{
  +  int color;
  +
  +  if (o_current == NULL) {
  +    printf("got null in o_line_print\n");
  +    return;
  +  }
  +
  +  if (color_mode == TRUE) {
  +    color = o_image_geda2gd_color(o_current->color);
  +  } else {
  +    color = image_black;
  +  }
  +
  +  /* assumes screen coords are already calculated correctly */
  +#ifdef HAS_LIBGDGEDA
  +
  +  gdImageSetThickness(current_im_ptr, SCREENabs(w_current, 
  +					        o_current->line_width));
  +
  +  gdImageLine(current_im_ptr, 
  +              o_current->line->screen_x[0],
  +              o_current->line->screen_y[0],
  +              o_current->line->screen_x[1],
  +              o_current->line->screen_y[1], 
  +              color);
  +#endif
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x_scale
  + *  \param [in] y_scale
  + *  \param [in] object
  + */
  +void o_line_scale_world(TOPLEVEL *w_current, int x_scale, int y_scale,
  +			OBJECT *object)
  +{
  +  if (object == NULL) printf("lsw NO!\n");
  +
  +  /* scale the line world coords */
  +  object->line->x[0] = object->line->x[0] * x_scale;
  +  object->line->y[0] = object->line->y[0] * y_scale;
  +  object->line->x[1] = object->line->x[1] * x_scale;
  +  object->line->y[1] = object->line->y[1] * y_scale;
  +
  +  /* update screen coords */
  +  o_line_recalc(w_current, object);
  +  
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] line
  + *  \param [in] x1
  + *  \param [in] y1
  + *  \param [in] x2
  + *  \param [in] y2
  + *  \return int
  + */
  +int o_line_visible(TOPLEVEL *w_current, LINE *line, 
  +		   int *x1, int *y1, int *x2, int *y2)
  +{
  +  int visible=0;
  +
  +
  +  /* don't do clipping if this is false */
  +  if (!w_current->object_clipping) {
  +    return(TRUE);
  +  }
  +
  +  *x1 = line->screen_x[0];
  +  *y1 = line->screen_y[0];
  +  *x2 = line->screen_x[1];
  +  *y2 = line->screen_y[1];
  +
  +  visible = SCREENclip_change(w_current, x1, y1, x2, y2);
  +
  +  return(visible);
  +}
  +
  +/*! \brief
  + *  \par Function Description
  + *
  + *  \param [in] object
  + *  \return double
  + */
  +double o_line_length(OBJECT *object)
  +{
  +  double length;
  +  double dx, dy;
  +  
  +  if (!object->line) {
  +    return 0.0;
  +  }
  +
  +  dx = object->line->x[0]-object->line->x[1];
  +  dy = object->line->y[0]-object->line->y[1];
  +
  +  length = sqrt((dx*dx) + (dy*dy));
  +                
  +  return(length);
  +}
  
  
  
  1.18      +340 -285  eda/geda/gaf/libgeda/src/o_list.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_list.c
  ===================================================================
  RCS file: o_list.c
  diff -N o_list.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_list.c	5 Jul 2006 03:13:38 -0000	1.18
  @@ -0,0 +1,438 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! global which is used in o_list_copy_all */
  +extern int global_sid;
  +
  +/*! \todo Finish documentation!!!!
  + *  \brief
  + *  \par Function Description
  + *  returns head !!!!!!!!!!!!!!!!!!!
  + *  look at above.. this returns what was passed in!!!!
  + *  copies selected to list_head (!! returns new list)
  + *  flag is either NORMAL_FLAG or SELECTION_FLAG
  + *
  + *  \param [in]  w_current   The TOPLEVEL object.
  + *  \param [in]  list_head
  + *  \param [in]  selected
  + *  \param [in]  flag
  + *  \param [out] return_end  
  + *  \return OBJECT pointer.
  + */
  +OBJECT *o_list_copy_to(TOPLEVEL *w_current, OBJECT *list_head,
  +		       OBJECT *selected, int flag, OBJECT **return_end)
  +{
  +  OBJECT *end=NULL;
  +
  +  /* are we adding a selection or the real object list */
  +  w_current->ADDING_SEL = flag;
  +
  +  end = (OBJECT *) return_tail(list_head);
  +
  +  switch(selected->type) {
  +
  +    case(OBJ_LINE):
  +      /* do we do anything with the return value) ? */
  +      end = (OBJECT *) o_line_copy(w_current, end, selected);	
  +      break;
  +
  +    case(OBJ_NET):
  +      end = (OBJECT *) o_net_copy(w_current, end, selected);	
  +      break;
  +
  +    case(OBJ_BUS):
  +      end = (OBJECT *) o_bus_copy(w_current, end, selected);	
  +      break;
  +
  +    case(OBJ_BOX):
  +      end = (OBJECT *) o_box_copy(w_current, end, selected);	
  +      break;
  +
  +    case(OBJ_PICTURE):
  +      end = (OBJECT *) o_picture_copy(w_current, end, selected);	
  +      break;
  +
  +    case(OBJ_CIRCLE):
  +      end = (OBJECT *) o_circle_copy(w_current, end, selected);	
  +      break;
  +
  +    case(OBJ_COMPLEX):
  +    case(OBJ_PLACEHOLDER):
  +      if (selected->complex_clib && 
  +          strncmp(selected->complex_clib, "EMBEDDED", 8) == 0) {
  +        end = (OBJECT *) o_complex_copy_embedded(w_current, end, selected);	
  +      } else {
  +        end = (OBJECT *) o_complex_copy(w_current, end, selected);	
  +      }
  +      break;
  +
  +    case(OBJ_TEXT):
  +      end = (OBJECT *) o_text_copy(w_current, end, selected);	
  +      if (selected->attribute && 
  +          selected->visibility == INVISIBLE) {
  +        end->visibility = INVISIBLE;
  +      }
  +      break;
  +
  +    case(OBJ_PIN):
  +      end = (OBJECT *) o_pin_copy(w_current, end, selected);	
  +      break;
  +
  +    case(OBJ_ARC):
  +      end = (OBJECT *) o_arc_copy(w_current, end, selected);	
  +      break;
  +  }
  +
  +  if (list_head == NULL)
  +  list_head = end;
  +
  +  /* make sure sid is the same! */
  +  if (selected) {
  +    end->sid = selected->sid;
  +  }
  +
  +  /* I don't think this is a good idea at all */
  +  /* w_current->ADDING_SEL = 0; */
  +        
  +  if (return_end) {
  +    *return_end = end;	
  +  }
  +
  +  return(list_head);
  +}
  +
  +/*! \todo Finish function description!!!
  + *  \brief
  + *  \par Function Description
  + *  you need to pass in a head_node for dest_list_head
  + *  flag is either NORMAL_FLAG or SELECTION_FLAG
  + *
  + *  \param [in] w_current       The TOPLEVEL object.
  + *  \param [in] src_list_head   
  + *  \param [in] dest_list_head  
  + *  \param [in] flag
  + *  \return OBJECT pointer.
  + */
  +OBJECT *o_list_copy_all(TOPLEVEL *w_current, OBJECT *src_list_head,
  +			OBJECT *dest_list_head, int flag)
  +{
  +  OBJECT *src;
  +  OBJECT *dest;
  +  OBJECT *temp_parent=NULL;
  +  int adding_sel_save;
  +
  +  src = src_list_head;
  +  dest = dest_list_head;
  +  temp_parent = w_current->page_current->object_parent;
  +  w_current->page_current->object_parent = dest_list_head;
  +
  +  if (dest == NULL) {
  +    w_current->page_current->object_parent = temp_parent;
  +    return(NULL);
  +  }
  +
  +  if (src == NULL) {
  +    w_current->page_current->object_parent = temp_parent;
  +    return(NULL);
  +  }
  +
  +  adding_sel_save = w_current->ADDING_SEL;
  +
  +  /* first do all NON text items */
  +  while(src != NULL) {
  +
  +    if (src->type != OBJ_TEXT) {
  +      dest->next = o_list_copy_to(w_current, NULL, src, flag,
  +                                  NULL);
  +		
  +      dest->next->prev = dest;
  +      dest = dest->next;
  +      dest->sid = global_sid++;
  +    }
  +
  +    src = src->next;
  +  }
  +
  +  src = src_list_head;
  +  /*dest = dest_list_head; out since we want to add to the end */
  +
  +  if (dest == NULL) {
  +    w_current->page_current->object_parent = temp_parent;
  +    return(NULL);
  +  }
  +
  +  if (src == NULL) {
  +    w_current->page_current->object_parent = temp_parent;
  +    return(NULL);
  +  }
  +
  +  /* then do all text items */
  +  while(src != NULL) {
  +
  +    if (src->type == OBJ_TEXT) {
  +      dest->next = o_list_copy_to(w_current, NULL, src, flag,
  +                                  NULL);
  +		
  +      dest->next->prev = dest;
  +      dest = dest->next;
  +      dest->sid = global_sid++;
  +	
  +      if (src->attached_to /*&& !w_current->ADDING_SEL*/) {
  +        if (src->attached_to->copied_to) {
  +          o_attrib_attach(w_current,
  +                          w_current->page_current->object_parent,
  +                          dest, src->attached_to->copied_to);     
  +
  +                                /* satisfied copy request */
  +          src->attached_to->copied_to = NULL;
  +        } 
  +      }
  +    }
  +
  +    src = src->next;
  +  }
  +
  +  w_current->ADDING_SEL = adding_sel_save;
  +  w_current->page_current->object_parent = temp_parent;
  +
  +  return(dest);
  +}
  +
  +/*! \todo Finish function description!!!
  + *  \brief
  + *  \par Function Description
  + *  you need to pass in a head_node for dest_list_head
  + *  flag is either NORMAL_FLAG or SELECTION_FLAG
  + *  this function copies the objects in the src SELECTION list
  + *  to the OBJECT list in dest_list_head
  + *  this routine assumes that objects in src_list_head are selected
  + *  objects are unselected before they are copied and then reselected
  + *  this is necessary to preserve the color info
  + *
  + *  \param [in] w_current       The TOPLEVEL object.
  + *  \param [in] src_list_head   
  + *  \param [in] dest_list_head  
  + *  \param [in] flag
  + *  \return OBJECT pointer.
  + */
  +OBJECT *o_list_copy_all_selection2(TOPLEVEL *w_current,
  +				   SELECTION *src_list_head, 
  +				   OBJECT *dest_list_head, int flag)
  +{
  +  SELECTION *src;
  +  OBJECT *object;
  +  OBJECT *dest;
  +  OBJECT *temp_parent=NULL;
  +  int adding_sel_save;
  +
  +  src = src_list_head;
  +  dest = dest_list_head;
  +
  +  temp_parent = w_current->page_current->object_parent;
  +  w_current->page_current->object_parent = dest_list_head;
  +
  +  if (dest == NULL) {
  +    w_current->page_current->object_parent = temp_parent;
  +    return(NULL);
  +  }
  +
  +  if (src == NULL) {
  +    w_current->page_current->object_parent = temp_parent;
  +    return(NULL);
  +  }
  +
  +  adding_sel_save = w_current->ADDING_SEL;
  +
  +  /* first do all NON text items */
  +  while(src != NULL) {
  +
  +    object = src->selected_object;
  +
  +    /* unselect the object before the copy */
  +    o_selection_unselect(object);	
  +
  +    if (object->type != OBJ_TEXT && object->type != OBJ_HEAD) {
  +      dest->next = o_list_copy_to(w_current, NULL, object, 
  +                                  flag, NULL);
  +      dest->next->prev = dest;
  +      dest = dest->next;
  +      dest->sid = global_sid++;
  +    }
  +
  +    /* reselect it */
  +    o_selection_select(object, SELECT_COLOR);
  +
  +    src = src->next;
  +  }
  +
  +  src = src_list_head;
  +  /*dest = dest_list_head; out since we want to add to the end */
  +
  +  if (dest == NULL) {
  +    w_current->page_current->object_parent = temp_parent;
  +    return(NULL);
  +  }
  +
  +  if (src == NULL) {
  +    w_current->page_current->object_parent = temp_parent;
  +    return(NULL);
  +  }
  +
  +  /* then do all text items */
  +  while(src != NULL) {
  +
  +    object = src->selected_object;
  +
  +    /* unselect the object before the copy */
  +    o_selection_unselect(object);	
  +
  +    if (object->type == OBJ_TEXT) {
  +      dest->next = o_list_copy_to(w_current, NULL, object, 
  +                                  flag, NULL);
  +	
  +      dest->next->prev = dest;
  +      dest = dest->next;
  +      dest->sid = global_sid++;
  +
  +      if (object->attached_to /*&& !w_current->ADDING_SEL*/) {
  +        if (object->attached_to->copied_to) {
  +          o_attrib_attach(w_current,
  +                          w_current->page_current->object_parent,
  +                          dest, object->attached_to->copied_to);     
  +                                /* satisfied copy request */
  +          object->attached_to->copied_to = NULL;
  +        } 
  +      }
  +    }
  +
  +    /* reselect it */
  +    o_selection_select(object, SELECT_COLOR);
  +
  +    src = src->next;
  +  }
  +
  +  w_current->ADDING_SEL = adding_sel_save;
  +  w_current->page_current->object_parent = temp_parent;
  +
  +  return(dest);
  +}
  +
  +/*! \todo Finish function description!!!
  + *  \brief
  + *  \par Function Description
  + *  returns entry in the list
  + *
  + *  \param [in] list
  + *  \param [in] current
  + *  \return OBJECT pointer.
  + */
  +OBJECT *o_list_search(OBJECT *list, OBJECT *current)
  +{
  +  OBJECT *o_current;
  +
  +  o_current = list ;
  +
  +  if (current == NULL) {
  +    return(NULL);
  +  }
  +
  +  if (list == NULL) {
  +    return(NULL);
  +  }
  +
  +  while(o_current != NULL) {
  +    /* look for uniq sid */
  +    if (current->sid == o_current->sid) {
  +      return(o_current);
  +    }
  +    o_current = o_current->next;
  +  }
  +  return(NULL);
  +}
  +
  +/*! \todo Finish function description!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] list
  + *  \param [in] delete
  + */
  +void o_list_delete(TOPLEVEL *w_current, OBJECT *list, OBJECT *delete)
  +{
  +  OBJECT *find;
  +
  +  find = o_list_search(list, delete);
  +
  +  if (find != NULL)
  +  s_delete(w_current, find);
  +
  +}
  +
  +/*! \todo Finish function description!!!
  + *  \brief
  + *  \par Function Description
  + *  assuming list is head
  + *  head will NOT be deleted
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] list
  + */
  +void o_list_delete_rest(TOPLEVEL *w_current, OBJECT *list)
  +{
  +  OBJECT *o_current=NULL;
  +  OBJECT *o_prev=NULL;
  +	
  +  o_current = (OBJECT *) return_tail(list);
  +
  +  w_current->REMOVING_SEL = 1;
  +  /* remove list backwards */
  +  while(o_current != NULL) {
  +    if (o_current->type != OBJ_HEAD) {
  +      o_prev = o_current->prev;
  +      s_delete(w_current, o_current);	
  +      o_current = o_prev;
  +    } else {
  +      o_current->next = NULL; /* set sel_head->next to be empty */
  +      o_current = NULL;
  +    }
  +  }
  +  w_current->REMOVING_SEL = 0;
  +}
  
  
  
  1.29      +684 -569  eda/geda/gaf/libgeda/src/o_net_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_net_basic.c
  ===================================================================
  RCS file: o_net_basic.c
  diff -N o_net_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_net_basic.c	5 Jul 2006 03:13:38 -0000	1.29
  @@ -0,0 +1,1012 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#ifdef HAS_LIBGDGEDA
  +#include <gdgeda/gd.h>
  +#endif
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +#include "funcs.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  line
  + *  \param [out] left
  + *  \param [out] top
  + *  \param [out] right
  + *  \param [out] bottom
  + */
  +void get_net_bounds(TOPLEVEL *w_current, LINE *line, int *left, int *top,
  +		    int *right, int *bottom)
  +{
  +  *left = w_current->width;
  +  *top = w_current->height;
  +  *right = 0;
  +  *bottom = 0;
  +
  +  if (line->screen_x[0] < *left)
  +  *left = line->screen_x[0];
  +  if (line->screen_x[0] > *right)
  +  *right = line->screen_x[0];
  +  if (line->screen_y[0] < *top)
  +  *top = line->screen_y[0];
  +  if (line->screen_y[0] > *bottom)
  +  *bottom = line->screen_y[0];
  +
  +  if (line->screen_x[1] < *left)
  +  *left = line->screen_x[1];
  +  if (line->screen_x[1] > *right)
  +  *right = line->screen_x[1];
  +  if (line->screen_y[1] < *top)
  +  *top = line->screen_y[1];
  +  if (line->screen_y[1] > *bottom)
  +  *bottom = line->screen_y[1];
  +
  +  *left = *left - 4;
  +  *top = *top - 4;
  +
  +  *right = *right + 4;
  +  *bottom = *bottom + 4;
  +}
  +
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  line
  + *  \param [out] left
  + *  \param [out] top
  + *  \param [out] right
  + *  \param [out] bottom
  + */
  +void world_get_net_bounds(TOPLEVEL *w_current, LINE *line, int *left,
  +			  int *top, int *right, int *bottom)
  +{
  +  *left = w_current->init_right;
  +  *top = w_current->init_bottom;
  +  *right = 0;
  +  *bottom = 0;
  +
  +  if (line->x[0] < *left)
  +  *left = line->x[0];
  +  if (line->x[0] > *right)
  +  *right = line->x[0];
  +  if (line->y[0] < *top)
  +  *top = line->y[0];
  +  if (line->y[0] > *bottom)
  +  *bottom = line->y[0];
  +
  +  if (line->x[1] < *left)
  +  *left = line->x[1];
  +  if (line->x[1] > *right)
  +  *right = line->x[1];
  +  if (line->y[1] < *top)
  +  *top = line->y[1];
  +  if (line->y[1] > *bottom)
  +  *bottom = line->y[1];
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \param [in]     w_current    The TOPLEVEL object.
  + *  \param [in,out] object_list
  + *  \param [in]     type
  + *  \param [in]     color
  + *  \param [in]     x1
  + *  \param [in]     y1
  + *  \param [in]     x2
  + *  \param [in]     y2
  + *  \return OBJECT *
  + */
  +OBJECT *o_net_add(TOPLEVEL *w_current, OBJECT *object_list, char type,
  +		  int color, int x1, int y1, int x2, int y2)
  +{
  +  int screen_x, screen_y;
  +  int left, right, top, bottom;
  +  OBJECT *new_node;
  +
  +  new_node = s_basic_init_object("net");
  +  new_node->type = type;
  +  new_node->color = color;
  +
  +  new_node->line = (LINE *) malloc(sizeof(LINE));
  +  /* check for null */
  +
  +  new_node->line->x[0] = x1;
  +  new_node->line->y[0] = y1;
  +  new_node->line->x[1] = x2;
  +  new_node->line->y[1] = y2;
  +
  +  WORLDtoSCREEN(w_current,
  +                new_node->line->x[0], new_node->line->y[0],
  +                &screen_x, &screen_y);
  +
  +  new_node->line->screen_x[0] = screen_x;
  +  new_node->line->screen_y[0] = screen_y;
  +
  +  WORLDtoSCREEN(w_current,
  +                new_node->line->x[1], new_node->line->y[1],
  +                &screen_x, &screen_y);
  +
  +  new_node->line->screen_x[1] = screen_x;
  +  new_node->line->screen_y[1] = screen_y;
  +
  +  get_net_bounds(w_current, new_node->line, &left, &top, &right,
  +                 &bottom);
  +
  +  new_node->left = left;
  +  new_node->top = top;
  +  new_node->right = right;
  +  new_node->bottom = bottom;
  +
  +  /* \todo questionable cast */
  +  new_node->draw_func = (void *) net_draw_func;
  +  /* \todo questionable cast */
  +  new_node->sel_func = (void *) select_func;
  +
  +  object_list = (OBJECT *) s_basic_link_object(new_node, object_list);
  +
  +
  +  if (!w_current->ADDING_SEL) {
  +    s_tile_add_object(w_current, object_list,
  +		      new_node->line->x[0], new_node->line->y[0],
  +		      new_node->line->x[1], new_node->line->y[1]);
  +    s_conn_update_object(w_current, object_list);
  +  }
  +
  +  return (object_list);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *
  + */
  +void o_net_recalc(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int screen_x1, screen_y1;
  +  int screen_x2, screen_y2;
  +  int left, right, top, bottom;
  +
  +  if (o_current == NULL) {
  +    return;
  +  }
  +
  +  if (o_current->line == NULL) {
  +    return;
  +  }
  +
  +  WORLDtoSCREEN(w_current, o_current->line->x[0],
  +                o_current->line->y[0], &screen_x1, &screen_y1);
  +
  +  o_current->line->screen_x[0] = screen_x1;
  +  o_current->line->screen_y[0] = screen_y1;
  +
  +  WORLDtoSCREEN(w_current, o_current->line->x[1],
  +                o_current->line->y[1], &screen_x2, &screen_y2);
  +
  +  o_current->line->screen_x[1] = screen_x2;
  +  o_current->line->screen_y[1] = screen_y2;
  +
  +  get_net_bounds(w_current, o_current->line, &left, &top, &right,
  +                 &bottom);
  +
  +  o_current->left = left;
  +  o_current->top = top;
  +  o_current->right = right;
  +  o_current->bottom = bottom;
  +
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *
  + */
  +OBJECT *o_net_read(TOPLEVEL *w_current, OBJECT *object_list, char buf[],
  +		   unsigned int release_ver, unsigned int fileformat_ver)
  +{
  +  char type;
  +  int x1, y1;
  +  int x2, y2;
  +  int d_x1, d_y1;
  +  int d_x2, d_y2;
  +  int color;
  +
  +  sscanf(buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color);
  +  d_x1 = x1;
  +  d_y1 = y1;
  +  d_x2 = x2;
  +  d_y2 = y2;
  +
  +  if (x1 == x2 && y1 == y2) {
  +    fprintf(stderr, "Found a zero length net [ %c %d %d %d %d %d ]\n",
  +            type, x1, y1, x2, y2, color);
  +    s_log_message("Found a zero length net [ %c %d %d %d %d %d ]\n",
  +                  type, x1, y1, x2, y2, color);
  +  }
  +
  +
  +  if (w_current->override_net_color != -1) {
  +    color = w_current->override_net_color;
  +  }
  +
  +  if (color < 0 || color > MAX_COLORS) {
  +    fprintf(stderr, "Found an invalid color [ %s ]\n", buf);
  +    s_log_message("Found an invalid color [ %s ]\n", buf);
  +    s_log_message("Setting color to WHITE\n");
  +    color = WHITE;
  +  }
  +
  +  object_list =
  +  o_net_add(w_current, object_list, type, color, d_x1, d_y1, d_x2,
  +            d_y2);
  +  return (object_list);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *
  + */
  +char *o_net_save(OBJECT *object)
  +{
  +  int x1, x2, y1, y2;
  +  int color;
  +  char *buf;
  +
  +  x1 = object->line->x[0];
  +  y1 = object->line->y[0];
  +  x2 = object->line->x[1];
  +  y2 = object->line->y[1];
  +
  +  /* Use the right color */
  +  if (object->saved_color == -1) {
  +    color = object->color;
  +  } else {
  +    color = object->saved_color;
  +  }
  +
  +  buf = g_strdup_printf("%c %d %d %d %d %d", object->type, x1, y1, x2, y2, color);
  +  return (buf);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *
  + */
  +void o_net_translate(TOPLEVEL *w_current, int dx, int dy, OBJECT *object)
  +{
  +  int x, y;
  +
  +  if (object == NULL)
  +  printf("nt NO!\n");
  +
  +
  +  /* Do world coords */
  +  object->line->screen_x[0] = object->line->screen_x[0] + dx;
  +  object->line->screen_y[0] = object->line->screen_y[0] + dy;
  +  object->line->screen_x[1] = object->line->screen_x[1] + dx;
  +  object->line->screen_y[1] = object->line->screen_y[1] + dy;
  +
  +  /* do we want snap grid here? */
  +  SCREENtoWORLD(w_current, object->line->screen_x[0],
  +                object->line->screen_y[0], &x, &y);
  +
  +  object->line->x[0] = snap_grid(w_current, x);
  +  object->line->y[0] = snap_grid(w_current, y);
  +
  +  SCREENtoWORLD(w_current, object->line->screen_x[1],
  +                object->line->screen_y[1], &x, &y);
  +
  +  object->line->x[1] = snap_grid(w_current, x);
  +  object->line->y[1] = snap_grid(w_current, y);
  +
  +  s_tile_update_object(w_current, object);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *
  + */
  +void o_net_translate_world(TOPLEVEL *w_current, int x1, int y1,
  +			   OBJECT *object)
  +{
  +  int screen_x1, screen_y1;
  +  int screen_x2, screen_y2;
  +  int left, right, top, bottom;
  +
  +  if (object == NULL)
  +  printf("ntw NO!\n");
  +
  +
  +  /* Do world coords */
  +  object->line->x[0] = object->line->x[0] + x1;
  +  object->line->y[0] = object->line->y[0] + y1;
  +  object->line->x[1] = object->line->x[1] + x1;
  +  object->line->y[1] = object->line->y[1] + y1;
  +
  +  /* update screen coords */
  +  WORLDtoSCREEN(w_current, object->line->x[0],
  +                object->line->y[0], &screen_x1, &screen_y1);
  +
  +  object->line->screen_x[0] = screen_x1;
  +  object->line->screen_y[0] = screen_y1;
  +
  +  WORLDtoSCREEN(w_current, object->line->x[1],
  +                object->line->y[1], &screen_x2, &screen_y2);
  +
  +  object->line->screen_x[1] = screen_x2;
  +  object->line->screen_y[1] = screen_y2;
  +
  +  /* update bounding box */
  +  get_net_bounds(w_current, object->line, &left, &top, &right, &bottom);
  +
  +  object->left = left;
  +  object->top = top;
  +  object->right = right;
  +  object->bottom = bottom;
  +
  +  s_tile_update_object(w_current, object);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *
  + */
  +OBJECT *o_net_copy(TOPLEVEL *w_current, OBJECT *list_tail,
  +		   OBJECT *o_current)
  +{
  +  OBJECT *new_obj;
  +  ATTRIB *a_current;
  +  int color;
  +
  +  if (o_current->saved_color == -1) {
  +    color = o_current->color;
  +  } else {
  +    color = o_current->saved_color;
  +  }
  +
  +  /* make sure you fix this in pin and bus as well */
  +  /* still doesn't work... you need to pass in the new values */
  +  /* or don't update and update later */
  +  /* I think for now I'll disable the update and manually update */
  +  new_obj = o_net_add(w_current, list_tail, OBJ_NET, color,
  +                      o_current->line->x[0], o_current->line->y[0],
  +                      o_current->line->x[1], o_current->line->y[1]);
  +
  +  new_obj->line->screen_x[0] = o_current->line->screen_x[0];
  +  new_obj->line->screen_y[0] = o_current->line->screen_y[0];
  +  new_obj->line->screen_x[1] = o_current->line->screen_x[1];
  +  new_obj->line->screen_y[1] = o_current->line->screen_y[1];
  +
  +  new_obj->line->x[0] = o_current->line->x[0];
  +  new_obj->line->y[0] = o_current->line->y[0];
  +  new_obj->line->x[1] = o_current->line->x[1];
  +  new_obj->line->y[1] = o_current->line->y[1];
  +
  +  a_current = o_current->attribs;
  +
  +  if (a_current) {
  +    while (a_current) {
  +
  +      /* head attrib node has prev = NULL */
  +      if (a_current->prev != NULL) {
  +        a_current->copied_to = new_obj;
  +      }
  +      a_current = a_current->next;
  +    }
  +  }
  +
  +  return (new_obj);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *
  + */
  +void o_net_print(TOPLEVEL *w_current, FILE *fp, OBJECT *o_current,
  +		 int origin_x, int origin_y)
  +{
  +  int offset, offset2;
  +  int cross, net_width;
  +  int x1, y1;
  +  int x2, y2;
  +
  +  if (o_current == NULL) {
  +    printf("got null in o_net_print\n");
  +    return;
  +  }
  +
  +  offset = 7 * 6;
  +  offset2 = 7;
  +
  +  cross = offset;
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, o_current->color);
  +  }
  +
  +  net_width = 2;
  +  if (w_current->net_style == THICK) {
  +    net_width = NET_WIDTH;
  +  }
  +
  +  x1 = o_current->line->x[0] - origin_x,
  +  y1 = o_current->line->y[0] - origin_y;
  +  x2 = o_current->line->x[1] - origin_x,
  +  y2 = o_current->line->y[1] - origin_y;
  +
  +  fprintf(fp, "%d %d %d %d %d line\n", x1,y1,x2,y2,net_width);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *
  + */
  +void o_net_image_write(TOPLEVEL *w_current, OBJECT *o_current,
  +		       int origin_x, int origin_y, int color_mode)
  +{
  +  int offset, offset2;
  +  int cross;
  +  int x1, y1;
  +  int x2, y2;
  +  int endpoint_color;
  +  int color;
  +
  +  if (o_current == NULL) {
  +    printf("got null in o_net_image_write\n");
  +    return;
  +  }
  +
  +  if (color_mode == TRUE) {
  +    color = o_image_geda2gd_color(o_current->color);
  +  } else {
  +    color = image_black;
  +  }
  +
  +  offset = SCREENabs(w_current, NET_WIDTH);
  +
  +  /* 
  +     offset = 7 * (float) w_current->height/ (float) w_current->width;
  +     offset2 = 7 * (float) w_current->height/ (float) w_current->width*2;  
  +
  +     printf("%f %d %d\n", (float) ( (float) w_current->height/ (float) w_current->width), 
  +     offset, offset2);
  +  */
  +
  +  offset2 = offset * 2;
  +
  +  cross = offset;
  +
  +  x1 = o_current->line->screen_x[0];
  +  y1 = o_current->line->screen_y[0];
  +  x2 = o_current->line->screen_x[1];
  +  y2 = o_current->line->screen_y[1];
  +
  +  /* assumes screen coords are already calculated correctly */
  +#ifdef HAS_LIBGDGEDA
  +
  +  if (w_current->net_style == THICK) {
  +    gdImageSetThickness(current_im_ptr, SCREENabs(w_current,
  +                                                  NET_WIDTH));
  +  } else {
  +    gdImageSetThickness(current_im_ptr, 0);
  +  }
  +
  +  gdImageLine(current_im_ptr, x1, y1, x2, y2, color);
  +#endif
  +
  +  if (color_mode == TRUE) {
  +    endpoint_color =
  +      o_image_geda2gd_color(w_current->net_endpoint_color);
  +  } else {
  +    endpoint_color = image_black;
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + * takes in screen coordinates for the centerx,y, and then does the rotate 
  + * in world space
  + * also ignores angle argument... for now, rotate only in 90 degree 
  + * increments
  + * fully functional
  + */
  +void o_net_rotate(TOPLEVEL *w_current, int centerx, int centery, int angle,
  +		  OBJECT *object)
  +{
  +  int world_centerx, world_centery;
  +  int newx, newy;
  +
  +  SCREENtoWORLD(w_current, centerx, centery,
  +                &world_centerx, &world_centery);
  +
  +  /* translate object to origin */
  +  o_net_translate_world(w_current, -world_centerx, -world_centery,
  +                        object);
  +
  +  rotate_point_90(object->line->x[0], object->line->y[0], angle,
  +                  &newx, &newy);
  +
  +  object->line->x[0] = newx;
  +  object->line->y[0] = newy;
  +
  +  rotate_point_90(object->line->x[1], object->line->y[1], angle,
  +                  &newx, &newy);
  +
  +  object->line->x[1] = newx;
  +  object->line->y[1] = newy;
  +
  +  o_net_translate_world(w_current, world_centerx, world_centery, object);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *
  + */
  +void o_net_rotate_world(TOPLEVEL *w_current,
  +			int world_centerx, int world_centery, int angle,
  +			OBJECT *object)
  +{
  +  int newx, newy;
  +
  +  if (angle == 0)
  +  return;
  +
  +  /* translate object to origin */
  +  o_net_translate_world(w_current, -world_centerx, -world_centery,
  +                        object);
  +
  +  rotate_point_90(object->line->x[0], object->line->y[0], angle,
  +                  &newx, &newy);
  +
  +  object->line->x[0] = newx;
  +  object->line->y[0] = newy;
  +
  +  rotate_point_90(object->line->x[1], object->line->y[1], angle,
  +                  &newx, &newy);
  +
  +  object->line->x[1] = newx;
  +  object->line->y[1] = newy;
  +
  +  o_net_translate_world(w_current, world_centerx, world_centery, object);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *
  + */
  +void o_net_mirror(TOPLEVEL *w_current, int centerx, int centery,
  +		  OBJECT *object)
  +{
  +  int world_centerx, world_centery;
  +
  +  SCREENtoWORLD(w_current, centerx, centery,
  +                &world_centerx, &world_centery);
  +
  +  /* translate object to origin */
  +  o_net_translate_world(w_current, -world_centerx, -world_centery,
  +                        object);
  +
  +  object->line->x[0] = -object->line->x[0];
  +
  +  object->line->x[1] = -object->line->x[1];
  +
  +  o_net_translate_world(w_current, world_centerx, world_centery, object);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *
  + */
  +void o_net_mirror_world(TOPLEVEL *w_current, int world_centerx,
  +			int world_centery, OBJECT *object)
  +{
  +  /* translate object to origin */
  +  o_net_translate_world(w_current, -world_centerx, -world_centery,
  +                        object);
  +
  +  object->line->x[0] = -object->line->x[0];
  +
  +  object->line->x[1] = -object->line->x[1];
  +
  +  o_net_translate_world(w_current, world_centerx, world_centery, object);
  +}
  +
  +int o_net_orientation(OBJECT *object)
  +{
  +    if (object->line->y[0] == object->line->y[1]) {
  +	return (HORIZONTAL);
  +    }
  +
  +    if (object->line->x[0] == object->line->x[1]) {
  +	return (VERTICAL);
  +    }
  +
  +    return (NEITHER);
  +}
  +
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + * this function does the actual work of making one net segment out of two
  + * connected segments
  + * The second object (del_object) is the object that should be deleted
  + */
  +void o_net_consolidate_lowlevel(OBJECT *object, OBJECT *del_object,
  +				int orient)
  +{
  +  int temp1, temp2;
  +  int final1, final2;
  +  int changed = 0;
  +  ATTRIB *tail;
  +
  +#if DEBUG
  +  printf("o %d %d %d %d\n", object->line->x[0], object->line->y[0],
  +         object->line->x[1], object->line->y[1]);
  +  printf("d %d %d %d %d\n", del_object->line->x[0],
  +         del_object->line->y[0], del_object->line->x[1],
  +         del_object->line->y[1]);
  +#endif
  +
  +
  +  if (orient == HORIZONTAL) {
  +
  +    temp1 = min(object->line->x[0], del_object->line->x[0]);
  +    temp2 = min(object->line->x[1], del_object->line->x[1]);
  +
  +    final1 = min(temp1, temp2);
  +
  +    temp1 = max(object->line->x[0], del_object->line->x[0]);
  +    temp2 = max(object->line->x[1], del_object->line->x[1]);
  +
  +    final2 = max(temp1, temp2);
  +
  +    object->line->x[0] = final1;
  +    object->line->x[1] = final2;
  +    changed = 1;
  +  }
  +
  +  if (orient == VERTICAL) {
  +    temp1 = min(object->line->y[0], del_object->line->y[0]);
  +    temp2 = min(object->line->y[1], del_object->line->y[1]);
  +
  +    final1 = min(temp1, temp2);
  +
  +    temp1 = max(object->line->y[0], del_object->line->y[0]);
  +    temp2 = max(object->line->y[1], del_object->line->y[1]);
  +
  +    final2 = max(temp1, temp2);
  +
  +    object->line->y[0] = final1;
  +    object->line->y[1] = final2;
  +    changed = 1;
  +  }
  +#if DEBUG
  +  printf("fo %d %d %d %d\n", object->line->x[0], object->line->y[0],
  +         object->line->x[1], object->line->y[1]);
  +#endif
  +
  +  if (changed) {
  +
  +    /* first check for attributes */
  +    if (del_object->attribs) {
  +#if DEBUG
  +      printf("yeah... del object has attributes\n");
  +      printf("reconnecting them to the right place\n");
  +#endif
  +      if (object->attribs) {
  +
  +#if DEBUG
  +        printf("object DID have attributes\n");
  +#endif
  +
  +
  +        /* NEWSEL, this corrupts the selection / object_head badly */
  +        /* fix it, because you can't just go around deleting objects */
  +        /* this whole net conslidate needs to be re thought.. since you */
  +        /* don't really del the del_object */
  +#if 0
  +        printf("object->attribs\n");
  +        o_attrib_print(object->attribs);
  +        printf("--\n");
  +        printf("del_object->attribs\n");
  +        o_attrib_print(del_object->attribs);
  +        printf("--\n");
  +#endif
  +        tail = o_attrib_return_tail(object->attribs);
  +
  +        /* skip over old attrib head */
  +        tail->next = del_object->attribs->next;
  +
  +        /* step prev object to point to last object */
  +        if (tail->next) {
  +          tail->next->prev = tail;
  +        }
  +
  +        /* delete old attrib head */
  +        /* and nothing else */
  +        del_object->attribs->object = NULL;
  +        del_object->attribs->next = NULL;
  +        del_object->attribs->prev = NULL;
  +        o_attrib_delete(del_object->attribs);
  +
  +        /* you don't need to free the attribs list */
  +        /* since it's been relinked into object's */
  +        /* attribs list */
  +
  +        del_object->attribs = NULL;
  +#if 0
  +        printf("\n\nfinal object->attribs\n");
  +        o_attrib_print(object->attribs);
  +        printf("--\n");
  +#endif
  +
  +      } else {
  +
  +#if DEBUG
  +        printf("object didn't have any attributes\n");
  +#endif
  +        object->attribs = del_object->attribs;
  +        /*! \todo what should this be? */
  +        object->attribs->prev = NULL;
  +
  +        /* setup parent attribute */
  +        object->attribs->object = object;
  +
  +        /* you don't need to free the attribs list */
  +        /* since it's been used by object */
  +
  +        del_object->attribs = NULL;
  +      }
  +    }
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + * check to see if this connection also causes a midpoint
  + * if so, return false, else return true
  + */
  +int o_net_consolidate_nomidpoint(OBJECT *object, int x, int y)
  +{
  +  GList *c_current;
  +  CONN *conn;
  +
  +  c_current = object->conn_list;
  +  while(c_current != NULL) {
  +    conn = (CONN *) c_current->data;
  +    if (conn->other_object) {
  +      if (conn->other_object->sid != object->sid &&
  +          conn->x == x && conn->y == y &&
  +          conn->type == CONN_MIDPOINT) {
  +#if DEBUG        
  +        printf("Found one! %s\n", conn->other_object->name); 
  +#endif         
  +        return(FALSE);
  +      }
  +    }
  +    
  +    c_current = c_current->next;
  +  }
  +
  +  return(TRUE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *
  + */
  +int o_net_consolidate_segments(TOPLEVEL *w_current, OBJECT *object)
  +{
  +  int object_orient;
  +  int other_orient;
  +  GList *c_current;
  +  CONN *conn;
  +  OBJECT *other_object;
  +  int changed = 0;
  +  int reselect_new=FALSE;
  +  
  +  if (object == NULL) {
  +    return(0);
  +  }
  +
  +  if (object->type != OBJ_NET) {
  +    return(0);
  +  }
  +
  +  object_orient = o_net_orientation(object);
  +
  +  /*screen_x = object->line->screen_x[j];
  +    screen_y = object->line->screen_y[i];*/
  +
  +  c_current = object->conn_list;
  +  while(c_current != NULL) {
  +    conn = (CONN *) c_current->data;
  +    other_object = conn->other_object;
  +
  +    /* only look at end points which have a valid end on the other side */
  +    if (other_object != NULL && conn->type == CONN_ENDPOINT &&
  +        conn->other_whichone != -1 && conn->whichone != -1 &&
  +        o_net_consolidate_nomidpoint(object, conn->x, conn->y) ) {
  +      
  +      if (other_object->type == OBJ_NET) {
  +        other_orient = o_net_orientation(other_object);
  +
  +        /* - both objects have the same orientation (either vert or horiz) */
  +        /* - it's not the same object */
  +        if (object_orient == other_orient &&
  +            object->sid != other_object->sid &&
  +            other_orient != NEITHER) {
  +
  +#if DEBUG          
  +          printf("consolidating %s to %s\n", object->name, other_object->name);
  +#endif          
  +          
  +          o_net_consolidate_lowlevel(object, other_object, other_orient);
  +
  +          changed++;
  +          if (other_object->selected == TRUE ) {
  +            o_selection_remove(w_current->page_current->selection2_head, 
  +                               other_object);
  +            reselect_new=TRUE;
  +          }
  +
  +          if (reselect_new == TRUE) {
  +            o_selection_remove(w_current->page_current->selection2_head, 
  +                               object);
  +
  +            o_selection_add(w_current->page_current->selection2_head, 
  +                            object);
  +          }
  +				
  +          s_conn_remove(w_current, other_object);
  +          s_delete(w_current, other_object);
  +          o_net_recalc(w_current, object);
  +          s_tile_update_object(w_current, object);
  +          s_conn_update_object(w_current, object);
  +          w_current->page_current->object_tail = 	
  +            return_tail(w_current->page_current->object_head);
  +          return(-1);
  +        }
  +      }
  +      
  +    }
  +
  +    c_current = c_current->next;
  +  }
  +
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *
  + */
  +void o_net_consolidate(TOPLEVEL *w_current)
  +{
  +  OBJECT *o_current;
  +  int status = 0;
  +
  +  o_current = w_current->page_current->object_head;
  +
  +  while (o_current != NULL) {
  +
  +    if (o_current->type == OBJ_NET) {
  +      status = o_net_consolidate_segments(w_current, o_current);
  +    }
  +
  +    if (status == -1) {
  +      o_current = w_current->page_current->object_head;
  +      status = 0;
  +    } else {
  +      o_current = o_current->next;
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *
  + */
  +void o_net_modify(TOPLEVEL *w_current, OBJECT *object,
  +		  int x, int y, int whichone)
  +{
  +  int screen_x, screen_y;
  +  int left, right, top, bottom;
  +
  +  object->line->x[whichone] = x;
  +  object->line->y[whichone] = y;
  +
  +  WORLDtoSCREEN(w_current,
  +                object->line->x[whichone],
  +                object->line->y[whichone], &screen_x, &screen_y);
  +
  +  object->line->screen_x[whichone] = screen_x;
  +  object->line->screen_y[whichone] = screen_y;
  +
  +  get_net_bounds(w_current, object->line, &left, &top, &right, &bottom);
  +
  +  object->left = left;
  +  object->top = top;
  +  object->right = right;
  +  object->bottom = bottom;
  +
  +  s_tile_update_object(w_current, object);
  +}
  
  
  
  1.1                  eda/geda/gaf/libgeda/src/o_picture.c
  
  Index: o_picture.c
  ===================================================================
  /* gEDA - GPL Electronic Design Automation
   * libgeda - gEDA's library
   * Copyright (C) 1998-2000 Ales V. Hvezda
   *
   * 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.
   *
   * This program 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 this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
   */
  #include <config.h>
  
  #include <stdio.h>
  #ifdef HAVE_STRING_H
  #include <string.h>
  #endif
  #include <math.h>
  
  #include <gtk/gtk.h>
  #include <guile/gh.h>
  #ifndef HAS_GTK12
  #include <gdk/gdk.h>
  #include <gdk-pixbuf/gdk-pixbuf.h>
  #include <gdk-pixbuf/gdk-pixdata.h>
  #endif
  
  #include "defines.h"
  #include "struct.h"
  #include "globals.h"
  #include "o_types.h"
  #include "colors.h"
  #include "funcs.h"
  
  #include "../include/prototype.h"
  
  #ifndef HAS_GTK12
  /*! \brief Create picture OBJECT from character string.
   *  \par Function Description
   *  This function will get the description of a picture from the character
   *  string <B>*buf</B>. The new picture is then added to the list of object of
   *  which <B>*object_list</B> is the last element before the call.
   *  The function returns the new last element, that is the added
   *  picture object.
   *
   *  \param [in]  w_current       The TOPLEVEL object.
   *  \param [out] object_list     OBJECT list to create picture in.
   *  \param [in]  buf             Character string with picture description.
   *  \param [in]  fp              Picture file to read.
   *  \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 *w_current, OBJECT *object_list,
  		       char buf[], FILE *fp,
  		       unsigned int release_ver,unsigned int fileformat_ver)
  {
    int x1, y1;
    int width, height, angle;
    gchar mirrored, embedded;
    int num_conv;
    gchar type;
    gchar buffer[MAX_TEXT_LINE_LENGTH]; 
    gchar *filename;
    GdkPixbuf *pixbuf;
    static char gdk_initialized=0;
  
    /* Initialize GDK first if it isn't a graphic app */
    /* i.e: it has no main window */
    if ( (w_current->main_window == NULL) &&
         (gdk_initialized == 0)) {
      gdk_init(NULL, NULL);
      gdk_initialized = 1;
    }
  
    num_conv = sscanf(buf, "%c %d %d %d %d %d %c %c\n",
  	 &type, &x1, &y1, &width, &height, &angle, &mirrored, &embedded);
    
    if (num_conv != 8) {
      fprintf(stderr, "Error reading picture definition line: %s.\n", buf);
      s_log_message ("Error reading picture definition line: %s.\n", buf);
    }
  
    /* 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) {
      fprintf(stderr, "Found a zero width/height picture [ %c %d %d %d %d ]\n",
              type, x1, y1, width, height);
      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)) {
      fprintf(stderr, "Found a picture with a wrong 'mirrored' parameter: %c.\n",
  	    mirrored);
      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)) {
      fprintf(stderr, "Found a picture with a wrong 'embedded' parameter: %c.\n",
  	    embedded);
      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:
      fprintf(stderr, "Found an unsupported picture angle [ %d ]\n", angle);
      s_log_message("Found an unsupported picture angle [ %d ]\n", angle);
      s_log_message("Setting angle to 0\n");
      angle=0;
      break;
  
    }
  
    fgets(buffer, 1024, fp);
    
    filename = g_strdup (buffer);
    filename = remove_last_nl(filename);	
      
    pixbuf = NULL;
  
    if (embedded == 0) {
  #ifndef HAS_GTK12
      pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
      if (pixbuf == NULL) {
        fprintf(stderr, "Error loading picture from file: %s.\n", filename);
        s_log_message( "Error loading picture from file: %s.\n", filename);
      }
  #endif  
    }
    else {
      GString *encoded_picture=g_string_new("");
      GdkPixdata pixdata;
      guint pixdata_serialized_length;
      gchar *pixdata_serialized_data;
      char finished = 0;
  
      /* Read the encoded picture */
      do {
        finished = 0;
        fgets(buffer, 1024, fp);
        if (g_strcasecmp(buffer, ".\n") != 0) {
  	encoded_picture=g_string_append (encoded_picture, buffer);
  	encoded_picture=g_string_append (encoded_picture, "\n");
        }
        else {
  	finished = 1;
        }
      } while (finished == 0);
  
      /* Decode the picture */
      pixdata_serialized_data=s_encoding_base64_decode(encoded_picture->str,
  						     encoded_picture->len,
  						     &pixdata_serialized_length);
      if (pixdata_serialized_data == NULL) {
        fprintf(stderr, "Error decoding picture.\n");      
        s_log_message ("Error decoding picture.\n");
      }
      else {
        /* Deserialize the picture */
        if (!gdk_pixdata_deserialize(&pixdata,pixdata_serialized_length, 
  				   (guint8 *) pixdata_serialized_data, NULL)) {
  				     fprintf(stderr, "Error deserializing picture.\n");
  				   }
        else {
  	pixbuf = gdk_pixbuf_from_pixdata (&pixdata,TRUE, NULL);
        }
      }
  
      if (pixdata_serialized_data != NULL) {
        free (pixdata_serialized_data);
      }
      if (encoded_picture != NULL) {
        g_string_free (encoded_picture, TRUE);
      }
  
    }
  
    if (pixbuf == NULL) {
      /* If the pixbuf couldn't be loaded, then try to load a warning picture */
      char *temp_filename;
  
      fprintf(stderr, "Loading warning picture.\n");
      s_log_message ("Loading warning picture.\n");
      
      temp_filename = g_strconcat(w_current->bitmap_directory, 
  			       G_DIR_SEPARATOR_S, "gschem-warning.png", NULL);
      pixbuf = gdk_pixbuf_new_from_file (temp_filename, NULL);
      if (pixbuf == NULL) {
        fprintf(stderr, "Error loading picture from file: %s.\n", temp_filename);
        s_log_message( "Error loading picture from file: %s.\n", temp_filename);
      }      
      free (temp_filename);
    }
    
    /* create and add the picture to the list */
    /* The picture is described by its upper left and lower right corner */
    object_list = (OBJECT *) o_picture_add(w_current, object_list,
  					 pixbuf, filename, 
  					 (double) (height/width),
  					 type, 
  					 x1, y1+height, x1+width, y1, 
  					 angle, mirrored, embedded);
    if (object_list->picture->filename) {
      free(object_list->picture->filename);
    }
    object_list->picture->filename = g_strdup(filename);
    
    free (filename);
    return(object_list);
  }
  
  /*! \brief Create a character string representation of a picture OBJECT.
   *  \par Function Description
   *  This function formats a string in the buffer <B>*buff</B> to describe
   *  the picture object <B>*object</B>.
   *
   *  \param [in] object  Picture OBJECT to create string from.
   *  \return A pointer to the picture OBJECT character string.
   *
   *  \note
   *  Caller must free returned character string.
   *
   */
  char *o_picture_save(OBJECT *object)
  {
    int width, height, x1, y1;
    gchar *encoded_picture=NULL;
    gchar *out=NULL;
    gchar *pixdata_serialized_data=NULL;
    guint pixdata_serialized_stream_length;
    guint encoded_picture_length;
  
    /* calculate the width and height of the box */
    width  = abs(object->picture->lower_x - object->picture->upper_x); 
    height = abs(object->picture->upper_y - object->picture->lower_y);
  
    /* calculate the lower left corner of the box */
    x1 = object->picture->upper_x;
    y1 = object->picture->upper_y - height; /* move the origin to 0, 0*/
    
  #if DEBUG
    printf("picture: %d %d %d %d\n", x1, y1, width, height);
  #endif
  
    /* Encode the picture if it's embedded */
    if (object->picture->embedded == 1) {
      GdkPixdata pixdata;
      
      /* Serialize the picture data */
      gdk_pixdata_from_pixbuf (&pixdata, object->picture->original_picture, FALSE);
      pixdata_serialized_data = (gchar *) gdk_pixdata_serialize(&pixdata, 
  						    &pixdata_serialized_stream_length);
      if (pixdata_serialized_data == NULL) {
        fprintf (stderr, "ERROR: o_picture_save: failed to create serialized data from picture\n");
        s_log_message ("ERROR: o_picture_save: failed to create serialized data from picture\n");
      }
      else {
        /* Encode the picture */
        encoded_picture = s_encoding_base64_encode(pixdata_serialized_data, 
  						 pixdata_serialized_stream_length,
  						 &encoded_picture_length, TRUE); 
        if (encoded_picture == NULL) {
  	fprintf(stderr, "ERROR: o_picture_save: unable to encode the picture.\n");
  	s_log_message("ERROR: o_picture_save: unable to encode the picture.\n");
        }
      }
    }
  
    if (object->picture->embedded==1) {
      out = g_strdup_printf("%c %d %d %d %d %d %c %c\n%s\n%s\n%s", 
  			  object->type,
  			  x1, y1, width, height,
  			  object->picture->angle,
  			  /* Convert the (0,1) chars to ASCII */
  			  (object->picture->mirrored)+0x30, 
  			  object->picture->embedded+0x30, 
  			  object->picture->filename,
  			  encoded_picture,
  			  ".");
    }
    else {
      out = g_strdup_printf("%c %d %d %d %d %d %c %c\n%s", 
  			  object->type,
  			  x1, y1, width, height,
  			  object->picture->angle,
  			  /* Convert the (0,1) chars to ASCII */
  			  (object->picture->mirrored)+0x30, 
  			  object->picture->embedded+0x30, 
  			  object->picture->filename);
    }
    if (encoded_picture != NULL) {
      free(encoded_picture);
    }
    if (pixdata_serialized_data != NULL) {
      free(pixdata_serialized_data);
    }
  
    return(out);
  
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   *  \param [in] w_current  The TOPLEVEL object.
   *  \param [in] pixbuf
   *  \param [in] filename
   */
  void o_picture_set_pixbuf(TOPLEVEL *w_current,
  			  GdkPixbuf *pixbuf, char *filename)
  {
  
    /* need to put an error messages here */
    if (pixbuf == NULL)  {
      fprintf(stderr, "error! picture in set pixbuf was NULL\n");
      return;
    }
  
    if (w_current->current_pixbuf != NULL) {
      free(w_current->current_pixbuf);
      w_current->current_pixbuf=NULL;
    }
  
    if (w_current->pixbuf_filename != NULL) {
      free(w_current->pixbuf_filename);
      w_current->pixbuf_filename=NULL;
    }
  
    w_current->current_pixbuf = pixbuf;
    w_current->pixbuf_filename = (char *) g_strdup(filename);
    
    w_current->pixbuf_wh_ratio = (double) gdk_pixbuf_get_width(pixbuf) / 
                                          gdk_pixbuf_get_height(pixbuf);
  
    /* be sure to free this pixbuf somewhere */
  }
  
  /*! \brief Create and add picture OBJECT to list.
   *  \par Function Description
   *  This function creates a new object representing a picture.
   *  This object is added to the end of the list <B>object_list</B> pointed
   *  object belongs to.
   *  The picture is described by its upper left corner - <B>x1</B>, <B>y1</B> -
   *  and its lower right corner - <B>x2</B>, <B>y2</B>.
   *  The <B>type</B> parameter must be equal to #OBJ_PICTURE. 
   *
   *  The #OBJECT structure is allocated with the
   *  #s_basic_init_object() function. The structure describing the
   *  picture is allocated and initialized with the parameters given to the
   *  function.
   *
   *  The object is added to the end of the list described by the
   *  <B>object_list</B> parameter by the #s_basic_link_object().
   *
   *  \param [in]     w_current    The TOPLEVEL object.
   *  \param [in,out] object_list  OBJECT list to add line to.
   *  \param [in]     pixbuf       The GdkPixbuf picture to add.
   *  \param [in]     filename     File name to read picture from.
   *  \param [in]     ratio        Picture height to width ratio.
   *  \param [in]     type         Must be OBJ_PICTURE.
   *  \param [in]     x1           Upper x coordinate.
   *  \param [in]     y1           Upper y coordinate.
   *  \param [in]     x2           Lower x coordinate.
   *  \param [in]     y2           Lower y coordinate.
   *  \param [in]     angle        Picture rotation angle.
   *  \param [in]     mirrored     Whether the image should be mirrored or not.
   *  \param [in]     embedded     ???
   *  \return A pointer to the new end of the object list.
   */
  OBJECT *o_picture_add(TOPLEVEL *w_current, OBJECT *object_list,
  		      GdkPixbuf * pixbuf, char *filename, double ratio,
  		      char type, 
  		      int x1, int y1, int x2, int y2, int angle, char mirrored,
  		      char embedded)
  {
    OBJECT *new_node;
    PICTURE *picture;
  
    /* create the object */
    new_node        = s_basic_init_object("picture");
    new_node->type  = type;
    
    picture = (PICTURE *) malloc(sizeof(PICTURE));
    new_node->picture   = picture;
    
    /* describe the picture with its upper left and lower right corner */
    picture->upper_x = x1;
    picture->upper_y = y1;
    picture->lower_x = x2;
    picture->lower_y = y2;
    
    /* Fill the picture data */
    
    /* Create a copy of the pixbuf */
    picture->original_picture = gdk_pixbuf_rotate(pixbuf, 0);
    picture->filename = (char *) g_strdup(filename);
    picture->ratio = ratio;
    picture->displayed_picture = NULL;
    picture->angle = angle;
    picture->mirrored = mirrored;
    picture->embedded = embedded;
    
    if (picture->original_picture == NULL) {
      fprintf(stderr, "new picture: Couldn't get enough memory for the new picture\n");
    }
    
    /* Clean w_current variables */
    /* \bug This should be done when canceling the action. */
    /* Pixbuf filename is not freed because we want to
       remember the last directory
    */
    /*
      if (w_current->current_pixbuf != NULL) {
        free (w_current->current_pixbuf);
      }
      w_current->current_pixbuf = NULL;
      w_current->pixbuf_wh_ratio = 0;
    */
  
    /* \todo questionable cast */     
    new_node->draw_func = (void *) picture_draw_func; 
    /* \todo questionable cast */     
    new_node->sel_func  = (void *) select_func;  
  
    /* compute the bounding picture */
    o_picture_recalc(w_current, new_node);
    
    /* add the object to the list */
    object_list = (OBJECT *) s_basic_link_object(new_node, object_list);
    
    return(object_list);
  }
  
  /*! \brief Recalculate picture coordinates in SCREEN units.
   *  \par Function Description
   *  This function recalculates the screen coords of the <B>o_current</B>
   *  parameter picture object from its world coords.
   *
   *  The picture coordinates and its bounding are recalculated as well
   *  as the #OBJECT specific fields (line width, filling ...).
   *
   *  \param [in] w_current      The TOPLEVEL object.
   *  \param [in,out] o_current  Picture OBJECT to be recalculated.
   */
  void o_picture_recalc(TOPLEVEL *w_current, OBJECT *o_current)
  {
    int left, top, right, bottom;
    int screen_x1, screen_y1;
    int screen_x2, screen_y2;
  
    if (o_current->picture == NULL) {
      return;
    }
  
    /* update the screen coords of the upper left corner of the picture */
    WORLDtoSCREEN(w_current,
  		o_current->picture->upper_x, o_current->picture->upper_y, 
  		&screen_x1, &screen_y1);  
    o_current->picture->screen_upper_x = screen_x1;
    o_current->picture->screen_upper_y = screen_y1;
    
    /* update the screen coords of the lower right corner of the picture */
    WORLDtoSCREEN(w_current,
  		o_current->picture->lower_x, o_current->picture->lower_y, 
  		&screen_x2, &screen_y2);  
    o_current->picture->screen_lower_x = screen_x2;
    o_current->picture->screen_lower_y = screen_y2;
    
    /* update the bounding picture - screen unit */
    get_picture_bounds(w_current, o_current->picture,
  		     &left, &top, &right, &bottom);
    o_current->left   = left;
    o_current->top    = top;
    o_current->right  = right;
    o_current->bottom = bottom;
    
    /* recalc OBJECT specific parameters */
    o_object_recalc(w_current, o_current);
  
  }
  
  /*! \brief Get picture bounding rectangle.
   *  \par Function Description 
   *  This function sets the <B>left</B>, <B>top</B>, <B>right</B> and
   *  <B>bottom</B> parameters to the boundings of the picture object described
   *  in <B>*picture</B> in SCREEN units.
   *
   *  \param [in]  w_current  The TOPLEVEL object.
   *  \param [in]  picture    Picture OBJECT to read coordinates from.
   *  \param [out] left       Left picture coordinate in SCREEN units.
   *  \param [out] top        Top picture coordinate in SCREEN units.
   *  \param [out] right      Right pircture coordinate in SCREEN units.
   *  \param [out] bottom     Bottom picture coordinate in SCREEN units.
   */
  void get_picture_bounds(TOPLEVEL *w_current, PICTURE *picture,
  			int *left, int *top, int *right, int *bottom)
  {
    *left   = picture->screen_upper_x;
    *top    = picture->screen_upper_y;
    *right  = picture->screen_lower_x;
    *bottom = picture->screen_lower_y;
  
  }
  
  /*! \brief Get picture bounding rectangle in WORLD coordinates.
   *  \par Function Description
   *  This function sets the <B>left</B>, <B>top</B>, <B>right</B> and
   *  <B>bottom</B> parameters to the boundings of the picture object
   *  described in <B>*picture</B> in WORLD units.
   *
   *  \param [in]  w_current  The TOPLEVEL object.
   *  \param [in]  picture    Picture OBJECT to read coordinates from.
   *  \param [out] left       Left picture coordinate in WORLD units.
   *  \param [out] top        Top picture coordinate in WORLD units.
   *  \param [out] right      Right picture coordinate in WORLD units.
   *  \param [out] bottom     Bottom picture coordinate in WORLD units.
   */
  void world_get_picture_bounds(TOPLEVEL *w_current, PICTURE *picture,
  			      int *left, int *top, int *right, int *bottom)
  {
  	/* pb20011002 - why using min and max here and not above ? */
  	*left   = min(picture->upper_x, picture->lower_x);
  	*top    = min(picture->upper_y, picture->lower_y);
  	*right  = max(picture->upper_x, picture->lower_x);
  	*bottom = max(picture->upper_y, picture->lower_y);
  	
  	/* PB : same as above here for width of edges */	
  
  #if DEBUG 
  	printf("picture: %d %d %d %d\n", *left, *top, *right, *bottom);
  #endif
  	
  }
                   
  /*! \brief Modify the description of a picture OBJECT.
   *  \par Function Description
   *  This function modifies the coordinates of one of the four corner of
   *  the picture. The new coordinates of the corner identified by
   *  <B>whichone</B> are given by <B>x</B> and <B>y</B> in world unit.
   *
   *  The coordinates of the corner is modified in the world coordinate system.
   *  Screen coordinates and boundings are then updated.
   *
   *  \param [in]     w_current  The TOPLEVEL object.
   *  \param [in,out] object     Picture OBJECT to modify.
   *  \param [in]     x          New x coordinate.
   *  \param [in]     y          New y coordinate.
   *  \param [in]     whichone   Which picture parameter to modify.
   *
   *  <B>whichone</B> can have the following values:
   *  <DL>
   *    <DT>*</DT><DD>PICTURE_UPPER_LEFT
   *    <DT>*</DT><DD>PICTURE_LOWER_LEFT
   *    <DT>*</DT><DD>PICTURE_UPPER_RIGHT
   *    <DT>*</DT><DD>PICTURE_LOWER_RIGHT
   *  </DL>
   *
   *  \par Author's note
   *  pb20011002 - rewritten : old one did not used x, y and whichone
   */
  void o_picture_modify(TOPLEVEL *w_current, OBJECT *object, 
  		      int x, int y, int whichone)
  {
    int tmp;
    
    /* change the position of the selected corner */
    switch(whichone) {
      case PICTURE_UPPER_LEFT:
        object->picture->upper_x = x;
        tmp = abs(object->picture->upper_x - object->picture->lower_x) / 
  	object->picture->ratio;
        if (y < object->picture->lower_y) {
  	tmp = -tmp;
        }
        object->picture->upper_y = object->picture->lower_y + tmp;
        break;
  			
      case PICTURE_LOWER_LEFT:
        object->picture->upper_x = x;
        tmp = abs(object->picture->upper_x - object->picture->lower_x) / 
  	object->picture->ratio;
        if (y > object->picture->upper_y) {
  	tmp = -tmp;
        }
        object->picture->lower_y = object->picture->upper_y - tmp;
        break;
        
      case PICTURE_UPPER_RIGHT:
        object->picture->lower_x = x;
        tmp = abs(object->picture->upper_x - object->picture->lower_x) / 
  	object->picture->ratio;
        if (y < object->picture->lower_y) {
  	tmp = -tmp;
        }
        object->picture->upper_y = object->picture->lower_y + tmp;
        break;
        
      case PICTURE_LOWER_RIGHT:
        object->picture->lower_x = x;
        tmp = abs(object->picture->upper_x - object->picture->lower_x) / 
  	object->picture->ratio;
        if (y > object->picture->upper_y) {
  	tmp = -tmp;
        }
        object->picture->lower_y = object->picture->upper_y - tmp;
        break;
        
      default:
        return;
    }
    
    /* need to update the upper left and lower right corners */
    if(object->picture->upper_x > object->picture->lower_x) {
      tmp                      = object->picture->upper_x;
      object->picture->upper_x = object->picture->lower_x;
      object->picture->lower_x = tmp;
    }
    
    if(object->picture->upper_y < object->picture->lower_y) {
      tmp                      = object->picture->upper_y;
      object->picture->upper_y = object->picture->lower_y;
      object->picture->lower_y = tmp;
    }
  	
    /* recalculate the screen coords and the boundings */
    o_picture_recalc(w_current, object);
  }
  
  /*! \brief Rotate a picture OBJECT.
   *  \par Function Description
   *  This function applies a rotation of center (<B>centerx</B>, <B>centery</B>)
   *  and angle <B>angle</B> to the picture object <B>*object</B>.
   *  The coordinates of the rotation center are in screen units. 
   *  <B>angle</B> must be a 90 degree multiple. If not, no rotation is applied.
   *
   *  The rotation is made with the #o_picture_rotate_world() function
   *  that perform a rotation of angle <B>angle</B> and center
   *  (<B>world_centerx</B>, <B>world_centery</B>) in world unit.
   *
   *  \param [in]     w_current  The TOPLEVEL object.
   *  \param [in]     centerx    Rotation center x coordinate in SCREEN units.
   *  \param [in]     centery    Rotation center y coordinate in SCREEN units.
   *  \param [in]     angle      Rotation angle in degrees (unused).
   *  \param [in,out] object     Picture OBJECT to rotate.
   *
   *  \note
   *  takes in screen coordinates for the centerx,y, and then does the rotate 
   *  in world space
   *  also ignores angle argument... for now, rotate only in 90 degree 
   *  increments
   *  fixed to 90 degrees... it's *not* general now
   */
  void o_picture_rotate(TOPLEVEL *w_current,
  		      int centerx, int centery, int angle,
  		      OBJECT *object)
  {
    int world_centerx, world_centery;
  
    /* convert the center of rotation to world unit */
    SCREENtoWORLD(w_current,
  				centerx, centery, 
                  &world_centerx, &world_centery);  
  
    /* rotate the picture */
    /* the check of the rotation angle is in o_picture_rotate_world() */
    o_picture_rotate_world(w_current,
  					 world_centerx, world_centery, angle,
  					 object);
  
    /* screen coords and boundings are updated by _rotate_world() */
    
  }
  
  /*! \brief Rotate picture OBJECT using WORLD coordinates.
   *  \par Function Description 
   *  This function rotates the picture described by <B>*object</B> around
   *  the (<B>world_centerx</B>, <B>world_centery</B>) point by <B>angle</B>
   *  degrees.
   *  The center of rotation is in world units.
   *
   *  \param [in]      w_current      The TOPLEVEL object.
   *  \param [in]      world_centerx  Rotation center x coordinate in
   *                                  WORLD units.
   *  \param [in]      world_centery  Rotation center y coordinate in
   *                                  WORLD units.
   *  \param [in]      angle          Rotation angle in degrees (See note below).
   *  \param [in,out]  object         Picture OBJECT to rotate.
   */
  void o_picture_rotate_world(TOPLEVEL *w_current, 
  			    int world_centerx, int world_centery, int angle,
  			    OBJECT *object)
  {
    int newx1, newy1;
    int newx2, newy2;
    
    /* Only 90 degree multiple and positive angles are allowed. */
    /* angle must be positive */
    if(angle < 0) angle = -angle;
    /* angle must be a 90 multiple or no rotation performed */
    if((angle % 90) != 0) return;
    
    object->picture->angle = ( object->picture->angle + angle ) % 360;
  	
    /* The center of rotation (<B>world_centerx</B>, <B>world_centery</B>) is
     * translated to the origin. The rotation of the upper left and lower
     * right corner are then performed. Finally, the rotated picture is
     * translated back to its previous location.
     */
    /* translate object to origin */
    object->picture->upper_x -= world_centerx;
    object->picture->upper_y -= world_centery;
    object->picture->lower_x -= world_centerx;
    object->picture->lower_y -= world_centery;
    
    /* rotate the upper left corner of the picture */
    rotate_point_90(object->picture->upper_x, object->picture->upper_y, angle,
  		  &newx1, &newy1);
    
    /* rotate the lower left corner of the picture */
    rotate_point_90(object->picture->lower_x, object->picture->lower_y, angle,
  		  &newx2, &newy2);
    
    /* reorder the corners after rotation */
    object->picture->upper_x = min(newx1,newx2);
    object->picture->upper_y = max(newy1,newy2);
    object->picture->lower_x = max(newx1,newx2);
    object->picture->lower_y = min(newy1,newy2);
    
    /* translate object back to normal position */
    object->picture->upper_x += world_centerx;
    object->picture->upper_y += world_centery;
    object->picture->lower_x += world_centerx;
    object->picture->lower_y += world_centery;
    
    /* recalc boundings and screen coords */
    o_picture_recalc(w_current, object);
  	
  }
  
  /*! \brief Mirror a picture.
   *  \par Function Description
   *  This function mirrors the picture from the point
   *  (<B>centerx</B>,<B>centery</B>) in screen unit.
   *
   *  The origin of the mirror in screen unit is converted in world unit.
   *  The picture is mirrored with the function #o_picture_mirror_world()
   *  for which the origin of the mirror must be given in world unit.
   *
   *  \param [in]     w_current  The TOPLEVEL object.
   *  \param [in]     centerx    Origin x coordinate in WORLD units.
   *  \param [in]     centery    Origin y coordinate in WORLD units.
   *  \param [in,out] object     Picture OBJECT to mirror.
   */
  void o_picture_mirror(TOPLEVEL *w_current,
  		      int centerx, int centery,
  		      OBJECT *object)
  {
    int world_centerx, world_centery;
  
    /* convert the origin of mirror */
    SCREENtoWORLD(w_current, centerx, centery, 
                  &world_centerx,
                  &world_centery);  
  
    /* apply the mirror in world coords */
    o_picture_mirror_world(w_current,
  			 world_centerx, world_centery,
  			 object);
  
    /* screen coords and boundings are updated by _mirror_world() */
    
  }
  
  /*! \brief Mirror a picture using WORLD coordinates.
   *  \par Function Description
   *  This function mirrors the picture from the point
   *  (<B>world_centerx</B>,<B>world_centery</B>) in world unit.
   *
   *  The picture is first translated to the origin, then mirrored and
   *  finally translated back at its previous position.
   *
   *  \param [in]     w_current      The TOPLEVEL object.
   *  \param [in]     world_centerx  Origin x coordinate in WORLD units.
   *  \param [in]     world_centery  Origin y coordinate in WORLD units.
   *  \param [in,out] object         Picture OBJECT to mirror.
   */
  void o_picture_mirror_world(TOPLEVEL *w_current,
  			    int world_centerx, int world_centery,
  			    OBJECT *object)
  {
    int newx1, newy1;
    int newx2, newy2;
  
    
    /* Set info in object */
    object->picture->mirrored = (object->picture->mirrored ^ 1) & 1;
  
    /* translate object to origin */
    object->picture->upper_x -= world_centerx;
    object->picture->upper_y -= world_centery;
    object->picture->lower_x -= world_centerx;
    object->picture->lower_y -= world_centery;
  
    /* mirror the corners */
    newx1 = -object->picture->upper_x;
    newy1 = object->picture->upper_y;
    newx2 = -object->picture->lower_x;
    newy2 = object->picture->lower_y;
  
    /* reorder the corners */
    object->picture->upper_x = min(newx1,newx2);
    object->picture->upper_y = max(newy1,newy2);
    object->picture->lower_x = max(newx1,newx2);
    object->picture->lower_y = min(newy1,newy2);
  
    /* translate back in position */
    object->picture->upper_x += world_centerx;
    object->picture->upper_y += world_centery;
    object->picture->lower_x += world_centerx;
    object->picture->lower_y += world_centery;
  
    /* recalc boundings and screen coords */
    o_picture_recalc(w_current, object);
    
  }
  
  /*! \brief Translate a picture position by a delta.
   *  \par Function Description
   *  This function applies a translation of (<B>dx</B>,<B>dy</B>) to the picture
   *  described by <B>*object</B>. <B>dx</B> and <B>dy</B> are in screen units.
   *
   *  The translation vector is converted in world unit. The translation is 
   *  made with #o_picture_translate_world().
   *
   *  \param [in]     w_current   The TOPLEVEL object.
   *  \param [in]     dx          x distance to move.
   *  \param [in]     dy          y distance to move.
   *  \param [in,out] object      Picture OBJECT to translate.
   */
  void o_picture_translate(TOPLEVEL *w_current, int dx, int dy, OBJECT *object)
  {
    int world_dx, world_dy;
  
    if (object == NULL) printf("bt NO!\n");
  
    /* convert the translation vector in world unit */
    world_dx = SCREENabs(w_current, dx);
    world_dy = SCREENabs(w_current, dy);
  
    /* translate the picture */
    o_picture_translate_world(w_current, world_dx, world_dy, object);
  
    /* screen coords and boundings are updated by _translate_world */
    
  }
  
  /*! \brief Translate a picture position in WORLD coordinates by a delta.
   *  \par Function Description
   *  This function applies a translation of (<B>x1</B>,<B>y1</B>) to the picture
   *  described by <B>*object</B>. <B>x1</B> and <B>y1</B> are in world units.
   *
   *  \param [in]     w_current  The TOPLEVEL object.
   *  \param [in]     x1         x distance to move.
   *  \param [in]     y1         y distance to move.
   *  \param [in,out] object     Picture OBJECT to translate.
   */
  void o_picture_translate_world(TOPLEVEL *w_current,
  			       int x1, int y1, OBJECT *object)
  {
    if (object == NULL) printf("btw NO!\n");
  
    /* Do world coords */
    object->picture->upper_x = object->picture->upper_x + x1;
    object->picture->upper_y = object->picture->upper_y + y1;
    object->picture->lower_x = object->picture->lower_x + x1;
    object->picture->lower_y = object->picture->lower_y + y1;     
    
    /* recalc the screen coords and the bounding picture */
    o_picture_recalc(w_current, object);
  }
  
  /*! \brief Create a copy of a picture.
   *  \par Function Description
   *  This function creates a verbatim copy of the object pointed by
   *  <B>o_current</B> describing a picture. The new object is added at the
   *  end of the list, following the <B>list_tail</B> pointed object.
   *
   *  \param [in]  w_current  The TOPLEVEL object.
   *  \param [out] list_tail  OBJECT list to copy to.
   *  \param [in]  o_current  Picture OBJECT to copy.
   *  \return A new pointer to the end of the object list.
   */
  OBJECT *o_picture_copy(TOPLEVEL *w_current, OBJECT *list_tail,
  		       OBJECT *o_current)
  {
    OBJECT *new_obj;
    ATTRIB *a_current;
    int color;
  	
    if (o_current->saved_color == -1) {
      color = o_current->color;
    } else {
      color = o_current->saved_color;
    }
  
    /* A new picture object is added at the end of the object list with
     * #o_picture_add(). Values for its fields are default and need to
     * be modified.
     */
  
    /* create and link a new picture object */	
    new_obj = o_picture_add(w_current, list_tail,
  			  w_current->current_pixbuf, 
  			  w_current->pixbuf_filename, 
  			  w_current->pixbuf_wh_ratio,
  			  OBJ_PICTURE,
  			  0, 0, 0, 0, 0, FALSE, FALSE);
  
    /* The dimensions of the new picture are set with the ones of the
     * original picture. The two picturees have the same line type and
     * the same filling options.
     *
     * The coordinates and the values in screen unit are computed with
     * #o_picture_recalc().
     */
    /* modifying */
    /* pb20011002 - have to check if o_current is a picture object */
    new_obj->picture->upper_x = o_current->picture->upper_x;
    new_obj->picture->upper_y = o_current->picture->upper_y;
    new_obj->picture->lower_x = o_current->picture->lower_x;
    new_obj->picture->lower_y = o_current->picture->lower_y;
    
    /* Copy the picture data */
    new_obj->picture->original_picture = 
      gdk_pixbuf_scale_simple(o_current->picture->original_picture,
  			    gdk_pixbuf_get_width (o_current->picture->original_picture),
  			    gdk_pixbuf_get_height (o_current->picture->original_picture),
  			    GDK_INTERP_BILINEAR);
    new_obj->picture->displayed_picture = 
      gdk_pixbuf_scale_simple(o_current->picture->displayed_picture,
  			    gdk_pixbuf_get_width (o_current->picture->displayed_picture),
  			    gdk_pixbuf_get_height (o_current->picture->displayed_picture),
  			    GDK_INTERP_BILINEAR);
  
    new_obj->picture->ratio = o_current->picture->ratio;
    new_obj->picture->filename = g_strdup(o_current->picture->filename);
    
    new_obj->picture->angle = o_current->picture->angle;
    new_obj->picture->mirrored = o_current->picture->mirrored;
    
    o_picture_recalc(w_current, new_obj);
    
    /* new_obj->attribute = 0;*/
    a_current = o_current->attribs;
    if (a_current) {
      while ( a_current ) {
        /* head attrib node has prev = NULL */
        if (a_current->prev != NULL) {
  	a_current->copied_to = new_obj;
        }
        a_current = a_current->next;
      }
    }
    
    /* return the new tail of the object list */
    return(new_obj);
  } 
  
  /*! \brief Get RGB data from image.
   *  \par Function Description
   *  This function returns the RGB data of the given image.
   *  Function taken from the DIA source code (http://www.gnome.org/projects/dia)
   *  and licensed under the GNU GPL version 2.
   *
   *  \param [in] image  GdkPixbuf image to read RGB data from.
   *  \return Array of rgb data from image.
   *
   *  \note
   *  Caller must free returned guint8 array.
   */
  guint8 *o_picture_rgb_data(GdkPixbuf *image)
  {
    int width = gdk_pixbuf_get_width(image);
    int height = gdk_pixbuf_get_height(image);
    int rowstride = gdk_pixbuf_get_rowstride(image);
    int size = height*rowstride;
    guint8 *rgb_pixels = g_malloc(size);
  
    if (gdk_pixbuf_get_has_alpha(image)) {
      guint8 *pixels = gdk_pixbuf_get_pixels(image);
      int i, j;
      for (i = 0; i < height; i++) {
        for (j = 0; j < width; j++) {
  	rgb_pixels[i*rowstride+j*3] = pixels[i*rowstride+j*4];
  	rgb_pixels[i*rowstride+j*3+1] = pixels[i*rowstride+j*4+1];
  	rgb_pixels[i*rowstride+j*3+2] = pixels[i*rowstride+j*4+2];
        }
      }
      return rgb_pixels;
    } else {
      guint8 *pixels = gdk_pixbuf_get_pixels(image);
  
      g_memmove(rgb_pixels, pixels, height*rowstride);
      return rgb_pixels;
    }
  }
  
  /*! \brief Get mask data from image.
   *  \par Function Description
   *  This function returns the mask data of the given image.
   *  Function taken from the DIA source code (http://www.gnome.org/projects/dia)
   *  and licensed under the GNU GPL version 2.
   *
   *  \param [in] image  GdkPixbuf image to get mask data from.
   *  \return Array of mask data from image.
   *
   *  \note
   *  Caller must free returned guint8 array.
   */
  guint8 *o_picture_mask_data(GdkPixbuf *image)
  {
    guint8 *pixels;
    guint8 *mask;
    int i, size;
  
    if (!gdk_pixbuf_get_has_alpha(image)) {
      return NULL;
    }
    
    pixels = gdk_pixbuf_get_pixels(image);
  
    size = gdk_pixbuf_get_width(image)*
      gdk_pixbuf_get_height(image);
  
    mask = g_malloc(size);
  
    /* Pick every fourth byte (the alpha channel) into mask */
    for (i = 0; i < size; i++)
      mask[i] = pixels[i*4+3];
  
    return mask;
  }
  
  /*! \brief Print picture to Postscript document.
   *  \par Function Description
   *  This function prints a picture object. The picture is defined by the
   *  coordinates of its upper left corner in (<B>x</B>,<B>y</B>) and its width
   *  and height given by the <B>width</B> and <B>height</B> parameters. 
   *  The Postscript document is defined by the file pointer <B>fp</B>.
   *  Function based on the DIA source code (http://www.gnome.org/projects/dia)
   *  and licensed under the GNU GPL version 2.
   *
   *  All dimensions are in mils.
   *  
   *  \param [in] w_current  The TOPLEVEL object.
   *  \param [in] fp         FILE pointer to Postscript document.
   *  \param [in] o_current  Picture OBJECT to write to document.
   *  \param [in] origin_x   Page x coordinate to place picture OBJECT.
   *  \param [in] origin_y   Page y coordinate to place picture OBJECT.
   */
  void o_picture_print(TOPLEVEL *w_current, FILE *fp, OBJECT *o_current, 
  		     int origin_x, int origin_y)
  {
    int x1, y1, x, y;
    int height, width;
    GdkPixbuf* image = o_current->picture->displayed_picture;
    int img_width, img_height, img_rowstride;
    double ratio;
    guint8 *rgb_data;
    guint8 *mask_data;
  
    /* calculate the width and height of the box */
    width  = abs(o_current->picture->lower_x - o_current->picture->upper_x); 
    height = abs(o_current->picture->upper_y - o_current->picture->lower_y);
  
    /* calculate the origin of the box */
    x1 = o_current->picture->upper_x;
    y1 = o_current->picture->upper_y;
  
    img_width = gdk_pixbuf_get_width(image);
    img_rowstride = gdk_pixbuf_get_rowstride(image);
    img_height = gdk_pixbuf_get_height(image);
  
    rgb_data = o_picture_rgb_data(image);
    mask_data = o_picture_mask_data(image);
  
    ratio = height/width;
  
    fprintf(fp, "gsave\n");
  
    /* color output only */
    fprintf(fp, "/pix %i string def\n", img_width * 3);
    fprintf(fp, "%i %i 8\n", img_width, img_height);
    fprintf(fp, "%i %i translate\n", x1, y1);
    fprintf(fp, "%i %i scale\n", width, height);
    fprintf(fp, "[%i 0 0 -%i 0 0]\n", img_width, img_height);
  
    fprintf(fp, "{currentfile pix readhexstring pop}\n");
    fprintf(fp, "false 3 colorimage\n");
    fprintf(fp, "\n");
  
    if (mask_data) {
      for (y = 0; y < img_height; y++) {
        for (x = 0; x < img_width; x++) {
  	int i = y*img_rowstride+x*3;
  	int m = y*img_width+x;
          fprintf(fp, "%02x", 255-(mask_data[m]*(255-rgb_data[i])/255));
          fprintf(fp, "%02x", 255-(mask_data[m]*(255-rgb_data[i+1])/255));
          fprintf(fp, "%02x", 255-(mask_data[m]*(255-rgb_data[i+2])/255));
        }
        fprintf(fp, "\n");
      }
    } else {
      for (y = 0; y < img_height; y++) {
        for (x = 0; x < img_width; x++) {
  	int i = y*img_rowstride+x*3;
          fprintf(fp, "%02x", (int)(rgb_data[i]));
          fprintf(fp, "%02x", (int)(rgb_data[i+1]));
          fprintf(fp, "%02x", (int)(rgb_data[i+2]));
        }
        fprintf(fp, "\n");
      }
    }
    fprintf(fp, "grestore\n");
    fprintf(fp, "\n");
     
    g_free(rgb_data);
    g_free(mask_data);
  
  	
  }
  #endif
  
  
  
  
  1.21      +704 -457  eda/geda/gaf/libgeda/src/o_pin_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_pin_basic.c
  ===================================================================
  RCS file: o_pin_basic.c
  diff -N o_pin_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_pin_basic.c	5 Jul 2006 03:13:38 -0000	1.21
  @@ -0,0 +1,804 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#ifdef HAS_LIBGDGEDA
  +#include <gdgeda/gd.h>
  +#endif
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +#include "funcs.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void get_pin_bounds(TOPLEVEL *w_current, LINE *line, int *left, int *top,
  +		    int *right, int *bottom)
  +{
  +  *left = w_current->width;
  +  *top = w_current->height;
  +  *right = 0;
  +  *bottom = 0;
  +
  +  if (line->screen_x[0] < *left) *left = line->screen_x[0];
  +  if (line->screen_x[0] > *right) *right = line->screen_x[0];
  +  if (line->screen_y[0] < *top) *top = line->screen_y[0];
  +  if (line->screen_y[0] > *bottom) *bottom = line->screen_y[0];
  +
  +  if (line->screen_x[1] < *left) *left = line->screen_x[1];
  +  if (line->screen_x[1] > *right) *right = line->screen_x[1];
  +  if (line->screen_y[1] < *top) *top = line->screen_y[1];
  +  if (line->screen_y[1] > *bottom) *bottom = line->screen_y[1];
  +
  +  *left = *left - 4;
  +  *top = *top - 4;
  +
  +  *right = *right + 4;
  +  *bottom = *bottom + 4;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void world_get_pin_bounds(TOPLEVEL *w_current, LINE *line, int *left, int *top,
  +			  int *right, int *bottom)
  +{
  +  *left = w_current->init_right;
  +  *top = w_current->init_bottom;
  +  *right = 0;
  +  *bottom = 0;
  +
  +  if (line->x[0] < *left) *left = line->x[0];
  +  if (line->x[0] > *right) *right = line->x[0];
  +  if (line->y[0] < *top) *top = line->y[0];
  +  if (line->y[0] > *bottom) *bottom = line->y[0];
  +
  +  if (line->x[1] < *left) *left = line->x[1];
  +  if (line->x[1] > *right) *right = line->x[1];
  +  if (line->y[1] < *top) *top = line->y[1];
  +  if (line->y[1] > *bottom) *bottom = line->y[1];
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *o_pin_add(TOPLEVEL *w_current, OBJECT *object_list,
  +		  char type, int color,
  +		  int x1, int y1, int x2, int y2, int pin_type, int whichend)
  +{
  +  int screen_x, screen_y;
  +  int left, right, top, bottom;
  +  OBJECT *new_node;
  +
  +  new_node = s_basic_init_object("pin");
  +  new_node->type = type;
  +  new_node->color = color;
  +
  +  new_node->line = (LINE *) malloc(sizeof(LINE));
  +
  +  new_node->line->x[0] = x1;
  +  new_node->line->y[0] = y1;
  +  new_node->line->x[1] = x2;
  +  new_node->line->y[1] = y2;
  +
  +  WORLDtoSCREEN(w_current, 
  +                new_node->line->x[0], new_node->line->y[0], 
  +                &screen_x,
  +                &screen_y);  
  +	
  +  new_node->line->screen_x[0] = screen_x;
  +  new_node->line->screen_y[0] = screen_y;
  +
  +  WORLDtoSCREEN(w_current, 
  +                new_node->line->x[1], new_node->line->y[1], 
  +                &screen_x,
  +                &screen_y);  
  +
  +  new_node->line->screen_x[1] = screen_x;
  +  new_node->line->screen_y[1] = screen_y;
  +
  +  get_pin_bounds(w_current, new_node->line, &left, &top, &right, &bottom);
  +	
  +  new_node->left = left;
  +  new_node->top = top;
  +  new_node->right = right;
  +  new_node->bottom = bottom;	
  +
  +  /*! \todo questionable cast */
  +  new_node->draw_func = (void *) pin_draw_func;  
  +  /*! \todo questionable cast */
  +  new_node->sel_func = (void *) select_func;  
  +
  +  new_node->pin_type = pin_type;
  +  new_node->whichend = whichend;
  +  
  +  object_list = (OBJECT *) s_basic_link_object(new_node, object_list);
  +
  +  /* this mod causes shadow pins to appear at 0,0 if you copy a complex
  +   * that has pins... 
  +   * This mod was added so that you could draw pins to nets and have
  +   * the dangling cue go away 
  +   * There is a complementary one in o_nets, but it doesn't work 
  +   * completely either... hack */
  +#if 0
  +  /*  ifed out 3/15/98 due to above  */
  +  if (!adding_sel) {
  +    o_pin_conn_recalc(w_current, object_list); /* old conn system */
  +    /*o_net_conn_recalc(object_list); */
  +  }     
  +#endif
  +
  +
  +  if (!w_current->ADDING_SEL) {
  +    s_tile_add_object(w_current, object_list, 
  +                      new_node->line->x[0], new_node->line->y[0], 
  +                      new_node->line->x[1], new_node->line->y[1]);
  +    s_conn_update_object(w_current, object_list);
  +  }
  +
  +  return(object_list);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_pin_recalc(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int screen_x1, screen_y1;
  +  int screen_x2, screen_y2;	
  +  int left, right, top, bottom;
  +
  +  if (o_current->line == NULL) {
  +    return;
  +  }
  +
  +
  +  WORLDtoSCREEN(w_current, o_current->line->x[0], 
  +                o_current->line->y[0], 
  +                &screen_x1,
  +                &screen_y1);  
  +
  +  o_current->line->screen_x[0] = screen_x1;
  +  o_current->line->screen_y[0] = screen_y1;
  +
  +  WORLDtoSCREEN(w_current, o_current->line->x[1], 
  +                o_current->line->y[1], 
  +                &screen_x2,
  +                &screen_y2);  
  +
  +  o_current->line->screen_x[1] = screen_x2;
  +  o_current->line->screen_y[1] = screen_y2;
  +
  +  get_pin_bounds(w_current, o_current->line, &left, &top, &right, &bottom);
  +
  +  o_current->left = left;
  +  o_current->top = top;
  +  o_current->right = right;
  +  o_current->bottom = bottom;
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *o_pin_read(TOPLEVEL *w_current, OBJECT *object_list, char buf[],
  +		   unsigned int release_ver, unsigned int fileformat_ver)
  +{
  +  char type; 
  +  int x1, y1;
  +  int x2, y2;
  +  int d_x1, d_y1;
  +  int d_x2, d_y2;
  +  int color;
  +  int pin_type;
  +  int whichend;
  +
  +  if(release_ver <= VERSION_20020825) {
  +    sscanf(buf, "%c %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2, &color);
  +    pin_type = PIN_TYPE_NET;
  +    whichend = -1;     
  +  } else {
  +    sscanf(buf, "%c %d %d %d %d %d %d %d\n", &type, &x1, &y1, &x2, &y2,
  +           &color, &pin_type, &whichend);
  +  }
  +
  +  if (whichend == -1) {
  +    fprintf(stderr,
  +            "Found a pin which did not have the whichone field set.\nVerify and correct manually.\n");
  +    s_log_message("Found a pin which did not have the whichone field set.\nVerify and correct manully.\n");
  +  } else if (whichend < -1 || whichend > 1) {
  +    fprintf(stderr,
  +            "Found an invalid whichend on a pin (reseting to zero): %d\n",
  +            whichend);
  +    s_log_message("Found an invalid whichend on a pin (reseting to zero): %d\n",
  +                  whichend);
  +    whichend = 0;
  +  }
  +  
  +  d_x1 = x1; 
  +  d_y1 = y1; 
  +  d_x2 = x2; 
  +  d_y2 = y2; 
  +
  +  if (x1 == x2 && y1 == y2) {
  +    fprintf(stderr, "Found a zero length pin: [ %s ]\n", buf);
  +    s_log_message("Found a zero length pin: [ %s ]\n", buf);
  +  }
  +
  +  if (color < 0 || color > MAX_COLORS) {
  +    fprintf(stderr, "Found an invalid color [ %s ]\n", buf);
  +    s_log_message("Found an invalid color [ %s ]\n", buf);
  +    s_log_message("Setting color to WHITE\n");
  +    color = WHITE;
  +  }
  +
  +  if (w_current->override_pin_color != -1) {
  +    color = w_current->override_pin_color;
  +  }
  +
  +  object_list = o_pin_add(w_current, object_list, type, color, d_x1, d_y1,
  +                          d_x2, d_y2, pin_type, whichend);
  +  return(object_list);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +char *o_pin_save(OBJECT *object)
  +{
  +  int x1, x2, y1, y2;
  +  int color;
  +  int pin_type, whichend;
  +  char *buf;
  +  
  +  x1 = object->line->x[0];
  +  y1 = object->line->y[0];
  +  x2 = object->line->x[1];
  +  y2 = object->line->y[1];
  +  
  +  /* Use the right color */
  +  if (object->saved_color == -1) {
  +    color = object->color;
  +  } else {
  +    color = object->saved_color;
  +  }
  +
  +  pin_type = object->pin_type;
  +  whichend = object->whichend;
  +  
  +  buf = g_strdup_printf("%c %d %d %d %d %d %d %d", object->type,
  +		   x1, y1, x2, y2, color, pin_type, whichend);
  +  return(buf);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_pin_translate(TOPLEVEL *w_current, int dx, int dy, OBJECT *object)
  +{
  +  int x, y;
  +
  +  if (object == NULL) printf("pt NO!\n");
  +
  +
  +  /* Do screen coords */
  +  object->line->screen_x[0] = object->line->screen_x[0] + dx;
  +  object->line->screen_y[0] = object->line->screen_y[0] + dy;
  +  object->line->screen_x[1] = object->line->screen_x[1] + dx;
  +  object->line->screen_y[1] = object->line->screen_y[1] + dy;
  +
  +  /* do we want snap grid here? */
  +  SCREENtoWORLD(w_current, object->line->screen_x[0], 
  +                object->line->screen_y[0], 
  +                &x,
  +                &y);  
  +	
  +  object->line->x[0] = snap_grid(w_current, x);
  +  object->line->y[0] = snap_grid(w_current, y);
  +	
  +  SCREENtoWORLD(w_current, object->line->screen_x[1], 
  +                object->line->screen_y[1], 
  +                &x,
  +                &y);  
  +	
  +  object->line->x[1] = snap_grid(w_current, x);
  +  object->line->y[1] = snap_grid(w_current, y);
  +
  +  s_tile_update_object(w_current, object);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_pin_translate_world(TOPLEVEL *w_current, int x1, int y1, OBJECT *object)
  +{
  +  int screen_x1, screen_y1;
  +  int screen_x2, screen_y2;	
  +  int left, right, top, bottom;
  +
  +  if (object == NULL) printf("ptw NO!\n");
  +
  +
  +  /* Do world coords */
  +  object->line->x[0] = object->line->x[0] + x1;
  +  object->line->y[0] = object->line->y[0] + y1;
  +  object->line->x[1] = object->line->x[1] + x1;
  +  object->line->y[1] = object->line->y[1] + y1;
  +
  +  /* update screen coords */
  +  WORLDtoSCREEN(w_current, object->line->x[0], 
  +                object->line->y[0], 
  +                &screen_x1,
  +                &screen_y1);  
  +
  +  object->line->screen_x[0] = screen_x1;
  +  object->line->screen_y[0] = screen_y1;
  +
  +  WORLDtoSCREEN(w_current, object->line->x[1], 
  +                object->line->y[1], 
  +                &screen_x2,
  +                &screen_y2);  
  +
  +  object->line->screen_x[1] = screen_x2;
  +  object->line->screen_y[1] = screen_y2;
  +
  +  /* update bounding box */
  +  get_pin_bounds(w_current, object->line, &left, &top, &right, &bottom);
  +
  +  object->left = left;
  +  object->top = top;
  +  object->right = right;
  +  object->bottom = bottom;
  +
  +  s_tile_update_object(w_current, object);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *o_pin_copy(TOPLEVEL *w_current, OBJECT *list_tail, OBJECT *o_current)
  +{
  +  OBJECT *new_obj;
  +  ATTRIB *a_current;
  +  int color;
  +
  +  if (o_current->saved_color == -1) {
  +    color = o_current->color;
  +  } else {
  +    color = o_current->saved_color;
  +  }
  +
  +  new_obj = o_pin_add(w_current, list_tail, OBJ_PIN, color, 
  +                      o_current->line->x[0], o_current->line->y[0],
  +                      o_current->line->x[1], o_current->line->y[1],
  +                      o_current->pin_type, o_current->whichend);
  +
  +  /* why is this here ? */
  +  /* because they all have it, and it is used during outline actions */
  +  new_obj->line->screen_x[0] = o_current->line->screen_x[0];
  +  new_obj->line->screen_y[0] = o_current->line->screen_y[0];
  +  new_obj->line->screen_x[1] = o_current->line->screen_x[1];
  +  new_obj->line->screen_y[1] = o_current->line->screen_y[1];
  +
  +
  +  new_obj->line->x[0] = o_current->line->x[0];
  +  new_obj->line->y[0] = o_current->line->y[0];
  +  new_obj->line->x[1] = o_current->line->x[1];
  +  new_obj->line->y[1] = o_current->line->y[1];
  +
  +  /*	new_obj->attribute = 0;*/
  +  a_current = o_current->attribs;
  +  if (a_current) {
  +    while ( a_current ) {
  +
  +      /* head attrib node has prev = NULL */
  +      if (a_current->prev != NULL) {
  +        a_current->copied_to = new_obj;
  +      }
  +      a_current = a_current->next;
  +    }
  +  }
  +
  +  return(new_obj);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_pin_print(TOPLEVEL *w_current, FILE *fp, OBJECT *o_current, 
  +		 int origin_x, int origin_y)
  +{
  +  int pin_width;
  +  int x1, y1;
  +  int x2, y2;
  +  
  +  if (o_current == NULL) {
  +    printf("got null in o_pin_print\n");
  +    return;
  +  }
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, o_current->color);
  +  }
  +
  +  x1 = o_current->line->x[0] - origin_x;
  +  y1 = o_current->line->y[0] - origin_y;
  +  x2 = o_current->line->x[1] - origin_x;
  +  y2 = o_current->line->y[1] - origin_y;
  +  pin_width = 2;
  +  if(w_current->pin_style == THICK) {
  +    pin_width = PIN_WIDTH;
  +  }
  +
  +  fprintf(fp, "%d %d %d %d %d line\n",x1,y1,x2,y2,pin_width);
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_pin_image_write(TOPLEVEL *w_current, OBJECT *o_current,
  +		       int origin_x, int origin_y, int color_mode)
  +{
  +  int color;
  +
  +  if (o_current == NULL) {
  +    printf("got null in o_pin_image_write\n");
  +    return;
  +  }
  +
  +  if (color_mode == TRUE) {
  +    color = o_image_geda2gd_color(o_current->color);
  +  } else {
  +    color = image_black;
  +  }
  +
  +  /* assumes screen coords are already calculated correctly */
  +#ifdef HAS_LIBGDGEDA
  +
  +  if (w_current->pin_style == THICK) {
  +    gdImageSetThickness(current_im_ptr, SCREENabs(w_current,
  +                                                  PIN_WIDTH));
  +  } else {
  +    gdImageSetThickness(current_im_ptr, 0);
  +  }
  +
  +  gdImageLine(current_im_ptr,
  +              o_current->line->screen_x[0],
  +              o_current->line->screen_y[0],
  +              o_current->line->screen_x[1],
  +              o_current->line->screen_y[1],
  +              color);
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_pin_rotate(TOPLEVEL *w_current, int centerx, int centery, int angle,
  +		  OBJECT *object)
  +{
  +  int world_centerx, world_centery;
  +  int newx, newy;
  +
  +  SCREENtoWORLD(w_current, centerx, centery, 
  +                &world_centerx,
  +                &world_centery);  
  +
  +  /* translate object to origin */
  +  o_pin_translate_world(w_current, -world_centerx, -world_centery, object);
  +
  +  rotate_point_90(object->line->x[0], object->line->y[0], angle,
  +                  &newx, &newy);
  +
  +  object->line->x[0] = newx;
  +  object->line->y[0] = newy;
  +
  +  rotate_point_90(object->line->x[1], object->line->y[1], angle,
  +                  &newx, &newy);
  +
  +  object->line->x[1] = newx;
  +  object->line->y[1] = newy;
  +
  +  o_pin_translate_world(w_current, world_centerx, world_centery, object);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_pin_rotate_world(TOPLEVEL *w_current, int world_centerx, 
  +			int world_centery, int angle,
  +			OBJECT *object)
  +{
  +  int newx, newy;
  +	
  +  if (angle == 0)
  +  return;
  +
  +  /* translate object to origin */
  +  o_pin_translate_world(w_current, -world_centerx, -world_centery, object);
  +
  +  rotate_point_90(object->line->x[0], object->line->y[0], angle,
  +                  &newx, &newy);
  +
  +  object->line->x[0] = newx;
  +  object->line->y[0] = newy;
  +
  +  rotate_point_90(object->line->x[1], object->line->y[1], angle,
  +                  &newx, &newy);
  +
  +  object->line->x[1] = newx;
  +  object->line->y[1] = newy;
  +
  +  o_pin_translate_world(w_current, world_centerx, world_centery, object);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_pin_mirror(TOPLEVEL *w_current,
  +		  int centerx, int centery, OBJECT *object)
  +{
  +  int world_centerx, world_centery;
  +
  +  SCREENtoWORLD(w_current, centerx, centery, 
  +                &world_centerx,
  +                &world_centery);  
  +
  +  /* translate object to origin */
  +  o_pin_translate_world(w_current, -world_centerx, -world_centery, object);
  +
  +  object->line->x[0] = -object->line->x[0];
  +
  +  object->line->x[1] = -object->line->x[1];
  +
  +  o_pin_translate_world(w_current, world_centerx, world_centery, object);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_pin_mirror_world(TOPLEVEL *w_current,
  +			int world_centerx, int world_centery, OBJECT *object)
  +{
  +  /* translate object to origin */
  +  o_pin_translate_world(w_current, -world_centerx, -world_centery, object);
  +
  +  object->line->x[0] = -object->line->x[0];
  +
  +  object->line->x[1] = -object->line->x[1];
  +
  +  o_pin_translate_world(w_current, world_centerx, world_centery, object);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_pin_modify(TOPLEVEL *w_current, OBJECT *object, 
  +		  int x, int y, int whichone)
  +{
  +  int screen_x, screen_y;
  +  int left, right, top, bottom;
  +
  +  object->line->x[whichone] = x;
  +  object->line->y[whichone] = y;
  +
  +  WORLDtoSCREEN(w_current, 
  +                object->line->x[whichone], 
  +                object->line->y[whichone], 
  +                &screen_x, &screen_y);  
  +	
  +  object->line->screen_x[whichone] = screen_x;
  +  object->line->screen_y[whichone] = screen_y;
  +
  +  get_pin_bounds(w_current, object->line, &left, &top, &right, &bottom);
  +	
  +  object->left = left;
  +  object->top = top;
  +  object->right = right;
  +  object->bottom = bottom;	
  +
  +  s_tile_update_object(w_current, object);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_pin_update_whichend(TOPLEVEL *w_current,
  +			   OBJECT *object_list, int num_pins)
  +{
  +  OBJECT *o_current;
  +  int top, left;
  +  int right, bottom;
  +  int d1, d2, d3, d4;
  +  int min0, min1;
  +  int min0_whichend, min1_whichend;
  +  int rleft, rtop, rright, rbottom;
  +
  +  if (object_list && num_pins) {
  +    if (num_pins == 1 || w_current->force_boundingbox) {
  +      world_get_complex_bounds(w_current, object_list,
  +                             &left, &top, &right, &bottom);
  +    } else {
  +      left = rleft = w_current->init_right;
  +      top = rtop = w_current->init_bottom;;
  +      right = rright = 0;
  +      bottom = rbottom = 0;
  +
  +      /* only look at the pins to calculate bounds of the symbol */
  +      o_current = object_list;
  +      while (o_current != NULL) {
  +        if (o_current->type == OBJ_PIN) {
  +          world_get_pin_bounds(w_current, o_current->line,
  +                               &rleft, &rtop, &rright, &rbottom);
  +        }
  +
  +        if (rleft < left) left = rleft;
  +        if (rtop < top) top = rtop;
  +        if (rright > right) right = rright;
  +        if (rbottom > bottom) bottom = rbottom;
  +      
  +        o_current=o_current->next;
  +      }
  +
  +      
  +    }
  +  } else {
  +    return;
  +  }
  +
  +  o_current = object_list;
  +  while (o_current != NULL) {
  +    if (o_current->type == OBJ_PIN && o_current->whichend == -1) {
  +      if (o_current->line->y[0] == o_current->line->y[1]) {
  +        /* horizontal */
  +        
  +        if (o_current->line->x[0] == left) {
  +          o_current->whichend = 0;
  +        } else if (o_current->line->x[1] == left) {
  +          o_current->whichend = 1;        
  +        } else if (o_current->line->x[0] == right) {
  +          o_current->whichend = 0;        
  +        } else if (o_current->line->x[1] == right) {
  +          o_current->whichend = 1;
  +        } else {
  +            
  +          d1 = abs(o_current->line->x[0] - left);
  +          d2 = abs(o_current->line->x[1] - left);
  +          d3 = abs(o_current->line->x[0] - right);
  +          d4 = abs(o_current->line->x[1] - right);
  +
  +          if (d1 <= d2) {
  +            min0 = d1;
  +            min0_whichend = 0;
  +          } else {
  +            min0 = d2;
  +            min0_whichend = 1;
  +          }
  +
  +          if (d3 <= d4) {
  +            min1 = d3;
  +            min1_whichend = 0;
  +          } else {
  +            min1 = d4;
  +            min1_whichend = 1;
  +          }
  +
  +          if (min0 <= min1) {
  +            o_current->whichend = min0_whichend;
  +          } else {
  +            o_current->whichend = min1_whichend;
  +          }
  +        }
  +           
  +      } else if (o_current->line->x[0] == o_current->line->x[1]) {
  +        /* vertical */
  +        
  +        if (o_current->line->y[0] == top) {
  +          o_current->whichend = 0;
  +        } else if (o_current->line->y[1] == top) {
  +          o_current->whichend = 1;        
  +        } else if (o_current->line->x[0] == bottom) {
  +          o_current->whichend = 0;        
  +        } else if (o_current->line->x[1] == bottom) {
  +          o_current->whichend = 1;
  +        } else {
  +            
  +          d1 = abs(o_current->line->y[0] - top);
  +          d2 = abs(o_current->line->y[1] - top);
  +          d3 = abs(o_current->line->y[0] - bottom);
  +          d4 = abs(o_current->line->y[1] - bottom);
  +
  +          if (d1 <= d2) {
  +            min0 = d1;
  +            min0_whichend = 0;
  +          } else {
  +            min0 = d2;
  +            min0_whichend = 1;
  +          }
  +
  +          if (d3 <= d4) {
  +            min1 = d3;
  +            min1_whichend = 0;
  +          } else {
  +            min1 = d4;
  +            min1_whichend = 1;
  +          }
  +
  +          if (min0 <= min1) {
  +            o_current->whichend = min0_whichend;
  +          } else {
  +            o_current->whichend = min1_whichend;
  +          }
  +        }
  +      }
  +    }
  +    o_current = o_current->next;
  +  }
  +}
  
  
  
  1.6       +304 -226  eda/geda/gaf/libgeda/src/o_selection.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_selection.c
  ===================================================================
  RCS file: o_selection.c
  diff -N o_selection.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_selection.c	5 Jul 2006 03:13:38 -0000	1.6
  @@ -0,0 +1,387 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <ctype.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_ASSERT_H
  +#include <assert.h>
  +#endif
  +#ifndef HAVE_VSNPRINTF
  +#include <stdarg.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "defines.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SELECTION *o_selection_return_tail(SELECTION *head)
  +{
  +  SELECTION *s_current=NULL;
  +  SELECTION *ret_struct=NULL;
  +
  +  s_current = head;
  +  while ( s_current != NULL ) { /* goto end of list */
  +    ret_struct = s_current;
  +    s_current = s_current->next;
  +  }
  +
  +  return(ret_struct);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SELECTION *o_selection_return_head(SELECTION *tail)
  +{
  +  SELECTION *s_current=NULL;
  +  SELECTION *ret_struct=NULL;
  +
  +  s_current = tail;
  +  while ( s_current != NULL ) { /* goto end of list */
  +    ret_struct = s_current;
  +    s_current = s_current->prev;
  +  }
  +
  +  return(ret_struct);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SELECTION *o_selection_new_head(void)
  +{
  +  SELECTION *s_new;
  +
  +  s_new = (SELECTION *) malloc(sizeof(SELECTION));
  +  s_new->selected_object = NULL;
  +  s_new->prev = NULL;
  +  s_new->next = NULL;
  +
  +  return(s_new);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_selection_destroy_head(SELECTION *s_head)
  +{
  +  free(s_head);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* also does the needed work to make the object visually selected */
  +SELECTION *o_selection_add(SELECTION *head, OBJECT *o_selected)
  +{
  +  SELECTION *tail;
  +  SELECTION *s_new;
  +	
  +  s_new = (SELECTION *) malloc(sizeof(SELECTION));
  +
  +  if (o_selected != NULL) {
  +    s_new->selected_object = o_selected;
  +  } else {
  +    fprintf(stderr, "Got NULL passed to o_selection_new\n");
  +  }
  +
  +  o_selection_select(o_selected, SELECT_COLOR);
  +
  +  if (head == NULL) {
  +    s_new->prev = NULL; /* setup previous link */
  +    s_new->next = NULL;
  +    return(s_new);
  +  } else {
  +    tail = o_selection_return_tail(head);
  +    s_new->prev = tail; /* setup previous link */
  +    s_new->next = NULL;
  +    tail->next = s_new;
  +    return(tail->next);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* it's okay to call this with an o_selected which is not necessarily */
  +/* selected */
  +void o_selection_remove(SELECTION *head, OBJECT *o_selected)
  +{
  +  SELECTION *s_current;
  +
  +  if (o_selected == NULL) {
  +    fprintf(stderr, "Got NULL for o_selected in o_selection_remove\n");
  +    return;
  +  }
  +
  +  s_current = head;	
  +
  +  while (s_current != NULL) {
  +    if (s_current->selected_object == o_selected) {
  +      if (s_current->next)
  +        s_current->next->prev = s_current->prev;
  +      else
  +        s_current->next = NULL;
  +
  +      if (s_current->prev)
  +        s_current->prev->next = s_current->next;
  +      else
  +        s_current->prev = NULL;
  +
  +      o_selection_unselect(s_current->selected_object);
  +
  +      s_current->selected_object = NULL;
  +      free(s_current);
  +      return;
  +    }
  +    s_current = s_current->next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* removes all but the head node */
  +void o_selection_remove_most(TOPLEVEL *w_current, SELECTION *head)
  +{
  +  SELECTION *s_current;
  +  SELECTION *s_prev;
  +
  +  s_current = o_selection_return_tail(head);
  +
  +  while (s_current != NULL) {
  +    if (s_current->selected_object != NULL) {
  +      s_prev = s_current->prev;	
  +
  +      o_selection_unselect(s_current->selected_object);
  +
  +      o_redraw_single(w_current,  
  +                      s_current->selected_object);
  +	
  +      s_current->selected_object = NULL;
  +      free(s_current);
  +      s_current = s_prev;
  +    } else {
  +      break;
  +    }
  +  }
  +
  +  /* clear out any dangling pointers */
  +  head->next=NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_selection_print_all( SELECTION *head )
  +{
  +  SELECTION *s_current;
  +
  +  s_current = head;
  +
  +  printf("START printing selection ********************\n");
  +  while(s_current != NULL) {
  +    if (s_current->selected_object) {
  +      printf("Selected object: %d\n", 
  +             s_current->selected_object->sid);
  +    }
  +    s_current = s_current->next;
  +  }
  +  printf("DONE printing selection ********************\n");
  +  printf("\n");
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_selection_destroy_all(SELECTION *head) 
  +{
  +  SELECTION *s_current;
  +  SELECTION *s_prev;
  +
  +  s_current = o_selection_return_tail(head);
  +
  +  while (s_current != NULL) {
  +    s_prev = s_current->prev;	
  +    s_current->selected_object = NULL;
  +    free(s_current);
  +    s_current = s_prev;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* this sets the select flag, saves the color, and then sets the color */
  +void o_selection_select(OBJECT *object, int color)
  +{
  +  if (object->selected == TRUE) {
  +    printf("object already selected == TRUE\n");
  +    return;
  +  }
  +
  +  if (object->saved_color != -1) {
  +    printf("object already saved_color != -1\n");
  +    return;
  +  }
  +
  +  object->selected = TRUE;
  +  object->draw_grips = TRUE;
  +  object->saved_color = object->color;
  +  object->color = color;
  +  if (object->type == OBJ_COMPLEX || object->type == OBJ_PLACEHOLDER) { 
  +    o_complex_set_color_save(object->complex->prim_objs, color);
  +  } else if (object->type == OBJ_TEXT) {
  +    o_complex_set_color_save(object->text->prim_objs, color);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* this unsets the select flag and restores the original color */
  +/* this function should not be called by anybody outside of this file */
  +void o_selection_unselect(OBJECT *object)
  +{
  +  object->selected = FALSE;
  +  /* object->draw_grips = FALSE; can't do this here... */
  +  /* draw_grips is cleared in the individual draw functions after the */
  +  /* grips are erase */
  +  object->color = object->saved_color;
  +  if (object->type == OBJ_COMPLEX || object->type == OBJ_PLACEHOLDER) { 
  +    o_complex_unset_color(object->complex->prim_objs);
  +  } else if (object->type == OBJ_TEXT) {
  +    o_complex_unset_color(object->text->prim_objs);
  +  }
  +
  +  object->saved_color = -1;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *o_selection_return_first_object(SELECTION *head) 
  +{
  +  if (!head)
  +  return(NULL);
  +
  +  if (!head->next)  
  +  return(NULL);
  +
  +  if (!head->next->selected_object) 
  +  return(NULL);
  +
  +  return(head->next->selected_object);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* Nth starts counting a ZERO */
  +/* doesn't consider the head node an object */
  +OBJECT *o_selection_return_nth_object(SELECTION *head, int count) 
  +{
  +  int internal_counter = 0;
  +  SELECTION *s_current;
  +
  +  s_current = head->next;
  +
  +  while (s_current != NULL) {
  +    if (internal_counter == count) {
  +      if (s_current->selected_object) {
  +        return(s_current->selected_object);
  +      }
  +    }
  +    internal_counter++;
  +
  +    s_current = s_current->next;
  +  }
  +  return(NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int o_selection_return_num(SELECTION *head)
  +{
  +  int counter = 0;
  +  SELECTION *s_current;
  +
  +  if (!head) {
  +    return 0;
  +  }
  +  
  +  /* skip over head */
  +  s_current = head->next;
  +
  +  while (s_current != NULL) {
  +    counter++;
  +    s_current = s_current->next;
  +  }
  +  
  +  return(counter);
  +}
  
  
  
  1.19      +2300 -1979eda/geda/gaf/libgeda/src/o_text_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_text_basic.c
  ===================================================================
  RCS file: o_text_basic.c
  diff -N o_text_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_text_basic.c	5 Jul 2006 03:13:38 -0000	1.19
  @@ -0,0 +1,2433 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +#include <sys/stat.h>
  +#include <assert.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +#include "funcs.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +#line 117 "../noweb/o_text_basic.nw"
  +#define WINONLY	1
  +#define BACKING 2
  +
  +/*! \note
  + *  font storage and friends are staying global so that all can access
  + */
  +
  +/*! Hashtable storing font_character (string) as a key, and pointer to data */
  +GHashTable *font_loaded = NULL;
  +
  +/*! Hashtable storing mapping between character and font definition file */
  +GHashTable *font_char_to_file = NULL;
  +
  +/*! Size of a tab in characters */
  +int tab_in_chars = 8;
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void get_text_bounds(TOPLEVEL *w_current, OBJECT *o_current,
  +		     int *left, int *top, int *right, int *bottom)
  +{
  +  get_complex_bounds(w_current, o_current->text->prim_objs, left, top,
  +                     right, bottom);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void world_get_text_bounds(TOPLEVEL *w_current, OBJECT *o_current, int *left,
  +			   int *top, int *right, int *bottom)
  +{
  +  world_get_complex_bounds(w_current, o_current->text->prim_objs,
  +                           left, top, right, bottom);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *o_text_add_head(void)
  +{
  +  OBJECT *new_node=NULL;
  +
  +  new_node = s_basic_init_object("text_head");
  +  new_node->type = OBJ_HEAD;
  +
  +  /* don't need to do this for head nodes */
  +  /* ret = s_basic_link_object(new_node, NULL);*/
  +  return(new_node);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_init(void)
  +{
  +  if (font_loaded == NULL) {
  +    font_loaded = g_hash_table_new_full (g_direct_hash,
  +                                         g_direct_equal,
  +                                         NULL,
  +                                         g_free);
  +  } else {
  +    fprintf (stderr, "o_text_init: Tried to initialize an already initialized font_loaded hash table!!\n");
  +  }
  +  if (font_char_to_file == NULL) {
  +    font_char_to_file = g_hash_table_new_full (g_direct_hash,
  +                                               g_direct_equal,
  +                                               NULL,
  +                                               g_free);
  +  }
  +  else {
  +    fprintf (stderr, "o_text_init: Tried to initialize an already initialized font_char_to_file hash table!!\n");
  +  }
  +  
  +  return;
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_print_set(void)
  +{
  +  OBJECT *o_current, *o_font_set;
  +  char i;
  +	
  +  for (i = 'A' ; i < 'Z'+1; i++) {
  +    o_font_set = g_hash_table_lookup (font_loaded,
  +                                      GUINT_TO_POINTER ((gunichar)i));
  +    if (o_font_set != NULL) {
  +      printf("%c: LOADED\n", i);	
  +      for (o_current=return_tail(o_font_set->font_prim_objs); o_current; 
  +           o_current=o_current->prev) 
  +      {
  +        printf("  %s\n", o_current->name);	
  +      }
  +    } else {
  +      printf("%c: unloaded\n", i);	
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *o_text_load_font(TOPLEVEL *w_current, gunichar needed_char)
  +{
  +  gchar *temp_string = NULL;
  +  OBJECT *temp_parent, *o_font_set;
  +  int not_found = FALSE;
  +  gchar *aux_str2;
  +
  +  /* retrieve the name of the file where the char is defined */
  +  aux_str2 = g_hash_table_lookup (font_char_to_file,
  +                                  GUINT_TO_POINTER (needed_char));
  +  if (aux_str2 == NULL) {
  +      /* this is needed since WinNT file systems are 
  +       * case insensitive, and cannot tell the difference 
  +       * between A.sym and a.sym.  So we create a_.sym -  
  +       * z_.sym, this loads up the chars 
  +       */
  +      if (needed_char >= 'a' && needed_char <= 'z') {
  +        temp_string = g_strdup_printf("%s%c%c_.sym", 
  +                w_current->font_directory, G_DIR_SEPARATOR,
  +                needed_char);
  +      } else {
  +        temp_string = g_strdup_printf("%s%c%c.sym", 
  +                w_current->font_directory, G_DIR_SEPARATOR,
  +                needed_char);
  +      }
  +  } else {
  +    temp_string = g_strdup_printf("%s", aux_str2);
  +  }
  +  aux_str2 = NULL;
  +
  +  if ( access(temp_string, R_OK) != 0 ) {
  +    gchar outbuf[7];
  +    gint l;
  +
  +    /* convert needed_char to a utf-8 string */
  +    l = g_unichar_to_utf8 (needed_char, outbuf);
  +    outbuf[l] = '\0';
  +    s_log_message("Could not find character '%s' definition.\n", outbuf);
  +    
  +    g_free (temp_string);
  +    temp_string = g_strdup_printf("%s%cquest.sym", w_current->font_directory, G_DIR_SEPARATOR);
  +    if ( access(temp_string, R_OK) != 0 ) {
  +      fprintf(stderr, "Could not load question font char -- check font-directory keyword\n");
  +      exit(-1);
  +    }
  +    not_found = TRUE; 
  +  }
  +
  +  /* Make new object for the font set list */
  +  o_font_set = (OBJECT*)g_new (OBJECT, 1);	
  +  
  +  o_font_set->font_prim_objs = NULL;
  +  o_font_set->font_text_size = 100;
  +
  +  o_font_set->name = g_strdup_printf ("%c", needed_char);
  +  o_font_set->font_prim_objs = o_text_add_head();
  +  
  +  /* Add it to the list and hash table. Some functions will need it */
  +  g_hash_table_insert (font_loaded,
  +                       GUINT_TO_POINTER (needed_char), o_font_set);
  +
  +  if (not_found == TRUE) {
  +    /* set the font text size (width) to the question mark's size */
  +    /* yes, the question mark character was loaded instead of the real char */
  +    /* 63 == question mark character */
  +
  +    OBJECT *aux_obj;
  +    
  +    aux_obj = g_hash_table_lookup (font_loaded,
  +                                   GUINT_TO_POINTER ((gunichar)'?'));
  +    if (aux_obj == NULL) {
  +      o_text_load_font(w_current, (gunichar) '?');
  +      aux_obj = g_hash_table_lookup (font_loaded,
  +                                     GUINT_TO_POINTER ((gunichar)'?'));
  +    }
  +
  +    o_font_set->font_text_size = aux_obj->font_text_size;
  +  }
  +	
  +
  +  temp_parent = w_current->page_current->object_parent;
  +  /* set the addition of attributes to the head node */
  +  w_current->page_current->object_parent = o_font_set->font_prim_objs;
  +
  +  o_font_set->font_prim_objs = o_read(w_current, o_font_set->font_prim_objs,
  +				      temp_string);
  +  w_current->page_current->object_parent = temp_parent;
  +
  +  o_font_set->font_prim_objs = return_head(o_font_set->font_prim_objs);
  +
  +  return(o_font_set->font_prim_objs);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int o_text_num_lines(char *string) 
  +{
  +  int line_count = 0;
  +  gchar *aux;
  +  gunichar current_char;
  +
  +  if (string == NULL) {
  +    return 0;
  +  }
  +  
  +  /* if it's not null, then we have at least one line */
  +  line_count++;
  +  /* Count how many \n are in the string */
  +  aux = string;
  +  while (aux && ((gunichar) (*aux) != 0) ) {
  +    current_char = g_utf8_get_char_validated(aux, -1);
  +    if (current_char == '\n')
  +      line_count++;
  +    aux = g_utf8_find_next_char(aux, NULL);
  +  }
  +
  +  return (line_count);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* You do not need to divide the size in half here. */
  +int o_text_height(char *string, int size) 
  +{
  +  int line_count = 0;
  +
  +  if (string == NULL) {
  +    return 0;
  +  }
  +
  +  /* Get the number of lines in the string */
  +  line_count = o_text_num_lines(string);
  +  
  +  /* 26 is the height of a single char (in mils) */
  +  /* which represents a character which is 2 pts high */
  +  /* So size has to be divided in half */
  +  /* and it's added the LINE_SPACING*character_height of each line */
  +  return(26*size/2*(1+LINE_SPACING*(line_count-1)));
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* You need to divide the size in half here. */
  +/*! \todo FIXME consistancy. */
  +int o_text_width(TOPLEVEL *w_current, char *string, int size) 
  +{
  +  int width=0, max_width=0;
  +  int size_of_tab_in_coord;
  +  OBJECT *o_font_set;
  +  gchar *ptr;
  +  gunichar previous_char;
  +  gunichar c = 0;
  +  if (string == NULL) {
  +    return 0;
  +  }
  +  
  +  /* Make sure TAB_CHAR_MODEL is loaded before trying to use its text */
  +  /* size */
  +  o_font_set = g_hash_table_lookup (
  +    font_loaded, GUINT_TO_POINTER ((gunichar)TAB_CHAR_MODEL[0]));
  +  if (o_font_set == NULL) {
  +    o_text_load_font(w_current, (gunichar) TAB_CHAR_MODEL[0]);
  +    o_font_set = (OBJECT *) g_hash_table_lookup (
  +      font_loaded, GUINT_TO_POINTER ((gunichar)TAB_CHAR_MODEL[0]));
  +  }
  + 
  +  /* Get the maximum tab width's in coordinates */
  +  size_of_tab_in_coord = tab_in_chars * size * o_font_set->font_text_size;
  +
  +  for (ptr = string;
  +       ptr != NULL && *ptr != 0;
  +       ptr = g_utf8_find_next_char (ptr, NULL))
  +  {
  +    previous_char = c;
  +    c = g_utf8_get_char_validated (ptr, -1);
  +
  +    if ( (c == (gunichar) '\\') &&
  +	 (previous_char != (gunichar) '\\') ) {
  +      continue;
  +    }
  +    if ( (c == (gunichar) '_') &&
  +	 (previous_char == (gunichar) '\\') ) {
  +      continue;
  +    }
  +    switch (c) {
  +        case ((gunichar)'\n'):
  +          width = 0;
  +          break;
  +        case ((gunichar)'\t'):
  +          width += (size_of_tab_in_coord - (width % size_of_tab_in_coord));
  +          break;
  +        default:
  +          /* find current_char */
  +          o_font_set = g_hash_table_lookup (font_loaded,
  +                                            GUINT_TO_POINTER (c));
  +          if (o_font_set == NULL) {
  +            o_text_load_font (w_current, (gunichar)c);
  +            /* let do a new search for character c */
  +            o_font_set = g_hash_table_lookup (font_loaded,
  +                                              GUINT_TO_POINTER (c));
  +          }
  +
  +          if (o_font_set != NULL) {
  +            width = width + size*o_font_set->font_text_size;
  +          }
  +
  +          if (width > max_width) {
  +            max_width = width;
  +          }
  +    }
  +  }
  +
  +  /* the size is a fudge factor */
  +  /* Changed the return value according to a suggestion of Ales. */
  +  /* Yes, the -size*10 fudge factor should be removed. */
  +  /* return(max_width - size*10); */
  +  return max_width;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *o_text_create_string(TOPLEVEL *w_current, OBJECT *object_list, 
  +			     char *string, int size, int color, int x, int y,
  +			     int alignment, int angle)
  +{
  +  OBJECT *temp_tail=NULL;
  +  OBJECT *temp_list;
  +  OBJECT *start_of_char;
  +  int x_offset;
  +  int y_offset;
  +  int text_width;
  +  int text_height;
  +  int char_height;
  +  int line_start_x, line_start_y;
  +  int sign=1;
  +  int overbar_startx=0, overbar_starty=0;
  +  int overbar_endx=0, overbar_endy=0;
  +  int overbar_height_offset = 0;
  +  int last_char_width;
  +  gboolean overbar_started = FALSE;
  +  gchar *ptr;
  +  gchar *aux_string;
  +  OBJECT *o_font_set;
  +  gunichar c=0, previous_char = 0, next_char = 0;
  +  int escapes_counter = 0;
  +
  +  temp_list = object_list;
  +
  +
  +  /* error condition hack */
  +  if (string == NULL) {
  +    return(NULL);
  +  }
  +	
  +  /* now read in the chars */
  +  temp_tail = w_current->page_current->object_tail;
  +
  +  text_height = o_text_height(string, size); 
  +  char_height = o_text_height("a", size);
  +  text_width = o_text_width(w_current, string, size/2);
  +
  +  switch(angle) {
  +    case(0):
  +      sign = -1;
  +      break;
  +    case(90):
  +      sign = 1;
  +      break;
  +    case(180):
  +      sign = 1;
  +      break;
  +    case(270):
  +      sign = -1;
  +      break;
  +  }
  +
  +  if (angle == 0 || angle == 180) {
  +    y = y - o_text_height("a", size) + text_height;
  +    
  +    switch(alignment) {
  +
  +      case(LOWER_LEFT):
  +      x_offset = x;
  +      y_offset = y;
  +      break;
  +		
  +      case(MIDDLE_LEFT):
  +      x_offset = x;
  +      y_offset = y + sign*0.5*text_height;
  +      break;
  +	
  +      case(UPPER_LEFT):
  +      x_offset = x;
  +      y_offset = y + sign*text_height;
  +      break;
  +	
  +      case(LOWER_MIDDLE):
  +      x_offset = x + sign*0.5*text_width;
  +      y_offset = y;
  +      break;
  +	
  +      case(MIDDLE_MIDDLE):
  +      x_offset = x + sign*0.5*text_width;
  +      y_offset = y + sign*0.5*text_height;
  +      break;
  +	
  +      case(UPPER_MIDDLE):
  +      x_offset = x + sign*0.5*text_width;
  +      y_offset = y + sign*text_height;
  +	
  +      break;
  +	
  +      case(LOWER_RIGHT):
  +      x_offset = x + sign*text_width;
  +      y_offset = y;
  +      break;
  +	
  +      case(MIDDLE_RIGHT):
  +      x_offset = x + sign*text_width;
  +      y_offset = y + sign*0.5*text_height;
  +      break;
  +	
  +      case(UPPER_RIGHT):
  +      x_offset = x + sign*text_width;
  +      y_offset = y + sign*text_height;
  +      break;
  +
  +      default: 
  +      fprintf(stderr, "Got an invalid text alignment [%d]\n",
  +              alignment); 
  +      fprintf(stderr, "Defaulting to Lower Left");
  +      alignment = LOWER_LEFT;
  +      x_offset = x;
  +      y_offset = y;
  +      break;
  +    }
  +  } else { /* angle is 90 or 270 */
  +    x = x + sign*(o_text_height("a", size) - text_height);
  +
  +    switch(alignment) {
  +
  +      case(LOWER_LEFT):
  +      x_offset = x;
  +      y_offset = y;
  +      break;
  +		
  +      case(MIDDLE_LEFT):
  +      x_offset = x + sign*0.5*text_height;
  +      y_offset = y;
  +      break;
  +	
  +      case(UPPER_LEFT):
  +      x_offset = x + sign*text_height;
  +      y_offset = y;
  +      break;
  +	
  +      case(LOWER_MIDDLE):
  +      x_offset = x;
  +      y_offset = y - sign*0.5*text_width;
  +      break;
  +	
  +      case(MIDDLE_MIDDLE):
  +      x_offset = x + sign*0.5*text_height;
  +      y_offset = y - sign*0.5*text_width;
  +      break;
  +	
  +      case(UPPER_MIDDLE):
  +      x_offset = x + sign*text_height;
  +      y_offset = y - sign*0.5*text_width;
  +	
  +      break;
  +	
  +      case(LOWER_RIGHT):
  +      x_offset = x;
  +      y_offset = y - sign*text_width;
  +      break;
  +	
  +      case(MIDDLE_RIGHT):
  +      x_offset = x + sign*0.5*text_height;
  +      y_offset = y - sign*text_width;
  +      break;
  +	
  +      case(UPPER_RIGHT):
  +      x_offset = x + sign*text_height;
  +      y_offset = y - sign*text_width;
  +      break;
  +
  +      default: 
  +      fprintf(stderr, "Got an invalid text alignment [%d]\n",
  +              alignment); 
  +      fprintf(stderr, "Defaulting to Lower Left");
  +      alignment = LOWER_LEFT;
  +      x_offset = x;
  +      y_offset = y;
  +      break;
  +    }
  +
  +  }
  +
  +  switch(angle) {
  +    case(180):
  +    x_offset = x_offset - text_width;
  +    y_offset = y_offset - text_height;
  +    angle = 0;
  +    break;
  +  }
  +
  +#if DEBUG
  +  printf("width: %d\n", o_text_width(w_current, string, size/2));
  +  printf("1 %d %d\n", x_offset, y_offset);
  +#endif
  +
  +  line_start_x = x_offset;
  +  line_start_y = y_offset;
  +
  +  for (ptr = string;
  +       ptr != NULL && *ptr != 0;
  +       previous_char = 
  +	 g_utf8_get_char_validated (ptr, -1),
  +	 ptr = g_utf8_find_next_char (ptr, NULL),
  +	 next_char = g_utf8_get_char_validated(g_utf8_find_next_char (ptr, NULL),-1)) {
  +    /* Keep track of the previous character and its width.
  +       They will be used in the overbar and escape characters */
  +    aux_string = g_strdup_printf("%c", previous_char);
  +    last_char_width = o_text_width(w_current, aux_string, size/2);
  +    g_free(aux_string);
  +
  +    c = g_utf8_get_char_validated (ptr, -1);
  +
  +    o_font_set = g_hash_table_lookup (font_loaded, GUINT_TO_POINTER (c));
  +    if (o_font_set == NULL) {
  +      o_text_load_font(w_current, (gunichar) c);
  +      o_font_set = g_hash_table_lookup (font_loaded, GUINT_TO_POINTER (c));
  +    }
  +
  +    start_of_char = temp_list;
  +
  +    if (o_font_set->font_prim_objs->next != NULL) {
  +      int rel_char_coord;
  +      int size_of_tab_in_coord;
  +      OBJECT *o_font_set_aux;
  +
  +      /* Make sure TAB_CHAR_MODEL is loaded before trying to use its text */
  +      /* size */
  +      o_font_set_aux = g_hash_table_lookup (
  +        font_loaded, GUINT_TO_POINTER ((gunichar)TAB_CHAR_MODEL[0]));
  +      if (o_font_set_aux == NULL) {
  +         o_text_load_font(w_current, (gunichar) TAB_CHAR_MODEL[0]);
  +         o_font_set_aux = g_hash_table_lookup (
  +           font_loaded, GUINT_TO_POINTER ((gunichar)TAB_CHAR_MODEL[0]));
  +       }
  +    
  +      /* Get the maximum tab width's in coordinates */
  +      size_of_tab_in_coord = tab_in_chars * 
  +                 o_text_width(w_current, TAB_CHAR_MODEL, size/2);
  +
  +      /* Count escape characters. Notice it includes the current character */
  +      if (c == '\\') {
  +	escapes_counter++;
  +      }
  +      
  +      /* Ignore escape characters */
  +      if ( ((c == '\\') && (previous_char != '\\')) ||
  +	   ((c == '\\') && (escapes_counter == 1)) )
  +	continue;
  +
  +      if (c != '\n' && c != '\t') {
  +         /* only add the character if it is not a newline, a tab character
  +	    a escape character or the overbar delimiter escape sequence.
  +	    Add it if it is the escaped escape character */
  +	if ( ( (c != '\\') &&
  +	       (!(previous_char == '\\' && c == '_')) ) ||
  +	     (previous_char == '\\' && c == '\\' && (escapes_counter > 1)) ) {
  +	  temp_list = o_list_copy_all(w_current, 
  +				      o_font_set->font_prim_objs->next, 
  +				      temp_list, NORMAL_FLAG);
  +	  if (start_of_char != NULL)
  +	    start_of_char = start_of_char->next;
  +	  /* does not get here if the character was a newline, tab, or
  +	     special character.
  +	     This is correct. */ 
  +	  o_complex_set_color(start_of_char, color);	
  +	  o_scale(w_current, start_of_char, size/2, size/2);
  +	  
  +	  /* do this if you want to stack chars */
  +	  /* we don't want to do that for now */
  +	  /* Rotate and translate the character to its world position */
  +	  o_text_rotate_lowlevel(w_current, x, y, angle, start_of_char);
  +	  o_complex_world_translate(w_current, 
  +				    x_offset, y_offset, 
  +				    start_of_char);
  +	  
  +	  /* Reset the escapes counter after being processed. Otherwise, 
  +	     if the next character is also a backslash, it will
  +	     be processed as if were also escaped */
  +	  if (previous_char == '\\' && c == '\\') {
  +	    escapes_counter = 0;
  +	  }
  +	} 
  +      }
  +      
  +      /* Now check for special characters */
  +      
  +      if ( (c == '_' && previous_char == '\\') || 
  +	   (c == '\n' && overbar_started) || 
  +	   (previous_char == '\n' && overbar_started) ||
  +	   (overbar_started && next_char == 0) ) { 
  +	/* Found the overbar delimiter sequence 
  +	   If the character is the newline and the overbar was started,
  +	   then end it and start it again in the next character, after
  +	   processing the newline. */
  +	overbar_height_offset = char_height + (char_height >> 2);
  +	if ( (!overbar_started) ||
  +	     (overbar_started && previous_char == '\n') ){
  +	  /* Start point of the overbar */
  +	  overbar_started = TRUE;
  +	  switch (angle) {
  +	    case 0:
  +	      overbar_startx = x_offset;
  +	      overbar_starty = y_offset + overbar_height_offset;
  +	      break;
  +	    case 90:
  +	      overbar_startx = x_offset - overbar_height_offset;
  +	      overbar_starty = y_offset;
  +	      break;
  +	    case 180:
  +	      overbar_startx = x_offset;
  +	      overbar_starty = y_offset - overbar_height_offset;
  +	      break;
  +	    case 270:
  +	      overbar_startx = x_offset + overbar_height_offset;
  +	      overbar_starty = y_offset;
  +	      break;
  +	    default:
  +	      fprintf(stderr, "o_text_create_string: Angle not supported\n");
  +	      break;
  +	  }
  +	} else {
  +	  /* Then this is the end point of the overbar */
  +	  if (overbar_started && next_char == 0 &&
  +	      !(c == '_' && previous_char == '\\')) {
  +	    /* Instead of ending in the last character, end the overbar
  +	       after the current character (its width is 
  +	       size/2*o_font_set->font_text_size */
  +	    last_char_width = -size/2*o_font_set->font_text_size;
  +	  }
  +	  switch (angle) {
  +	    case 0:
  +	      overbar_endx = x_offset - last_char_width;
  +	      overbar_endy = y_offset + overbar_height_offset;
  +	      break;
  +	    case 90:
  +	      overbar_endx = x_offset - overbar_height_offset;
  +	      overbar_endy = y_offset - last_char_width;
  +	      break;
  +	    case 180:
  +	      overbar_endx = x_offset + last_char_width;
  +	      overbar_endy = y_offset - overbar_height_offset;
  +	      break;
  +	    case 270:
  +	      overbar_endx = x_offset + overbar_height_offset;
  +	      overbar_endy = y_offset + last_char_width;
  +	      break;
  +	    default:
  +	      fprintf(stderr, "o_text_create_string: Angle not supported\n");
  +	      break;
  +	  }
  +	  /* Now add the overbar (if it is not a zero length overbar) */
  +	  if ( (overbar_startx != overbar_endx) ||
  +	       (overbar_starty != overbar_endy) ) {
  +	    temp_list = o_line_add(w_current, temp_list, OBJ_LINE, color,
  +				   overbar_startx, overbar_starty,
  +				   overbar_endx, overbar_endy);
  +	  }
  +
  +	  if (!((c == '\n') && (overbar_started))) {
  +	    /* If it's the newline character, keep the overbar started, since
  +	       we have to end this one & start another one in the next line */
  +	    overbar_started = FALSE;
  +	  }
  +	}
  +	if (c != '\n')
  +	  continue;
  +      }
  +     
  +      /* If the character is a newline or tab, this code will "continue" */
  +      switch (c) {
  +      case '\n':
  +	/* The character is a newline. Calcule the start of the next line */
  +        switch (angle) {
  +            case 0:
  +              x_offset = line_start_x;
  +              y_offset = line_start_y - char_height * LINE_SPACING;
  +              line_start_x = x_offset;
  +              line_start_y = y_offset;
  +              continue;	
  +              break;
  +            case 90:
  +              x_offset = line_start_x + char_height * LINE_SPACING;
  +              y_offset = line_start_y;
  +              line_start_x = x_offset;
  +              line_start_y = y_offset;
  +              continue;	
  +              break;
  +            case 180:
  +              x_offset = line_start_x;
  +              y_offset = line_start_y + char_height * LINE_SPACING;
  +              line_start_x = x_offset;
  +              line_start_y = y_offset;
  +              continue;	
  +              break;
  +            case 270:
  +              x_offset = line_start_x - char_height * LINE_SPACING;
  +              y_offset = line_start_y;
  +              line_start_x = x_offset;
  +              line_start_y = y_offset;
  +              continue;	
  +              break;
  +            default:
  +              fprintf(stderr, "o_text_create_string: Angle not supported\n");
  +              break;
  +        }
  +          case '\t':
  +#if DEBUG
  +            printf("Found tab character.\n");
  +            printf("Tab size in coord: %i\n", size_of_tab_in_coord);
  +            printf("Line start: %i,%i\n", line_start_x, line_start_y);
  +            printf("Position: %i, %i\n", x_offset, y_offset);
  +#endif
  +            switch (angle) {
  +                case 0:
  +                case 180:
  +                  rel_char_coord = x_offset - line_start_x;
  +#if DEBUG
  +                  printf("Add: %i\n", (size_of_tab_in_coord - (rel_char_coord % size_of_tab_in_coord)));
  +#endif
  +                  x_offset += (size_of_tab_in_coord - (rel_char_coord % size_of_tab_in_coord));
  +                  continue;	
  +                  break;
  +                case 90:
  +                  rel_char_coord = y_offset - line_start_y;
  +#if DEBUG
  +                  printf("Add: %i\n", (size_of_tab_in_coord - (rel_char_coord % size_of_tab_in_coord)));
  +#endif
  +                  y_offset += (size_of_tab_in_coord - (rel_char_coord % size_of_tab_in_coord));
  +                  continue;	
  +                  break;
  +                case 270:
  +                  rel_char_coord = line_start_y - y_offset;
  +#if DEBUG
  +                  printf("Add: %i\n", (size_of_tab_in_coord - (rel_char_coord % size_of_tab_in_coord)));
  +#endif
  +                  y_offset -= (size_of_tab_in_coord - (rel_char_coord % size_of_tab_in_coord));
  +                  continue;	
  +                  break;
  +                default:
  +                  fprintf(stderr, "o_text_create_string: Angle not supported\n");
  +                  break;
  +            }
  +      }      
  +    }
  +
  +    /* Calcule the position of the next character */
  +    switch(angle) {
  +      case(0):	
  +        x_offset = (x_offset) + 
  +          size/2*o_font_set->font_text_size;
  +        break;
  +		
  +      case(90):
  +        y_offset = (y_offset) + 
  +          size/2*o_font_set->font_text_size;
  +        break;
  +
  +      case(180):
  +        x_offset = (x_offset) - 
  +          size/2*o_font_set->font_text_size;
  +        break;
  +		
  +      case(270):
  +        y_offset = (y_offset) - 
  +          size/2*o_font_set->font_text_size;
  +        break;
  +    }
  +  }
  +
  +  /* don't set the head */	
  +
  +  w_current->page_current->object_tail = temp_tail;
  +
  +#if DEBUG
  +  printf("2 %d %d\n", x_offset, y_offset);
  +#endif
  +  return(object_list);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *o_text_add(TOPLEVEL *w_current, OBJECT *object_list, 
  +		   char type, int color, int x, int y, int alignment,
  +		   int angle, char *string, int size, 
  +		   int visibility, int show_name_value)
  +{
  +  OBJECT *new_node=NULL;
  +  OBJECT *temp_list=NULL;
  +  OBJECT *temp_parent=NULL;
  +  TEXT *text;
  +  int left, right, top, bottom;
  +  char *name = NULL;
  +  char *value = NULL; 
  +  char *output_string = NULL;
  +
  +  if (string == NULL) {
  +    return(NULL);
  +  }
  +
  +  new_node = s_basic_init_object("text");
  +  new_node->type = type;
  +
  +  text = (TEXT *) malloc(sizeof(TEXT));
  +
  +  text->string = g_strdup (string);
  +  text->length = strlen(string);
  +  text->size = size;
  +  text->alignment = alignment;
  +  text->x = x;
  +  text->y = y;
  +  WORLDtoSCREEN(w_current, x, y, &text->screen_x, &text->screen_y);
  +  text->angle = angle;
  +
  +  new_node->text = text;
  +
  +  /* \todo questionable cast */
  +  new_node->draw_func = (void *) text_draw_func;  
  +  /* \todo questionable cast */
  +  new_node->sel_func = (void *) select_func;  
  +
  +  new_node->color = color;
  +  new_node->visibility = visibility; 
  +  new_node->show_name_value = show_name_value;
  +
  +  /* create the object in the main list */
  +  /* object_list points to the object */
  +  /* I use it below as a sanity check to make sure it was linked */
  +  /* properly */ 
  +  object_list = (OBJECT *) s_basic_link_object(new_node, object_list);
  +
  +  /* fix up actual string here */ 
  +  if (o_attrib_get_name_value(string, &name, &value)) {
  +
  +    switch(show_name_value) {
  +      case(SHOW_NAME_VALUE):
  +        output_string = g_strdup(string);
  +        break;
  +
  +      case(SHOW_NAME):
  +        if (name[0] != '\0') {
  +          output_string = g_strdup(name);
  +        } else {
  +          /* you probably can remove this now... */
  +          /* since improper attributes will never get here */
  +          fprintf(stderr, 
  +                  "Got an improper attribute: %s\n", 
  +                  string);
  +          output_string = g_strdup("invalid");
  +
  +        }
  +        break;
  +
  +      case(SHOW_VALUE):
  +        if (value[0] != '\0') {
  +          output_string = g_strdup (value);
  +        } else {
  +          /* you probably can remove this now... */
  +          /* since improper attributes will never get here */
  +          fprintf(stderr, 
  +                  "Got an improper attribute: %s\n", 
  +                  string);
  +          output_string = g_strdup("invalid");
  +        }
  +        break;
  +    }
  +  } else {
  +    output_string = g_strdup(string);
  +  }
  +
  +
  +  /* now start working on the complex */
  +  temp_list = o_text_add_head();
  +
  +  temp_parent = w_current->page_current->object_parent;
  +  /* set the addition of attributes to the head node */
  +  w_current->page_current->object_parent = temp_list;
  +
  +  if (visibility == VISIBLE ||
  +      (visibility == INVISIBLE && w_current->show_hidden_text)) {
  +    object_list->text->prim_objs = 
  +      o_text_create_string(w_current, temp_list, 
  +                           output_string, size, color,
  +                           x, y, alignment, angle); 
  +    object_list->text->displayed_width = o_text_width(w_current,
  +                                                      output_string, size/2);
  +    object_list->text->displayed_height = o_text_height(output_string, size);
  +  } else {
  +    object_list->text->prim_objs = NULL;
  +    object_list->text->displayed_width = 0;
  +    object_list->text->displayed_height = 0;
  +    s_delete(w_current, temp_list);
  +  }
  +
  +  w_current->page_current->object_parent = temp_parent;
  +
  +  get_text_bounds(w_current, object_list, &left, &top, &right, &bottom);
  +
  +  /* set the new object's bounding box */
  +  object_list->left = left;
  +  object_list->top = top;
  +  object_list->right = right;
  +  object_list->bottom = bottom;
  +
  +  if (name) free(name);
  +  if (value) free(value);
  +  if (output_string) free(output_string);
  +  return(object_list);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_recalc(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int left, right, top, bottom;
  +
  +  if (o_current->visibility == INVISIBLE && !w_current->show_hidden_text) {
  +    return;
  +  }
  +
  +  get_complex_bounds(w_current, o_current->text->prim_objs, 
  +                     &left, &top, &right, &bottom);
  +  o_current->left = left;
  +  o_current->top = top;
  +  o_current->right = right;
  +  o_current->bottom = bottom;
  +
  +  WORLDtoSCREEN(w_current, o_current->text->x,
  +                o_current->text->y,
  +                &o_current->text->screen_x,
  +                &o_current->text->screen_y);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *o_text_read(TOPLEVEL *w_current, OBJECT *object_list,
  +		    char buf[], FILE *fp, unsigned int release_ver,
  +		    unsigned int fileformat_ver)
  +{
  +  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) {
  +    sscanf(buf, "%c %d %d %d %d %d %d %d %d %d\n", &type, &x, &y, 
  +           &color, &size,
  +           &visibility, &show_name_value, 
  +           &angle, &alignment, &num_lines);	
  +  } else if (release_ver < VERSION_20000220) {
  +    /* yes, above less than (not less than and equal) is correct. The format */
  +    /* change occurred in 20000220 */
  +    sscanf(buf, "%c %d %d %d %d %d %d %d\n", &type, &x, &y, 
  +           &color, &size,
  +           &visibility, &show_name_value, 
  +           &angle);	
  +    alignment = LOWER_LEFT; /* older versions didn't have this */
  +    num_lines = 1; /* only support a single line */
  +  } else {
  +    sscanf(buf, "%c %d %d %d %d %d %d %d %d\n", &type, &x, &y, 
  +           &color, &size,
  +           &visibility, &show_name_value, 
  +           &angle, &alignment);	
  +    num_lines = 1; /* only support a single line */
  +  }
  +
  +  if (size == 0) {
  +    fprintf(stderr, "Found a zero size text string [ %c %d %d %d %d %d %d %d %d ]\n", type, x, y, color, size, visibility, show_name_value, angle, alignment);
  +    s_log_message("Found a zero size text string [ %c %d %d %d %d %d %d %d %d ]\n", type, x, y, color, size, visibility, show_name_value, angle, alignment);
  +  }
  +
  +  switch(angle) {
  +	
  +    case(0):
  +    case(90):
  +    case(180):
  +    case(270):
  +    break;
  +
  +    default:
  +    fprintf(stderr, "Found an unsupported text angle [ %c %d %d %d %d %d %d %d %d ]\n", type, x, y, color, size, visibility, show_name_value, angle, alignment);
  +    s_log_message("Found an unsupported text angle [ %c %d %d %d %d %d %d %d %d ]\n", type, x, y, color, size, visibility, show_name_value, angle, alignment);
  +    s_log_message("Setting angle to 0\n");
  +    angle=0;
  +    break;
  +
  +  }
  +
  +  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:
  +    fprintf(stderr, "Found an unsupported text alignment [ %c %d %d %d %d %d %d %d %d ]\n", type, x, y, color, size, visibility, show_name_value, angle, alignment);
  +    s_log_message("Found an unsupported text alignment [ %c %d %d %d %d %d %d %d %d ]\n", type, x, y, color, size, visibility, show_name_value, angle, alignment);
  +    s_log_message("Setting alignment to LOWER_LEFT\n");
  +    alignment = LOWER_LEFT; 
  +    break;
  +  }
  +
  +  if (color < 0 || color > MAX_COLORS) {
  +    fprintf(stderr, "Found an invalid color [ %s ]\n", buf);
  +    s_log_message("Found an invalid color [ %s ]\n", buf);
  +    s_log_message("Setting color to WHITE\n");
  +    color = WHITE;
  +  }
  +
  +  assert(num_lines && num_lines > 0);
  +
  +  textstr = g_string_new ("");
  +  for (i = 0; i < num_lines; i++) {
  +    gchar buffer[MAX_TEXT_LINE_LENGTH];
  +    
  +    fgets (buffer, MAX_TEXT_LINE_LENGTH, fp);
  +
  +    textstr = g_string_append (textstr, buffer);
  +  }
  +  /* retrieve the character string from the GString */
  +  string = g_string_free (textstr, FALSE);
  +
  +  string = remove_last_nl(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: %s.\n",
  +               string);
  +    } else {
  +      /* successfully converted string, now use tmp as string */
  +      g_free (string);
  +      string = tmp;
  +    }
  +  }
  +  
  +  object_list = o_text_add(w_current, object_list, type, color, x, y, 
  +                           alignment, angle, string, 
  +                           size, visibility, show_name_value);
  +  g_free(string);
  +
  +  return(object_list);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_set_info_font(char buf[])
  +{
  +  char type; 
  +  int width;
  +  gunichar character=0;
  +  gchar *buf_ptr;
  +  int special=0;
  +  char *string; 
  +  OBJECT *o_font_set;
  +
  +  string = remove_nl (buf);	
  +
  +  /* parse the font info: */
  +  buf_ptr = (gchar*)string;
  +  /*   - type */
  +  type = *buf_ptr++;
  +  g_assert (type == INFO_FONT);
  +  while (buf_ptr != NULL && *buf_ptr == ' ') buf_ptr++;
  +  /*   - character */
  +  if (buf_ptr != NULL && *buf_ptr != '\0') {
  +    character = g_utf8_get_char_validated (buf_ptr, -1);
  +    if (character == (gunichar)-1) {
  +      s_log_message (
  +        "Failed to validate utf-8 character in font definition: \"%s\".\n",
  +        string);
  +      return;
  +    }
  +    /* move buf_ptr just after character */
  +    buf_ptr = g_utf8_find_next_char (buf_ptr, NULL);
  +  }
  +  while (buf_ptr != NULL && *buf_ptr == ' ') buf_ptr++;
  +  /*   - width and special */
  +  if (buf_ptr != NULL) {
  +    sscanf (buf_ptr, "%d %d\n", &width, &special);
  +  }
  +
  +  /* deal with special characters */
  +  if (special == 1) {
  +    switch (character) {
  +      case ((gunichar)'_'):
  +      /* space */
  +      character = (gunichar)' ';
  +      break;
  +      case ((gunichar)'n'):
  +      /* newline */
  +      character = (gunichar)'\n';
  +      break;
  +    }
  +  }
  +
  +  o_font_set = g_hash_table_lookup (font_loaded,
  +                                    GUINT_TO_POINTER ((gunichar)character));
  +  if (o_font_set != NULL) {
  +    o_font_set->font_text_size = width;
  +  } else {
  +    gchar outbuf[7];
  +    gint l = g_unichar_to_utf8 (character, outbuf);
  +    outbuf[l] = '\0';
  +    fprintf(stderr,
  +            "o_text_set_info_font: character %s not found!!!\n", outbuf);
  +  }
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +char *o_text_save(OBJECT *object)
  +{
  +  int x, y;
  +  int color;
  +  int size;
  +  char *string;
  +  char *buf;
  +  int num_lines;
  +
  +  x = object->text->x;
  +  y = object->text->y;
  +
  +  string = object->text->string;
  +  size = object->text->size;
  +
  +  /* Use the right color */
  +  if (object->saved_color == -1) {
  +    color = object->color;
  +  } else {
  +    color = object->saved_color;
  +  }
  +
  +  /* string can have multiple lines (seperated by \n's) */
  +  num_lines = o_text_num_lines(string);
  +
  +  buf = g_strdup_printf("%c %d %d %d %d %d %d %d %d %d\n%s", object->type,
  +                        x, y, color, size, object->visibility, 
  +			object->show_name_value, object->text->angle, 
  +			object->text->alignment, num_lines, string);
  +
  +  return(buf);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_recreate(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  OBJECT *temp_parent;
  +  char *name = NULL;
  +  char *value = NULL;
  +  char *output_string = NULL;
  +
  +  if (o_attrib_get_name_value(o_current->text->string, &name, &value)) {
  +    switch(o_current->show_name_value) {
  +      case(SHOW_NAME_VALUE):
  +        output_string = g_strdup(o_current->text->string);
  +        break;
  +
  +      case(SHOW_NAME):
  +        if (name[0] != '\0') {
  +          output_string = g_strdup(name);
  +        } else {
  +          /* you probably can remove this now... */
  +          /* since improper attributes will never get here */
  +          fprintf(stderr, 
  +                  "Got an improper attribute: %s\n", 
  +                  o_current->text->string);
  +          output_string = g_strdup("invalid");
  +        }
  +        break;
  +
  +      case(SHOW_VALUE):
  +        if (value[0] != '\0') {
  +          output_string = g_strdup(value);
  +        } else {
  +          /* you probably can remove this now... */
  +          /* since improper attributes will never get here */
  +          fprintf(stderr, 
  +                  "Got an improper attribute: %s\n", 
  +                  o_current->text->string);
  +          output_string = g_strdup("invalid");
  +        }
  +        break;
  +    }
  +  } else {
  +    output_string = g_strdup(o_current->text->string);
  +  }
  +
  +  o_list_delete_rest(w_current, o_current->text->prim_objs);
  +
  +  temp_parent = w_current->page_current->object_parent;
  +  /* set the addition of attributes to the head node */
  +  w_current->page_current->object_parent = o_current->text->prim_objs;
  +
  +  if (o_current->visibility == VISIBLE ||
  +      (o_current->visibility == INVISIBLE && w_current->show_hidden_text)) {
  +
  +    /* need to create that head node if complex is null */
  +    if (o_current->text->prim_objs == NULL) {
  +      o_current->text->prim_objs = o_text_add_head();
  +    }
  +
  +    o_current->text->prim_objs = 
  +      o_text_create_string(w_current, 
  +                           o_current->text->prim_objs, 
  +                           output_string, 
  +                           o_current->text->size, 
  +                           o_current->color, 
  +                           o_current->text->x, 
  +                           o_current->text->y,
  +                           o_current->text->alignment,
  +                           o_current->text->angle); 
  +
  +    o_complex_set_saved_color_only(o_current->text->prim_objs, 
  +                                   o_current->saved_color);
  +    o_current->text->displayed_width = o_text_width(w_current,
  +                                                    output_string,
  +                                                    o_current->text->size/2);
  +    o_current->text->displayed_height = o_text_height(output_string,
  +                                                      o_current->text->size);
  +  } else {
  +    /* make sure list is truely free */
  +    s_delete_list_fromstart(w_current, o_current->text->prim_objs);
  +    o_current->text->prim_objs = NULL;
  +    o_current->text->displayed_width = 0;
  +    o_current->text->displayed_height = 0;
  +  }
  +
  +  w_current->page_current->object_parent = temp_parent;
  +  if (name) free(name);
  +  if (value) free(value);
  +  if (output_string) free(output_string);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_translate_world(TOPLEVEL *w_current,
  +			    int x1, int y1, OBJECT *o_current)
  +{
  +  int screen_x, screen_y;
  +  int left, right, top, bottom;
  +	
  +	
  +  o_current->text->x = o_current->text->x + x1;
  +  o_current->text->y = o_current->text->y + y1;
  +			
  +  /* update screen coords */
  +  WORLDtoSCREEN(w_current, o_current->text->x, o_current->text->y, 
  +                &screen_x, &screen_y);
  +
  +  o_current->text->screen_x = screen_x;
  +  o_current->text->screen_y = screen_y;
  +						
  +  o_complex_world_translate(w_current, x1, y1, o_current->text->prim_objs);
  +
  +  /* update bounding box */
  +  /* do it */
  +  get_text_bounds(w_current, o_current, &left, &top, &right, &bottom);
  +
  +  o_current->left = left;
  +  o_current->top = top;
  +  o_current->right = right;
  +  o_current->bottom = bottom;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *o_text_copy(TOPLEVEL *w_current, OBJECT *list_tail, OBJECT *o_current)
  +{
  +  OBJECT *new_obj;
  +  int color;
  +
  +  if (o_current->saved_color == -1) {
  +    color = o_current->color;
  +  } else {
  +    color = o_current->saved_color;
  +  }
  +
  +  new_obj = o_text_add(w_current, list_tail, OBJ_TEXT, 
  +                       color, 
  +                       o_current->text->x, o_current->text->y, 
  +                       o_current->text->alignment, 
  +                       o_current->text->angle,
  +                       o_current->text->string, 
  +                       o_current->text->size, 
  +                       o_current->visibility, 
  +                       o_current->show_name_value); 
  +
  +  return(new_obj);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static gboolean delete_font_set (gpointer key, gpointer value,
  +				 gpointer user_data)
  +{
  +  OBJECT *tmp = (OBJECT*)value;
  +  TOPLEVEL *toplevel = (TOPLEVEL*)user_data;
  +
  +  if (tmp != NULL) {
  +    if (tmp->font_prim_objs != NULL) {
  +      s_delete_list_fromstart (toplevel, tmp->font_prim_objs);
  +      tmp->font_prim_objs = NULL;
  +    }
  +    /* do not use s_delete() as tmp is not fully initialized */
  +    g_free (tmp->name);
  +
  +    /* Do not free tmp here since it will be freed with the function */
  +    /* that was specified when the hash table was created. */
  +  }
  +
  +  return TRUE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_freeallfonts(TOPLEVEL *w_current)
  +{
  +  /* destroy the char-to-objects hastable */
  +  g_hash_table_foreach_remove (font_loaded,
  +                               delete_font_set,
  +                               w_current);
  +  g_hash_table_destroy (font_loaded);
  +  font_loaded = NULL;
  +
  +  /* destroy the font-to-filename hashtable */
  +  g_hash_table_destroy (font_char_to_file);
  +  font_char_to_file = NULL;
  + 
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_print_text_width(FILE *fp, char *output_string)
  +{
  +  int len, i, j;
  +  int starting_character = 0;
  +  int num_lines, line_number;
  +  int max_len = -1;
  +  char *single_line = NULL;
  +  char *max_length_line = NULL;
  +  int single_len;
  +
  +  /* break up the string and find the longest string */
  +  num_lines = o_text_num_lines(output_string);
  +  single_line = g_strdup (output_string);  /* larger than needed */
  +  len = strlen(output_string);
  +  for (line_number = 0; line_number < num_lines; line_number++)
  +  {
  +    j = 0;
  +    /* break up the string into lines */
  +    for (i = starting_character; i < len; i++)
  +    {
  +      if (output_string[i] != '\n' && output_string[i] != '\0')
  +      {
  +        single_line[j] = output_string[i];
  +      }
  +      else
  +      {
  +        starting_character = i + 1;
  +        break;
  +      }
  +      j++;
  +    }
  +    single_line[j] = '\0';
  +
  +    single_len = strlen(single_line);
  +    if (single_len > max_len)
  +    {
  +      max_len = strlen(single_line);
  +      if (max_length_line) free(max_length_line);
  +      max_length_line = g_strdup (single_line);
  +    }
  +  }
  +
  +
  +  fprintf(fp, "(");
  +  len = strlen(max_length_line);
  +  for (i = 0 ; i < len; i++) {  
  +    if (max_length_line[i] == '(' || max_length_line[i] == ')' || max_length_line[i] == '\\' ) {
  +      fprintf(fp, "\\");
  +    }
  +
  +    fprintf(fp, "%c", max_length_line[i]);
  +  }
  +
  +  /* convert width to mils */
  +  /* .95 is a fudge factor */
  +  fprintf(fp, ") stringwidth pop\n");
  +
  +  if (single_line) free(single_line);
  +  if (max_length_line) free(max_length_line);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_print_text_height(FILE *fp, int size)
  +{
  +  fprintf(fp, "%f\n", (float) size);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_print_text_height_full(FILE *fp, char *string, int size)
  +{
  +  int num_lines = o_text_num_lines(string);
  +  fprintf(fp, "%f\n", (float) (size*num_lines + 
  +          size * LINE_SPACING * (num_lines - 1)));
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_print_text_string(FILE *fp, char *string, int unicode_count, 
  +			      gunichar *unicode_table)
  +{
  +  int len, j;
  +  gchar *aux;
  +  gunichar current_char, c;
  +
  +  if (!string)
  +  {
  +    return;
  +  }
  +
  +  aux = string;
  +  len = g_utf8_strlen(string, -1);
  +  
  +  fprintf(fp, "(");
  +
  +  while (aux && ((gunichar) (*aux) != 0)) {
  +    current_char = g_utf8_get_char_validated(aux, -1);
  +    if (current_char == '(' || current_char == ')' || current_char == '\\') {
  +      fprintf(fp, "\\");
  +    }
  +  
  +    c = current_char;
  +    if (c >= 128) {
  +      current_char = '?';
  +      if (unicode_count)  {
  +        for (j = 0; j < unicode_count; j++)
  +          if (c == unicode_table[j]) {
  +	    current_char = j + 128;
  +            break;
  +          }
  +      }
  +    }
  +    fprintf(fp, "%c", current_char);
  +    aux = g_utf8_find_next_char(aux, NULL);
  +  }
  +
  +  fprintf(fp,") ");
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_print(TOPLEVEL *w_current, FILE *fp, OBJECT *o_current, 
  +		  int origin_x, int origin_y, 
  +		  int unicode_count, gunichar *unicode_table)
  +{
  +  char *centering_control = NULL;
  +  char *p,*s;
  +  char *output_string = NULL;
  +  char *name = NULL;
  +  char *value = NULL;
  +  int x, y, angle, len, char_height;
  +  float font_size;
  +
  +  if (!o_current->text->string) {
  +    return;
  +  }
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, o_current->color);
  +  }
  +
  +
  +  if (o_attrib_get_name_value(o_current->text->string, &name, &value)) {
  +    switch(o_current->show_name_value) {
  +      case(SHOW_NAME_VALUE):
  +        output_string = g_strdup(o_current->text->string);
  +        break;
  +
  +      case(SHOW_NAME):
  +        if (name[0] != '\0') {
  +          output_string = g_strdup(name);
  +        } else {
  +          fprintf(stderr, 
  +                  "Got an improper attribute: %s\n", 
  +                  o_current->text->string);
  +          output_string = g_strdup("invalid");
  +        }
  +        break;
  +
  +      case(SHOW_VALUE):
  +        if (value[0] != '\0') {
  +          output_string = g_strdup(value);
  +        } else {
  +          /* you probably can remove this now... */
  +          /* since improper attributes will never get here */
  +          fprintf(stderr, 
  +                  "Got an improper attribute: %s\n", 
  +                  o_current->text->string);
  +          output_string = g_strdup("invalid");
  +        }
  +        break;
  +    }
  +  } else {
  +    output_string = g_strdup(o_current->text->string);
  +  }
  +
  +
  +  /* Create an appropriate control string for the centering. */
  +  switch(o_current->text->alignment) {
  +                                       /* hcenter rjustify vcenter vjustify */
  +  case(LOWER_LEFT):    centering_control = "false false false false";
  +    break;
  +  case(MIDDLE_LEFT):   centering_control = "false false true false";
  +    break;
  +  case(UPPER_LEFT):    centering_control = "false false false true";
  +    break;
  +  case(LOWER_MIDDLE):  centering_control = "true false false false";
  +    break;
  +  case(MIDDLE_MIDDLE): centering_control = "true false true false";
  +    break;
  +  case(UPPER_MIDDLE):  centering_control = "true false false true";
  +    break;
  +  case(LOWER_RIGHT):   centering_control = "false true false false";
  +    break;
  +  case(MIDDLE_RIGHT):  centering_control = "false true true false";
  +    break;
  +  case(UPPER_RIGHT):   centering_control = "false true false true";
  +    break;
  +  }
  +
  +  char_height = o_text_height("a", o_current->text->size);
  +  fprintf(fp,"%s %f [",centering_control,(float)(char_height*LINE_SPACING));
  +
  +  /* split the line at each newline and print them */
  +  p = output_string;   /* Current point */
  +  s = output_string;   /* Start of the current string */
  +  len = strlen(output_string)+1;
  +  while(len != 0) {
  +    /* Have we reached the end of a line? */
  +    if((*p == '\n') || (*p == '\0')) {
  +      /* Yes, replace the newline with a NULL and output the string */
  +      *p = '\0';
  +      o_text_print_text_string(fp,s,unicode_count,unicode_table);
  +      /* Update output string start for next string */
  +      s = p+1; /* One past the current character. */
  +    }
  +    p++;   /* Advance to next character */
  +    len--; /* Keep track of how many characters left to process */
  +  }
  +
  +  /* Finish up with the rest of the text print command */
  +  /* Collect pertinent info about the text location */
  +  x = o_current->text->x;
  +  y = o_current->text->y;
  +  angle = o_current->text->angle; 
  +  font_size = (float) o_current->text->size/72.0*1000.0;
  +  fprintf(fp,"] %d %d %d %f text\n",angle,x,y,font_size);
  +
  +  
  +  if (output_string) free(output_string);
  +  if (name) free(name);
  +  if (value) free(value);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* takes world coords as the center point as well as a true angle */
  +void o_text_rotate_lowlevel(TOPLEVEL *w_current, int world_centerx,
  +			    int world_centery, int angle, OBJECT *object)
  +{
  +  OBJECT *o_current=NULL;
  +
  +  /* translate object to origin */
  +  /* o_text_translate_world(w_current, -world_centerx, -world_centery, object);*/
  +
  +  /* rotate_point_90(object->text->x, object->text->y, &newx, &newy);*/
  +	
  +  /* o_text_translate_world(w_current, world_centerx, world_centery, object);*/
  +	
  +  o_current = object;
  +
  +  while ( o_current != NULL ) {
  +    switch(o_current->type) {
  +      case(OBJ_LINE):
  +        o_line_rotate_world(w_current, 0, 0, angle, o_current);
  +        break;
  +    }
  +    o_current=o_current->next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_rotate_world(TOPLEVEL *w_current,
  +			 int world_centerx, int world_centery,
  +			 int angle, int angle_change, OBJECT *object)
  +{
  +  int newx, newy;
  +  int origx, origy;
  +  int x, y;
  +	
  +  origx = object->text->x;
  +  origy = object->text->y;
  +
  +  object->text->angle = ( object->text->angle + angle_change ) % 360;
  +
  +#if DEBUG 
  +  printf("rotating text angle: %d\n", angle);
  +  printf("rotating text angle_change: %d\n", angle_change);
  +  printf("final text angle: %d\n",  object->text->angle);
  +#endif
  +
  +  x = origx + (-world_centerx);
  +  y = origy + (-world_centery);
  +	
  +  rotate_point_90(x, y, angle_change, &newx, &newy);
  +
  +  x = newx + (world_centerx);
  +  y = newy + (world_centery);
  +	
  +  o_text_translate_world(w_current, x-object->text->x, y-object->text->y, object);
  +
  +  o_text_recreate(w_current, object);
  +}
  +
  +void o_text_rotate(TOPLEVEL *w_current, int centerx, int centery, int angle,
  +		   int angle_change, OBJECT *object)
  +{
  +  int newx, newy;
  +  int origx, origy;
  +  int world_centerx, world_centery;
  +  int x, y;
  +	
  +  SCREENtoWORLD(w_current, centerx, centery,
  +                &world_centerx,
  +                &world_centery);
  +	
  +
  +  origx = object->text->x;
  +  origy = object->text->y;
  +
  +  object->text->angle = angle;
  +
  +  x = origx + (-world_centerx);
  +  y = origy + (-world_centery);
  +	
  +  rotate_point_90(x, y, angle_change, &newx, &newy);
  +
  +  x = newx + (world_centerx);
  +  y = newy + (world_centery);
  +	
  +  o_text_translate_world(w_current, x-object->text->x, y-object->text->y, object);
  +
  +  o_text_recreate(w_current, object);
  +}
  +
  +#if 0 /* code which is no longer needed, replaced by new functions below */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_mirror_old(TOPLEVEL *w_current, int centerx, int centery,
  +		       OBJECT *object)
  +{
  +  int newx=0, newy=0;
  +  int origx, origy;
  +  int world_centerx, world_centery;
  +  int x, y;
  +  char *output_string = NULL;
  +  char *name = NULL;
  +  char *value = NULL;
  +  int height_mod=0;
  +  int sign=1;
  +	
  +  SCREENtoWORLD(w_current, centerx, centery,
  +                &world_centerx,
  +                &world_centery);
  +
  +  origx = object->text->x;
  +  origy = object->text->y;
  +
  +  x = origx + (-world_centerx);
  +  y = origy + (-world_centery);
  +
  +  if (o_attrib_get_name_value(object->text->string, &name, &value)) {
  +    switch(object->show_name_value) {
  +      case(SHOW_NAME_VALUE):
  +        output_string = g_strdup(object->text->string);
  +        break;
  +
  +      case(SHOW_NAME):
  +        if (name[0] != '\0') {
  +          output_string = g_strdup(name);
  +        } else {
  +          /* you probably can remove this now... */
  +          /* since improper attributes will never get here */
  +          fprintf(stderr, 
  +                  "Got an improper attribute: %s\n", 
  +                  object->text->string);
  +          output_string = g_strdup("invalid");
  +        }
  +        break;
  +
  +      case(SHOW_VALUE):
  +        if (value[0] != '\0') {
  +          output_string = g_strdup(value);
  +        } else {
  +          /* you probably can remove this now... */
  +          /* since improper attributes will never get here */
  +          fprintf(stderr, 
  +                  "Got an improper attribute: %s\n", 
  +                  object->text->string);
  +          output_string = g_strdup("invalid");
  +        }
  +        break;
  +    }
  +  } else {
  +    output_string = g_strdup(object->text->string);
  +  }
  +
  +  switch(object->text->alignment) {
  +    case(LOWER_LEFT):
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = 1;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      height_mod = 0;
  +    }
  +    break;
  +
  +    case(MIDDLE_LEFT):
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = 1;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      height_mod = o_text_height(object->text->string,
  +                                 object->text->size);
  +    }
  +    break;
  +
  +    case(UPPER_LEFT):
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = 1;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      height_mod = 2*o_text_height(object->text->string,
  +                                   object->text->size);
  +    }
  +    break;
  +
  +    case(LOWER_MIDDLE):
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = 0.5;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      sign = 1;
  +      height_mod = 0;
  +    }
  +    break;
  +
  +    case(MIDDLE_MIDDLE): 
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = 0.5;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      sign = 1;
  +      height_mod = o_text_height(object->text->string,
  +                                 object->text->size);
  +    }
  +    break;
  +
  +    case(UPPER_MIDDLE): 
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = 0.5;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      sign = 1;
  +      height_mod = 2*o_text_height(object->text->string,
  +                                   object->text->size);
  +    }
  +    break;
  +
  +    case(LOWER_RIGHT):
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = -1;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      sign = 1;
  +      height_mod = 0;
  +    }
  +    break;
  +
  +    case(MIDDLE_RIGHT):
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = -1;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      sign = 1;
  +      height_mod = o_text_height(object->text->string,
  +                                 object->text->size);
  +    }
  +    break;
  +
  +    case(UPPER_RIGHT):
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = -1;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      sign = 1;
  +      height_mod = 2*o_text_height(object->text->string,
  +                                   object->text->size);
  +    }
  +    break;
  +  }
  +
  +  switch (object->text->angle) {
  +
  +    case(0): 
  +    newx = -(x + sign*o_text_width(w_current, 
  +                                   output_string, 
  +                                   object->text->size/2)); 
  +    break;
  +
  +    case(90):
  +    newx = -(x - sign*o_text_height(object->text->string,
  +                                    object->text->size)+
  +             height_mod);
  +    break;
  +
  +    case(180):
  +    newx = -(x - sign*o_text_width(w_current,
  +                                   output_string, 
  +                                   object->text->size/2)); 
  +    break;
  +
  +    case(270):
  +    newx = -(x + sign*o_text_height(object->text->string,
  +                                    object->text->size)-
  +             height_mod);
  +    break;
  +
  +
  +    default:
  +    fprintf(stderr, "Invalid angle specified!\n");
  +    return;
  +    break;
  +
  +  }
  +
  +  newy = y;
  +
  +  x = newx + (world_centerx);
  +  y = newy + (world_centery);
  +	
  +  /* don't know if this is needed? */	
  +  o_text_translate_world(w_current, x-object->text->x, y-object->text->y, object);
  +
  +  o_text_recreate(w_current, object);
  +  if (output_string) free(output_string);
  +  if (name) free(name);
  +  if (value) free(value);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_mirror_world_old(TOPLEVEL *w_current, int world_centerx,
  +			     int world_centery, OBJECT *object)
  +{
  +  int newx=0, newy=0;
  +  int origx, origy;
  +  int x, y;
  +  char *output_string = NULL;
  +  char *name = NULL;
  +  char *value = NULL;
  +  int sign=1;
  +  int height_mod=0;
  +	
  +  origx = object->text->x;
  +  origy = object->text->y;
  +
  +  /* translate to origin */
  +  x = origx + (-world_centerx);
  +  y = origy + (-world_centery);
  +
  +
  +  if (o_attrib_get_name_value(object->text->string, &name, &value)) {
  +    switch(object->show_name_value) {
  +      case(SHOW_NAME_VALUE):
  +        output_string = g_strdup(object->text->string);
  +        break;
  +
  +      case(SHOW_NAME):
  +        if (name[0] != '\0') {
  +          output_string = g_strdup(name);
  +        } else {
  +          /* you probably can remove this now... */
  +          /* since improper attributes will never get here */
  +          fprintf(stderr, 
  +                  "Got an improper attribute: %s\n", 
  +                  object->text->string);
  +          output_string = g_strdup("invalid");
  +        }
  +        break;
  +
  +      case(SHOW_VALUE):
  +        if (value[0] != '\0') {
  +          output_string = g_strdup(value);
  +        } else {
  +          /* you probably can remove this now... */
  +          /* since improper attributes will never get here */
  +          fprintf(stderr, 
  +                  "Got an improper attribute: %s\n", 
  +                  object->text->string);
  +          output_string = g_strdup("invalid");
  +        }
  +        break;
  +    }
  +  } else {
  +    output_string = g_strdup(object->text->string);
  +  }
  +
  +  switch(object->text->alignment) {
  +    case(LOWER_LEFT):
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = 1;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      height_mod = 0;
  +    }
  +    break;
  +
  +    case(MIDDLE_LEFT):
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = 1;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      height_mod = o_text_height(object->text->string,
  +                                 object->text->size);
  +    }
  +    break;
  +
  +    case(UPPER_LEFT):
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = 1;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      height_mod = 2*o_text_height(object->text->string,
  +                                   object->text->size);
  +    }
  +    break;
  +
  +    case(LOWER_MIDDLE): 
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = 0.5;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      sign = 1;
  +      height_mod = 0;
  +    }
  +    break;
  +
  +    case(MIDDLE_MIDDLE): 
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = 0.5;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      sign = 1;
  +      height_mod = o_text_height(object->text->string,
  +                                 object->text->size);
  +    }
  +    break;
  +
  +    case(UPPER_MIDDLE): 
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = 0.5;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      sign = 1;
  +      height_mod = 2*o_text_height(object->text->string,
  +                                   object->text->size);
  +    }
  +    break;
  +
  +    case(LOWER_RIGHT):
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = -1;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      sign = 1;
  +      height_mod = 0;
  +    }
  +    break;
  +
  +    case(MIDDLE_RIGHT):
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = -1;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      sign = 1;
  +      height_mod = o_text_height(object->text->string,
  +                                 object->text->size);
  +    }
  +    break;
  +
  +    case(UPPER_RIGHT):
  +    if (object->text->angle == 0 || object->text->angle == 180) {
  +      sign = -1;
  +      height_mod = 0;
  +    } else if (object->text->angle == 90 || object->text->angle == 270) {
  +      sign = 1;
  +      height_mod = 2*o_text_height(object->text->string,
  +                                   object->text->size);
  +    }
  +    break;
  +  }
  +
  +  switch (object->text->angle) {
  +
  +    case(0): 
  +    newx = -(x + sign*o_text_width(w_current, 
  +                                   output_string, 
  +                                   object->text->size/2)); 
  +
  +    break;
  +
  +    case(90):
  +    newx = -(x - sign*o_text_height(object->text->string,
  +                                    object->text->size)+height_mod);
  +    break;
  +
  +    case(180):
  +    newx = -(x - sign*o_text_width(w_current, 
  +                                   output_string, 
  +                                   object->text->size/2)); 
  +    break;
  +
  +    case(270):
  +    newx = -(x + sign*o_text_height(object->text->string,
  +                                    object->text->size)+height_mod);
  +    break;
  +
  +    default:
  +    fprintf(stderr, "Invalid angle specified!\n");
  +    return;
  +    break;
  +
  +  }
  +
  +  newy = y;
  +
  +  x = newx + (world_centerx);
  +  y = newy + (world_centery);
  +
  +  object->text->x = x;
  +  object->text->y = y;
  +
  +  /* don't know if this is needed ?*/	
  +  /* o_text_translate_world(w_current, x-object->text->x, y-object->text->y, object);*/
  +  o_text_recreate(w_current, object);
  +  if (output_string) free(output_string);
  +  if (name) free(name);
  +  if (value) free(value);
  +}
  +#endif
  +
  +#if 0 /* interesting, but currently unused code */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_return_center(TOPLEVEL *w_current, OBJECT *o_current,
  +			  int *centerx, int *centery)
  +{
  +  int text_height; 
  +  int text_width;
  +
  +  text_height = o_text_height(o_current->text->string,
  +			      o_current->text->size);
  +
  +  /* this will NOT NOT NOT work with attributes */
  +  text_width = o_text_width(w_current, o_current->text->string, 
  +                            o_current->text->size/2); 
  +	
  +  switch(o_current->text->angle) {
  +    case(0):
  +      *centerx = o_current->text->x + text_width/2;
  +      *centery = o_current->text->y + text_height/2;
  +      break;
  +
  +    case(90):
  +      *centerx = o_current->text->x - text_height/2;
  +      *centery = o_current->text->y + text_width/2;
  +      break;
  +
  +    case(180):
  +      *centerx = o_current->text->x - text_width/2;
  +      *centery = o_current->text->y - text_height/2;
  +      break;
  +
  +    case(270):
  +      *centerx = o_current->text->x + text_height/2;
  +      *centery = o_current->text->y - text_width/2;
  +      break;
  +  }	
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* the complex here is the complex of a complex object */
  +void o_text_change_angle(TOPLEVEL *w_current, OBJECT *prim_objs, int new_angle)
  +{
  +  OBJECT *o_current;
  +  int centerx, centery;
  +
  +  o_current = prim_objs;
  +
  +  while (o_current != NULL) {
  +    if (o_current->type == OBJ_TEXT) {
  +      o_current->text->angle = new_angle;
  +
  +      /* change world to non */
  +      o_text_return_center(w_current, o_current, &centerx, &centery);
  +
  +      o_text_translate_world(w_current, 
  +                             -centerx, -centery, o_current);
  +
  +      o_text_mirror_world(w_current, 0, 0, 
  +                          o_current);
  +      /* 
  +         o_text_rotate_world(w_current, 0, 0, 
  +         new_angle, 180, o_current);
  +      */
  +
  +      /*			o_text_rotate_world(w_current, 0, 0, new_angle, 
  +                                180, o_current)*/
  +
  +      o_text_translate_world(w_current, 
  +                             centerx, centery, o_current);
  +
  +      /* 			o_text_rotate_lowlevel(w_current, 
  +				0, 0, new_angle, 180, o_current->text->prim_objs);*/
  +
  +#if 0
  +      w_current->override_color =
  +        w_current->background_color;
  +      o_text_draw(w_current, o_current);
  +      w_current->override_color = -1;
  +#endif
  +
  +      o_text_recreate(w_current, o_current);
  +    }
  +    o_current = o_current->next;
  +  }
  +}
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_mirror_world(TOPLEVEL *w_current,
  +			 int world_centerx, int world_centery,
  +			 OBJECT *object)
  +{
  +  int origx, origy;
  +  int x, y;
  +	
  +  origx = object->text->x;
  +  origy = object->text->y;
  +
  +  x = origx + (-world_centerx);
  +  y = origy + (-world_centery);
  +
  +  if ((object->text->angle%180)==0) {
  +    switch(object->text->alignment) {
  +      case(LOWER_LEFT):
  +        object->text->alignment=LOWER_RIGHT;
  +        break;
  +
  +      case(MIDDLE_LEFT):
  +        object->text->alignment=MIDDLE_RIGHT;
  +        break;
  +
  +      case(UPPER_LEFT):
  +        object->text->alignment=UPPER_RIGHT;
  +        break;
  +
  +      case(LOWER_RIGHT):
  +        object->text->alignment=LOWER_LEFT;
  +        break;
  +
  +      case(MIDDLE_RIGHT):
  +        object->text->alignment=MIDDLE_LEFT;
  +        break;
  +
  +      case(UPPER_RIGHT):
  +        object->text->alignment=UPPER_LEFT;
  +        break;
  +
  +      default:
  +        break;
  +    }
  +  } else {
  +    switch(object->text->alignment) {
  +      case(LOWER_LEFT):
  +      object->text->alignment=UPPER_LEFT;
  +      break;
  +
  +      case(UPPER_LEFT):
  +      object->text->alignment=LOWER_LEFT;
  +      break;
  +
  +      case(LOWER_RIGHT):
  +      object->text->alignment=UPPER_RIGHT;
  +      break;
  +
  +      case(UPPER_RIGHT):
  +      object->text->alignment=LOWER_RIGHT;
  +      break;
  +
  +      case(LOWER_MIDDLE):
  +      object->text->alignment=UPPER_MIDDLE;
  +      break;
  +
  +      case(UPPER_MIDDLE):
  +      object->text->alignment=LOWER_MIDDLE;
  +      break;
  +
  +      default:
  +      break;
  +    }
  +  }
  +
  +  object->text->x = -x + (world_centerx);
  +  object->text->y =  y + (world_centery);
  +	
  +  o_text_recreate(w_current, object);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_mirror(TOPLEVEL *w_current,
  +		   int centerx, int centery, OBJECT *object)
  +{
  +  int world_centerx, world_centery;
  +
  +  SCREENtoWORLD(w_current, centerx, centery,
  +                &world_centerx,
  +                &world_centery);
  +
  +  o_text_mirror_world(w_current, world_centerx, world_centery, object);
  +}
  
  
  
  1.10      +89 -59    eda/geda/gaf/libgeda/src/s_attrib.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_attrib.c
  ===================================================================
  RCS file: s_attrib.c
  diff -N s_attrib.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ s_attrib.c	5 Jul 2006 03:13:38 -0000	1.10
  @@ -0,0 +1,158 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <sys/types.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +#define MAX_ATTRIBS	128
  +
  +/*! \brief */
  +struct st_attrib_names {
  +  char *attrib_name;
  +};
  +
  +/*! \brief */
  +static int attrib_index=0;
  +
  +/*! \brief */
  +/* and eventually make this unlimited */
  +/* hack hack */
  +static struct st_attrib_names attrib[MAX_ATTRIBS];
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int s_attrib_add_entry(char *new_attrib) 
  +{
  +  if (new_attrib == NULL) {
  +    return(-1); 
  +  }
  +
  +  if (attrib_index >= MAX_ATTRIBS) {
  +    return(-1); 
  +  }
  +	
  +  attrib[attrib_index].attrib_name = (char *) malloc(sizeof(char)*strlen(new_attrib)+1);
  +
  +  strcpy(attrib[attrib_index].attrib_name, new_attrib);
  +
  +  attrib_index++;
  +  return(attrib_index);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_attrib_print()
  +{
  +  int i;
  +
  +  for (i = 0; i < attrib_index; i++) {
  +    printf("%s\n", attrib[i].attrib_name);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* true for uniqueness, zero for duplication */
  +int s_attrib_uniq(char *name)
  +{
  +  int i;
  +
  +  for (i = 0; i < attrib_index; i++) {
  +    if (strcmp(attrib[i].attrib_name, name) == 0) {
  +      return(0);
  +    }
  +  }
  +
  +  return(1);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_attrib_free()
  +{
  +	int i;
  +
  +	for (i = 0; i < attrib_index; i++) {
  +		if (attrib[i].attrib_name)
  +               		free(attrib[i].attrib_name);
  +	}
  +
  +	attrib_index=0;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_attrib_init()
  +{
  +  int i;
  +  for (i = 0; i < MAX_ATTRIBS; i++) {
  +    attrib[i].attrib_name = NULL;	
  +  } 
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +char *s_attrib_get(int counter)
  +{
  +  if (counter < attrib_index) {
  +    return(attrib[counter].attrib_name);
  +  } else {
  +    return(NULL);
  +  }
  +
  +  return(NULL);
  +}
  
  
  
  1.21      +755 -582  eda/geda/gaf/libgeda/src/s_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_basic.c
  ===================================================================
  RCS file: s_basic.c
  diff -N s_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ s_basic.c	5 Jul 2006 03:13:38 -0000	1.21
  @@ -0,0 +1,946 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <ctype.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_ASSERT_H
  +#include <assert.h>
  +#endif
  +#ifndef HAVE_VSNPRINTF
  +#include <stdarg.h>
  +#endif
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "defines.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! this is modified here and in o_list.c */
  +int global_sid=0;
  +
  +#define NUMCOLORS 9  /*!< */
  +
  +/*! \brief */
  +struct st_old_colors {
  +        char *name;
  +        int value;
  +};
  +
  +/*! \brief
  + * Colors must be in alphabetical order
  + * be sure that you update above define
  + */
  +struct st_old_colors old_colors[] = {
  +	{ "black", 0 },
  +	{ "blue", 4 },
  +	{ "cyan", 6 },
  +	{ "green", 3 },
  +	{ "grey", 7 }, 
  +	{ "grey90", 8 },
  +	{ "red", 2 },
  +	{ "white", 1 },
  +	{ "yellow", 5 },
  +};
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void error_if_called(void)
  +{
  +	fprintf(stderr, "Somebody called error_if_called!\n");
  +	assert(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void exit_if_null(void *ptr) 
  +{
  +  if (ptr == NULL) {
  +    fprintf(stderr, "gEDA: Got NULL ptr!, please e-mail maintainer\n");
  +    assert(0);
  +    exit(-1);
  +  }	
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* hack rename this to be s_return_tail */
  +/* update object_tail or any list of that matter */
  +OBJECT *return_tail(OBJECT *head)
  +{
  +  OBJECT *o_current=NULL;
  +  OBJECT *ret_struct=NULL;
  +
  +  o_current = head;
  +  while ( o_current != NULL ) { /* goto end of list */
  +    ret_struct = o_current;	
  +    o_current = o_current->next;
  +  }
  +	
  +  return(ret_struct);	
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* hack rename this to be s_return_head */
  +/* update object_tail or any list of that matter */
  +OBJECT *return_head(OBJECT *tail)
  +{
  +  OBJECT *o_current=NULL;
  +  OBJECT *ret_struct=NULL;
  +
  +  o_current = tail;
  +  while ( o_current != NULL ) { /* goto end of list */
  +    ret_struct = o_current;	
  +    o_current = o_current->prev;
  +  }
  +	
  +  return(ret_struct);	
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *s_basic_init_object( char *name ) 
  +{
  +  OBJECT *new_node;
  +
  +  new_node = (OBJECT *) malloc(sizeof(OBJECT));	
  +
  +  if (new_node == NULL) {
  +    fprintf(stderr, "Could not perform malloc; something is broken or increase your process limits\n");
  +    exit(-1);
  +  }
  +
  +  /* setup sid */
  +  new_node->sid = global_sid++;
  +  new_node->type = -1;
  +
  +  /* Setup the name */
  +  /*! \todo get rid of magic number 16 that's the size of new_node->sid, */
  +  new_node->name = (char *) malloc(sizeof(char)*(strlen(name)+16));
  +  sprintf(new_node->name, "%s.%d", name, new_node->sid);
  +
  +  /* Setup the bounding box */
  +  new_node->top = 999999;
  +  new_node->left = 999999;
  +  new_node->right = 0;
  +  new_node->bottom = 0;
  +
  +  /* Setup line/circle structs */
  +  new_node->line = NULL;
  +  new_node->circle = NULL;
  +  new_node->arc = NULL;
  +  new_node->box = NULL;
  +  new_node->picture = NULL;
  +  new_node->text = NULL;
  +  new_node->complex = NULL;
  +
  +  new_node->tile_locs = NULL;
  +
  +  new_node->conn_list = NULL;
  +
  +  new_node->visited = 0;
  +	
  +  new_node->complex_basename = NULL;
  +  new_node->complex_clib = NULL;
  +  new_node->complex_parent = NULL;
  +		
  +  /* Setup the color */
  +  new_node->color = WHITE;
  +  new_node->saved_color = -1;
  +  new_node->selected = FALSE;
  +  new_node->locked_color = -1;
  +  new_node->draw_grips = FALSE;
  +
  +  new_node->bus_ripper_direction = 0;
  +
  +  new_node->action_func = error_if_called; 
  +  new_node->sel_func = error_if_called; 
  +  new_node->draw_func = error_if_called; 
  +
  +  new_node->line_end = END_NONE;
  +  new_node->line_type = TYPE_SOLID;
  +  new_node->line_width = 0;
  +  new_node->screen_line_width = 0;
  +  new_node->line_space = 0;
  +  new_node->screen_line_space = 0;
  +  new_node->line_length = 0;
  +  new_node->screen_line_length = 0;
  +  new_node->fill_width = 0;
  +  new_node->screen_fill_width = 0;
  +  new_node->fill_angle1 = 0;
  +  new_node->fill_angle2 = 0;
  +  new_node->fill_pitch1 = 0;
  +  new_node->screen_fill_pitch1 = 0;
  +  new_node->fill_pitch2 = 0;
  +  new_node->screen_fill_pitch2 = 0;
  +	
  +  new_node->attribs = NULL;
  +  new_node->attached_to = NULL;
  +  new_node->attribute = 0; 
  +  new_node->show_name_value = SHOW_NAME_VALUE;
  +  new_node->visibility = VISIBLE;
  +
  +  new_node->pin_type = PIN_TYPE_NET;
  +  new_node->whichend = -1;
  +	
  +  /* Setup link list stuff */
  +  new_node->prev = NULL;
  +  new_node->next = NULL;
  +
  +  return(new_node);
  +}
  +
  +OBJECT *s_basic_link_object( OBJECT *new_node, OBJECT *ptr ) 
  +{
  +  /* should never happen, but could */
  +  if (new_node == NULL) {
  +    fprintf(stderr, "Got a null new_node in link_object\n");
  +    return(ptr);
  +  }
  +
  +  if (ptr == NULL) {
  +    new_node->prev = NULL; /* setup previous link */
  +    return(new_node);
  +  } else {
  +    new_node->prev = ptr; /* setup previous link */
  +    ptr->next = new_node;
  +    return(ptr->next);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void print_struct_forw(OBJECT *ptr)
  +{
  +  OBJECT *o_current=NULL;
  +  ATTRIB *attr=NULL;
  +  int i;
  +
  +  o_current = ptr;
  +
  +  if (o_current == NULL) {
  +
  +    printf("AGGGGGGGGGGG NULLLLL PRINT\n");
  +  }
  +  printf("TRYING to PRINT\n");
  +  while (o_current != NULL) {
  +    printf("Name: %s\n", o_current->name);
  +    printf("Type: %d\n", o_current->type);
  +    printf("Sid: %d\n", o_current->sid);
  +
  +    if (o_current->type == OBJ_COMPLEX || o_current->type == OBJ_PLACEHOLDER) {
  +      print_struct_forw(o_current->complex->prim_objs);
  +    }
  +
  +	
  +    if (o_current->attribs) {
  +      attr = o_current->attribs;
  +      i = 0;
  +      while (attr != NULL) {
  +        if (attr->object != NULL) 
  +          printf("%d attribute %s\n", i, attr->object->name);
  +        attr = attr->next;
  +      }    
  +    }
  +
  +    printf("----\n");
  +    o_current = o_current->next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void print_struct_back(OBJECT *ptr)
  +{
  +  OBJECT *o_current=NULL;
  +
  +  o_current = ptr;
  +
  +  while (o_current != NULL) {
  +    printf("Name: %s\n", o_current->name);
  +    printf("Type: %d\n", o_current->type);
  +    printf("Sid: %d\n", o_current->sid);
  +    printf("----\n");
  +    o_current = o_current->prev;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void print_struct(OBJECT *ptr)
  +{
  +  OBJECT *o_current=NULL;
  +  ATTRIB *attr=NULL;
  +  int i;
  +
  +  o_current = ptr;
  +
  +  if (o_current != NULL) {
  +    printf("Name: %s\n", o_current->name);
  +    printf("Type: %d\n", o_current->type);
  +    printf("Sid: %d\n", o_current->sid);
  +    if (o_current->line != NULL) {
  +      printf("Line points.x1: %d\n", o_current->line->x[0]);
  +      printf("Line points.y1: %d\n", o_current->line->y[0]);
  +      printf("Line points.x2: %d\n", o_current->line->x[1]);
  +      printf("Line points.y2: %d\n", o_current->line->y[1]);
  +    }
  +
  +    if (o_current->attribs) {
  +      attr = o_current->attribs;
  +      i = 0;
  +      while (attr != NULL) {
  +        printf("%d attribute %s\n", i, attr->object->name);
  +        attr = attr->next;
  +      }
  +		
  +    }
  +    printf("----\n");
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_delete(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  if (o_current != NULL) {
  +
  +
  +#if DEBUG
  +    printf("sdel: %s\n", o_current->name);
  +    printf("sdel: %d\n", o_current->sid);
  +#endif
  +
  +    if (o_current->next) 
  +    o_current->next->prev = o_current->prev;
  +    else
  +    o_current->next = NULL;
  +
  +    if (o_current->prev) 
  +    o_current->prev->next = o_current->next;
  +    else
  +    o_current->prev = NULL;
  +
  +    s_conn_remove(w_current, o_current);
  +	
  +    /* second half of if is odd that we need it? hack */
  +    /* need to do this early so we can do the printfs */
  +    if (o_current->attached_to != NULL && o_current->attribute == 1) {
  +      if (o_current->attached_to->object) {
  +				/*printf("removing %s\n", o_current->attached_to->object->name);*/
  +      } else {
  +        printf("found a null I didn't expect!!!!!!!!!\n");
  +      }
  +
  +      /* do the actual remove */
  +      o_attrib_delete(o_current->attached_to);
  +    }
  +
  +    if (w_current->page_current->object_lastplace == o_current) {
  +      w_current->page_current->object_lastplace = NULL; 
  +    }
  +
  +    if (o_current->line) {
  +      /*	printf("sdeleting line\n");*/
  +      free(o_current->line);
  +
  +      /* yes this object might be in the tile system */
  +      s_tile_remove_object_all(w_current,
  +                               w_current->page_current,
  +                               o_current);
  +    }
  +    o_current->line = NULL;
  +
  +    if (o_current->circle) {
  +      /*	printf("sdeleting circle\n");*/
  +      free(o_current->circle);
  +    }
  +    o_current->circle = NULL;
  +
  +    if (o_current->arc) {
  +      /*	printf("sdeleting arc\n");*/
  +      free(o_current->arc);
  +    }
  +    o_current->arc = NULL;
  +
  +    if (o_current->box) {
  +      /*	printf("sdeleting box\n");*/
  +      free(o_current->box);
  +    }
  +    o_current->box = NULL;
  +
  +    if (o_current->picture) {
  +      /*	printf("sdeleting picture\n");*/
  +#ifndef HAS_GTK12
  +      if (o_current->picture->original_picture)
  +	free(o_current->picture->original_picture);
  +      if (o_current->picture->displayed_picture)
  +	free(o_current->picture->displayed_picture);
  +#endif
  +      if (o_current->picture->filename)
  +	free(o_current->picture->filename);
  +      free(o_current->picture);
  +    }
  +    o_current->picture = NULL;
  +
  +    if (o_current->text) {
  +      if (o_current->text->string) {
  +				/*printf("sdeleting text->string\n");*/
  +        free(o_current->text->string); 
  +      }
  +      o_current->text->string = NULL;
  +
  +      if (o_current->text->prim_objs) {
  +				/*printf("sdeleting text complex\n");*/
  +        s_delete_list_fromstart(w_current, 
  +                                o_current->text->prim_objs);
  +      }
  +      o_current->text->prim_objs = NULL;
  +
  +      /*	printf("sdeleting text\n");*/
  +      free(o_current->text);
  +    }
  +    o_current->text = NULL;
  +
  +    if (o_current->name) {
  +      /*	printf("sdeleting name\n");*/
  +      free(o_current->name);
  +    }
  +    o_current->name = NULL;
  +
  +
  +    if (o_current->complex_basename) {
  +      /*	printf("sdeleting complex_basename\n");*/
  +      free(o_current->complex_basename); 
  +    }
  +    o_current->complex_basename = NULL;
  +
  +    if (o_current->complex_clib) {
  +      /*	printf("sdeleting complex_clib\n");*/
  +      free(o_current->complex_clib); 
  +    }
  +    o_current->complex_clib = NULL;
  +
  +    if (o_current->complex) {
  +
  +      if (o_current->complex->prim_objs) {
  +        /* printf("sdeleting complex->primitive_objects\n");*/
  +        s_delete_list_fromstart(w_current, 
  +                                o_current->complex->prim_objs);
  +      }
  +      o_current->complex->prim_objs = NULL;
  +
  +      free(o_current->complex);
  +      o_current->complex = NULL;
  +    }
  +
  +    if (o_current->attribs) {
  +      o_attrib_free_all(w_current, o_current->attribs);
  +    }
  +    o_current->attribs = NULL;
  +
  +
  +    free(o_current);	/* assuming it is not null */
  +
  +    o_current=NULL;		/* misc clean up */
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* deletes everything include the head */
  +void s_delete_list_fromstart(TOPLEVEL *w_current, OBJECT *start)
  +{
  +  OBJECT *temp=NULL; /* literally is a temp */
  +  OBJECT *current=NULL; /* ugg... you have both o_current and current? */
  +  OBJECT *o_current=NULL; /* hack */
  +
  +  temp = start;
  +  current = return_tail(start);
  +
  +  /* do the delete backwards */
  +  /*while(current != NULL && current->type != OBJ_HEAD ) {*/
  +  while(current != NULL) {
  +    o_current = current->prev;
  +    s_delete(w_current, current);
  +    current = o_current;
  +  }
  +
  +  /* now delete the head node */
  +  /* might not need this but what the hell */
  +  /* no longer needed, since it's deleted above */
  +  /*s_delete_head(w_current, start);*/
  +}
  +
  +#if 0 /* old way of doing this */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_delete_list_fromstart(OBJECT *start)
  +{
  +  OBJECT *traverse=NULL;
  +  OBJECT *o_current=NULL;
  +
  +  for (traverse = start; traverse ; traverse = o_current) {
  +    o_current = traverse->next;
  +    if (traverse->type != OBJ_HEAD) /* don't delete any head nodes */
  +      s_delete(traverse);
  +    else 
  +      break; /* found a head node */
  +  }
  +  s_delete(traverse);
  +}
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  This function removes one object pointed by parameter <B>object</B> from
  + *  a list as far as it does not represents a head. If so the function returns
  + *  NULL. If not it returns the pointer on the object, i.e. the same as the
  + *  parameter.
  + *
  + *  This function must be followed by a call to #return_tail() on the
  + *  list it belonged to as it can be the last object. Therefore the tail
  + *  of the list is modified.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] object
  + *  \return OBJECT *
  + */
  +OBJECT *s_remove(TOPLEVEL *w_current, OBJECT *object)
  +{
  +  if(object->type == OBJ_HEAD)
  +  return NULL;
  +	
  +  if(object->prev != NULL)
  +  object->prev->next = object->next;
  +  if(object->next != NULL)
  +  object->next->prev = object->prev;
  +
  +  object->next = NULL;
  +  object->prev = NULL;
  +
  +  return object;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* Done */
  +void string_toupper(char *in, char *out)
  +{
  +  int len;
  +  int i;
  +
  +  len = strlen(in);
  +
  +  for (i = 0 ; i < len ; i++) {
  +    out[i] = toupper(in[i]);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void string_tolower(char *in, char *out)
  +{
  +	int len;
  +	int i;
  +
  +	len = strlen(in);
  +
  +	for (i = 0 ; i < len ; i++) {
  +		out[i] = tolower(in[i]);
  +	}
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int colornametovalue(char *string)
  +{
  +	
  +  int lower = 0; 
  +  int upper = NUMCOLORS - 1;
  +  int middle;
  +  int val;
  +  struct st_old_colors *ptr=NULL;
  +
  +  if (!string) {
  +    return(-1);
  +  }
  +
  +  string_tolower(string, string);
  +  while (lower <= upper) {
  +    middle = (lower + upper) / 2;
  +
  +    ptr = &old_colors[middle];
  +    val = strcmp (ptr->name, string);
  +
  +    if (val < 0) {
  +      lower = middle + 1;
  +    } else if (val == 0) {
  +      return(ptr->value);
  +    } else {
  +      upper = middle - 1;
  +    }
  +  }                
  +  return(-1);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* used by o_text_read */
  +char *remove_nl(char *string)
  +{
  +  int i;
  +
  +  if (!string)
  +    return NULL;
  +  
  +  i = 0;
  +  while(string[i] != '\0' && string[i] != '\n' && string[i] != '\r') {
  +    i++; 
  +  }
  +
  +  string[i] = '\0';
  +
  +  return(string);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* used by o_text_read */
  +char *remove_last_nl(char *string)
  +{
  +  int len;
  +
  +  if (!string)
  +    return NULL;		
  +
  +  len = strlen(string);
  +  if (string[len-1] == '\n' || string[len-1] == '\r')
  +    string[len-1] = '\0';
  +     
  +  return(string);
  +}
  +
  +#ifndef HAVE_VSNPRINTF
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void vsnprintf(char *buff, size_t bufsiz, const char *fmt, va_list ap)
  +{
  +    char *tmpbuf = buff;
  +
  +    vsprintf(tmpbuf, fmt, ap);
  +}
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* this function is called by expand_env_variables */
  +/* changes and returns new string, frees the one that was passed in */
  +char *remove_string(char *string, int start, int end) 
  +{
  +  char *return_string;
  +  int i;
  +  int len;
  +  int j;
  +
  +  if (!string) {
  +    return(NULL);
  +  }
  +
  +  len = strlen(string);
  +
  +  return_string = (char *) malloc(sizeof(char)*(len+1));
  +
  +  j = 0;
  +  for (i = 0 ; i < len; i++) {
  +    if (i >= start && i <= end) {
  +      /* do nothing */
  +      /* removing characters */
  +    } else {
  +      return_string[j] = string[i];
  +      j++;
  +    }
  +  }
  +  return_string[j] = '\0';
  +
  +  /* free original string */
  +  free(string);
  +
  +  return(return_string);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* this function is called by expand_env_variables */
  +/* changes and returns new string, frees the one that was passed in */
  +char *insert_string(char *string, int start, char *insert_string)
  +{
  +  char *new_string=NULL;
  +  int i;
  +  int len;
  +  int insert_len;
  +  int total_len;
  +  int j;
  +  int orig_count=0;
  +
  +  /* this should never happen */
  +  if (!insert_string) {
  +    return(NULL);	
  +  }
  +
  +  /* this should never happen either */
  +  if (!string) {
  +    return(NULL);	
  +  }
  +
  +  len = strlen(string);
  +  insert_len = strlen(insert_string);
  +  total_len = len+insert_len;
  +
  +  new_string = (char *) malloc(sizeof(char)*(total_len+1));
  +
  +  i = 0;
  +  while (i < total_len) {
  +    if (i == start) {
  +      for (j = 0 ; j < insert_len; j++) {
  +        new_string[i+j] = insert_string[j];
  +      }
  +      i = j+i;
  +    } else {
  +      new_string[i] = string[orig_count];
  +      i++;
  +      orig_count++;
  +    }
  +  }
  +
  +  new_string[i] = '\0';
  +
  +  /* now free the original string */
  +  free(string);
  +
  +  return(new_string);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* this function changes and then returns the string which has the 
  + * expanded environment variables, frees passed in string */
  +/* Environment variables MUST be in the form ${variable_name} */
  +/* $variable_name is not valid here */
  +char *expand_env_variables(char *string)
  +{
  +  char wanted_var[80]; /* size is hack */
  +  char *return_string=NULL;
  +  char *environment_string=NULL;
  +  int changed=1;
  +  int found_dollar=0;
  +  int found_lbrac=0; 
  +  int found_rbrac=0;
  +  int start_of_variable= -1;
  +  int end_of_variable= -1;
  +  int count=0;
  +  int i,j;
  +
  +  if (!string) {
  +    return(NULL);
  +  }
  +
  +  return_string = string;	
  +
  +  while(changed) {
  +	
  +    changed=0;
  +    j=0;
  +    for (i = 0 ; i < strlen(return_string); i++) {
  +
  +      switch(return_string[i]) {
  +
  +        case('$'):
  +
  +#if DEBUG
  +          printf("found a $\n");
  +#endif
  +          found_dollar=1;	
  +          start_of_variable=i;
  +          break;
  +
  +        case('{'):
  +          if (found_dollar) {
  +            found_lbrac=1;
  +            count=1;
  +          }
  +          break;
  +
  +        case('}'):
  +          if (found_dollar) {
  +            found_rbrac=1;
  +            /* ends filling of wanted_var */	
  +            found_lbrac=0;
  +            end_of_variable=i;
  +          }
  +          break;
  +
  +      }
  +
  +      /* the > 1 bit is so that we don't store the { */
  +      if (found_dollar && found_lbrac && (count > 1)) {
  +        wanted_var[j] = return_string[i];
  +        j++; /* check for size */
  +      }
  +
  +      /* skip over initial { */ 
  +      count++;
  +
  +      if (found_rbrac && !found_lbrac) {
  +        wanted_var[j] = '\0';
  +#if DEBUG
  +        printf("variable wanted: _%s_\n",  wanted_var);
  +        printf("Between index: %d and %d\n", 
  +               start_of_variable,
  +               end_of_variable);
  +#endif
  +
  +		
  +        environment_string = getenv(wanted_var);	
  +
  +#if DEBUG
  +        if (environment_string) {
  +          printf("%s = _%s_\n", wanted_var, 
  +                 environment_string);
  +        }
  +#endif
  +
  +        return_string = remove_string(return_string,
  +                                      start_of_variable,
  +                                      end_of_variable);
  +
  +#if DEBUG
  +        printf("removed string: _%s_\n", return_string);
  +#endif
  +
  +        if (environment_string) {
  +          return_string = insert_string(
  +                                        return_string,
  +                                        start_of_variable,
  +                                        environment_string);
  +
  +        }
  +
  +#if DEBUG
  +        printf("final string: _%s_\n", return_string);
  +#endif
  +        changed=1;
  +
  +				/* end of search */
  +        found_dollar=0;
  +        found_rbrac=0;
  +        count=0;
  +        start_of_variable= -1;
  +        end_of_variable= -1;
  +
  +        break;
  +      }
  +    }
  +  }
  +
  +  if (found_dollar) {
  +    fprintf(stderr, "Found malformed environment variable (use ${varname})!\n");
  +  }
  +
  +  return(return_string);
  +}
  
  
  
  1.18      +221 -494  eda/geda/gaf/libgeda/src/s_clib.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_clib.c
  ===================================================================
  RCS file: s_clib.c
  diff -N s_clib.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ s_clib.c	5 Jul 2006 03:13:38 -0000	1.18
  @@ -0,0 +1,253 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +/*! \file s_clib.c
  + *  <B>clib</B> stands for component library.
  + *
  + *  A component library is made of several directories gathering
  + *  component files. 
  + *
  + *  It must first be initialized with #s_clib_init(). When it is no more
  + *  useful, use #s_clib_free() to free memory and reset the component
  + *  library.
  + *
  + *  To add a directory to the library, use #s_clib_add_directory().
  + *
  + *  To retrieve a list of the directories that make the library, use
  + *  #s_clib_get_directories(). For a list of component files in a
  + *  directory of the library, use #s_clib_get_files().
  + *
  + *  #s_clib_search_basename() let you find a specific component from
  + *  its name. Please note that it returns a list of directories as there
  + *  may be several places that contains a component with this name.
  + */
  +
  +#include <config.h>
  +
  +#include <glib.h>
  +
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +#include "defines.h"
  +
  +
  +void s_clib_free (void);
  +
  +static GSList *clib_directories = NULL;
  +
  +static GHashTable *clib_cache = NULL;
  +
  +/*! \brief Initializes the component library handling code.
  + *  \par Function Description
  + *  Initializes the component library handling code.
  + *  \warning This function must be called before any other function
  + *           of this file.
  + */
  +void s_clib_init (void)
  +{
  +  if (clib_directories != NULL || clib_cache != NULL) {
  +    s_clib_free ();
  +  }
  +
  +  clib_cache = g_hash_table_new (g_str_hash, g_str_equal);
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void clib_free_cache_entry (gpointer key, gpointer value,
  +				   gpointer user_data)
  +{
  +  g_free (key);
  +  if (value != NULL) {
  +    /* value is a singly-linked list of strings */
  +    g_slist_foreach (value, (GFunc)g_free, NULL);
  +    g_slist_free ((GSList*)value);
  +  }
  +}
  +
  +/*! \brief Frees memory used by the component library.
  + *  \par Function Description
  + *  Frees memory used by the component library.
  + */
  +void s_clib_free (void)
  +{
  +  if (clib_directories != NULL) {
  +    g_slist_foreach (clib_directories, (GFunc)g_free, NULL);
  +    g_slist_free (clib_directories);
  +    clib_directories = NULL;
  +  }
  +
  +  if (clib_cache != NULL) {
  +    g_hash_table_foreach (clib_cache, clib_free_cache_entry, NULL);
  +    g_hash_table_destroy (clib_cache);
  +    clib_cache = NULL;
  +  }
  +  
  +}
  +
  +/*! \brief Adds a new directory to the component library.
  + *  \par Function Description
  + *  Adds <B>directory</B> as a new directory for the component library.
  + *
  + *  \param [in] directory  Character string with the new directory name.
  + */
  +void s_clib_add_directory (const gchar *directory)
  +{
  +  /* search for directory in clib_directories */
  +  if (!g_slist_find_custom (clib_directories,
  +                            directory,
  +                            (GCompareFunc) g_strcasecmp))
  +  {
  +    /* directory not yet in the list of known directories */
  +    /* add directory to list */
  +    clib_directories = g_slist_append (clib_directories,
  +                                       g_strdup (directory));
  +  }
  +  
  +}
  +
  +/*! \brief Get list of component library directories.
  + *  \par Function Description
  + *  This function returns the list of directories part of
  + *  the component library.
  + *
  + *  \return Global libgead #clib_directories variable.
  + *  \warning
  + *  The returned value is owned by libgeda and must not be modified or freed.
  + *
  + */
  +const GSList *s_clib_get_directories()
  +{
  +  return clib_directories;
  +}
  +
  +/*! \brief Get a list of files found a directory.
  + *  \par Function Description
  + *  This function returns a list of file names found in <B>directory</B> and
  + *  that match <B>filter</B>
  + *
  + *  \param [in] directory  Character string with the path to search.
  + *  \param [in] filter     Character string to compare file names against.
  + *  \return List of file name that matched <B>filter</B>, NULL otherwise.
  + */
  +GSList *s_clib_get_files (const gchar *directory, const gchar *filter)
  +{
  +  GDir *dir;
  +  const gchar *entry;
  +  GSList *ret = NULL;
  +
  +  /* check directory is in clib_directories */
  +  if (g_slist_find_custom (clib_directories,
  +                           directory,
  +                           (GCompareFunc) g_strcasecmp) == NULL)
  +  {
  +    /* no, unknown directory: report an error */
  +    s_log_message ("Directory [%s] is not part of the component library\n",
  +                   directory);
  +    return NULL;
  +  }
  +
  +  /* open the directory */
  +  dir = g_dir_open (directory, 0, NULL);
  +  if (dir == NULL) {
  +    s_log_message ("Failed to open directory [%s]\n", directory);
  +    return NULL;
  +  }
  +
  +  /* now read the entire directory */
  +  /* and build a list of filenames in directory that match filter */
  +  while ((entry = g_dir_read_name (dir)) != NULL) {
  +    /* skip .'s */
  +    if (entry[0] == '.') {
  +      continue;
  +    }
  +
  +    /* identify filter-matching filenames */
  +    if (strstr (entry, filter)) {
  +      ret = g_slist_append (ret, (gpointer)g_strdup (entry));
  +    }
  +   
  +  }
  +  
  +  /* finished: close the directory stream */
  +  g_dir_close (dir);
  +
  +  /* sort the list alphabetically */
  +  ret = g_slist_sort (ret, (GCompareFunc)g_strcasecmp);
  +  
  +  /* and return the sorted list of filenames */
  +  return ret;
  +}
  +
  +/*! \brief Search for a symbol file in the component library.
  + *  \par Function Description
  + *  Searches in component library for a symbol file with name <B>basename</B>.
  + *
  + *  \param [in] basename  Character string with base symbol name to search for.
  + *  \return List of directories where symbol file with this name was found,
  + *          NULL otherwise.
  + *
  + *  \warning
  + *  The returned value is owned by libgeda and must not be modified or freed.
  + *
  + */
  +const GSList *s_clib_search_basename(const gchar *basename)
  +{
  +  GSList *ret, *tmp;
  +  
  +  /* first check if basename is in cache */
  +  ret = g_hash_table_lookup (clib_cache, basename);
  +  if (ret != NULL) {
  +    /* yes, found basename in cache, nothing more to do */
  +    return ret;
  +  }
  +
  +  /* looks like we have to search for basename in the library */
  +  for (tmp = clib_directories; tmp != NULL; tmp = g_slist_next (tmp)) {
  +    gchar *dir_name  = (gchar*)tmp->data;
  +    gchar *file_name = g_strconcat (dir_name,
  +                                    G_DIR_SEPARATOR_S,
  +                                    basename,
  +                                    NULL);
  +
  +    if (g_file_test (file_name, G_FILE_TEST_EXISTS)) {
  +      /* add directory name to the list */
  +      ret = g_slist_append (ret, g_strdup (dir_name));
  +    }
  +
  +    g_free (file_name);
  +  }
  +
  +  /* have we found something? */
  +  if (ret != NULL) {
  +    /* yes, add the result to cache */
  +    g_hash_table_insert (clib_cache, g_strdup (basename), ret);
  +  }
  +  
  +  return ret;
  +}
  
  
  
  1.8       +194 -141  eda/geda/gaf/libgeda/src/s_color.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_color.c
  ===================================================================
  RCS file: s_color.c
  diff -N s_color.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ s_color.c	5 Jul 2006 03:13:38 -0000	1.8
  @@ -0,0 +1,247 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +COLOR colors[MAX_COLORS];
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_color_init(void)
  +{
  +  int i;
  +
  +  for (i = 0; i < MAX_COLORS; i++) {
  +    colors[i].color_name = NULL; 
  +    colors[i].outline_color_name = NULL; 
  +    colors[i].ps_color_string = NULL; 
  +    colors[i].image_red = -1;
  +    colors[i].image_green = -1;
  +    colors[i].image_blue = -1;
  +    colors[i].gtk_color = NULL;
  +    colors[i].image_color = 0;
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* you are allowed to call this function with the same color index again and */
  +/* and again, last call is the final color request */
  +int s_color_request(int color_index, char *color_name,
  +		    char *outline_color_name, char *ps_color_string, 
  +		    int image_red, int image_green, int image_blue)
  +{
  +
  +#if 0
  +  if (colors[color_index].color_name) {
  +    return;
  +  }
  +#endif
  +
  +  if (color_index > MAX_COLORS) {
  +    fprintf(stderr, "Cannot allocate specified color, increase MAX_COLORS\n");
  +    return(-1);
  +  } 
  +
  +  /* search for the color name see if it's already been alloced */
  +
  +  if (colors[color_index].color_name) {
  +    free(colors[color_index].color_name);	
  +  }
  +
  +  colors[color_index].color_name = g_strdup (color_name);
  +
  +  if (strcmp(outline_color_name, "null") != 0) {
  +    colors[color_index].outline_color_name = g_strdup (outline_color_name);
  +  } else {
  +    colors[color_index].outline_color_name = NULL;
  +  }
  +	
  +  if (strcmp(ps_color_string, "null") != 0) {
  +    colors[color_index].ps_color_string = g_strdup( ps_color_string);
  +  } else {
  +    colors[color_index].ps_color_string = NULL;
  +  }
  +
  +  colors[color_index].image_red = image_red;
  +  colors[color_index].image_green = image_green;
  +  colors[color_index].image_blue = image_blue;
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_color_destroy_all(void)
  +{
  +  int i;
  +
  +  for (i = 0; i < MAX_COLORS; i++) {
  +    if (colors[i].color_name) {
  +      free(colors[i].color_name);
  +    }
  +    if (colors[i].outline_color_name) {
  +      free(colors[i].outline_color_name);
  +    }
  +    if (colors[i].ps_color_string) {
  +      free(colors[i].ps_color_string);
  +    }
  +    colors[i].image_red = -1;
  +    colors[i].image_green = -1;
  +    colors[i].image_blue = -1;
  +    colors[i].image_color = 0;
  +    /* free the colors */
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +char *s_color_ps_string(int color)
  +{
  +  if (colors[color].ps_color_string) {
  +    return(colors[color].ps_color_string);
  +  } else {
  +    return(NULL);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int s_color_image_int(int color)
  +{
  +  if (colors[color].image_color != -1) {
  +    return(colors[color].image_color);
  +  } else {
  +    return(0);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* \bug I have no idea if this causes a memory leak or not */
  +void s_color_gdcolor_init(void)
  +{
  +  int i;
  +
  +  for (i = 0; i < MAX_COLORS; i++) {
  +
  +    if (colors[i].image_red != -1 && colors[i].image_green != -1 &&
  +        colors[i].image_blue != -1) {
  +#ifdef HAS_LIBGDGEDA
  +      colors[i].image_color = gdImageColorAllocate(
  +                                                   current_im_ptr, 
  +                                                   colors[i].image_red,
  +                                                   colors[i].image_green,
  +                                                   colors[i].image_blue);
  +#endif
  +
  +#if DEBUG
  +      printf("%d) %d %d %d -> %d\n", i,
  +             colors[i].image_red,
  +             colors[i].image_green,
  +             colors[i].image_blue, colors[i].image_color);
  +#endif
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int s_color_get_name(int index, char *string)
  +{
  +  if (index > MAX_COLORS) {
  +    return(FALSE);
  +  }
  +
  +  /* only if these two variables are not null is the color settable */
  +  if (colors[index].color_name && colors[index].outline_color_name) {
  +    if (string) {
  +      strcpy(string, colors[index].color_name);
  +    }
  +    return(TRUE);
  +  }
  +
  +  string[0] = '\0';
  +  /* didn't find a color, but there still might be more */
  +  return(-1);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \return The index of the given color name, -1 if index was not found.
  + */
  +int s_color_get_index(char *string)
  +{
  +  int index;
  +
  +  if (string == NULL) {
  +    return(-1);
  +  }
  +
  +  for (index = 0; index < MAX_COLORS; index++) {
  +    if (strcasecmp(string, colors[index].color_name) == 0) {
  +      return (index); 
  +    }
  +  }
  +
  +  /* If the color was not found, return -1 */
  +  return (-1);
  +
  +}
  
  
  
  1.4       +508 -192  eda/geda/gaf/libgeda/src/s_conn.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_conn.c
  ===================================================================
  RCS file: s_conn.c
  diff -N s_conn.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ s_conn.c	5 Jul 2006 03:13:38 -0000	1.4
  @@ -0,0 +1,847 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <ctype.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_ASSERT_H
  +#include <assert.h>
  +#endif
  +#ifndef HAVE_VSNPRINTF
  +#include <stdarg.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "defines.h"
  +#include "globals.h"
  +#include "colors.h"
  +#include "o_types.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +CONN *s_conn_return_new(OBJECT * other_object, int type, int x, int y,
  +			int whichone, int other_whichone)
  +{
  +  CONN *new_conn;
  +
  +  new_conn = (CONN *) malloc(sizeof(CONN));
  +
  +#if DEBUG
  +  printf("** creating: %s %d %d\n", other_object->name, x, y);
  +#endif
  +
  +  new_conn->other_object = other_object;
  +  new_conn->type = type;
  +  new_conn->x = x;
  +  new_conn->y = y;
  +  new_conn->whichone = whichone;
  +  new_conn->other_whichone = other_whichone;
  +
  +  return (new_conn);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \return TRUE if the CONN structure is unique, FALSE otherwise.
  + */
  +int s_conn_uniq(GList * conn_list, CONN * input_conn)
  +{
  +  GList *c_current;
  +  CONN *conn;
  +
  +  c_current = conn_list;
  +  while (c_current != NULL) {
  +    conn = (CONN *) c_current->data;
  +
  +    if (conn->other_object == input_conn->other_object &&
  +        conn->x == input_conn->x && conn->y == input_conn->y &&
  +        conn->type == input_conn->type) {
  +      return (FALSE);
  +    }
  +
  +    c_current = c_current->next;
  +  }
  +
  +  return (TRUE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int s_conn_remove_other(TOPLEVEL * w_current, OBJECT * other_object,
  +			OBJECT * to_remove)
  +{
  +    GList *c_current = NULL;
  +    CONN *conn = NULL;
  +
  +    c_current = other_object->conn_list;
  +    while (c_current != NULL) {
  +	conn = (CONN *) c_current->data;
  +
  +	if (conn->other_object == to_remove) {
  +	    other_object->conn_list =
  +		g_list_remove(other_object->conn_list, conn);
  +
  +#if DEBUG
  +	    printf("Found other_object in remove_other\n");
  +	    printf("Freeing other: %s %d %d\n", conn->other_object->name,
  +		   conn->x, conn->y);
  +#endif
  +
  +	    c_current->data = NULL;
  +	    free(conn);
  +
  +#if 0 /* this does not work right */
  +            if (other_object->type == OBJ_BUS &&
  +                other_object->conn_list == NULL) {
  +              other_object->bus_ripper_direction = 0;
  +            }
  +#endif
  +            
  +	    return (TRUE);
  +	}
  +
  +	c_current = c_current->next;
  +    }
  +
  +    return (FALSE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_conn_remove(TOPLEVEL * w_current, OBJECT * to_remove)
  +{
  +  GList *c_current;
  +  CONN *conn;
  +
  +  if (to_remove->type != OBJ_PIN && to_remove->type != OBJ_NET &&
  +      to_remove->type != OBJ_BUS) {
  +    return;
  +  }
  +
  +  c_current = to_remove->conn_list;
  +  while (c_current != NULL) {
  +    conn = (CONN *) c_current->data;
  +
  +#if DEBUG
  +    printf("Removing: %s\n", conn->other_object->name);
  +#endif
  +
  +    /* keep calling this till it returns false (all refs removed) */
  +    /* there is NO body to this while loop */
  +    while (s_conn_remove_other
  +           (w_current, conn->other_object, to_remove));
  +
  +#if DEBUG
  +    printf("returned from remove_other\n");
  +    printf("Freeing: %s %d %d\n", conn->other_object->name, conn->x,
  +           conn->y);
  +#endif
  +    c_current->data = NULL;
  +    free(conn);
  +    c_current = c_current->next;
  +  }
  +
  +#if DEBUG
  +  printf("length: %d\n", g_list_length(to_remove->conn_list));
  +#endif
  +  g_list_free(to_remove->conn_list);
  +  to_remove->conn_list = NULL; /*! \todo Memory leak? TODO hack */
  +
  +#if 0 /* this does not work right either */
  +  if (to_remove->type == OBJ_BUS)
  +  {
  +    to_remove->bus_ripper_direction = 0;
  +  }
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_conn_remove_complex(TOPLEVEL * w_current, OBJECT * to_remove)
  +{
  +  OBJECT *o_current;
  +  
  +  if (to_remove->type != OBJ_COMPLEX && to_remove->type != OBJ_PLACEHOLDER) {
  +    return;
  +  }
  +
  +  o_current = to_remove->complex->prim_objs;
  +  while (o_current != NULL) {
  +    switch (o_current->type) {
  +      case (OBJ_NET):
  +      case (OBJ_PIN):
  +      case (OBJ_BUS):
  +        s_conn_remove(w_current, o_current);
  +        break;
  +
  +    }
  +    o_current = o_current->next;
  +  }
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *s_conn_check_midpoint(OBJECT *o_current, int x, int y)
  +{
  +  int min_x, min_y, max_x, max_y;
  +
  +  switch(o_current->type) {
  +    case(OBJ_NET):
  +    case(OBJ_PIN):
  +    case(OBJ_BUS):
  +      min_y = min(o_current->line->y[0], 
  +                  o_current->line->y[1]);
  +      max_y = max(o_current->line->y[0], 
  +                  o_current->line->y[1]);
  +
  +				/* vertical */
  +      if ( (o_current->line->x[0] == x) &&
  +           (y > min_y) && (y < max_y) &&
  +           (o_current->line->x[0] ==
  +            o_current->line->x[1]) ) {
  +#if DEBUG
  +        printf("Found vertical point\n");
  +#endif
  +        return(o_current);
  +      }
  +
  +      min_x = min(o_current->line->x[0], 
  +                  o_current->line->x[1]);
  +      max_x = max(o_current->line->x[0], 
  +                  o_current->line->x[1]);
  +
  +				/* horizontal */
  +      if ( (o_current->line->y[0] == y) &&
  +           (x > min_x) && (x < max_x) &&
  +           (o_current->line->y[0] ==
  +            o_current->line->y[1]) ) {
  +#if DEBUG
  +        printf("Found horizontal point\n");
  +#endif
  +        return(o_current);
  +      }
  +
  +      break;
  +  }
  +  return(NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_conn_update_object(TOPLEVEL * w_current, OBJECT * object)
  +{
  +  TILE *t_current;
  +  TILE_LOC *tl_current;
  +  GList *tloc_list;
  +  GList *object_list;
  +  OBJECT *other_object;
  +  OBJECT *found;
  +  CONN *new_conn;
  +  int i, j;
  +  int k;
  +  int add_conn;
  +
  +  /* loop over all tiles which object appears in */
  +  tloc_list = object->tile_locs;
  +  while (tloc_list != NULL) {
  +    tl_current = (TILE_LOC *) tloc_list->data;
  +
  +    add_conn = FALSE;
  +    
  +    i = tl_current->i;
  +    j = tl_current->j;
  +
  +#if DEBUG
  +    printf("\nInside tile: %d %d\n\n", i, j);
  +#endif
  +    
  +    t_current = &w_current->page_current->world_tiles[i][j];
  +    object_list = t_current->objects;
  +    while (object_list != NULL) {
  +      other_object = (OBJECT *) object_list->data;
  +      
  +#if DEBUG
  +      printf("Tile has object: %s\n", other_object->name);
  +#endif
  +
  +      /* here is where you check the end points */
  +      for (k = 0; k < 2; k++) {
  +        /* do first end point */
  +
  +        if (object->line->x[0] == other_object->line->x[k] &&
  +            object->line->y[0] == other_object->line->y[k] &&
  +            object != other_object) {
  +
  +          if (object->type == OBJ_PIN) {
  +            if (0 == object->whichend) {
  +              if (other_object->type == OBJ_PIN && /* new addition */
  +                  k != other_object->whichend ) { /* was 0 */
  +                add_conn = FALSE; 
  +              } else {
  +                add_conn = TRUE;
  +              }
  +            } else {
  +              add_conn = FALSE;
  +            }
  +          } else if (other_object->type == OBJ_PIN) {
  +            if (k == other_object->whichend) {
  +              if (object->type == OBJ_PIN && /* new addition */
  +                  k != object->whichend ) {
  +                add_conn = FALSE; 
  +              } else {
  +                add_conn = TRUE;
  +              }
  +            } else {
  +              add_conn = FALSE;
  +            }
  +          } else {
  +            add_conn = TRUE;
  +          }
  +
  +          /* check for pin / bus compatibility */
  +          /* you cannot connect pins and buses at all */
  +          if (add_conn) {
  +            if ((object->type == OBJ_PIN && other_object->type == OBJ_BUS) ||
  +                (object->type == OBJ_BUS && other_object->type == OBJ_PIN)) {
  +              add_conn = FALSE;
  +            } else {
  +              add_conn = TRUE;
  +            }
  +          }
  +
  +          /* check for net / bus compatibility */
  +          /* you cannot connect the endpoint of a bus to a net */
  +          /* and the reverse is true as well */
  +          if (add_conn) {
  +            if ((object->type == OBJ_NET && other_object->type == OBJ_BUS) ||
  +                (object->type == OBJ_BUS && other_object->type == OBJ_NET)) {
  +              add_conn = FALSE;
  +            } else {
  +              add_conn = TRUE;
  +            }
  +          }
  +          
  +#if DEBUG
  +          if (add_conn) {
  +            printf("0\n");
  +            printf("k: %d\n", k);
  +            printf("object: %d\n", object->whichend);
  +            printf("other: %d\n\n", other_object->whichend);
  +          }
  +#endif
  +
  +          if (add_conn) {
  +            new_conn =
  +              s_conn_return_new(other_object, CONN_ENDPOINT,
  +                                other_object->line->x[k],
  +                                other_object->line->y[k], 0, k);
  +
  +            /* do uniqness check */
  +            if (s_conn_uniq(object->conn_list, new_conn)) {
  +              object->conn_list =
  +                g_list_append(object->conn_list, new_conn);
  +            } else {
  +              free(new_conn);
  +            }
  +
  +            new_conn = s_conn_return_new(object, CONN_ENDPOINT,
  +                                         object->line->x[0],
  +                                         object->line->y[0], k, 0);
  +
  +            /* do uniqness check */
  +            if (s_conn_uniq(other_object->conn_list, new_conn)) {
  +              other_object->conn_list =
  +                g_list_append(other_object->conn_list,
  +                              new_conn);
  +            } else {
  +              free(new_conn);
  +            }
  +
  +#if DEBUG
  +            printf("first end point -> %d\n", k);
  +#endif
  +          }
  +        }
  +
  +        /* do second end point */
  +        if (object->line->x[1] == other_object->line->x[k] &&
  +            object->line->y[1] == other_object->line->y[k] &&
  +            object != other_object) {
  +          
  +          if (object->type == OBJ_PIN) {
  +            if (1 == object->whichend) {
  +              if (other_object->type == OBJ_PIN && /* new addition */
  +                  k != other_object->whichend ) { /* was 1 */
  +                add_conn = FALSE; 
  +              } else {
  +                add_conn = TRUE;
  +              }
  +            } else {
  +              add_conn = FALSE;
  +            }
  +          } else if (other_object->type == OBJ_PIN) {
  +            if (k == other_object->whichend) {
  +              if (object->type == OBJ_PIN && /* new addition */
  +                  k != object->whichend ) {
  +                add_conn = FALSE; 
  +              } else {
  +                add_conn = TRUE;
  +              }       
  +            } else {
  +              add_conn = FALSE;
  +            }
  +          } else {
  +            add_conn = TRUE;
  +          }
  +
  +          /* check for pin / bus compatibility */
  +          /* you cannot connect pins and buses at all */
  +          if (add_conn) {
  +            if ((object->type == OBJ_PIN && other_object->type == OBJ_BUS) ||
  +                (object->type == OBJ_BUS && other_object->type == OBJ_PIN)) {
  +              add_conn = FALSE;
  +            } else {
  +              add_conn = TRUE;
  +            }
  +          }
  +
  +          /* check for net / bus compatibility */
  +          /* you cannot connect the endpoint of a bus to a net */
  +          /* and the reverse is true as well */
  +          if (add_conn) {
  +            if ((object->type == OBJ_NET && other_object->type == OBJ_BUS) ||
  +                (object->type == OBJ_BUS && other_object->type == OBJ_NET)) {
  +              add_conn = FALSE;
  +            } else {
  +              add_conn = TRUE;
  +            }
  +          }
  +
  +#if DEBUG
  +          if (add_conn) {
  +            printf("1\n");
  +            printf("k: %d\n", k);
  +            printf("object: %d\n", object->whichend);
  +            printf("other: %d\n\n", other_object->whichend);
  +          }
  +#endif
  +          
  +          if (add_conn) {
  +            new_conn =
  +              s_conn_return_new(other_object, CONN_ENDPOINT,
  +                                other_object->line->x[k],
  +                                other_object->line->y[k], 1, k);
  +
  +            /* do uniqness check */
  +            if (s_conn_uniq(object->conn_list, new_conn)) {
  +              object->conn_list =
  +                g_list_append(object->conn_list, new_conn);
  +            } else {
  +              free(new_conn);
  +            }
  +
  +            new_conn = s_conn_return_new(object, CONN_ENDPOINT,
  +                                         object->line->x[1],
  +                                         object->line->y[1], k, 1);
  +
  +            /* do uniqness check */
  +            if (s_conn_uniq(other_object->conn_list, new_conn)) {
  +              other_object->conn_list =
  +                g_list_append(other_object->conn_list,
  +                              new_conn);
  +            } else {
  +              free(new_conn);
  +            }
  +
  +#if DEBUG
  +            printf("second end point -> %d\n", k);
  +#endif
  +          }
  +        }
  +        
  +
  +        /* check for midpoint of other object, k endpoint of current obj*/
  +        found = s_conn_check_midpoint(other_object,
  +                                      object->line->x[k],
  +                                      object->line->y[k]);
  +
  +        /* pins are not allowed midpoint connections (on them) */
  +        /* pins can cause midpoint connections (via their endpoints) */
  +        if (found && other_object->type != OBJ_PIN) { /* found midpoint */
  +          /* have to add it to the current object and other object */
  +#if DEBUG         
  +          printf("%d endpoint to %s midpoint of: %s\n", k, object->name,
  +                 found->name);
  +#endif          
  +
  +          if (object->type == OBJ_PIN) {
  +            if (k == object->whichend) {
  +              add_conn = TRUE;
  +            } else {
  +              add_conn = FALSE;
  +            }
  +          } else {
  +            add_conn = TRUE;
  +          }
  +
  +          /* check for pin / bus compatibility */
  +          /* you cannot connect pins and buses at all */
  +          if (add_conn) {
  +            if ((object->type == OBJ_PIN && other_object->type == OBJ_BUS) ||
  +                (object->type == OBJ_BUS && other_object->type == OBJ_PIN)) {
  +              add_conn = FALSE;
  +            } else {
  +              add_conn = TRUE;
  +            }
  +          }
  +
  +          /* check for bus / net compatibility */
  +          /* you cannot have the middle of bus connect to nets */
  +          if (add_conn) {
  +            if (object->type == OBJ_BUS && other_object->type == OBJ_NET) {
  +              add_conn = FALSE;
  +            } else {
  +              add_conn = TRUE;
  +            }
  +          }
  +
  +          if (add_conn) {
  +            /* First do the other object and put it in the current */
  +            /* object list */
  +            new_conn =
  +              s_conn_return_new(other_object, CONN_MIDPOINT,
  +                                object->line->x[k],
  +                                object->line->y[k], k, -1);
  +
  +            /* do uniqness check */
  +            if (s_conn_uniq(object->conn_list, new_conn)) {
  +              object->conn_list =
  +                g_list_append(object->conn_list, new_conn);
  +            } else {
  +              free(new_conn);
  +            }
  +
  +            /* Next do the current object and put it into the other */
  +            /* object list */
  +            new_conn = s_conn_return_new(object, CONN_MIDPOINT,
  +                                         object->line->x[k],
  +                                         object->line->y[k], -1, k);
  +
  +            /* do uniqness check */
  +            if (s_conn_uniq(other_object->conn_list, new_conn)) {
  +              other_object->conn_list =
  +                g_list_append(other_object->conn_list,
  +                              new_conn);
  +            } else {
  +              free(new_conn);
  +            }
  +
  +          }
  +        }
  +        
  +        /****/
  +
  +        /* do object's endpoints cross the middle of other_object? */
  +        /* check for midpoint of other object, k endpoint of current obj*/
  +        found = s_conn_check_midpoint(object,
  +                                      other_object->line->x[k],
  +                                      other_object->line->y[k]);
  +
  +        /* pins are not allowed midpoint connections (on them) */
  +        /* pins can cause midpoint connections (via their endpoints) */
  +        if (found && object->type != OBJ_PIN) { /* found midpoint */
  +          /* have to add it to the current object and other object */
  +#if DEBUG          
  +          printf("SECOND! %d endpoint to %s midpoint of: %s\n", k,
  +                 other_object->name,
  +                 found->name);
  +#endif          
  +
  +          if (other_object->type == OBJ_PIN) {
  +            if (k == other_object->whichend) {
  +              add_conn = TRUE;
  +            } else {
  +              add_conn = FALSE;
  +            }
  +          } else {
  +            add_conn = TRUE;
  +          }
  +
  +          
  +          /* check for pin / bus compatibility */
  +          /* you cannot connect pins and buses at all */
  +          if (add_conn) {
  +            if ((object->type == OBJ_PIN && other_object->type == OBJ_BUS) ||
  +                (object->type == OBJ_BUS && other_object->type == OBJ_PIN)) {
  +              add_conn = FALSE;
  +            } else {
  +              add_conn = TRUE;
  +            }
  +          }
  +
  +          /* check for bus / net compatibility */
  +          /* you cannot have the middle of bus connect to nets */
  +          if (add_conn) {
  +            if (object->type == OBJ_NET && other_object->type == OBJ_BUS) {
  +              add_conn = FALSE;
  +            } else {
  +              add_conn = TRUE;
  +            }
  +          }
  +
  +          
  +          if (add_conn) {
  +            /* First do the other object and put it in the current */
  +            /* object list */
  +            new_conn =
  +              s_conn_return_new(other_object, CONN_MIDPOINT,
  +                                other_object->line->x[k],
  +                                other_object->line->y[k], -1, k);
  +
  +            /* do uniqness check */
  +            if (s_conn_uniq(object->conn_list, new_conn)) {
  +              object->conn_list =
  +                g_list_append(object->conn_list, new_conn);
  +            } else {
  +              free(new_conn);
  +            }
  +
  +            /* Next do the current object and put it into the other */
  +            /* object list */
  +            new_conn = s_conn_return_new(object, CONN_MIDPOINT,
  +                                         other_object->line->x[k],
  +                                         other_object->line->y[k], k, -1);
  +
  +            /* do uniqness check */
  +            if (s_conn_uniq(other_object->conn_list, new_conn)) {
  +              other_object->conn_list =
  +                g_list_append(other_object->conn_list,
  +                              new_conn);
  +            } else {
  +              free(new_conn);
  +            }
  +
  +          }
  +          /* **** */
  +          
  +        } /* found midpoint */
  +
  +      } /* end of for over endpoints */
  +
  +      object_list = object_list->next;
  +    } 
  +
  +    tloc_list = tloc_list->next;
  +  }
  +
  +#if DEBUG
  +  s_conn_print(object->conn_list);
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_conn_update_complex(TOPLEVEL * w_current, OBJECT * complex)
  +{
  +  OBJECT *o_current;
  +
  +  o_current = complex;
  +  while (o_current != NULL) {
  +    switch (o_current->type) {
  +      case (OBJ_PIN):
  +      case (OBJ_NET):
  +      case (OBJ_BUS):
  +        s_conn_update_object(w_current, o_current);
  +        break;
  +
  +    }
  +    o_current = o_current->next;
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_conn_print(GList * conn_list)
  +{
  +  CONN *conn;
  +  GList *cl_current;
  +
  +  printf("\nStarting s_conn_print\n");
  +  cl_current = conn_list;
  +  while (cl_current != NULL) {
  +
  +    conn = (CONN *) cl_current->data;
  +    printf("-----------------------------------\n");
  +    printf("other object: %s\n", conn->other_object->name);
  +    printf("type: %d\n", conn->type);
  +    printf("x: %d y: %d\n", conn->x, conn->y);
  +    printf("whichone: %d\n", conn->whichone);
  +    printf("other_whichone: %d\n", conn->other_whichone);
  +    printf("-----------------------------------\n");
  +
  +    cl_current = cl_current->next;
  +  }
  +
  +}
  +
  +/*! \brief Search for net in existing connections.
  + *  \par Function Description
  + *  This method searches the connection list for the first matching
  + *  connection with the given x, y, and whichone endpoint.
  + *
  + *  \param [in] new_net    Net OBJECT to compare to.
  + *  \param [in] whichone   The connection number to check.
  + *  \param [in] conn_list  List of existing connections to compare
  + *                         <B>new_net</B> to.
  + *  \return TRUE if a matching connection is found, FALSE otherwise. 
  + */
  +int s_conn_net_search(OBJECT* new_net, int whichone, GList * conn_list)
  +{
  +  CONN *conn;
  +  GList *cl_current;
  +
  +  cl_current = conn_list;
  +  while (cl_current != NULL) {
  +
  +    conn = (CONN *) cl_current->data;
  +    if (conn != NULL && conn->whichone == whichone && 
  +        conn->x == new_net->line->x[whichone] &&
  +	conn->y == new_net->line->y[whichone])
  +    {
  +       return TRUE;
  +    }
  +
  +    cl_current = cl_current->next;
  +  }
  + 
  +  return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \warning
  + *  Caller must free returned GList pointer.
  + *  Do not free individual data items in list.
  + */
  +GList *s_conn_return_others(GList *input_list, OBJECT *object)
  +{
  +  CONN *conn;
  +  GList *cl_current;
  +  GList *return_list=NULL;
  +
  +  return_list = input_list;
  +  
  +  cl_current = object->conn_list;
  +  while (cl_current != NULL) {
  +
  +    conn = (CONN *) cl_current->data;
  +    
  +    if (conn->other_object && conn->other_object != object) {
  +      return_list = g_list_append(return_list, conn->other_object);
  +    }
  +        
  +    cl_current = cl_current->next;
  +  }
  +
  +  return(return_list);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \warning
  + *  Caller must free returned GList pointer.
  + *  Do not free individual data items in list.
  + */
  +GList *s_conn_return_complex_others(GList *input_list, OBJECT *object)
  +{
  +  OBJECT *o_current;
  +  CONN *conn;
  +  GList *cl_current;
  +  GList *return_list=NULL;
  +
  +  if (object->type != OBJ_COMPLEX && object->type != OBJ_PLACEHOLDER) {
  +    return(NULL);
  +  }
  +
  +  return_list = input_list;
  +  
  +  o_current = object->complex->prim_objs;
  +  while(o_current != NULL) {
  +    cl_current = o_current->conn_list;
  +    while (cl_current != NULL) {
  +
  +      conn = (CONN *) cl_current->data;
  +    
  +      if (conn->other_object && conn->other_object != o_current) {
  +        return_list = g_list_append(return_list, conn->other_object);
  +      }
  +        
  +      cl_current = cl_current->next;
  +    }
  +
  +    o_current = o_current->next;
  +  }
  +  
  +  return(return_list);
  +}
  
  
  
  1.4       +285 -192  eda/geda/gaf/libgeda/src/s_cue.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_cue.c
  ===================================================================
  RCS file: s_cue.c
  diff -N s_cue.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ s_cue.c	5 Jul 2006 03:13:38 -0000	1.4
  @@ -0,0 +1,387 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <ctype.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_ASSERT_H
  +#include <assert.h>
  +#endif
  +#ifndef HAVE_VSNPRINTF
  +#include <stdarg.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "defines.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_cue_postscript_fillbox(TOPLEVEL * w_current, FILE * fp, int x,
  +			      int y)
  +{
  +  int offset;
  +  int offset2;
  +
  +  /* hard coded values */
  +  offset = CUE_BOX_SIZE;
  +  offset2 = offset*2;
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, w_current->net_endpoint_color);
  +  }
  +
  +  fprintf(fp, "%d %d %d %d fbox\n", 
  +	   offset2, offset2, x-offset, y-offset);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_cue_postscript_fillcircle(TOPLEVEL * w_current, FILE * fp,
  +                                 int x, int y, int size_flag)
  +{
  +  int offset2;
  +
  +  if (!size_flag) {
  +    offset2 = CUE_CIRCLE_LARGE_SIZE;
  +  } else {
  +    offset2 = CUE_CIRCLE_SMALL_SIZE;
  +  }
  +
  +  if (w_current->print_color) {
  +    f_print_set_color(fp, w_current->net_endpoint_color);
  +  }
  +
  +  fprintf(fp, "newpath\n");
  +  fprintf(fp, "%d %d\n", x, y);
  +  fprintf(fp, "%d\n", offset2 / 2);
  +  fprintf(fp, "0 360 arc\n");
  +  fprintf(fp, "fill\n");
  +}
  +
  +#ifdef HAS_LIBGDGEDA
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_cue_image_fillbox(TOPLEVEL * w_current, OBJECT * object, int world_x,
  +			 int world_y)
  +{
  +  int endpoint_color;
  +  int offset, offset2;
  +  int x, y;
  +
  +  if (w_current->image_color == TRUE) {
  +    endpoint_color =
  +      o_image_geda2gd_color(w_current->net_endpoint_color);
  +  } else {
  +    endpoint_color = image_black;
  +  }
  +
  +  WORLDtoSCREEN(w_current, world_x, world_y, &x, &y);
  +
  +  offset = SCREENabs(w_current, CUE_BOX_SIZE);
  +  offset2 = offset * 2;
  +
  +  gdImageFilledRectangle(current_im_ptr,
  +                         x - offset, y - offset, x - offset + offset2,
  +                         y - offset + offset2, endpoint_color);
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_cue_image_fillcircle(TOPLEVEL * w_current, int world_x, int world_y,
  +                            int size_flag)
  +{
  +  int endpoint_color;
  +  int offset, offset2;
  +  int i;
  +  int x, y;
  +
  +  if (w_current->image_color == TRUE) {
  +    endpoint_color =
  +      o_image_geda2gd_color(w_current->net_endpoint_color);
  +  } else {
  +    endpoint_color = image_black;
  +  }
  +
  +  WORLDtoSCREEN(w_current, world_x, world_y, &x, &y);
  +
  +  /* this needs to be rewritten to be much cleaner */
  +  if (!size_flag) {
  +    offset = SCREENabs(w_current, 30); /* large size */
  +  } else {
  +    offset = SCREENabs(w_current, 10);  /* small size */
  +  }
  +  offset2 = offset * 2;
  +
  +  gdImageArc(current_im_ptr, x, y,
  +             offset2 * 1.25, offset2 * 1.25, 0, 360, endpoint_color);
  +
  +  for (i = 0; i < offset2 * 1.25; i++) {
  +    gdImageArc(current_im_ptr, x, y, i, i, 0, 360, endpoint_color);
  +  }
  +
  +}
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_cue_output_all(TOPLEVEL * w_current, OBJECT * head, FILE * fp,
  +		      int type)
  +{
  +  OBJECT *o_current;
  +
  +  o_current = head;
  +  while (o_current != NULL) {
  +    switch (o_current->type) {
  +      case (OBJ_NET):
  +      case (OBJ_BUS):
  +      case (OBJ_PIN):
  +        s_cue_output_single(w_current, o_current, fp, type);
  +        break;
  +
  +      case (OBJ_COMPLEX):
  +      case (OBJ_PLACEHOLDER):
  +        s_cue_output_all(w_current, o_current->complex->prim_objs, fp,
  +                         type);
  +        break;
  +
  +    }
  +
  +    o_current = o_current->next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_cue_output_lowlevel(TOPLEVEL * w_current, OBJECT * object, int whichone,
  +			   FILE * fp, int output_type)
  +{
  +  int x, y;
  +  GList *cl_current;
  +  CONN *conn;
  +  int type, count = 0;
  +  int done = FALSE;
  +  int bus_involved = FALSE;
  +
  +  x = object->line->x[whichone];
  +  y = object->line->y[whichone];
  +
  +  type = CONN_ENDPOINT;
  +
  +  cl_current = object->conn_list;
  +  while (cl_current != NULL && !done) {
  +    conn = (CONN *) cl_current->data;
  +
  +    if (conn->x == x && conn->y == y) {
  +      switch (conn->type) {
  +
  +        case (CONN_ENDPOINT):
  +          count++;
  +          if (conn->other_object &&
  +              ((object->type == OBJ_NET &&
  +                conn->other_object->type == OBJ_BUS) ||
  +               (object->type == OBJ_BUS &&
  +                conn->other_object->type == OBJ_NET))) {
  +            bus_involved=TRUE;
  +          }
  +          break;
  +
  +        case (CONN_MIDPOINT):
  +          type = CONN_MIDPOINT;
  +          done = TRUE;
  +          count = 0;
  +          if (conn->other_object &&
  +              ((object->type == OBJ_NET &&
  +                conn->other_object->type == OBJ_BUS) ||
  +               (object->type == OBJ_BUS &&
  +                conn->other_object->type == OBJ_NET))) {
  +            bus_involved=TRUE;
  +          }
  +          break;
  +      }
  +    }
  +
  +    cl_current = cl_current->next;
  +  }
  +
  +#if DEBUG
  +  printf("type: %d count: %d\n", type, count);
  +#endif
  +
  +  switch (type) {
  +
  +    case (CONN_ENDPOINT):
  +      if (object->type == OBJ_NET) {	/* only nets have these cues */
  +        if (count < 1) {	/* Didn't find anything connected there */
  +          if (output_type == POSTSCRIPT) {
  +            s_cue_postscript_fillbox(w_current, fp, x, y);
  +#ifdef HAS_LIBGDGEDA
  +          } else if (output_type == PNG) {
  +            s_cue_image_fillbox(w_current, object, x, y);
  +#endif
  +          }
  +
  +
  +        } else if (count >= 2) {
  +          if (output_type == POSTSCRIPT) {
  +            if (!bus_involved) {
  +              s_cue_postscript_fillcircle(w_current, fp, x, y, FALSE);
  +            } else {
  +              s_cue_postscript_fillcircle(w_current, fp, x, y, TRUE);
  +            }
  +#ifdef HAS_LIBGDGEDA
  +          } else if (output_type == PNG) {
  +            if (!bus_involved) {
  +              s_cue_image_fillcircle(w_current, x, y, FALSE);
  +            } else {
  +              s_cue_image_fillcircle(w_current, x, y, TRUE);
  +            }
  +#endif
  +          }
  +        }
  +      }
  +      break;
  +
  +    case (CONN_MIDPOINT):
  +      if (output_type == POSTSCRIPT) {
  +        if (!bus_involved) {
  +          s_cue_postscript_fillcircle(w_current, fp, x, y, FALSE);
  +        } else {
  +          s_cue_postscript_fillcircle(w_current, fp, x, y, TRUE);
  +        }
  +#ifdef HAS_LIBGDGEDA
  +      } else if (output_type == PNG) {
  +        if (!bus_involved) {
  +          s_cue_image_fillcircle(w_current, x, y, FALSE);
  +        } else {
  +          s_cue_image_fillcircle(w_current, x, y, TRUE);
  +        }
  +#endif
  +      }
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_cue_output_lowlevel_midpoints(TOPLEVEL * w_current, OBJECT * object,
  +				     FILE * fp, int output_type)
  +{
  +  int x, y;
  +  GList *cl_current;
  +  CONN *conn;
  +  int size_flag;
  +
  +  cl_current = object->conn_list;
  +  while (cl_current != NULL) {
  +    conn = (CONN *) cl_current->data;
  +
  +    switch (conn->type) {
  +      case (CONN_MIDPOINT):
  +
  +        x = conn->x;
  +        y = conn->y;
  +
  +        if (conn->other_object &&
  +          ( (object->type == OBJ_BUS &&
  +             conn->other_object->type == OBJ_NET) ||
  +            (object->type == OBJ_NET &&
  +             conn->other_object->type == OBJ_BUS))) {
  +        size_flag = TRUE;
  +      } else {
  +        size_flag = FALSE;
  +      }
  +
  +        
  +        if (output_type == POSTSCRIPT) {
  +          s_cue_postscript_fillcircle(w_current, fp, x, y, size_flag);
  +#ifdef HAS_LIBGDGEDA
  +        } else if (output_type == PNG) {
  +          s_cue_image_fillcircle(w_current, x, y, size_flag);
  +#endif
  +        }
  +        break;
  +    }
  +
  +
  +    cl_current = cl_current->next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_cue_output_single(TOPLEVEL * w_current, OBJECT * object, FILE * fp,
  +			 int type)
  +{
  +  if (!object) {
  +    return;
  +  }
  +
  +  if (object->type != OBJ_NET && object->type != OBJ_PIN &&
  +      object->type != OBJ_BUS) {
  +	return;
  +      }
  +
  +  s_cue_output_lowlevel(w_current, object, 0, fp, type);
  +  s_cue_output_lowlevel(w_current, object, 1, fp, type);
  +  s_cue_output_lowlevel_midpoints(w_current, object, fp, type);
  +}
  +
  +
  +
  
  
  
  1.1                  eda/geda/gaf/libgeda/src/s_encoding.c
  
  Index: s_encoding.c
  ===================================================================
  /*! \verbatim
   ***********************************************************************
   *                   _     _                     __   _  _
   *   __ _ _ __   ___| |_  | |__   __ _ ___  ___ / /_ | || |
   *  / _` | '_ \ / _ \ __| | '_ \ / _` / __|/ _ \ '_ \| || |_
   * | (_| | | | |  __/ |_  | |_) | (_| \__ \  __/ (_) |__   _|
   *  \__, |_| |_|\___|\__| |_.__/ \__,_|___/\___|\___/   |_|
   *  |___/
   *
   *  created by Alfred Reibenschuh <alfredreibenschuh@xxxxxxx>,
   *  under the ``GNU Library General Public License´´ (see below).
   *
   ***********************************************************************
   *
   * Copyright (C) 2003 Free Software Foundation
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Library General Public
   * License as published by the Free Software Foundation; either
   * version 2 of the License, or (at your option) any later version.
   *
   * This library 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
   * Library General Public License for more details.
   *
   * You should have received a copy of the GNU Library General Public
   * License along with this library; if not, write to the Free
   * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   *
   ***********************************************************************
      \endverbatim
   *
   *  Taken from gnet's sources
   *  Modified the name of the functions and some variables
   */
  #ifdef HAVE_CONFIG_H
  #include "config.h"
  #endif
  
  #include <ctype.h>
  #include <glib.h>
  #ifdef HAVE_STRING_H
  #include <string.h>
  #endif
  
  static gchar s_encoding_Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  #define s_encoding_Pad64	'='
  static guchar s_encoding_Base64_rank[256] = {
  	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*	0x00-0x0f	*/
  	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*	0x10-0x1f	*/
  	255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63, /*	0x20-0x2f	*/
  	 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,255,255,255, /*	0x30-0x3f	*/
  	255,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, /*	0x40-0x4f	*/
  	 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, /*	0x50-0x5f	*/
  	255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /*	0x60-0x6f	*/
  	 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255, /*	0x70-0x7f	*/
  	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*	0x80-0x8f	*/
  	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*	0x90-0x9f	*/
  	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*	0xa0-0xaf	*/
  	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*	0xb0-0xbf	*/
  	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*	0xc0-0xcf	*/
  	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*	0xd0-0xdf	*/
  	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*	0xe0-0xef	*/
  	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*	0xf0-0xff	*/
  };
  
  /*! \brief Convert a buffer from binary to base64 representation.
   *  \par Function Description
   *  Convert a buffer from binary to base64 representation.  Set
   *  <B>strict</B> to TRUE to insert a newline every 72th character.  This is
   *  required by RFC 2045, but some applications don't require this.
   *  
   *  \param [in]  src      Source buffer.
   *  \param [in]  srclen   Length of source buffer.
   *  \param [out] dstlenp  Length of buffer returned
   *                        (including the terminating \\0).
   *  \param [in]  strict   Insert new lines as required by RFC 2045.
   *  \return Caller owned buffer containing base64 representation.
   */
  gchar* s_encoding_base64_encode (gchar* src, guint srclen, 
  				 guint* dstlenp, gboolean strict) 
  {
    gchar* dst;
    guint dstpos;
    guchar input[3];
    guchar output[4];
    guint ocnt;
    guint i;
  
    if (srclen == 0) 
      return NULL;	/* FIX: Or return ""? */
  
    /* Calculate required length of dst.  4 bytes of dst are needed for
       every 3 bytes of src. */
    *dstlenp = (((srclen + 2) / 3) * 4)+5;
    if (strict)
      *dstlenp += (*dstlenp / 72);	/* Handle trailing \n */
  
    dst = g_new(gchar, *dstlenp );
  
    /* bulk encoding */
    dstpos = 0;
    ocnt = 0;
    while (srclen >= 3) 
      {
        /*
  	Convert 3 bytes of src to 4 bytes of output
  
  	output[0] = input[0] 7:2
  	output[1] = input[0] 1:0 input[1] 7:4
  	output[2] = input[1] 3:0 input[2] 7:6
  	output[3] = input[1] 5:0
  
         */
        input[0] = *src++;
        input[1] = *src++;
        input[2] = *src++;
        srclen -= 3;
  
        output[0] = (input[0] >> 2);
        output[1] = ((input[0] & 0x03) << 4) + 
  	(input[1] >> 4);
        output[2] = ((input[1] & 0x0f) << 2) + 
  	(input[2] >> 6);
        output[3] = (input[2] & 0x3f);
  
        g_assert ((dstpos + 4) < *dstlenp);
  
        /* Map output to the Base64 alphabet */
        dst[dstpos++] = s_encoding_Base64[(guint) output[0]];
        dst[dstpos++] = s_encoding_Base64[(guint) output[1]];
        dst[dstpos++] = s_encoding_Base64[(guint) output[2]];
        dst[dstpos++] = s_encoding_Base64[(guint) output[3]];
  
        /* Add a newline if strict and  */
        if (strict)
  	if ((++ocnt % (72/4)) == 0) 
  	  dst[dstpos++] = '\n';
      }
  
    /* Now worry about padding with remaining 1 or 2 bytes */
    if (srclen != 0) 
      {
        input[0] = input[1] = input[2] = '\0';
        for (i = 0; i < srclen; i++) 
  	input[i] = *src++;
  
        output[0] = (input[0] >> 2);
        output[1] = ((input[0] & 0x03) << 4) + 
  	(input[1] >> 4);
        output[2] = ((input[1] & 0x0f) << 2) + 
  	(input[2] >> 6);
  
        g_assert ((dstpos + 4) < *dstlenp);
  
        dst[dstpos++] = s_encoding_Base64[(guint) output[0]];
        dst[dstpos++] = s_encoding_Base64[(guint) output[1]];
  
        if (srclen == 1)
  	dst[dstpos++] = s_encoding_Pad64;
        else
  	dst[dstpos++] = s_encoding_Base64[(guint) output[2]];
  
        dst[dstpos++] = s_encoding_Pad64;
      }
  
    g_assert (dstpos <= *dstlenp);
  
    dst[dstpos] = '\0';
  
    *dstlenp = dstpos + 1;
  
    return dst;
  }
  
  /*! \brief Convert a buffer from base64 to binary representation.
   *  \par Function Description
   *  Convert a buffer from base64 to binary representation.  This
   *  function is liberal in what it will accept.  It ignores non-base64
   *  symbols.
   *  
   *  \param [in]  src      Source buffer.
   *  \param [in]  srclen   Length of the source buffer.
   *  \param [out] dstlenp  Pointer to length of the destination buffer
   *  \return Caller-owned buffer with binary representation.
   *          The integer pointed to by <B>dstlenp</B> is set to the length
   *          of that buffer.
   */
  gchar *s_encoding_base64_decode (gchar* src, guint srclen, guint* dstlenp)
  {
  
    gchar* dst;
    guint   dstidx, state, ch = 0;
    gchar  res;
    guchar pos;
  
    if (srclen == 0) 
      srclen = strlen(src);
    state = 0;
    dstidx = 0;
    res = 0;
  
    dst = g_new(gchar, srclen+1);
    *dstlenp = srclen+1;
  
    while (srclen-- > 0) 
      {
        ch = *src++;
        if (s_encoding_Base64_rank[ch]==255) /* Skip any non-base64 anywhere */
  	continue;
        if (ch == s_encoding_Pad64) 
  	break;
  
        pos = s_encoding_Base64_rank[ch];
  
        switch (state) 
  	{
  	case 0:
  	  if (dst != NULL) 
  	    {
  	      dst[dstidx] = (pos << 2);
  	    }
  	  state = 1;
  	  break;
  	case 1:
  	  if (dst != NULL) 
  	    {
  	      dst[dstidx] |= (pos >> 4);
  	      res = ((pos & 0x0f) << 4);
  	    }
  	  dstidx++;
  	  state = 2;
  	  break;
  	case 2:
  	  if (dst != NULL) 
  	    {
  	      dst[dstidx] = res | (pos >> 2);
  	      res = (pos & 0x03) << 6;
  	    }
  	  dstidx++;
  	  state = 3;
  	  break;
  	case 3:
  	  if (dst != NULL) 
  	    {
  	      dst[dstidx] = res | pos;
  	    }
  	  dstidx++;
  	  state = 0;
  	  break;
  	default:
  	  break;
  	}
      }
    /*
     * We are done decoding Base-64 chars.  Let's see if we ended
     * on a byte boundary, and/or with erroneous trailing characters.
     */
    if (ch == s_encoding_Pad64)           /* We got a pad char. */
      {
        switch (state) 
  	{
  	case 0:             /* Invalid = in first position */
  	case 1:             /* Invalid = in second position */
  	  return NULL;
  	case 2:             /* Valid, means one byte of info */
                                  /* Skip any number of spaces. */
  	  while (srclen-- > 0) 
  	    {
  	      ch = *src++;
  	      if (s_encoding_Base64_rank[ch] != 255) break;
  	    }
                                  /* Make sure there is another trailing = sign. */
  	  if (ch != s_encoding_Pad64) 
  	    {
  	      g_free(dst);
  	      *dstlenp = 0;
  	      return NULL;
  	    }
                                  /* FALLTHROUGH */
  	case 3:             /* Valid, means two bytes of info */
                                  /*
                                   * We know this char is an =.  Is there anything but
                                   * whitespace after it?
                                   */
  	  while (srclen-- > 0) 
  	    {
  	      ch = *src++;
  	      if (s_encoding_Base64_rank[ch] != 255) 
  		{
  		  g_free(dst);
  		  *dstlenp = 0;
  		  return NULL;
  		}
  	    }
                                  /*
                                   * Now make sure for cases 2 and 3 that the "extra"
                                   * bits that slopped past the last full byte were
                                   * zeros.  If we don't check them, they become a
                                   * subliminal channel.
                                   */
  	  if (dst != NULL && res != 0) 
  	    {
  	      g_free(dst);
  	      *dstlenp = 0;
  	      return NULL;
  	    }
  	default:
  	  break;
  	}
      } else 
        {
  	/*
  	 * We ended by seeing the end of the string.  Make sure we
  	 * have no partial bytes lying around.
  	 */
  	if (state != 0) 
  	  {
  	    g_free(dst);
  	    *dstlenp = 0;
  	    return NULL;
  	  }
        }
    dst[dstidx]=0;
    *dstlenp = dstidx;
    return dst;
  }
  
  
  
  1.13      +353 -190  eda/geda/gaf/libgeda/src/s_hierarchy.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_hierarchy.c
  ===================================================================
  RCS file: s_hierarchy.c
  diff -N s_hierarchy.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ s_hierarchy.c	5 Jul 2006 03:13:39 -0000	1.13
  @@ -0,0 +1,430 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_ASSERT_H
  +#include <assert.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "defines.h"
  +#include "globals.h"
  +#include "o_types.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \brief */
  +static int page_control_counter=0;
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief Search for schematic associated source files and load them.
  + *  \par Function Description
  + *  This function searches the associated source file refered by the
  + *  <B>filename</B> and loads it.  If the <B>flag</B> is set to
  + *  <B>HIERARCHY_NORMAL_LOAD</B> and the page is allready in the list of
  + *  pages it will return the <B>pid</B> of that page.
  + *  If the <B>flag</B> is set to <B>HIERARCHY_FORCE_LOAD</B> then this
  + *  function will load the page again with a new page id. The second case
  + *  is mainly used by gnetlist where pushed down schematics MUST be unique.
  + *
  + *  \param [in] w_current     The TOPLEVEL object.
  + *  \param [in] filename      Schematic file name.
  + *  \param [in] parent        The parent page of the schematic.
  + *  \param [in] page_control
  + *  \param [in] flag
  + *  \return The number of pages loaded, -1 otherwise.
  + *
  + *  \note
  + *  This function goes and finds the associated source files and
  + *  loads all up
  + *  It only works for schematic files though
  + *  this is basically push
  + *  flag can either be HIERARCHY_NORMAL_LOAD or HIERARCHY_FORCE_LOAD
  + *  flag is mainly used by gnetlist where pushed down schematics MUST be unique
  + */
  +int s_hierarchy_down_schematic_single(TOPLEVEL *w_current,
  +				      const gchar *filename, PAGE *parent,
  +				      int page_control, int flag) 
  +{
  +  gchar *string;
  +  PAGE *found;
  +  PAGE *forbear;
  +
  +  string = s_slib_search_single(filename);
  +  if (string == NULL) {
  +    return -1;
  +  }
  +
  +  switch (flag) {
  +    case HIERARCHY_NORMAL_LOAD:
  +    {
  +      found = s_page_search (w_current, string);
  +      
  +      if (found) {
  +	/* check whether this page is in the parents list */
  +	for (forbear = parent; 
  +	     forbear != NULL && found->pid != forbear->pid && forbear->up >= 0;
  +	     forbear = s_page_search_pid(w_current, forbear->up))
  +	  ; /* void */
  +
  +	if (found->pid == forbear->pid) {
  +	  s_log_message("hierarchy loop detected while visiting page:\n"
  +			"  \"%s\"\n",found->page_filename);
  +	  return -1;  /* error signal */
  +	}
  +        s_page_goto (w_current, found);
  +        if (page_control != 0) {
  +          found->page_control = page_control;
  +        }
  +        found->up = parent->pid;
  +        g_free (string);
  +        return found->page_control;
  +      }
  +      
  +      found = s_page_new (w_current, string);
  +      s_page_goto (w_current, found);
  +      
  +      f_open (w_current, found->page_filename);
  +    }
  +    break;
  +
  +    case HIERARCHY_FORCE_LOAD:
  +    {
  +      PAGE *page = s_page_new (w_current, string);
  +      s_page_goto (w_current, page);
  +      f_open (w_current, page->page_filename);
  +    }
  +    break;
  +  }
  +
  +  if (page_control == 0) {
  +    page_control_counter++;
  +    w_current->page_current->page_control = page_control_counter;
  +  } else {
  +    w_current->page_current->page_control = page_control;
  +  }
  +
  +  w_current->page_current->up = parent->pid;
  +
  +  s_page_goto(w_current, w_current->page_current);
  +
  +  g_free (string);
  +
  +  return(page_control_counter);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  This function goes and finds the associated source files and loads ALL up
  + *  only works for schematic files though
  + *  this is basically push
  + */
  +void s_hierarchy_down_schematic_multiple (TOPLEVEL *w_current,
  +					  const gchar *filename, PAGE *parent) 
  +{
  +  char *string=NULL;
  +  PAGE *save_first_page=NULL;
  +  PAGE *found;
  +  int loaded_schematics=0;
  +
  +  s_slib_search (NULL, SLIB_SEARCH_START);
  +
  +  string = s_slib_search (filename, SLIB_SEARCH_NEXT);
  +  while (string != NULL) {
  +
  +    found = s_page_new(w_current, string);
  +
  +    if (found) {
  +      w_current->page_current = found;
  +      s_page_goto(w_current, found);
  +      if (string) 
  +        free(string);
  +      return;
  +    }
  +
  +    f_open(w_current, w_current->page_current->page_filename);
  +
  +    if (loaded_schematics == 0) {
  +      page_control_counter++;
  +      save_first_page = w_current->page_current;
  +      /* parent->down = w_current->page_current; not needed */
  +      w_current->page_current->page_control = 
  +        page_control_counter;
  +      loaded_schematics=1;
  +    } else {
  +      w_current->page_current->page_control = 
  +        page_control_counter;
  +    }
  +
  +    w_current->page_current->up = parent->pid;
  +    /* w_current->page_current->down = NULL; not needed */
  +
  +    if (string) 
  +      free(string);
  +
  +    string = s_slib_search(filename, SLIB_SEARCH_NEXT);
  +  }
  +
  +  s_slib_search(NULL, SLIB_SEARCH_DONE);
  +
  +  g_free (string);
  +
  +  if (loaded_schematics) {
  +    w_current->page_current = save_first_page;
  +  }
  +
  +  s_page_goto (w_current, w_current->page_current);
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_hierarchy_down_symbol (TOPLEVEL *w_current,
  +			      const gchar *filename, PAGE *parent)
  +{
  +  PAGE *page;
  +
  +  page = s_page_search (w_current, filename);
  +  if (page) {
  +    s_page_goto (w_current, page);
  +    return;
  +  }
  +
  +  page = s_page_new (w_current, filename);
  +  s_page_goto (w_current, page);
  +
  +  f_open(w_current, page->page_filename);
  +
  +  page->up = parent->pid;
  +  page_control_counter++;
  +  page->page_control = page_control_counter;
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_hierarchy_up(TOPLEVEL *w_current, int pid)
  +{
  +  PAGE *p_current;
  +
  +  if (pid < 0) {
  +    s_log_message("There are no schematics above the current one!\n");
  +    return;
  +  }
  +
  +  p_current = s_hierarchy_find_page(w_current->page_head, pid);
  +
  +  if (p_current) {
  +    s_page_goto(w_current, p_current);
  +  } else {
  +    s_log_message("Cannot find any schematics above the current one!\n");
  +    s_log_message("Maybe toplevel schematic page was closed/discarded?\n");
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  This function traverses the hierarchy tree of pages and returns a flat
  + *  list of pages that are below the current page. There are two
  + *  <B>flags</B>: <B>HIERARCHY_NODUPS</B>: returns a list without
  + *  duplicate pages 
  + *  <B>HIERARCHY_POSTORDER</B>: traverses the hierarchy tree and
  + *  returns a postorder list instead of preorder.
  + *
  + *  \return A GList of PAGE pointers.
  + *
  + *  \warning
  + *  Call must free returned GList.
  + */
  +GList *s_hierarchy_traversepages(TOPLEVEL *w_current,
  +				 gint flags)
  +{
  +  PAGE *p_current;
  +  OBJECT *o_current;
  +  char *filename = NULL;
  +  gint page_control = 0;
  +  static GList *pages = NULL;
  +  
  +  /* init static variables the first time*/
  +  if (!(flags & HIERARCHY_INNERLOOP)) {
  +    pages = NULL;
  +  }
  +
  +  p_current = w_current->page_current;
  +
  +  /* preorder traversing */
  +  if (!(flags & HIERARCHY_POSTORDER)) {
  +    /* check whether we already visited this page */
  +    if ((flags & HIERARCHY_NODUPS)
  +	&& (g_list_find(pages, p_current) != NULL)) {
  +      return pages;  /* drop the page subtree */
  +      }
  +    pages = g_list_append(pages, p_current);
  +  }
  +
  +  /* walk throught the page objects and search for underlaying schematics */
  +  for (o_current = p_current->object_head;
  +       o_current != NULL ;
  +       o_current = o_current->next) {
  +
  +    /* only complex things like symbols can contain attributes */
  +    if (o_current->type == OBJ_COMPLEX) {
  +      filename = o_attrib_search_name_single_count(o_current,
  +						   "source", 0);
  +      
  +      /* if above is NULL, then look inside symbol */
  +      if (filename == NULL) {
  +	filename = o_attrib_search_name(o_current->
  +				      complex->prim_objs, "source", 0);
  +      }
  +
  +      if (filename != NULL) {
  +	/* we got a schematic source attribute 
  +	   lets load the page and dive into it */
  +	page_control =s_hierarchy_down_schematic_single(w_current,
  +							filename,
  +							p_current,
  +							0,
  +							HIERARCHY_NORMAL_LOAD);
  +	if (page_control != -1) {
  +	  /* call the recursive function */
  +	  s_hierarchy_traversepages(w_current,
  +				    flags | HIERARCHY_INNERLOOP);
  +	  s_hierarchy_up(w_current, w_current->page_current->up);
  +	}
  +	else {
  +	  s_log_message("ERROR in s_hierarchy_traverse: "
  +			"schematic not found: %s\n", 
  +			filename);
  +	}
  +	
  +	g_free(filename);
  +	filename = NULL;
  +      }
  +    }
  +  }
  +
  +  /* postorder traversing */
  +  if (flags & HIERARCHY_POSTORDER) {
  +    /* check whether we already visited this page */
  +    if ((flags & HIERARCHY_NODUPS)
  +	&& (g_list_find(pages, p_current) != NULL)) {
  +      return pages;  /* don't append it */
  +    }
  +    pages = g_list_append(pages, p_current);
  +  }
  +
  +  return pages;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  Test function which only prints the name of a page and it's number.
  + */
  +gint s_hierarchy_print_page(PAGE *p_current, void * data)
  +{
  +  printf("pagefilename: %s pageid: %d\n", 
  +         p_current->page_filename, p_current->pid);
  +  return 0;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +PAGE *s_hierarchy_find_prev_page (PAGE *p_start, int page_control) 
  +{
  +  PAGE *p_current;	
  +
  +  for (p_current = p_start->prev;
  +       p_current != NULL;
  +       p_current = p_current->prev) {
  +    if (p_current->page_control == page_control) {
  +      return p_current;
  +    }
  +  }
  +
  +  return NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +PAGE *s_hierarchy_find_next_page (PAGE *p_start, int page_control)
  +{
  +  PAGE *p_current;	
  +
  +  for (p_current = p_start->next;
  +       p_current != NULL;
  +       p_current = p_current->next) {
  +    if (p_current->page_control == page_control) {
  +      return p_current;
  +    }
  +  }
  +
  +  return NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +PAGE *s_hierarchy_find_page (PAGE *p_start, int pid)
  +{
  +  PAGE *p_current = p_start;	
  +
  +  for (p_current = p_start;
  +       p_current != NULL;
  +       p_current = p_current->next) {
  +    if (p_current->pid == pid) {
  +      return p_current;
  +    }
  +  }
  +
  +  return NULL;
  +}
  
  
  
  1.12      +149 -83   eda/geda/gaf/libgeda/src/s_log.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_log.c
  ===================================================================
  RCS file: s_log.c
  diff -N s_log.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ s_log.c	5 Jul 2006 03:13:39 -0000	1.12
  @@ -0,0 +1,200 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <sys/stat.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_ASSERT_H
  +#include <assert.h>
  +#endif
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +#ifdef HAVE_STDARG_H
  +#include <stdarg.h>
  +#endif
  +#ifdef HAVE_FCNTL_H
  +#include <fcntl.h>
  +#endif
  +#ifdef HAVE_ERRNO_H
  +#include <errno.h>
  +#endif
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "defines.h"
  +#include "globals.h"
  +#include "funcs.h"
  +#include "o_types.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +
  +static void s_log_handler (const gchar *log_domain,
  +                           GLogLevelFlags log_level,
  +                           const gchar *message,
  +                           gpointer user_data);
  +
  +static int logfile_fd = -1;
  +
  +static guint log_handler_id;
  +
  +/*! \brief Initialize libgeda logging feature.
  + *  \par Function Description
  + *  This function opens the file <B>filename</B> to log to and registers the
  + *  handler to redirect log message to this file.
  + *
  + *  \param [in] filename  Character string with file name to log to.
  + */
  +void s_log_init (const gchar *filename)
  +{
  +  if (do_logging == FALSE) {
  +    logfile_fd = -1;
  +    return;
  +  }
  +
  +  /* create log file */
  +  logfile_fd = open (filename, O_RDWR|O_CREAT|O_TRUNC, 0600);
  +  if (logfile_fd == -1) {
  +    fprintf(stderr, "Could not open log file: %s\n", filename);
  +    fprintf(stderr, "Errno was: %d\n", errno);
  +    return;
  +  }
  +
  +  /* install the log handler */
  +  log_handler_id = g_log_set_handler (NULL,
  +                                      G_LOG_LEVEL_MESSAGE,
  +                                      s_log_handler,
  +                                      NULL);
  +
  +}
  +
  +/*! \brief Terminates the logging of messages.
  + *  \par Function Description
  + *  This function deregisters the handler for redirection to the log file
  + *  and closes it.
  + */
  +void s_log_close (void)
  +{
  +  do_logging = FALSE; /* subsequent messages are lost after the close */
  +
  +  if (logfile_fd == -1)
  +  {
  +    return;
  +  }
  +
  +  /* remove the handler */
  +  g_log_remove_handler (NULL, log_handler_id);
  +  
  +  /* close the file */
  +  if (logfile_fd != -1) {
  +    close (logfile_fd);
  +    logfile_fd = -1;
  +  }
  +
  +}
  +
  +/*! \brief  Reads the current log file and returns its contents.
  + *  \par Function Description
  + *  This function reads the current log file and returns its contents.
  + *
  + *  \return Character string with current log's contents.
  + *
  + */
  +gchar *s_log_read (void)
  +{
  +  gboolean tmp;
  +#define BUFSIZE 200  
  +  gchar buf[BUFSIZE];
  +  GString *contents;
  +  gint len;
  +  
  +  if (logfile_fd == -1) {
  +    return NULL;
  +  }
  +
  +  tmp = do_logging;
  +  do_logging = FALSE;
  +
  +  /* rewind the file */
  +  lseek(logfile_fd, 0, SEEK_SET);
  +
  +  /* read its contents and build a string */
  +  contents = g_string_new ("");
  +  while ((len = read (logfile_fd, &buf, BUFSIZE)) != 0) {
  +    contents = g_string_append_len (contents, buf, len);
  +  }
  +
  +  do_logging = tmp;
  +
  +  return g_string_free (contents, FALSE);
  +}
  +
  +/*! \brief Write a message to the current log file.
  + *  \par Function Description
  + *  Writes <B>message</B> to the current log file whose file descriptor
  + *  is <B>logfile_fd</B>.
  + *
  + *  It also sends <B>message</B> to the optional function <B>x_log_update</B>
  + *  for further use.
  + *
  + *  \param [in] log_domain  (unused).
  + *  \param [in] log_level   (unused).
  + *  \param [in] message     Character string containing message to 
  + *                          write to log.
  + *  \param [in] user_data   (unused).
  + *
  + */
  +static void s_log_handler (const gchar *log_domain,
  +			   GLogLevelFlags log_level,
  +			   const gchar *message,
  +			   gpointer user_data)
  +{
  +  int status;
  +
  +  if (do_logging == FALSE) {
  +    return;
  +  }
  +  g_assert (logfile_fd != -1);
  +  
  +  status = write (logfile_fd, message, strlen (message));
  +  if (status == -1) {
  +    fprintf(stderr, "Could not write message to log file\n");
  +    fprintf(stderr, "Message was: %s\n", message);
  +    fprintf(stderr, "Errno was: %d\n", errno);
  +  }
  +
  +  if (x_log_update_func) {
  +    (*x_log_update_func) (message);
  +  }
  +
  +}
  
  
  
  1.1                  eda/geda/gaf/libgeda/src/s_menu.c
  
  Index: s_menu.c
  ===================================================================
  /* gEDA - GPL Electronic Design Automation
   * libgeda - gEDA's library
   * Copyright (C) 1998-2000 Ales V. Hvezda
   *
   * 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.
   *
   * This program 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 this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
   */
  #include <config.h>
  
  #include <stdio.h>
  #include <sys/types.h>
  #ifdef HAVE_STDLIB_H
  #include <stdlib.h>
  #endif
  #ifdef HAVE_STRING_H
  #include <string.h>
  #endif
  #if defined(HAVE_DIRENT_H) 
  #include <dirent.h>
  #endif
  
  #include <gtk/gtk.h>
  #include <libguile.h>
  
  #include "defines.h"
  #include "struct.h"
  #include "globals.h"
  
  #include "../include/prototype.h"
  
  #ifdef HAVE_LIBDMALLOC
  #include <dmalloc.h>
  #endif
  
  /*! \brief */
  struct st_menu {
    char *menu_name;
    SCM menu_items;
  };
  
  static int menu_index=0;
  
  #define MAX_MENUS	32
  
  /* and eventually make this unlimited */
  /* hack hack */
  static struct st_menu menu[MAX_MENUS];
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  int s_menu_return_num(void) 
  {
    return(menu_index);
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  SCM s_menu_return_entry(int index, char **menu_name) 
  {
    if (menu_name == NULL) {
      return SCM_BOOL_F;
    }
  
    if (index > MAX_MENUS || index < 0) {
      *menu_name = NULL;
      return SCM_BOOL_F;
    }
  
    *menu_name = menu[index].menu_name;
    return(menu[index].menu_items);
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  int s_menu_add_entry(char *new_menu, SCM menu_items) 
  {
    if (new_menu == NULL) {
      return(-1); 
    }
  
    if (menu_index >= MAX_MENUS) {
      return(-1); 
    }
  
    menu[menu_index].menu_name = g_strdup (new_menu);
    menu[menu_index].menu_items = menu_items;
    menu_index++;
    
    return(menu_index);
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  void s_menu_print()
  {
    int i;
  
    for (i = 0; i < menu_index; i++) {
      printf("Name; %s\n", menu[i].menu_name);
      scm_display (menu[i].menu_items, scm_current_output_port ());
      printf("\n");
    }
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  void s_menu_free()
  {
  	int i;
  
  	for (i = 0; i < menu_index; i++) {
  		if (menu[i].menu_name) {
                          free(menu[i].menu_name);
  			menu[i].menu_name = NULL;
  		}		
  	}
  
  	menu_index=0;
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  void s_menu_init()
  {
    int i;
    for (i = 0; i < MAX_MENUS; i++) {
      menu[i].menu_name = NULL;	
    } 
  }
  
  
  
  1.23      +521 -396  eda/geda/gaf/libgeda/src/s_page.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_page.c
  ===================================================================
  RCS file: s_page.c
  diff -N s_page.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ s_page.c	5 Jul 2006 03:13:39 -0000	1.23
  @@ -0,0 +1,571 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +#ifdef HAVE_ASSERT_H
  +#include <assert.h>
  +#endif
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <glib.h>
  +#include <libguile.h>
  +#include <sys/types.h>
  +#include <sys/stat.h>
  +#include <unistd.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "funcs.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +static gint global_pid = 0;
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  Creates a new page and add it to <B>toplevel</B>'s list of pages.
  + *
  + *  It initializes the #PAGE structure and set its <B>page_filename</B>
  + *  to <B>filename</B>. <B>toplevel</B>'s current page is not changed by
  + *  this function.
  + */
  +PAGE *s_page_new (TOPLEVEL *toplevel, const gchar *filename)
  +{
  +  PAGE *page;
  +
  +  /* Now create a blank page */
  +  page = (PAGE*)g_new (PAGE, 1);
  +
  +  page->pid = global_pid++;
  +
  +  page->CHANGED = 0;
  +
  +  /* big assumption here that page_filename isn't null */
  +  if (g_path_is_absolute (filename)) {
  +    page->page_filename = g_strdup (filename);
  +  } else {
  +    gchar *pwd = g_get_current_dir ();
  +    page->page_filename = g_strconcat (pwd,
  +                                       G_DIR_SEPARATOR_S,
  +                                       filename,
  +                                       NULL);
  +    g_free (pwd);
  +  }
  +	
  +  g_assert (toplevel->init_bottom != 0);
  +  page->coord_aspectratio = (
  +    ((float) toplevel->init_right) / ((float) toplevel->init_bottom));
  +
  +  page->up = -2;
  +  page->page_control = 0;
  +
  +  /* Init tile array */
  +  s_tile_init (toplevel, page);
  +
  +  /* First one to setup head */
  +  page->object_head = s_basic_init_object("object_head");
  +  page->object_head->type = OBJ_HEAD;
  +
  +  /* new selection mechanism */
  +  page->selection2_head = page->selection2_tail = 
  +  o_selection_new_head();
  +
  +  /* net/pin/bus stretch when doing moves */
  +  page->stretch_head = page->stretch_tail = s_stretch_new_head();
  +
  +  page->complex_place_tail = page->complex_place_head = 
  +  s_basic_init_object("complex_place_head");
  +  page->complex_place_tail->type = OBJ_HEAD;
  +
  +  /* add p_attrib and p_attached_to */
  +  page->attrib_place_tail = page->attrib_place_head = 
  +  s_basic_init_object("attrib_place_head");
  +  page->attrib_place_tail->type = OBJ_HEAD;
  +	
  +  /* do this just to be sure that object tail is truely correct */
  +  page->object_tail = return_tail(page->object_head);
  +
  +  /* setup parent to point to list */
  +  /* this is used for attributes so */
  +  /* that we know which list to search */
  +  page->object_parent = page->object_head; 
  +
  +  /* init undo struct pointers */
  +  s_undo_init(page);
  +  
  +  page->object_lastplace = NULL;
  +  page->object_selected  = NULL;
  +  
  +  set_window (toplevel, page,
  +              toplevel->init_left, toplevel->init_right,
  +              toplevel->init_top,  toplevel->init_bottom);
  +
  +  /* Backup variables */
  +  g_get_current_time (&page->last_load_or_save_time);
  +  page->ops_since_last_backup = 0;
  +  page->saved_since_first_loaded = 0;
  +  page->do_autosave_backup = 0;
  +
  +  page->load_newer_backup_func = load_newer_backup_func;
  +
  +  /* now append page to page list of toplevel */
  +  toplevel->page_tail->next = page;
  +  page->prev = toplevel->page_tail;
  +  page->next = NULL;
  +  toplevel->page_tail = page;
  +  
  +  return page;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  Deletes a single page <B>page</B> from <B>toplevel</B>'s list of pages.
  + *
  + *  This function is not appropriate for deleting page head. 
  + *  See #s_page_delete_list() for that.
  + *
  + *  If the current page of toplevel is given as parameter <B>page</B>,
  + *  the function sets the field <B>page_current</B> of the TOPLEVEL
  + *  struct to NULL.
  + */
  +void s_page_delete (TOPLEVEL *toplevel, PAGE *page)
  +{
  +  PAGE *tmp;
  +  gchar *backup_filename;
  +  gchar *real_filename;
  +  gchar *only_filename;
  +  gchar *dirname;
  +  
  +  g_assert (page->pid != -1);
  +
  +  /* we need to play with page_current because s_delete_list_fromstart() */
  +  /* make use of it (see s_tile_remove_object_all) */
  +  
  +  /* save page_current and switch to page */
  +  if (page == toplevel->page_current) {
  +    tmp = NULL;
  +  } else {
  +    tmp = toplevel->page_current;
  +    s_page_goto (toplevel, page);
  +  }
  +
  +  /* Get the real filename and file permissions */
  +  real_filename = follow_symlinks (page->page_filename, NULL);
  +  
  +  if (real_filename == NULL) {
  +    s_log_message ("s_page_delete: Can't get the real filename of %s.", page->page_filename);
  +    fprintf (stderr, "s_page_delete: Can't get the real filename of %s.\n", page->page_filename);
  +  }
  +  else {
  +    /* Get the directory in which the real filename lives */
  +    dirname = g_path_get_dirname (real_filename);
  +    only_filename = g_path_get_basename(real_filename);  
  +    
  +    backup_filename = g_strdup_printf("%s%c"AUTOSAVE_BACKUP_FILENAME_STRING,
  +				      dirname, G_DIR_SEPARATOR, only_filename);
  +
  +    /* Delete the backup file */
  +    if ( (g_file_test (backup_filename, G_FILE_TEST_EXISTS)) && 
  +	 (!g_file_test(backup_filename, G_FILE_TEST_IS_DIR)) )
  +    {
  +      if (unlink(backup_filename) != 0) {
  +	s_log_message("s_page_delete: Unable to delete backup file %s.", backup_filename);      }
  +    }
  +    g_free (dirname);
  +    g_free (only_filename);
  +    g_free (backup_filename);
  +  }
  +  g_free(real_filename);
  +
  +  /* first delete objects of page */
  +  s_delete_list_fromstart (toplevel, page->object_head);
  +  
  +  toplevel->REMOVING_SEL = 1;
  +  s_delete_list_fromstart (toplevel, page->complex_place_head);
  +  s_delete_list_fromstart (toplevel, page->attrib_place_head);
  +  o_selection_destroy_all (page->selection2_head);
  +  toplevel->REMOVING_SEL = 0;  
  +
  +#if DEBUG
  +  printf("Freeing page: %s\n", page->page_filename);
  +  s_tile_print(toplevel);
  +#endif
  +  s_tile_free_all (page);
  +
  +  s_stretch_destroy_all (page->stretch_head);
  +
  +  /* free current page undo structs */
  +  s_undo_free_all (toplevel, page); 
  +
  +  /* ouch, deal with parents going away and the children still around */
  +  page->up = -2;
  +  /* p_current->down = NULL; not needed */
  +
  +  g_free (page->page_filename);
  +
  +  /* now unlink page from its list */
  +  if (page->next) {
  +    page->next->prev = page->prev;
  +  } else {
  +    /* page if the tail of page list: update toplevel */
  +    g_assert (toplevel->page_tail == page);
  +    toplevel->page_tail = page->prev;
  +  }
  +  if (page->prev) {
  +    page->prev->next = page->next;
  +  }
  +  
  +#if DEBUG
  +  s_tile_print (toplevel);
  +#endif
  +
  +  g_free (page);
  +
  +#if 0 /* don't do this for now hack */ /* this is a per window free */
  +  o_attrib_free_current(w_current);
  +  o_complex_free_filename(w_current);
  +#endif
  +
  +  /* restore page_current */
  +  if (tmp != NULL) {
  +    s_page_goto (toplevel, tmp);
  +  } else {
  +    /* page was page_current */
  +    toplevel->page_current = NULL;
  +    /* page_current must be updated by calling function */
  +  }
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief Initializes <B>toplevel</B>'s list of pages.
  + *  \par Function Description
  + *  This function creates a head page and set the toplevel fields relative
  + *  to page management.
  + */
  +void s_page_init_list (TOPLEVEL *toplevel)
  +{
  +  PAGE *head;
  +
  +  g_assert (toplevel->page_head == NULL);
  +
  +  head = (PAGE*)g_new (PAGE, 1);
  +
  +  head->pid = -1;
  +  head->CHANGED = 0;
  +  head->page_filename = g_strdup ("page_head");
  +  head->prev = NULL;
  +  head->next = NULL;
  +  /* this is important so that page_next and page_prev ignore the 
  +   * page head node 
  +   */
  +  head->page_control = -1; 
  +
  +  /* add head as page head of toplevel */
  +  toplevel->page_head = toplevel->page_tail = head;
  + 
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief Deletes the list of pages of <B>toplevel</B>.
  + *  \par Function Description
  + *  Deletes the list of pages of <B>toplevel</B>.
  + *  This function should only be called when you are finishing up.
  + */
  +void s_page_delete_list(TOPLEVEL *toplevel)
  +{
  +  PAGE *p_current, *p_prev;
  +
  +  p_current = toplevel->page_tail;
  +
  +  while (p_current != NULL && p_current->pid != -1) {
  +    p_prev = p_current->prev;
  +    s_page_delete (toplevel, p_current);
  +    p_current = p_prev;
  +  }	
  +
  +  g_assert (p_current->pid == -1 &&
  +            p_current->prev == NULL && p_current->next == NULL);
  +  
  +  /* Now free the head */
  +  g_free (p_current->page_filename);
  +  g_free (p_current);
  +
  +  /* reset toplevel fields */
  +  toplevel->page_head    = NULL;
  +  toplevel->page_tail    = NULL;
  +  toplevel->page_current = NULL;
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief Changes the current page in <B>toplevel</B> to be <B>p_new</B>.
  + *  \par Function Description
  + *  Changes the current page in <B>toplevel</B> to be <B>p_new</B>.
  + *
  + */
  +void s_page_goto (TOPLEVEL *toplevel, PAGE *p_new) 
  +{
  +  gchar *dirname;
  +  
  +  toplevel->page_current = p_new;
  +
  +  dirname = g_dirname (p_new->page_filename);
  +  chdir (dirname);
  +  g_free (dirname);
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief Search for pages by filename.
  + *  \par Function Description
  + *  Searches in <B>toplevel</B>'s list of pages for a page with a filename
  + *  equal to <B>filename</B>.
  + *  
  + *  \return PAGE pointer to a matching page, NULL otherwise.
  + */
  +PAGE *s_page_search (TOPLEVEL *toplevel, const gchar *filename)
  +{
  +  PAGE *p_current;
  +
  +  for (p_current = toplevel->page_head;
  +       p_current != NULL;
  +       p_current = p_current->next) {
  +    if (g_strcasecmp (p_current->page_filename, filename) == 0) {
  +      return p_current;
  +    }
  +  }
  +
  +  return NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief Search for pages by page id.
  + *  \par Function Description
  + *  This function tries to find a page refered by its <B>page_id</B>.
  + *
  + *  \return PAGE pointer to matching page, NULL otherwise.
  + */
  +PAGE *s_page_search_pid(TOPLEVEL * toplevel, gint page_id) 
  +{
  +  PAGE* p_current;
  +
  +  for (p_current = toplevel->page_head;
  +       p_current != NULL;
  +       p_current = p_current->next) {
  +    if (p_current->pid == page_id)
  +      return p_current;
  +  }
  +
  +  return NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief 
  + *  \par Function Description
  + *
  + */
  +gint s_page_search_row(TOPLEVEL *toplevel, PAGE *p_findme)
  +{
  +  PAGE *p_current;
  +
  +  for (p_current = toplevel->page_head;
  +       p_current != NULL;
  +       p_current = p_current->next) {
  +    if (p_current->clist_row == p_findme->clist_row) {
  +      return p_current->clist_row;
  +    }
  +  }
  +
  +  return 0; /* can't find page... well just select row 0 */
  +}
  +
  +/*! \brief Print full TOPLEVEL structure.
  + *  \par Function Description
  + *  This function prints the internal structure of <B>toplevel</B>'s
  + *  list of pages.
  + *
  + *  \param [in] toplevel  The TOPLEVEL object to print.
  + */
  +void s_page_print_all (TOPLEVEL *toplevel)
  +{
  +  PAGE *p_current;
  +
  +  g_assert (toplevel->page_head != NULL &&
  +            toplevel->page_head->pid == -1);
  +
  +  for (p_current = toplevel->page_head->next;
  +       p_current != NULL;
  +       p_current = p_current->next) {
  +    printf ("FILENAME: %s\n", p_current->page_filename);
  +    print_struct_forw (p_current->object_head);
  +  }
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief Saves all the pages of a TOPLEVEL object.
  + *  \par Function Description
  + *  Saves all the pages in the <B>toplevel</B> parameter.
  + *
  + *  \param [in] toplevel  The TOPLEVEL to save pages from.
  + *  \return The number of failed tries to save a page.
  + */
  +gint s_page_save_all (TOPLEVEL *toplevel)
  +{
  +  PAGE *p_save, *p_current;
  +  gint status = 0;
  +
  +  g_assert (toplevel->page_head != NULL &&
  +            toplevel->page_head->pid == -1);
  +
  +  /* save current page */
  +  p_save = toplevel->page_current;
  +  
  +  for (p_current = toplevel->page_head->next;
  +       p_current != NULL;
  +       p_current = p_current->next) {
  +    /* make p_current the current page of toplevel */
  +    s_page_goto (toplevel, p_current);
  +
  +    if (f_save (toplevel, p_current->page_filename)) {
  +      s_log_message ("Saved [%s]\n",
  +                     toplevel->page_current->page_filename);
  +      /* reset the CHANGED flag of p_current */
  +      p_current->CHANGED = 0;
  +      
  +    } else {
  +      s_log_message ("Could NOT save [%s]\n", 
  +                     toplevel->page_current->page_filename);
  +      /* increase the error counter */
  +      status++;
  +    }
  +    
  +  }
  +
  +  /* restore current page */
  +  s_page_goto (toplevel, p_save);
  +
  +  return status;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief Check if CHANGED flag is set for any page in list.
  + *  \par Function Description
  + *  This function checks the CHANGED flag for all pages in the <B>head</B>
  + *  object.
  + *
  + *  \param [in] head  PAGES list to check CHANGED flag in.
  + *  \return 1 if any page has the CHANGED flag set, 0 otherwise.
  + */
  +gboolean s_page_check_changed (PAGE *head)
  +{
  +  PAGE *p_current;
  +
  +  for (p_current = head;
  +       p_current != NULL;
  +       p_current = p_current->next) {
  +    if (p_current->CHANGED) {
  +      return TRUE;
  +    }
  +  }
  +
  +  return FALSE;
  +}
  +
  +/*! \brief Reset the CHANGED flag of all pages.
  + *  \par Function Description
  + *  This function resets the CHANGED flag of each page following <B>head</B>.
  + *
  + *  \param [in,out] head  PAGE list to set CHANGED flags in.
  + */
  +void s_page_clear_changed (PAGE *head)
  +{
  +  PAGE *p_current;
  +
  +  for (p_current = head;
  +       p_current != NULL;
  +       p_current = p_current->next) {
  +    p_current->CHANGED = 0;
  +  }
  +
  +}
  +
  +/*! \brief Autosave callback function.
  + *  \par Function Description
  + *  This function is a callback of the glib g_timeout functions.
  + *  It is called every "interval" milliseconds and it sets a flag to save
  + *  a backup copy of the opened pages.
  + *
  + *  \param [in] toplevel  The TOPLEVEL object.
  + *  \return The length in milliseconds to set for next interval.
  + */
  +gint s_page_autosave (TOPLEVEL *toplevel) 
  +{
  +  PAGE *p_current;
  +
  +  if (toplevel == NULL) {
  +    return 0;
  +  }
  +
  +  /* Do nothing if the interval is 0 */
  +  if (toplevel->auto_save_interval == 0) {
  +    return toplevel->auto_save_interval;
  +  }
  +  
  +  /* In which situation can be page_head = NULL?
  +     Should we just disable the autosave timeout returning 0 or
  +     just wait for more pages to be added? */
  +  if ( (toplevel->page_head == NULL) ||
  +       (toplevel->page_head->next == NULL) ) {
  +    return (toplevel->auto_save_interval);
  +  }
  +
  +  for (p_current = toplevel->page_head->next;
  +       p_current != NULL;
  +       p_current = p_current->next) {
  +
  +    if (p_current->ops_since_last_backup != 0) {
  +      /* Real autosave is done in o_undo_savestate */
  +      p_current->do_autosave_backup = 1;
  +    }
  +    
  +  }
  +
  +  return toplevel->auto_save_interval;
  +  
  +}
  
  
  
  1.10      +113 -78   eda/geda/gaf/libgeda/src/s_papersizes.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_papersizes.c
  ===================================================================
  RCS file: s_papersizes.c
  diff -N s_papersizes.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ s_papersizes.c	5 Jul 2006 03:13:39 -0000	1.10
  @@ -0,0 +1,184 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <sys/types.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h> 
  +#endif
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \brief */
  +struct st_papersizes_names {
  +	char *papersize_name;
  +	int width, height;
  +};
  +
  +/*! \brief */
  +static int papersizes_index=0;
  +
  +/*! \brief */
  +#define MAX_PAGESIZES	60
  +
  +/*! \brief
  + * and eventually make this unlimited
  + * hack hack 
  + */
  +static struct st_papersizes_names papersizes[MAX_PAGESIZES];
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  width and height in portrait mode
  + */
  +int s_papersizes_add_entry(char *new_papersize, int width, int height) 
  +{
  +  if (new_papersize == NULL) {
  +    return(-1); 
  +  }
  +
  +  if (papersizes_index >= MAX_PAGESIZES) {
  +    return(-1); 
  +  }
  +	
  +  papersizes[papersizes_index].papersize_name = (char *) malloc(sizeof(char)*strlen(new_papersize)+1);
  +
  +  strcpy(papersizes[papersizes_index].papersize_name, new_papersize);
  +
  +  papersizes[papersizes_index].width = width;
  +  papersizes[papersizes_index].height = height;
  +
  +  papersizes_index++;
  +  return(papersizes_index);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_papersizes_print()
  +{
  +  int i;
  +
  +  for (i = 0; i < papersizes_index; i++) {
  +    printf("%s\n", papersizes[i].papersize_name);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  true for uniqueness, zero for duplication
  + */
  +int s_papersizes_uniq(char *name)
  +{
  +  int i;
  +
  +  for (i = 0; i < papersizes_index; i++) {
  +    if (strcmp(papersizes[i].papersize_name, name) == 0) {
  +      return(0);
  +    }
  +  }
  +
  +  return(1);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_papersizes_free()
  +{
  +	int i;
  +
  +	for (i = 0; i < papersizes_index; i++) {
  +		if (papersizes[i].papersize_name)
  +               		free(papersizes[i].papersize_name);
  +	}
  +
  +	papersizes_index=0;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_papersizes_init()
  +{
  +  int i;
  +  for (i = 0; i < MAX_PAGESIZES; i++) {
  +    papersizes[i].papersize_name = NULL;	
  +  } 
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +char *s_papersizes_get(int counter)
  +{
  +  if (counter < papersizes_index) {
  +    return(papersizes[counter].papersize_name);
  +  } else {
  +    return(NULL);
  +  }
  +
  +  return(NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_papersizes_get_size(char *string, int *width, int *height) 
  +{
  +  int i;
  +
  +  for (i = 0; i < papersizes_index; i++) {
  +    if (strcmp(papersizes[i].papersize_name, string) == 0) {
  +      *width = papersizes[i].width;
  +      *height = papersizes[i].height;
  +      return;
  +    }
  +  }
  +
  +  *width = 0;
  +  *height = 0;
  +}
  
  
  
  1.16      +531 -447  eda/geda/gaf/libgeda/src/s_slib.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_slib.c
  ===================================================================
  RCS file: s_slib.c
  diff -N s_slib.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ s_slib.c	5 Jul 2006 03:13:39 -0000	1.16
  @@ -0,0 +1,659 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +/*! slib stands for source (project/schematic/hdl/model source) library */
  +
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <sys/types.h>
  +#include <ctype.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +#ifdef HAVE_DIRENT_H
  +#include <dirent.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/* need to test everything at boundary conditions (exceed cache size etc...) */
  +
  +/*! \brief */
  +struct st_slib {
  +  char *dir_name;
  +};
  +
  +/*! \brief */
  +static int slib_index=0;
  +
  +/*! \brief */
  +#define MAX_SLIBS	128
  +
  +/*! \brief
  + * and eventually make this unlimited
  + * hack hack
  + */
  +static struct st_slib slib[MAX_SLIBS];
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int s_slib_add_entry(char *new_path) 
  +{
  +  if (new_path == NULL) {
  +    return(-1); 
  +  }
  +
  +  if (slib_index >= MAX_SLIBS) {
  +    return(-1); 
  +  }
  +
  +  slib[slib_index].dir_name = (char *) malloc(sizeof(char)*strlen(new_path)+1);
  +
  +  strcpy(slib[slib_index].dir_name, new_path);
  +
  +  slib_index++;
  +  return(slib_index);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \return 1 if directory is found, zero otherwise.
  + */
  +int s_slib_search_for_dirname(char *dir_name)
  +{
  +  int i;
  +
  +  for (i = 0; i < slib_index; i++) {
  +    if (strcmp(slib[i].dir_name, dir_name) == 0) {
  +      return(1);	
  +    }	
  +  }
  +
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \warning
  + *  Caller must free returned pointer.
  + */
  +char *s_slib_search_dirs(const char *basename)
  +{
  +  int i;
  +  int len;
  +  DIR *ptr=NULL;
  +  struct dirent *dptr;
  +  char *slib_path=NULL;
  +
  +  /* search slib paths backwards */
  +  for (i = slib_index-1 ; i >= 0; i--) {
  +    /* for (i = 0 ; i < slib_index; i++) {*/
  +
  +#if DEBUG
  +    printf("searching: %d %s\n", i, slib[i].dir_name);
  +#endif
  +
  +    ptr = opendir(slib[i].dir_name);
  +
  +    if (ptr == NULL) {
  +      fprintf(stderr, "Oops got a null dir_name!\n");
  +      exit(-1);
  +    }
  +
  +    dptr = readdir(ptr);
  +
  +    while(dptr != NULL) {
  +
  +      /* Do a substring comp for a match */
  +      if (strstr(dptr->d_name, basename) != NULL)  {
  +        len = strlen(slib[i].dir_name);				
  +        slib_path = (char *) malloc(sizeof(char)*len+1);
  +        strcpy(slib_path, slib[i].dir_name);
  +	
  +        if (ptr) {
  +          closedir(ptr);
  +          ptr = NULL;
  +        }
  +
  +        return(slib_path);
  +      }
  +      dptr = readdir(ptr);
  +    }
  +
  +    if (ptr) {
  +      closedir(ptr);
  +      ptr = NULL;
  +    }
  +
  +  }
  +
  +  if (ptr) {
  +    closedir(ptr);
  +    ptr = NULL;
  +  }
  +
  +  return(NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \warning
  + *  Caller must free returned pointer.
  + */
  +char *s_slib_search_lowlevel(const char *basename) 
  +{
  +  char *slib_path=NULL;
  +  char *full_path=NULL;
  +  int len;
  +
  +  slib_path = s_slib_search_dirs(basename);
  +
  +  if (slib_path) {
  +    /* return type */
  +
  +    s_log_message("Found [%s]\n", basename);
  +    /* s_log_message("Found [%s] in [%s]\n", basename, slib_path);*/
  +
  +    len = strlen(basename)+strlen(slib_path);
  +	
  +    /* The 2 is for NULL char and the slash inbetween the two */
  +    /* strings */	
  +    full_path = (char *) malloc(sizeof(char)*(len+2));
  +
  +    sprintf(full_path, "%s%c%s", slib_path, G_DIR_SEPARATOR, basename);
  +		
  +    free(slib_path);
  +
  +    return(full_path);
  +  } else {
  +
  +    s_log_message("Could not find [%s] in any SourceLibrary\n", basename);
  +
  +#if DEBUG 
  +    fprintf(stderr, "Could not find [%s] in any SourceLibrary\n", basename);
  +#endif
  +    return(NULL);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief Get the base file name from a raw file name string.
  + *  \par Function Description
  + *  This function takes a raw file name and returns a processed file name.
  + *  It takes the raw file name and copies everything up to the first period
  + *  and removes any _# (where # is any number of digits.
  + *  
  + *  \param [in] rawname  Character string with the raw file name to parse.
  + *  \return The base file name in a character string.
  + *
  + *  \warning
  + *  Caller must free returned pointer.
  + */
  +char *s_slib_getbasename(const char *rawname)
  +{
  +  char *return_filename;
  +  char *copy;
  +  int i;
  +  int done=0;
  +  int lastchar;
  +  int valid=0;
  +  int len;
  +  int seen_underscore=0;
  +	
  +  if (!rawname) 
  +  return(NULL);
  +
  +  len = strlen(rawname)+1;
  +
  +  return_filename = (char *) malloc(sizeof(char)*len);
  +
  +  i = 0;
  +  /* first get everything up to the leading dot */
  +  while(rawname[i] != '\0' && rawname[i] != '.') {
  +    return_filename[i] = rawname[i];
  +    i++;
  +  }
  +
  +
  +  return_filename[i] = '\0';
  +
  +
  +  /* keep filename for safe keeping */
  +  copy = return_filename;
  +
  +  /* skip null terminator */
  +  i--;
  +
  +  lastchar=i;
  +
  +  /* this is a quick and dirty state machine to */
  +  /* go back and strip off any _#'s */
  +  /* if there is a better way let me know */
  +  while (i >= 0 && !done) {
  +
  +    /* first we need to check to see if we have seen the first '_' */
  +    /* if we have then we already removing chars, continue with that */
  +    if ( seen_underscore ) {
  +      if (return_filename[i] == '_') {
  +        done = 1;	
  +      }
  +			
  +      return_filename[i] = '\0';
  +    } else {
  +      /* we are still searching for the first underscore */
  +
  +      /* first make sure char is a number */
  +      if (isdigit((int) return_filename[i])) {
  +        valid=1;
  +      } else if (return_filename[i] == '_' && valid) {
  +				/* yes it is okay to delete the chars */
  +        seen_underscore=1;
  +				/* incremented, since it is then */
  +				/* decremented */
  +        i = lastchar+1;  
  +      } else {
  +        valid = 0;
  +        done = 1;	
  +      }
  +    }
  +
  +    i--;
  +  }
  +
  +  /* be sure to free this somewhere */
  +  return(return_filename); 
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief Search SLIB for a particular file name.
  + *  \par Function Description
  + *  This function will search the SLIB for a particular file name starting
  + *  at a location specified by the <B>flag</B> parameter.
  + *
  + *  \param [in] filename  Character string with file name to search for.
  + *  \param [in] flag      Specifies search start location. (See below...)
  + *
  + *  The <B>flag</B> parameter can be one of the following values:
  + *  <DL>
  + *    <DT>SLIB_SEARCH_START</DT><DD>Starts a new search for a source file.
  + *    <DT>SLIB_SEARCH_NEXT</DT><DD>Returns the next instance of the file if
  + *                                 one exists.
  + *    <DT>SLIB_SEARCH_DONE</DT><DD>Finish searching.
  + *  </DL>
  + *
  + *  Filename is the raw symbol/whatever file name. This function does all the
  + *  required stripping (up to the first period).
  + *
  + *  \warning
  + *  Caller must free returned pointer.
  + */
  +char *s_slib_search(const char *filename, int flag)
  +{
  +  char *processed_name=NULL;
  +  char *new_filename=NULL;
  +  char *string=NULL;
  +  char *number_suffix;
  +  int len;
  +  int len2;
  +  static int count;
  +
  +  switch(flag) {
  +    case(SLIB_SEARCH_START):
  +      count = 0;
  +      string=NULL;
  +      break;
  +
  +    case(SLIB_SEARCH_NEXT):
  +      count++;
  +
  +      /* be sure to free processed_name */
  +      processed_name = s_slib_getbasename(filename);	
  +
  +#if DEBUG 
  +      printf("proced: %s\n", processed_name);
  +#endif
  +
  +      len = strlen(processed_name);
  +
  +      /* for now only look for .sch's */
  +      /* this needs to be *MUCH* more flexible */
  +      /* number_suffix is large enough ? */
  +      number_suffix = g_strdup_printf("_%d.sch", count); 
  +      len2 = strlen(number_suffix);
  +      new_filename = (char *) 
  +        malloc (sizeof(char)*(len+len2+1));
  +
  +      sprintf(new_filename, "%s%s", processed_name, number_suffix);
  +      string = s_slib_search_lowlevel(new_filename);
  +
  +      free(new_filename);
  +      free(number_suffix);
  +      break;
  +
  +    case(SLIB_SEARCH_DONE):
  +      count = 0;
  +      string=NULL;
  +      break;
  +  }
  +
  +  if (processed_name)
  +  free(processed_name);
  +
  +  /* don't forget to free this string */
  +  return(string);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief Search SLIB for a particular file name.
  + *  \par Function Description
  + *  This function will search the SLIB for a particular file name starting
  + *  at a location specified by the <B>flag</B> parameter.
  + *
  + *  \param [in] filename  Character string with file name to search for.
  + *
  + *  Filename is the raw symbol/whatever file name. This function only looks
  + *  for the file name as is and does no other changes to it.
  + *
  + *  \warning
  + *  Caller must free returned pointer.
  + */
  +char *s_slib_search_single(const char *filename)
  +{
  +  char *string=NULL;
  +
  +  string = s_slib_search_lowlevel(filename);
  +
  +  /* don't forget to free this string */
  +  return(string);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_slib_free()
  +{
  +  int i;
  +
  +  for (i = 0; i < slib_index; i++) {
  +    if (slib[i].dir_name)
  +      free(slib[i].dir_name);
  +  }
  +
  +  slib_index=0;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_slib_init()
  +{
  +  int i;
  +  for (i = 0; i < MAX_SLIBS; i++) {
  +    slib[i].dir_name = NULL;	
  +  } 
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \warning
  + *  Caller must free returned pointer.
  + */
  +/* returns slibs */
  +char *s_slib_getdir(int index)
  +{
  +  if (slib[index].dir_name != NULL)
  +  return(slib[index].dir_name);
  +  else 
  +  return(NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \param [in] directory  Character string with directory to get files from.
  + *  \param [in] flag       Search control flag. (See below...)
  + *  \return A file name if one is found, NULL otherwise.
  + *
  + *  \warning
  + *  Caller must free returned pointer.
  + *
  + *  The flag parameter can be one of the following values:
  + *  <DL>
  + *    <DT>OPEN_DIR</DT><DD>Opens the directory and returns NULL.
  + *    <DT>READ_DIR</DT><DD>Returns the next non "." entry.
  + *    <DT>CLOSE_DIR</DT><DD>Closes the directory.
  + *  </DL>
  + *  \bug This is TOTTALLY BROKEN!
  + *       statics are not allowed anymore
  + *  \warning
  + *  this function is not reentrant
  + */
  +char *s_slib_getfiles(char *directory, int flag)
  +{
  +  static DIR *ptr;
  +  static struct dirent *dptr;
  +  static char *whole_dir[256]; /* make this dynamic hack */
  +  static int count=0;
  +  static int current=0;
  +
  +  int j;
  +  int len;
  +
  +  switch(flag) {
  +
  +    case(CLOSE_DIR):
  +      if (ptr) {
  +        closedir(ptr);
  +      }
  +
  +      ptr = NULL;
  +
  +      for (j = 0 ; j < count ;j++) {
  +        if (whole_dir[j]) 
  +          free(whole_dir[j]);
  +      }
  +      count = current = 0 ;
  +
  +      return(NULL);
  +      break;
  +
  +      /* open the directory and return first element (after if) */
  +    case(OPEN_DIR):
  +
  +      if (ptr) {
  +        closedir(ptr);
  +      }
  +
  +      ptr = NULL;
  +
  +      for (j = 0 ; j < count ;j++) {
  +        if (whole_dir[j]) 
  +          free(whole_dir[j]);
  +      }
  +      count = current = 0 ;
  +
  +      ptr = opendir(directory); /* hack check for existance */
  +
  +      if (ptr == NULL) 
  +        return(NULL);
  +
  +
  +      /* now read the entire directory */
  +      dptr = readdir(ptr);
  +
  +      while (dptr != NULL) {
  +
  +				/* skip .'s */
  +        while (dptr != NULL) {
  +          if (dptr->d_name[0] == '.') {
  +            dptr = readdir(ptr);
  +          } else {
  +            break;
  +          }
  +        }
  +		
  +        if (dptr == NULL) {
  +          break;
  +        }	
  +
  +        if (dptr->d_name != NULL) {
  +          len = strlen(dptr->d_name);
  +
  +          /* hack */
  +          if (count < 256) {
  +
  +            whole_dir[count] = (char *)
  +              malloc(sizeof(char)*len+1);
  +            strcpy(whole_dir[count], 
  +                   dptr->d_name);
  +            count++;
  +          } else {
  +            fprintf(stderr, 
  +                    "uggg. too many files in s_slib_getfiles!\n");
  +            exit(-1);
  +          }
  +        }
  +
  +        dptr = readdir(ptr);
  +      }
  +      return(NULL);
  +
  +      break;
  +
  +    case(READ_DIR):
  +
  +		
  +      if (whole_dir[current] && current < count) {
  +        return(whole_dir[current++]);
  +      } else {
  +        return(NULL);
  +      }
  +
  +      break;
  +
  +    default:
  +      return(NULL);
  +  }
  +
  +#if DEBUG
  +  for (j = 0;j < count; j++) {
  +    printf("string: %s\n", whole_dir[j]);
  +  }
  +#endif
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_slib_print(void)
  +{
  +  int i;
  +
  +  for (i = 0; i < slib_index; i++) {
  +    printf("%s\n", slib[i].dir_name);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int s_slib_uniq(char *path)
  +{
  +  if (s_slib_search_for_dirname(path)) {
  +
  +#if DEBUG 
  +    printf("found\n");
  +#endif
  +    return(0);
  +  } else {
  +
  +#if DEBUG
  +    printf("NOT found\n");
  +#endif
  +
  +    return(1);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_slib_print_dirs(void)
  +{
  +  int i;
  +  char *string;
  +  char *file;
  +
  +  i = 0;
  +  string = s_slib_getdir(i);
  +  while(string != NULL) {
  +
  +    s_slib_getfiles(string, OPEN_DIR);
  +    printf("Opened %s\n", string);
  +
  +    file = (char *) s_slib_getfiles(string, READ_DIR);
  +
  +    while(file != NULL) {
  +      printf("file: %s\n", file);
  +      file = (char *) s_slib_getfiles(string, READ_DIR);
  +    }
  +
  +    printf("Closed %s\n", string);
  +    s_slib_getfiles(string, CLOSE_DIR);
  +    i++;
  +    string = s_slib_getdir(i);
  +  }
  +}
  
  
  
  1.4       +216 -179  eda/geda/gaf/libgeda/src/s_stretch.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_stretch.c
  ===================================================================
  RCS file: s_stretch.c
  diff -N s_stretch.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ s_stretch.c	5 Jul 2006 03:13:39 -0000	1.4
  @@ -0,0 +1,294 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <ctype.h>
  +#if HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#if HAVE_ASSERT_H
  +#include <assert.h>
  +#endif
  +#ifndef HAVE_VSNPRINTF
  +#include <stdarg.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "defines.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +STRETCH *s_stretch_return_tail(STRETCH *head)
  +{
  +  STRETCH *s_current=NULL;
  +  STRETCH *ret_struct=NULL;
  +
  +  s_current = head;
  +  while ( s_current != NULL ) { /* goto end of list */
  +    ret_struct = s_current;
  +    s_current = s_current->next;
  +  }
  +
  +  return(ret_struct);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +STRETCH *s_stretch_return_head(STRETCH *tail)
  +{
  +  STRETCH *s_current=NULL;
  +  STRETCH *ret_struct=NULL;
  +
  +  s_current = tail;
  +  while ( s_current != NULL ) { /* goto end of list */
  +    ret_struct = s_current;
  +    s_current = s_current->prev;
  +  }
  +
  +  return(ret_struct);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +STRETCH *s_stretch_new_head(void)
  +{
  +  STRETCH *s_new;
  +
  +  s_new = (STRETCH *) malloc(sizeof(STRETCH));
  +
  +  s_new->object = NULL;
  +  s_new->connection = NULL;
  +  s_new->whichone = -1;
  +
  +  s_new->prev = NULL;
  +  s_new->next = NULL;
  +
  +  return(s_new);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_stretch_destroy_head(STRETCH *s_head)
  +{
  +  free(s_head);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/*! \todo also does the needed work to make the object visually selected */
  +STRETCH *s_stretch_add(STRETCH *head, OBJECT *object,
  +		       CONN *connection, int whichone)
  +{
  +  STRETCH *tail;
  +  STRETCH *s_new;
  +  STRETCH *s_current;
  +	
  +  s_current = head;
  +  while (s_current != NULL) {
  +    if (s_current->object) {
  +      /*printf("%d %d\n", s_current->object->sid, object->sid);*/
  +      if (s_current->object->sid == object->sid) {
  +				/* printf("already inside\n");*/
  +        return(s_stretch_return_tail(head));
  +      }
  +    }
  +		
  +    s_current = s_current->next;
  +  }
  +  /*printf("Adding: %s\n", object->name);*/
  +
  +  s_new = (STRETCH *) malloc(sizeof(STRETCH));
  +  s_new->object = object;
  +  s_new->connection = connection;
  +  s_new->whichone = whichone;
  +
  +  if (head == NULL) {
  +    s_new->prev = NULL; /* setup previous link */
  +    s_new->next = NULL;
  +    return(s_new);
  +  } else {
  +    tail = s_stretch_return_tail(head);
  +    s_new->prev = tail; /* setup previous link */
  +    s_new->next = NULL;
  +    tail->next = s_new;
  +    return(tail->next);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/*! \note
  + *  it's okay to call this with an o_selected which is not necessarily
  + *  selected
  + */
  +void s_stretch_remove(STRETCH *head, OBJECT *object)
  +{
  +  STRETCH *s_current;
  +
  +  if (object == NULL) {
  +    fprintf(stderr, "Got NULL for s_stretch in s_stretch_remove\n");
  +    return;
  +  }
  +
  +  s_current = head;	
  +
  +  while (s_current != NULL) {
  +    if (s_current->object == object) {
  +      if (s_current->next)
  +        s_current->next->prev = s_current->prev;
  +      else
  +        s_current->next = NULL;
  +
  +      if (s_current->prev)
  +        s_current->prev->next = s_current->next;
  +      else
  +        s_current->prev = NULL;
  +
  +      s_current->object = NULL;
  +      s_current->connection = NULL;
  +      s_current->whichone = -1;
  +
  +      free(s_current);
  +      return;
  +    }
  +    s_current = s_current->next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/*! \note removes all but the head node */
  +void s_stretch_remove_most(TOPLEVEL *w_current, STRETCH *head)
  +{
  +  STRETCH *s_current;
  +  STRETCH *s_prev;
  +
  +  s_current = s_stretch_return_tail(head);
  +
  +  while (s_current != NULL) {
  +    if (s_current->object != NULL) {
  +      s_prev = s_current->prev;	
  +
  +      s_current->object = NULL;
  +      s_current->connection = NULL;
  +      s_current->whichone = -1;
  +	
  +      free(s_current);
  +      s_current = s_prev;
  +    } else {
  +      break;
  +    }
  +  }
  +
  +  /* clear out any dangling pointers */
  +  head->next=NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_stretch_print_all( STRETCH *head )
  +{
  +  STRETCH *s_current;
  +
  +  s_current = head;
  +
  +  printf("START printing stretch ********************\n");
  +  while(s_current != NULL) {
  +    if (s_current->object) {
  +      printf("Object: %s\n", s_current->object->name);
  +    } else {
  +      printf("Object is NULL\n");
  +    }
  +
  +    if (s_current->object) {
  +      printf("Connection type: %d\n", s_current->connection->type);
  +    } else {
  +      printf("Connection is NULL\n");
  +    }
  +
  +    printf("which one: %d\n", s_current->whichone);
  +
  +    s_current = s_current->next;
  +  }
  +  printf("DONE printing stretch ********************\n");
  +  printf("\n");
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_stretch_destroy_all(STRETCH *head) 
  +{
  +  STRETCH *s_current;
  +  STRETCH *s_prev;
  +
  +  s_current = s_stretch_return_tail(head);
  +
  +  while (s_current != NULL) {
  +    s_prev = s_current->prev;	
  +
  +    s_current->object = NULL;
  +    s_current->connection = NULL;
  +    s_current->whichone = -1;
  +
  +    free(s_current);
  +    s_current = s_prev;
  +  }
  +}
  
  
  
  1.4       +94 -50    eda/geda/gaf/libgeda/src/s_tile.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_tile.c
  ===================================================================
  RCS file: s_tile.c
  diff -N s_tile.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ s_tile.c	5 Jul 2006 03:13:39 -0000	1.4
  @@ -0,0 +1,497 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_ASSERT_H
  +#include <assert.h>
  +#endif
  +#include <ctype.h>
  +#include <math.h>
  +#ifndef HAVE_VSNPRINTF
  +#include <stdarg.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "defines.h"
  +#include "globals.h"
  +#include "o_types.h"
  +#include "colors.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_tile_init(TOPLEVEL * w_current, PAGE * p_current)
  +{
  +  int i, j;
  +  TILE *t_current;
  +  int x_size = w_current->init_right / MAX_TILES_X;
  +  int y_size = w_current->init_bottom / MAX_TILES_Y;
  +  int x_sum = 0;
  +  int y_sum = 0;
  +
  +#if DEBUG 
  +  printf("X, Y: %d %d\n", x_size, y_size);
  +#endif
  +    
  +  for (j = 0; j < MAX_TILES_Y; j++) {
  +    for (i = 0; i < MAX_TILES_X; i++) {
  +      t_current = &p_current->world_tiles[i][j];
  +
  +      t_current->objects = NULL;
  +
  +      t_current->left = x_sum;
  +      t_current->right = x_sum + x_size;
  +
  +      t_current->top = y_sum;
  +      t_current->bottom = y_sum + y_size;
  +
  +      x_sum = x_sum + x_size;
  +    }
  +    x_sum = 0;
  +    y_sum = y_sum + y_size;
  +  }
  +
  +#if DEBUG
  +  for (j = 0; j < MAX_TILES_Y; j++) {
  +    for (i = 0; i < MAX_TILES_X; i++) {
  +      t_current = &p_current->world_tiles[i][j];
  +      printf("\n%d %d\n", i, j);
  +      printf("----------------\n");
  +      printf("left %d top %d\n", t_current->left, t_current->top);
  +      printf("right %d bottom %d\n", t_current->right,
  +             t_current->bottom);
  +    }
  +  }
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +TILE_LOC *s_tile_new_loc(int i, int j)
  +{
  +  TILE_LOC *tile_loc;
  +
  +  tile_loc = (TILE_LOC *) malloc(sizeof(TILE_LOC));
  +
  +  tile_loc->i = i;
  +  tile_loc->j = j;
  +
  +  return (tile_loc);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_tile_add_object(TOPLEVEL * w_current, OBJECT * object, int world_x1,
  +		       int world_y1, int world_x2, int world_y2)
  +{
  +  TILE *t_current;
  +  PAGE *p_current;
  +  GList *found;
  +  TILE_LOC *tile_loc;
  +  int i, j;
  +  int v, w;
  +  double x1, y1, x2, y2;
  +  double bottom;
  +  double m, b;
  +  double x_size, y_size;
  +  double x, y;
  +  int start, end;
  +
  +#if DEBUG  
  +  printf("name: %s\n", object->name);
  +#endif
  +
  +  if (w_current->ADDING_SEL) {
  +#if DEBUG    
  +    printf("s_tile_add_object, adding sel TRUE\n");
  +#endif
  +    return;
  +  }
  +  
  +  x_size = (double) w_current->init_right / (double) MAX_TILES_X;
  +  y_size = (double) w_current->init_bottom / (double) MAX_TILES_Y;
  +
  +  x1 = (int) (world_x1 / x_size);
  +  x2 = (int) (world_x2 / x_size);
  +  y1 = (int) (world_y1 / y_size);
  +  y2 = (int) (world_y2 / y_size);
  +
  +  bottom = x2 - x1;
  +  p_current = w_current->page_current;
  +
  +  if (bottom != 0.0) {
  +    m = (double) (y2 - y1) / bottom;
  +    b = y1 - m * x1;
  +
  +    start = min((int) x1, (int) x2);
  +    end = max((int) x1, (int) x2);
  +    for (i = start; i <= end; i++) {
  +      x = i;
  +      y = m * x + b;
  +      if (floor(y) != ceil(y)) {
  +
  +        v = (int) x;
  +        w = (int) floor(y);
  +        if (v < 0 || w < 0 || v > MAX_TILES_X-1 || w > MAX_TILES_Y-1) {
  +          return;
  +        }
  +        /* assert(v < MAX_TILES_X && w < MAX_TILES_Y && v >= 0 && w >= 0); */
  +        t_current = &p_current->world_tiles[v][w];
  +        found = g_list_find(t_current->objects, object);
  +
  +        if (!found) {
  +          /*printf("%d %d\n", v, w);*/
  +          t_current->objects = g_list_append(t_current->objects,
  +                                             object);
  +
  +          tile_loc = s_tile_new_loc(v, w);
  +          object->tile_locs = g_list_append(object->tile_locs,
  +                                            tile_loc);
  +        }
  +
  +        v = (int) x;
  +        w = (int) ceil(y);
  +        if (v < 0 || w < 0 || v > MAX_TILES_X-1 || w > MAX_TILES_Y-1) {
  +          return;
  +        }
  +        /*assert(v < MAX_TILES_X && w < MAX_TILES_Y && v >= 0 && w >= 0);*/
  +        t_current = &p_current->world_tiles[v][w];
  +        found = g_list_find(t_current->objects, object);
  +
  +        if (!found) {
  +          /*printf("%d %d\n", v, w);*/
  +          t_current->objects = g_list_append(t_current->objects,
  +                                             object);
  +          tile_loc = s_tile_new_loc(v, w);
  +          object->tile_locs = g_list_append(object->tile_locs,
  +                                            tile_loc);
  +        }
  +
  +      } else {
  +        v = (int) x;
  +        w = (int) floor(y);
  +        if (v < 0 || w < 0 || v > MAX_TILES_X-1 || w > MAX_TILES_Y-1) {
  +          return;
  +        }
  +        /*assert(v < MAX_TILES_X && w < MAX_TILES_Y && v >= 0 && w >= 0);*/
  +        t_current = &p_current->world_tiles[v][w];
  +        found = g_list_find(t_current->objects, object);
  +
  +        if (!found) {
  +          /*printf("%d %d\n", v, w);*/
  +          t_current->objects = g_list_append(t_current->objects,
  +                                             object);
  +          tile_loc = s_tile_new_loc(v, w);
  +          object->tile_locs = g_list_append(object->tile_locs,
  +                                            tile_loc);
  +        }
  +      }
  +    }
  +
  +    if (m != 0.0) {
  +      start = min((int) y1, (int) y2);
  +      end = max((int) y1, (int) y2);
  +      for (j = start; j <= end; j++) {
  +        y = j;
  +        x = (y - b) / m;
  +        if (floor(x) != ceil(x)) {
  +          w = (int) y;
  +          v = (int) floor(x);
  +          if (v < 0 || w < 0 || v > MAX_TILES_X-1 || w > MAX_TILES_Y-1) {
  +            return;
  +          }
  +          /*assert(v < MAX_TILES_X && w < MAX_TILES_Y &&
  +            v >= 0 && w >= 0);*/
  +          t_current = &p_current->world_tiles[v][w];
  +          found = g_list_find(t_current->objects, object);
  +
  +          if (!found) {
  +            /*printf("%d %d\n", v, w);*/
  +            t_current->objects =
  +              g_list_append(t_current->objects, object);
  +            tile_loc = s_tile_new_loc(v, w);
  +            object->tile_locs =
  +              g_list_append(object->tile_locs, tile_loc);
  +          }
  +
  +          w = (int) y;
  +          v = (int) ceil(x);
  +          if (v < 0 || w < 0 || v > MAX_TILES_X-1 || w > MAX_TILES_Y-1) {
  +            return;
  +          }
  +          /* assert(v < MAX_TILES_X && w < MAX_TILES_Y &&
  +             v >= 0 && w >= 0);*/
  +          t_current = &p_current->world_tiles[v][w];
  +          found = g_list_find(t_current->objects, object);
  +
  +          if (!found) {
  +            /*printf("%d %d\n", v, w);*/
  +            t_current->objects =
  +              g_list_append(t_current->objects, object);
  +            tile_loc = s_tile_new_loc(v, w);
  +            object->tile_locs =
  +              g_list_append(object->tile_locs, tile_loc);
  +          }
  +
  +        } else {
  +          w = (int) y;
  +          v = (int) floor(x);
  +          if (v < 0 || w < 0 || v > MAX_TILES_X-1 || w > MAX_TILES_Y-1) {
  +            return;
  +          }
  +          /*assert(v < MAX_TILES_X && w < MAX_TILES_Y &&
  +            v >= 0 && w >= 0);*/
  +          t_current = &p_current->world_tiles[v][w];
  +          found = g_list_find(t_current->objects, object);
  +
  +          if (!found) {
  +            /*printf("%d %d\n", v, w);*/
  +            t_current->objects =
  +              g_list_append(t_current->objects, object);
  +            tile_loc = s_tile_new_loc(v, w);
  +            object->tile_locs =
  +              g_list_append(object->tile_locs, tile_loc);
  +          }
  +        }
  +      }
  +    }
  +  } else {
  +    start = min((int) y1, (int) y2);
  +    end = max((int) y1, (int) y2);
  +    for (j = start; j <= end; j++) {
  +
  +      y = j;
  +      x = x1;
  +      v = (int) x;
  +      w = (int) y;
  +      if (v < 0 || w < 0 || v > MAX_TILES_X-1 || w > MAX_TILES_Y-1) {
  +        return;
  +      }
  +      /*assert(v < MAX_TILES_X && w < MAX_TILES_Y &&
  +        v >= 0 && w >= 0);*/
  +      t_current = &p_current->world_tiles[v][w];
  +      found = g_list_find(t_current->objects, object);
  +
  +      if (!found) {
  +        /*printf("%d %d\n", v, w);*/
  +        t_current->objects = g_list_append(t_current->objects,
  +                                           object);
  +        tile_loc = s_tile_new_loc(v, w);
  +        object->tile_locs = g_list_append(object->tile_locs,
  +                                          tile_loc);
  +      }
  +
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_tile_remove_object_all_crude(TOPLEVEL * w_current, OBJECT * object)
  +{
  +  TILE *t_current;
  +
  +  int i, j;
  +
  +  for (j = 0; j < MAX_TILES_Y; j++) {
  +    for (i = 0; i < MAX_TILES_X; i++) {
  +#if 0				/* this checks for existance */
  +      t_current = &w_current->page_current->world_tiles[i][j];
  +      found = g_list_find(t_current->objects, object);
  +
  +      if (found) {
  +        printf("found object %s in %d, %d\n", object->name, i, j);
  +        t_current->objects = g_list_remove(t_current->objects,
  +                                           object);
  +      }
  +#endif
  +
  +      /* this just does the remove if the object is found */
  +#if 1
  +      t_current = &w_current->page_current->world_tiles[i][j];
  +      t_current->objects = g_list_remove(t_current->objects, object);
  +#endif
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \bug
  + *  this is still wrong, p_current needs to be the page the object is on 
  + *  doesn't work if the current page isn't where the object lives
  + */
  +void s_tile_remove_object_all(TOPLEVEL * w_current, PAGE *p_current,
  +                              OBJECT * object)
  +{
  +  TILE *t_current;
  +  TILE_LOC *tl_current;
  +  GList *tloc_list;
  +  GList *found;
  +  int i, j;
  +
  +  tloc_list = object->tile_locs;
  +  while (tloc_list != NULL) {
  +
  +    tl_current = (TILE_LOC *) tloc_list->data;
  +        
  +    i = tl_current->i;
  +    j = tl_current->j;
  +
  +    free(tl_current);
  +
  +    t_current = &p_current->world_tiles[i][j];
  +    t_current->objects = g_list_remove(t_current->objects, object);
  +
  +#if 1 
  +    found = g_list_find(t_current->objects, object);
  +    if (found) {
  +      printf("found an object left over %s in %d, %d\nPlease e-mail ahvezda@xxxxxxxxxxxxx with this error message and .sch\n", object->name, i, j);
  +    }
  +#endif
  +    
  +    tloc_list = tloc_list->next;	
  +  }
  +
  +  g_list_free(tloc_list);
  +  object->tile_locs = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_tile_update_object(TOPLEVEL * w_current, OBJECT * object)
  +{
  +  s_tile_remove_object_all(w_current, w_current->page_current, object);
  +  s_tile_add_object(w_current, object,
  +                    object->line->x[0], object->line->y[0],
  +                    object->line->x[1], object->line->y[1]);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_tile_print(TOPLEVEL * w_current)
  +{
  +  TILE *t_current;
  +  GList *temp;
  +  GList *temp2;
  +  OBJECT *o_current;
  +  TILE_LOC *tloc;
  +  int i, j;
  +
  +  for (j = 0; j < MAX_TILES_Y; j++) {
  +    for (i = 0; i < MAX_TILES_X; i++) {
  +      printf("\nTile %d %d\n", i, j);
  +
  +      t_current = &w_current->page_current->world_tiles[i][j];
  +
  +      temp = t_current->objects;
  +      while (temp) {
  +        o_current = (OBJECT *) temp->data;
  +
  +        printf("%s\n", o_current->name);
  +        temp2 = o_current->tile_locs;
  +        while (temp2 != NULL) {
  +          tloc = (TILE_LOC *) temp2->data;
  +          printf("	%d %d\n", tloc->i, tloc->j);
  +          temp2 = temp2->next;
  +        }
  +
  +        temp = temp->next;
  +      }
  +
  +      printf("------------------\n");
  +    }
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_tile_free_all(PAGE * p_current)
  +{
  +  int i, j;
  +  TILE *t_current;
  +  
  +  for (j = 0; j < MAX_TILES_Y; j++) {
  +    for (i = 0; i < MAX_TILES_X; i++) {
  +      t_current = &p_current->world_tiles[i][j];
  +      if (g_list_length(t_current->objects) != 0) {
  +        fprintf(stderr,
  +                "OOPS! t_current->objects had something in it when it was freed!\n");
  +        fprintf(stderr, "Length: %d\n", g_list_length(t_current->objects));
  +
  +
  +#if DEBUG          
  +        printf("%s %d %d\n", p_current->page_filename, i, j);
  +        objects = t_current->objects;
  +        while(objects != NULL) {
  +          real_object = (OBJECT *) objects->data;
  +          printf("yes %s\n", real_object->name);
  +          objects = objects->next;
  +        }
  +                        
  +        if (t_current->objects == NULL) {
  +          printf("yes null\n");
  +        }
  +#endif
  +        
  +      }
  +      g_list_free(t_current->objects);
  +    }
  +  }
  +}
  +
  +
  +
  
  
  
  1.1                  eda/geda/gaf/libgeda/src/s_toplevel.c
  
  Index: s_toplevel.c
  ===================================================================
  /* gEDA - GPL Electronic Design Automation
   * libgeda - gEDA's library
   * Copyright (C) 1998, 1999, 2000 Kazu Hirata / Ales Hvezda
   *
   * 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.
   *
   * This program 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 this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
   */
  #include <config.h>
  
  #include <stdio.h>
  #ifdef HAVE_STRING_H
  #include <string.h>
  #endif
  #ifdef HAVE_STRARG_H
  #include <stdarg.h>
  #endif
  #ifdef HAVE_STDLIB_H
  #include <stdlib.h>
  #endif
  
  #include <gtk/gtk.h>
  #include <libguile.h>
  
  #include "defines.h"
  #include "struct.h"
  #include "globals.h"
  #include "funcs.h"
  
  #include "../include/prototype.h"
  
  #ifdef HAVE_LIBDMALLOC
  #include <dmalloc.h>
  #endif
  
  /* global_wid always increments, it needs to be unique per run */
  static int global_wid = 0;
  
  /* head pointer to toplevel structure, this points to all the toplevels that
     currently exist */
  static TOPLEVEL *toplevel_head = NULL;
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  void s_toplevel_init (void)
  {
    toplevel_head = (TOPLEVEL*)g_new (TOPLEVEL, 1);
    toplevel_head->wid = -1;
    toplevel_head->next = NULL;  
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  TOPLEVEL *s_toplevel_new (void)
  {
    TOPLEVEL *toplevel, *tmp;
  
    toplevel = (TOPLEVEL*)g_new (TOPLEVEL, 1);
  
    toplevel->wid = global_wid++;
  
    toplevel->num_untitled = 0;
  
    toplevel->start_x = -1;
    toplevel->start_y = -1;
    toplevel->save_x  = -1;
    toplevel->save_y  = -1;
    toplevel->last_x  = -1;
    toplevel->last_y  = -1;
    toplevel->loc_x   = -1;
    toplevel->loc_y   = -1;
    toplevel->distance = -1;
  
    toplevel->current_attribute = NULL;
  
    toplevel->current_visible = -1; /* not sure on these */
    toplevel->current_show    = -1;
  
    toplevel->internal_basename = NULL;
    toplevel->internal_clib = NULL;
    
    toplevel->RC_list = NULL;
  
    toplevel->series_name        = NULL;
    toplevel->untitled_name      = NULL;
    toplevel->font_directory     = NULL;
    toplevel->scheme_directory   = NULL;
    toplevel->bitmap_directory   = NULL;
  
    toplevel->event_state = -1;
  
    toplevel->inside_action = 0;
  
    toplevel->init_left = 0;
    toplevel->init_top  = 0;
    /* init_right and _bottom are set before this function is called */
  
    toplevel->win_width  = 0;
    toplevel->win_height = 0;
    toplevel->width  = 1;
    toplevel->height = 1;
    toplevel->image_width  = 0;
    toplevel->image_height = 0;
    toplevel->snap = 1;
    toplevel->grid = 1;
    toplevel->min_zoom = 0;
    toplevel->max_zoom = 8;
  
    toplevel->starting_width = 0;
  
    toplevel->text_alignment = 0;
  
    toplevel->line_type = 0;
  
    toplevel->fill_type = 0;
  
    toplevel->override_color = -1;
    toplevel->inside_redraw = 0;
    toplevel->window_aspectratio = 0;
    toplevel->display_height = 0;
    toplevel->display_width  = 0;
  
    toplevel->DONT_DRAW_CONN    = 0;
    toplevel->DONT_RESIZE       = 0;
    toplevel->DONT_EXPOSE       = 0;
    toplevel->DONT_REDRAW       = 0;
    toplevel->DONT_RECALC       = 0;
    toplevel->FORCE_CONN_UPDATE = 0;
    toplevel->ADDING_SEL        = 0;
    toplevel->REMOVING_SEL      = 0;
  
    toplevel->drawbounding_action_mode = FREE;
    toplevel->last_drawb_mode = -1;
  
    toplevel->CONTROLKEY = 0;
    toplevel->SHIFTKEY   = 0;
    toplevel->ALTKEY     = 0;
  	
    toplevel->doing_pan = 0;
    
    /* Put head node on page list... */
    toplevel->page_head = NULL;
    s_page_init_list (toplevel);
    toplevel->page_current = NULL;
  
    toplevel->buffer_number = 0;
  
    toplevel->show_hidden_text = 0;
  
    toplevel->complex_rotate = 0;
  
    toplevel->last_callback = NULL;
    toplevel->cwd = NULL;
  
    toplevel->major_changed_refdes = NULL;
  
    toplevel->main_window  = NULL;
    toplevel->drawing_area = NULL;
    toplevel->menubar      = NULL;
    toplevel->popup_menu   = NULL;
    toplevel->h_scrollbar  = NULL;
    toplevel->v_scrollbar  = NULL;    
    toplevel->h_adjustment = NULL;
    toplevel->v_adjustment = NULL;
    toplevel->left_label   = NULL;
    toplevel->middle_label = NULL;
    toplevel->right_label  = NULL;
    toplevel->filename_label = NULL;
    toplevel->status_label = NULL;
  
    toplevel->toolbar_select = NULL;
    toplevel->toolbar_net    = NULL;
    toplevel->toolbar_bus    = NULL;
    toplevel->toolbar_edit   = NULL;
    toplevel->toolbar_move   = NULL;
    toplevel->toolbar_copy   = NULL;
    toplevel->toolbar_delete = NULL;
    toplevel->toolbar_rotate = NULL;
    toplevel->toolbar_mirror = NULL;
  
    toplevel->fowindow = NULL;
    toplevel->fswindow = NULL;
    toplevel->sowindow = NULL;
    toplevel->saveas_flag = 0;
  
    toplevel->aswindow      = NULL;
    toplevel->attr_list     = NULL;
    toplevel->asentry_name  = NULL;
    toplevel->asentry_value = NULL;
  
    toplevel->cswindow      = NULL;
    toplevel->clib_list     = NULL;
    toplevel->basename_list = NULL;
    toplevel->current_clib = NULL;
  /*   toplevel->current_basename 	 */
  
  /*   toplevel->fileselect */
  
    toplevel->pwindow = NULL;
    toplevel->plib_list = NULL;
    toplevel->pfilename_entry = NULL; 
  
    toplevel->iwindow = NULL;
    toplevel->ifilename_entry = NULL; 
  
    toplevel->pswindow   = NULL;
    toplevel->page_clist = NULL;
    toplevel->clist_sig = 0;
  
    toplevel->tiwindow = NULL;
    toplevel->tewindow = NULL;
    toplevel->teentry  = NULL;
    toplevel->ltwindow = NULL;
    toplevel->ftwindow = NULL;
    toplevel->sewindow = NULL;
    toplevel->seentry  = NULL;
    toplevel->exwindow = NULL;
    toplevel->aawindow = NULL;
    toplevel->mawindow = NULL;
    toplevel->aewindow = NULL;
    toplevel->aaentry_start = NULL;
    toplevel->aaentry_sweep = NULL;
    toplevel->trwindow = NULL;
    toplevel->trentry  = NULL;
    toplevel->tswindow = NULL;
    toplevel->tsentry  = NULL;
  	
    toplevel->abwindow = NULL;
    toplevel->hkwindow = NULL;
    toplevel->cowindow = NULL;
    toplevel->coord_world = NULL;
    toplevel->coord_screen = NULL;
  
    toplevel->pfswindow = NULL;
    toplevel->pcfswindow = NULL;
  #ifndef HAS_GTK12
    toplevel->current_pixbuf = NULL;
  #endif
    toplevel->pixbuf_filename = NULL;
    toplevel->pixbuf_wh_ratio = 0;
  
    toplevel->clwindow = NULL;
    toplevel->edit_color = 0;
  
    toplevel->window = NULL; 
  	
    toplevel->gc              = NULL;
    toplevel->xor_gc          = NULL;
    toplevel->outline_xor_gc  = NULL;
    toplevel->bounding_xor_gc = NULL;
    toplevel->bus_gc          = NULL;
  
    toplevel->backingstore = NULL;
  
    toplevel->graphic_color = 0;
    toplevel->pin_color     = 0;
    toplevel->text_color    = 0;
  
    toplevel->logic_bubble_color = 0; 
    toplevel->zoom_box_color = 0; 
    toplevel->text_caps = 0;
    toplevel->attribute_color    = 0;
    toplevel->detachedattr_color = 0;
    toplevel->text_size = 0;
  
    toplevel->snap_size = 100;
  
    toplevel->grid_color         = 0;
    toplevel->background_color   = 0;
    toplevel->select_color       = 0;
    toplevel->bb_color           = 0;
    toplevel->lock_color         = 0;
    toplevel->net_endpoint_color = 0;
    toplevel->net_color          = 0;
    toplevel->bus_color          = 0;
    toplevel->override_net_color = -1;
    toplevel->override_bus_color = -1;
    toplevel->override_pin_color = -1;
    toplevel->pin_style = 0;
    toplevel->net_style = 0;
    toplevel->bus_style = 0;
    toplevel->zoom_with_pan = 0;
  
    toplevel->actionfeedback_mode = OUTLINE;
  
    toplevel->text_feedback = 0;
  
    toplevel->text_display_zoomfactor = 0;
  
    toplevel->net_endpoint_mode = NONE;
  
    toplevel->net_midpoint_mode = NONE;
  
    toplevel->object_clipping = 0;
  
    toplevel->embed_complex = 0;
  
    toplevel->include_complex = 0;
  
    toplevel->text_output = 0;
  
    toplevel->scrollbars_flag = 0;
  
    toplevel->print_orientation = 0;
  
    toplevel->image_color = FALSE;
  
    toplevel->print_color = FALSE;
  
    toplevel->print_color_background = 0;
  
    toplevel->setpagedevice_orientation = FALSE;
  
    toplevel->setpagedevice_pagesize = FALSE;
  
    toplevel->postscript_prolog = NULL;
  
    toplevel->stroke_color = 0;
  
    toplevel->log_window = 0;
  
    toplevel->log_window_type = 0;
  
    toplevel->third_button = 0;
  
    toplevel->middle_button = 0;
  
    toplevel->net_consolidate = FALSE;
  
    toplevel->file_preview = 0;
  
    toplevel->enforce_hierarchy = 0;
  
    toplevel->text_origin_marker = 0;
  
    toplevel->fast_mousepan = 0;
  
    toplevel->raise_dialog_boxes = 0;
  
    /* The following is an attempt at getting (deterministic) defaults */
    /* for the following variables */
    toplevel->attribute_promotion = FALSE;
    toplevel->promote_invisible   = FALSE;
    toplevel->keep_invisible      = FALSE;
  
    toplevel->continue_component_place = 0;
  
    toplevel->undo_levels = 0;
  
    toplevel->undo_control = 0;
  
    toplevel->undo_type = 0;
  
    toplevel->draw_grips = 0;
  
    toplevel->netconn_rubberband = 0;
  
    toplevel->sort_component_library = 0;
  
    toplevel->warp_cursor = 0;
  
    toplevel->toolbars = 0;
  
    toplevel->handleboxes = 0;
  
    toplevel->print_output_type = 0;
  
    toplevel->print_output_capstyle = BUTT_CAP;
  
    toplevel->image_output_type = 0;
  
    toplevel->paper_width  = 0;
    toplevel->paper_height = 0;
  
    toplevel->bus_ripper_size = 0;
  
    toplevel->bus_ripper_type = 0;
  
    toplevel->bus_ripper_symname = NULL;
  
    toplevel->bus_ripper_rotation = 0;
  
    toplevel->force_boundingbox = FALSE;
  
    toplevel->grid_dot_size = 1;
    toplevel->grid_mode = GRID_VARIABLE_MODE;
    toplevel->grid_fixed_threshold = 10;
  
    toplevel->print_vector_threshold = 3;
  
    toplevel->add_attribute_offset = 50;
  
    toplevel->drag_can_move = TRUE;
  
    toplevel->always_promote_attributes = NULL;
  
    toplevel->net_naming_priority = 0;
    toplevel->hierarchy_traversal = 0;
    toplevel->hierarchy_uref_mangle = 0;
    toplevel->hierarchy_netname_mangle = 0;
    toplevel->hierarchy_netattrib_mangle = 0;
    toplevel->hierarchy_uref_separator      = NULL;
    toplevel->hierarchy_netname_separator   = NULL;
    toplevel->hierarchy_netattrib_separator = NULL;
    toplevel->hierarchy_netattrib_order = 0;
    toplevel->hierarchy_netname_order = 0;
    toplevel->hierarchy_uref_order = 0;
    toplevel->unnamed_netname = NULL;
  
    /* Auto-save interval */
    toplevel->auto_save_interval = 0;
  
    /* set the rest of the variables */
    if (variable_set_func) {
      (*variable_set_func) (toplevel);
    }
  
  
    /* disable the events */
    toplevel->DONT_DRAW_CONN = 1;
    toplevel->DONT_RESIZE = 1;
    toplevel->DONT_EXPOSE = 1;
    toplevel->DONT_RECALC = 1;
    toplevel->DONT_REDRAW = 1;
  
    
    /* now append toplevel to this list: */
    /*   - find the tail of the toplevel list */
    for (tmp = toplevel_head; tmp->next != NULL; tmp = tmp->next);
    /*   - link toplevel with tmp */
    tmp->next = toplevel;
    toplevel->prev = tmp;
    toplevel->next = NULL;
  
    return toplevel;
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  void s_toplevel_delete (TOPLEVEL *toplevel)
  {
    if (toplevel->wid == -1) {
      /* do no delete head */
      return;
    }
  
    g_free (toplevel->series_name);
    g_free (toplevel->untitled_name);
    g_free (toplevel->font_directory);
    g_free (toplevel->scheme_directory);
    g_free (toplevel->bitmap_directory);
    g_free (toplevel->bus_ripper_symname);
    
    /* free all fonts */
    /* if you close a window, then you free the font set... */
    /* this is probably a bad idea... */
    /* The font set can ONLY be freed when exiting!!! */
    /*  o_text_freeallfonts (toplevel); */
  
    /* delete all pages */
    s_page_delete_list (toplevel);
    
    /* unlink toplevel from toplevel list */
    toplevel->prev->next = toplevel->next;
    if (toplevel->next != NULL) {
      toplevel->next->prev = toplevel->prev;
    }
    
    g_free (toplevel);
    
  }
  
  
  
  1.5       +270 -226  eda/geda/gaf/libgeda/src/s_undo.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: s_undo.c
  ===================================================================
  RCS file: s_undo.c
  diff -N s_undo.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ s_undo.c	5 Jul 2006 03:13:39 -0000	1.5
  @@ -0,0 +1,352 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <ctype.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_ASSERT_H
  +#include <assert.h>
  +#endif
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "defines.h"
  +#include "globals.h"
  +#include "colors.h"
  +#include "o_types.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +UNDO *s_undo_return_tail(UNDO *head)
  +{
  +  UNDO *u_current=NULL;
  +  UNDO *ret_struct=NULL;
  +
  +  u_current = head;
  +  while ( u_current != NULL ) { /* goto end of list */
  +    ret_struct = u_current;
  +    u_current = u_current->next;
  +  }
  +
  +  return(ret_struct);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +UNDO *s_undo_return_head(UNDO *tail)
  +{
  +  UNDO *u_current=NULL;
  +  UNDO *ret_struct=NULL;
  +
  +  u_current = tail;
  +  while ( u_current != NULL ) { /* goto end of list */
  +    ret_struct = u_current;
  +    u_current = u_current->prev;
  +  }
  +
  +  return(ret_struct);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +UNDO *s_undo_new_head(void)
  +{
  +  UNDO *u_new;
  +
  +  u_new = (UNDO *) malloc(sizeof(UNDO));
  +  u_new->type = -1;
  +  u_new->filename = NULL;
  +  u_new->object_head = NULL;
  +  u_new->left = u_new->right = u_new->top = u_new->bottom = -1;
  +
  +  u_new->page_control = 0;
  +  u_new->up = -2;
  +
  +  u_new->prev = NULL;
  +  u_new->next = NULL;
  +
  +  return(u_new);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_undo_destroy_head(UNDO *u_head)
  +{
  +  free(u_head);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +UNDO *s_undo_add(UNDO *head, int type, char *filename, OBJECT *object_head,
  +		 int left, int top, int right, int bottom, int page_control,
  +		 int up)
  +{
  +  UNDO *tail;
  +  UNDO *u_new;
  +
  +  u_new = (UNDO *) malloc(sizeof(UNDO));
  +
  +  u_new->filename = g_strdup (filename);
  +	
  +  if (object_head != NULL) {
  +    u_new->object_head = object_head;	
  +  } else {
  +    u_new->object_head = NULL;	
  +  }
  +
  +  u_new->type = type;
  +
  +  u_new->left = left;
  +  u_new->top = top;
  +  u_new->right = right;
  +  u_new->bottom = bottom;
  +
  +  u_new->page_control = page_control;
  +  u_new->up = up;
  +
  +  if (head == NULL) {
  +    u_new->prev = NULL; /* setup previous link */
  +    u_new->next = NULL;
  +    return(u_new);
  +  } else {
  +    tail = s_undo_return_tail(head);
  +    u_new->prev = tail; /* setup previous link */
  +    u_new->next = NULL;
  +    tail->next = u_new;
  +    return(tail->next);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_undo_print_all( UNDO *head )
  +{
  +  UNDO *u_current;
  +
  +  u_current = head;
  +
  +  printf("START printing undo ********************\n");
  +  printf("BOTTOM\n");
  +  while(u_current != NULL) {
  +
  +    if (u_current->filename) printf("%s\n", u_current->filename);
  +		
  +    if (u_current->object_head) {
  +      printf("%s\n", u_current->object_head->name);	
  +      print_struct_forw(u_current->object_head);
  +    }
  +		
  +    printf("\t%d %d %d %d\n", u_current->left, u_current->top,
  +           u_current->right, u_current->bottom);
  +    u_current = u_current->next;
  +  }
  +  printf("TOS\n");
  +  printf("Number of levels: %d\n", s_undo_levels(head));
  +  printf("DONE printing undo ********************\n");
  +  printf("\n");
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_undo_destroy_all(TOPLEVEL *w_current, UNDO *head) 
  +{
  +  UNDO *u_current;
  +  UNDO *u_prev;
  +
  +  u_current = s_undo_return_tail(head);
  +
  +  while (u_current != NULL) {
  +    u_prev = u_current->prev;	
  +    if (u_current->filename) free(u_current->filename);
  +		
  +    if (u_current->object_head) {
  +      w_current->REMOVING_SEL = 1;
  +      s_delete_list_fromstart(w_current, 
  +                              u_current->object_head);
  +      w_current->REMOVING_SEL = 0;
  +      u_current->object_head = NULL;
  +    }
  +
  +    free(u_current);
  +    u_current = u_prev;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_undo_remove(TOPLEVEL *w_current, UNDO *head, UNDO *u_tos)
  +{
  +  UNDO *u_current;
  +
  +  if (u_tos == NULL) {
  +    fprintf(stderr, "Got NULL for u_tos in s_undo_remove\n");
  +    return;
  +  }
  +
  +  u_current = head;	
  +
  +  while (u_current != NULL) {
  +    if (u_current == u_tos) {
  +      if (u_current->next)
  +        u_current->next->prev = u_current->prev;
  +      else
  +        u_current->next = NULL;
  +
  +      if (u_current->prev)
  +        u_current->prev->next = u_current->next;
  +      else
  +        u_current->prev = NULL;
  +
  +      if (u_current->filename) {
  +        free(u_current->filename);	
  +      }
  +
  +      if (u_current->object_head) {
  +				/*w_current->REMOVING_SEL = 1; */
  +        s_delete_list_fromstart(w_current, 
  +                                u_current->object_head);
  +				/*w_current->REMOVING_SEL = 0;*/
  +        u_current->object_head = NULL;
  +      }
  +
  +      free(u_current);
  +      return;
  +    }
  +    u_current = u_current->next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_undo_remove_rest(TOPLEVEL *w_current, UNDO *head) 
  +{
  +  UNDO *u_current;
  +  UNDO *u_next;
  +
  +  u_current = head;
  +
  +  while (u_current != NULL) {
  +    u_next = u_current->next;	
  +
  +    if (u_current->filename) {
  +      unlink(u_current->filename);
  +      free(u_current->filename);
  +    }
  +
  +    if (u_current->object_head) {
  +      w_current->REMOVING_SEL = 1;
  +      s_delete_list_fromstart(w_current, 
  +                              u_current->object_head);
  +      w_current->REMOVING_SEL = 0;
  +      u_current->object_head = NULL;
  +    }
  +
  +    free(u_current);
  +    u_current = u_next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int s_undo_levels(UNDO *head)
  +{
  +  UNDO *u_current;
  +  int count = 0;
  +	
  +  u_current = head;
  +  while (u_current != NULL) {
  +    if (u_current->filename || u_current->object_head) {
  +      count++;	
  +    } 	
  +		
  +    u_current = u_current->next;
  +  }
  +	
  +  return(count);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_undo_init(PAGE *p_current)
  +{
  +	p_current->undo_tos = p_current->undo_bottom = NULL;
  +	p_current->undo_current = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void s_undo_free_all(TOPLEVEL *w_current, PAGE *p_current)
  +{
  +  s_undo_destroy_all(w_current, p_current->undo_bottom);
  +  p_current->undo_bottom = NULL;
  +  p_current->undo_tos = NULL;
  +  p_current->undo_current = NULL;
  +}
  
  
  
  1.10      +131 -103  eda/geda/gaf/libgeda/src/u_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: u_basic.c
  ===================================================================
  RCS file: u_basic.c
  diff -N u_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ u_basic.c	5 Jul 2006 03:13:39 -0000	1.10
  @@ -0,0 +1,167 @@
  +/* gEDA - GPL Electronic Design Automation
  + * libgeda - gEDA's library
  + * Copyright (C) 1998, 1999, 2000 Kazu Hirata / Ales Hvezda
  + *
  + * 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.
  + *
  + * This program 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 this program; if not, write to the Free Software
  + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +#ifdef HAVE_STDARG_H
  +#include <stdarg.h>
  +#endif
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +
  +#include <gtk/gtk.h>
  +#include <libguile.h>
  +
  +#include "defines.h"
  +#include "struct.h"
  +#include "globals.h"
  +
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* the delimiter is what is passed in or spaces */
  +/* count starts at zero */
  +char *u_basic_breakup_string(char *string, char delimiter, int count)
  +{
  +  int i=0, j=0;
  +  int internal_counter=0;
  +  int done=FALSE;
  +  char *return_value;
  +
  +  /* skip over any leading white space */
  +  while(string[i] == ' ' && !string[i]) {
  +    i++;
  +  }
  +
  +  /* Allocate space for temp string storage (+1 for null character) */ 
  +  return_value = malloc(sizeof(char)*(strlen(string) + 1));
  +
  +  while(!done) {
  +
  +    /* oops, ran out of string before we found what we were */
  +    /* looking for */
  +    if (i > strlen(string)) {
  +      free(return_value);
  +      return(NULL);
  +    }
  +
  +    /* skip over any leading white space */
  +    while(string[i] == ' ' && string[i] != '\0') {
  +      i++;
  +    }
  +
  +    j = 0;
  +
  +    /* Old forgiving parsing */
  +    /*		while(string[i] != ',' && string[i] != ';' && */
  +    /*		      string[i] != ' ' && string[i] != '\0') {*/
  +
  +    while(string[i] != delimiter && string[i] != '\0') {
  +      return_value[j] = string[i];
  +      i++; j++;
  +    }
  +
  +    if (internal_counter == count)  { 
  +      done = TRUE;	
  +    } else {
  +      internal_counter++;
  +      i++; /* skip the offending character */
  +    }
  +  }
  +
  +  return_value[j] = '\0';
  +  return(return_value);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void u_basic_strip_trailing(char *string, char c)
  +{
  +  if (string) {
  +   int len = strlen(string) - 1; /* point to last char */
  +   if (string[len] == c) {
  +       string[len] = '\0';
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int u_basic_has_trailing(char *string, char c)
  +{
  +  if (string) {
  +   int len = strlen(string) - 1; /* point to last char */
  +   if (string[len] == c) {
  +	return TRUE;
  +    }
  +  }
  +  return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/*
  + * This fcn counts the number of occurances of the character
  + * "character" in the string "string".
  + * 1.23.2005 -- SDB
  + */
  +int u_basic_count_char(const char *string, char character)
  +{
  +  int count = 0;
  +  int i=0;
  +
  +#ifdef DEBUG
  +  printf("In u_basic_count_char, looking for char \"%c\" in string \"%s\".\n", 
  +	  character, string);
  +#endif
  +
  +  while (string[i] != '\0') {
  +    if (string[i] == character) {
  +      count++;
  +    }
  +  i++;
  +  }
  +#ifdef DEBUG
  +  printf(". . . . .   Found it %d times.\n", 
  +	  count);
  +#endif
  +
  +return count;
  +}
  
  
  
_______________________________________________
geda-cvs mailing list
geda-cvs@xxxxxxxxxxxxxx
http://www.seul.org/cgi-bin/mailman/listinfo/geda-cvs