Skip to content

Commit f06bb9f

Browse files
committed
ini: Fix the ini-file parser and Tcl interaction
ini: Expose enum mapping functions in python ini: Improve linuxcnc pre-run ini-file check ini: Reintroduce to remove comments in values
1 parent 41c25d8 commit f06bb9f

29 files changed

Lines changed: 1371 additions & 256 deletions

File tree

debian/linuxcnc.install.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ usr/bin/latency-plot
4141
usr/bin/latency-test
4242
usr/bin/lineardelta
4343
usr/bin/linuxcnc
44+
usr/bin/linuxcnc_check_ini
4445
usr/bin/linuxcnc_info
4546
usr/bin/linuxcnc_module_helper
4647
usr/bin/linuxcnc_var

debian/linuxcnc.manpages.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ usr/share/man/man1/latency-plot.1
3939
usr/share/man/man1/latency-test.1
4040
usr/share/man/man1/lineardelta.1
4141
usr/share/man/man1/linuxcnc.1
42+
usr/share/man/man1/linuxcnc_check_ini.1
4243
usr/share/man/man1/linuxcnc_info.1
4344
usr/share/man/man1/linuxcnclcd.1
4445
usr/share/man/man1/linuxcncmkdesktop.1

docs/man/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ man1/latency-histogram.1
4848
man1/latency-plot.1
4949
man1/latency-test.1
5050
man1/lineardelta.1
51+
man1/linuxcnc_check_ini.1
5152
man1/linuxcnc_info.1
5253
man1/linuxcnc_module_helper.1
5354
man1/linuxcnc_var.1

docs/src/config/ini-config.adoc

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ In this list, the DISPLAY variable will be set to axis because the other one is
4646
If someone carelessly edits a list like this and leaves two of the lines uncommented, the first one encountered will be used.
4747

4848
Note that inside a variable's value, the "#" and ";" characters are part of the value:
49-
5049
[source,{ini}]
5150
----
5251
# Below does not result in INCORRECT=value
@@ -116,26 +115,26 @@ ini.1.max_velocity \
116115
ini.2.max_velocity
117116
----
118117

119-
A specific variable in a specific sections is often denoted in the documentation as [SECTION]VARIABLE.
118+
A specific variable in a specific sections is often denoted in the documentation as `[SECTION]VARIABLE`.
120119
This specification mirrors the same way they are specified in HAL files for expansion.
121120

122121
Variable values may embed special characters in literal or escaped forms.
123122
Single or double quotes are not treated as special and are a literal part of the value.
124123
Values also support all common escape formats and full Unicode:
125124

126-
* control: \\[abfnrtv]
127-
* octal: \\[0-2][0-7]{0,2}
128-
* hex: \\x[0-9a-fA-F]{2}
129-
* UTF-16: \\u[0-9a-fA-F]{4}
130-
* UTF-32: \\U[0-9a-fA-F]{8}
125+
* control: `\[abfnrtv]`
126+
* octal: `\[0-2][0-7]{0,2}`
127+
* hex: `\x[0-9a-fA-F]{2}`
128+
* UTF-16: `\u[0-9a-fA-F]{4}`
129+
* UTF-32: `\U[0-9a-fA-F]{8}`
131130

132131
The resulting value is always converted into UTF-8 and checked for validity.
133132
It is not allowed to embed NUL characters either literally or by using an escape.
134133

135134
Leading and trailing white space is normally removed from a value.
136-
You can add leading and trailing space in a value by using an escaped value for space (\\x20) as first or last character.
135+
You can add leading and trailing space in a value by using an escaped value for space (`\x20`) as first or last character.
137136
Spaces inside a value are automatically part of the value.
138-
Tabs and newlines can be added using \\t and \\n.
137+
Tabs and newlines can be added using `\t` and `\n`.
139138

140139
.Value Escape Example
141140
[source,{ini}]
@@ -148,10 +147,10 @@ STRING = Hello\
148147
World\
149148
!
150149
151-
SMILE = \\370\\237\\230\\200 = 😀
152-
SMILE = \\xf0\\x9f\\x98\\x80 = 😀
153-
SMILE = \\ud83d\\ude00 = 😀
154-
SMILE = \\U0001f600 = 😀
150+
SMILE = \370\237\230\200 = 😀
151+
SMILE = \xf0\x9f\x98\x80 = 😀
152+
SMILE = \ud83d\ude00 = 😀
153+
SMILE = \U0001f600 = 😀
155154
----
156155

