english
version "1.0"
identify "xyz"

#: 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 check

#: This module implement some code for laying out printed circuit boards
#, doing schematic capture.


procedure check
    takes
	executable_directory string
	file_names vector[string]
	glyph_table glyph_table
	wire_list_file string
	error_stream out_stream
	debug_stream out_stream
	timer timer
    returns logical

    #: This procedure will examine all of the files in {file_names}
    #, for any inconsistencies.  {true} is returned if any errors
    #, have occured.


procedure board_parts_power_extract
    takes
	board_parts vector[board_part]
	wire_list vector[vector[component_lead]]
    returns_nothing

    #: This procedure will extract all implied Vcc and Ground
    #, connections from {board_parts} and add them to {wire_list}.


procedure power_extract@board_part
    takes
	board_part board_part
	ground_wire vector[component_lead]
	vcc_wire vector[component_lead]
	junction junction
    returns_nothing

    #: This procedure will extract the implied Vcc and Ground wires
    #, from each {part_lead} in {part_leads} and add them to {ground_wire}
    #, or {vcc_wire} as appropriate.


procedure component_leads_check
    takes
	component_leads vector[component_lead]
	board_part_table table[string, board_part]
	error_stream out_stream
    returns logical

    #: This procedure will check {component_leads} for signal mismatches.

    #, exists and the signals are all compatible with one another.


procedure component_leads_duplicates
    takes
	component_leads vector[component_lead]
	component_leads_set set[component_lead]
	error_stream out_stream
    returns logical

    #: This procedure will check {component_leads} for signal mismatches.

    #, exists and the signals are all compatible with one another.


procedure wire_list_check
    takes
	wire_list vector[vector[component_lead]]
	board_part_table table[string, board_part]
	error_stream out_stream
    returns logical

    #: This procedure will check {wire_list} looking for signal type
    #, mismatches.


procedure wire_list_duplicates
    takes
	wire_list vector[vector[component_lead]]
	error_stream out_stream
    returns logical

    #: This procedure will check {wire_list} looking for duplicated
    #, component leads.  If any duplicates are found, an error message
    #, is output to {error_stream}, and {true} is returned, otherwise
    #, {false} is returned.


procedure wire_list_reduce
    takes
	wire_list vector[vector[component_lead]]
	error_stream out_stream
	debug_stream out_stream
    returns logical

    #: This procedure will merge together any wires in {wire_list} with
    #, the same name.  Any wires that are stand-alone are listed as error
    #, messages to {error_stream}.  If any errors are output, {true] is
    #, returned; otherwise, {false} is returned.


procedure component_leads_append
    takes
	to_component_leads vector[component_lead]
	from_component_leads vector[component_lead]
    returns_nothing

    #: This procedure will append the wires from {from_component_leads}
    #, to {to_component_leads} skipping over any wire names.


procedure wire_list_output
    takes
	wire_list vector[vector[component_lead]]
	out_stream out_stream
    returns_nothing

    #: This procedure will output {wire_list} to {out_stream}.


procedure component_leads_output
    takes
	component_leads vector[component_lead]
	out_stream out_stream
    returns_nothing

    #: This procedure will output {wire_list} to {out_stream}.


#: {component} routines:

procedure create@component
    takes
	diagram diagram
	name string
    returns component

    #: This procedure will create and return a new {component} object.


procedure leads_find@component
    takes
	component component
	x_minimum unsigned
	y_minimum unsigned
	x_maximum unsigned
	y_maximum unsigned
    	direction direction
    returns logical

    #: This procedure will find any component leads for {component} along
    #, the line segment starting from ({x_minimum}, {y_minimum}) to
    #, ({x_maximum}, {y_maximum}).  The line segment must be a vertical
    #, or horizontal line segment.  Wires on the {direction} side of the
    #, line segment are examined.


#: {component_lead} routines:

