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

gEDA-user: dsn exporter



   This exporter outputs a .dsn file for opening with freeroute.net.  It
   only works on 2 layer designs so far.
   I did not start writing an importer for it yet, if anyone has
   suggestions on the architecture of this I will listen.  (.cmd file?)
   I will be out of town for the next 10 days and then I will work on the
   importer.
   To install it, make a specctra directory in the hid directory, put
   this file in it, a copy of hid.conf, make a change to makefile.am in
   /src, and make install again.
/*
This program exports specctra .dsn files from geda .pcb files.
By Josh Jordan
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "global.h"
#include "data.h"
#include "error.h"
#include "misc.h"
#include "gts.h"
#include "rats.h"
#include "buffer.h"
#include "parse_l.h"

#include "hid.h"
#include "../hidint.h"

#ifdef HAVE_LIBDMALLOC
#include <dmalloc.h>
#endif

static HID_Attribute specctra_options[] = {
  {"specctrafile", "SPECCTRA output file",
   HID_String, 0, 0, {0, 0, 0}, 0, 0},
#define HA_specctrafile 0
  {"trackwidth", "default track width in mils",
   HID_Integer, 0, 0, {0, 0, 0}, 0, 0},
#define HA_trackwidth 1
};

#define NUM_OPTIONS (sizeof(specctra_options)/sizeof(specctra_options[0]))

static HID_Attr_Val specctra_values[NUM_OPTIONS];

static char *specctra_filename;

typedef struct _StringList
{
  char *str;
  struct _StringList *next;
} StringList;

typedef struct _SpecctraList
{
  char *descr;
  char *value;
  int num;
  StringList *refdes;
  struct _SpecctraList *next;
} SpecctraList;

static HID_Attribute *
specctra_get_export_options (int *n)
{
  static char *last_specctra_filename = 0;
  if (PCB) {
	derive_default_filename(PCB->Filename, &specctra_options[HA_specctrafile], ".dsn", &last_specctra_filename);
  }

  if (n)
    *n = NUM_OPTIONS;
  return specctra_options;
}


static char *
CleanSPECCTRAString (char *in)
{
  char *out;
  int i;

  if ((out = malloc ((strlen (in) + 1) * sizeof (char))) == NULL)
    {
      fprintf (stderr, "Error:  CleanSPECCTRAString() malloc() failed\n");
      exit (1);
    }

  /* 
   * copy over in to out with some character conversions.
   * Go all the way to then end to get the terminating \0
   */
  for (i = 0; i <= strlen (in); i++)
    {
      switch (in[i])
	{
	case '"':
	  out[i] = '\'';
	  break;
	default:
	  out[i] = in[i];
	}
    }

  return out;
}


static double
xyToAngle (double x, double y)
{
  double theta;

  if ((x > 0.0) && (y >= 0.0))
    theta = 180.0;
  else if ((x <= 0.0) && (y > 0.0))
    theta = 90.0;
  else if ((x < 0.0) && (y <= 0.0))
    theta = 0.0;
  else if ((x >= 0.0) && (y < 0.0))
    theta = 270.0;
  else
    {
      theta = 0.0;
      Message ("xyToAngle(): unable to figure out angle of element\n"
	       "     because the pin is at the centroid of the part.\n"
	       "     This is a BUG!!!\n"
	       "     Setting to %g degrees\n", theta);
    }

  return (theta);
}

typedef struct {
  double centx;
  double centy;
  int rot;
} CentroidRotation;

/* this function is mostly ripped from bom.c 
   it gives only absolute rotation, it must be
    compared to the absolute rotation of the library part*/
