Solving problems and even reinventing wheels can be fun, I've done that a lot, but sometimes it becomes tiresome and may even become stupid
pig-headed. So I decided to ask for help again.
I need to collect the names of all files and directories in a path. We have glob for that.
OK. Now I need to organize that data. The problem is, there may be many
ways of organizing data. Talk about skinning cats.
Maybe the user wants it all sorted by file name, alphabetically. OK. The problem is, maybe the user wants directories listed first. Maybe the user wants files listed first. That alone means three possible lists. Not to mention reverse order. That's another three lists.
Then maybe the user wants it all sorted by date. OK. The problem is, maybe the user wants newest first, maybe the user wants oldest first. That alone means two possible lists. And again, maybe the user wants directories
listed first. Maybe the user wants files listed first. Maybe the user wants files and directories mixed. Those combined make six possible lists. And an additional problem. I will certainly use the Unix epoch to sort dates, but will display a nicely formatted date string to the user later, so whatever
is used in the sorting process cannot be used in the display step.
I've done all that. It works. The problem is, 1. It's 150 lines of code.
More IFs than ChatGPT. It's big and awkward. 2. I did it in a way that
sorts lists with strides and assumes that filename is [lindex list 0], size is [lindex list 1], and so on. That is going to break because I want to let the user change the position of the columns.
Another problem is, there is a very, very unexpected little obstacle in the way. You would never guess what it is.
I use an old kernel. And there is a bug in BTRFS. One of my files is listed twice. Every time. Same name, same size, same date, same inode. I talked about it in the #btrfs IRC channel and they confirmed the bug. It's old,
but it exists in old kernels. If it's there, it has to be seen. I can't let my application hide it. It's not my job to sweep file system bugs under the carpet. Which means that, counterintuitively, I must not treat filenames as unique. I must assume there may be duplicates, as weird as that sounds. And they must be shown as such. You know what, I think I am going to write code to flag that kind of situation very visibly to the user because that's the kind of meticulous sad soul that I am. So anyway, I can't index my dict or array structure around file names.
Note that if you store the "filename" separated from the "path to the
file" then you have to be able to support duplicate filenames anyway,
even without a "bug", because two sub directories could have the
identical filename inside.
Create one list of lists, with each sublist being the columns of raw
data for the files that you want to use.
Then, create a set of procs that utilize the "-command" interface to
lsort. One proc sorts by name, one proc by date, one proc by whatever
else.
Then when the user changes the sort order, just resort the single
nested list using the appropriate "sort type" proc.
On Tue, 19 Dec 2023 22:49:37 -0000 (UTC), Rich wrote:
Note that if you store the "filename" separated from the "path to the
file" then you have to be able to support duplicate filenames anyway,
even without a "bug", because two sub directories could have the
identical filename inside.
I don't really understand what you mean here because in my case there
won't be any subdirectories. Each "view" contemplates the flat listing
inside a directory. There is no recursive action here whatsoever.
Create one list of lists, with each sublist being the columns of raw
data for the files that you want to use.
Then, create a set of procs that utilize the "-command" interface to
lsort. One proc sorts by name, one proc by date, one proc by whatever >>else.
Then when the user changes the sort order, just resort the single
nested list using the appropriate "sort type" proc.
I never used the -command option before so I had to look it up.
Ugh! Why are so many examples in the manual so opaque?
% proc compare {a b} {
set a0 [lindex $a 0]
set b0 [lindex $b 0]
if {$a0 < $b0} {
return -1
} elseif {$a0 > $b0} {
return 1
}
return [string compare [lindex $a 1] [lindex $b 1]]
}
% lsort -command compare {{3 apple} {0x2 carrot} {1 dingo} {2 banana}}
{1 dingo} {2 banana} {0x2 carrot} {3 apple}
I copied and changed and ran that many times trying to understand what in
the world is going on here, but I can't. How does the comparison work?
Is {3 apple} compared to {0x2 carrot} then {1 dingo} compared to
{2 banana}?
% proc compare {a b} {
set a0 [lindex $a 0]
set b0 [lindex $b 0]
if {$a0 < $b0} {
return -1
} elseif {$a0 > $b0} {
return 1
}
return [string compare [lindex $a 1] [lindex $b 1]]
}
Does it stride in leaps of 2 because two arguments were given (a and b)?
I guess {3 apple} is compared with {0x2 carrot}. Actually, just their
0 indices. So 3 > 1 so return 1. OK, 1. But what is "1" here?
Holy mackerew. I need to dissect this thing:
proc compare {a b} {
puts "begin: a is $a b is $b"
set a0 [lindex $a 0]
set b0 [lindex $b 0]
if {$a0 < $b0} {
puts "R1 $a0 < $b0, returning -1"
return -1
} elseif {$a0 > $b0} {
puts "R2 $a0 > $b0, returning 1"
return 1
}
puts "two tests failed with $a0 vs. $b0, going to the third"
puts "R3 [lindex $a 1] [lindex $b 1], returning [string compare [lindex $a 1] [lindex $b 1]] for [lindex $a 1] and [lindex $b 1]"
return [string compare [lindex $a 1] [lindex $b 1]]
}
puts [lsort -command compare {{3 apple} {0x2 carrot} {1 dingo} {2 banana}}]
Output:
begin: a is 3 apple b is 0x2 carrot
R2 3 > 0x2, returning 1
begin: a is 1 dingo b is 2 banana
R1 1 < 2, returning -1
begin: a is 0x2 carrot b is 1 dingo
R2 0x2 > 1, returning 1
begin: a is 0x2 carrot b is 2 banana
two tests failed with 0x2 vs. 2, going to the third
R3 carrot banana, returning 1 for carrot and banana
{1 dingo} {2 banana} {0x2 carrot} {3 apple}
So I see the first pair was compared to the second pair, then the third
pair was compared to the fourth pair... OK...
Then the second pair is compared to the fourth pair... Why?
And the results of all the comparisons were 1, -1, 1 and 1. OK.
And what does that mean?
Sorry, but I really can't understand the shuffle.
It's not a shuffle, it's a sort (although sorts and shuffles are**************************
somewhat two sides of the same coin).
On Wed, 20 Dec 2023 02:41:42 -0000 (UTC), Rich wrote:
It's not a shuffle, it's a sort (although sorts and shuffles are**************************
somewhat two sides of the same coin).
I guess I struggled to understand the concept because I had planted
some idea in my head that was a lot more complicated.
I continually failed to realize that it amounts to mere one on one comparisons and a very simple 1/-1 output.
I also learned that one pass of lsort "survives" a previous pass so I
can sort the listing by size then again by directories versus files
and have everything sorted by size but with directories first. Super
neat.
| Sysop: | Keyop |
|---|---|
| Location: | Huddersfield, West Yorkshire, UK |
| Users: | 715 |
| Nodes: | 16 (2 / 14) |
| Uptime: | 149:59:56 |
| Calls: | 12,091 |
| Calls today: | 4 |
| Files: | 15,000 |
| Messages: | 6,517,591 |