procedure compare@component_lead
    takes
	component_lead1 component_lead
	component_lead2 component_lead
    returns integer

    #: This will compare {component_lead1} to {component_lead2} and
    #, return -1, 0, 1 depending upon whether {component_lead1} is
    #, less than, equal to, or greater than {component_lead2}.


procedure create@component_lead
    takes
	component component
	junction junction
	name string
    returns component_lead

    #: This procedure will create and return a new {component_lead} object
    #, and containing {junction}, {component}, and {name}.


procedure equal@component_lead
    takes
	component_lead1 component_lead
	component_lead2 component_lead
    returns logical

    #: This procedure will return {true} if {component_lead1} equals
    #, {component_lead2} and {false} otherwise.


procedure hash@component_lead
    takes
	component_lead component_lead
    returns unsigned

    #: This procedure will return a hash value for {component_lead}.


procedure output@component_lead
    takes
	component_lead component_lead
	out_stream out_stream
    returns_nothing

    #: This procedure will output {component_lead} to {out_stream}.


procedure parts_lookup@component_lead
    takes
	component_lead component_lead
	board_part_table table[string, board_part]
    returns_nothing

    #: This procedure will lookup all of the board parts and part leads
    #, for {component_lead}.

    #else
    #	put@('Board part not found\n\', error_stream)



procedure wire_name@component_lead
    takes
	component_lead component_lead
    returns string
    #: This procedure will return the wire name for {component_lead}
    #, of the empty string, depending upon whether {component_lead} is
    #, a wire name or not.


#: {diagram_glyph} routines:

procedure leads_find@diagram_glyph
    takes
	diagram_glyph diagram_glyph
	component component
    returns logical

    #: This procedure will find any wires connected to leads associated
    #, with {diagram_glyph} and attach them to {component}.  {true} is
    #, returned if any errors are found, and {false} otherwise.


procedure name_find@diagram_glyph
    takes
	diagram_glyph diagram_glyph
	component component
	component_only logical
    returns logical

    #: This procedure will search for a component name around {diagram_glyph},
    #, mark it as used, insert it into {component} as its name and return
    #, {false}.  If {component_only} is {true}, a scan is made to see whether
    #, there is exactly one component name; if so, the component name is
    #, grabbed and {false} is returned.  If {component_only} is {false}
    #, and exactly one component name is *not* found, an error message is
    #, is generated and {true} is returned.


#: {diagram_text} routines:

procedure is_wire_label@diagram_text
    takes
	diagram_text diagram_text
	board_part_table table[string, board_part]
    returns logical

    #: This procedure will deterimine whether {diagram_text} is a wire label.
    #, {true} is returned if it is and {false} otherwise.


procedure wire_label_make@diagram_text
    takes
	diagram_text diagram_text
	point point
	board_part_table table[string, board_part]
    returns_nothing

    #: This procedure will create a wire label for {diagram_text} at {point}.


#: {junction} routines:

procedure create@junction
    takes
	diagram diagram
	point point
	junctions vector[junction]
    returns junction

    #: This procedure will create and return a new junction object
    #, in {diagram} and containing {point} {point} ust be immutable.
    #, The newly allocated {junction} object is appended to {junctions}.


procedure label_find@junction
    takes
	junction junction
	component component
	x1 unsigned
	y1 unsigned
	x2 unsigned
	y2 unsigned
    returns_nothing

    #: This procedure will search the cells from ({x1}, {y1}) to ({x2}, {y2})
    #, looking for a label for a glyph lead in {diagram}.  {x1} must be less
    #, than {x2} and {y1} must be less than {y2}.


#: {diagram} routines:

procedure component_boxes_extract@diagram
    takes
	diagram diagram
	board_part_table table[string, board_part]
    returns logical

    #: This procedure will extract the component boxes from {diagram}
    #, and store the result back into {diagram}.  {true} is returned
    #, if any errors occur and {false} otherwise.