static CentroidRotation
get_rotation_and_centroid (ElementType *element){
  CentroidRotation centrot;
  int found_pin1;
  int found_pin2;
  int pin_cnt;
  double x, y, theta = 0.0, user_x, user_y;
  double pin1x = 0.0, pin1y = 0.0, pin1angle = 0.0;
  double pin2x = 0.0, pin2y = 0.0, pin2angle;
  double sumx, sumy;
  /* initialize our pin count and our totals for finding the centriod */
  pin_cnt = 0;
  sumx = 0.0;
  sumy = 0.0;
  found_pin1 = 0;
  found_pin2 = 0;
  /*
   * iterate over the pins and pads keeping a running count of how
   * many pins/pads total and the sum of x and y coordinates
   * 
   * While we're at it, store the location of pin/pad #1 and #2 if
   * we can find them
   */

  PIN_LOOP (element);
  {
    sumx += (double) pin->X;
    sumy += (double) pin->Y;
    pin_cnt++;

    if (NSTRCMP (pin->Number, "1") == 0)
    {
      pin1x = (double) pin->X;
      pin1y = (double) pin->Y;
      pin1angle = 0.0;	/* pins have no notion of angle */
      found_pin1 = 1;
    }
    else if (NSTRCMP (pin->Number, "2") == 0)
    {
      pin2x = (double) pin->X;
      pin2y = (double) pin->Y;
      pin2angle = 0.0;	/* pins have no notion of angle */
      found_pin2 = 1;
    }
  }
  END_LOOP;

  PAD_LOOP (element);
  {
    sumx += (pad->Point1.X + pad->Point2.X) / 2.0;
    sumy += (pad->Point1.Y + pad->Point2.Y) / 2.0;
    pin_cnt++;

    if (NSTRCMP (pad->Number, "1") == 0)
    {
      pin1x = (double) (pad->Point1.X + pad->Point2.X) / 2.0;
      pin1y = (double) (pad->Point1.Y + pad->Point2.Y) / 2.0;
      /*
       * NOTE:  We swap the Y points because in PCB, the Y-axis
       * is inverted.  Increasing Y moves down.  We want to deal
       * in the usual increasing Y moves up coordinates though.
       */
      pin1angle = (180.0 / M_PI) * atan2 (pad->Point1.Y - pad->Point2.Y,
	                pad->Point2.X - pad->Point1.X);
      found_pin1 = 1;
    }
    else if (NSTRCMP (pad->Number, "2") == 0)
    {
      pin2x = (double) (pad->Point1.X + pad->Point2.X) / 2.0;
      pin2y = (double) (pad->Point1.Y + pad->Point2.Y) / 2.0;
      pin2angle = (180.0 / M_PI) * atan2 (pad->Point1.Y - pad->Point2.Y,
	                pad->Point2.X - pad->Point1.X);
      found_pin2 = 1;
    }

  }
  END_LOOP;

  if (pin_cnt > 0)
  {
    x = sumx / (double) pin_cnt;
    y = sumy / (double) pin_cnt;

    if (found_pin1)
    {
      /* recenter pin #1 onto the axis which cross at the part
         centroid */
      pin1x -= x;
      pin1y -= y;
      pin1y = -1.0 * pin1y;

      /* if only 1 pin, use pin 1's angle */
      if (pin_cnt == 1)
        theta = pin1angle;
      else
      {
        /* if pin #1 is at (0,0) use pin #2 for rotation */
        if ((pin1x == 0.0) && (pin1y == 0.0))
        {
          if (found_pin2)
            theta = xyToAngle (pin2x, pin2y);
          else
          {
          Message
            ("SPECCTRA EXPORTER: unable to figure out angle of element\n"
             "     %s because pin #1 is at the centroid of the part.\n"
             "     and I could not find pin #2's location\n"
             "     Setting to %g degrees\n",
             UNKNOWN (NAMEONPCB_NAME (element)), theta);
          }
        }
        else
          theta = xyToAngle (pin1x, pin1y);
      }
    }
    /* we did not find pin #1 */
    else
    {
      theta = 0.0;
      Message
      ("SPECCTRA EXPORTER: unable to figure out angle because I could\n"
       "     not find pin #1 of element %s\n"
       "     Setting to %g degrees\n",
       UNKNOWN (NAMEONPCB_NAME (element)), theta);
    }
   	y = PCB->MaxHeight - y;

   	/* dimensions in mils */
   	user_x = 0.01 * x;
   	user_y = 0.01 * y;
    centrot.centx = user_x;
    centrot.centy = user_y;
    centrot.rot = theta;
    return centrot;
  }
}


