Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
150 commits
Select commit Hold shift + click to select a range
2a9ecc8
first commit
rcannood Aug 12, 2024
77cd691
fix usage of wrong varible
rcannood Aug 12, 2024
8190a76
fix missing $
rcannood Aug 12, 2024
a0b8c62
fix variables again
rcannood Aug 12, 2024
8d96497
unset first, just in case
rcannood Aug 12, 2024
3b96160
replace `IFS=... for var in $myarg` with `for i in ${!myarg[@]}`
rcannood Aug 12, 2024
5aaa7df
fix type mismatch error
rcannood Aug 12, 2024
df650b1
move dependencies to mods
rcannood Aug 12, 2024
2b81cc9
wip helper functions
rcannood Aug 12, 2024
af2bf7f
rename helper functions
rcannood Aug 13, 2024
140d2f9
fixes to generated code
rcannood Aug 13, 2024
b47957a
add more comments
rcannood Aug 13, 2024
4e016be
remove unused code
rcannood Aug 13, 2024
6ffee93
make certain BashWrapper functions private
rcannood Aug 13, 2024
aaea0ef
Merge remote-tracking branch 'origin/develop' into switch_to_arrays
rcannood Aug 14, 2024
147290d
improve yaml rendering
rcannood Aug 14, 2024
921fa8b
fixes
rcannood Aug 14, 2024
653b328
more fixes
rcannood Aug 14, 2024
18f594b
only input multiples are arrays
rcannood Aug 14, 2024
9b0d19c
Merge remote-tracking branch 'origin/develop' into switch_to_arrays
rcannood Dec 16, 2024
488aab5
wip add tests
rcannood Dec 16, 2024
c6086b3
implement escaping en quoting during bashwrapper parsing
rcannood Mar 4, 2025
d633599
Merge remote-tracking branch 'origin/develop_0_9' into switch_to_arrays
rcannood Mar 4, 2025
feda25b
fix renderyaml function
rcannood Mar 6, 2025
c8181c9
add docs
rcannood Mar 6, 2025
5ba4936
unset variables if they contain @@VIASH_UNDEFINED@@
rcannood Mar 6, 2025
a1b2db8
Merge branch 'develop' into switch_to_arrays
rcannood Mar 6, 2025
f9a149a
wip python render attempt
rcannood Mar 24, 2025
16189fd
create languages with viash yaml parsers
rcannood Aug 28, 2025
09a415a
add a unit test
rcannood Aug 28, 2025
c7df019
restructure code
rcannood Aug 28, 2025
a996fa2
fix parsers, add tests
rcannood Aug 28, 2025
eec566e
fix tests and parsers
rcannood Aug 28, 2025
0e7c6b9
try to create script in local tempdir
rcannood Aug 30, 2025
23fbde8
switch to json parsers
rcannood Oct 5, 2025
0c93222
add tests
rcannood Oct 5, 2025
31706ec
refactor languages <> scripts
rcannood Oct 6, 2025
aad8b1e
fix run cmd in bashwrapper
rcannood Jan 6, 2026
f40e313
fix viash json rendering indentation
rcannood Jan 6, 2026
506ab7b
fix scala parse json test
rcannood Jan 6, 2026
f9aaf74
add json parser test suite
rcannood Jan 6, 2026
0e2635a
Merge remote-tracking branch 'origin/main' into switch_to_arrays
rcannood Jan 6, 2026
455c56c
fix nextflow helper
rcannood Jan 6, 2026
9994f0a
wip extra test
rcannood Jan 6, 2026
9917e15
refactor script generation
rcannood Jan 7, 2026
54051fb
fix set wd to resources
rcannood Jan 7, 2026
2ce6165
dot is now included in the extension
rcannood Jan 7, 2026
204bd46
add progress file
rcannood Feb 4, 2026
fb0aa54
move injectionmods code
rcannood Feb 4, 2026
d3bf526
fix r component
rcannood Feb 4, 2026
3656b0a
bump minimum docker version to 4.4 (due to declare -g)
rcannood Feb 4, 2026
90a3ea4
fix bash json parser
rcannood Feb 4, 2026
5b0887e
fix bash json parser test
rcannood Feb 4, 2026
3d7e625
improve unit test to get more info on what failed
rcannood Feb 4, 2026
7dfeaa8
fix bash component
rcannood Feb 4, 2026
80db78d
add cleanup registry to make sure multiple trap calls don't override …
rcannood Feb 4, 2026
48816d0
remove outdated code
rcannood Feb 4, 2026
f3eda80
add tests for the viashcleanupregistry
rcannood Feb 4, 2026
fd6e904
automate running tests
rcannood Feb 4, 2026
5f0919d
fix scala parsers
rcannood Feb 4, 2026
db7f390
fix component
rcannood Feb 4, 2026
ca5b341
use anonymous class
rcannood Feb 4, 2026
d4cc5b4
fix javascript component and code
rcannood Feb 4, 2026
497aaa5
add override
rcannood Feb 4, 2026
36a408d
update progress
rcannood Feb 4, 2026
ee134ea
fix executable
rcannood Feb 4, 2026
bd99bc9
Wip refactor nextflow runner
rcannood Feb 5, 2026
d83ed67
fix tests
rcannood Feb 5, 2026
64e4afd
fix quoting when checking choices
rcannood Feb 5, 2026
a9fe7cd
add touch command
rcannood Feb 5, 2026
b6f9253
fix tests
rcannood Feb 5, 2026
0daab8d
refactor viash config inject
rcannood Feb 5, 2026
db9d12f
fix testbash component
rcannood Feb 5, 2026
e686384
fix test
rcannood Feb 5, 2026
90e88ed
reduce verbosity
rcannood Feb 5, 2026
30a5b7f
fix tests
rcannood Feb 5, 2026
5c21ebc
fix test
rcannood Feb 5, 2026
703c1d5
fix mount detection
rcannood Feb 5, 2026
74f60ec
fix warning message
rcannood Feb 5, 2026
08585b4
fix test
rcannood Feb 5, 2026
17bbc6a
fix description
rcannood Feb 5, 2026
8ea7cba
update viash par
rcannood Feb 5, 2026
28f72cc
fix tests
rcannood Feb 5, 2026
2221898
fix formatting
rcannood Feb 5, 2026
c62e05e
fix trap
rcannood Feb 5, 2026
8047edd
try to fix missing scala and dotnet dependencies
rcannood Feb 5, 2026
945c4b5
try to make bash 3.2 compatible
rcannood Feb 5, 2026
bb5f624
switch back to bash 3.2
rcannood Feb 5, 2026
59a0441
fix error message
rcannood Feb 5, 2026
ea7181d
fix test
rcannood Feb 6, 2026
0b017c2
fix escaping
rcannood Feb 6, 2026
b3c45ff
extgend test
rcannood Feb 6, 2026
dde9866
add tests for renderjson function
rcannood Feb 6, 2026
1d42dfb
adjust helper functions, expand tests
rcannood Feb 6, 2026
35f5770
expand tests; fix summary
rcannood Feb 6, 2026
6940137
fixes for viashrenderjson
rcannood Feb 6, 2026
081dede
fix test
rcannood Feb 6, 2026
bed0048
add more tests
rcannood Feb 6, 2026
99599c1
add additional tests
rcannood Feb 6, 2026
ec26dab
add test
rcannood Feb 6, 2026
affe704
add bashutil test
rcannood Feb 6, 2026
4106a7d
refactor bash util test suite
rcannood Feb 6, 2026
7c79c82
fix viashparsejson
rcannood Feb 6, 2026
57ca1d2
remove debug notes
rcannood Feb 6, 2026
e593aad
update test
rcannood Feb 6, 2026
0e51167
store work dir inside current temp dir for ease of debugging
rcannood Feb 6, 2026
902538c
resolve issue with temp dir on mac os x
rcannood Feb 6, 2026
72077fe
try to fix viash parse argument with native bash instead of awk
rcannood Feb 6, 2026
33ec42f
refactor example code
rcannood Feb 6, 2026
b8914c9
add entry to changelog
rcannood Feb 6, 2026
148a20c
update intermediate progress file
rcannood Feb 6, 2026
2459362
remove intermediate progress file
rcannood Feb 6, 2026
dc0e838
Merge remote-tracking branch 'origin/main' into switch_to_arrays
rcannood Feb 6, 2026
5a2915d
fix edge cases
rcannood Feb 6, 2026
2a958d4
fix test
rcannood Feb 6, 2026
8a36ea8
update docs
rcannood Feb 6, 2026
fe002a9
update changelog
rcannood Feb 6, 2026
64d35fd
unset memory and cpus with UNDEFINED
rcannood Feb 6, 2026
9b574b1
satisfy linter
rcannood Feb 6, 2026
143e171
Add nasty_val to break test
tverbeiren Feb 9, 2026
04bf128
con't wrap testexecutable as nextflow
rcannood Feb 10, 2026
387f527
fix test
rcannood Feb 10, 2026
c364088
fix renderjson function
rcannood Feb 10, 2026
0d3a51a
add test to verify fix
rcannood Feb 10, 2026
768dce8
validate unquoted values
rcannood Feb 10, 2026
a0b4e6b
Merge branch 'switch_to_arrays' of github.com:viash-io/viash into swi…
rcannood Feb 10, 2026
4056fde
fix curly brackets in strings for bash json parser (#868)
hcannoodt Feb 10, 2026
c640a6d
add improved json parser
rcannood Feb 10, 2026
2428ed9
improve speed
rcannood Feb 10, 2026
3d7ebdf
Improved bash json parser (#869)
Feb 10, 2026
fe7238f
improve parser
rcannood Feb 23, 2026
46ca704
Implement hybrid approach
rcannood Feb 24, 2026
e617a71
add argument
rcannood Feb 24, 2026
da4fac8
Update tests
rcannood Feb 24, 2026
34416d7
Merge branch 'switch_to_arrays' of github.com:viash-io/viash into swi…
rcannood Feb 24, 2026
51f6fa2
move regular json parser to compatibility; add new jq parser
rcannood Feb 24, 2026
9a56fce
add argument to bash script
rcannood Feb 24, 2026
b2bb497
simplify code
rcannood Feb 24, 2026
0823264
update tests
rcannood Feb 25, 2026
cead8e3
fix imports
rcannood Feb 25, 2026
004c818
extend unit tests
rcannood Feb 25, 2026
8d5c0b0
update components
rcannood Feb 25, 2026
1f36e41
add tests
rcannood Feb 25, 2026
a642893
unset arguments before assignment
rcannood Feb 25, 2026
14ae37b
add jq as dependency
rcannood Feb 25, 2026
f835923
fix tests
rcannood Feb 26, 2026
b3fb0b6
fix tests
rcannood Feb 26, 2026
46b6f62
update old image definitions for js and r (#872)
hcannoodt Feb 27, 2026
c59ea32
Merge branch 'main' into switch_to_arrays
hcannoodt Mar 4, 2026
ce6b187
fix scala json test
hcannoodt Mar 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions .github/workflows/sbt_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,34 @@ jobs:
- name: Set up sbt
uses: sbt/setup-sbt@v1

- name: Set up Scala
- name: Set up Scala (via Coursier)
uses: coursier/setup-action@v2
with:
apps: scala:3.6.2 bloop

- name: Warm up scala
run: |
if [[ "${{ matrix.config.os }}" =~ ^macos.*$ ]]; then
brew install scala
else
sudo apt-get update
sudo apt-get install -y scala
fi
# start the bloop server, it'll download a lot of dependencies, so do it early
# also we need to start it before running any scala code, otherwise it will often timeout and cause the whole job to fail
bloop server &
for i in $(seq 1 30); do
timeout 5 bloop about 2>/dev/null && echo "Bloop is ready!" && break
echo "Waiting for Bloop... ($i/30)"
sleep 2
done

scala -version
scala -e 'println("Hello, Scala!")'

- name: Set up .NET SDK
if: ${{ runner.os == 'Linux' }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'

- name: Set up dotnet-script
if: ${{ runner.os == 'Linux' }}
run: dotnet tool install -g dotnet-script

- name: Set up Python
uses: actions/setup-python@v6
Expand Down Expand Up @@ -91,7 +111,7 @@ jobs:

- name: Upload check results on fail
if: failure()
uses: actions/upload-artifact@master
uses: actions/upload-artifact@v6
with:
name: ${{ matrix.config.name }}_results
path: check
20 changes: 20 additions & 0 deletions CHANGELOGS/CHANGELOG_0.10.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ TODO add summary
This allows for running a component without having to build it first.
Example: `viash run vsh://toolbox@v0.1.0/yq -- --input input.yaml --output output.yaml`.

* `Parameter passing`: Add support for unsetting argument values and computational requirements at runtime (PR #762, fixes #375).
* Pass the literal `UNDEFINED` (unquoted) to set a single-value argument to undefined/null: `./my_component --arg UNDEFINED`
* Pass `UNDEFINED_ITEM` as a value in a multi-value argument to represent a missing item: `./my_component --args "value1;UNDEFINED_ITEM;value3"`
* Unset computational requirements with `---cpus UNDEFINED` or `---memory UNDEFINED`
* Quote the values (`'"UNDEFINED"'` or `"'UNDEFINED'"`) to pass the literal string `UNDEFINED` instead of null.

## BREAKING CHANGES

Expand All @@ -19,10 +24,25 @@ TODO add summary

* Remove deprecated functionality `functionality` and `platforms` (PR #832).

* `Bash scripts`: Arguments with `multiple: true` are now stored as bash arrays instead of semicolon-separated strings (PR #762).
Update scripts to use array syntax: `for item in "${par_inputs[@]}"; do ...` instead of IFS splitting.

## BUG FIXES

* `NextflowRunner`: Automatically convert integers to doubles when argument type is `double` (port of PR #824, PR #825).

* `Parameter passing`: Fix handling of special characters in argument values (PR #762, fixes #619, #705, #763, #821, #840).
* Backticks in argument values no longer cause command substitution
* Backslash-quote sequences (`\'`) no longer break Python syntax
* Dollar signs, newlines, and other special characters are properly preserved

## MINOR FIXES

* `Executable`: Add more info to the --help (PR #802).

## INTERNAL CHANGES

* `Parameter passing`: Switch from code injection to JSON-based parameter passing (PR #762).
Instead of injecting argument values directly into script code, values are now stored in a JSON file
(`params.json`) and parsed at runtime using language-specific JSON parsers. This approach is more
robust, easier to debug, and handles special characters (backticks, quotes, newlines) correctly.
6 changes: 5 additions & 1 deletion Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ $(obj): $(shell find src/ -name "*.scala")
cat src/stub.sh target/viash.jar > $(obj)
chmod +x $(obj)
@echo "==================================> $(obj)"


touch: $(obj)
@echo "Touching src/main/scala/io/viash/Main.scala to trigger rebuild"
touch src/main/scala/io/viash/Main.scala

tools: $(obj) $(shell find src/viash)
bin/viash ns build -s src/viash -t bin --flatten -c ".version := '$(VERSION)'"
@echo "==================================> tools"
Expand Down
28 changes: 28 additions & 0 deletions docs/reference/viash_code_block/index.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,28 @@ The `par` object (or `par_` environment variables in Bash) will contain argument
Try adding more [arguments]({{< var reference.arguments >}}) with different types to see what effect this has on the resulting placeholder.
:::

### Special values: undefined and missing items

When calling a Viash component, you can use special values to explicitly set arguments to undefined or represent missing items in multi-value arguments:

* **Unsetting a single-value argument**: Pass the literal `UNDEFINED` (unquoted) to set a single-value argument to undefined/null:
```bash
./my_component --arg UNDEFINED
```
In the script, `par["arg"]` will be `None` (Python), `NULL` (R), `null` (JavaScript), or unset (Bash).

* **Missing items in multi-value arguments**: When passing multiple values via semicolon-separated syntax, use `UNDEFINED_ITEM` to represent a missing element:
```bash
./my_component --values "item1;UNDEFINED_ITEM;item3"
```
In the script, `par["values"]` will be `["item1", None, "item3"]` (Python) or equivalent.

* **Passing the literal string "UNDEFINED"**: Quote the value to pass it as a literal string:
```bash
./my_component --arg '"UNDEFINED"' # par["arg"] = "UNDEFINED"
./my_component --arg "'UNDEFINED'" # par["arg"] = "UNDEFINED"
```

## Meta variables in `meta`

Meta-variables offer information on the runtime environment which you can use from within your script.
Expand Down Expand Up @@ -215,6 +237,9 @@ viash test config.vsh.yaml --cpus 10
viash build config.vsh.yaml -o output
output/my_executable ---cpus 10
# ↑ notice the triple dash

# to unset a default cpu value, pass UNDEFINED
output/my_executable ---cpus UNDEFINED
```

### `config` (string)
Expand Down Expand Up @@ -267,6 +292,9 @@ viash test config.vsh.yaml --memory 2GB
viash build config.vsh.yaml -o output
output/my_executable ---memory 2GB
# ↑ notice the triple dash

# to unset a default memory value, pass UNDEFINED
output/my_executable ---memory UNDEFINED
```

### `resources_dir` (string)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Cleanup handler registry
# Allows multiple cleanup functions to be registered and called on exit

# Array to store registered cleanup function names
VIASH_CLEANUP_HANDLERS=()

# ViashRegisterCleanup: Register a cleanup function to be called on exit
# $1: Name of the function to call during cleanup
# usage: ViashRegisterCleanup my_cleanup_function
function ViashRegisterCleanup {
local handler="$1"
VIASH_CLEANUP_HANDLERS+=("$handler")
}

# ViashRunCleanupHandlers: Run all registered cleanup handlers in reverse order
# This function is meant to be used as the EXIT trap handler
function ViashRunCleanupHandlers {
# Run handlers in reverse order (LIFO - last registered runs first)
local i
for (( i=${#VIASH_CLEANUP_HANDLERS[@]}-1 ; i>=0 ; i-- )); do
local handler="${VIASH_CLEANUP_HANDLERS[$i]}"
if type "$handler" &>/dev/null; then
ViashDebug "Running cleanup handler: $handler"
"$handler"
fi
done
}

# Set up the master EXIT trap that runs all registered handlers
trap ViashRunCleanupHandlers EXIT
11 changes: 7 additions & 4 deletions src/main/resources/io/viash/helpers/bashutils/ViashDockerFuns.sh
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ function ViashDockerSetup {
# $1 : image identifier with format `[registry/]image[:tag]`
# $@ : commands to verify being present
# examples:
# ViashDockerCheckCommands bash:4.0 bash ps foo
# ViashDockerCheckCommands bash:3.2 bash ps foo
function ViashDockerCheckCommands {
local image_id="$1"
shift 1
Expand Down Expand Up @@ -220,10 +220,13 @@ function ViashDockerBuild {
# create temporary directory to store dockerfile & optional resources in
local tmpdir=$(mktemp -d "$VIASH_META_TEMP_DIR/dockerbuild-$VIASH_META_NAME-XXXXXX")
local dockerfile="$tmpdir/Dockerfile"
function clean_up {
rm -rf "$tmpdir"

# Use a unique cleanup function name to avoid conflicts
VIASH_DOCKER_BUILD_TMPDIR="$tmpdir"
function ViashDockerBuildCleanup {
rm -rf "$VIASH_DOCKER_BUILD_TMPDIR"
}
trap clean_up EXIT
ViashRegisterCleanup ViashDockerBuildCleanup

# store dockerfile and resources
ViashDockerfile "$VIASH_ENGINE_ID" > "$dockerfile"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
# ViashParseArgumentValue: Parse the value of an argument
#
# This script is used by to parse the value of an argument and set
# the corresponding environment variable.
#
# If the argument is multiple: false:
#
# * If the variable is already set, an error is thrown.
# * If the value is equal to UNDEFINED, it is replaced with
# @@VIASH_UNDEFINED@@.
# * If the value is quoted, the quotes are removed.
#
# If the argument is multiple: true:
#
# * If the value is equal to UNDEFINED, it is replaced with
# @@VIASH_UNDEFINED@@.
# * If the value is quoted, the quotes are removed.
# * If the value is a list of values, the values are split by semicolons.
# * If the value contains escaped characters '"\;, they are unescaped.
#
# Arguments:
# $1: The name of an argument (used for error messages)
# $2: The name of the environment variable to set
# $3: Whether the argument can be passed multiple times (true/false)
# $4: The value of the argument
# return: None, but sets the environment variable
#
# Examples:
#
# ViashParseArgumentValue "--input" "par_input" "true" "'UNDEFINED'" "false"
#
# See ViashParseArgumentValue.test.sh for additional examples.
#
# Note: This function is written to be compatible with bash 3.2 (macOS default)
# and avoids bash 4+ features like declare -g, local -n, ${var@Q}, and readarray.
function ViashParseArgumentValue {
local flag="$1"
local env_name="$2"
local multiple="$3"
local value="$4"

if [ $# -lt 4 ]; then
ViashError "Not enough arguments passed to ${flag}. Use '--help' to get more information on the parameters."
exit 1
fi

if [ "$multiple" == "false" ]; then
# check whether the variable is already set (bash 3.2 compatible)
eval "local is_set=\${${env_name}+x}"
if [ ! -z "$is_set" ]; then
eval "local prev_value=\"\${$env_name}\""
ViashError "Pass only one argument to argument '${flag}'. Found: '${prev_value}' & '${value}'"
exit 1
fi

value=$(ViashParseSingleString "$value")

# set the variable globally (bash 3.2 compatible - using eval instead of declare -g)
# use printf %q to safely escape the value for eval to prevent backtick/command substitution
local escaped_value
escaped_value=$(printf '%q' "$value")
eval "$env_name=$escaped_value"
else
# Get existing array values (bash 3.2 compatible)
eval "local prev_values=(\"\${${env_name}[@]}\")"

# Parse new values into array (bash 3.2 compatible - using while loop instead of readarray)
local new_values=()
while IFS= read -r line || [ -n "$line" ]; do
new_values+=("$line")
done < <(ViashParseMultipleStringAsArray "$value")

local combined_values=( "${prev_values[@]}" "${new_values[@]}" )

# if length is larger than 1 and some element is @@VIASH_UNDEFINED@@, throw error
if [ ${#combined_values[@]} -gt 1 ]; then
for element in "${combined_values[@]}"; do
if [ "$element" == "@@VIASH_UNDEFINED@@" ]; then
# bash 3.2 compatible quoting (using printf %q instead of ${var@Q})
local combined_quoted=$(printf '%q ' "${combined_values[@]}")
ViashError "Argument '${flag}': If argument value 'UNDEFINED' is passed, no other values should be provided.\nFound: ${combined_quoted}"
exit 1
fi
done
fi

# Set the global array (bash 3.2 compatible - using eval instead of declare -g -a)
eval "$env_name=(\"\${combined_values[@]}\")"
fi
}

function ViashParseSingleString() {
local value="$1"

# if value is equal to UNDEFINED, replace with @@VIASH_UNDEFINED@@
if [ "$value" == "UNDEFINED" ]; then
value="@@VIASH_UNDEFINED@@"
fi

# if value is quoted, remove the quotes
if [[ "$value" =~ ^\".*\"$ ]]; then
value="${value:1:${#value}-2}"
elif [[ "$value" =~ ^\'.*\'$ ]]; then
value="${value:1:${#value}-2}"
fi

echo "$value"
}

function ViashParseMultipleStringAsArray() {
local value="$1"

# if value is equal to UNDEFINED, replace with @@VIASH_UNDEFINED@@
if [ "$value" == "UNDEFINED" ]; then
echo "@@VIASH_UNDEFINED@@"
return
fi

# if value is empty, return nothing (results in 0-length array)
if [ -z "$value" ]; then
return
fi

# Parse semicolon-separated values with proper quote handling
# This is a bash-native implementation that doesn't rely on gawk's FPAT
# (which isn't available in BSD awk on macOS or BusyBox awk)
local i=0
local len=${#value}
local in_double_quote=false
local in_single_quote=false
local escape_next=false
local current_field=""
local field_was_quoted=false # Track if field started with a quote
local char

while [ $i -lt $len ]; do
char="${value:$i:1}"

if $escape_next; then
# Previous char was backslash - add escaped char to field
current_field+="$char"
escape_next=false
elif [ "$char" = "\\" ]; then
# Backslash - escape next character
escape_next=true
elif [ "$char" = '"' ] && ! $in_single_quote; then
# Toggle double quote state (unless we're in single quotes)
if $in_double_quote; then
in_double_quote=false
else
in_double_quote=true
# Mark field as quoted if this is the first char
if [ -z "$current_field" ]; then
field_was_quoted=true
fi
fi
elif [ "$char" = "'" ] && ! $in_double_quote; then
# Toggle single quote state (unless we're in double quotes)
if $in_single_quote; then
in_single_quote=false
else
in_single_quote=true
# Mark field as quoted if this is the first char
if [ -z "$current_field" ]; then
field_was_quoted=true
fi
fi
elif [ "$char" = ";" ] && ! $in_double_quote && ! $in_single_quote; then
# Semicolon outside quotes - end of field
# Handle UNDEFINED_ITEM replacement (only if not quoted)
if [ "$current_field" == "UNDEFINED_ITEM" ] && ! $field_was_quoted; then
current_field="@@VIASH_UNDEFINED_ITEM@@"
fi
echo "$current_field"
current_field=""
field_was_quoted=false
else
# Regular character - add to field
current_field+="$char"
fi

i=$((i + 1))
done

# Don't forget the last field (after the last semicolon or if no semicolon)
# Handle UNDEFINED_ITEM replacement (only if not quoted)
if [ "$current_field" == "UNDEFINED_ITEM" ] && ! $field_was_quoted; then
current_field="@@VIASH_UNDEFINED_ITEM@@"
fi
echo "$current_field"
}
Loading
Loading