157156
Variables' value can have types associated when they are read by LinuxCNC.
@@ -171,18 +170,18 @@ Plain old 32-bit integers are marked `int` and are always signed.
171170
The default number base is decimal. Alternative bases may be specified using a prefix.
172171
The complete list of valid integer numbers:
173172

174-
* \[0-9]+ - decimal
175-
* 0x\[0-9A-Fa-f]+ - hexadecimal
176-
* 0o\[0-7]+ - octal
177-
* 0b\[01]+ - binary
173+
* `[0-9]+` (decimal)
174+
* `0x[0-9A-Fa-f]+` (hexadecimal)
175+
* `0o[0-7]+` (octal)
176+
* `0b[01]+` (binary)
178177

179178
Signed integers may be preceded by a plus (+) or minus (-) sign, regardless number base.
180179
Unsigned integers will generate a warning if they are preceded by a minus (-) sign upon conversion.
181180

182181
Boolean values are case insensitive and allow the following words:
183182

184-
* true/enabled - `TRUE`, `YES` `ON` or `1`
185-
* false/disabled - `FALSE`, `NO` `OFF` or `0`
183+
* true/enabled - `TRUE`, `YES`, `ON` or `1`
184+
* false/disabled - `FALSE`, `NO`, `OFF` or `0`
186185

187186
Enumerations are a set of keywords defined by LinuxCNC and interpreted to mean a setting, value or functionality.
188187
The exact values are declared in the individual variable description and the variables are marked with `enum`.
@@ -253,7 +252,8 @@ G10 L20 P0 Z#<_ini[probe]z_offset>
253252
[[sub:ini:include]]
254253
=== Include Files(((INI File,Components,Include)))
255254

256-
An INI file may include the contents of another file by using a #INCLUDE directive.
255+
An INI file may include the contents of another file by using a `#INCLUDE` directive.
256+
The `#INCLUDE` directive must be in upper case, start in the first column of the line and have at least one space after it.
257257

258258
.#INCLUDE Format
259259
[source,{ini}]
@@ -268,7 +268,7 @@ The filename can be specified as:
268268
* an absolute file name (starts with a /)
269269
* a user-home-relative file name (starts with a ~/)
270270

271-
Multiple #INCLUDE directives are supported.
271+
Multiple `#INCLUDE` directives are supported.
272272

273273
.#INCLUDE Examples
274274
[source,{ini}]
@@ -280,7 +280,7 @@ Multiple #INCLUDE directives are supported.
280280
#INCLUDE ~/linuxcnc/myincludes/rs274ngc.inc
281281
----
282282