procedure component_glyphs_extract@diagram
    takes
	diagram diagram
	board_part_table table[string, board_part]
    returns logical

    #: This procedure will extract the component glyphs from {diagram}
    #, and store the result back into {diagram}.  {true} is returned
    #, if any errors occur and {false} otherwise.


procedure components_extract@diagram
    takes
	diagram diagram
	board_part_table table[string, board_part]
    returns logical

    #: This procedure will extract the component boxes and glyphs from
    #, {diagram} and store the result back into {diagram}.  {true} is
    #, returned if any errors occur and {false} otherwise.


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

    #: This procedure will insert the chunk named {name} into {diagram} at
    #, ({x}, {y}) in {layer}.  {false}@{logical} is returned if any errors
    #, occur; otherwise, {true@{logical} is returned.  (This is insconsistent
    #, with the other routines.)


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

    #: This procedure will insert {characters} into {diagram} at ({x}, {y})
    #, in {layer}.  {true}@{logical} is returned if any errors occur;
    #, otherwise, {false}@{logical} is returned.


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

    #: This procedure will insert a via/connection into {diagram}
    #, at ({x}, {y]) with a hole number of {hole_number}.
    #,  {true}@{logical} is returned if any errors occur;
    #, otherwise, {false}@{lobical} is returned.


procedure glyph_file_read@diagram
    takes
	file_name string
	inverted logical
    returns logical

    #: This procedure is a place holder needed for {read}@{board_data1}.
    #, {false} is returned to indicate no errors have occured.  Both
    #, arguments are ignored.


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

    #: This procedure will insert a via named {name} at ({x}, {y}) with
    #, a hole number of {hole_number} in {diagram}.


procedure create@diagram
    takes
	file_name string
	glyph_table glyph_table
	error_stream out_stream
	debug_stream out_stream
    returns diagram

    #: This procedure creates and returns a new {diagram} object
    #, that has been initialized to contain {file_name},
    #, {glyph_table}, {error_stream}, and {debug_stream}.


procedure junction_lookup@diagram
    takes
	diagram diagram
	x unsigned
	y unsigned
	junctions vector[junction]
	table table[point, junction]    
    returns junction

    #: This procedure will lookup the junction associated with the point
    #, ({x}, {y}) in {table}.  If no such {junction} exists, a new junction
    #, will be created, inserted into {table}, and appended to {junctions}.
    #, {diagram} is used to provide a temporary lookup {point} object, as
    #, well as it is needed in any newly created {junction} object.


procedure labels_wrapup@diagram
    takes
	diagram diagram
	board_part_table table[string, board_part]
    returns logical

    #: This procedure will iterate through all of the unused labels
    #, in {diagram} and either cause the label to be attached to 
    #, an unterminate wire or report the label as unsued.  {true}
    #, is returned if any errors are reported and {false} otherwise.


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

    #: This procedure will insert a line between ({x1}, {y1}) to ({x2}, {y2})
    #, {layer} of {diagram} with a line of thickness {line_thickness}.  
    #, {true}@{logical} is returned if any errors occur; otherwise,
    #, {false}@{lobical} is returned.


procedure unterminated_wires_find@diagram
    takes
	diagram diagram
    returns logical


procedure vias_label@diagram
    takes
	diagram diagram
	board_part_table table[string, board_part]
	error_stream out_stream
    returns logical

    #: This procedure will find all of the component leads in diagram
    #, and label the appropriate vias.


procedure wire_list_extract@diagram
    takes
	diagram diagram
	wire_list vector[vector[component_lead]]
	layer layer
    returns_nothing

    #: This procedure will extract the wire list from {diagram} and
    #, append it to {wire_list}.


procedure meshes_extract@diagram
    takes
	diagram diagram
	layer layer
	text string
	double_sided logical
    returns_nothing

    #: This procedure will visit each wire on {layer} and figure out which
    #, ones are connected to one another.  Each group of connected wires
    #, will be inserted into a {mesh} object.  The list of {mesh} objects
    #, is stored back in {diagram}.  If {double_sided} is {true}, vias
    #, that go through the board will be spanned as well.