static StringList *
string_insert (char *str, StringList * list)
{
  StringList *new, *cur;

  if ((new = (StringList *) malloc (sizeof (StringList))) == NULL)
    {
      fprintf (stderr, "malloc() failed in string_insert()\n");
      exit (1);
    }

  new->next = NULL;
  new->str = strdup (str);

  if (list == NULL)
    return (new);

  cur = list;
  while (cur->next != NULL)
    cur = cur->next;

  cur->next = new;

  return (list);
}

static SpecctraList *
specctra_insert (char *refdes, char *descr, char *value, SpecctraList * specctra)
{
  SpecctraList *new, *cur, *prev = NULL;

  if (specctra == NULL)
    {
      /* this is the first element so automatically create an entry */
      if ((new = (SpecctraList *) malloc (sizeof (SpecctraList))) == NULL)
	{
	  fprintf (stderr, "malloc() failed in specctra_insert()\n");
	  exit (1);
	}

      new->next = NULL;
      new->descr = strdup (descr);
      new->value = strdup (value);
      new->num = 1;
      new->refdes = string_insert (refdes, NULL);
      return (new);
    }

  /* search and see if we already have used one of these
     components */
  cur = specctra;
  while (cur != NULL)
    {
      if ((NSTRCMP (descr, cur->descr) == 0) &&
	  (NSTRCMP (value, cur->value) == 0))
	{
	  cur->num++;
	  cur->refdes = string_insert (refdes, cur->refdes);
	  break;
	}
      prev = cur;
      cur = cur->next;
    }

  if (cur == NULL)
    {
      if ((new = (SpecctraList *) malloc (sizeof (SpecctraList))) == NULL)
	{
	  fprintf (stderr, "malloc() failed in specctra_insert()\n");
	  exit (1);
	}

      prev->next = new;

      new->next = NULL;
      new->descr = strdup (descr);
      new->value = strdup (value);
      new->num = 1;
      new->refdes = string_insert (refdes, NULL);
    }

  return (specctra);

}

/* 
 * If fp is not NULL then print out the bill of materials contained in
 * specctra.  Either way, free all memory which has been allocated for specctra.
 */
static void
print_and_free (FILE *fp, SpecctraList *specctra)
{
  SpecctraList *lastb;
  StringList *lasts;
  char *descr, *value;

  while (specctra != NULL)
    {
      if (fp)
	{
	  descr = CleanSPECCTRAString (specctra->descr);
	  value = CleanSPECCTRAString (specctra->value);
	  fprintf (fp, "%d,\"%s\",\"%s\",", specctra->num, descr, value);
	  free (descr);
	  free (value);
	}
      
      while (specctra->refdes != NULL)
	{
	  if (fp)
	    {
	      fprintf (fp, "%s ", specctra->refdes->str);
	    }
	  free (specctra->refdes->str);
	  lasts = specctra->refdes;
	  specctra->refdes = specctra->refdes->next;
	  free (lasts);
	}
      if (fp)
	{
	  fprintf (fp, "\n");
	}
      lastb = specctra;
      specctra = specctra->next;
      free (lastb);
    }
}

