4

This is a common, basic task, so it would be good to know an appropriate way to do this. A similar program in C++ might look like this (ref):

#include <iostream>
using namespace std;

int main(int argc, char** argv)
{

    for (int i = 0; i < argc; ++i)
        cout << argv[i] << "\n";

    return 0;
}

In this example, we are printing out each of the arguments on the command line. So that running the programming like ./main.exe asdf 1234 bob would give:

./main.exe 
asdf 
1234 
bob
bbarker
  • 11,636
  • 9
  • 38
  • 62
  • Even if you're going to self-answer a question, the question should still fit the standards of an appropriate SO question capable of standing on it's own. – jmoerdyk Mar 14 '18 at 22:43
  • @jmoerdyk - you are right, I updated the question to be more clear, thanks! – bbarker Mar 14 '18 at 22:44

3 Answers3

4

This is very similar to the same kind of program in C, with a few differences related to constraints and linear types. The constraints are straightforward once set up:

(*
Run patscc -o hello hello.dats
*)

#include "share/atspre_staload.hats"

implement main0{n}
(argc, argv): void = {

  fun echoArgs{i:nat | i < n}
  (ii: int(i), argv: !argv(n)): void = {
    val () = println!("arg ", ii, " is ", argv[ii])
    val () = if ii + 1 < argc then echoArgs(ii + 1, argv) 
  }

  val () = echoArgs(0, argv)
}

Since we need to access the contents of argv, we have to change the view of its viewtype by supplying the linear-dependent type !argv(n); the ! corresponds to the bang in linear logic indicating that values of that type are still available after the function call; the (n) just means argv is a string array of size n. We have to guarantee the index i into the array is less than the size n of the array.

bbarker
  • 11,636
  • 9
  • 38
  • 62
1

Here is a combinator-based style:

#include "share/atspre_staload.hats"
#include "share/atspre_staload_libats_ML.hats"

implement
main0(argc, argv) = let
//
val args = listize_argc_argv(argc, argv)
//
in
  list0_foreach(args, lam(arg) => println!(arg))
end // end of [main0]
Hongwei Xi
  • 895
  • 1
  • 5
  • 10
  • I think doing this with a `stream_vt` might be interesting if not particularly useful (since the time and memory saved by removing `listize_argc_argv` would be minimal since there are rarely enough arguments for that to matter); I may give it a try later, but just wanted to make a note for now. – bbarker Mar 17 '18 at 19:02
1

Probably, the more common desire is to get flags and arguments from the command line, to change program behavior. For this, you can just use getopt (or with slightly more complexity but a much nicer CLI interface, GNU getopt). These functions do basically everything for you.

For a somewhat silly example:

#include "share/atspre_staload.hats"
%{^
#include <unistd.h>
%}

extern fun getopt{n:int}(argc: int, argv: !argv(n), flags: string): int = "mac#"

val trad = ref<bool>(false)
val color = ref<bool>(false)
val progname = ref<string>("hello4")

fn get_progname{n:int}(argc: int(n), argv: !argv(n)): void =
        if argc > 0 then
                !progname := argv[0]

implement main0(argc, argv) = (
        get_progname(argc, argv);
        process_args(argc, argv);
        case+ (!trad, !color) of
        | (true, true) => println!("\033[31;1mhello world\033[0m")
        | (true, false) => println!("hello world")
        | (false, true) => println!("\033[31;1mHello, world!\033[0m")
        | (false, false) => println!("Hello, modern world!")
) where {
        fn usage(): void = (
                fprintln!(stderr_ref, "usage: ", !progname, " [-htc]");
                exit(1);
        )
        fun process_args{n:int}(argc: int, argv: !argv(n)): void =
                let
                        val r = getopt(argc, argv, "htc")
                in
                        if r >= 0 then (
                                ifcase
                                | r = 'h' => usage()
                                | r = 't' => (!trad := true; process_args(argc, argv))
                                | r = 'c' => (!color := true; process_args(argc, argv))
                                | _ => (println!("fell through with: ", $UNSAFE.cast{char}(r)); usage())
                        )
                end
}

Usage:

$ ./hello4
Hello, modern world!
$ ./hello4 -t
hello world
$ ./hello4 -c
Hello, world!    <-- this is red
Julian Fondren
  • 5,459
  • 17
  • 29