seq

seq is a command line interface program that is very popular in Unix/Linux. I find myself using it often in my Tcl code so I wrote my own seq.

LES 2025-01-05: added two new blocks (the first ones) to get rid of the "08" octal interpretation. I doubt the octal interpretation will ever be useful in the context of seq. Note that Tcl 9 no longer does the octal assumption.

proc p.seq {args} {
        # remove unwanted zeros
        set cleanargs {}
        for {set x 0} {$x < [llength $args]} {incr x} {
            if  {[string length [lindex $args $x]] > 1}        {
                set newitem [string trimleft [lindex $args $x] 0]
                lappend cleanargs $newitem
            } else {lappend cleanargs [lindex $args $x]}
        }
        set args $cleanargs                
                                
        # the same again, but with negative integers
        set cleanargs {}
        for {set x 0} {$x < [llength $args]} {incr x} {
            if  {[string range [lindex $args $x] 0 0] == "-"}        {
                set newitem [string trimleft [string range [lindex $args $x] 1 end] 0]
                lappend cleanargs "-$newitem"
            } else {lappend cleanargs [lindex $args $x]}
        }
        set args $cleanargs                

        if  {[llength $args] > 3 || [llength $args] < 1} {return ""}
        set mode ""
        set intcount 0
        for {set x 0} {$x < [llength $args]} {incr x} {
            if {[string is integer [lindex $args $x]]} {incr intcount}
        }
        if {$intcount == [llength $args]} {set mode "integer"}
        set alphacount 0
        for {set x 0} {$x < [llength $args]} {incr x} {
            if {[string length [lindex $args $x]] > 1} {continue}
            if {[string is alpha [lindex $args $x]]} {incr alphacount}
        }
        if {$alphacount == [llength $args]} {set mode "alpha"}
        if {$mode == ""} {return ""}

        # INT MODE
        if  {$mode == "integer"}          { 
            lassign $args A B C
            if  {[llength $args] == 3 && $B < 1}          {return ""}
            if  {[llength $args] == 3 && $A < $C}          { 
                for {set i $A} {$i <= $C} {set i [expr {$i + $B}]} {lappend _output $i}
                    return $_output
                }
                if  {[llength $args] == 3 && $A > $C}          { 
                    for {set i $A} {$i >= $C} {set i [expr {$i - $B}]} {lappend _output $i}
                    return $_output
                }

                if  {[llength $args] == 1} { 
                    set A 1; set B [lindex $args 0]
                    if {$B <= 1} {return $args}
                    for {set i $A} {$i <= $B} {incr i} {lappend _output $i}
                    return $_output
                }

                if  {$A == $B} {return $A}
                if  {$A < $B} { 
                    for {set i $A} {$i <= $B} {incr i} {lappend _output $i}
                    return $_output
                }
                if  {$A > $B} { 
                    for {set i $A} {$i >= $B} {incr i -1} {lappend _output $i}
                    return $_output
                }
        }

        # ALPHA MODE
        if  {$mode == "alpha"}          { 
            if {[llength $args] < 1 || [llength $args] > 2} {return ""}
            if {[llength $args] == 1}          { 
               if {[string is lower $args]} { 
                  set args "a $args"
               } else {set args "A $args"}
            }
            lassign $args A B
            if {$A == $B} {return $A}
            set An [scan $A %c]; set Bn [scan $B %c]
            set _output {}
            foreach i [p.seq $An $Bn]          { 
                if  {[string is alpha [format %c $i]] == 1} {lappend _output [format %c $i]}
            }
            return $_output
        }
}

Testing it:

> p.seq 4
1 2 3 4
> p.seq 4 11
4 5 6 7 8 9 10 11
> p.seq 11 4
11 10 9 8 7 6 5 4
> p.seq 4 -4
4 3 2 1 0 -1 -2 -3 -4
> p.seq 3 3 18
3 6 9 12 15 18
> p.seq 3 2 18
3 5 7 9 11 13 15 17
> p.seq a g
a b c d e f g
> p.seq A G
A B C D E F G
> p.seq A g
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g
> p.seq g A
g f e d c b a Z Y X W V U T S R Q P O N M L K J I H G F E D C B A