static void
print_structure (FILE *fp)
{
  fprintf (fp, "  (structure\n");

  /* define layers */
  fprintf (fp, "    (layer Component\n");
  fprintf (fp, "      (type signal)\n");
  fprintf (fp, "      (property\n");
  fprintf (fp, "        (index 0)\n      )\n    )\n");
  fprintf (fp, "    (layer Copper\n");
  fprintf (fp, "      (type signal)\n");
  fprintf (fp, "      (property\n");
  fprintf (fp, "        (index 1)\n      )\n    )\n");

  /* PCB outline */
  fprintf (fp, "    (boundary\n");
  fprintf (fp, "      (rect pcb 0.0 0.0 %.2f %.2f)\n", PCB->MaxWidth*0.01, PCB->MaxHeight*0.01);
  fprintf (fp, "    )\n");

  fprintf (fp, "    (via \"via_45_25_mil\")\n");

  /* DRC rules */
  fprintf (fp, "    (rule\n");
  fprintf (fp, "      (width 8)\n");
  fprintf (fp, "      (clear 10)\n");
  fprintf (fp, "      (clear 10 (type wire_area))\n");
  fprintf (fp, "      (clear 10 (type via_smd via_pin))\n");
  fprintf (fp, "      (clear 10 (type smd_smd))\n");
  fprintf (fp, "      (clear 10 (type default_smd))\n");
  fprintf (fp, "    )\n  )\n");
}

static void
print_placement (FILE *fp)
/* gather all footprint names in a list
   gather list of refdes for each footprint in list */
{
  int i;
  GList *footprints; //contain unique footprint names
  fprintf (fp, "  (placement\n");
  ELEMENT_LOOP (PCB->Data);
  {
    gconstpointer descript = DESCRIPTION_NAME (element);
    if( !g_list_find_custom( footprints, descript, strcmp ) ){
      footprints = g_list_append( footprints, descript );
    }
  }
  END_LOOP;
  for(i=0; i < g_list_length( footprints ); i++){
    int firstrot = -1; //change to the degree of the first element found
    fprintf (fp, "    (component %s\n", g_list_nth_data( footprints, i ));
    ELEMENT_LOOP (PCB->Data);
    {
      if(!strcmp(DESCRIPTION_NAME (element), g_list_nth_data( footprints, i ) )){
        CentroidRotation crot = get_rotation_and_centroid(element);
        if (firstrot == -1)
        {
          firstrot = crot.rot;
        }
        char* side = TEST_FLAG (ONSOLDERFLAG, element) ? "back" : "front";
        fprintf (fp, "      (place %s %.2f %.2f %s %d (PN %s))\n", NAMEONPCB_NAME (element), crot.centx, crot.centy, side, firstrot-crot.rot, VALUE_NAME (element) );
      }
    }
    END_LOOP;
    fprintf (fp, "    )\n");
  }
  fprintf (fp, "  )\n");
  g_list_free( footprints );
}

