s/@/@0/g;s/>/@1/g;s/\[/@2/g;s/\]/@3/g;x s/^.*$/>/;x;:l;s/(>>+)([^,{}<>]),/,\1\2/ tl;s/(>)([^,{}<>]),/,\2\1\2/;tl s/(>+)([^,{}<>])([^,{}<>])/\3\1\2/;tl s/>(>+)([^,{}<>])}/}\1\2/;tl s/>([^,{}<>])\}/\}/;tl s/([^>])(>+)([^,{}<>])\{/\1\{\2>\3/;tl s/([^,{}<>])\{/\{\1>\1/;tl /^{.*\[/{y/[']/{,}/;bl;} s/^{(.*)}{/>{\1}{/;tm;bM :m;s/>}{/]{/;tl;s/>{/[>/;tm;s/>}/]>/ tm;s/>,/'>/;tm;s/>(.)/\1>/;tm;:M s/^{(.*)}$/\1/;tl;:R;s/^/>/;:r s/>(.*)(.)/\2>\1/;tr;s/>$//;y/{}/}{/ x;y/<>/>;x;/^[^{].*}$/bl;x;/{x;bR;};x s/[{}]//g;s/@1/>/g;s/@2/[/g;s/@3/]/g;s/@0/@/g
the 545 bytes above are program to expand a subset of shell globs, specifically those using braces and commas to specify alternatives. for example, here is one that expands to all the urls that this page is accessible at:
{gemini,http{s,}}://binarycat.flounder.online/gemlog/2022-03-08_a-glob-of-sed.gmi
here is the commented version:
(also contains some "assertions")
#!/bin/sed -f # > pushes a character to the right # having multiple signifies a greater depth # escape certain chars to be used internally s/@/@0/g s/>/@1/g s/\[/@2/g s/\]/@3/g # we use the hold area to store whether we are currently in a "reversed" state. # this is just used so we don't print the output backwards. x s/^.*$/>/ x # start of main loop :l # debug print #p # assert that no more than one cascade exists />[^>]+>/ { s/^.*$/ERROR/ q } # pull cascading charachter over a comma (level > 1) s/(>>+)([^,{}<>]),/,\1\2/ t l # pull cascading characher over a comma, leaving behind a copy (level == 1) s/(>)([^,{}<>]),/,\2\1\2/ t l # advance cascading characher s/(>+)([^,{}<>])([^,{}<>])/\3\1\2/ t l # cascade exits brace, loses a level (if level > 1) s/>(>+)([^,{}<>])}/}\1\2/ t l # cascade hits brace and ends (level == 1) s/>([^,{}<>])\}/\}/ t l # increase the depth of an existing cascade s/([^>])(>+)([^,{}<>])\{/\1\{\2>\3/ t l # assert that no cascade exists />/ { s/^.*$/ERROR/ q } # start cascading a new charachter through the expansions, leave behind a copy s/([^,{}<>])\{/\{\1>\1/ t l # here we multiply adjacent arrays. # this is quite tricky, and requires almost doubling the amount of metachars used # basically, we convert all metachars in the left array to # an alternate form, then let the rest of the program # move them to where they need to be, then convert them back. # the final step, convert everything back /^{.*\[/ { y/[']/{,}/ b l } # if there are adjacent arrays, mark the start and begin converting s/^{(.*)}{/>{\1}{/ t m # otherwise, continue with other tests. b M # loop to convert metachars :m # more debug prints #p # exit condition: converting the final brace s/>}{/]{/ t l # do conversion s/>{/[>/;t m s/>}/]>/;t m s/>,/'>/;t m # leave other chars unchanged s/>(.)/\1>/;t m a\ unreachable q # done with array multiplication :M # remove outer redundant braces s/^{(.*)}$/\1/ t l #p # start reversing :R # delimiter between reversed and unreversed parts (reusing a metachar) s/^/>/ # start reversal loop :r s/>(.*)(.)/\2>\1/ t r # end reversal loop # remove delimiter s/>$// y/{}/}{/ # update stored direction x y/<>/> x # done reversing # brace at end but not start, cascade more chars /^[^{].*}$/ b l # if the pattern space is backwards, reverse it. x / { x b R } x # remove leftover braces s/[{}]//g # unescape internal metachars s/@1/>/g s/@2/[/g s/@3/]/g # this one must be done last s/@0/@/g
if you uncomment some of the print statements (or add you own!), you can actually see the program shuffling chars around.
quite likely.
=> home | gemlog index This content has been proxied by September (ba2dc).Proxy Information
text/gemini; charset=utf-8