If the contours() loop member is called without a second parameter, it loops through all of the contour wires, regardless whether they belong to a positive or a negative polygon. If you are interested in getting the positive and negative contour wires separately, you can call contours() with an additional integer parameter (see the second example below). The sign of that parameter determines whether a positive or a negative polygon will be handled, and the value indicates the index of that polygon. If there is no polygon with the given index, the statement will not be executed. Another advantage of this method is that you don't need to determine the beginning and end of a particular polygon yourself (by comparing coordinates). For any given index, the statement will be executed for all the wires of that polygon. With the second parameter 0 the behavior is the same as without a second parameter.
The wires looped through by contours() always start with a positive polygon. To find out where one partial polygon ends and the next one begins, simply store the (x1,y1) coordinates of the first wire and check them against (x2,y2) of every following wire. As soon as these are equal, the last wire of a partial polygon has been found. It is also guaranteed that the second point (x2,y2) of one wire is identical to the first point (x1,y1) of the next wire in that partial polygon.
To find out where the "inside" and the "outside" of the polygon lays, take any contour wire and imagine looking from its point (x1,y1) to (x2,y2). The "inside" of the polygon is always on the right side of the wire. Note that if you simply want to draw the polygon you won't need all these details.
board(B) { B.signals(S) { S.polygons(P) { int x0, y0, first = 1; P.contours(W) { if (first) { // a new partial polygon is starting x0 = W.x1; y0 = W.y1; } // ... // do something with the wire // ... if (first) first = 0; else if (W.x2 == x0 && W.y2 == y0) { // this was the last wire of the partial polygon, // so the next wire (if any) will be the first wire // of the next partial polygon first = 1; } } } } }
board(B) { B.signals(S) { S.polygons(P) { // handle only the "positive" polygons: int i = 1; int active; do { active = 0; P.contours(W, i) { active = 1; // do something with the wire } i++; } while (active); } } }
| border | int (MODULE_BORDER_...) | |
| bus | string (see note) | |
| direction | int (PIN_DIRECTION_... (see note)) | |
| name | string (PORT_NAME_LENGTH) | |
| net | string (see note) | |
| x, y | int (connection point) |
| nets() | UL_NET (see note) | |
| texts() | UL_TEXT | |
| wires() | UL_WIRE |
| MODULE_BORDER_BOTTOM | at bottom border of module | |
| MODULE_BORDER_RIGHT | at right border of module | |
| MODULE_BORDER_TOP | at top border of module | |
| MODULE_BORDER_LEFT | at left border of module | |
| PORT_NAME_LENGTH | max. recommended length of a port name (used in formatted output only) |
The bus and the net data members return the name of the bus or net to which this port is connected to (only available in a UL_MODULEINST context). Additionally the nets loop member loops through all available nets of this connection.
schematic(SCH) { SCH.modules(M) { M.ports(P) printf("Port: %s\n", P.name); } }
| moduleinst | UL_MODULEINST | |
| port | UL_PORT |
schematic(SCH) { SCH.sheets(SH) { printf("Sheet: %d\n", SH.number); SH.nets(N) { printf("\tNet: %s\n", N.name); N.segments(SEG) { SEG.portrefs(P) { printf("\tconnected to: %s, %s\n", P.moduleinst.name, P.port.name); } } } } }
| angle | real (0.0...359.9) | |
| layer | int | |
| x1, y1 | int (lower left corner) | |
| x2, y2 | int (upper right corner) |
The coordinates (x1 y1) and (x2 y2) are always referring to the initial orientation of the rectangle regardless of the angle.
angle defines how many degrees the rectangle is rotated counterclockwise around its center. The center coordinates are given by (x1+x2)/2 and (y1+y2)/2.
board(B) { B.rectangles(R) { printf("Rectangle: (%f %f), (%f %f)\n", u2mm(R.x1), u2mm(R.y1), u2mm(R.x2), u2mm(R.y2)); } }
| alwaysvectorfont | int (ALWAYS_VECTOR_FONT_..., see note) | |
| description | string | |
| grid | UL_GRID | |
| headline | string | |
| name | string (see note) | |
| verticaltext | int (VERTICAL_TEXT_...) | |
| xreflabel | string | |
| xrefpart | string |
| allparts() | UL_PART (see note) | |
| attributes() | UL_ATTRIBUTE (see note) | |
| classes() | UL_CLASS | |
| layers() | UL_LAYER | |
| libraries() | UL_LIBRARY | |
| modules() | UL_MODULE | |
| nets() | UL_NET | |
| parts() | UL_PART | |
| sheets() | UL_SHEET | |
| variantdefs() | UL_VARIANTDEF |
| ALWAYS_VECTOR_FONT_GUI | alwaysvectorfont is set in the user interface dialog | |
| ALWAYS_VECTOR_FONT_PERSISTENT | alwaysvectorfont is set persistent in this schematic |
| VERTICAL_TEXT_UP | reading direction for vertical texts: up | |
| VERTICAL_TEXT_DOWN | reading direction for vertical texts: down |
if (sch.alwaysvectorfont) { // alwaysvectorfont is set in general } if (sch.alwaysvectorfont & ALWAYS_VECTOR_FONT_GUI) { // alwaysvectorfont is set in the user interface }The name member returns the full file name, including the directory.
The xreflabel and xrefpart members return the format strings used to display cross-reference labels and part cross-references.
The allparts() loop member loops through the parts() of the schematic itself and through the hierarchical parts generated by module instances.
The attributes() loop member loops through the global attributes.
schematic(S) { S.parts(P) printf("Part: %s\n", P.name); }
| junctions() | UL_JUNCTION (see note) | |
| labels() | UL_LABEL | |
| pinrefs() | UL_PINREF (see note) | |
| portrefs() | UL_PORTREF | |
| texts() | UL_TEXT (deprecated, see note) | |
| wires() | UL_WIRE |
The texts() loop member was used in older EAGLE versions to loop through the labels of a segment, and is only present for compatibility. It will not deliver the text of cross-reference labels at the correct position. Use the labels() loop member to access a segment's labels.
schematic(SCH) { SCH.sheets(SH) { printf("Sheet: %d\n", SH.number); SH.nets(N) { printf("\tNet: %s\n", N.name); N.segments(SEG) { SEG.pinrefs(P) { printf("connected to: %s, %s, %s\n", P.part.name, P.instance.name, P.pin.name); } } } } }
| area | UL_AREA | |
| description | string | |
| headline | string | |
| number | int |
| busses() | UL_BUS | |
| circles() | UL_CIRCLE | |
| dimensions() | UL_DIMENSION | |
| frames() | UL_FRAME | |
| instances() | UL_INSTANCE | |
| moduleinsts() | UL_MODULEINST | |
| nets() | UL_NET | |
| polygons() | UL_POLYGON | |
| rectangles() | UL_RECTANGLE | |
| texts() | UL_TEXT | |
| wires() | UL_WIRE |
schematic(SCH) { SCH.sheets(S) { printf("Sheet: %d\n", S.number); } }
| airwireshidden | int | |
| class | UL_CLASS | |
| name | string (SIGNAL_NAME_LENGTH) |
| contactrefs() | UL_CONTACTREF | |
| polygons() | UL_POLYGON | |
| vias() | UL_VIA | |
| wires() | UL_WIRE |
| SIGNAL_NAME_LENGTH | max. recommended length of a signal name (used in formatted output only) |
board(B) { B.signals(S) printf("Signal: %s\n", S.name); }
| angle | real (0.0...359.9) | |
| dx[layer], dy[layer] | int (size) | |
| flags | int (SMD_FLAG_...) | |
| layer | int (see note) | |
| name | string (SMD_NAME_LENGTH) | |
| roundness | int (see note) | |
| signal | string | |
| x, y | int (center point, see note) |
| SMD_FLAG_STOP | generate stop mask | |
| SMD_FLAG_THERMALS | generate thermals | |
| SMD_FLAG_CREAM | generate cream mask |
| SMD_NAME_LENGTH | max. recommended length of an smd name (same as CONTACT_NAME_LENGTH) |
angle defines how many degrees the smd is rotated counterclockwise around its center.
The value returned by flags must be masked with the SMD_FLAG_... constants to determine the individual flag settings, as in
if (smd.flags & SMD_FLAG_STOP) { ... }Note that if your ULP just wants to draw the objects, you don't need to check these flags explicitly. The dx[] and dy[] members will return the proper data; for instance, if SMD_FLAG_STOP is set, dx[LAYER_TSTOP] will return 0, which should result in nothing being drawn in that layer. The flags member is mainly for ULPs that want to create script files that create library objects.
library(L) { L.packages(PAC) { PAC.contacts(C) { if (C.smd) printf("Smd: '%s', (%f %f), dx=%f, dy=%f\n", C.name, u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.dx), u2mm(C.smd.dy)); } } }
| area | UL_AREA | |
| description | string | |
| headline | string | |
| library | string | |
| name | string (SYMBOL_NAME_LENGTH) |
| circles() | UL_CIRCLE | |
| dimensions() | UL_DIMENSION | |
| frames() | UL_FRAME | |
| rectangles() | UL_RECTANGLE | |
| pins() | UL_PIN | |
| polygons() | UL_POLYGON | |
| texts() | UL_TEXT (see note) | |
| wires() | UL_WIRE |
| SYMBOL_NAME_LENGTH | max. recommended length of a symbol name (used in formatted output only) |
library(L) { L.symbols(S) printf("Sym: %s\n", S.name); }
| align | int (ALIGN_...) | |
| angle | real (0.0...359.9) | |
| font | int (FONT_...) | |
| layer | int | |
| linedistance | int | |
| mirror | int | |
| ratio | int | |
| size | int | |
| spin | int | |
| value | string | |
| x, y | int (origin point) |
| wires() | UL_WIRE (see note) |
| FONT_VECTOR | vector font | |
| FONT_PROPORTIONAL | proportional font | |
| FONT_FIXED | fixed font |
| ALIGN_BOTTOM_LEFT | bottom/left aligned | |
| ALIGN_BOTTOM_CENTER | bottom/center aligned | |
| ALIGN_BOTTOM_RIGHT | bottom/right aligned | |
| ALIGN_CENTER_LEFT | center/left aligned | |
| ALIGN_CENTER | centered | |
| ALIGN_CENTER_RIGHT | center/right aligned | |
| ALIGN_TOP_LEFT | top/left aligned | |
| ALIGN_TOP_CENTER | top/center aligned | |
| ALIGN_TOP_RIGHT | top/right aligned |
If the UL_TEXT is derived from a UL_ELEMENT or UL_INSTANCE context, the member values will be those of the actual text as located in the board or sheet drawing.
board(B) { B.texts(T) { printf("Text: %s\n", T.value); } }
| name | string |
schematic(SCH) { SCH.variantdefs(VD) { printf("Variant: '%s'\n", VD.name); } }
| populate | int (0=do not populate, 1=populate) | |
| value | string | |
| technology | string | |
| variantdef | UL_VARIANTDEF |
schematic(SCH) { SCH.parts(P) { P.variants(V) { printf("%s: %spopulate\n", V.variantdef.name, V.populate ? "" : "do not "); } } }
| diameter[layer] | int | |
| drill | int | |
| drillsymbol | int | |
| end | int | |
| flags | int (VIA_FLAG_...) | |
| shape[layer] | int (VIA_SHAPE_...) | |
| start | int | |
| x, y | int (center point) |
| VIA_FLAG_STOP | always generate stop mask |
| VIA_SHAPE_SQUARE | square | |
| VIA_SHAPE_ROUND | round | |
| VIA_SHAPE_OCTAGON | octagon |
Note that diameter and shape will always return the diameter or shape that a via would have in the given layer, even if that particular via doesn't cover that layer (or if that layer isn't used in the layer setup at all).
start and end return the layer numbers in which that via starts and ends. The value of start will always be less than that of end.
drillsymbol returns the number of the drill symbol that has been assigned to this drill diameter (see the manual for a list of defined drill symbols). A value of 0 means that no symbol has been assigned to this drill diameter.
board(B) { B.signals(S) { S.vias(V) { printf("Via: (%f %f)\n", u2mm(V.x), u2mm(V.y)); } } }
| arc | UL_ARC | |
| cap | int (CAP_...) | |
| curve | real | |
| layer | int | |
| style | int (WIRE_STYLE_...) | |
| width | int | |
| x1, y1 | int (starting point) | |
| x2, y2 | int (end point) |
| pieces() | UL_WIRE (see note) |
| CAP_FLAT | flat arc ends | |
| CAP_ROUND | round arc ends | |
| WIRE_STYLE_CONTINUOUS | continuous | |
| WIRE_STYLE_LONGDASH | long dash | |
| WIRE_STYLE_SHORTDASH | short dash | |
| WIRE_STYLE_DASHDOT | dash dot |
The cap parameter only has a meaning for actual arcs, and will always return CAP_ROUND for a straight wire.
Whether or not an UL_WIRE is an arc can be determined by checking the boolean return value of the arc data member. If it returns 0, we have a straight wire, otherwise an arc. If arc returns a non-zero value it may be further dereferenced to access the UL_ARC specific parameters start and end angle, radius and center point. Note that you may only need these additional parameters if you are going to draw the arc or process it in other ways where the actual shape is important.
board(B) { B.wires(W) { printf("Wire: (%f %f) (%f %f)\n", u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2)); } }
There are three kinds of definitions:
The scope of a constant or variable definition goes from the line in which it has been defined to the end of the current block, or to the end of the User Language Program, if the definition appeared outside any block.
The scope of a function definition goes from the closing
brace (}) of the function body to the end of the User Language
Program.
Constants may also be initialized to specific values, like
Constant Definitions
Constants are defined using the keyword enum, as in
enum { a, b, c };
which would define the three constants a, b and c,
giving them the values 0, 1 and 2, respectively.
enum { a, b = 5, c };
where a would be 0, b would be 5 and
c would be 6.
Variable Definitions
The general syntax of a variable definition is
[numeric] type identifier [= initializer][, ...];
where type is one of the
data or
object types,
identifier is the name of the variable, and initializer
is a optional initial value.
Multiple variable definitions of the same type are separated by commas (,).
If identifier is followed by a pair of brackets ([]), this defines an array of variables of the given type. The size of an array is automatically adjusted at runtime.
The optional keyword numeric can be used with string arrays to have them sorted alphanumerically by the sort() function.
By default (if no initializer is present), data variables are set to 0 (or "", in case of a string), and object variables are "invalid".
| int i; | defines an int variable named i | |
| string s = "Hello"; | defines a string variable named s and initializes it to "Hello" | |
| real a, b = 1.0, c; | defines three real variables named a, b and c, initializing b to the value 1.0 | |
| int n[] = { 1, 2, 3 }; | defines an array of int, initializing the first three elements to 1, 2 and 3 | |
| numeric string names[]; | defines a string array that can be sorted alphanumerically | |
| UL_WIRE w; | defines a UL_WIRE object named w |
UL_SIGNAL signals[]; ... UL_SIGNAL s = signals[0]; printf("%s", s.name);
The general syntax of a function definition is
type identifier(parameters) { statements }where type is one of the data or object types, identifier is the name of the function, parameters is a list of comma separated parameter definitions, and statements is a sequence of statements.
Functions that do not return a value have the type void.
A function must be defined before it can be called, and function calls can not be recursive (a function cannot call itself).
The statements in the function body may modify the values of the parameters, but this will not have any effect on the arguments of the function call.
Execution of a function can be terminated by the return statement. Without any return statement the function body is executed until it's closing brace (}).
A call to the exit() function will terminate the entire User Language Program.
Command line arguments are available to the program through the global Builtin Variables argc and argv.
int CountDots(string s) { int dots = 0; for (int i = 0; s[i]; ++i) if (s[i] == '.') ++dots; return dots; } string dotted = "This.has.dots..."; output("test") { printf("Number of dots: %d\n", CountDots(dotted)); }
| Unary | ! ~ + - ++ -- | |
| Multiplicative | * / % | |
| Additive | + - | |
| Shift | << >> | |
| Relational | < <= > >= | |
| Equality | == != | |
| Bitwise AND | & | |
| Bitwise XOR | ^ | |
| Bitwise OR | | | |
| Logical AND | && | |
| Logical OR | || | |
| Conditional | ?: | |
| Assignment | = *= /= %= += -= &= ^= |= <<= >>= | |
| Comma | , |
Associativity is left to right for all operators, except for Unary, Conditional and Assignment, which are right to left associative.
The normal operator precedence can be altered by the use of
parentheses.
Bitwise Operators
Bitwise operators work only with data types
char and
int.
| Unary | ||
| ~ | Bitwise (1's) complement | |
| Binary | ||
| << | Shift left | |
| >> | Shift right | |
| & | Bitwise AND | |
| ^ | Bitwise XOR | |
| | | Bitwise OR | |
| Assignment | ||
| &= | Assign bitwise AND | |
| ^= | Assign bitwise XOR | |
| |= | Assign bitwise OR | |
| <<= | Assign left shift | |
| >>= | Assign right shift |
| Unary | ||
| ! | Logical NOT | |
| Binary | ||
| && | Logical AND | |
| || | Logical OR |
Using a string expression with a logical operator checks whether the string is empty.
Using an Object Type with a logical
operator checks whether that object contains valid data.
Comparison Operators
Comparison operators work with expressions
of any data type,
except Object Types.
| < | Less than | |
| <= | Less than or equal to | |
| > | Greater than | |
| >= | Greater than or equal to | |
| == | Equal to | |
| != | Not equal to |
| ?: | Conditional | |
| , | Comma |
The Conditional operator is used to make a decision within an expression, as in
int a; // ...code that calculates 'a' string s = a ? "True" : "False";which is basically the same as
int a; string s; // ...code that calculates 'a' if (a) s = "True"; else s = "False";but the advantage of the conditional operator is that it can be used in an expression.
The Comma operator is used to evaluate a sequence of expressions from left to right, using the type and value of the right operand as the result.
Note that arguments in a function call as well as multiple variable declarations
also use commas as delimiters, but in that case this is not a
comma operator!
Arithmetic Operators
Arithmetic operators work with data types
char,
int and
real
(except for ++, --, % and %=).
| Unary | ||
| + | Unary plus | |
| - | Unary minus | |
| ++ | Pre- or postincrement | |
| -- | Pre- or postdecrement | |
| Binary | ||
| * | Multiply | |
| / | Divide | |
| % | Remainder (modulus) | |
| + | Binary plus | |
| - | Binary minus | |
| Assignment | ||
| = | Simple assignment | |
| *= | Assign product | |
| /= | Assign quotient | |
| %= | Assign remainder (modulus) | |
| += | Assign sum | |
| -= | Assign difference |
See also String Operators
String Operators
String operators work with data types
char,
int and
string.
The left operand must always be of type
string.
| Binary | ||
| + | Concatenation | |
| Assignment | ||
| = | Simple assignment | |
| += | Append to string |
The + operator concatenates two strings, or adds a character to the end of a string and returns the resulting string.
The += operator appends a string or a character to the end of a given string.
See also Arithmetic Operators
Expressions
An expression can be one of the following:
Expressions can be grouped using parentheses,
and may be recursive, meaning that an expression can consist of
subexpressions.
Arithmetic Expression
An arithmetic expression is any combination of numeric
operands and an arithmetic operator or a
bitwise operator.
a + b c++ m << 1
a = x + 42 b += c s = "Hello"
s + ".brd" t + 'x'
Comma expressions are evaluated left to right, and the result of a comma expression is the type and value of the rightmost expression.
i++, j++, k++
int a; // ...code that calculates 'a' string s = a ? "True" : "False";
int p = strchr(s, 'b');
Compound statements can be nested to any depth.
Expression Statement
An expression statement is any
expression followed by a
semicolon.
An expression statement is executed by evaluating the expression. All side effects of this evaluation are completed before the next statement is executed. Most expression statements are assignments or function calls.
A special case is the empty statement, consisting of only a
semicolon.
An empty statement does nothing, but it may be useful in situations
where the ULP syntax expects a statement but your program does not
need one.
Iteration statements are
Control Statements
Control statements are used to control the program flow.
do...while
for
while
Selection statements are
if...else
switch
Jump statements are
break
continue
return
break
The break statement has the general syntax
break;
and immediately terminates the nearest enclosing
do...while,
for,
switch or
while
statement.
This also applies to loop members of object types.
Since all of these statements can be intermixed and nested to any
depth, take care to ensure that your break exits from the
correct statement.
continue
The continue statement has the general syntax
continue;
and immediately transfers control to the test condition of the
nearest enclosing
do...while,
while, or
for statement, or to the increment expression
of the nearest enclosing
for
statement.
Since all of these statements can be intermixed and nested to any
depth, take care to ensure that your continue affects the
correct statement.
The condition is tested after the first
execution of statement, which means that the statement is
always executed at least one time.
If there is no
break or
return
inside the statement, the statement must affect
the value of the condition, or condition itself must
change during evaluation in order to avoid an endless loop.
The initializing expression init normally initializes one or more
loop counters. It may also define a new variable as a loop counter.
The scope of such a variable is valid until the end of the active block.
An else clause is always matched to the last encountered if
without an else. If this is not what you want, you need to use
braces to group the statements, as in
do...while
The do...while statement has the general syntax
do statement while (condition);
and executes the statement until the condition
expression becomes zero.
Example
string s = "Trust no one!";
int i = -1;
do {
++i;
} while (s[i]);
for
The for statement has the general syntax
for ([init]; [test]; [inc]) statement
and performs the following steps:
If there is no
break or
return
inside the statement, the inc expression (or the
statement) must affect
the value of the test expression, or test itself must
change during evaluation in order to avoid an endless loop.
Example
string s = "Trust no one!";
int sum = 0;
for (int i = 0; s[i]; ++i)
sum += s[i]; // sums up the characters in s
if...else
The if...else statement has the general syntax
if (expression)
t_statement
[else
f_statement]
The conditional expression is evaluated, and if its value is nonzero
the t_statement is executed. Otherwise the f_statement is
executed in case there is an else clause.
if (a == 1) {
if (b == 1)
printf("a == 1 and b == 1\n");
}
else
printf("a != 1\n");
return
A function with a return type
other than void must contain at least one return
statement with the syntax
return expression;where expression must evaluate to a type that is compatible with the function's return type. The value of expression is the value returned by the function.
If the function is of type void, a return statement
without an expression can be used to return from the function
call.
Any case_statement can be labeled by one or more case
labels. The case_exp of each case label must evaluate
to a constant integer which is unique within it's enclosing switch
statement.
There can also be at most one default label.
After evaluating sw_exp, the case_exp are checked for
a match. If a match is found, control passes to the case_statement
with the matching case label.
If no match is found and there is a default label, control
passes to def_statement. Otherwise none of the statements in the
switch is executed.
Program execution is not affected when case and default
labels are encountered. Control simply passes through the labels to the
following statement.
To stop execution at the end of a group of statements for a particular
case, use the break statement.
The condition is tested before the first possible
execution of statement, which means that the statement may never
be executed if condition is initially zero.
If there is no
break or
return
inside the statement, the statement must affect
the value of the condition, or condition itself must
change during evaluation in order to avoid an endless loop.
Many of the object types have their
own Constants section which lists the builtin constants for that
particular object (see e.g. UL_PIN).
The following builtin constants are defined in addition to the ones
listed for the various object types:
switch
The switch statement has the general syntax
switch (sw_exp) {
case case_exp: case_statement
...
[default: def_statement]
}
and allows for the transfer of control to one of several
case-labeled statements, depending on the value of
sw_exp (which must be of integral type).
Example
string s = "Hello World";
int vowels = 0, others = 0;
for (int i = 0; s[i]; ++i)
switch (toupper(s[i])) {
case 'A':
case 'E':
case 'I':
case 'O':
case 'U': ++vowels;
break;
default: ++others;
}
printf("There are %d vowels in '%s'\n", vowels, s);
while
The while statement has the general syntax
while (condition) statement
and executes the statement as long as the condition
expression is not zero.
Example
string s = "Trust no one!";
int i = 0;
while (s[i])
++i;
Builtins
Builtins are Constants, Variables, Functions and Statements
that provide additional information and allow for data manipulations.
Builtin Constants
Builtin constants are used to provide information about
object parameters, such as maximum recommended name length, flags etc.
| EAGLE_VERSION | EAGLE program version number (int) | |
| EAGLE_RELEASE | EAGLE program release number (int) | |
| EAGLE_SIGNATURE | a string containing EAGLE program name, version and copyright information | |
| EAGLE_PATH | a string containing the complete path of the EAGLE executable | |
| EAGLE_DIR | a string containing the directory of the EAGLE installation ($EAGLEDIR) | |
| EAGLE_HOME | a string containing the user's home directory when starting EAGLE ($HOME) | |
| OS_SIGNATURE | a string containing a signature of the operating system (e.g. Mac..., Windows... or Linux) | |
| REAL_EPSILON | the minimum positive real number such that 1.0 + REAL_EPSILON != 1.0 | |
| REAL_MAX | the largest possible real value | |
| REAL_MIN | the smallest possible (positive!) real value the smallest representable number is -REAL_MAX | |
| INT_MAX | the largest possible int value | |
| INT_MIN | the smallest possible int value | |
| PI | the value of "pi" (3.14..., real) | |
| usage | a string containing the text from the #usage directive |
These builtin constants contain the directory paths defined in the directories dialog, with any of the special variables ($HOME and $EAGLEDIR) replaced by their actual values. Since each path can consist of several directories, these constants are string arrays with an individual directory in each member. The first empty member marks the end of the path:
| path_lbr[] | Libraries | |
| path_dru[] | Design Rules | |
| path_ulp[] | User Language Programs | |
| path_scr[] | Scripts | |
| path_cam[] | CAM Jobs | |
| path_epf[] | Projects |
When using these constants to build a full file name, you need to use a directory separator, as in
string s = path_lbr[0] + '/' + "mylib.lbr";
The libraries that are currently in use through the USE command:
| used_libraries[] |
| int argc | number of arguments given to the RUN command | |
| string argv[] | arguments given to the RUN command (argv[0] is the full ULP file name) |
You may also write your own functions and use them to structure your User Language Program.
The builtin functions are grouped into the following categories:
The following character functions are available:
| isalnum | letters (A to Z or a to z) or digits (0 to 9) | |
| isalpha | letters (A to Z or a to z) | |
| iscntrl | delete characters or ordinary control characters (0x7F or 0x00 to 0x1F) | |
| isdigit | digits (0 to 9) | |
| isgraph | printing characters (except space) | |
| islower | lowercase letters (a to z) | |
| isprint | printing characters (0x20 to 0x7E) | |
| ispunct | punctuation characters (iscntrl or isspace) | |
| isspace | space, tab, carriage return, new line, vertical tab, or formfeed (0x09 to 0x0D, 0x20) | |
| isupper | uppercase letters (A to Z) | |
| isxdigit | hex digits (0 to 9, A to F, a to f) |
char c = 'A'; if (isxdigit(c)) printf("%c is hex\n", c); else printf("%c is not hex\n", c);
The following file handling functions are available:
See output() for information about how to write into a file.fileerror checks the status of any I/O operations that have been performed since the last call to this function and returns 0 if everything was ok. If any of the I/O operations has caused an error, a value other than 0 will be returned.
You should call fileerror before any I/O operations to reset any previous error state, and call it again after the I/O operations to see if they were successful.
When fileerror returns a value other than 0 (thus indicating an error) a proper error message has already been given to the user.
fileerror(); output("file.txt", "wt") { printf("Test\n"); } if (fileerror()) exit(1);
fileglob performs a directory search using pattern.
pattern may contain '*' and '?' as wildcard characters. If pattern ends with a '/', the contents of the given directory will be returned.
Names in the resulting array that end with a '/' are directory names.
The array is sorted alphabetically, with the directories coming first.
The special entries '.' and '..' (for the current and parent directories) are never returned in the array.
If pattern doesn't match, or if you don't have permission to search the given directory, the resulting array will be empty.
|
The directory delimiter in the array is always a forward slash.
This makes sure User Language Programs will work platform independently.
In the pattern the backslash ('\') is also treated
as a directory delimiter.
Sorting filenames under Windows is done case insensitively. |
string a[]; int n = fileglob(a, "*.brd");
if (board) board(B) { output(filesetext(B.name, ".out")) { ... } }
board(B) printf("Board: %s\nSize: %d\nTime: %s\n", B.name, filesize(B.name), t2string(filetime(B.name)));
The following file input is available:
See output() for information about how to write into a file.If dest is a character array, the file will be read as raw binary data and the return value reflects the number of bytes read into the character array (which is equal to the file size).
If dest is a string array, the file will be read as a text file (one line per array member) and the return value will be the number of lines read into the string array. Newline characters will be stripped.
If dest is a string, the entire file will be read into that string and the return value will be the length of that string (which is not necessarily equal to the file size, if the operating system stores text files with "cr/lf" instead of a "newline" character).
char b[]; int nBytes = fileread(b, "data.bin"); string lines[]; int nLines = fileread(lines, "data.txt"); string text; int nChars = fileread(text, "data.txt");
The following mathematical functions are available:
real x = -1.0; real r = sqrt(2 * x);will lead to the error message
Invalid argument in call to 'sqrt(-2)'
The return type of these functions is the same as the (larger) type of the arguments. type must be one of char, int or real.
real x = 2.567, y = 3.14; printf("The maximum is %f\n", max(x, y));
real x = 2.567; printf("The rounded value of %f is %f\n", x, round(x));
| PI | the value of "pi" (3.14...) |
real x = PI / 2; printf("The sine of %f is %f\n", x, sin(x));
real x = 2.1; printf("The square root of %f is %f\n", x, sqrt(x)); printf("The 3rd root of %f is %f\n", x, pow(x, 1.0/3));
The following miscellaneous functions are available:
The cfgset function sets the parameter with the given name to the given value.
The valid characters for name are
'A'-'Z',
'a'-'z',
'0'-'9',
'.' and
'_'.
Parameter names are case sensitive.
The parameters are stored in the user's eaglerc file. To ensure that different User Language Programs don't overwrite each other's parameters in case they use the same parameter names, it is recommended to put the name of the ULP at the beginning of the parameter name. For example, a ULP named mytool.ulp that uses a parameter named MyParam could store that parameter under the name
mytool.MyParamBecause the configuration parameters are stored in the eaglerc file, which also contains all of EAGLE's other user specific parameters, it is also possible to access the EAGLE parameters with cfgget() and cfgset(). In order to make sure no ULP parameters collide with any EAGLE parameters, the EAGLE parameters must be prefixed with "EAGLE:", as in
EAGLE:Option.XrefLabelFormatNote that there is no documentation of all of EAGLE's internal parameters and how they are stored in the eaglerc file. Also, be very careful when changing any of these parameters! As with the eaglerc file itself, you should only manipulate these parameters if you know what you are doing! Some EAGLE parameters may require a restart of EAGLE for changes to take effect.
In the eaglerc file the User Language parameters are stored with the prefix "ULP:". Therefore this prefix may be optionally put in front of User Language parameter names, as in
ULP:mytool.MyParam
string MyParam = cfgget("mytool.MyParam", "SomeDefault"); MyParam = "OtherValue"; cfgset("mytool.MyParam", MyParam);
dlgMessageBox("Your country code is: " + country());
The exit function terminates execution of a User Language Program.
If an integer result is given it will be used as the
return value of the program.
If a string command is given, that command will be executed as if it
were entered into the command line immediately after the RUN command. In that
case the return value of the ULP is set to EXIT_SUCCESS.
| EXIT_SUCCESS | return value for successful program execution (value 0) | |
| EXIT_FAILURE | return value for failed program execution (value -1) |
fdlsignature()
The fdlsignature function is used to calculate a digital signature
when accessing Premier Farnell's Design Link interface.
language()
See also country
The language function can be used to make a ULP use different message string, depending on which language the current system is using.
In the example below all the strings used in the ULP are listed in the string array I18N[], preceeded by a string containing the various language codes supported by this ULP. Note the vtab characters used to separate the individual parts of each string (they are important for the lookup function) and the use of the commas to separate the strings. The actual work is done in the function tr(), which returns the translated version of the given string. If the original string can't be found in the I18N array, or there is no translation for the current language, the original string will be used untranslated.
The first language defined in the I18N array must be the one in which the strings used throughout the ULP are written, and should generally be English in order to make the program accessible to the largest number of users.
string I18N[] = { "en\v" "de\v" "it\v" , "I18N Demo\v" "Beispiel für Internationalisierung\v" "Esempio per internazionalizzazione\v" , "Hello world!\v" "Hallo Welt!\v" "Ciao mondo!\v" , "+Ok\v" "+Ok\v" "+Approvazione\v" , "-Cancel\v" "-Abbrechen\v" "-Annullamento\v" }; int Language = strstr(I18N[0], language()) / 3; string tr(string s) { string t = lookup(I18N, s, Language, '\v'); return t ? t : s; } dlgDialog(tr("I18N Demo")) { dlgHBoxLayout dlgSpacing(350); dlgLabel(tr("Hello world!")); dlgHBoxLayout { dlgPushButton(tr("+Ok")) dlgAccept(); dlgPushButton(tr("-Cancel")) dlgReject(); } };
An array that can be used with lookup() consists of strings of text, each string representing one data record.
Each data record contains an arbitrary number of fields, which are separated by the character separator (default is '\t', the tabulator). The first field in a record is used as the key and is numbered 0.
All records must have unique key fields and none of the key fields may be empty - otherwise it is undefined which record will be found.
If the first string in the array contains a "Header" record (i.e. a record where
each field describes its contents), using lookup with a field_name
string automatically determines the index of that field. This allows using the
lookup function without exactly knowing which field index contains
the desired data.
It is up to the user to make sure that the first record actually
contains header information.
If the key parameter in the call to lookup() is an empty string, the first string of the array will be used. This allows a program to determine whether there is a header record with the required field names.
If a field contains the separator character, that field must be enclosed
in double quotes (as in "abc;def", assuming the semicolon (';')
is used as separator). The same applies if the field contains double quotes
("), in which case the double quotes inside the field have to be doubled
(as in "abc;""def"";ghi", which would be abc;"def";ghi).
It is best to use the default "tab" separator, which doesn't have these problems
(no field can contain a tabulator).
Here's an example data file (';' has been used as separator for better readability):
Name;Manufacturer;Code;Price 7400;Intel;I-01-234-97;$0.10 68HC12;Motorola;M68HC1201234;$3.50
string OrderCodes[]; if (fileread(OrderCodes, "ordercodes") > 0) { if (lookup(OrderCodes, "", "Code", ';')) { schematic(SCH) { SCH.parts(P) { string OrderCode; // both following statements do exactly the same: OrderCode = lookup(OrderCodes, P.device.name, "Code", ';'); OrderCode = lookup(OrderCodes, P.device.name, 2, ';'); } } } else dlgMessageBox("Missing 'Code' field in file 'ordercodes'); }
The special value -1 for index makes the function return the type of the palette that is currently in use by the editor window.
If either index or type is out of range, an error message will be given and the ULP will be terminated.
| PALETTE_TYPES | the number of palette types (3) | |
| PALETTE_BLACK | the black background palette (0) | |
| PALETTE_WHITE | the white background palette (1) | |
| PALETTE_COLORED | the colored background palette (2) | |
| PALETTE_ENTRIES | the number of colors per palette (64) |
The sleep function delays the execution of an ULP program for number
of seconds.
In any case, the number argument defines the number of items in the
array(s).
Note the use of the keyword numeric in the string arrays. This causes
the strings to be sorted in a way that takes into account a numeric part
at the end of the strings, which leads to IC1, IC2,... IC9, IC10 instead of
the alphabetical order IC1, IC10, IC2,...IC9.
When sorting a set of arrays, the first (index) array must be of type
int and need not be initialized. Any
contents the index array might have before calling the sort
function will be overwritten by the resulting index values.
The status function displays the given message in the status bar of the
editor window in which the ULP is running.
sort()
The sort function either directly sorts a given array1,
or it sorts a set of arrays (starting with array2), in which case
array1 is supposed to be an array of int, which will
be used as a pointer array.
Sorting a single array
If the sort function is called with one single array, that array
will be sorted directly, as in the following example:
string A[];
int n = 0;
A[n++] = "World";
A[n++] = "Hello";
A[n++] = "The truth is out there...";
sort(n, A);
for (int i = 0; i < n; ++i)
printf(A[i]);
Sorting a set of arrays
If the sort function is called with more than one array, the first
array must be an array of int, while all of the other arrays may be
of any array type and hold the data to be sorted. The following example
illustrates how the first array will be used as a pointer:
numeric string Nets[], Parts[], Instances[], Pins[];
int n = 0;
int index[];
schematic(S) {
S.nets(N) N.pinrefs(P) {
Nets[n] = N.name;
Parts[n] = P.part.name;
Instances[n] = P.instance.name;
Pins[n] = P.pin.name;
++n;
}
sort(n, index, Nets, Parts, Instances, Pins);
for (int i = 0; i < n; ++i)
printf("%-8s %-8s %-8s %-8s\n",
Nets[index[i]], Parts[index[i]],
Instances[index[i]], Pins[index[i]]);
}
The idea behind this is that one net can have several pins connected to it,
and in a netlist you might want to have the net names sorted, and within
one net you also want the part names sorted and so on.
status()
See also dlgMessageBox()
system()
The system function executes the external program given by the command
string, and waits until the program ends.
Input/Output redirection
If the external program shall read its standard input from (or write its standard
output to) a particular file, input/output needs to be redirected.
On Linux and Mac OS X this is done by simply adding a '<' or
'>' to the command line, followed by the desired file name, as in
system("program < infile > outfile");which runs program and makes it read from infile and write to outfile. |
On Windows you have to explicitly run a command processor to do this, as in
system("cmd.exe /c program < infile > outfile");(on DOS based Windows systems use command.com instead of cmd.exe). |
If an external program runs for a longer time, and you want the system
call to return immediately, without waiting for the program to end, you
can simply add an '&' to the command string under Linux and
Mac OS X, as in
system("program &"); |
Under Windows you need to explicitly run a command processor to do this, as in
system("cmd.exe /c start program");(on DOS based Windows systems use command.com instead of cmd.exe). |
int result = system("simulate -f filename");This would call a simulation program, giving it a file which the ULP has just created. Note that simulate here is just an example, it is not part of the EAGLE package!
If you want to have control over what system commands are actually executed, you can write a wrapper function that prompts the user for confirmation before executing the command, like
int MySystem(string command) { if (dlgMessageBox("!Ok to execute the following command?<p><tt>" + command + "</tt>", "&Yes", "&No") == 0) return system(command); return -1; } int result = MySystem("simulate -f filename");
EAGLE stores all coordinate and size values as int values with a resolution of 1/320000mm (0.003125µ). The above unit conversion functions can be used to convert these internal units to the desired measurement units, and vice versa.
board(B) { B.elements(E) { printf("%s at (%f, %f)\n", E.name, u2mm(E.x), u2mm(E.y)); } }
The following network functions are available:
The neterror function should be called after any of the other network functions has returned a negative value, indicating that an error has occurred. The return value of neterror is a textual string that can be presented to the user.
For errors related to SSL connections (HTTPS) also consider the note in netget.
string Result; if (netget(Result, "http://www.cadsoft.de/cgi-bin/http-test?see=me&hear=them") >= 0) { // process Result } else dlgMessageBox(neterror());
The netget function sends the given url to the network and
stores the result in the dest variable.
If no network activity has occurred for timeout seconds,
the connection will be terminated. The default timeout is 20 seconds.
The url must contain the protocol to use (HTTP, HTTPS or FTP) and can
contain name=value pairs of parameters, as in
http://www.cadsoft.de/cgi-bin/http-test?see=me&hear=them ftp://ftp.cadsoft.de/eagle/userfiles/READMEIf a user id and password is required to access a remote site, these can be given as
<EMAIL_ADDRESS>dest is a character array, the result will be treated as raw binary data and the return value reflects the number of bytes stored in the character array.
If dest is a string array, the result will be treated as text data (one line per array member) and the return value will be the number of lines stored in the string array. Newline characters will be stripped.
If dest is a string, the result will be stored in that string and the return value will be the length of the string. Note that in case of binary data the result is truncated at the first occurrence of a byte with the value 0x00.
If you need to use a proxy to access the Internet with HTTP or HTTPS, you can set that up in the "Configure" dialog under "Help/Check for Update" in the Control Panel.
string Result; if (netget(Result, "http://www.cadsoft.de/cgi-bin/http-test?see=me&hear=them") >= 0) { // process Result } else dlgMessageBox(neterror());
The netpost function sends the given data to the given url
on the network and stores the result in the dest variable.
If no network activity has occurred for timeout seconds,
the connection will be terminated. The default timeout is 20 seconds.
If content_type is given, it overwrites the default content type
of "text/html; charset=utf-8".
The url must contain the protocol to use (HTTP or HTTPS).
If a user id and password is required to access a remote site, these can be given as
<EMAIL_ADDRESS>dest is a character array, the result will be treated as raw binary data and the return value reflects the number of bytes stored in the character array.
If dest is a string array, the result will be treated as text data (one line per array member) and the return value will be the number of lines stored in the string array. Newline characters will be stripped.
If dest is a string, the result will be stored in that string and the return value will be the length of the string. Note that in case of binary data the result is truncated at the first occurrence of a byte with the value 0x00.
If you need to use a proxy to access the Internet with HTTP or HTTPS, you can set that up in the "Configure" dialog under "Help/Check for Update" in the Control Panel.
If you should face problems related to SSL connections (HTTPS) consider the note in netget.
string Data = "see=me\nhear=them"; string Result; if (netpost(Result, "http://www.cadsoft.de/cgi-bin/http-test", Data) >= 0) { // process Result } else dlgMessageBox(neterror());
The following printing functions are available:
In case of an error, printf returns -1.
The format string contains two types of objects - plain characters and format specifiers:
% [flags] [width] [.prec] type
Each format specification begins with the percent character (%). After the % comes the following, in this order:
| d | signed decimal int | |
| o | unsigned octal int | |
| u | unsigned decimal int | |
| x | unsigned hexadecimal int (with a, b,...) | |
| X | unsigned hexadecimal int (with A, B,...) | |
| f | signed real value of the form [-]dddd.dddd | |
| e | signed real value of the form [-]d.dddde[±]ddd | |
| E | same as e, but with E for exponent | |
| g | signed real value in either e or f form, based on given value and precision | |
| G | same as g, but with E for exponent if e format used | |
| c | single character | |
| s | character string | |
| % | the % character is printed |
| "-" | the formatted item is left-justified within the field; normally, items are right-justified | |
| "+" | a signed, positive item will always start with a plus character (+); normally, only negative items begin with a sign | |
| " " | a signed, positive item will always start with a space character; if both "+" and " " are specified, "+" overrides " " |
Width is specified either directly, through a decimal digit string, or indirectly, through an asterisk (*). If you use an asterisk for the width specifier, the preceding argument (which must be an int) to the one being formatted (with this format specifier) determines the minimum output field width.
In no case does a nonexistent or small field width cause truncation of a field. If the result of a conversion is wider than the field width, the field is simply expanded to contain the conversion result.
| n | At least n characters are printed. If the output value has less than n characters, the output is padded with blanks (right-padded if "-" flag given, left-padded otherwise). | |
| 0n | At least n characters are printed. If the output value has less than n characters, it is filled on the left with zeros. | |
| * | The argument list supplies the width specifier, which must precede the actual argument being formatted. |
| none | Precision set to default. | |
| .0 | For int types, precision is set to default; for real types, no decimal point is printed. | |
| .n | n characters or n decimal places are printed. If the output value has more than n characters the output might be truncated or rounded (depending on the type character). | |
| * | The argument list supplies the precision specifier, which must precede the actual argument being formatted. |
| douxX | 1 | |
| eEf | 6 | |
| gG | all significant digits | |
| c | no effect | |
| s | print entire string |
| douxX | .n specifies that at least n characters are printed. If the input argument has less than n digits, the output value is left-padded with zeros. If the input argument has more than n digits, the output value is not truncated. | |
| eEf | .n specifies that n characters are printed after the decimal point, and the last digit printed is rounded. | |
| gG | .n specifies that at most n significant digits are printed. | |
| c | .n has no effect on the output. | |
| s | .n specifies that no more than n characters are printed. |
char c = 0x00; printf("%c", c);
int i = 42; real r = 3.14; char c = 'A'; string s = "Hello"; printf("Integer: %8d\n", i); printf("Hex: %8X\n", i); printf("Real: %8f\n", r); printf("Char: %-8c\n", c); printf("String: %-8s\n", s);
In case of an error, sprintf returns -1.
string result; int number = 42; sprintf(result, "The number is %d", number);
The following string functions are available:
If index is given, the search starts at that position. Negative values are counted from the end of the string.
string s = "This is a string"; char c = 'a'; int pos = strchr(s, c); if (pos >= 0) printf("The character %c is at position %d\n", c, pos); else printf("The character was not found\n");
strjoin joins all entries in array, delimited by the given separator and returns the resulting string.
If separator is the newline character ('\n') the resulting string will be terminated with a newline character. This is done to have a text file that consists of N lines (each of which is terminated with a newline) and is read in with the fileread() function and split into an array of N strings to be joined to the original string as read from the file.
string a[] = { "Field 1", "Field 2", "Field 3" }; string s = strjoin(a, ':');
string s = "This is a string"; int l = strlen(s); printf("The string is %d characters long\n", l);
string s = "This Is A String"; string r = strlwr(s); printf("Prior to strlwr: %s - after strlwr: %s\n", s, r);
If index is given, the search starts at that position. Negative values are counted from the end of the string.
string s = "This is a string"; char c = 'a'; int pos = strrchr(s, c); if (pos >= 0) printf("The character %c is at position %d\n", c, pos); else printf("The character was not found\n");
If index is given, the search starts at that position. Negative values are counted from the end of the string.
string s1 = "This is a string", s2 = "is a"; int pos = strrstr(s1, s2); if (pos >= 0) printf("The substring starts at %d\n", pos); else printf("The substring was not found\n");
strsplit splits the string s at the given separator and stores the resulting fields in the array.
If separator is the newline character ('\n') the last field will be silently dropped if it is empty. This is done to have a text file that consists of N lines (each of which is terminated with a newline) and is read in with the fileread() function to be split into an array of N strings. With any other separator an empty field at the end of the string will count, so "a:b:c:" will result in 4 fields, the last of which is empty.
string a[]; int n = strsplit(a, "Field 1:Field 2:Field 3", ':');
If index is given, the search starts at that position. Negative values are counted from the end of the string.
string s1 = "This is a string", s2 = "is a"; int pos = strstr(s1, s2); if (pos >= 0) printf("The substring starts at %d\n", pos); else printf("The substring was not found\n");
The value for length must be positive, otherwise an empty string will be returned. If length is ommitted, the rest of the string (beginning at start) is returned.
If start points to a position outside the string, an empty string is returned.
string s = "This is a string"; string t = strsub(s, 4, 7); printf("The extracted substring is: %s\n", t);
string s = "3.1415"; real r = strtod(s); printf("The value is %f\n", r);
string s = "1234"; int i = strtol(s); printf("The value is %d\n", i);
string s = "This Is A String"; string r = strupr(s); printf("Prior to strupr: %s - after strupr: %s\n", s, r);
If index is given, the search starts at that position. Negative values are counted from the end of the string.
If length is given, the actual length of the matching substring is returned in that variable.
Regular expressions allow you to find a pattern within a text string.
For instance, the regular expression "i.*a" would find a sequence of characters
that starts with an 'i', followed by any character ('.') any number of times ('*'),
and ends with an 'a'. It would match on "is a" as well as "is this a" or "ia".
Details on regular expressions can be found, for instance, in the book
Mastering Regular Expressions by Jeffrey E. F. Friedl.
string s1 = "This is a string", s2 = "i.*a"; int len = 0; int pos = strxstr(s1, s2, 0, len); if (pos >= 0) printf("The substring starts at %d and is %d charcaters long\n", pos, len); else printf("The substring was not found\n");
The following time functions are available:
int CurrentTime = time();
After 86400000 milliseconds (i.e. every 24 hours), the value starts at 0 again.
int elapsed = timems();
The t2string function without the optional format parameter converts the given time t into a country specific string in local time.
If t2string is called with a format string, that format is used to determine what the result should look like.
The following expressions can be used in a format string:
| d | the day as a number without a leading zero (1 to 31) | |
| dd | the day as a number with a leading zero (01 to 31) | |
| ddd | the abbreviated localized day name (e.g. "Mon" to "Sun") | |
| dddd | the long localized day name (e.g. "Monday" to "Sunday") | |
| M | the month as a number without a leading zero (1-12) | |
| MM | the month as a number with a leading zero (01-12) | |
| MMM | the abbreviated localized month name (e.g. "Jan" to "Dec") | |
| MMMM | the long localized month name (e.g. "January" to "December") | |
| yy | the year as a two digit number (00-99) | |
| yyyy | the year as a four digit number | |
| h | the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display) | |
| hh | the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display) | |
| m | the minute without a leading zero (0 to 59) | |
| mm | the minute with a leading zero (00 to 59) | |
| s | the second without a leading zero (0 to 59) | |
| ss | the second with a leading zero (00 to 59) | |
| z | the milliseconds without leading zeros (always 0, since the given time only has a one second resolution) | |
| zzz | the milliseconds with leading zeros (always 000, since the given time only has a one second resolution) | |
| AP | use AM/PM display (AP will be replaced by either "AM" or "PM") | |
| ap | use am/pm display (ap will be replaced by either "am" or "pm") | |
| U | display the given time as UTC (must be the first character; default is local time) |
All other characters will be copied "as is". Any sequence of characters that are enclosed in singlequotes will be treated as text and not be used as an expression. Two consecutive single quotes ('') are replaced by a single quote in the output.
int t = time(); printf("It is now %02d:%02d:%02d\n", t2hour(t), t2minute(t), t2second(t)); printf("ISO time is %s\n", t2string(t, "Uyyyy-MM-dd hh:mm:ss"));
The following object functions are available:
The clrgroup() function clears the group flags of the given object, so that it is no longer part of the previously defined group.
When applied to an object that contains other objects (like a UL_BOARD or UL_NET) the group flags of all contained objects are cleared recursively, but with analogous limitations like for setgroup().
board(B) { B.elements(E) clrgroup(E); }
If a group has been defined in the editor, the ingroup() function can be used to check whether a particular object is part of the group.
Objects with a single coordinate that are individually selectable in the current drawing (like UL_TEXT, UL_VIA, UL_CIRCLE etc.) return a non-zero value in a call to ingroup() if that coordinate is within the defined group.
A UL_WIRE returns 0, 1, 2 or 3, depending on whether none, the first, the second or both of its end points are in the group.
A UL_RECTANGLE and UL_FRAME returns a non-zero value if one or more of its corners are in the group. The value has bit 0 set for the upper right corner, bit 1 for the upper left, bit 2 for the bottom left, and bit 3 for the bottom right corner.
Higher ranking objects that have no coordinates (UL_NET, UL_SEGMENT, UL_SIGNAL, UL_POLYGON)
or that are actually not available as drawing objects (UL_SHEET, UL_DEVICESET, UL_SYMBOL, UL_PACKAGE),
return a non-zero value if one or more of the objects within them are in the group.
For details on the object hierarchies see Object Types.
UL_CONTACTREF and UL_PINREF, though not having coordinates of their own, return
a non-zero value if the referenced UL_CONTACT or UL_PIN, respectively, is within
the group.
For other not selectable objects like UL_GRID, UL_VARIANT or wires of a UL_TEXT or
UL_FRAME object, the behaviour of ingroup() is undefined and therefore should not be used.
output("group.txt") { board(B) { B.elements(E) { if (ingroup(E)) printf("Element %s is in the group\n", E.name); } } }
The setgroup() function sets the group flags of the given object, so that it becomes part of the group.
If no flags are given, the object is added to the group as a whole (i.e. all of its selection points, in case it has more than one).
If flags has a non-zero value, only the group flags of the given points of the object are set. For a UL_WIRE this means that '1' sets the group flag of the first point, '2' that of the second point, and '3' sets both. Any previously set group flags remain unchanged by a call to setgroup().
When applied to an object that contains other objects (like a UL_BOARD or
UL_NET) the group flags of all contained objects are set recursively with following limitations:
It's not the case for UL_LIBRARY and UL_SCHEMATIC. Subordinate objects that are not selectable
or not inidividually selectable are not flagged (e.g. UL_GRID or UL_VARIANT objects or wires
of UL_TEXT or UL_FRAME objects).
For details on the object hierarchies see Object Types.
board(B) { B.elements(E) setgroup(E); }
The setvariant() function sets the current assembly variant to the one given by name. This can be used to loop through all of the parts and "see" their data exactly as defined in the given variant.
name must reference a valid assembly variant that is contained in the current drawing.
This function returns a non-zero value if the given assembly variant exists, zero otherwise.
The assembly variant that has been set by a call to setvariant() is only active until the User Language Program returns. After that, the variant in the drawing will be the same as before the start of the ULP.
Setting the assembly variant in a board is only possible if the consistent schematic is loaded.
if (setvariant("My variant")) { // do something ... else // error: unknown variant
The variant() function returns the name of the current assembly variant. If no variant is currently selected, the empty string ('') is returned.
string CurrentVariant = variant();
The following XML functions are available:
The xmlattribute function returns the value of the given attribute from the given tag within the given xml code. If an attribute appears more than once in the same tag, the value of its last occurrence is taken.
The xmlattributes function stores the names of all attributes from the given tag within the given xml code in the array and returns the number of attributes found. The order is not necessarily the same like in the given xml code. If an attribute appears more than once in the same tag, its name appears only once in the array.
The tag is given in the form of a path.
If the given xml code contains an error, the result of any XML function is empty, and a warning dialog is presented to the user, giving information about where in the ULP and XML code the error occurred. Note that the line and column number within the XML code refers to the actual string given to this function as the xml parameter.
// XML contains the following data: <root> <body abc="def" xyz="123"> ... </body> </root> // string s[]; int n = xmlattributes(s, XML, "root/body"); Result: { "abc", "xyz" } string s = xmlattribute(XML, "root/body", "xyz"); Result: "123"
The xmlelement function returns the complete XML element of the given
tag within the given xml code.
The result still contains the element's outer XML tag, and can thus be used
for further processing with the other XML functions.
Any whitespace within plain text parts of the element is retained.
The overall formatting of the XML tags within the element and the order of element
attributes may be different than the original xml code, though.
If there is more than one occurrence of tag within xml, the
first one will be returned. Use xmlelements if you want to get all
occurrences.
The xmlelements function works just like xmlelement, but returns all occurrences of elements with the given tag. The return value is the number of elements stored in the array.
The tag is given in the form of a path.
If the given xml code contains an error, the result of any XML function is empty, and a warning dialog is presented to the user, giving information about where in the ULP and XML code the error occurred. Note that the line and column number within the XML code refers to the actual string given to this function as the xml parameter.
// XML contains the following data: <root> <body> <contents> <string>Some text 1</string> <any>anything 1</any> </contents> <contents> <string>Some text 2</string> <any>anything 2</any> </contents> <appendix> <string>Some text 3</string> </appendix> </body> </root> // string s = xmlelement(XML, "root/body/appendix"); Result: " <appendix>\n <string>Some text 3</string>\n </appendix>\n" string s[]; int n = xmlelements(s, XML, "root/body/contents"); Result: { " <contents>\n <string>Some text 1</string>\n <any>anything 1</any>\n </contents>\n", " <contents>\n <string>Some text 2</string>\n <any>anything 2</any>\n </contents>\n" }
The xmltags function returns the names of all the tags on the top level of the given tag within the given xml code. The return value is the number of tag names stored in the array.
Each tag name is returned only once, even if it appears several times in the XML code.
The tag is given in the form of a path.
If the given xml code contains an error, the result of any XML function is empty, and a warning dialog is presented to the user, giving information about where in the ULP and XML code the error occurred. Note that the line and column number within the XML code refers to the actual string given to this function as the xml parameter.
// XML contains the following data: <root> <body> <contents> <string>Some text 1</string> <any>anything 1</any> </contents> <contents> <string>Some text 2</string> <any>anything 2</any> </contents> <appendix> <string>Some text 3</string> </appendix> </body> </root> // string s[]; int n = xmltags(s, XML, "root/body"); Result: { "contents", "appendix" } int n = xmltags(s, XML, ""); Result: "root"
The xmltext function returns the textual data from the given tag within the given xml code.
Any tags within the text are stripped, whitespace (including newline characters) is retained.
The tag is given in the form of a path.
If the given xml code contains an error, the result of any XML function is empty, and a warning dialog is presented to the user, giving information about where in the ULP and XML code the error occurred. Note that the line and column number within the XML code refers to the actual string given to this function as the xml parameter.
// XML contains the following data: <root> <body> Some <b>text</b>. </body> </root> // string s = xmltext(XML, "root/body"); Result: "\n Some text.\n "
The general syntax of a builtin statement is
name(parameters) statementwhere name is the name of the builtin statement, parameters stands for one or more parameters, and statement is the code that will be executed inside the context opened by the builtin statement.
Note that statement can be a compound statement, as in
board(B) { B.elements(E) printf("Element: %s\n", E.name); B.Signals(S) printf("Signal: %s\n", S.name); }The following builtin statements are available:
The board statement opens a board context if the current editor window contains a board drawing. A variable of type UL_BOARD is created and is given the name indicated by identifier.
Once the board context is successfully opened and a board variable has been created, the statement is executed. Within the scope of the statement the board variable can be accessed to retrieve further data from the board.
If the current editor window does not contain a board drawing, an error message is given and the ULP is terminated.
project.board(B) { ... }This will open a board context regardless whether the current editor window contains a board or a schematic drawing. However, there must be an editor window containing that board somewhere on the desktop!
if (board) board(B) { B.elements(E) printf("Element: %s\n", E.name); }
The deviceset statement opens a device set context if the current editor window contains a device drawing. A variable of type UL_DEVICESET is created and is given the name indicated by identifier.
Once the device set context is successfully opened and a device set variable has been created, the statement is executed. Within the scope of the statement the device set variable can be accessed to retrieve further data from the device set.
If the current editor window does not contain a device drawing, an error message is given and the ULP is terminated.
if (deviceset) deviceset(D) { D.gates(G) printf("Gate: %s\n", G.name); }
The library statement opens a library context if the current editor window contains a library drawing. A variable of type UL_LIBRARY is created and is given the name indicated by identifier.
Once the library context is successfully opened and a library variable has been created, the statement is executed. Within the scope of the statement the library variable can be accessed to retrieve further data from the library.
If the current editor window does not contain a library drawing, an error message is given and the ULP is terminated.
if (library) library(L) { L.devices(D) printf("Device: %s\n", D.name); }
The output statement opens a file with the given filename and mode for output through subsequent printf() calls. If the file has been successfully opened, the statement is executed, and after that the file is closed.
If the file cannot be opened, an error message is given and execution of the ULP is terminated.
By default the output file is written into the Project directory.
| a | append to an existing file, or create a new file if it does not exist | |
| w | create a new file (overwriting an existing file) | |
| t | open file in text mode | |
| b | open file in binary mode | |
| D | delete this file when ending the EAGLE session (only works together with w) | |
| F | force using this file name (normally *.brd, *.sch and *.lbr are rejected) |
Mode characters may appear in any order and combination. However, only the last one of a and w or t and b, respectively, is significant. For example a mode of "abtw" would open a file for textual write, which would be the same as "wt".
void PrintText(string s) { printf("This also goes into the file: %s\n", s); } output("file.txt", "wt") { printf("Directly printed\n"); PrintText("via function call"); }
The package statement opens a package context if the current editor window contains a package drawing. A variable of type UL_PACKAGE is created and is given the name indicated by identifier.
Once the package context is successfully opened and a package variable has been created, the statement is executed. Within the scope of the statement the package variable can be accessed to retrieve further data from the package.
If the current editor window does not contain a package drawing, an error message is given and the ULP is terminated.
if (package) package(P) { P.contacts(C) printf("Contact: %s\n", C.name); }
The schematic statement opens a schematic context if the current editor window contains a schematic drawing. A variable of type UL_SCHEMATIC is created and is given the name indicated by identifier.
Once the schematic context is successfully opened and a schematic variable has been created, the statement is executed. Within the scope of the statement the schematic variable can be accessed to retrieve further data from the schematic.
If the current editor window does not contain a schematic drawing, an error message is given and the ULP is terminated.
project.schematic(S) { ... }This will open a schematic context regardless whether the current editor window contains a schematic or a board drawing. However, there must be an editor window containing that schematic somewhere on the desktop!
if (schematic) schematic(S) { S.parts(P) printf("Part: %s\n", P.name); }
The sheet statement opens a sheet context if the current editor window contains a sheet drawing. A variable of type UL_SHEET is created and is given the name indicated by identifier.
Once the sheet context is successfully opened and a sheet variable has been created, the statement is executed. Within the scope of the statement the sheet variable can be accessed to retrieve further data from the sheet.
If the current editor window does not contain a sheet drawing, an error message is given and the ULP is terminated.
if (sheet) sheet(S) { S.instances(I) printf("Instance: %s\n", I.name); }
The symbol statement opens a symbol context if the current editor window contains a symbol drawing. A variable of type UL_SYMBOL is created and is given the name indicated by identifier.
Once the symbol context is successfully opened and a symbol variable has been created, the statement is executed. Within the scope of the statement the symbol variable can be accessed to retrieve further data from the symbol.
If the current editor window does not contain a symbol drawing, an error message is given and the ULP is terminated.
if (symbol) symbol(S) { S.pins(P) printf("Pin: %s\n", P.name); }
The following sections describe User Language Dialogs in detail:
| Predefined Dialogs | describes the ready to use standard dialogs | |
| Dialog Objects | defines the objects that can be used in a dialog | |
| Layout Information | explains how to define the location of objects within a dialog | |
| Dialog Functions | describes special functions for use with dialogs | |
| A Complete Example | shows a complete ULP with a data entry dialog |
The following predefined dialogs are available:
See Dialog Objects for information on how to define your own complex user dialogs.The dlgDirectory function displays a directory dialog from which the user can select a directory.
Title will be used as the dialog's title.
If Start is not empty, it will be used as the starting point for the dlgDirectory.
string dirName; dirName = dlgDirectory("Select a directory", "");
The dlgFileOpen and dlgFileSave functions display a file dialog from which the user can select a file.
Title will be used as the dialog's title.
If Start is not empty, it will be used as the starting point for the file dialog. Otherwise the current directory will be used.
Only files matching Filter will be displayed. If Filter is empty, all files will be displayed.
Filter can be either a simple wildcard (as in "*.brd"), a list of wildcards (as in "*.bmp *.jpg") or may even contain descriptive text, as in "Bitmap files (*.bmp)". If the "File type" combo box of the file dialog shall contain several entries, they have to be separated by double semicolons, as in "Bitmap files (*.bmp);;Other images (*.jpg *.png)".
string fileName; fileName = dlgFileOpen("Select a file", "", "*.brd");
The dlgMessageBox function displays the given Message in a modal dialog and waits until the user selects one of the buttons defined in button_list.
If Message contains any HTML tags, the characters '<', '>' and '&' must be given as "<", ">" and "&", respectively, if they shall be displayed as such.
button_list is an optional list of comma separated strings, which defines the
set of buttons that will be displayed at the bottom of the message box.
A maximum of three buttons can be defined.
If no button_list is given, it defaults to "OK".
The first button in button_list will become the default button (which will be selected if the user hits ENTER), and the last button in the list will become the "cancel button", which is selected if the user hits ESCape or closes the message box. You can make a different button the default button by starting its name with a '+', and you can make a different button the cancel button by starting its name with a '-'. To start a button text with an actual '+' or '-' it has to be escaped.
If a button text contains an '&', the character following the ampersand will become a hotkey, and when the user hits the corresponding key, that button will be selected. To have an actual '&' character in the text it has to be escaped.
The message box can be given an icon by setting the first character of Message to
';' - for an Information
'!' - for a Warning
':' - for an Error
If, however, the Message shall begin with one of these characters, it has to be escaped.
| On Mac OS X only the character ':' will actually result in showing an icon. All others are ignored. |
if (dlgMessageBox("!Are you sure?", "&Yes", "&No") == 0) { // let's do it! }
| dlgCell | a grid cell context | |
| dlgCheckBox | a checkbox | |
| dlgComboBox | a combo box selection field | |
| dlgDialog | the basic container of any dialog | |
| dlgGridLayout | a grid based layout context | |
| dlgGroup | a group field | |
| dlgHBoxLayout | a horizontal box layout context | |
| dlgIntEdit | an integer entry field | |
| dlgLabel | a text label | |
| dlgListBox | a list box | |
| dlgListView | a list view | |
| dlgPushButton | a push button | |
| dlgRadioButton | a radio button | |
| dlgRealEdit | a real entry field | |
| dlgSpacing | a layout spacing object | |
| dlgSpinBox | a spin box selection field | |
| dlgStretch | a layout stretch object | |
| dlgStringEdit | a string entry field | |
| dlgTabPage | a tab page | |
| dlgTabWidget | a tab page container | |
| dlgTextEdit | a text entry field | |
| dlgTextView | a text viewer field | |
| dlgVBoxLayout | a vertical box layout context |
dlgCell
See also dlgGridLayout,
dlgHBoxLayout,
dlgVBoxLayout,
Layout Information,
A Complete Example
The dlgCell statement defines the location of a cell within a grid layout context.
The row and column indexes start at 0, so the upper left cell has the index (0, 0).
With two parameters the dialog object defined by statement will be placed in the single cell addresses by row and column. With four parameters the dialog object will span over all cells from row/column to row2/column2.
By default a dlgCell contains a dlgHBoxLayout, so if the cell contains more than one dialog object, they will be placed next to each other horizontally.
string Text; dlgGridLayout { dlgCell(0, 0) dlgLabel("Cell 0,0"); dlgCell(1, 2, 4, 7) dlgTextEdit(Text); }
The dlgCheckBox statement defines a check box with the given Text.
If Text contains an '&', the character following the ampersand will become a hotkey, and when the user hits Alt+hotkey, the checkbox will be toggled. To have an actual '&' character in the text it has to be escaped.
dlgCheckBox is mainly used within a dlgGroup,
but can also be used otherwise.
All check boxes within the same dialog must have different Checked variables!
If the user checks a dlgCheckBox, the associated Checked variable is set to 1, otherwise it is set to 0. The initial value of Checked defines whether a checkbox is initially checked. If Checked is not equal to 0, the checkbox is initially checked.
The optional statement is executed every time the dlgCheckBox is toggled.
int mirror = 0; int rotate = 1; int flip = 0; dlgGroup("Orientation") { dlgCheckBox("&Mirror", mirror); dlgCheckBox("&Rotate", rotate); dlgCheckBox("&Flip", flip); }
The dlgComboBox statement defines a combo box selection field with the contents of the given array.
Selected reflects the index of the selected combo box entry. The first entry has index 0.
Each element of array defines the contents of one entry in the combo box. None of the strings in array may be empty (if there is an empty string, all strings after and including that one will be dropped).
The optional statement is executed whenever the selection in the dlgComboBox changes.
Before the statement is executed, all variables that have been used with dialog objects
are updated to their current values, and any changes made to these variables inside the
statement will be reflected in the dialog when the statement returns.
If the initial value of Selected is outside the range of the array indexes, it is set to 0.
string Colors[] = { "red", "green", "blue", "yellow" }; int Selected = 2; // initially selects "blue" dlgComboBox(Colors, Selected) dlgMessageBox("You have selected " + Colors[Selected]);
The dlgDialog function executes the dialog defined by block. This is the only dialog object that actually is a User Language builtin function. Therefore it can be used anywhere where a function call is allowed.
The block normally contains only other dialog objects, but it is also possible to use other User Language statements, for example to conditionally add objects to the dialog (see the second example below).
By default a dlgDialog contains a dlgVBoxLayout, so a simple dialog doesn't have to worry about the layout.
A dlgDialog should at some point contain a call to the dlgAccept() function in order to allow the user to close the dialog and accept its contents.
If all you need is a simple message box or file dialog you might want to use one of the Predefined Dialogs instead.
int Result = dlgDialog("Hello") { dlgLabel("Hello world"); dlgPushButton("+OK") dlgAccept(); }; int haveButton = 1; dlgDialog("Test") { dlgLabel("Start"); if (haveButton) dlgPushButton("Here") dlgAccept(); };
The dlgGridLayout statement opens a grid layout context.
The only dialog object that can be used directly in statement is dlgCell, which defines the location of a particular dialog object within the grid layout.
The row and column indexes start at 0, so the upper left cell has the index (0, 0).
The number of rows and columns is automatically extended according to the location of
dialog objects that are defined within the grid layout context, so you don't have
to explicitly define the number of rows and columns.
dlgGridLayout { dlgCell(0, 0) dlgLabel("Row 0/Col 0"); dlgCell(1, 0) dlgLabel("Row 1/Col 0"); dlgCell(0, 1) dlgLabel("Row 0/Col 1"); dlgCell(1, 1) dlgLabel("Row 1/Col 1"); }
The dlgGroup statement defines a group with the given Title.
By default a dlgGroup contains a dlgVBoxLayout, so a simple group doesn't have to worry about the layout.
dlgGroup is mainly used to contain a set of radio buttons
or check boxes, but may as well contain any other objects in its
statement.
Radio buttons within a dlgGroup are numbered starting with 0.
int align = 1; dlgGroup("Alignment") { dlgRadioButton("&Top", align); dlgRadioButton("&Center", align); dlgRadioButton("&Bottom", align); }
The dlgHBoxLayout statement opens a horizontal box layout context for the given statement.
dlgHBoxLayout { dlgLabel("Box 1"); dlgLabel("Box 2"); dlgLabel("Box 3"); }
The dlgIntEdit statement defines an integer entry field with the given Value.
If Value is initially outside the range defined by Min and Max it will be limited to these values.
int Value = 42; dlgHBoxLayout { dlgLabel("Enter a &Number between 0 and 99"); dlgIntEdit(Value, 0, 99); }
The dlgLabel statement defines a label with the given Text.
Text can be either a string literal, as in "Hello", or a string variable.
If Text contains any HTML tags, the characters '<', '>' and '&' must be given as "<", ">" and "&", respectively, if they shall be displayed as such.
External hyperlinks in the Text will be opened with the appropriate application program.
If the Update parameter is not 0 and Text is a string variable, its contents can be modified in the statement of, e.g., a dlgPushButton, and the label will be automatically updated. This, of course, is only useful if Text is a dedicated string variable (not, e.g., the loop variable of a for statement).
If Text contains an '&', and the object following the label can have the keyboard focus, the character following the ampersand will become a hotkey, and when the user hits Alt+hotkey, the focus will go to the object that was defined immediately following the dlgLabel. To have an actual '&' character in the text it has to be escaped.
string OS = "Windows"; dlgHBoxLayout { dlgLabel(OS, 1); dlgPushButton("&Change OS") { OS = "Linux"; } }
The dlgListBox statement defines a list box selection field with the contents of the given array.
Selected reflects the index of the selected list box entry. The first entry has index 0.
Each element of array defines the contents of one line in the list box. None of the strings in array may be empty (if there is an empty string, all strings after and including that one will be dropped).
The optional statement is executed whenever the user double clicks on an entry
of the dlgListBox (see dlgSelectionChanged
for information on how to have the statement called when only the selection in the list
changes).
Before the statement is executed, all variables that have been used with dialog objects
are updated to their current values, and any changes made to these variables inside the
statement will be reflected in the dialog when the statement returns.
If the initial value of Selected is outside the range of the array indexes, no entry will be selected.
string Colors[] = { "red", "green", "blue", "yellow" }; int Selected = 2; // initially selects "blue" dlgListBox(Colors, Selected) dlgMessageBox("You have selected " + Colors[Selected]);
The dlgListView statement defines a multi column list view selection field with the contents of the given array.
Headers is the tab separated list of column headers.
Selected reflects the index of the selected list view entry in the array
(the sequence in which the entries are actually displayed may be different, because the contents
of a dlgListView can be sorted by the various columns).
The first entry has index 0.
If no particular entry shall be initially selected, Selected should be
initialized to -1.
If it is set to -2, the first item according
to the current sort column is made current.
Sort defines which column should be used to sort the list view. The leftmost column is numbered 1. The sign of this parameter defines the direction in which to sort (positive values sort in ascending order). If Sort is 0 or outside the valid number of columns, no sorting will be done. The returned value of Sort reflects the column and sort mode selected by the user by clicking on the list column headers. By default dlgListView sorts by the first column, in ascending order.
Each element of array defines the contents of one line in the list view, and must contain tab separated values. If there are fewer values in an element of array than there are entries in the Headers string the remaining fields will be empty. If there are more values in an element of array than there are entries in the Headers string the superfluous elements will be silently dropped. None of the strings in array may be empty (if there is an empty string, all strings after and including that one will be dropped).
A list entry that contains line feeds ('\n') will be displayed in several lines accordingly.
The optional statement is executed whenever the user double clicks on an entry
of the dlgListView (see dlgSelectionChanged
for information on how to have the statement called when only the selection in the list
changes).
Before the statement is executed, all variables that have been used with dialog objects
are updated to their current values, and any changes made to these variables inside the
statement will be reflected in the dialog when the statement returns.
If the initial value of Selected is outside the range of the array indexes, no entry will be selected.
If Headers is an empty string, the first element of the array is used as the header string. Consequently the index of the first entry is then 1.
The contents of a dlgListView can be sorted by any column by clicking on that column's header. Columns can also be swapped by "click&dragging" a column header. Note that none of these changes will have any effect on the contents of the array. If the contents shall be sorted alphanumerically a numeric string[] array can be used.
string Colors[] = { "red\tThe color RED", "green\tThe color GREEN", "blue\tThe color BLUE" }; int Selected = 0; // initially selects "red" dlgListView("Name\tDescription", Colors, Selected) dlgMessageBox("You have selected " + Colors[Selected]);
The dlgPushButton statement defines a push button with the given Text.
If Text contains an '&', the character following the ampersand will become a hotkey, and when the user hits Alt+hotkey, the button will be selected. To have an actual '&' character in the text it has to be escaped.
If Text starts with a '+' character, this button will become the default
button, which will be selected if the user hits ENTER.
If Text starts with a '-' character, this button will become the cancel
button, which will be selected if the user closes the dialog.
CAUTION: Make sure that the statement of such a marked cancel button contains
a call to dlgReject()! Otherwise the user may be unable
to close the dialog at all!
To have an actual '+' or '-' character as the first character of the text
it has to be escaped.
If the user selects a dlgPushButton, the given statement is executed.
Before the statement is executed, all variables that have been used with dialog objects
are updated to their current values, and any changes made to these variables inside the
statement will be reflected in the dialog when the statement returns.
int defaultWidth = 10; int defaultHeight = 20; int width = 5; int height = 7; dlgPushButton("&Reset defaults") { width = defaultWidth; height = defaultHeight; } dlgPushButton("+&Accept") dlgAccept(); dlgPushButton("-Cancel") { if (dlgMessageBox("Are you sure?", "Yes", "No") == 0) dlgReject(); }
The dlgRadioButton statement defines a radio button with the given Text.
If Text contains an '&', the character following the ampersand will become a hotkey, and when the user hits Alt+hotkey, the button will be selected. To have an actual '&' character in the text it has to be escaped.
dlgRadioButton can only be used within a dlgGroup.
All radio buttons within the same group must use the same Selected variable!
If the user selects a dlgRadioButton, the index of that button within the dlgGroup
is stored in the Selected variable.
The initial value of Selected defines which radio button is initially selected.
If Selected is outside the valid range for this group, no radio button will be selected.
In order to get the correct radio button selection, Selected must be set before
the first dlgRadioButton is defined, and must not be modified between adding subsequent
radio buttons. Otherwise it is undefined which (if any) radio button will be selected.
The optional statement is executed every time the dlgRadioButton is selected.
int align = 1; dlgGroup("Alignment") { dlgRadioButton("&Top", align); dlgRadioButton("&Center", align); dlgRadioButton("&Bottom", align); }
The dlgRealEdit statement defines a real entry field with the given Value.
If Value is initially outside the range defined by Min and Max it will be limited to these values.
real Value = 1.4142; dlgHBoxLayout { dlgLabel("Enter a &Number between 0 and 99"); dlgRealEdit(Value, 0.0, 99.0); }
The dlgSpacing statement defines additional space in a vertical or horizontal box layout context.
Size defines the number of pixels of the additional space.
dlgVBoxLayout { dlgLabel("Label 1"); dlgSpacing(40); dlgLabel("Label 2"); }
The dlgSpinBox statement defines a spin box entry field with the given Value.
If Value is initially outside the range defined by Min and Max it will be limited to these values.
int Value = 42; dlgHBoxLayout { dlgLabel("&Select value"); dlgSpinBox(Value, 0, 99); }
The dlgStretch statement defines an empty stretchable space in a vertical or horizontal box layout context.
Factor defines the stretch factor of the space.
dlgHBoxLayout { dlgStretch(1); dlgPushButton("+OK") { dlgAccept(); }; dlgPushButton("Cancel") { dlgReject(); }; }
The dlgStringEdit statement defines a one line text entry field with the given Text.
If History is given, the strings the user has entered over time are stored
in that string array. The entry field then has a button that allows the user to
select from previously entered strings. If a Size greater than zero is given,
only at most that number of strings are stored in the array. If History
contains data when the dialog is newly opened, that data will be used to initialize
the history. The most recently entered user input is stored at index 0.
None of the strings in History may be empty (if there is an empty string,
all strings after and including that one will be dropped).
string Name = "Linus"; dlgHBoxLayout { dlgLabel("Enter &Name"); dlgStringEdit(Name); }
The dlgTabPage statement defines a tab page with the given Title containing the given statement.
If Title contains an '&', the character following the ampersand will become a hotkey, and when the user hits Alt+hotkey, this tab page will be opened. To have an actual '&' character in the text it has to be escaped.
Tab pages can only be used within a dlgTabWidget.
By default a dlgTabPage contains a dlgVBoxLayout, so a simple tab page doesn't have to worry about the layout.
dlgTabWidget { dlgTabPage("Tab &1") { dlgLabel("This is page 1"); } dlgTabPage("Tab &2") { dlgLabel("This is page 2"); } }
The dlgTabWidget statement defines a container for a set of tab pages.
statement must be a sequence of one or more dlgTabPage objects. There must be no other dialog objects in this sequence.
dlgTabWidget { dlgTabPage("Tab &1") { dlgLabel("This is page 1"); } dlgTabPage("Tab &2") { dlgLabel("This is page 2"); } }
The dlgTextEdit statement defines a multiline text entry field with the given Text.
The lines in the Text have to be delimited by a newline character ('\n'). Any whitespace characters at the end of the lines contained in Text will be removed, and upon return there will be no whitespace characters at the end of the lines. Empty lines at the end of the text will be removed entirely.
string Text = "This is some text.\nLine 2\nLine 3"; dlgVBoxLayout { dlgLabel("&Edit the text"); dlgTextEdit(Text); }
The dlgTextView statement defines a multiline text viewer field with the given Text.
The Text may contain HTML tags.
External hyperlinks in the Text will be opened with the appropriate application program.
If Link is given and the Text contains hyperlinks, statement will be executed every time the user clicks on a hyperlink, with the value of Link set to whatever the <a href=...> tag defines as the value of href. If, after the execution of statement, the Link variable is not empty, the default handling of hyperlinks will take place. This is also the case if Link contains some text before dlgTextView is opened, which allows for an initial scrolling to a given position. If a Link is given, external hyperlinks will not be opened.
string Text = "This is some text.\nLine 2\nLine 3"; dlgVBoxLayout { dlgLabel("&View the text"); dlgTextView(Text); }
The dlgVBoxLayout statement opens a vertical box layout context for the given statement.
By default a dlgDialog contains a dlgVBoxLayout, so a simple dialog doesn't have to worry about the layout.
dlgVBoxLayout { dlgLabel("Box 1"); dlgLabel("Box 2"); dlgLabel("Box 3"); }
Layout contexts can be either grid, horizontal or vertical.
dlgGridLayout { dlgCell(5, 2) dlgLabel("Text"); }If the object shall span over more than one cell you need to specify the coordinates of the starting cell and the ending cell. To place a group that extends from row 1, column 2 up to row 3, column 5, you would write
dlgGridLayout { dlgCell(1, 2, 3, 5) dlgGroup("Title") { //... } }
The special objects dlgStretch and dlgSpacing can be used to further refine the distribution of the available space.
To define two buttons that are pushed all the way to the right edge of the dialog, you would write
dlgHBoxLayout { dlgStretch(1); dlgPushButton("+OK") dlgAccept(); dlgPushButton("Cancel") dlgReject(); }
| dlgAccept() | closes the dialog and accepts its contents | |
| dlgRedisplay() | immediately redisplays the dialog after changes to any values | |
| dlgReset() | resets all dialog objects to their initial values | |
| dlgReject() | closes the dialog and rejects its contents | |
| dlgSelectionChanged() | tells whether the current selection in a dlgListView or dlgListBox has changed |
The dlgAccept function causes the dlgDialog to be closed and return after the current statement sequence has been completed.
Any changes the user has made to the dialog values will be accepted and are copied into the variables that have been given when the dialog objects were defined.
The optional Result is the value that will be returned by the dialog. Typically this should be a positive integer value. If no value is given, it defaults to 1.
Note that dlgAccept() does return to the normal program execution, so in a sequence like
dlgPushButton("OK") { dlgAccept(); dlgMessageBox("Accepting!"); }the statement after dlgAccept() will still be executed!
int Result = dlgDialog("Test") { dlgPushButton("+OK") dlgAccept(42); dlgPushButton("Cancel") dlgReject(); };
The dlgRedisplay function can be called to immediately refresh the dlgDialog after changes have been made to the variables used when defining the dialog objects.
You only need to call dlgRedisplay() if you want the dialog to be refreshed while still executing program code. In the example below the status is changed to "Running..." and dlgRedisplay() has to be called to make this change take effect before the "program action" is performed. After the final status change to "Finished." there is no need to call dlgRedisplay(), since all dialog objects are automatically updated after leaving the statement.
string Status = "Idle"; int Result = dlgDialog("Test") { dlgLabel(Status, 1); // note the '1' to tell the label to be updated! dlgPushButton("+OK") dlgAccept(42); dlgPushButton("Cancel") dlgReject(); dlgPushButton("Run") { Status = "Running..."; dlgRedisplay(); // some program action here... Status = "Finished."; } };
The dlgReset function copies the initial values back into all dialog objects of the current dlgDialog.
Any changes the user has made to the dialog values will be discarded.
Calling dlgReject() implies a call to dlgReset().
int Number = 1; int Result = dlgDialog("Test") { dlgIntEdit(Number); dlgPushButton("+OK") dlgAccept(42); dlgPushButton("Cancel") dlgReject(); dlgPushButton("Reset") dlgReset(); };
The dlgReject function causes the dlgDialog to be closed and return after the current statement sequence has been completed.
Any changes the user has made to the dialog values will be discarded. The variables that have been given when the dialog objects were defined will be reset to their original values when the dialog returns.
The optional Result is the value that will be returned by the dialog. Typically this should be 0 or a negative integer value. If no value is given, it defaults to 0.
Note that dlgReject() does return to the normal program execution, so in a sequence like
dlgPushButton("Cancel") { dlgReject(); dlgMessageBox("Rejecting!"); }the statement after dlgReject() will still be executed!
Calling dlgReject() implies a call to dlgReset().
int Result = dlgDialog("Test") { dlgPushButton("+OK") dlgAccept(42); dlgPushButton("Cancel") dlgReject(); };
The dlgSelectionChanged function can be used in a list context to determine whether the statement of the dlgListView or dlgListBox was called because the user double clicked on an item, or whether only the current selection in the list has changed.
If the statement of a dlgListView or dlgListBox doesn't contain any call to dlgSelectionChanged, that statement is only executed when the user double clicks on an item in the list. However, if a ULP needs to react on changes to the current selection in the list, it can call dlgSelectionChanged within the list's statement. This causes the statement to also be called if the current selection in the list changes.
If a list item is initially selected when the dialog is opened and the list's statement contains a call to dlgSelectionChanged, the statement is executed with dlgSelectionChanged returning true in order to indicate the initial change from "no selection" to an actual selection. Any later programmatical changes to the strings or the selection of the list will not trigger an automatic execution of the list's statement. This is important to remember in case the current list item controls another dialog object, for instance a dlgTextView that shows an extended representation of the currently selected item.
string Colors[] = { "red\tThe color RED", "green\tThe color GREEN", "blue\tThe color BLUE" }; int Selected = 0; // initially selects "red" string MyColor; dlgLabel(MyColor, 1); dlgListView("Name\tDescription", Colors, Selected) { if (dlgSelectionChanged()) MyColor = Colors[Selected]; else dlgMessageBox("You have chosen " + Colors[Selected]); }
To do this you need to prepend the character with a backslash, as in
dlgLabel("Miller \\& Co.");This will result in "Miller & Co." displayed in the dialog.
Note that there are actually two backslash characters here, since this line
will first go through the User Language parser, which will strip the first backslash.
A Complete Example
Here's a complete example of a User Language Dialog.
int hor = 1;
int ver = 1;
string fileName;
int Result = dlgDialog("Enter Parameters") {
dlgHBoxLayout {
dlgStretch(1);
dlgLabel("This is a simple dialog");
dlgStretch(1);
}
dlgHBoxLayout {
dlgGroup("Horizontal") {
dlgRadioButton("&Top", hor);
dlgRadioButton("&Center", hor);
dlgRadioButton("&Bottom", hor);
}
dlgGroup("Vertical") {
dlgRadioButton("&Left", ver);
dlgRadioButton("C&enter", ver);
dlgRadioButton("&Right", ver);
}
}
dlgHBoxLayout {
dlgLabel("File &name:");
dlgStringEdit(fileName);
dlgPushButton("Bro&wse") {
fileName = dlgFileOpen("Select a file", fileName);
}
}
dlgGridLayout {
dlgCell(0, 0) dlgLabel("Row 0/Col 0");
dlgCell(1, 0) dlgLabel("Row 1/Col 0");
dlgCell(0, 1) dlgLabel("Row 0/Col 1");
dlgCell(1, 1) dlgLabel("Row 1/Col 1");
}
dlgSpacing(10);
dlgHBoxLayout {
dlgStretch(1);
dlgPushButton("+OK") dlgAccept();
dlgPushButton("Cancel") dlgReject();
}
};
Supported HTML tags
EAGLE supports a subset of the tags used to format HTML pages.
This can be used to format the text of several User Language Dialog objects,
in the #usage directive or in the description
of library objects.
Text is considered to be HTML if the first line contains a tag. If this is not the case, and you want the text to be formatted, you need to enclose the entire text in the <html>...</html> tag.
The following table lists all supported HTML tags and their available attributes:
| Tag | Description | |
| <html>...</html> | An HTML document. | |
| <html>...</html> | The body of an HTML document. It understands the following attribute
| |
| <h1>...</h1> | A top-level heading. | |
| <h2>...</h2> | A sub-level heading. | |
| <h3>...</h3> | A sub-sub-level heading. | |
| <p>...</p> | A left-aligned paragraph. Adjust the alignment with the align attribute. Possible values are left, right and center. | |
| <center>...</center> | A centered paragraph. | |
| <blockquote>...</blockquote> | An indented paragraph, useful for quotes. | |
| <ul>...</ul> | An un-ordered list. You can also pass a type argument to define the bullet style. The default is type=disc, other types are circle and square. | |
| <ol>...</ol> | An ordered list. You can also pass a type argument to define the enumeration label style. The default is type="1", other types are "a" and "A". | |
| <li>...</li> | A list item. This tag can only be used within the context of ol or ul. | |
| <pre>...</pre> | For larger chunks of code. Whitespaces in the contents are preserved. For small bits of code, use the inline-style code. | |
| <a>...</a> | An anchor or link. It understands the following attributes:
| |
| <em>...</em> | Emphasized (same as <i>...</i>). | |
| <strong>...</strong> | Strong (same as <b>...</b>). | |
| <i>...</i> | Italic font style. | |
| <b>...</b> | Bold font style. | |
| <u>...</u> | Underlined font style. | |
| <big>...</big> | A larger font size. | |
| <small>...</small> | A smaller font size. | |
| <code>...</code> | Indicates Code. (same as <tt>...</tt>. For larger chunks of code, use the block-tag pre. | |
| <tt>...</tt> | Typewriter font style. | |
| <font>...</font> | Customizes the font size, family and text color. The tag understands the following attributes:
| |
| <img...> | An image. This tag understands the following attributes:
| |
| <hr> | A horizonal line. | |
| <br> | A line break. | |
| <nobr>...</nobr> | No break. Prevents word wrap. | |
| <table>...</table> | A table definition.
The default table is frameless. Specify the boolean attribute
border in order to get a frame. Other attributes are:
| |
| <tr>...</tr> | A table row. Can only be used within table. Understands the attribute
| |
| <td>...</td> | A table data cell. Can only be used within tr. Understands the attributes
| |
| <th>...</th> | A table header cell. Like td but defaults to center-alignment and a bold font. | |
| <author>...</author> | Marks the author of this text. | |
| <dl>...</dl> | A definition list. | |
| <dt>...</dt> | A definition tag. Can only be used within dl. | |
| <dd>...</dd> | Definition data. Can only be used within dl. |
| Tag | Meaning | |
| < | < | |
| > | > | |
| & | & | |
| | non-breaking space | |
| ä | ä | |
| ö | ö | |
| ü | ü | |
| Ä | Ä | |
| Ö | Ö | |
| Ü | Ü | |
| ß | ß | |
| © | © | |
| ° | ° | |
| µ | µ | |
| ± | ± | |
| " | " |
.x#nIn this pattern 'x' is replaced by the character
'b' for board files
's' for schematic files
'l' for library files
'n' stands for a single digit number in the range 1..9. Higher numbers indicate older files.
The fixed '#' character makes it easy to delete all backup files from the operating system, using *.?#? as a wildcard.
Note that backup files with the same number 'n' do not necessarily represent consistent combinations of board and schematic files!
The maximum number of backup copies can be set in the backup dialog.
This safety backup file will have a name that follows the pattern
.x##In this pattern 'x' is replaced by the character
'b' for board files
's' for schematic files
'l' for library files
The safety backup file will be deleted after a successful regular save operation. If the drawing has not been saved with the WRITE command (e.g. due to a power failure) this file can be renamed and loaded as a normal board, schematic or library file, repectively.
The auto backup interval can be set in the backup dialog.
Normally a board and schematic will always be consistent as long as they
have never been edited separately (in which case the message
"No Forward&Back Annotation will be performed!"
will have warned you).
When loading a pair of board and schematic files the program will check
some consistency markers in the data files to see if these two files are
still consistent. If these markers indicate an inconsistency, you will be
offered to run an Electrical Rule Check (ERC),
which will do a detailed cross-check on both files.
If this check turns out positive, the two files are marked as consistent
and Forward&Back Annotation will be activated.
If the two files are found to be inconsistent the ERC protocol file will
be brought up in a dialog and Forward&Back Annotation will
not be activated.
Please do not be alarmed if you get a lot
of inconsistency messages. In most cases fixing one error (like renaming
a part or a net) will considerably reduce the number of error messages you get in the next
ERC run.
Forward&Back Annotation
A schematic and board file are logically interconnected through automatic
Forward&Back Annotation. Normally there are no special things to be
considered about Forward&Back Annotation. This section, however, lists all of the
details about what exactly happens during f/b activities:
Consistency Check
In order to use Forward&Back Annotation a board and schematic
must be consistent, which means they must contain an equivalent set of
parts/elements and nets/signals.
Making a Board and Schematic consistent
To make an inconsistent pair of board and schematic files consistent, you
have to manually fix any inconsistency listed in the ERC protocol.
This can be done by applying editor commands like
NAME,
VALUE,
PINSWAP,
REPLACE etc.
After fixing the inconsistencies you must use the
ERC command again to check the files and
eventually activate Forward&Back Annotation.
CadSoft Computer
19620 Pines Blvd. Suite 217
Pembroke Pines, FL 33029
USA
| Phone |<PHONE_NUMBER> | |
| Fax |<PHONE_NUMBER> | |
|<EMAIL_ADDRESS>| ||
| URL | www.cadsoftusa.com |
| Under Mac OS X you can find this information under "EAGLE/About EAGLE". |
There are different types of licenses, varying in the number of users who may use the program and in the areas of application the program may be used in:
A typical application of this kind would be a user who has a PC at home and also a notebook or laptop computer which he uses "on the road". As he would only use one of these computers at a time it is ok to have EAGLE installed on both of them.
In the dialog "EAGLE License" enter the name of your EAGLE license file, as well as the corresponding Installation Code you have received together with your license file (this code consists of 10 lowercase characters).
After pressing enter or clicking on the OK button, EAGLE will be installed with your personalized license data.
If you have problems installing EAGLE or are in doubt about the validity of your license please contact our Technical Support staff for assistance.
If you receive an error message like
The Light edition of EAGLE can't perform the requested action!
this means that you are attempting to do something that would violate the limitations that apply to the EAGLE edition in use, like for example placing an element outside of the allowed area.
All editions of EAGLE can be used to view files created with the Standard or Professional edition, even if these drawings exceed the editing capabilities of the edition currently in use.
To check which edition your license has enabled, select Help/About EAGLE from the Control Panel's menu.