static void
print_library (FILE *fp)
/* gather all footprint names in a list
   print info on each footprint */
{
  int i;
  GList *footprints; //contain unique footprint names
  GList *pads; //contain unique pad names
  fprintf (fp, "  (library\n");
  ELEMENT_LOOP (PCB->Data);
  {
    if( !g_list_find_custom( footprints, DESCRIPTION_NAME (element), strcmp ) ){
      char *padstack;
      int rotation;
      int whichside = TEST_FLAG (ONSOLDERFLAG, element) ? -1 : 1;
      CentroidRotation crot = get_rotation_and_centroid(element);
      footprints = g_list_append( footprints, g_strdup( DESCRIPTION_NAME (element) ) );
      fprintf (fp, "    (image %s\n", DESCRIPTION_NAME (element) );
      /* loop thru pins and pads here */
      PIN_LOOP (element);
      {
        int ty;
        float pinthickness;
        float lx, ly; //hold local pin coordinates
        ty = PCB->MaxHeight - pin->Y;
        pinthickness = pin->Thickness*0.01;
        padstack = g_strdup_printf ("Th_round_%.0f_mil", pinthickness);
        lx = (pin->X*0.01-crot.centx)*whichside;
        ly = (crot.centy - ty*0.01)*(-1);
        if( !g_list_find_custom( pads, padstack, strcmp ) )
        {
          pads = g_list_append( pads, padstack );
        }
        if (!pin->Number) //if pin is null just make it a keepout
        {
          fprintf (fp, "      (keepout \"\" (circle Component %.0f %.2f %.2f))\n", pinthickness, lx, ly);
          fprintf (fp, "      (keepout \"\" (circle Copper %.0f %.2f %.2f))\n", pinthickness, lx, ly);
        }
        else
        {
          fprintf (fp, "      (pin %s %s %.2f %.2f)\n", padstack, pin->Number, lx, ly);
        }
      }
      END_LOOP;
      PAD_LOOP (element);
      {
        int xlen, ylen, xc, yc, p1y, p2y;
        float lx, ly; //store local coordinates for pins
        p1y = PCB->MaxHeight - pad->Point1.Y;
        p2y = PCB->MaxHeight - pad->Point2.Y;
        /* pad dimensions are thickness and point difference plus thickness */
        xlen = (ABS(pad->Point1.X - pad->Point2.X)+50)/100; //round to mil
        if (xlen == 0)
        {
          xlen = (pad->Thickness+50)/100; //round to mil
          ylen = (ABS(p1y - p2y)+50)/100 + xlen; //round to mil
        }
        else
        {
          ylen = (pad->Thickness+50)/100;
          xlen += ylen;
        }
        xc = (pad->Point1.X + pad->Point2.X)/2;
        yc = (p1y + p2y)/2;
        lx = (xc*0.01-crot.centx)*whichside;
        ly = (crot.centy - yc*0.01)*(-1);
        padstack = g_strdup_printf ("Smd_rect_%dx%d_mil", xlen, ylen);
        if( !g_list_find_custom( pads, padstack, strcmp ) )
        {
          pads = g_list_append( pads, padstack );
        }
        if (!pad->Number) //if pad is null just make it a keepout
        {
          fprintf (fp, "      (keepout \"\" (rect %s %.2f %.2f %.2f %.2f))\n", (whichside == 1) ? "Component" : "Copper", lx-xlen/2, ly-ylen/2, lx+xlen/2, ly+ylen/2);
        }
        else
        {
          fprintf (fp, "      (pin %s %s %.2f %.2f)\n", padstack, pad->Number, lx, ly);
        }
      }
      END_LOOP;
      fprintf (fp, "    )\n");
    }
  }
  END_LOOP;
  /* loop thru padstacks and define them all */
  for(i=0; i < g_list_length( pads ); i++)
  {
    int retargs, dim1, dim2;
    char * padstring = g_list_nth_data( pads, i );
    fprintf (fp, "    (padstack %s\n", padstring);
    /* print info about pad here */
    retargs = sscanf (padstring, "Smd_rect_%dx%d_mil", &dim1, &dim2);
    if (retargs == 2) //then pad is smd
    { 
      fprintf (fp, "      (shape (rect Component %.1f %.1f %.1f %.1f))\n", dim1/(-2.0), dim2/(-2.0), dim1/2.0, dim2/2.0);
    }
    else ///then pad is th
    {
      retargs = sscanf (padstring, "Th_round_%d_mil", &dim1);
      fprintf (fp, "      (shape (circle Component %d))\n", dim1);
      fprintf (fp, "      (shape (circle Copper %d))\n", dim1);
    }
    fprintf (fp, "      (attach off)\n");
    fprintf (fp, "    )\n");
  }
  /* add padstack for via */
  fprintf (fp, "    (padstack \"via_45_25_mil\"\n      (shape (circle Component 45))\n      (shape (circle Copper 45))\n      (attach off)\n    )\n");
  fprintf (fp, "  )\n");
  g_list_foreach( footprints, (GFunc)g_free, NULL );
  g_list_free( footprints );
  g_list_foreach( pads, (GFunc)g_free, NULL );
  g_list_free( pads );
}