283-
The #INCLUDE directives are supported up to 16 levels -- an included file may include additional files up to 16 levels deep.
283+
The `#INCLUDE` directives are supported up to 16 levels -- an included file may include additional files up to 16 levels deep.
284284
Recursive inclusion of files is detected and flagged as an error.
285285
The recommended file extension is '.inc'.
286286
Do _not_ use a file extension of '.ini' for included files.
@@ -331,12 +331,12 @@ Descriptions of the interfaces are in the Interfaces section of the User Manual.
331331
The example above will display only one decimal digit.
332332
Formatting follows Python practice: https://docs.python.org/2/library/string.html#format-specification-mini-language .
333333
An error will be raised if the format can not accept a floating-point value.
334-
* `CONE_BASESIZE = .25` - Override the default cone/tool base size of .5 in the graphics display. Valid values are between 0.025 and 2.0.
335-
* `DISABLE_CONE_SCALING = TRUE` - Any non-empty value (including "0") will override the default behavior of scaling the cone/tool size using the extents of the currently loaded G-code program in the graphics display.
336-
* `GCODE_VIEW_TOOL_MIN_DIA = 2.0` - If the tool diameter is very small, but non-zero then the displayed cylinder may be too small to see.
334+
* `CONE_BASESIZE = .25` - (real) Override the default cone/tool base size of .5 in the graphics display. Valid values are between 0.025 and 2.0.
335+
* `DISABLE_CONE_SCALING = TRUE` - (bool) Will override the default behavior of scaling the cone/tool size using the extents of the currently loaded G-code program in the graphics display.
336+
* `GCODE_VIEW_TOOL_MIN_DIA = 2.0` - (real) If the tool diameter is very small, but non-zero then the displayed cylinder may be too small to see.
337337
This could happen if the tool diameter was being used as a wear offset. This setting will cause the tool cone to be displayed
338338
rather than a tool cylinder.
339-
* `MAX_FEED_OVERRIDE = 1.2` - The maximum feed override the user may select.
339+
* `MAX_FEED_OVERRIDE = 1.2` - (real) The maximum feed override the user may select.
340340
1.2 means 120% of the programmed feed rate.
341341
* `MIN_SPINDLE_OVERRIDE = 0.5` - (real) The minimum spindle override the user may select.
342342
0.5 means 50% of the programmed spindle speed. (This is used to set the minimum spindle speed.)
@@ -373,7 +373,7 @@ Descriptions of the interfaces are in the Interfaces section of the User Manual.
373373
An under powered CPU may see improvement with a longer setting.
374374
Usually the default is fine.
375375
* `PREVIEW_TIMEOUT = 5` - Timeout (in seconds) for loading graphical preview of G-code. Currently AXIS only.
376-
* `HOMING_PROMPT = TRUE` - Any non-empty value (including "0") will enable showing a prompt message with homing request, when the Power On button is pressed in AXIS GUI. Pressing the "Ok" button in prompt message is equivalent to pressing the "Home All" button(or the Ctrl-HOME key).
376+
* `HOMING_PROMPT = TRUE` - (bool) Will enable showing a prompt message with homing request, when the Power On button is pressed in AXIS GUI. Pressing the "Ok" button in prompt message is equivalent to pressing the "Home All" button(or the Ctrl-HOME key).
377377
* `FOAM_W = 1.5` sets the foam W height.
378378
* `FOAM_Z = 0` sets the foam Z height.
379379
* `GRAPHICAL_MAX_FILE_SIZE = 20` largest size (in mega bytes) that will be displayed graphically.
@@ -425,9 +425,9 @@ See <<cha:gmoccapy,GMOCCAPY>> document for GMOCCAPY details.
425425
* `PYVCP_POSITION = BOTTOM` - The placement of the PyVCP panel in the AXIS user interface.
426426
If this variable is omitted the panel will default to the right side.
427427
The only valid alternative is `BOTTOM`. See the <<cha:pyvcp,PyVCP Chapter>> for more information.
428-
* `LATHE = 1` - Any non-empty value (including "0") causes axis to use "lathe mode" with a top view and with Radius and Diameter on the DRO.
429-
* `BACK_TOOL_LATHE = 1` - Any non-empty value (including "0") causes axis to use "back tool lathe mode" with inverted X axis.
430-
* `FOAM = 1` - Any non-empty value (including "0") causes axis to change the display for foam-cutter mode.
428+
* `LATHE = 1` - (bool) Causes axis to use "lathe mode" with a top view and with Radius and Diameter on the DRO.
429+
* `BACK_TOOL_LATHE = 1` - (bool) Causes axis to use "back tool lathe mode" with inverted X axis.
430+
* `FOAM = 1` - (bool) Causes axis to change the display for foam-cutter mode.
431431
* `GEOMETRY = XYZABCUVW` - Controls the *preview* and *backplot* of motion.
432432
This item consists of a sequence of axis letters and control characters, optionally preceded with a "-" sign:
433433

@@ -805,26 +805,26 @@ The applications can be started after a specified delay to allow for GUI-depende
805805
If no executable file is found using these names, then the user search PATH is used to find the application. +
806806
Examples:
807807
** Simulate inputs to HAL pins for testing (using sim_pin -- a simple GUI to set inputs to parameters, unconnected pins, or signals with no writers):
808-
+
808+
809809
[source,{ini}]
810810
----
811811
APP = sim_pin motion.probe-input halui.abort motion.analog-in-00
812812
----
813813
** Invoke halshow with a previuosly saved watchlist.
814814
Since LinuxCNC sets the working directory to the directory for the INI file, you can refer to files in that directory (example: my.halshow):
815-
+
815+
816816
[source,{ini}]
817817
----
818818
APP = halshow my.halshow
819819
----
820820
** Alternatively, a watchlist file identified with a full pathname could be specified:
821-
+
821+
822822
[source,{ini}]
823823
----
824824
APP = halshow ~/saved_shows/spindle.halshow
825825
----
826826
** Open halscope using a previously saved configuration:
827-
+
827+
828828
[source,{ini}]
829829
----
830830
APP = halscope -i my.halscope
@@ -846,9 +846,9 @@ ARC_BLEND_RAMP_FREQ = 100
846846

847847
The [TRAJ] section contains general parameters for the trajectory planning module in 'motion'.
848848

