english
version "1.0"
identify "%Z%%M% %I% %E%"

#: Copyright (c) 1995, 1997 2003 by Wayne C. Gramlich.
#, All rights reserved.
#,
#, Permission to use, copy, modify, distribute, and sell this software
#, for any purpose is hereby granted without fee provided that the above
#, copyright notice and this permission are retained.  The author makes
#, no representations about the suitability of this software for any purpose.
#, It is provided "as is" without express or implied warranty.

module board_data

#: This module implements a printed circuit board data abstraction.

define board_data				#: Printed circuit board data
    record
	cells cells				#: Matrix of {cell} objects
	changed logical				#: {true}=>board has changed
	changed_east unsigned			#: Rightmost changed cell
	changed_north unsigned			#: Topmost changed cell
	changed_south unsigned			#: Bottommost changed cell
	changed_west unsigned			#: Leftmost changed cell
	character_chunks vector[chunk]		#: Character to glyph table
	character_chunks1 vector[chunk]		#: Character to glyph table 1R
	character_chunks2 vector[chunk]		#: Character to glyph table 2R
	character_chunks3 vector[chunk]		#: Character to glyph table 3R
	chunk_layers vector[chunk_layer]	#: Other glyphs on board
	cursor_thick chunk			#: Thick cursor chunk
	cursor_thin chunk			#: Thin cursor chunk
	debug_stream out_stream			#: Debugging output stream
	error_stream out_stream			#: Error output stream
	executable_directory string		#: Directory containing exec.
	file_name string			#: File name
	geometry geometry			#: Current geometry of board
	glyph_table glyph_table			#: Glyph information table
	glyph_table_read logical		#: {true}=>glyph table read
	index2direction vector[direction]	#: Conversion table
	index2hole_number vector[chunk]		#: Conversion table
	index2inverted_hole_number vector[chunk] #: Conversion table
	index2thick vector[chunk]		#: Conversion table
	index2thick_edge vector[chunk]		#: Conversion table
	index2thin vector[chunk]		#: Conversion table
	index2thin_edge vector[chunk]		#: Conversion table
	index2via_edge vector[chunk]		#: Conversion table
	name string				#: Temporay hole name
	over_bar chunk				#: Over bar chunk
	read_write_data read_write_data		#: Write data helper
	schematic_capture logical		#: {true}=schematic;else=>PCB
	space chunk				#: Space chunk
	timer_segments timer
	timer_characters timer
	timer_chunks timer
	timer_glyph timer
	via_center chunk			#: Via center chunk
	via_center_named chunk			#: Via center for named via
	wire_connection chunk			#: Wire connection chunk
    generate allocate, erase, print

define geometry					#: Board geometry information
    record
	cell_height unsigned			#: Cell height in pixels
	cell_width unsigned			#: Cell width in pixels
	cells_high unsigned			#: Visible cell rows
	cells_wide unsigned			#: Visible cell columns
    generate address_get, allocate, erase, identical, print

define read_write_data				#: Reader data structure
    record
	relative_mode logical			#: {true}=>use (dx,dy) points
	x_last unsigned				#: Last x value read/written
	y_last unsigned				#: Last y value read/written
    generate allocate, erase, print


#: {board_data} routines:

procedure changed@board_data
    takes
	board_data board_data
	x unsigned
	y unsigned
    returns_nothing

    #: This procedure will extend the cell modification area in {board_data}
    #, to include cell ({x}, {y}).  This routine assumes that the associated
    #, cell has been marked as changed.


procedure character_chunks_insert@board_data
    takes
	board_data board_data
	inverted logical
	text string
	name string
    returns_nothing

    #: This procedure will lookup the glyph associated with {name}
    #, and associate it with the first character in {text}
    #, for the {character_chunks} field of {board_data}.  If {inverted}
    #, is {true}, the character glyph is mirrored to support mirrored
    #, board output.

    #format@format5[unsigned, string, string, string, string](debug_stream,
    #  "n:%d% ch:%ds% ch1:%ds% ch2:%ds% ch3:%ds%\n\",
    #  number, character_chunks[number].glyph.name,
    #  character_chunks1[number].glyph.name,
    #  character_chunks2[number].glyph.name,
    #  character_chunks3[number].glyph.name)



procedure character_delete@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
    returns logical

    #: This procedure will delete that is one to the left of ({x}, {y})
    #, in {layer} of {board_data}.  {true} is returned if the character
    #, cursor should moved to the left by one and {false} otherwise.


procedure character_extract@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
    returns character

    #: This procedure will return the {chunk_layer} object associated
    #, with the character at ({x}, {y}) in {layer} of {board_data}.

procedure character_find@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
    returns character

    #: This procedure will find and return the {character} associated
    #, with a character in {layer} of {board_data} at ({x}, {y}).
    #, If there is no character in the position, ??@{character}
    #, is returned.