static void
print_network (FILE *fp)
{
  GList *netlistnames;  //contain unique strings of netlist names
  int i, firstcon;
  NetListListType Nets;
  Nets = CollectSubnets (False);
  fprintf (fp, "  (network\n");
  NETLIST_LOOP (&Nets);
  {
    firstcon = 1; //clear flag after net name is found
    NET_LOOP (netlist);
    {
      CONNECTION_LOOP (net);
      {
        int ni, nei;
	      char *ename;
	      char *pname;
	      char *n;
        char *netname;
        /* looking for pins and pads */
        if (connection->type == PIN_TYPE || connection->type == PAD_TYPE)
        {
          PinTypePtr thispin;
          PadTypePtr thispad;
          ElementTypePtr thiselem;
          if (connection->type == PIN_TYPE)
          {
            thispin = connection->ptr2;
            thiselem = thispin->Element;
            pname = thispin->Number;
          }
          else
          {
            thispad = connection->ptr2;
            thiselem = thispad->Element;
            pname = thispad->Number;
          }
          ename = NAMEONPCB_NAME(thiselem);
          n = g_strconcat (ename, "-", pname, NULL);
	        for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++) //loop thru all nets
		      for (nei = 0; nei < PCB->NetlistLib.Menu[ni].EntryN; nei++) //loop thru all entries in all nets
		      {
		        if (strcmp (PCB->NetlistLib.Menu[ni].Entry[nei].ListEntry, n) == 0) //find the entry that matches this pin or pad
		        {
              netname = g_strdup (PCB->NetlistLib.Menu[ni].Name + 2); //find the net name of this entry
              //if( !g_list_find_custom( netlistnames, netname, strcmp ) ) //see if netlist was written down already
              if(firstcon == 1)
              {
                firstcon = 0;
                netlistnames = g_list_append( netlistnames, netname );
                fprintf (fp, "    (net %s\n      (pins", netname);
              }
            }
          }
          fprintf (fp, " %s", n);
          g_free(n);
        }
      }
      END_LOOP;
    }
    END_LOOP;
    fprintf (fp, ")\n    )\n");
  }
  END_LOOP;
  fprintf (fp, "    (class geda_default");
  for(i=0; i < g_list_length( netlistnames ); i++)
  {
    fprintf (fp, " %s", g_list_nth_data( netlistnames, i ) );
  }
  fprintf (fp, "\n      (circuit\n        (use_via via_45_25_mil)\n      )\n");
  fprintf (fp, "      (rule (width 8))\n    )\n  )\n");
  fprintf (fp, "  (wiring\n  )\n)\n");
  
  g_list_foreach( netlistnames, (GFunc)g_free, NULL );
  g_list_free( netlistnames );
}

static int
PrintSPECCTRA (void)
{
  char utcTime[64];
  double x, y, theta = 0.0, user_x, user_y;
  double sumx, sumy;
  double pin1x = 0.0, pin1y = 0.0, pin1angle = 0.0;
  double pin2x = 0.0, pin2y = 0.0, pin2angle;
  int found_pin1;
  int found_pin2;
  int pin_cnt;
  time_t currenttime;
  FILE *fp;
  SpecctraList *specctra = NULL;
  char *name, *descr, *value;

  /* Print out the specctra .dsn file. */

  fp = fopen (specctra_filename, "w");
  if (!fp)
    {
      gui->log ("Cannot open file %s for writing\n", specctra_filename);
      print_and_free (NULL, specctra);
      return 1;
    }

  /* pcb [required] */
  fprintf (fp, "(pcb %s\n", ((PCB->Name) && *(PCB->Name) ? (PCB->Name) : "notnamed"));
  
  /* parser descriptor [optional] */
  fprintf (fp, "  (parser\n");
  fprintf (fp, "    (string_quote \")\n");
  fprintf (fp, "    (space_in_quoted_tokens on)\n");
  fprintf (fp, "    (host_cad \"gEDA PCB\")\n");
  fprintf (fp, "    (host_version \"(i dunno?)\")\n");
  fprintf (fp, "  )\n");

  /* capacitance resolution descriptor [optional] */

  /* conductance resolution descriptor [optional] */

  /* current resolution descriptor [optional] */

  /* inductance resolution descriptor [optional] */

  /* resistance resolution descriptor [optional] */

  /* resolution descriptor [optional] */
  fprintf (fp, "  (resolution mil 10)\n");

  /* time resolution descriptor [optional] */

  /* voltage resolution descriptor [optional] */

  /* unit descriptor [optional] */
  fprintf (fp, "  (unit mil)\n");

  /* structure descriptor [required] */
  print_structure (fp);
  
  /* placement descriptor [optional] */
  print_placement (fp);
  
  /* library descriptor [required] */
  print_library (fp);
  
  /* floor plan descriptor [optional] */
  
  /* part library descriptor [optional] */
  
  /* network descriptor [required] */
  print_network (fp);
  
  /* wiring descriptor [optional] */
  
  /* color descriptor [optional] */
  
  print_and_free (fp, specctra);

  fclose (fp);

  return (0);
}