849-
* `ARC_BLEND_ENABLE = 1` - Turn on new TP.
849+
* `ARC_BLEND_ENABLE = 1` - (bool) Turn on new TP.
850850
If set to 0 TP uses parabolic blending (1 segment look ahead) (Default: 1).
851-
* `ARC_BLEND_FALLBACK_ENABLE = 0` - Optionally fall back to parabolic blends if the estimated speed is faster.
851+
* `ARC_BLEND_FALLBACK_ENABLE = 0` - (bool) Optionally fall back to parabolic blends if the estimated speed is faster.
852852
However, this estimate is rough, and it seems that just disabling it gives better performance (Default: 0).
853853
* `ARC_BLEND_OPTIMIZATION_DEPTH = 50` - Look ahead depth in number of segments.
854854
+
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
= linuxcnc_check_ini(1)
2+
3+
== NAME
4+
5+
linuxcnc_check_ini - LinuxCNC INI-file configuration checker
6+
7+
== SYNOPSIS
8+
9+
*linuxcnc_check_ini* [_-e_] [_-h_] _INIfile_
10+
11+
== DESCRIPTION
12+
13+
The *linuxcnc_check_ini* program is used to verify the LinuxCNC primary
14+
configuration. It takes the specified _INIfile_ and performs a set of sanity
15+
checks on the variables in various sections.
16+
17+
This program is called automatically from *linuxcnc(1)* as to warn the user of
18+
problems that may exist in the configuration. The tests are not exhaustive
19+
and *linuxcnc_check_ini* does _not_ protect your machine or hardware. It merely
20+
ensures some basic consistency in the configuration setup. You must not rely on
21+
passing the *linuxcnc_check_ini* tests to have a functional machine.
22+
23+
== OPTIONS
24+
25+
*-e*,*--error*::
26+
Treat warnings as errors
27+
28+
*-h*,*--help*::
29+
Shows brief help message
30+
31+
== EXIT VALUE
32+
33+
The exit value is 0 (zero) when no errors are detected and the program runs
34+
successfully.
35+
36+
The exit value is 1 (one) if any errors are detected.
37+
Additionally, if the *--error* option was specified, then any detected warnings
38+
also cause the exit value be 1 (one).
39+
40+
The exit value is 2 (two) in case of any other problem.
41+
42+
== SEE ALSO
43+
44+
*linuxcnc(1)*
45+
46+
== AUTHOR
47+
48+
This man page written by B.Stultiens, as part of the LinuxCNC Enhanced
49+
Machine Controller project.
50+
51+
== REPORTING BUGS
52+
53+
Please report any bugs at https://github.com/LinuxCNC/linuxcnc.
54+
55+
== COPYRIGHT
56+
57+
Copyright © 2026 The LinuxCNC authors.
58+
59+
This is free software; see the source for copying conditions. There is
60+
NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
61+
PURPOSE.

scripts/linuxcnc.in

Lines changed: 3 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -356,41 +356,6 @@ if [ -z "$INIFILE" ] ; then
356356
exit 0
357357
fi
358358

359-
# There is an INI-reader in the Tcl code (parse_ini in tcl/linuxcnc.tcl), but
360-
# that cannot read or enforce the new INI-file format. The Tcl version does not
361-
# handle includes, strings, continuations and comments. The includes were
362-
# previously handled in here by generating a patched-up INI-file. We now do the
363-
# same, but ensure the enforce the new format. We can generate a predigested
364-
# version of the INI-file using the inivalue program.
365-
# FIXME: This hack should be removed as soon as all the legacy Tcl code using
366-
# INI values has been replaced with python code.
367-
function make_ini_for_tcl() {
368-
inifile="$1"
369-
[ -r "$inifile" ] || { echo "E: Cannot read '$inifile'"; exit 1; }
370-
inidir="$(dirname "$inifile")"
371-
outfile="$inidir/$(basename "$inifile").expanded"
372-
# Fall back to a per-user cache dir if the inifile's directory is not
373-
# writable (e.g. installed sample configs under /usr/share/doc/linuxcnc/).
374-
if ! [ -w "$inidir" ]; then
375-
cachedir="${XDG_RUNTIME_DIR:-${TMPDIR:-/tmp}}/linuxcnc-$UID"
376-
mkdir -p "$cachedir" || { echo "E: Could not create cache dir '$cachedir'"; exit 1; }
377-
outfile="$cachedir/$(basename "$inifile").expanded"
378-
fi
379-
export LINUXCNC_INI_EXPANDED="$outfile"
380-
true >|"$outfile" || { echo "E: Could not create expanded inifile '$outfile' for Tcl"; exit 1; }
381-
{
382-
echo "#*** Source: $inifile"
383-
echo "#*** Created: $(date)"
384-
echo "#*** Autogenerated INI-file using linuxcnc for tcl/linuxcnc.tcl:parse_ini()"
385-
echo
386-
} >> "$outfile"
387-
# For all sections, output the variables as parsed
388-
for s in $(inivalue --sections "$inifile"); do
389-
echo "[$s]" >> "$outfile"
390-
inivalue --variables --content --sec "$s" "$inifile" >> "$outfile"
391-
done
392-
}
393-
394359
function split_app_items () {
395360
app_name=$1
396361
shift
@@ -443,10 +408,6 @@ function run_applications () {
443408
# a parse error in the file or it is empty.
444409
inivalue "$INIFILE" > /dev/null || { echo "E: The INI-file contains errors that need to be fixed."; exit 1; }
445410

446-
# The resulting INI-file for Tcl will be called "${INIFILE}.expanded"
447-
# See comment above the function why this is necessary.
448-
make_ini_for_tcl "$INIFILE"
449-
450411
# delete directories from path, save name only
451412
INI_NAME="${INIFILE##*/}"
452413
INI_DIR="${INIFILE%/*}"
@@ -525,12 +486,12 @@ if [ "$retval" != "1.1" ]; then
525486
esac
526487
fi
527488

528-
@TCLSH@ "$HALLIB_DIR/check_config.tcl" "$INIFILE"
489+
linuxcnc_check_ini "$INIFILE"
529490
exitval=$?
530491
case "$exitval" in
531492
0) ;;
532-
1) echo "check_config validation failed"; exit $exitval ;;
533-
*) echo "check_config validation failed in an unexpected way."; exit $exitval ;;
493+
1) echo "linuxcnc_check_ini validation failed"; exit $exitval ;;
494+
*) echo "linuxcnc_check_ini validation failed in an unexpected way."; exit $exitval ;;
534495
esac
535496
# 2.2. get param file
536497