procedure character_first_find@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
    returns unsigned

    #: This procedure will find and return the position of the first
    #, character in a sequence characters in {layer} of {board_data}
    #, starting at ({x}, {y}).  It is an error to call this routine
    #, if ({x}, {y}) does not already point to an appropriate character.


procedure character_left_most_find@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
    returns unsigned

    #: This procedure will return the position of the left most
    #, character of the string pointed to by ({x}, {y]) in {layer}
    #, of {board_data}.  ({x}, {y}) must either be directly on the
    #, string or one character to the right of the last character
    #, in the string.

procedure character_insert@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
	character character
    returns logical

    #: This procedure will attempt to insert {character} into {layer} of
    #, {board_data} at ({x}, {y}) if there is room.  Any characters at
    #, ({x}, {y}) and to the right will be moved right by one, unless
    #, that would cause the right most character on the end to be
    #, shifted off the edge of the board or be obstructed by a via.
    #, If the characters to the right can not be moved right by one,
    #, instead the characters to the left will be moved left by one,
    #, unless that would cause the left most character to be shifted
    #, off the edge of the board or be obstructed by a via.  In this
    #, last case, the characters are "jammed", and the glyph is not
    #, inserted.  {true} is returned if the insertion point should be
    #, moved to the right, and {false} otherwise.


procedure character_is_empty@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
    returns logical

    #: This procedure will return {true} if there is no character in {layer}
    #, of {board_data} at ({x}, {y]) and {false} otherwise.


procedure character_is_present@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
    returns logical

    #: This procedure will return {true} if there is a character in {layer}
    #, of {board_data} at ({x}, {y]) and {false} otherwise.


procedure character_last_find@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
    returns unsigned

    #: This procedure will find and return the position of the last
    #, character in a sequence characters in {layer} of {board_data}
    #, starting at ({x}, {y}).  It is an error to call this routine
    #, if ({x}, {y}) does not already point to an appropriate character.


procedure character_move@board_data
    takes
	board_data board_data
	layer layer
	x_from unsigned
	y_from unsigned
	x_to unsigned
	y_to unsigned
    returns logical

    #: This procedure will move the character at ({x_from}, {y_from})
    #, in {layer} of {board_data} to ({x_to}, {y_to}).  {true} is
    #, returned if the character is not successfully moved; and {false}
    #, otherwise.


procedure character_place@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
	character character
    returns_nothing

    #: This procedure will place {character} at ({x}, {y]) in {layer} of
    #, {board_data}.


procedure characters_is_empty@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
	count unsigned
    returns logical

    #: This procedure will return {true} if there are no characters
    #, or vias in {layer} of {board_data} from ({x}, {y}) through
    #, ({x} , {y} + {count} - 1).


procedure characters_move@board_data
    takes
	board_data board_data
	layer layer
	x_from unsigned
	y_from unsigned
	x_to unsigned
	y_to unsigned
	count unsigned
    returns logical

    #: This procedure will move the {count} characters in {layer} of
    #, {board_data} starting at ({x_from}, {y_from}) over to
    #, ({x_to}, {y_to}).  Overlapping moves are permitted.  {true}
    #, is returned if moving the characters would have caused a
    #, character to be obstructed.  {false} is returned if there
    #, were no problems moving the characters.


procedure chunk_layer_insert@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
	name string
    returns logical

    #, {board_data} at ({x}, {y]).  {true} is returned if either
    #, {name} is not a known glyph name, or the glyph named {name}
    #, is already present at ({x}, {y}) in the same {layer}.  {true}
    #, is returned upon successful insertion of the glyph and {false}
    #, otherwise.


procedure chunk_layers_delete@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
    returns_nothing

    #, {layer} of {board_data} and delete them.


procedure clear@board_data
    takes
	board_data board_data
    returns_nothing

    #: This procudure will empty out {board_data}.


procedure columns_size_get@board_data
    takes
	board_data board_data
    returns unsigned

    #: Return the number of rows in {board_data}.  All this means is that
    #, at some point of time there was/is something at the returned row
    #, size (minus one).  It does not mean that there is something there
    #, now.


procedure create@board_data
    takes
	file_name string
	executable_directory string
	schematic_capture logical
	glyph_table glyph_table
	debug_stream out_stream
	error_stream out_stream
	timer timer
    returns board_data

    #: This procedure will create and return a {board_data} object.
    #, If {schematic_capture} is {true}, the returned board is
    #, used for schematic capture, otherwise it is used for printed circuit
    #, board layout.


procedure glyph_file_read@board_data
    takes
	board_data board_data
	inverted logical
    returns logical

    #: This procedure will read the glyph file for {board_data}
    #, and initialized some other tables in {board_data}.  If {inverted}
    #, is {true}, the character glyphs will be mirrored to support
    #, mirrored output files.


