cd $REPO || exit 1$ time sh -c "for i in labwc-config labwc-dev labwc-menu-generator labwc sfwbar foot appindicator-broker dino; do treegen $i $(uname -r) >$i.tcz.tree; done"
real 0m 0.03s
user 0m 0.01s
sys 0m 0.00s
$ time sh -c "for i in labwc-config labwc-dev labwc-menu-generator labwc sfwbar foot appindicator-broker dino; do deptree -d $i >$i.tcz.tree; done"
real 0m 16.11s
user 0m 11.03s
sys 0m 4.37s
#!/usr/bin/awk -f
# usage example: $ treegen.awk labwc.tcz
BEGIN {
LEVEL = 0
LINUX_VERSION = "6.18.2-tinycore64"
MIRROR_PATH = "/path/to/your/local/tinycorelinux/17.x/x86_64/tcz/"
get_dependencies(ARGV[1])
}
function get_dependencies(app, depapp) {
gsub(/KERNEL/,LINUX_VERSION,app)
for (i = 0; i < LEVEL; i++)
printf(" ")
print app
while (getline depapp < MIRROR_PATH app ".dep" > 0) {
# if (depapp ~ /\.tcz/) is there because some .dep files have blank lines.
if (depapp ~ /\.tcz/) {
LEVEL++
get_dependencies(depapp)
}
}
close(MIRROR_PATH app ".dep")
LEVEL--
} busybox ash busybox awk C++
time to generate labwc-dev.tcz.tree: 11 sec 0.43 sec 0.06 sec
time to generate vlc-dev.tcz.tree: 49 sec 1.86 sec 0.31 sec... What does surprise me is the vast difference in performance between the shell script and the awk script--especially considering that the logic and number of operations in the two scripts is exactly the same.
... Given how quickly GNU awk is able to sort provides.db, I'd say this problem is more than solved. The problem is crushed.There's a reason roberts liked to inject awk snippets into his scripts. When it
comes to data manipulation, it can be wicked fast.
I've had a few instances were I found the execution time of a script unacceptable
and was forced to add an awk function. None of my techniques could even touch
the speed of awk.
#!/usr/bin/awk -f
# treegen.awk v1.2 (April 7, 2026)
# usage example: $ treegen.awk labwc.tcz
BEGIN {
LEVEL = 0
LINUX_VERSION = "6.18.2-tinycore64"
MIRROR_PATH = "/path/to/your/local/mirror/tinycorelinux/17.x/x86_64/tcz/"
get_dependencies(ARGV[1])
}
function get_dependencies(app, depapp) {
gsub(/KERNEL/,LINUX_VERSION,app)
for (i = 0; i < LEVEL; i++)
printf(" ")
printf("%s\n", app)
while (getline depapp <(MIRROR_PATH app ".dep") > 0) {
if (depapp ~ /\.tcz/) { # because some .dep files have blank lines
LEVEL++
get_dependencies(depapp)
}
}
close(MIRROR_PATH app ".dep")
LEVEL--
}$ time treegen.awk vlc-dev.tcz... count the number of times the get_dependencies function has been called, and bail out if that variable exceeds some appropriately large number. This could be used as a poor man's test for circular dependencies.A better way is to build a flattened version as you go:
A.tcz,B.tcz,C.tcz,D.tcz,E.tczBefore appending the next tcz to the flattened list, check if it exists.A.tcz,B.tcz,C.tcz,D.tcz,E.tcz,B.tcz,#!/usr/bin/awk -f
# treegen.awk v2.0 (April 8, 2026)
# usage example: $ treegen.awk labwc.tcz
BEGIN {
LEVEL = 0
LINUX_VERSION = "6.18.2-tinycore64"
MIRROR_PATH = "/mnt/usb/http/tinycorelinux/17.x/x86_64/tcz/"
get_dependencies(ARGV[1])
}
function get_dependencies(app, depapp) {
LEVEL++
gsub(/KERNEL/,LINUX_VERSION,app)
for (i = 1; i < LEVEL; i++)
printf(" ")
printf("%s\n", app)
if (getline depapp <(MIRROR_PATH app ".dep") > 0) {
do {
if (depapp ~ /\.tcz/) # because some .dep files have blank lines
get_dependencies(depapp)
} while (getline depapp <(MIRROR_PATH app ".dep") > 0)
close(MIRROR_PATH app ".dep")
}
LEVEL--
} Here's final tally of busybox ash vs. busybox awk vs. C++ implementations of treegen. All three implementations parse .dep files present on the local mirror (without using network/wget):I decided to try my hand at a busybox ash version.busybox ash busybox awk C++...
time to generate labwc-dev.tcz.tree: 11 sec 0.43 sec 0.06 sec
time to generate vlc-dev.tcz.tree: 49 sec 1.86 sec 0.31 sec
tc@E310:~/TreeGen$ time ./treegen.awk vlc-dev.tcz > vlc-dev.tcz.tree2
real 0m 8.49s
user 0m 3.56s
sys 0m 4.92stc@E310:~/TreeGen$ time ./TreeGen.sh vlc-dev
6.25
real 0m 6.27s
user 0m 3.71s
sys 0m 2.52stc@E310:~/TreeGen$ ls -l vlc*
-rw-r--r-- 1 tc staff 1879760 Apr 23 00:56 vlc-dev.tcz.tree <------ ash version
-rw-r--r-- 1 tc staff 1839796 Mar 30 13:48 vlc-dev.tcz.tree.bak <-- repo version
-rw-r--r-- 1 tc staff 1839795 Apr 22 22:53 vlc-dev.tcz.tree2 <----- awk versionThe repo versio is 1 byte longer than yours. It has an extra newline at the end of the file.tc@E310:~/TreeGen$ wc -l vlc-dev.tcz.tree*
41437 vlc-dev.tcz.tree <------ ash version
40528 vlc-dev.tcz.tree.bak <-- repo version
40527 vlc-dev.tcz.tree2 <----- awk version 3498 libsndfile-dev.tcz
3499 libsndfile.tcz
3500 flac.tcz
3501 libogg.tcz
3502 libvorbis.tcz
3503 libogg.tcz
3504 opus.tcz
3505 libmpg123.tcz
3506 lame.tcz
3507 flac-dev.tcz
3508 libvorbis-dev.tcz
3509 libbluetooth-dev.tcz 3498 libsndfile-dev.tcz
3499 libsndfile.tcz
3500 flac.tcz
3501 libogg.tcz
3502 libvorbis.tcz
3503 libogg.tcz
3504 opus.tcz
3505 libmpg123.tcz
3506 lame.tcz
3507 flac-dev.tcz
3508 flac.tcz
3509 libogg.tcz
3510 libogg-dev.tcz
3511 libogg.tcz
3512 libvorbis-dev.tcz
3513 libvorbis.tcz
3514 libogg.tcz
3515 libogg-dev.tcz
3516 libogg.tcz
3517 libbluetooth-dev.tcztc@E310:~/TreeGen$ grep " " DepFiles/libsndfile-dev.tcz.dep | tr " " "_"
flac-dev.tcz_
libvorbis-dev.tcz___The trailing spaces on those 2 entries are tripping up the C++ and awk programs.tc@E310:~/TreeGen$ grep " " DepFiles/* | tr " " "_"
DepFiles/acl.tcz.dep:_
DepFiles/libsane.tcz.dep:libavahi.tcz_____
DepFiles/libsndfile-dev.tcz.dep:flac-dev.tcz_
DepFiles/libsndfile-dev.tcz.dep:libvorbis-dev.tcz___
DepFiles/libsndfile.tcz.dep:libmpg123.tcz_
DepFiles/sane-dev.tcz.dep:avahi-dev.tcz__
DepFiles/taglib-dev.tcz.dep:taglib.tcz___________________________________There are a handful of entries with trailing spaces.tc@E310:~/TreeGen$ ./treegen.awk libsndfile-dev.tcz
libsndfile-dev.tcz
libsndfile.tcz
flac.tcz
libogg.tcz
libvorbis.tcz
libogg.tcz
opus.tcz
libmpg123.tcz
lame.tcz
flac-dev.tcz
libvorbis-dev.tczIt reports flac-dev.tcz and libvorbis-dev.tcz have no dependencies.tc@E310:~/TreeGen$ ./treegen.awk flac-dev.tcz
flac-dev.tcz
flac.tcz
libogg.tcz
libogg-dev.tcz
libogg.tcz
tc@E310:~/TreeGen$ ./treegen.awk libvorbis-dev.tcz
libvorbis-dev.tcz
libvorbis.tcz
libogg.tcz
libogg-dev.tcz
libogg.tczKernel="6.18.2-tinycore64"
Repo="DepFiles/"./TreeGen.sh FilenameThe script adds .tcz automatically if you omit it.... I think this is as good as I can make it. If anyone finds a bug ...Well, I pointed out a bug in my last post (not processing filenames with trailing spaces).
if (depapp ~ /\.tcz/) # because some .dep files have blank lines... or an optimization that I missed, please do share. ...
... I decided to try my hand at a busybox ash version.
Using your busybox awk as a benchmark, I got:Code: [Select]tc@E310:~/TreeGen$ time ./treegen.awk vlc-dev.tcz > vlc-dev.tcz.tree2
real 0m 8.49s
user 0m 3.56s
sys 0m 4.92s
Using my busybox ash version, I got:Code: [Select]tc@E310:~/TreeGen$ time ./TreeGen.sh vlc-dev...
6.25
real 0m 6.27s
user 0m 3.71s
sys 0m 2.52s
for (i = 1; i < LEVEL; i++)
printf(" ")To this: Width=(LEVEL - 1) * 3
printf("%"Width"s")And the execution time dropped to:tc@E310:~/TreeGen$ time ./treegen.awk vlc-dev.tcz > vlc-dev.tcz.tree2
real 0m 2.95s
user 0m 1.71s
sys 0m 1.22s Width=(LEVEL - 1) * 3
printf("%"Width"s")
printf("%s\n", app)To this: Width=(LEVEL - 1) * 3
printf("%"Width"s%s\n", "", app)And you get a further reduction in execution time:tc@E310:~/TreeGen$ time ./treegen.awk vlc-dev.tcz > vlc-dev.tcz.tree2
real 0m 2.44s
user 0m 1.45s
sys 0m 0.94s
#!/usr/bin/awk -f
# treegen.awk v2.0 (April 8, 2026)
# usage example: $ treegen.awk labwc.tcz
BEGIN {
LEVEL = 0
LINUX_VERSION = "6.18.2-tinycore64"
# MIRROR_PATH = "/mnt/usb/http/tinycorelinux/17.x/x86_64/tcz/"
MIRROR_PATH = "/home/tc/TreeGen/DepFiles/"
get_dependencies(ARGV[1])
}
function get_dependencies(app, depapp) {
gsub(/KERNEL/,LINUX_VERSION,app)
printf("%"LEVEL"s%s\n", "", app)
LEVEL+=3
if (getline depapp <(MIRROR_PATH app ".dep") > 0) {
do {
if (depapp ~ /\.tcz/) # because some .dep files have blank lines
get_dependencies(depapp)
} while (getline depapp <(MIRROR_PATH app ".dep") > 0)
close(MIRROR_PATH app ".dep")
}
LEVEL-=3
}tc@E310:~/TreeGen$ time ./treegen.awk vlc-dev.tcz > vlc-dev.tcz.tree2
real 0m 2.33s
user 0m 1.47s
sys 0m 0.84s#!/usr/bin/awk -f
# treegen.awk v3.0 (May 2, 2026)
# usage example: $ treegen.awk labwc.tcz
BEGIN {
N_SPACES = 0
LINUX_VERSION = "6.18.2-tinycore64"
# MIRROR_PATH = "/mnt/usb/http/tinycorelinux/17.x/x86_64/tcz/"
MIRROR_PATH = "/home/tc/TreeGen/DepFiles/"
get_dependencies(ARGV[1])
}
function get_dependencies(tczname, line) {
gsub(/KERNEL/, LINUX_VERSION, tczname)
printf("%"N_SPACES"s%s\n", "", tczname)
N_SPACES+=3
if (getline line <(MIRROR_PATH tczname ".dep") > 0) {
do {
if (line ~ /\.tcz/) # because some .dep files have blank lines
gsub(/\.tcz[ \t]+$/, ".tcz", line) # because some lines in .dep files have trailing whitespace
get_dependencies(line)
} while (getline line <(MIRROR_PATH tczname ".dep") > 0)
close(MIRROR_PATH tczname ".dep")
}
N_SPACES-=3
}
... We will lose some speed with the call go gsub, but it will be small because gsub is internal to awk. ...No big speed penalty:
tc@E310:~/TreeGen$ time ./treegen2.awk vlc-dev.tcz > vlc-dev.tcz.tree2
real 0m 2.35s
user 0m 1.45s
sys 0m 0.89s
tc@E310:~/TreeGen$ time ./treegen3.awk vlc-dev.tcz > vlc-dev.tcz.tree3
real 0m 2.50s
user 0m 1.56s
sys 0m 0.92stc@E310:~/TreeGen$ ls -l vlc*
-rw-r--r-- 1 tc staff 1879760 Apr 25 14:08 vlc-dev.tcz.tree <------ ash version
-rw-r--r-- 1 tc staff 1839796 Mar 30 13:48 vlc-dev.tcz.tree.bak <-- repo version
-rw-r--r-- 1 tc staff 1839795 May 2 07:35 vlc-dev.tcz.tree2
-rw-r--r-- 1 tc staff 1887792 May 2 07:35 vlc-dev.tcz.tree3 <----- awk versiontc@E310:~/TreeGen$ wc -l vlc-dev.tcz.tree*
41437 vlc-dev.tcz.tree
40528 vlc-dev.tcz.tree.bak
40527 vlc-dev.tcz.tree2
41695 vlc-dev.tcz.tree3
164187 total
tc@E310:~/TreeGen$ calc 41695-41437
258tc@E310:~/TreeGen$ busybox grep -c '^$' vlc-dev.tcz.tree3
0tc@E310:~/TreeGen$ busybox grep -c '^[[:blank:]]\+$' vlc-dev.tcz.tree3
258tc@E310:~/TreeGen$ busybox grep -c '^[[:space:]]\+$' vlc-dev.tcz.tree3
258awk '$1=$1' FileIn | sort -u > FileOutThe interesting part is awk '$1=$1' removes all whitespace.#!/usr/bin/awk -f
# treegen.awk v3.1 (May 2, 2026)
# usage example: $ treegen.awk labwc.tcz
BEGIN {
N_SPACES = 0
LINUX_VERSION = "6.18.2-tinycore64"
# MIRROR_PATH = "/mnt/usb/http/tinycorelinux/17.x/x86_64/tcz/"
MIRROR_PATH = "/home/tc/TreeGen/DepFiles/"
get_dependencies(ARGV[1])
}
function get_dependencies(tczname, line) {
gsub(/KERNEL/, LINUX_VERSION, tczname)
printf("%"N_SPACES"s%s\n", "", tczname)
N_SPACES+=3
if (getline line <(MIRROR_PATH tczname ".dep") > 0) {
do {
if (line ~ /\.tcz/) { # because some .dep files have blank lines
gsub(/\.tcz[ \t]+$/, ".tcz", line) # because some lines in .dep files have trailing whitespace
get_dependencies(line)
}
} while (getline line <(MIRROR_PATH tczname ".dep") > 0)
close(MIRROR_PATH tczname ".dep")
}
N_SPACES-=3
}
Can you please test this?tc@E310:~/TreeGen$ ls -l vlc*
-rw-r--r-- 1 tc staff 1879760 Apr 25 14:08 vlc-dev.tcz.tree <------ ash version
-rw-r--r-- 1 tc staff 1839796 Mar 30 13:48 vlc-dev.tcz.tree.bak <-- repo version
-rw-r--r-- 1 tc staff 1839795 May 2 21:59 vlc-dev.tcz.tree2
-rw-r--r-- 1 tc staff 1887792 May 2 07:35 vlc-dev.tcz.tree3
-rw-r--r-- 1 tc staff 1879760 May 2 21:59 vlc-dev.tcz.tree4 <----- awk versiontc@E310:~/TreeGen$ wc -l vlc-dev.tcz.tree*
41437 vlc-dev.tcz.tree
40528 vlc-dev.tcz.tree.bak
40527 vlc-dev.tcz.tree2
41695 vlc-dev.tcz.tree3
41437 vlc-dev.tcz.tree4tc@E310:~/TreeGen$ time ./treegen2.awk vlc-dev.tcz > vlc-dev.tcz.tree2
real 0m 2.35s
user 0m 1.54s
sys 0m 0.79s
tc@E310:~/TreeGen$ time ./treegen4.awk vlc-dev.tcz > vlc-dev.tcz.tree4
real 0m 2.47s
user 0m 1.59s
sys 0m 0.86s... P.S. The '$1=$1' trick is quite handy but I don't see an obvious way to integrate it with treegen.awk's existing logic.Yeah, I tried also but got nowhere.
I think we have a winner. ;DHi Rich. Good to hear. I'll be using this version myself :)
Out of curiosity, how long does this latest version take on your hardware?Here you go:
$ time treegen vlc-dev.tcz >/tmp/vlc-dev.tcz.tree
real 0m 0.67s
user 0m 0.40s
sys 0m 0.22sSo 1.86 sec before, 0.67 sec now. Your optimizations help a whole lot: The new version gets the job done in less than half the time, even with the call to gsub. awk C++
Size ~900 bytes ~25K bytes
Time to generate vlc-dev.tcz.tree 0.67 Secs. 0.31 Secs.
was there a robustness change needed for the repo, related to spaces and/or blank lines?Hi Paul_123. Yes, trailing whitespace in .dep files is causing problems for the c++ version of treegen. See Rich's analysis in Reply #20.
rich@tcbox:~/libsndfile$ cat libsndfile-dev.tcz.dep | tr " " "_"
libsndfile.tcz
flac-dev.tcz_
libvorbis-dev.tcz___The two -dev entries have trailing spaces.rich@tcbox:~/libsndfile$ treegen libsndfile-dev.tcz 6.18.2-tinycore64
libsndfile-dev.tcz
libsndfile.tcz
flac.tcz
libogg.tcz
libvorbis.tcz
libogg.tcz
opus.tcz
libmpg123.tcz
lame.tcz
flac-dev.tcz
libvorbis-dev.tczThe two dev entries get listed but not their dependencies.rich@tcbox:~/libsndfile$ treegen flac-dev.tcz 6.18.2-tinycore64
flac-dev.tcz
flac.tcz
libogg.tcz
libogg-dev.tcz
libogg.tcz
rich@tcbox:~/libsndfile$ treegen libvorbis-dev.tcz 6.18.2-tinycore64
libvorbis-dev.tcz
libvorbis.tcz
libogg.tcz
libogg-dev.tcz
libogg.tcz
static void nukenewline_space(char buf[]) {
unsigned src, dst;
for (src = 0, dst = 0; buf[src] != '\0'; src++) {
if (buf[src] == '\n')
break;
if (isspace((unsigned char)buf[src]))
continue;
buf[dst++] = buf[src];
}
buf[dst] = '\0';
}
If I'm reading it right:
At that point I guess the calling function discards any strings containing only
a newline character.
Only non whitespace characters are left in the string.
#!/usr/bin/awk -f
# treegen.awk v3.2 (May 5, 2026)
# usage example: $ treegen.awk labwc.tcz
BEGIN {
N_SPACES = 0
LINUX_VERSION = "6.18.2-tinycore64"
MIRROR_PATH = "/mnt/usb/http/tinycorelinux/17.x/x86_64/tcz/"
get_dependencies(ARGV[1])
}
function get_dependencies(tczname, line) {
gsub(/KERNEL/, LINUX_VERSION, tczname)
printf("%"N_SPACES"s%s\n", "", tczname)
N_SPACES+=3
if (getline line <(MIRROR_PATH tczname ".dep") > 0) {
do {
if (line ~ /\.tcz/) { # because some .dep files have blank lines
gsub(/[ \t\r]+/, "", line) # because some lines in .dep files have whitespace
get_dependencies(line)
}
} while (getline line <(MIRROR_PATH tczname ".dep") > 0)
close(MIRROR_PATH tczname ".dep")
}
N_SPACES-=3
} awk C++
Size ~900 bytes ~25K bytes
Time to generate vlc-dev.tcz.tree 0.45 Secs. 0.31 Secs.
1) Eliminates the N_SPACES += 3 / N_SPACES -= 3 mutations around every recursive call. Depth is now a pure value passed down the call stack — simpler and less error-prone.
2) %*s takes the width from the argument, avoiding the "%"N_SPACES"s" string concatenation on every call. Minor, but cleaner.
3) Use while (getline ...) (avoid the do/while pattern)
Your v2 reads the first line with if (getline ...) and then uses do { ... } while (getline ...), which does an extra getline control-flow dance. A single while loop is simpler and a bit faster.
4) Trim first, then test; avoid regex when possible
Right now you test if (line ~ /\.tcz/) then trim whitespace with a regex gsub. If most lines are blank/whitespace, trimming first lets you do a cheap suffix test.
Also: line ~ /\.tcz/ is “contains .tcz anywhere”. If dependency lines are supposed to end with .tcz, checking the suffix is both stricter and cheaper.
In awk you can do a suffix check without regex:
length(line) >= 4 && substr(line, length(line)-3) == ".tcz"
5) Replace dynamic-width format string building
printf("%"N_SPACES"s%s\n", "", tczname) rebuilds the format string each call. Prefer %*s:
printf("%*s%s\n", N_SPACES, "", tczname)
6) Minor: precompute the dep filename once per call
Don’t concatenate MIRROR_PATH tczname ".dep" multiple times.
7) Add caching, don't keep reading the same depfile over and over.
#!/usr/bin/awk -f
# treegen.awk v3.4 (May 5, 2026)
# usage example: $ treegen.awk labwc.tcz
BEGIN {
LINUX_VERSION = "6.18.2-tinycore64"
MIRROR_PATH = "/mnt/usb/http/tinycorelinux/17.x/x86_64/tcz/"
get_dependencies(ARGV[1], 0)
}
# Cache:
# loaded[pkg] = 1 once pkg.dep has been read (even if empty/missing)
# ndeps[pkg] = number of deps found
# deps[pkg, i] = ith dep (1..ndeps[pkg])
function load_depfile(pkg, depfile, line, n) {
if (loaded[pkg]) return
loaded[pkg] = 1
depfile = MIRROR_PATH pkg ".dep"
n = 0
while (getline line < depfile > 0) {
gsub(/[ \t\r]+/, "", line)
if (line == "") continue
# endswith ".tcz" is faster/stricter than /\.tcz/
L = length(line)
if (L >= 4 && substr(line, L-3) == ".tcz")
deps[pkg, ++n] = line
}
close(depfile)
ndeps[pkg] = n
}
function get_dependencies(tczname, depth, i, n) {
gsub(/KERNEL/, LINUX_VERSION, tczname)
printf("%*s%s\n", depth, "", tczname)
load_depfile(tczname)
n = ndeps[tczname]
for (i = 1; i <= n; i++) {
get_dependencies(deps[tczname, i], depth + 3)
}
}
Okay, I had time to play. Here is what AI thought of the code. There were a couple of iterations, but I just pasted it into one list. Based on my test, it cut the time in half on your vlc-dev.tcz test caseThe AI may prefer that syntax, but I used the other syntax for a reason.Quote----- Snip -----...
2) %*s takes the width from the argument, avoiding the "%"N_SPACES"s" string concatenation on every call. Minor, but cleaner.
----- Snip -----
5) Replace dynamic-width format string building
printf("%"N_SPACES"s%s\n", "", tczname) rebuilds the format string each call. Prefer %*s:
printf("%*s%s\n", N_SPACES, "", tczname)
----- Snip -----
tc@E310:~/TreeGen$ time ./treegen6.awk vlc-dev.tcz > vlc-dev.tcz.tree6
awk: ./treegen6.awk:40: %*x formats are not supported
Command exited with non-zero status 1After changing this:printf("%*s%s\n", depth, "", tczname)To this:printf("%"depth"s%s\n", "", tczname)It ran, and there was a very noticeable speed improvement.tc@E310:~/TreeGen$ time ./treegen5.awk vlc-dev.tcz > vlc-dev.tcz.tree5
real 0m 2.47s
user 0m 1.47s
sys 0m 0.96stc@E310:~/TreeGen$ time ./treegen6.awk vlc-dev.tcz > vlc-dev.tcz.tree6
real 0m 1.43s
user 0m 0.95s
sys 0m 0.47s
I saw the Dynamic format, I had missed you purposely removed it. ...Technically, the formatting is still dynamic since it's controlled by
... Man your computer is slow :)Thank you. It's plenty fast for most of my daily needs. Besides, its
tc@HP-G62:~/TreeGen$ time ./treegen5.awk vlc-dev.tcz > vlc-dev.tcz.tree5
real 0m 1.03s
user 0m 0.74s
sys 0m 0.27s
tc@HP-G62:~/TreeGen$ time ./treegen6.awk vlc-dev.tcz > vlc-dev.tcz.tree6
real 0m 0.63s
user 0m 0.51s
sys 0m 0.11stc@box:~/TreeGen$ time ./treegen5.awk vlc-dev.tcz > vlc-dev.tcz.tree5
real 0m 0.61s
user 0m 0.46s
sys 0m 0.14s
tc@box:~/TreeGen$ time ./treegen6.awk vlc-dev.tcz > vlc-dev.tcz.tree6
real 0m 0.35s
user 0m 0.30s
sys 0m 0.04s
After changing this:Code: [Select]printf("%*s%s\n", depth, "", tczname)To this:Code: [Select]printf("%"depth"s%s\n", "", tczname)
... But it only worked for me (on TCL17 x86_64 with busybox awk) after I made Rich's edit: ...That's not surprising, considering I had to make those changes for TC10, TC14, and TC16.
#!/bin/sh
xyzzy=10
printf "%*s%s\n" "$xyzzy" "" "Hi there!"tc@E310:~/TreeGen$ ./Printf
Hi there!
tc@E310:~/TreeGen$... Rich, the thread can be safely marked as "Solved" :)Done. ;D
#!/usr/bin/awk -f
# treegen.awk v3.5 (May 6, 2026)
# usage example: $ treegen.awk vlc-dev.tcz
BEGIN {
LINUX_VERSION = "6.18.2-tinycore64"
MIRROR_PATH = "/mnt/usb/http/tinycorelinux/17.x/x86_64/tcz/"
get_dependencies(ARGV[1], 0)
}
# Cache:
# loaded[pkg] = 1 once pkg.dep has been read (even if empty/missing)
# ndeps[pkg] = number of deps found
# deps[pkg, i] = ith dep (1..ndeps[pkg])
function load_depfile(pkg, depfile, line, n) {
if (loaded[pkg]) return
loaded[pkg] = 1
depfile = MIRROR_PATH pkg ".dep"
n = 0
while (getline line < depfile > 0) {
gsub(/[ \t\r]+/, "", line)
if (line == "") continue
# endswith ".tcz" is faster/stricter than /\.tcz/
L = length(line)
if (L > 4 && substr(line, L-3) == ".tcz")
deps[pkg, ++n] = line
}
close(depfile)
ndeps[pkg] = n
}
function get_dependencies(tczname, depth, i, n) {
gsub(/KERNEL/, LINUX_VERSION, tczname)
printf("%"depth"s%s\n", "", tczname)
load_depfile(tczname)
n = ndeps[tczname]
for (i = 1; i <= n; i++) {
get_dependencies(deps[tczname, i], depth + 3)
}
}
These little exercises, while mundane in themselves, get you thinking, and learning.Agreed. And that's what it's all about :)