static void
specctra_do_export (HID_Attr_Val * options)
{
  int i;

  if (!options)
    {
      specctra_get_export_options (0);
      for (i = 0; i < NUM_OPTIONS; i++)
	specctra_values[i] = specctra_options[i].default_val;
      options = specctra_values;
    }

  specctra_filename = options[HA_specctrafile].str_value;
  if (!specctra_filename)
    specctra_filename = "pcb-out.dsn";

  PrintSPECCTRA ();
}

static void
specctra_parse_arguments (int *argc, char ***argv)
{
  hid_register_attributes (specctra_options,
			   sizeof (specctra_options) / sizeof (specctra_options[0]));
  hid_parse_command_line (argc, argv);
}

HID specctra_hid = {
  sizeof (HID),
  "specctra",
  "Exports a SPECCTRA .dsn file",
  0, 0, 1, 0, 0, 0,
  specctra_get_export_options,
  specctra_do_export,
  specctra_parse_arguments,
  0,				/* specctra_invalidate_wh */
  0,				/* specctra_invalidate_lr */
  0,				/* specctra_invalidate_all */
  0,				/* specctra_set_layer */
  0,				/* specctra_make_gc */
  0,				/* specctra_destroy_gc */
  0,				/* specctra_use_mask */
  0,				/* specctra_set_color */
  0,				/* specctra_set_line_cap */
  0,				/* specctra_set_line_width */
  0,				/* specctra_set_draw_xor */
  0,				/* specctra_set_draw_faded */
  0,				/* specctra_set_line_cap_angle */
  0,				/* specctra_draw_line */
  0,				/* specctra_draw_arc */
  0,				/* specctra_draw_rect */
  0,				/* specctra_fill_circle */
  0,				/* specctra_fill_polygon */
  0,				/* specctra_fill_rect */
  0,				/* specctra_calibrate */
  0,				/* specctra_shift_is_pressed */
  0,				/* specctra_control_is_pressed */
  0,				/* specctra_get_coords */
  0,				/* specctra_set_crosshair */
  0,				/* specctra_add_timer */
  0,				/* specctra_stop_timer */
  0,				/* specctra_log */
  0,				/* specctra_logv */
  0,				/* specctra_confirm_dialog */
  0,				/* specctra_close_confirm_dialog */
  0,				/* specctra_report_dialog */
  0,				/* specctra_prompt_for */
  0,				/* specctra_fileselect */
  0,				/* specctra_attribute_dialog */
  0,				/* specctra_show_item */
  0,				/* specctra_beep */
  0,				/* specctra_progress */
};

void
hid_specctra_init ()
{
  apply_default_hid (&specctra_hid, 0);
  hid_register_hid (&specctra_hid);
}


_______________________________________________
geda-user mailing list
geda-user@xxxxxxxxxxxxxx
http://www.seul.org/cgi-bin/mailman/listinfo/geda-user