procedure line_draw@board_data
    takes
	board_data board_data
	layer layer
	x1 unsigned
	y1 unsigned
	x2 unsigned
	y2 unsigned
	thickness line_thickness
    returns logical

    #: This procedure will draw/erase/compliment a line of thickness
    #, {thickness} that starts at ({x1}, {y2}) to ({x2}, {y2}) on
    #, {layer} in {board_data}.  {true}@{logical} is, returned if
    #, any errors occur; otherwise, {false}@{logical} is returned.


procedure line_operation@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
	direction direction
	length unsigned
	thickness line_thickness
	operation line_operation
    returns_nothing

    #: This procedure will draw/erase/compliment a line of thickness
    #, {thickness} that starts at ({x}, {y}) on {layer} in {board_data}
    #, and goes in {direction} for {length} cells.  If {operation} is
    #, {set}, a line is drawn, if {operation} is {clear}, a line is erased,
    #, and if {operation} is {invert}, the line is inverted.


procedure rows_size_get@board_data
    takes
	board_data board_data
    returns unsigned

    #: Return the number of rows in {board_data}.  All this means is that
    #, at some point of time there was/is something at the returned row
    #, size (minus one).  It does not mean that there is something there
    #, now.


procedure character_select@board_data
    takes
	board_data board_data
	character character
    returns chunk

    #: This procedure will select the correct chunk to render
    #, {character} as.


#: {read_write_data} procedures:

procedure unsigned_parse_x@read_write_data
    takes
	read_write_data read_write_data
	line string
    returns unsigned

    #: This procedure will parse a number from the front of {string}.


procedure unsigned_parse_y@read_write_data
    takes
	read_write_data read_write_data
	line string
    returns unsigned

    #: This procedure will parse a number from the front of {string}.


procedure read@board_data
    takes
	board_data board_data
	in_stream in_stream
	file_name string
	inverted_image logical
	error_stream out_stream
	debug_stream out_stream
	timer timer
    returns logical

    #: This procedure will read in and return a {board_data} object
    #, from the previously opened {in_stream}.  Glyph information
    #, is entered into {glyph_table}.  If any errors occur, an error message
    #, is output to {error_stream} and ??@{board_data} is returned.  If
    #, {inverted_image} is {true}, the characters in each string are
    #, transposed to support the output of mirror images.


procedure read@board_data1[board_data]
    takes
	board_data board_data
	in_stream in_stream
	file_name string
	inverted_image logical
	error_stream out_stream
	debug_stream out_stream
	timer timer
    returns logical
    needs
	procedure chunk_layer_insert@board_data
	    takes board_data, layer, unsigned, unsigned, string
	    returns logical
	procedure characters_insert@board_data
	    takes board_data, layer,
	      unsigned, unsigned, logical, vector[unsigned]
	    returns logical
	procedure connection_insert@board_data
	    takes board_data, unsigned, unsigned, unsigned
	    returns logical
	procedure geometry_get@board_data
	    takes board_data
	    returns geometry
	procedure line_draw@board_data
	    takes board_data,
	      layer, unsigned, unsigned, unsigned, unsigned, line_thickness
	    returns logical
	procedure schematic_capture_set@board_data
	    takes board_data, logical
	    returns_nothing
	procedure via_name_insert@board_data
	    takes board_data, unsigned, unsigned, unsigned, string
	    returns logical
	procedure glyph_file_read@board_data
	    takes board_data, logical
	    returns logical

    #: This procedure read in information from {in_stream} and enter it
    #, into {board_data}.  {in_stream} has been previously opened.
    #, {error_stream}, {debug_stream}, and {timer} are used
    #, for error messages, debugging message, memory allocation, and
    #, performance tuning.  {true}@{logical} is returned if any fatal
    #, errors occur; otherwise, {false}@{logical} is returned.


procedure connection_insert@board_data
    takes
	board_data board_data
	x unsigned
	y unsigned
	hole_number unsigned
    returns logical

    #: This procedure will insert a connection/via at ({x}, {y}) with
    #, a hole number of {hole_number} into {board_data}.  {true}@{logical}
    #, is returned if there are any errors.


procedure via_name_delete@board_data
    takes
	board_data board_data
	x unsigned
	y unsigned
    returns_nothing

    #: This procedure will delete the named via at ({x}, {y}) in {board_data}.


procedure via_name_insert@board_data
    takes
	board_data board_data
	x unsigned
	y unsigned
	hole_number unsigned
	name string
    returns logical

    #: This procedure will insert {name} into a via at ({x}, {y})
    #, with a hole number of {hole_number} in {board_data}.  {true}
    #, is returned if an error occurs and {false} otherwise.  It is
    #, erroneous to assign a name to a cell that is not already a via.


