Skip to content
Files and arguments

Files and arguments

Mira keeps her score sheet in a text file, one result to a line, with an empty line wherever she felt like leaving one. The repository has it as examples/scores/scores.txt.

mira 12
tomas 7
mira 5

tomas 9
ines 14

The finished program is next to it, as examples/scores/scores.qdx. This chapter walks through its parts.

The file and its lines

fn main() -> int {
  if arg_count() != 2 { panic("usage: scores <file>") } else {
    let all = results_in(lines(read_file(arg(1))));
    print_totals(all, players_in(all, bytes_nil()))
  }
}

arg_count is the number of command-line arguments, counting the program’s own name, and arg(1) is the first one after it. read_file returns a whole file as bytes, and lines splits bytes into a list at each line end.

That list has the type bytes_list, a union from the standard library with the cases bytes_nil() and bytes_cons(head, tail).

One line

A line holds a result or is blank, so reading one produces a union.

union entry { scored(made: result), blank() }

fn entry_in(line: bytes) -> entry {
  let name_end = index_of_byte(line, space(), 0);
  if len(line) == 0 { blank() }
  else if name_end == len(line) { panic(concat("no points on this line: ", line)) }
  else {
    scored(made: result(player: slice(line, 0, name_end),
      points: text_to_int(slice(line, name_end + 1, len(line)))))
  }
}

fn space() -> int { 32 }

index_of_byte finds the first space, and returns the length of the line when there is none. slice cuts out the bytes from one position up to another, and text_to_int reads decimal digits. A byte is a number, so the space character is written as 32, behind a function that gives it a name.

All the lines

fn results_in(remaining: bytes_list) -> results {
  match remaining {
    bytes_nil() => no_results(),
    bytes_cons(head, tail) => match entry_in(head) {
      blank() => results_in(tail),
      scored(made) => result_then(first: made, rest: results_in(tail))
    }
  }
}

One match walks the list of lines, and a second decides what each line contributes. Blank lines are skipped by going on with the rest.

Run it

bootstrap/qdx run std/*.qdx examples/scores/scores.qdx -- examples/scores/scores.txt
ines 14
mira 17
tomas 16

Everything after -- is handed to the program as its arguments. The rest of the program collects the players’ names, sorts them, and prints a total for each using total_for from chapter 6.

A sheet with a mistake in it stops the program with a message.

no points on this line: mira

The program is finished. The last chapter looks under the standard library it has been leaning on.