src/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,7 @@ install-kernel-indep: install-dirs
688688
$(EXE) ../scripts/gladevcp_demo $(DESTDIR)$(bindir)
689689
$(EXE) ../scripts/linuxcncmkdesktop $(DESTDIR)$(bindir)
690690
$(EXE) ../bin/update_ini $(DESTDIR)$(bindir)
691+
$(EXE) ../bin/linuxcnc_check_ini $(DESTDIR)$(bindir)
691692
$(EXE) ../scripts/halreport $(DESTDIR)$(bindir)
692693
$(FILE) $(filter ../lib/%.a ../lib/%.so.0 ../lib/%.so.1,$(TARGETS)) $(DESTDIR)$(libdir)
693694
cp --no-dereference $(wildcard ../lib/*.so) $(DESTDIR)$(libdir)

src/emc/ini/Submakefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,12 @@ TARGETS += ../bin/inivar
4646
$(ECHO) Copying python script $(notdir $@)
4747
$(Q)(echo '#!$(PYTHON)'; sed '1 { /^#!/d; }' $<) > $@.tmp && chmod +x $@.tmp && mv -f $@.tmp $@
4848

49+
# Ini-file checker at linuxcnc start
50+
../bin/linuxcnc_check_ini: emc/ini/linuxcnc_check_ini.py
51+
@$(ECHO) Syntax checking python script $(notdir $@)
52+
$(Q)$(PYTHON) -m py_compile $<
53+
$(ECHO) Copying python script $(notdir $@)
54+
$(Q)(echo '#!$(PYTHON)'; sed '1 { /^#!/d; }' $<) > $@.tmp && chmod +x $@.tmp && mv -f $@.tmp $@
55+
4956
PYTARGETS += ../bin/update_ini
57+
PYTARGETS += ../bin/linuxcnc_check_ini

src/emc/ini/iniaxis.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,15 @@ static int loadAxis(int axis, const IniFile &ini)
6262
std::string axisSection = fmt::format("AXIS_{}", "XYZABCUVW"[axis]);
6363

6464
// set min position limit
65-
double limit = ini.findRealV("MIN_LIMIT", axisSection, -1e99);
65+
double limit = ini.findRealV("MIN_LIMIT", axisSection, DEFAULT_AXIS_MIN_LIMIT);
6666
if (0 != emcAxisSetMinPositionLimit(axis, limit)) {
6767
print_dbg_config("emcAxisSetMinPositionLimit");
6868
return -1;
6969
}
7070
old_inihal_data.axis_min_limit[axis] = limit;
7171

7272
// set max position limit
73-
limit = ini.findRealV("MAX_LIMIT", axisSection, 1e99);
73+
limit = ini.findRealV("MAX_LIMIT", axisSection, DEFAULT_AXIS_MAX_LIMIT);
7474
if (0 != emcAxisSetMaxPositionLimit(axis, limit)) {
7575
print_dbg_config("emcAxisSetMaxPositionLimit");
7676
return -1;

0 commit comments

Comments
 (0)