procedure layer_parse@string
    takes
	line string
    returns layer

    #: This procedure will parse a layer from the from of {string}


procedure lop@string
    takes
	string string
    returns character

    #: This procedure will remove the first character from the beginning
    #, of {string}.


procedure characters_insert@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
	inverted_image logical
	characters vector[unsigned]
    returns logical

    #: This procedure will insert {characrters} into {board_data} at
    #, ({x},{y},{layer}).  If {inverted_image} is {true}, the characters
    #, will be transposed for support of mirror image output.


procedure unsigned_parse@string
    takes
	line string
    returns unsigned

    #: This procedure will parse a number from the front of {string}.


procedure integer_parse@string
    takes
	line string
    returns integer

    #: This procedure will parse a signed integer from the front of {string}.


procedure string_parse@string
    takes
	line string
    returns string

    #: This procedure will take the remainder of line and return a copy of it.


procedure space_skip@string
    takes
	line string
    returns_nothing

    #: This procedure will remove the space at the front of {line}.


procedure region_clear@board_data
    takes
	board_data board_data
	x_offset unsigned
	y_offset unsigned
	width unsigned
	height unsigned
    returns_nothing

    #: This procedure will clear the {width}+1 by {height}+1 region of cells
    #, in {board} starting at ({x_offset}, {y_offset}).


procedure region_edge_clear@board_data
    takes
	board_data board_data
	x_offset unsigned
	y_offset unsigned
	width unsigned
	height unsigned
    returns_nothing

    #: This procedure will clear the line segment edges of the {width}+1
    #, by {height}+1 region of cells in {board} starting at
    #, ({x_offset}, {y_offset}).


procedure region_copy@board_data
    takes
	from board_data
	from_x unsigned
	from_y unsigned
	to board_data
	to_x unsigned
	to_y unsigned
	width unsigned
	height unsigned
    returns_nothing

    #: This procedure will copy the {width}+1 by {height}+1 region of cells
    #, in {from} starting at ({from_x}, {from_y}) to the same size
    #, region of cells in {to} at ({to_x}, {to_y}).


procedure read_conditional@board_data
    takes
	board_data board_data
	file_name string
	inverted_image logical
	error_stream out_stream
	debug_stream out_stream
	timer timer
    returns logical

    #: This procedure will read in the contents of {file_name} into
    #, {board_data}, if {file_name} exists.  Otherwise, {board_data}
    #, is left empty.  If any errors occur, {true}@{logical} is returned,
    #, otherwise, {false}@{logical} is returned.  If {imverted_image}
    #, is {true}, the characters in each string will be transposed to
    #, support mirror image ouput.


procedure string_delete@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
    returns logical

    #: This procedure will delete the string at ({x}, {y}) in {layer} of
    #, {board_data}.  {true} is returned if no string is present to be
    #, deleted and {false} otherwise.


procedure string_extract@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
	name string
    returns logical

    #: This procedure will extract the string at ({x}, {y}) in {layer} of
    #, board and put it into {name}.  {true} is returned if a string is
    #, found and {false} otherwise.


procedure via_invert@board_data
    takes
	board_data board_data
	layer layer
	x unsigned
	y unsigned
    returns_nothing

    #: This procedure will add a via to {board_data} at ({x}, {y}) if the
    #, is none present, otherwise it will remove the via.  {layer} specifies
    #, which layer to look for the hole number on.  A via is plated
    #, through hole from one side of the printed circuit board to the other.


procedure write@board_data
    takes
	board_data board_data
	file_name string
	debug_mode logical
	cells_wide unsigned
	cells_high unsigned
	error_stream out_stream
    returns_nothing

    #: This procedure will write {board_data} to the file named {file_name}.
    #, The contents of the file are in an ASCII format so that it is human
    #, readable (editable.)  If {file_name} can not be opened, an error
    #, message will be output to {error_stream} and the file will be
    #, written to a file in the current directory named {file_name}.error.
    #, Each (x,y) coordinate is output relative to the previous coordinate
    #, in order to reduce the amount of changes recorded in the SCCS s.
    #, files when a block move is performed.


procedure create@read_write_data
    takes_nothing
    returns read_write_data

    #: This procedure will return a new {read_write_data} object.


# {geometry} routines:

procedure create@geometry
    takes_nothing
    returns geometry

    #: This routine will create and return a {geometry} object.


# Stand alone routines:

procedure has_pcb_suffix
    takes
	file_name string
    returns logical

    #: This procedure will return {true} if {file_name} has a suffix
    #, of {.pcb} and {false} otherwise.


procedure has_sc_suffix
    takes
	file_name string
    returns logical

    #: This procedure will return {true} if {file_name} has a suffix
    #, of {.sc} and {false} otherwise.