github.com/rminnich/u-root@v7.0.0+incompatible/cmds/core/seq/seq.go (about)

     1  // Copyright 2013-2017 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Print a sequence of numbers.
     6  //
     7  // Synopsis:
     8  //     seq [-f FORMAT] [-w] [-s SEPARATOR] [START [STEP [END]]]
     9  //
    10  // Examples:
    11  //    % seq -s=' ' 3
    12  //    1 2 3
    13  //    % seq -s=' ' 2 4
    14  //    2 3 4
    15  //    % seq -s=' ' 3 2 7
    16  //    3 5 7
    17  //
    18  // Options:
    19  //     -f: use printf style floating-point FORMAT (default: %v)
    20  //     -s: use STRING to separate numbers (default: \n)
    21  //     -w: equalize width by padding with leading zeroes (default: false)
    22  package main
    23  
    24  import (
    25  	"errors"
    26  	"flag"
    27  	"fmt"
    28  	"io"
    29  	"log"
    30  	"os"
    31  	"strings"
    32  )
    33  
    34  var (
    35  	flags struct {
    36  		format     string
    37  		separator  string
    38  		widthEqual bool
    39  	}
    40  	cmd = "seq [-f format] [-w] [-s separator] [start [step [end]]]"
    41  )
    42  
    43  func init() {
    44  	defUsage := flag.Usage
    45  	flag.Usage = func() {
    46  		os.Args[0] = cmd
    47  		defUsage()
    48  	}
    49  	flag.StringVar(&flags.format, "f", "%v", "use printf style floating-point FORMAT")
    50  	flag.StringVar(&flags.separator, "s", "\n", "use STRING to separate numbers")
    51  	flag.BoolVar(&flags.widthEqual, "w", false, "equalize width by padding with leading zeroes")
    52  }
    53  
    54  func seq(w io.Writer, args []string) error {
    55  	var (
    56  		stt   = 1.0
    57  		stp   = 1.0
    58  		end   float64
    59  		width int
    60  	)
    61  
    62  	format := flags.format // I use that because I'll modify a global variable
    63  	argv, argc := args, len(args)
    64  	if argc < 1 || argc > 4 {
    65  		return fmt.Errorf("mismatch n args; got %v, wants 1 >= n args >= 3", argc)
    66  	}
    67  
    68  	// loading step value if args is <start> <step> <end>
    69  	if argc == 3 {
    70  		_, err := fmt.Sscanf(argv[1], "%v", &stp)
    71  		if stp-float64(int(stp)) > 0 && format == "%v" {
    72  			d := len(fmt.Sprintf("%v", stp-float64(int(stp)))) - 2 // get the nums of y.xx decimal part
    73  			format = fmt.Sprintf("%%.%df", d)
    74  		}
    75  		if stp == 0.0 {
    76  			return errors.New("step value should be != 0")
    77  		}
    78  
    79  		if err != nil {
    80  			return err
    81  		}
    82  	}
    83  
    84  	if argc >= 2 { // cases: start + end || start + step + end
    85  		if _, err := fmt.Sscanf(argv[0]+" "+argv[argc-1], "%v %v", &stt, &end); err != nil {
    86  			return err
    87  		}
    88  	} else { // only <end>
    89  		if _, err := fmt.Sscanf(argv[0], "%v", &end); err != nil {
    90  			return err
    91  		}
    92  	}
    93  
    94  	format = strings.Replace(format, "%", "%0*", 1) // support widthEqual
    95  	if flags.widthEqual {
    96  		width = len(fmt.Sprintf(format, 0, end))
    97  	}
    98  
    99  	defer fmt.Fprint(w, "\n") // last char is always '\n'
   100  	for stt <= end {
   101  		fmt.Fprintf(w, format, width, stt)
   102  		stt += stp
   103  		if stt <= end { // print only between the values
   104  			fmt.Fprint(w, flags.separator)
   105  		}
   106  	}
   107  
   108  	return nil
   109  }
   110  
   111  func main() {
   112  	flag.Parse()
   113  
   114  	if err := seq(os.Stdout, flag.Args()); err != nil {
   115  		log.Println(err)
   116  		flag.Usage()
   117  		os.Exit(1)
   118  	}
   119  }