# 4. Attributes

{des4:0} An attribute is a tuple of:

- key
- value
- priority
- source information

{des4:1} The "Attributes of an Object" (AoO) is a flat map (hash table) of zero or more attributes. Attribute keys within the AoO are unique. There is no particular limit on the size of the AoO.

## 4.1. Attribute keys

{des4:2} Key is always a 7-bit ASCII string no longer than 510 characters, containing only characters between decimal 33 and 126.

{des4:3} As a convention the slash ('/') character can be used as a "path separator", emulating semantic hierarchy in the flat AoO list, with the leading '/' for root omitted. Cschem itself and most plugins will ignore such pseudo-hierarchy, and will handle slash without side effects. Nevertheless GUI implementations may present attributes as a tree and attribute conventions will use the pseudo-hierarchy to group attributes. If the first character of the key is with - or +, that alters attribute merging during compilation.. This is called attribute prefixing (the prefix is part of the key, e.g. when string comparing the key).

## 4.2. Attribute values

{des4:4} Each attribute has only one atomic value. The value can be changed (replaced) and interpreted as a whole. The value is one of: empty, scalar or array.

{des4:5} An attribute with an empty value should behave the same way as if the attribute was not present. The reason to have an explicit empty value is to provide a way to keep track on the compile-history of attributes.

{des4:6} A scalar value is a 7-bit ASCII string of arbitrary lengths, containing only characters between decimal 32 and 126, tab (\t) and newline (\n). The interpretation of the value should be detailed in the specification of the given attribute.

{des4:7} An array value is a one-dimensional, contiguous (free of holes or missing items), ordered list of values. Array members are indexed with positive integers starting from 0. Index values can be represented on at most 31 bits, which also means the largest array may not have more than 231 values.

{des4:8} The format and interpretation of array values are the same as of the scalar values. The interpretation of array indices is also attribute-specific.

## 4.3. Attribute priority

{des4:9} Each attribute has an unsigned 15 bit integer priority. Highest priority is value 0, lowest priority is value 215-1.

{des4:10} Whenever an attribute is going to be overwritten, the write action should carry a priority. The write succeeds only if its priority value is lower or equal to the the priority of the attribute in the target AoO. When a write fails, the compile-history of the attribute is still updated with the failed entry.

{des4:11} For most code priority values are arbitrary integers to compare. However, cschem as a whole have conventions on how priority values are allocated and assigned:

from | to | description
0 | 0 | Priority 0 shall be used for "hardwired" items the user shall not be able to change.
1 | 100 | user, high tier for group_ref instance
101 | 200 | user, high tier for group_ref original
201 | 300 | user, normal for group_ref instance
301 | 400 | user, normal for group_ref original
401 | 500 | user, low tier for group_ref instance
501 | 600 | user, low tier for group_ref original
1001 | 10000 | plugin, high tier
11001 | 20000 | plugin, normal
21001 | 30000 | plugin, low tier
31001 | 31100 | user, lowest tier

{des4:12} Default user priority shall be 250: middle of normal user priority for instances.

{des4:13} Plugins that modify attributes shall use priority values between 1001 and 30000. These values should be assigned by the view , as a range of priority values for each plugin the view refers to. Each plugin should get three ranges, each range should be of 10 values; one from the high tier, one from the normal and one from the low tier section. E.g. a plugin may get the priority number ranges 1041-1050, 11041-11050 and 21041-21050.

{des4:14} Plugin ranges shall not overlap with other ranges. There should be an empty 10 value range between every two plugin ranges so that the user can use priority values in between plugins.

## 4.4. Attribute source

{des4:15} After the concrete model is compiled into the abstract model , each attributes of the abstract model has a compilation-history that describes how the final value of that specific attribute was affected by different sources of information. The complete compilation-history is stored in the source field, as an array (as specified below).

{des4:17} Attributes of abstract objects start with an empty compilation-history. Each successful write shall append and entry to the source array in the following format:

    	prio::type::source::description

{des4:18} where prio is the new priority, source is the identifier of the information source and description is a short, free form text in which the source describes the reason for the change.

{des4:16}{des4:19} Type and sources are specified in the following format:

- a concrete attribute loaded from a file has "c" in type and the source shall be in filename,line,col format (,col is optional); description shall be empty
- an abstract attribute coming from the concrete model has "ac" in type and the source shall be in filename,oid-path,attr-key format; description shall be empty
- type is "pc" for an attribute generated by plugins from a concrete attribute, source is filename,oid-path,attr-key,plugin-name
- type is "pa" for an attribute generated by plugins from an abstract attribute, source is oid-path,attr-key,plugin-name
- an attribute generated by plugins without attribute source has "p" in type and the source the plugin-name
- (if multiple sources were used by a plugin, it needs to pick one main source and use one of the above three forms)
- if external tools modify the abstract model, the type shall be "e", and source shall be the name of the tool
- if the write failed a dash ("-") is appended to the type.

## 4.5. Attribute compilation process

{des4:51} First, all attributes of all concrete objects are copied into attributes of the abstract objects they contribute to. There are three ways the copy may happen depending on the first character of the concrete object attribute key:

- starting with minus (-) sign: attribute is not copied to the abstract object
- starting with a plus (+) sign: if attribute value is an array, values are appended on merge if there's an attribute collision (the plus prefix is removed from the key in the abstract object attribute)
- in any other case: user-user attribute collision is an error

### 4.5.1. Plugin invocation

{des4:20} Plugins are invoked in the order specified by the current view. The view also specifies a range of priorities the invoked plugin may use. Plugins that are invoked later shall have higher priority (lower integer priority value).

{des4:21} This means plugins invoked later can use, as input, attributes produced by plugins invoked earlier.

{des4:22} The same plugin can be present in the same view multiple times, but the view is a linear list, there are no loops. This means attribute-overwrite-loops can not form. (Such a loop would be two plugins A and B, A writing an attribute that is then input of B which writes another attribute that is input for A which then produces a new version of the attribute.)

{des4:23} Because of the unique priorities mandated by the view, it is also impossible that two plugins would attempt overwrite the same attribute with the same priority.

### 4.5.2. Collision handling

{des4:24} A collision is when the same attribute is written twice with the same priority. There are only two ways attribute collision may happen:

- user-user collision: the same attribute of an abstract object is derived from two or more concrete objects at the same priority (exception: with "-" prefix when the attribute is not copied/merged at all or array attribute keyed with the "+" prefix, when the list is appended)
- plugin-plugin collision: the same attribute of an abstract object is written twice by the same plugin

{des4:25} The collision does not happen if the values are the same; in this case the second write is silently ignored.

{des4:26} An user-user collision is an error; the compilation fails and the user shall be notified. Typical example is a "slotted" abstract component that is built of two concrete symbols; if the user specifies e.g. the "footprint" attribute in both symbols at the same priority but with different value, cschem has no chance to decide which value to use in the final "footprint" attribute of the abstract component. The user should resolve it by:

- removing attributes so that only one symbol of the component specifies the "footprint"
- raising the priority of the attribute in one of the related symbols
- editing attributes in all related symbols to have the same value

{des4:27} A plugin-plugin collision is not an error: the same plugin may decide to overwrite the value of a specific attribute at the same priority. Since both values are written by the same plugin in the same session, the value written later will silently replace the value written earlier. The source array is appended with the new write; examining the source field will reveal the multiple writes.

## 4.6. User edits and UI presentation

{des4:28} The empty value shall be displayed explicitly; it should be distinguishable from a scalar value with an empty string, a scalar value with a string containing white spaces only and an array value with zero elements.

{des4:29} An array value shall be displayed explicitly; it should be distinguishable from any valid text value. An empty array is a legal construct that needs to be displayed in a way the user recognizes it and can add items in it.

{des4:30} Setting an attribute to the empty value and removing the attribute from the concrete object's AoO are two different operations that should both be available. The first is used as a "strong remove", or "override-remove": the user may specify the attribute with a high priority empty value to make sure no plugin or group_ref "inheritance" can create it. The second, attribute removal, is the "weak remove", which only removes the attribute from the current AoO, leaving room for plugins to re-create it for the abstract model.

{des4:31} The user should be able to specify arbitrary priority value for any attribute the user may edit - the priority attribute may even be in a range not marked as "user". Typical use cases with group_ref:

- in group_ref: attribute priority in the "user low tier instance" range: "use this attribute if the library version doesn't have one"
- in group_ref: attribute priority in the "user lowest tier" range: "use this attribute if plugins did not set it"
- in group: "high tier original" attribute: "prefer this even if the group_ref had a different idea at normal priority" (should be used sparingly)
- in sheet, group_ref or atomic objects: knowing the plugin priorities set in the view config, a value higher than of a specific plugin's can be a fallback that says: "use this value if the first N plugins didn't fill in anything, but still don't let later plugins overwrite it"