procedure meshes_show@diagram
    takes
	diagram diagram
	layer layer
	text string
    returns_nothing

    #: This procedure will output {meshes} to {out_stream} with a
    #, label of {text}.


#: {mesh} routines:

procedure bounds_update@mesh
    takes
	mesh mesh
	point point
    returns_nothing

    #: This procedure will update the bounding box information in {mesh}
    #, to include {point}.


procedure component_leads_extract@mesh
    takes
	mesh mesh
	debug_stream out_stream
    returns vector[component_lead]

    #: This procedure will return the component leads list associated
    #, with {mesh}.

    #, it will get duplicated in the list.  We just cull out duplicates
    #, here:


procedure component_leads_show
    takes
	component_leads vector[component_lead]
	debug_stream out_stream
    returns_nothing

    #: This procedure will show {component_leads} with a label of {text}
    #, output to {debug_stream}.


procedure create@mesh
    takes
	diagram diagram
	wire wire
    returns mesh

    #: This procedure will create and return a new {mesh} object
    #, that contains {diagram} and {wire}.


procedure old_component_leads_aextract@mesh
    takes
	mesh mesh
	component_leads vector[component_lead]
	out_stream out_stream
    returns_nothing

    #: This procedure will output each component lead in {mesh} to
    #, {out_stream}.  {component_leads} is a temporary vector of
    #, component leads.


procedure expand@mesh
    takes
	mesh mesh
	wires vector[wire]
	main_table table[point, junction]
	other_table table[point, junction]
	indent string
    returns_nothing

    #: This procedure will recursively add each wire in {wires} to {mesh}
    #, if it is not already in {mesh}.  {main_table} and {other_table}
    #, are the tables used to look up wires for double sided boards.

    #put@("]", debug_stream)

    #trim@(indent, indent_size)



procedure has_line@mesh
    takes
	mesh mesh
	x1 unsigned
	y1 unsigned
	x2 unsigned
	y2 unsigned
	table table[point, junction]
    returns logical

    #: This procedure will return {true}@{logical} if {mesh} as a
    #, connected sequence of wires/lines that form a straight vertical
    #, or horizontal line connecting ({x1}, {y1}) to ({x2}, {y2}).
    #, This routine requires that {x1} <= {x2} and {y1} <= {y2}.

    #, that connect ({x1}, {y1}) to ({x2}, {y2}) in a straight line:

procedure is_enclosed_box@mesh
    takes
	mesh mesh
	table table[point, junction]
    returns logical

    #: This procedure will return {true}@{logical} if there is a box of
    #, wires/lines around all of the wires in {mesh} and {false}@{logical}
    #, otherwise.


procedure show@mesh
    takes
	mesh mesh
	out_stream out_stream
    returns_nothing

    #: This procedure will output the contents of {mesh} to {out_stream}.


procedure wire_insert@mesh
    takes
	mesh mesh
	wire wire
    returns_nothing

    #: This procedure will insert {wire} into {mesh}.

    #debug_stream :@= mesh.diagram.debug_stream
    #format@format1[address](debug_stream,
    #   "\t\wire_insert@mesh: address:%X% ", mesh.address)
    #show@(wire, debug_stream)
    #put@("\n\", debug_stream)



#: {point} routines:

procedure create@point
    takes
	x unsigned
	y unsigned
    returns point

    #: This procedure will create and return a new {point} object
    #, containing the coordinate ({x}, {y}).


#: {wire} routines:

procedure create@wire
    takes
	wires vector[wire]
	junction1 junction
	junction2 junction
    returns wire

    #: This procedure will create and return a wire consisting of {junction1}
    #, and {junction2}.


procedure show@wire
    takes
	wire wire
	out_stream out_stream
    returns_nothing

    #: This procedure will output {wire} to {out_stream} without any
    #, preceeding or following whitespace.