about summary refs log tree commit diff
path: root/language/dynamic/command-line.e
blob: 4b3ab6d766de0ee06fbfc4bd6e1b797b40abbbd5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ ~~ Command-line parameter semantics ~~
~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~
~   The Evocation executable runs as a command-line tool. As part of that, it
~ accepts command-line parameters via the POSIX argc/argv interface. The code
~ in this file implements the semantics of those parameters.
~
~   The rule is quite simple: Each parameter is treated as a single word, and
~ run as if by "interpret". When a parameter is neither a regular word nor an
~ integer literal, if it looks like it could be a source code filename, the
~ file it names is read as if by "include", except that the success flag is
~ discarded.
~
~   Nothing special is done to make command-line parameters appear as if
~ they're an input stream; they're not. They're special words that are invoked
~ before standard input is touched. Anything words run as command-line
~ parameters try to do to standard input will draw on standard input as usual,
~ despite that not being where they themselves come from, which will likely
~ cause unwanted behavior. See language/boot-source-footer.e for the exact
~ sequence of events during startup.
~
~   In particular, this means that words such as s" and ', which try to read
~ input, are unlikely to do what you want as command-line parameters.

8 2 * allocate s" argument-scan-state" variable
: argument-scan-state-next-argument-handle ;
: argument-scan-state-n-remaining-arguments 8 + ;

~ (next argument handle, n remaining arguments --)
: save-argument-scan-state
  argument-scan-state argument-scan-state-n-remaining-arguments !
  argument-scan-state argument-scan-state-next-argument-handle ! ;
~ (-- next argument handle, n remaining arguments)
: restore-argument-scan-state
  argument-scan-state argument-scan-state-next-argument-handle @
  argument-scan-state argument-scan-state-n-remaining-arguments @ ;


~   This tests whether a string looks like it could be an Evocation
~ source-code filename.
~
~   Specifically, it looks for an extension of *.e. Also, it disallows ".e" by
~ itself as a filename, requiring the length to be at least three characters.
~
~   This comparison is done case-sensitively. This means that, even on a
~ case-insensitive filesystem, from Evocation's perspective we always require
~ the extension to be treated as lowercase.
~
~ (string pointer -- boolean)
: is-possible-source-filename
  dup stringlen
  ~ (string pointer, length)
  dup 2 < {
    2 - + s" .e" stringcmp 0 =
  } {
    2drop 0
  } if-else ;


~ (argument pointer -- *)
: process-command-line-argument
  dup find dup {
    ~ (argument pointer, entry pointer)
    swap drop
    interpreter-flags @ 0x01 & {
      dup entry-flags@ 1 &
      swap entry-to-execution-token swap
      { execute } { , } if-else
    } { entry-to-execution-token execute } if-else
  } {
    drop
    ~ (argument pointer)
    dup read-integer 0 = {
      ~ (argument pointer, integer value)
      interpreter-flags @ 0x01 & {
        x' lit , ,
        drop
      } {
        swap drop
      } if-else
    } {
      ~ (argument pointer)
      dup is-possible-source-filename {
        include drop
      } {
        ." No such word: " emitstring newline
      } if-else
    } if-else
  } if-else ;

: process-command-line-arguments
  s0 @
  dup @
  swap 8 +
  swap
  ~ (next argument handle, n remaining arguments)
  dup {
    ~ Skip the executable name.
    1- swap 8 + swap

    { dup } {
      over @
      3unroll save-argument-scan-state

      process-command-line-argument

      restore-argument-scan-state
      1- swap 8 + swap
    } while
  } if 2drop ;