### 4.6.1. Concrete objects: atoms, groups and sheet

{des4:32} Sheet, the drawing primitive group and drawing primitives of type atoms have a singe AoO. The primary view of such an AoO should include the attribute key, the attribute value and the user specified priority. It may be useful to make the source field accessible.

### 4.6.2. Concrete objects: group_refs

{des4:33} A group_ref has two sets of AoO: the original AoO as specified in the referenced group and the instance AoO, that is specific to this group_ref object. Attribute priority values on the original AoO are increased by 100.

{des4:34} When the group_ref object is made an input for an abstract object, the two AoOs are merged and the resulting list is passed a single AoO.

{des4:35} The user interface should present the two AoOs separately and let the user edit the instance AoO. If the user interface permits edition of the original AoO, it should make it clear that this will potentially affect other group_ref objects as well ("editing the library").

{des4:36} The user interface should present the merge result of the two AoOs. A practical way to achieve this is not to present 3 AoOs (original, instance, merged) but to present the original and the merged; when the user edits the merged AoO, that should affect the instance AoO.

### 4.6.3. Abstract objects

{des4:37} When the user is editing the attributes of any concrete object, there is always zero or one abstract object that is potentially affected. It may be useful to compile the design and display the resulting abstract object and its AoO after each attribute modification. The abstract object's AoO shall be read-only, as the user can modify it only indirectly, by making modifications to an attribute of a concrete object.

{des4:38} If the abstract object's AoO is displayed, the full list of concrete objects that contributed to the abstract object should also be listed, preferably as a clickable cross-reference.

## 4.7. Typical scalar attribute value formats

{des4:39} The following conventions are documented to shorten plugin and attribute specifications. Any attribute specification can chose one of these value types/formats or can introduce its own. Formats specified in this section have a "cschem-" prefix in their name to make it easier to reference them from the plugin/attribute specification. Only the most commonly used formats are specified here.

{des4:40} Since the type/format shall be mandated by the attribute, there is no explicit type/format indication stored with the attribute.

{des4:41} All of these formats specify scalar values and can be used as a member in an "array-of-" construct.

### 4.7.1. cschem-string

{des4:42} Plain text string. Free form. May include &unicode; characters but implementations may not have support for displaying unicode. There is no restriction on the length of the value. May contain newlines.

### 4.7.2. cschem-integer

{des4:43} Unitless integer value, specified in decimal or in hex with a 0x prefix. The absolute value shall not be larger than 231-1. The value string may start with a single '+' or '-' character to indicate the sign or the value; the rest of the characters must be digits (between '0' and '9').

### 4.7.2. cschem-number

{des4:44} Unitless floating point value, specified in decimal format. Implementations shall convert and store the value at least with ieee754 double precision.

{des4:45} May have an optional sign, and can be specified in one of the following forms:

- integer: -522, +522, 42., 001
- decimal: -522.91, +522.31, 42.0000, 001.00700
- exponent: -5.2291e+2, +5.2231E+02, 4.200000e+1

### 4.7.3. cschem-value

{des4:46} A cschem-number followed by a unit. There may be zero or more whitepsace between the two. The unit is a case sensitive series of letters ('a'..'z', 'A'..'Z', including '&unicode;') or a single dash ('-'). If the unit is omitted or is a dash, the value is unitless. Unicode support is optional.

### 4.7.4. cschem-uid

{des4:47} An UID value stored as text. Useful for referencing other objects within the design.

### 4.7.5. cschem-symlink

{des4:48} The value is a reference to the value of another attribute. By default the symlink is followed, and the value of the attribute the symlink points (the deref'd value) to is returned whenever the attribute value is accessed by any code, unless the code explicit requests to avoid dereferencing. (Typically a GUI will display both the symlink value and the deref'd value and lets the symlink value be edited.)

{des4:49} The syntax of the the symlink value is objectpath::key, where objectpath is one of the following:

syntax | meaning
--- | ---
. | another attribute of the same object
.. | an attribute of the parent group
role | an attribute of the closest parent group with role attribute matching role, walking up the tree of group
sheet | an attribute of the current schematics sheet

{des4:50} .. and role can be combined to form a path (e.g. a full reference could be symbol/..::pcb/footprint).