diff options
Diffstat (limited to '')
37 files changed, 2200 insertions, 229 deletions
diff --git a/Changelog.md b/Changelog.md index bb96607..6d39421 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,7 +1,32 @@ # Change log +### v0.8.1-2 minor update (released on 1 May 2022) + +| | Haskell | OCaml | SML | Python | Inpla8 | Inpla8r | +| ------------ | :----------------------------------------: | :-------------------------------------: | :-------------------------------------: | :----------------------------------------: | :----------------------------------------------: | :----------------------------------------------------: | +| ack(3,11) | [2.30](comparison/Haskell/ack3-11.hs) | [0.46](comparison/OCaml/ack3_11.ml) | [**0.43**](comparison/SML/ack3-11.sml) | [-](comparison/Python/ack3-11.py) | [0.84](comparison/Inpla/src/ack-stream_3-11.in) | [0.71](comparison/Inpla/src/ack-stream_3-11-reuse.in) | +| fib 38 | [1.60](comparison/Haskell/fib38.hs) | [**0.15**](comparison/OCaml/fib38.ml) | [0.27](comparison/SML/fib38.sml) | [8.88](comparison/Python/fib38.py) | [0.41](comparison/Inpla/src/fib-38.in) | [0.43](comparison/Inpla/src/fib-38-reuse.in) | +| bsort 40000 | [34.48](comparison/Haskell/bsort-40000.hs) | [34.62](comparison/OCaml/bsort40000.ml) | [12.06](comparison/SML/bsort-40000.sml) | [79.53](comparison/Python/bsort-40000.py) | [3.02](comparison/Inpla/src/bsort-40000.in) | [**2.52**](comparison/Inpla/src/bsort-40000-reuse.in) | +| isort 40000 | [12.54](comparison/Haskell/isort-40000.hs) | [7.45](comparison/OCaml/isort40000.ml) | [2.94](comparison/SML/isort-40000.sml) | [36.89](comparison/Python/isort-40000.py) | [**1.15**](comparison/Inpla/src/isort-40000.in) | [1.24](comparison/Inpla/src/isort-40000-reuse.in) | +| qsort 260000 | [0.34](comparison/Haskell/qsort-800000.hs) | [0.25](comparison/OCaml/qsort800000.ml) | [0.27](comparison/SML/qsort-800000.sml) | [10.40](comparison/Python/qsort-800000.py) | [0.15](comparison/Inpla/src/qsort-800000.in) | [**0.12**](comparison/Inpla/src/qsort-800000-reuse.in) | +| msort 260000 | [0.39](comparison/Haskell/msort-800000.hs) | [0.29](comparison/OCaml/msort800000.ml) | [0.26](comparison/SML/msort-800000.sml) | [10.96](comparison/Python/msort-800000.py) | [**0.15**](comparison/Inpla/src/msort-800000.in) | [**0.15**](comparison/Inpla/src/msort-800000-reuse.in) | + +#### Bug fix + +* **Output format of integers** (again): Calculation and management of integer numbers had been 32-bit format. Now these are re-fixed as long integers correctly. + +#### Changes + +* From this version Quick and Merge sorts work for smaller lists whose elements are 260000, while it was 400000. This is because OCaml raises stack overflow error for over 260000 elements. As the result, the ratio looks not so good. + +  + + + ### v0.8.2 (released on 28 April 2022) + + | | Haskell | OCaml | SML | Python | Inpla8 | Inpla8r | | ------------ | :----------------------------------------: | :-------------------------------------: | :-------------------------------------: | :-----------------------------------------: | :---------------------------------------------: | :----------------------------------------------------: | | ack(3,11) | [2.30](comparison/Haskell/ack3-11.hs) | [0.46](comparison/OCaml/ack3_11.ml) | [**0.43**](comparison/SML/ack3-11.sml) | [-](comparison/Python/ack3-11.py) | [0.83](comparison/Inpla/src/ack-stream_3-11.in) | [0.71](comparison/Inpla/src/ack-stream_3-11-reuse.in) | @@ -18,7 +43,7 @@  #### Bug fix -* **The benchmark table was wrong**: With respect to the results in Haskell, the execution times of sort works were too short due to its lazy evaluation strategy. To solve it, every sort work will be followed by a validation check if a given list is correctly sorted, not only in Haskell but also in others. +* **The benchmark table was wrong**: With respect to the results in Haskell, the execution times of sort works were too short. This is thanks to its lazy evaluation strategy, quite nice, that gets only the first 10 elements the same as the written program, though these are expected to be taken after finishing these sort works. So, every sort work will be followed by a validation check if a given list is correctly sorted, not only in Haskell but also in others. @@ -6,18 +6,21 @@ Inpla is a multi-threaded parallel interpreter of interaction nets. Once you write programs for sequential execution, it works also in multi-threaded parallel execution. Each thread is managed on each CPU-core with POSIX-thread library. -* The current version is 0.8.2, released on **28 April 2022**. (See [Changelog.md](Changelog.md) for details.) +* The current version is 0.8.2-1, released on **2 May 2022**. (See [Changelog.md](Changelog.md) for details.) +* The below graph shows speed-up ratio to threads numbers for programs in the following benchmark table. In this version Quick and Merge sorts work for smaller lists whose elements are 260000, while it was 400000. This is because OCaml raises stack overflow error for over 260000 elements. As the result, the ratio looks not so good. For the results for 400000 elements (that are not so bad), which had been shown here, see the description of v0.8.2 in [Changelog.md](./Changelog.md) + + + - | | Haskell | OCaml | SML | Python | Inpla8 | Inpla8r | | -------------- | :------: | :------: | :----: | :----: | :------: | :------: | -| ack(3,11) | [2.30](comparison/Haskell/ack3-11.hs) | [0.46](comparison/OCaml/ack3_11.ml) | [**0.43**](comparison/SML/ack3-11.sml) | [-](comparison/Python/ack3-11.py) | [0.83](comparison/Inpla/src/ack-stream_3-11.in) | [0.71](comparison/Inpla/src/ack-stream_3-11-reuse.in) | -| fib 38 | [1.60](comparison/Haskell/fib38.hs) | [**0.15**](comparison/OCaml/fib38.ml) | [0.27](comparison/SML/fib38.sml) | [8.88](comparison/Python/fib38.py) | [0.39](comparison/Inpla/src/fib-38.in) | [0.40](comparison/Inpla/src/fib-38-reuse.in) | -| bsort 40000 | [34.48](comparison/Haskell/bsort-40000.hs) | [34.62](comparison/OCaml/bsort40000.ml) | [12.06](comparison/SML/bsort-40000.sml) | [79.53](comparison/Python/bsort-40000.py) | [2.98](comparison/Inpla/src/bsort-40000.in) | [**2.48**](comparison/Inpla/src/bsort-40000-reuse.in) | -| isort 40000 | [12.54](comparison/Haskell/isort-40000.hs) | [7.45](comparison/OCaml/isort40000.ml) | [2.94](comparison/SML/isort-40000.sml) | [36.89](comparison/Python/isort-40000.py) | [**1.15**](comparison/Inpla/src/isort-40000.in) | [1.21](comparison/Inpla/src/isort-40000-reuse.in) | -| qsort 800000 | [1.56](comparison/Haskell/qsort-800000.hs) | [-](comparison/OCaml/qsort800000.ml) | [1.14](comparison/SML/qsort-800000.sml) | [97.37](comparison/Python/qsort-800000.py) | [0.66](comparison/Inpla/src/qsort-800000.in) | [**0.37**](comparison/Inpla/src/qsort-800000-reuse.in) | -| msort 800000 | [1.55](comparison/Haskell/msort-800000.hs) | [-](comparison/OCaml/msort800000.ml) | [1.04](comparison/SML/msort-800000.sml) | [100.04](comparison/Python/msort-800000.py) | [0.48](comparison/Inpla/src/msort-800000.in) | [**0.35**](comparison/Inpla/src/msort-800000-reuse.in) | +| ack(3,11) | [2.30](comparison/Haskell/ack3-11.hs) | [0.46](comparison/OCaml/ack3_11.ml) | [**0.43**](comparison/SML/ack3-11.sml) | [-](comparison/Python/ack3-11.py) | [0.84](comparison/Inpla/src/ack-stream_3-11.in) | [0.71](comparison/Inpla/src/ack-stream_3-11-reuse.in) | +| fib 38 | [1.60](comparison/Haskell/fib38.hs) | [**0.15**](comparison/OCaml/fib38.ml) | [0.27](comparison/SML/fib38.sml) | [8.88](comparison/Python/fib38.py) | [0.41](comparison/Inpla/src/fib-38.in) | [0.43](comparison/Inpla/src/fib-38-reuse.in) | +| bsort 40000 | [34.48](comparison/Haskell/bsort-40000.hs) | [34.62](comparison/OCaml/bsort40000.ml) | [12.06](comparison/SML/bsort-40000.sml) | [79.53](comparison/Python/bsort-40000.py) | [3.02](comparison/Inpla/src/bsort-40000.in) | [**2.52**](comparison/Inpla/src/bsort-40000-reuse.in) | +| isort 40000 | [12.54](comparison/Haskell/isort-40000.hs) | [7.45](comparison/OCaml/isort40000.ml) | [2.94](comparison/SML/isort-40000.sml) | [36.89](comparison/Python/isort-40000.py) | [**1.15**](comparison/Inpla/src/isort-40000.in) | [1.24](comparison/Inpla/src/isort-40000-reuse.in) | +| qsort 260000 | [0.34](comparison/Haskell/qsort-800000.hs) | [0.25](comparison/OCaml/qsort800000.ml) | [0.27](comparison/SML/qsort-800000.sml) | [10.40](comparison/Python/qsort-800000.py) | [0.15](comparison/Inpla/src/qsort-800000.in) | [**0.12**](comparison/Inpla/src/qsort-800000-reuse.in) | +| msort 260000 | [0.39](comparison/Haskell/msort-800000.hs) | [0.29](comparison/OCaml/msort800000.ml) | [0.26](comparison/SML/msort-800000.sml) | [10.96](comparison/Python/msort-800000.py) | [**0.15**](comparison/Inpla/src/msort-800000.in) | [**0.15**](comparison/Inpla/src/msort-800000-reuse.in) | - **Comparison in execution time** with other implementations: **Haskell** (GHC version 8.10.7), **OCaml** (ocamlopt, the native-code compiler, version 4.08.1), **Standard ML of New Jersey** v110.74 (interpreter mode) and **Python** 3.8.5 in execution time. @@ -29,7 +32,7 @@ Inpla is a multi-threaded parallel interpreter of interaction nets. Once you wri - "fib 38" is computation to get the 38th Fibonacci number. - - "bsort *n*", "isort *n*", "qsort *n*" and "msort *n*" are computation of bubble sort, insertion sort, quick sort and merge sort for random *n*-element lists, respectively, followed by a validation check process. The blanks in OCaml are due to the following error: `Fatal error: exception Stack_overflow` + - "bsort *n*", "isort *n*", "qsort *n*" and "msort *n*" are computation of bubble sort, insertion sort, quick sort and merge sort for random *n*-element lists, respectively, followed by a validation check process. diff --git a/comparison/Haskell/Makefile b/comparison/Haskell/Makefile index 0042c28..b55259f 100644 --- a/comparison/Haskell/Makefile +++ b/comparison/Haskell/Makefile @@ -1,8 +1,7 @@ CC = stack ghc CFLAGS = -O2 BENCHMARK = bash ../tools/sptest_commands.sh -TARGET = ack3-11 fib38 bsort-40000 isort-40000 qsort-800000 msort-800000 -#TARGET = ack3-11 +TARGET = ack3-11 fib38 bsort-40000 isort-40000 qsort-260000 msort-260000 LOG = log.txt @@ -25,10 +24,10 @@ bsort-40000: bsort-40000.hs isort-40000: isort-40000.hs $(CC) -- $(CFLAGS) $< -qsort-800000: qsort-800000.hs +qsort-260000: qsort-260000.hs $(CC) -- $(CFLAGS) $< -msort-800000: msort-800000.hs +msort-260000: msort-260000.hs $(CC) -- $(CFLAGS) $< diff --git a/comparison/Haskell/bsort-40000.hs b/comparison/Haskell/bsort-40000.hs index 90f208c..c065a32 100644 --- a/comparison/Haskell/bsort-40000.hs +++ b/comparison/Haskell/bsort-40000.hs @@ -15,6 +15,7 @@ bs xs n = xs go xs 0 = xs go xs n = go (bs xs n) (n-1) +bsort [] = [] bsort xs = go xs (length xs -1) {- diff --git a/comparison/Haskell/msort-260000.hs b/comparison/Haskell/msort-260000.hs new file mode 100644 index 0000000..49cae3c --- /dev/null +++ b/comparison/Haskell/msort-260000.hs @@ -0,0 +1,51 @@ +{- +https://stackoverflow.com/questions/25839939/understanding-merge-sort-in-ml +-} +import System.Random + +mysplit [] = ([], []) +mysplit [a] = ([a], []) +mysplit (a:b:cs) = (a:m, b:n) + where + (m,n) = mysplit cs + +merge ([], ys) = ys +merge (xs, []) = xs +merge (x:xs, y:ys) + | x<y = x:merge(xs, y:ys) + | otherwise = y:merge(x:xs, ys) + +msort [] = [] +msort [a] = [a] +msort [a,b] + | a<b = [a,b] + | otherwise = [b,a] +msort xs = merge (msort m, msort n) + where + (m,n) = mysplit xs + +{- +main = print $ msort [3,2,8,5] +-} + + +randomList :: Int -> IO([Int]) +randomList 0 = return [] +randomList n = do + r <- randomRIO (1,10000) + rs <- randomList (n-1) + return (r:rs) + + +validation [] = True +validation (x:xs) = validation_cons x xs +validation_cons x [] = True +validation_cons x (y:ys) = + if x<=y then validation_cons y ys + else False + + +main = do + list <- randomList 260000 + let sorted = msort list + print (validation sorted) diff --git a/comparison/Haskell/qsort-260000.hs b/comparison/Haskell/qsort-260000.hs new file mode 100644 index 0000000..7115121 --- /dev/null +++ b/comparison/Haskell/qsort-260000.hs @@ -0,0 +1,43 @@ +{- +(* http://www.codecodex.com/wiki/Insertion_sort#Standard_ML *) +-} +import System.Random + +qsort [] = [] +qsort [x] = [x] +qsort (x:xs) = (qsort left) ++ [x] ++ (qsort right) + where (left, right) = part x xs + +part pivot [] = ([], []) +part pivot (x:xs) + | x<pivot = (x:below, above) + | otherwise = (below, x:above) + where + (below, above) = part pivot xs + + +{- +main = print $ qsort [3,2,8,5] +-} + + +randomList :: Int -> IO([Int]) +randomList 0 = return [] +randomList n = do + r <- randomRIO (1,10000) + rs <- randomList (n-1) + return (r:rs) + + +validation [] = True +validation (x:xs) = validation_cons x xs +validation_cons x [] = True +validation_cons x (y:ys) = + if x<=y then validation_cons y ys + else False + + +main = do + list <- randomList 260000 + let sorted = qsort list + print (validation sorted) diff --git a/comparison/Inpla/main.sh b/comparison/Inpla/main.sh index f7935fb..6975046 100644 --- a/comparison/Inpla/main.sh +++ b/comparison/Inpla/main.sh @@ -12,8 +12,8 @@ bash ./sptestInpla.sh src/bsort-40000-reuse.in bash ./sptestInpla.sh src/isort-40000.in bash ./sptestInpla.sh src/isort-40000-reuse.in -bash ./sptestInpla.sh src/qsort-800000.in -bash ./sptestInpla.sh src/qsort-800000-reuse.in '-Xms 18 -Xmt 0' +bash ./sptestInpla.sh src/qsort-260000.in +bash ./sptestInpla.sh src/qsort-260000-reuse.in '-Xms 17 -Xmt 0' -bash ./sptestInpla.sh src/msort-800000.in -bash ./sptestInpla.sh src/msort-800000-reuse.in '-Xms 18 -Xmt 0' +bash ./sptestInpla.sh src/msort-260000.in +bash ./sptestInpla.sh src/msort-260000-reuse.in '-Xms 18 -Xmt 0' diff --git a/comparison/Inpla/src/bsort-40000-reuse.in b/comparison/Inpla/src/bsort-40000-reuse.in index 5908f83..d5b23ff 100644 --- a/comparison/Inpla/src/bsort-40000-reuse.in +++ b/comparison/Inpla/src/bsort-40000-reuse.in @@ -18,7 +18,7 @@ make_RandList(ret) >< (int n) // validation checks -valid(ret) >< [] => ret~False; +valid(ret) >< [] => ret~True; valid(ret) >< x:xs => (*L)valid_Cons(ret,x)~xs; valid_Cons(ret, int x) >< [] => ret~True; diff --git a/comparison/Inpla/src/bsort-40000.in b/comparison/Inpla/src/bsort-40000.in index d3c8267..58a63da 100644 --- a/comparison/Inpla/src/bsort-40000.in +++ b/comparison/Inpla/src/bsort-40000.in @@ -18,7 +18,7 @@ make_RandList(ret) >< (int n) // validation checks -valid(ret) >< [] => ret~False; +valid(ret) >< [] => ret~True; valid(ret) >< x:xs => valid_Cons(ret,x)~xs; valid_Cons(ret, int x) >< [] => ret~True; diff --git a/comparison/Inpla/src/isort-40000-reuse.in b/comparison/Inpla/src/isort-40000-reuse.in index 1f7153d..daedf3a 100644 --- a/comparison/Inpla/src/isort-40000-reuse.in +++ b/comparison/Inpla/src/isort-40000-reuse.in @@ -16,7 +16,7 @@ make_RandList(ret) >< (int n) // validation checks -valid(ret) >< [] => ret~False; +valid(ret) >< [] => ret~True; valid(ret) >< x:xs => (*L)valid_Cons(ret,x)~xs; valid_Cons(ret, int x) >< [] => ret~True; diff --git a/comparison/Inpla/src/isort-40000.in b/comparison/Inpla/src/isort-40000.in index 0e3ed32..4947e28 100644 --- a/comparison/Inpla/src/isort-40000.in +++ b/comparison/Inpla/src/isort-40000.in @@ -16,7 +16,7 @@ make_RandList(ret) >< (int n) // validation checks -valid(ret) >< [] => ret~False; +valid(ret) >< [] => ret~True; valid(ret) >< x:xs => valid_Cons(ret,x)~xs; valid_Cons(ret, int x) >< [] => ret~True; diff --git a/comparison/Inpla/src/msort-260000-reuse.in b/comparison/Inpla/src/msort-260000-reuse.in new file mode 100644 index 0000000..7201ac7 --- /dev/null +++ b/comparison/Inpla/src/msort-260000-reuse.in @@ -0,0 +1,51 @@ +// Merge sort +msort(ret) >< [] => ret~[]; +msort(ret) >< x:xs => (*L)msort_tail(ret, x)~xs; + +msort_tail(ret, int n) >< [] => ret~[n]; +msort_tail(ret, int n) >< x:xs => + split(left,right) ~ (*R)(n:x:xs), + msort(a)~left, msort(b)~right, (*L)merge(ret,b)~a; + +merge(ret, snd) >< [] => ret~snd; +merge(ret, snd) >< x:xs => (*L)mergeCC(ret, x, xs)~snd; + +mergeCC(ret, int y, ys) >< [] => ret~(*R)(y:ys); +mergeCC(ret, int y, ys) >< (int x):xs +| x <= y => ret~(x:cnt), (*L)mergeCC(cnt, y, ys) ~ xs +| _ => ret~(y:cnt), (*L)mergeCC(cnt, x, xs) ~ ys; + + +split(right,left) >< [] => right~[], left~[]; +split(right,left) >< x:xs => + right~(*R)(x:cntl), left~cntr, (*L)split(cntr,cntl)~xs; + + +// creates a random list +make_RandList(ret) >< (int n) +| n>0 => ret~(rd:cnt), (*L)make_RandList(cnt)~(n-1) + where rd=rand(10000) +| _ => ret~[]; + + +// validation checks +valid(ret) >< [] => ret~True; +valid(ret) >< x:xs => (*L)valid_Cons(ret,x)~xs; + +valid_Cons(ret, int x) >< [] => ret~True; +valid_Cons(ret, int x) >< (int y):ys +| x<=y => (*L)valid_Cons(ret,y)~ys +| _ => ret~False, Eraser~ys; + +// The `Eraser' is a built-in agent defined for any agents as follows: +//Eraser >< Alpha(a1, ..., a5) => Eraser~a1, ..., Eraser~a5; + + +// Main +const LIST_ELEM=260000; + +make_RandList(rndlist)~(LIST_ELEM), +msort(sorted)~rndlist, +valid(ret)~sorted; + +ret; diff --git a/comparison/Inpla/src/msort-260000.in b/comparison/Inpla/src/msort-260000.in new file mode 100644 index 0000000..efa464d --- /dev/null +++ b/comparison/Inpla/src/msort-260000.in @@ -0,0 +1,51 @@ +// Merge sort +msort(ret) >< [] => ret~[]; +msort(ret) >< x:xs => msort_tail(ret, x)~xs; + +msort_tail(ret, int n) >< [] => ret~[n]; +msort_tail(ret, int n) >< x:xs => + split(left,right) ~ (n:x:xs), + msort(a)~left, msort(b)~right, merge(ret,b)~a; + +merge(ret, snd) >< [] => ret~snd; +merge(ret, snd) >< x:xs => mergeCC(ret, x, xs)~snd; + +mergeCC(ret, int y, ys) >< [] => ret~(y:ys); +mergeCC(ret, int y, ys) >< (int x):xs +| x <= y => ret~(x:cnt), mergeCC(cnt, y, ys) ~ xs +| _ => ret~(y:cnt), mergeCC(cnt, x, xs) ~ ys; + + +split(right,left) >< [] => right~[], left~[]; +split(right,left) >< x:xs => + right~(x:cntl), left~cntr, split(cntr,cntl)~xs; + + +// creates a random list +make_RandList(ret) >< (int n) +| n>0 => ret~(rd:cnt), make_RandList(cnt)~(n-1) + where rd=rand(10000) +| _ => ret~[]; + + +// validation checks +valid(ret) >< [] => ret~True; +valid(ret) >< x:xs => valid_Cons(ret,x)~xs; + +valid_Cons(ret, int x) >< [] => ret~True; +valid_Cons(ret, int x) >< (int y):ys +| x<=y => valid_Cons(ret,y)~ys +| _ => ret~False, Eraser~ys; + +// The `Eraser' is a built-in agent defined for any agents as follows: +//Eraser >< Alpha(a1, ..., a5) => Eraser~a1, ..., Eraser~a5; + + +// Main +const LIST_ELEM=260000; + +make_RandList(rndlist)~(LIST_ELEM), +msort(sorted)~rndlist, +valid(ret)~sorted; + +ret; diff --git a/comparison/Inpla/src/qsort-260000-reuse.in b/comparison/Inpla/src/qsort-260000-reuse.in new file mode 100644 index 0000000..b44e958 --- /dev/null +++ b/comparison/Inpla/src/qsort-260000-reuse.in @@ -0,0 +1,44 @@ +// Quick sort +qsort(ret) >< [] => ret~(*R)[]; +qsort(ret) >< (int x):xs => + (*R)part(x, left, right)~xs, + (*L)qsort(cntl)~left, qsort(cntr)~right, + Append(ret, x:cntl)~cntr; + +// Note: `Append' is implemented as built-in. + + +part(int x, a, b) >< [] => a~(*L)[], b~(*R)[]; +part(int x, a, b) >< (int y):ys +| y<x => b~(*R)(y:cnt), (*L)part(x, a, cnt)~ys +| _ => a~(*R)(y:cnt), (*L)part(x, cnt, b)~ys; + + +// creates a random list +make_RandList(ret) >< (int n) +| n>0 => ret~(rd:cnt), (*L)make_RandList(cnt)~(n-1) + where rd=rand(10000) +| _ => ret~[]; + + +// validation checks +valid(ret) >< [] => ret~True; +valid(ret) >< x:xs => (*L)valid_Cons(ret,x)~xs; + +valid_Cons(ret, int x) >< [] => ret~True; +valid_Cons(ret, int x) >< (int y):ys +| x<=y => (*L)valid_Cons(ret,y)~ys +| _ => ret~False, Eraser~ys; + +// The `Eraser' is a built-in agent defined for any agents as follows: +//Eraser >< Alpha(a1, ..., a5) => Eraser~a1, ..., Eraser~a5; + + +// Main +const LIST_ELEM=260000; + +make_RandList(rndlist)~(LIST_ELEM), +qsort(sorted)~rndlist, +valid(ret)~sorted; + +ret; diff --git a/comparison/Inpla/src/qsort-260000.in b/comparison/Inpla/src/qsort-260000.in new file mode 100644 index 0000000..2f7d63c --- /dev/null +++ b/comparison/Inpla/src/qsort-260000.in @@ -0,0 +1,44 @@ +// Quick sort +qsort(ret) >< [] => ret~[]; +qsort(ret) >< (int x):xs => + part(x, left, right)~xs, + qsort(cntl)~left, qsort(cntr)~right, + Append(ret, x:cntl)~cntr; + +// Note: `Append' is implemented as built-in. + + +part(int x, a, b) >< [] => a~[], b~[]; +part(int x, a, b) >< (int y):ys +| y<x => b~(y:cnt), part(x, a, cnt)~ys +| _ => a~(y:cnt), part(x, cnt, b)~ys; + + +// creates a random list +make_RandList(ret) >< (int n) +| n>0 => ret~(rd:cnt), make_RandList(cnt)~(n-1) + where rd=rand(10000) +| _ => ret~[]; + + +// validation checks +valid(ret) >< [] => ret~True; +valid(ret) >< x:xs => valid_Cons(ret,x)~xs; + +valid_Cons(ret, int x) >< [] => ret~True; +valid_Cons(ret, int x) >< (int y):ys +| x<=y => valid_Cons(ret,y)~ys +| _ => ret~False, Eraser~ys; + +// The `Eraser' is a built-in agent defined for any agents as follows: +//Eraser >< Alpha(a1, ..., a5) => Eraser~a1, ..., Eraser~a5; + + +// Main +const LIST_ELEM=260000; + +make_RandList(rndlist)~(LIST_ELEM), +qsort(sorted)~rndlist, +valid(ret)~sorted; + +ret; diff --git a/comparison/OCaml/Makefile b/comparison/OCaml/Makefile index 94a4ffb..d300b15 100644 --- a/comparison/OCaml/Makefile +++ b/comparison/OCaml/Makefile @@ -1,8 +1,7 @@ CC = ocamlopt CFLAGS = BENCHMARK = bash ../tools/sptest_commands.sh -#TARGET = ack3_11 fib38 bsort40000 isort40000 qsort800000 msort800000 -TARGET = ack3_11 fib38 bsort40000 isort40000 +TARGET = ack3_11 fib38 bsort40000 isort40000 qsort260000 msort260000 LOG = log.txt @@ -25,10 +24,10 @@ bsort40000: bsort40000.ml isort40000: isort40000.ml $(CC) $(CFLAGS) $< -o $@ -qsort800000: qsort-800000.ml +qsort260000: qsort260000.ml $(CC) $(CFLAGS) $< -o $@ -msort800000: msort-800000.ml +msort260000: msort260000.ml $(CC) $(CFLAGS) $< -o $@ diff --git a/comparison/OCaml/bsort40000.ml b/comparison/OCaml/bsort40000.ml index 2a06e85..80c222e 100644 --- a/comparison/OCaml/bsort40000.ml +++ b/comparison/OCaml/bsort40000.ml @@ -1,3 +1,5 @@ +open Format + let rec bs (alist : int list) n = match alist with (x::y::ys) -> @@ -11,9 +13,12 @@ let rec go xs n = 0 -> xs | n -> go (bs xs n) (n-1);; -let bsort xs = go xs (List.length(xs) - 1);; - +let bsort alist = + match alist with + [] -> [] + | xs -> go xs (List.length(xs) - 1);; + let rec mkRandList n = match n with 0 -> [] @@ -31,5 +36,4 @@ let rec validation alist = | x::xs -> validation_cons x xs;; -let main = validation (bsort (mkRandList 40000));; - +let () = print_bool (validation (bsort (mkRandList 40000)));; diff --git a/comparison/OCaml/isort40000.ml b/comparison/OCaml/isort40000.ml index 92e127d..a1d00a5 100644 --- a/comparison/OCaml/isort40000.ml +++ b/comparison/OCaml/isort40000.ml @@ -1,3 +1,5 @@ +open Format + let rec insert x ylist = match ylist with [] -> [x] @@ -30,5 +32,5 @@ let rec validation alist = | x::xs -> validation_cons x xs;; -let main = validation(isort (mkRandList 40000));; +let () = print_bool (validation (isort (mkRandList 40000)));; diff --git a/comparison/OCaml/msort260000.ml b/comparison/OCaml/msort260000.ml new file mode 100644 index 0000000..a44f41a --- /dev/null +++ b/comparison/OCaml/msort260000.ml @@ -0,0 +1,49 @@ +open Format + +let rec split (alist : int list) = + match alist with + [] -> ([], []) + | [a] -> ([a], []) + | a::b::cs -> + let (m,n) = split cs in + (a::m, b::m) ;; + +let rec merge (alist : int list) (blist : int list) = + match alist with + [] -> blist + | x::xs -> + match blist with + [] -> x::xs + | y::ys -> + if x<y then x::(merge xs (y::ys)) + else y::(merge (x::xs) ys) ;; + + +let rec msort (alist : int list) = + match alist with + [] -> [] + | a::[] -> [a] + | a::b::[] -> if a<b then [a;b] else [b;a] + | xs -> + let (m,n) = split xs + in merge (msort m) (msort n) ;; + + + +let rec mkRandList n = + match n with + 0 -> [] + | n -> (Random.int 10000)::(mkRandList (n-1)) ;; + +let rec validation alist = + let rec validation_cons x blist = + match blist with + [] -> true + | y::ys -> if x<=y then (validation_cons y ys) else false + in + match alist with + [] -> true + | x::xs -> validation_cons x xs;; + + +let () = print_bool (validation (msort (mkRandList 260000)));; diff --git a/comparison/OCaml/qsort260000.ml b/comparison/OCaml/qsort260000.ml new file mode 100644 index 0000000..983ad50 --- /dev/null +++ b/comparison/OCaml/qsort260000.ml @@ -0,0 +1,38 @@ +open Format + +let rec split pivot (alist : int list) = + match alist with + [] -> ([], []) + | (x::xs) -> + let (below, above) = split pivot xs in + if x<pivot then (x::below, above) + else (below, x::above) ;; + +let rec qsort (alist : int list) = + match alist with + [] -> [] + | pivot::rest -> + let (below, above) = split pivot rest + in (qsort below) @ [pivot] @ (qsort above) ;; + + + + +let rec mkRandList n = + match n with + 0 -> [] + | n -> (Random.int 10000)::(mkRandList (n-1)) ;; + + +let rec validation alist = + let rec validation_cons x blist = + match blist with + [] -> true + | y::ys -> if x<=y then (validation_cons y ys) else false + in + match alist with + [] -> true + | x::xs -> validation_cons x xs;; + + +let () = print_bool (validation (qsort (mkRandList 260000)));; diff --git a/comparison/Python/Makefile b/comparison/Python/Makefile index fb6de82..21f4b3d 100644 --- a/comparison/Python/Makefile +++ b/comparison/Python/Makefile @@ -1,6 +1,5 @@ COMMAND = python3 -#TARGET = ack3-11.py fib38.py bsort-40000.py isort-40000.py qsort-800000.py msort-800000.py -TARGET = fib38.py bsort-40000.py isort-40000.py qsort-800000.py msort-800000.py +TARGET = dummy.py ack3-11.py fib38.py bsort-40000.py isort-40000.py qsort-260000.py msort-260000.py BENCHMARK = bash ../tools/sptest_scripts.sh LOG = log.txt diff --git a/comparison/Python/dummy.py b/comparison/Python/dummy.py new file mode 100644 index 0000000..98c2206 --- /dev/null +++ b/comparison/Python/dummy.py @@ -0,0 +1,64 @@ +# Python program for implementation of MergeSort +# https://www.geeksforgeeks.org/merge-sort/ +import random + +def mergeSort(arr): + if len(arr) > 1: + + # Finding the mid of the array + mid = len(arr)//2 + + # Dividing the array elements + L = arr[:mid] + + # into 2 halves + R = arr[mid:] + + # Sorting the first half + mergeSort(L) + + # Sorting the second half + mergeSort(R) + + i = j = k = 0 + + # Copy data to temp arrays L[] and R[] + while i < len(L) and j < len(R): + if L[i] < R[j]: + arr[k] = L[i] + i += 1 + else: + arr[k] = R[j] + j += 1 + k += 1 + + # Checking if any element was left + while i < len(L): + arr[k] = L[i] + i += 1 + k += 1 + + while j < len(R): + arr[k] = R[j] + j += 1 + k += 1 + + +def mkRandList ( n ): + a=[] + for i in range(1,n+1): + a.insert(0, random.randint(0,10000)) + return a + + +def validation(alist): + for i in range(len(alist)-1): + if (alist[i] > alist[i+1]): + return False + + return True + + +a = mkRandList(10) +mergeSort(a) +print(validation(a)) diff --git a/comparison/Python/msort-260000.py b/comparison/Python/msort-260000.py new file mode 100644 index 0000000..e7d7011 --- /dev/null +++ b/comparison/Python/msort-260000.py @@ -0,0 +1,64 @@ +# Python program for implementation of MergeSort +# https://www.geeksforgeeks.org/merge-sort/ +import random + +def mergeSort(arr): + if len(arr) > 1: + + # Finding the mid of the array + mid = len(arr)//2 + + # Dividing the array elements + L = arr[:mid] + + # into 2 halves + R = arr[mid:] + + # Sorting the first half + mergeSort(L) + + # Sorting the second half + mergeSort(R) + + i = j = k = 0 + + # Copy data to temp arrays L[] and R[] + while i < len(L) and j < len(R): + if L[i] < R[j]: + arr[k] = L[i] + i += 1 + else: + arr[k] = R[j] + j += 1 + k += 1 + + # Checking if any element was left + while i < len(L): + arr[k] = L[i] + i += 1 + k += 1 + + while j < len(R): + arr[k] = R[j] + j += 1 + k += 1 + + +def mkRandList ( n ): + a=[] + for i in range(1,n+1): + a.insert(0, random.randint(0,10000)) + return a + + +def validation(alist): + for i in range(len(alist)-1): + if (alist[i] > alist[i+1]): + return False + + return True + + +a = mkRandList(260000) +mergeSort(a) +print(validation(a)) diff --git a/comparison/Python/qsort-260000.py b/comparison/Python/qsort-260000.py new file mode 100644 index 0000000..fbca39d --- /dev/null +++ b/comparison/Python/qsort-260000.py @@ -0,0 +1,43 @@ +# Quicksort +import random + +# https://stackoverflow.com/questions/23767787/python-implementation-of-quicksort-fails-to-sort-the-entire-array +def quickSort(arr): + less = [] + pivotList = [] + more = [] + if len(arr) <= 1: + return arr + else: + pivot = arr[0] + for i in arr: + if i < pivot: + less.append(i) + elif i > pivot: + more.append(i) + else: + pivotList.append(i) + + less = quickSort(less) + more = quickSort(more) + return less + pivotList + more + + +def mkRandList ( n ): + a=[] + for i in range(1,n+1): + a.insert(0, random.randint(0,10000)) + return a + + +def validation(alist): + for i in range(len(alist)-1): + if (alist[i] > alist[i+1]): + return False + + return True + + +a = mkRandList(260000) +b = quickSort(a) +print(validation(b)) diff --git a/comparison/SML/Makefile b/comparison/SML/Makefile index 8520e9d..0e4e2e3 100644 --- a/comparison/SML/Makefile +++ b/comparison/SML/Makefile @@ -1,5 +1,5 @@ COMMAND = sml -TARGET = ack3-11.sml fib38.sml bsort-40000.sml isort-40000.sml qsort-800000.sml msort-800000.sml +TARGET = dummy.sml ack3-11.sml fib38.sml bsort-40000.sml isort-40000.sml qsort-260000.sml msort-260000.sml BENCHMARK = bash ../tools/sptest_scripts.sh LOG = log.txt diff --git a/comparison/SML/bsort-40000.sml b/comparison/SML/bsort-40000.sml index 5e6e98b..d9e1a00 100644 --- a/comparison/SML/bsort-40000.sml +++ b/comparison/SML/bsort-40000.sml @@ -12,7 +12,8 @@ fun go xs 0 = xs | go xs n = go (bs xs n) (n-1); -fun bsort xs = go xs (length(xs) - 1); +fun bsort [] = [] + | bsort xs = go xs (length(xs) - 1); (* Creates a random list *) diff --git a/comparison/SML/dummy.sml b/comparison/SML/dummy.sml new file mode 100644 index 0000000..15ff263 --- /dev/null +++ b/comparison/SML/dummy.sml @@ -0,0 +1,55 @@ +(* https://stackoverflow.com/questions/25839939/understanding-merge-sort-in-ml *) + +fun split [] = ([], []) + | split [a] = ([a], []) + | split (a::b::cs) = + let + val (m,n) = split cs + in + (a::m, b::n) + end; + +fun merge ([], ys) = ys + | merge (xs, []) = xs + | merge (x::xs, y::ys) = + if x<y then + x::merge(xs, y::ys) + else + y::merge(x::xs, ys); + +fun msort [] = [] + | msort [a] = [a] + | msort [a,b] = if a<b then [a,b] else [b,a] + | msort xs = + let + val (m,n) = split xs; + in + merge (msort m, msort n) + end; + + +(* Creates a random list *) +local + val nextInt = Random.randRange(1,10000); + val r = Random.rand(1,1); +in + fun mkRandList 0 = [] + | mkRandList n = (nextInt r)::(mkRandList (n-1)) +end; + + +(* Validation checks *) +fun validation [] = true + | validation (x::xs) = + let fun validation_cons x [] = true + | validation_cons x (y::ys) = + if x<=y then validation_cons y ys + else false + in + validation_cons x xs + end; + + +(* Main *) +validation(msort (mkRandList 10)); + diff --git a/comparison/SML/msort-260000.sml b/comparison/SML/msort-260000.sml new file mode 100644 index 0000000..754ef2f --- /dev/null +++ b/comparison/SML/msort-260000.sml @@ -0,0 +1,55 @@ +(* https://stackoverflow.com/questions/25839939/understanding-merge-sort-in-ml *) + +fun split [] = ([], []) + | split [a] = ([a], []) + | split (a::b::cs) = + let + val (m,n) = split cs + in + (a::m, b::n) + end; + +fun merge ([], ys) = ys + | merge (xs, []) = xs + | merge (x::xs, y::ys) = + if x<y then + x::merge(xs, y::ys) + else + y::merge(x::xs, ys); + +fun msort [] = [] + | msort [a] = [a] + | msort [a,b] = if a<b then [a,b] else [b,a] + | msort xs = + let + val (m,n) = split xs; + in + merge (msort m, msort n) + end; + + +(* Creates a random list *) +local + val nextInt = Random.randRange(1,10000); + val r = Random.rand(1,1); +in + fun mkRandList 0 = [] + | mkRandList n = (nextInt r)::(mkRandList (n-1)) +end; + + +(* Validation checks *) +fun validation [] = true + | validation (x::xs) = + let fun validation_cons x [] = true + | validation_cons x (y::ys) = + if x<=y then validation_cons y ys + else false + in + validation_cons x xs + end; + + +(* Main *) +validation(msort (mkRandList 260000)); + diff --git a/comparison/SML/qsort-260000.sml b/comparison/SML/qsort-260000.sml new file mode 100644 index 0000000..40bf8b7 --- /dev/null +++ b/comparison/SML/qsort-260000.sml @@ -0,0 +1,41 @@ +fun quicksort nil = nil + | quicksort (pivot :: rest) = + let + fun split(nil) = (nil,nil) + | split(x :: xs) = + let + val (below, above) = split(xs) + in + if x < pivot then (x :: below, above) + else (below, x :: above) + end; + val (below, above) = split(rest) + in + quicksort below @ [pivot] @ quicksort above + end; + + +(* Creates a random list *) +local + val nextInt = Random.randRange(1,10000); + val r = Random.rand(1,1); +in + fun mkRandList 0 = [] + | mkRandList n = (nextInt r)::(mkRandList (n-1)) +end; + + +(* Validation checks *) +fun validation [] = true + | validation (x::xs) = + let fun validation_cons x [] = true + | validation_cons x (y::ys) = + if x<=y then validation_cons y ys + else false + in + validation_cons x xs + end; + + +(* Main *) +validation(quicksort(mkRandList 260000)); diff --git a/pic/benchmark_reuse_v0.8.2-1.png b/pic/benchmark_reuse_v0.8.2-1.png Binary files differnew file mode 100644 index 0000000..4b18d82 --- /dev/null +++ b/pic/benchmark_reuse_v0.8.2-1.png diff --git a/sample/pow.in b/sample/pow.in new file mode 100644 index 0000000..a123b9f --- /dev/null +++ b/sample/pow.in @@ -0,0 +1,16 @@ +pow2(r, int m) >< (int n) +| n == 0 => r~m +| _ => pow2(r, m*2)~(n-1); + +pow(r) >< (int n) +| n == 0 => r~1 +| _ => pow2(r, 1)~(n); + + +// Caclulate 2^10 +const NUM=10; +pow(r)~NUM; // it can also be written with abbreviation: r << pow(NUM) +r; + + + @@ -11,7 +11,7 @@ #define MAX_SYMBOLS 256 typedef struct { char* sym[MAX_SYMBOLS]; - int val[MAX_SYMBOLS]; + long val[MAX_SYMBOLS]; int nth; } SymbolTable; @@ -71,9 +71,9 @@ int ast_getRecordedVal(int entry) { } -void recordVal(SymbolTable *table, char *name, int val) { +void recordVal(SymbolTable *table, char *name, long val) { int i; - + for (i=0; i< table->nth; i++) { if (strcmp(table->sym[i], name) == 0) { @@ -142,11 +142,11 @@ Ast *ast_makeSymbol(char *name) { return ptr; } -Ast *ast_makeInt(int num) { +Ast *ast_makeInt(long num) { Ast *ptr; ptr = ast_myalloc(); ptr->id = AST_INT; - ptr->intval = num; + ptr->longval = num; return ptr; } @@ -169,7 +169,7 @@ Ast *ast_makeAST(AST_ID id, Ast *left, Ast *right) { ptr = ast_myalloc(); ptr->id = AST_INT; - ptr->intval = ConstTable.val[entry]; + ptr->longval = ConstTable.val[entry]; return ptr; } } @@ -34,6 +34,7 @@ typedef enum { typedef struct abstract_syntax_tree { AST_ID id; int intval; + long longval; char *sym; struct abstract_syntax_tree *left,*right; } Ast; @@ -41,7 +42,7 @@ typedef struct abstract_syntax_tree { void ast_heapInit(void); void ast_heapReInit(void); Ast *ast_makeSymbol(char *name); -Ast *ast_makeInt(int num); +Ast *ast_makeInt(long num); Ast *ast_makeAST(AST_ID id, Ast *left, Ast *right); Ast *ast_makeTuple(Ast *tuple); Ast *ast_addLast(Ast *l, Ast *p); diff --git a/src/id_table.c b/src/id_table.c index 86655b5..bf8be22 100644 --- a/src/id_table.c +++ b/src/id_table.c @@ -86,7 +86,8 @@ void IdTable_init() { int IdTable_getid_builtin_funcAgent(Ast *agent) { // returns -1 if the agent is not built-in. - + + // puts("!!"); int id = -1; if (agent->id != AST_AGENT) { diff --git a/src/inpla.y b/src/inpla.y index c84703f..b681b03 100644 --- a/src/inpla.y +++ b/src/inpla.y @@ -22,8 +22,8 @@ // ---------------------------------------------- -#define VERSION "0.8.2" -#define BUILT_DATE "28 Apr. 2022" +#define VERSION "0.8.2-1" +#define BUILT_DATE "2 May 2022" // ------------------------------------------------------------------ @@ -153,13 +153,13 @@ static char *Errormsg = NULL; %} %union{ - int intval; + long longval; char *chval; Ast *ast; } %token <chval> NAME AGENT -%token <intval> INT_LITERAL +%token <longval> INT_LITERAL %token <chval> STRING_LITERAL %token LP RP LC RC LB RB COMMA CROSS DELIMITER ABR %token COLON @@ -2358,7 +2358,7 @@ void CodeAddr_init(void) { #define MAX_IMCODE_SEQUENCE 1024 struct IMCode_tag { int opcode; - int operand1, operand2, operand3, operand4, operand5, operand6, operand7; + long operand1, operand2, operand3, operand4, operand5, operand6, operand7; } IMCode[MAX_IMCODE_SEQUENCE]; int IMCode_n; @@ -2373,26 +2373,26 @@ void IMCode_genCode0(int opcode) { IMCode[IMCode_n++].opcode = opcode; IMCODE_OVERFLOW_CHECK } -void IMCode_genCode1(int opcode, int operand1) { +void IMCode_genCode1(int opcode, long operand1) { IMCode[IMCode_n].operand1 = operand1; IMCode[IMCode_n++].opcode = opcode; IMCODE_OVERFLOW_CHECK } -void IMCode_genCode2(int opcode, int operand1, int operand2) { +void IMCode_genCode2(int opcode, long operand1, long operand2) { IMCode[IMCode_n].operand1 = operand1; IMCode[IMCode_n].operand2 = operand2; IMCode[IMCode_n++].opcode = opcode; IMCODE_OVERFLOW_CHECK } -void IMCode_genCode3(int opcode, int operand1, int operand2, int operand3) { +void IMCode_genCode3(int opcode, long operand1, long operand2, long operand3) { IMCode[IMCode_n].operand1 = operand1; IMCode[IMCode_n].operand2 = operand2; IMCode[IMCode_n].operand3 = operand3; IMCode[IMCode_n++].opcode = opcode; IMCODE_OVERFLOW_CHECK } -void IMCode_genCode4(int opcode, int operand1, int operand2, int operand3, - int operand4) { +void IMCode_genCode4(int opcode, long operand1, long operand2, long operand3, + long operand4) { IMCode[IMCode_n].operand1 = operand1; IMCode[IMCode_n].operand2 = operand2; IMCode[IMCode_n].operand3 = operand3; @@ -2400,8 +2400,8 @@ void IMCode_genCode4(int opcode, int operand1, int operand2, int operand3, IMCode[IMCode_n++].opcode = opcode; IMCODE_OVERFLOW_CHECK } -void IMCode_genCode5(int opcode, int operand1, int operand2, int operand3, - int operand4, int operand5) { +void IMCode_genCode5(int opcode, long operand1, long operand2, long operand3, + long operand4, long operand5) { IMCode[IMCode_n].operand1 = operand1; IMCode[IMCode_n].operand2 = operand2; IMCode[IMCode_n].operand3 = operand3; @@ -2410,8 +2410,8 @@ void IMCode_genCode5(int opcode, int operand1, int operand2, int operand3, IMCode[IMCode_n++].opcode = opcode; IMCODE_OVERFLOW_CHECK } -void IMCode_genCode6(int opcode, int operand1, int operand2, int operand3, - int operand4, int operand5, int operand6) { +void IMCode_genCode6(int opcode, long operand1, long operand2, long operand3, + long operand4, long operand5, long operand6) { IMCode[IMCode_n].operand1 = operand1; IMCode[IMCode_n].operand2 = operand2; IMCode[IMCode_n].operand3 = operand3; @@ -2421,8 +2421,8 @@ void IMCode_genCode6(int opcode, int operand1, int operand2, int operand3, IMCode[IMCode_n++].opcode = opcode; IMCODE_OVERFLOW_CHECK } -void IMCode_genCode7(int opcode, int operand1, int operand2, int operand3, - int operand4, int operand5, int operand6, int operand7) { +void IMCode_genCode7(int opcode, long operand1, long operand2, long operand3, + long operand4, long operand5, long operand6, long operand7) { IMCode[IMCode_n].operand1 = operand1; IMCode[IMCode_n].operand2 = operand2; IMCode[IMCode_n].operand3 = operand3; @@ -2498,47 +2498,47 @@ void IMCode_puts(int n) { switch (imcode->opcode) { case OP_MKNAME: - printf("%s var%d\n", string_opcode[imcode->opcode], + printf("%s var%ld\n", string_opcode[imcode->opcode], imcode->operand1); break; case OP_MKGNAME: - printf("%s id:%d var%d; \"%s\"\n", string_opcode[imcode->opcode], + printf("%s id:%ld var%ld; \"%s\"\n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2, IdTable_get_name(imcode->operand1)); break; case OP_MKAGENT0: - printf("%s id:%d var%d\n", string_opcode[imcode->opcode], + printf("%s id:%ld var%ld\n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2); break; case OP_MKAGENT1: - printf("%s id:%d var%d var%d\n", string_opcode[imcode->opcode], + printf("%s id:%ld var%ld var%ld\n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2, imcode->operand3); break; case OP_MKAGENT2: - printf("%s id:%d var%d var%d var%d\n", string_opcode[imcode->opcode], + printf("%s id:%ld var%ld var%ld var%ld\n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2, imcode->operand3, imcode->operand4); break; case OP_MKAGENT3: - printf("%s id:%d var%d var%d var%d var%d\n", string_opcode[imcode->opcode], + printf("%s id:%ld var%ld var%ld var%ld var%ld\n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2, imcode->operand3, imcode->operand4, imcode->operand5); break; case OP_MKAGENT4: - printf("%s id:%d var%d var%d var%d var%d var%d \n", string_opcode[imcode->opcode], + printf("%s id:%ld var%ld var%ld var%ld var%ld var%ld \n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2, imcode->operand3, imcode->operand4, imcode->operand5, imcode->operand6); break; case OP_MKAGENT5: - printf("%s id:%d var%d var%d var%d var%d var%d var%d \n", string_opcode[imcode->opcode], + printf("%s id:%ld var%ld var%ld var%ld var%ld var%ld var%ld \n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2, imcode->operand3, imcode->operand4, imcode->operand5, imcode->operand6, imcode->operand7); @@ -2546,36 +2546,36 @@ void IMCode_puts(int n) { case OP_REUSEAGENT0: - printf("%s var%d id:%d\n", string_opcode[imcode->opcode], + printf("%s var%ld id:%ld\n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2); break; case OP_REUSEAGENT1: - printf("%s var%d id:%d var%d\n", string_opcode[imcode->opcode], + printf("%s var%ld id:%ld var%ld\n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2, imcode->operand3); break; case OP_REUSEAGENT2: - printf("%s var%d id:%d var%d var%d\n", string_opcode[imcode->opcode], + printf("%s var%ld id:%ld var%ld var%ld\n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2, imcode->operand3, imcode->operand4); break; case OP_REUSEAGENT3: - printf("%s var%d id:%d var%d var%d var%d\n", string_opcode[imcode->opcode], + printf("%s var%ld id:%ld var%ld var%ld var%ld\n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2, imcode->operand3, imcode->operand4, imcode->operand5); break; case OP_REUSEAGENT4: - printf("%s var%d id:%d var%d var%d var%d var%d\n", string_opcode[imcode->opcode], + printf("%s var%ld id:%ld var%ld var%ld var%ld var%ld\n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2, imcode->operand3, imcode->operand4, imcode->operand5, imcode->operand6); break; case OP_REUSEAGENT5: - printf("%s var%d id:%d var%d var%d var%d var%d var%d\n", + printf("%s var%ld id:%ld var%ld var%ld var%ld var%ld var%ld\n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2, imcode->operand3, imcode->operand4, imcode->operand5, @@ -2584,7 +2584,7 @@ void IMCode_puts(int n) { case OP_LABEL: - printf("%s%d:\n", string_opcode[imcode->opcode], + printf("%s%ld:\n", string_opcode[imcode->opcode], imcode->operand1); break; @@ -2612,7 +2612,7 @@ void IMCode_puts(int n) { case OP_LOOP_RREC2: case OP_LOOP_RREC1_FREE_R: case OP_LOOP_RREC2_FREE_R: - printf("%s var%d\n", string_opcode[imcode->opcode], + printf("%s var%ld\n", string_opcode[imcode->opcode], imcode->operand1); break; @@ -2632,7 +2632,7 @@ void IMCode_puts(int n) { case OP_NE_R0: case OP_CNCTGN: case OP_SUBSTGN: - printf("%s var%d var%d\n", string_opcode[imcode->opcode], + printf("%s var%ld var%ld\n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2); break; @@ -2641,14 +2641,14 @@ void IMCode_puts(int n) { case OP_PUSHI: case OP_LOADI: case OP_EQI_R0: - printf("%s $%d var%d\n", string_opcode[imcode->opcode], + printf("%s $%ld var%ld\n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2); break; case OP_LOOP_RREC: case OP_LOOP_RREC_FREE_R: - printf("%s var%d $%d\n", string_opcode[imcode->opcode], + printf("%s var%ld $%ld\n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2); break; @@ -2664,7 +2664,7 @@ void IMCode_puts(int n) { case OP_LE: case OP_EQ: case OP_NE: - printf("%s var%d var%d var%d\n", string_opcode[imcode->opcode], + printf("%s var%ld var%ld var%ld\n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2, imcode->operand3); break; @@ -2673,7 +2673,7 @@ void IMCode_puts(int n) { case OP_ADDI: case OP_SUBI: case OP_EQI: - printf("%s var%d $%d var%d\n", string_opcode[imcode->opcode], + printf("%s var%ld $%ld var%ld\n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2, imcode->operand3); break; @@ -2682,7 +2682,7 @@ void IMCode_puts(int n) { case OP_JMPEQ0: case OP_JMPNEQ0: case OP_JMPCNCT_CONS: - printf("%s var%d %s%d\n", string_opcode[imcode->opcode], + printf("%s var%ld %s%ld\n", string_opcode[imcode->opcode], imcode->operand1, string_opcode[OP_LABEL],imcode->operand2); break; @@ -2690,26 +2690,26 @@ void IMCode_puts(int n) { // arity is 3: opcode var1 id2 LABEL3 case OP_JMPCNCT: - printf("%s var%d id:%d %s%d\n", string_opcode[imcode->opcode], + printf("%s var%ld id:%ld %s%ld\n", string_opcode[imcode->opcode], imcode->operand1, imcode->operand2, string_opcode[OP_LABEL],imcode->operand3); break; // others case OP_JMPEQ0_R0: - printf("%s %s%d\n", string_opcode[imcode->opcode], + printf("%s %s%ld\n", string_opcode[imcode->opcode], string_opcode[OP_LABEL],imcode->operand1); break; case OP_JMP: - printf("%s %s%d\n", string_opcode[imcode->opcode], + printf("%s %s%ld\n", string_opcode[imcode->opcode], string_opcode[OP_LABEL],imcode->operand1); break; default: - printf("CODE %d %d %d %d %d %d\n", + printf("CODE %ld %ld %ld %ld %ld %ld\n", imcode->operand1, imcode->operand2, imcode->operand3, imcode->operand4, imcode->operand5, imcode->operand6); } @@ -3831,7 +3831,7 @@ int CmEnv_Optimise_check_occurence_in_block(int localvar, int CmEnv_Optimise_VMCode_CopyPropagation_LOADI(int target_imcode_addr) { struct IMCode_tag *imcode; - int load_i, load_to; + long load_i, load_to; load_i = IMCode[target_imcode_addr].operand1; load_to = IMCode[target_imcode_addr].operand2; @@ -4214,7 +4214,7 @@ int CmEnv_generate_VMCode(void **code) { switch (imcode->opcode) { case OP_MKNAME: { // printf("OP_MKNAME var%d\n", imcode->operand1); - int dest = imcode->operand1; + long dest = imcode->operand1; #ifdef OPTIMISE_IMCODE dest = CmEnv_get_newreg(dest); @@ -4228,7 +4228,7 @@ int CmEnv_generate_VMCode(void **code) { // printf("OP_MKGNAME sym:%d var%d (as `%s')\n", // imcode->operand1, imcode->operand2, // CmEnv.bind[imcode->operand1].name); - int dest = imcode->operand2; + long dest = imcode->operand2; #ifdef OPTIMISE_IMCODE dest = CmEnv_get_newreg(dest); @@ -4244,7 +4244,7 @@ int CmEnv_generate_VMCode(void **code) { case OP_MKAGENT0: { // printf("OP_MKAGENT0 id var%d:%d\n", // imcode->operand1, imcode->operand2); - int dest = imcode->operand2; + long dest = imcode->operand2; #ifdef OPTIMISE_IMCODE dest = CmEnv_get_newreg(dest); @@ -4258,8 +4258,8 @@ int CmEnv_generate_VMCode(void **code) { case OP_MKAGENT1: { // printf("OP_MKAGENT1 id:%d var%d var%d\n", // imcode->operand1, imcode->operand2, imcode->operand3); - int src1 = imcode->operand2; - int dest = imcode->operand3; + long src1 = imcode->operand2; + long dest = imcode->operand3; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -4293,9 +4293,9 @@ int CmEnv_generate_VMCode(void **code) { // imcode->operand1, imcode->operand2, // imcode->operand3, imcode->operand4); - int src1 = imcode->operand2; - int src2 = imcode->operand3; - int dest = imcode->operand4; + long src1 = imcode->operand2; + long src2 = imcode->operand3; + long dest = imcode->operand4; #ifdef OPTIMISE_IMCODE @@ -4338,10 +4338,10 @@ int CmEnv_generate_VMCode(void **code) { // printf("OP_MKAGENT3 id:%d var%d var%d var%d var%d \n", // imcode->operand1, imcode->operand2, // imcode->operand3, imcode->operand4, imcode->operand5); - int src1 = imcode->operand2; - int src2 = imcode->operand3; - int src3 = imcode->operand4; - int dest = imcode->operand5; + long src1 = imcode->operand2; + long src2 = imcode->operand3; + long src3 = imcode->operand4; + long dest = imcode->operand5; #ifdef OPTIMISE_IMCODE @@ -4389,11 +4389,11 @@ int CmEnv_generate_VMCode(void **code) { // printf("OP_MKAGENT4 var%d id:%d var%d var%d var%d var%d\n", // imcode->operand1, imcode->operand2, // imcode->operand3, imcode->operand4, imcode->operand5); - int src1 = imcode->operand2; - int src2 = imcode->operand3; - int src3 = imcode->operand4; - int src4 = imcode->operand5; - int dest = imcode->operand6; + long src1 = imcode->operand2; + long src2 = imcode->operand3; + long src3 = imcode->operand4; + long src4 = imcode->operand5; + long dest = imcode->operand6; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -4435,12 +4435,12 @@ int CmEnv_generate_VMCode(void **code) { // printf("OP_MKAGENT5 var%d id:%d var%d var%d var%d var%d\n", // imcode->operand1, imcode->operand2, // imcode->operand3, imcode->operand4, imcode->operand5); - int src1 = imcode->operand2; - int src2 = imcode->operand3; - int src3 = imcode->operand4; - int src4 = imcode->operand5; - int src5 = imcode->operand6; - int dest = imcode->operand7; + long src1 = imcode->operand2; + long src2 = imcode->operand3; + long src3 = imcode->operand4; + long src4 = imcode->operand5; + long src5 = imcode->operand6; + long dest = imcode->operand7; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -4505,8 +4505,8 @@ int CmEnv_generate_VMCode(void **code) { case OP_REUSEAGENT1: { // printf("OP_REUSEAGENT1 var%d id:%d var%d\n", // imcode->operand1, imcode->operand2, imcode->operand3); - int dest = imcode->operand1; - int src1 = imcode->operand3; + long dest = imcode->operand1; + long src1 = imcode->operand3; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -4522,9 +4522,9 @@ int CmEnv_generate_VMCode(void **code) { } case OP_REUSEAGENT2: { - int dest = imcode->operand1; - int src1 = imcode->operand3; - int src2 = imcode->operand4; + long dest = imcode->operand1; + long src1 = imcode->operand3; + long src2 = imcode->operand4; #ifdef OPTIMISE_IMCODE @@ -4552,10 +4552,10 @@ int CmEnv_generate_VMCode(void **code) { // printf("OP_REUSEAGENT3 var%d id:%d var%d var%d var%d\n", // imcode->operand1, imcode->operand2, // imcode->operand3, imcode->operand4, imcode->operand5); - int dest = imcode->operand1; - int src1 = imcode->operand3; - int src2 = imcode->operand4; - int src3 = imcode->operand5; + long dest = imcode->operand1; + long src1 = imcode->operand3; + long src2 = imcode->operand4; + long src3 = imcode->operand5; #ifdef OPTIMISE_IMCODE @@ -4589,11 +4589,11 @@ int CmEnv_generate_VMCode(void **code) { // printf("OP_REUSEAGENT3 var%d id:%d var%d var%d var%d\n", // imcode->operand1, imcode->operand2, // imcode->operand3, imcode->operand4, imcode->operand5); - int dest = imcode->operand1; - int src1 = imcode->operand3; - int src2 = imcode->operand4; - int src3 = imcode->operand5; - int src4 = imcode->operand6; + long dest = imcode->operand1; + long src1 = imcode->operand3; + long src2 = imcode->operand4; + long src3 = imcode->operand5; + long src4 = imcode->operand6; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -4633,12 +4633,12 @@ int CmEnv_generate_VMCode(void **code) { // printf("OP_REUSEAGENT3 var%d id:%d var%d var%d var%d\n", // imcode->operand1, imcode->operand2, // imcode->operand3, imcode->operand4, imcode->operand5); - int dest = imcode->operand1; - int src1 = imcode->operand3; - int src2 = imcode->operand4; - int src3 = imcode->operand5; - int src4 = imcode->operand6; - int src5 = imcode->operand7; + long dest = imcode->operand1; + long src1 = imcode->operand3; + long src2 = imcode->operand4; + long src3 = imcode->operand5; + long src4 = imcode->operand6; + long src5 = imcode->operand7; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -4687,8 +4687,8 @@ int CmEnv_generate_VMCode(void **code) { case OP_LOAD: { // OP_LOAD src1 dest - int src1 = imcode->operand1; - int dest = imcode->operand2; + long src1 = imcode->operand1; + long dest = imcode->operand2; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -4713,8 +4713,8 @@ int CmEnv_generate_VMCode(void **code) { case OP_LOAD_META: { // OP_LOAD_META src1 dest // the dest is used as it is - int src1 = imcode->operand1; - int dest = imcode->operand2; + long src1 = imcode->operand1; + long dest = imcode->operand2; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -4744,7 +4744,7 @@ int CmEnv_generate_VMCode(void **code) { case OP_LOADI: { // OP_LOADI int1 dest - int dest = imcode->operand2; + long dest = imcode->operand2; #ifdef OPTIMISE_IMCODE dest = CmEnv_get_newreg(dest); @@ -4762,8 +4762,8 @@ int CmEnv_generate_VMCode(void **code) { case OP_MYPUSH: { // printf("OP_PUSH var%d var%d\n", // imcode->operand1, imcode->operand2); - int src1 = imcode->operand1; - int src2 = imcode->operand2; + long src1 = imcode->operand1; + long src2 = imcode->operand2; #ifdef OPTIMISE_IMCODE @@ -4799,7 +4799,7 @@ int CmEnv_generate_VMCode(void **code) { case OP_JMPNEQ0: case OP_JMPCNCT_CONS: { // OP_JMPEQ0 reg label - int src1 = imcode->operand1; + long src1 = imcode->operand1; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -4834,9 +4834,9 @@ int CmEnv_generate_VMCode(void **code) { case OP_EQ: case OP_NE: { // op src1 src2 dest - int src1 = imcode->operand1; - int src2 = imcode->operand2; - int dest = imcode->operand3; + long src1 = imcode->operand1; + long src2 = imcode->operand2; + long dest = imcode->operand3; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -4862,8 +4862,8 @@ int CmEnv_generate_VMCode(void **code) { case OP_ADDI: case OP_SUBI: { // op src1 $2 dest - int src1 = imcode->operand1; - int dest = imcode->operand3; + long src1 = imcode->operand1; + long dest = imcode->operand3; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -4884,8 +4884,8 @@ int CmEnv_generate_VMCode(void **code) { case OP_EQI: { // op src1 int2fix($2) dest - int src1 = imcode->operand1; - int dest = imcode->operand3; + long src1 = imcode->operand1; + long dest = imcode->operand3; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -4908,8 +4908,8 @@ int CmEnv_generate_VMCode(void **code) { case OP_EQ_R0: case OP_NE_R0: { // op src1 src2 - int src1 = imcode->operand1; - int src2 = imcode->operand2; + long src1 = imcode->operand1; + long src2 = imcode->operand2; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -4948,7 +4948,7 @@ int CmEnv_generate_VMCode(void **code) { #endif - int src1 = imcode->operand1; + long src1 = imcode->operand1; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -4968,8 +4968,8 @@ int CmEnv_generate_VMCode(void **code) { case OP_DEC: case OP_RAND: { // op src dest - int src1 = imcode->operand1; - int dest = imcode->operand2; + long src1 = imcode->operand1; + long dest = imcode->operand2; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -4999,7 +4999,7 @@ int CmEnv_generate_VMCode(void **code) { case OP_PUSHI: { // OP src1 int2 - int src1 = imcode->operand1; + long src1 = imcode->operand1; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -5032,7 +5032,7 @@ int CmEnv_generate_VMCode(void **code) { case OP_LOOP_RREC2_FREE_R: { // printf("OP_LOOP_RREC1 var%d\n", // imcode->operand1); - int src1 = imcode->operand1; + long src1 = imcode->operand1; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -5050,7 +5050,7 @@ int CmEnv_generate_VMCode(void **code) { case OP_LOOP_RREC_FREE_R: { // printf("OP_LOOP_RREC1 var%d $%d\n", // imcode->operand1, imcode->operand2); - int src1 = imcode->operand1; + long src1 = imcode->operand1; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -5068,7 +5068,7 @@ int CmEnv_generate_VMCode(void **code) { // OP_JMPCNCT var id label // printf("OP_JMPCNCT var%d id:%d $%d\n", // imcode->operand1, imcode->operand2, imcode->operand3); - int src1 = imcode->operand1; + long src1 = imcode->operand1; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -5100,8 +5100,8 @@ int CmEnv_generate_VMCode(void **code) { case OP_SUBSTGN: { // printf("OP_CNCTGN var%d $%d\n", // imcode->operand1, imcode->operand2); - int src1 = imcode->operand1; - int src2 = imcode->operand2; + long src1 = imcode->operand1; + long src2 = imcode->operand2; #ifdef OPTIMISE_IMCODE src1 = CmEnv_using_reg(src1); @@ -5159,7 +5159,7 @@ int CmEnv_generate_VMCode(void **code) { // two pass for label for (int i=0; i<backpatch_num; i++) { int hole_addr = backpatch_table[i]; - int jmp_label = (unsigned long)code[hole_addr]; + long jmp_label = (unsigned long)code[hole_addr]; code[hole_addr] = (void *)(unsigned long) (label_table[jmp_label]-(hole_addr+1)); } @@ -5677,10 +5677,9 @@ int Compile_expr_on_ast(Ast *ptr, int target) { if (ptr == NULL) { return 1; } - switch (ptr->id) { case AST_INT: - IMCode_genCode2(OP_LOADI, ptr->intval, target); + IMCode_genCode2(OP_LOADI, ptr->longval, target); return 1; break; @@ -5883,7 +5882,7 @@ int Compile_term_on_ast(Ast *ptr, int target) { int i, arity; int alloc[MAX_PORT]; - + if (ptr == NULL) { return -1; } @@ -5901,8 +5900,7 @@ int Compile_term_on_ast(Ast *ptr, int target) { case AST_INT: result = CmEnv_newvar(); - - IMCode_genCode2(OP_LOADI, ptr->intval, result); + IMCode_genCode2(OP_LOADI, ptr->longval, result); return result; break; @@ -6038,7 +6036,6 @@ int Compile_term_on_ast(Ast *ptr, int target) { case AST_AGENT: - if (target == -1) { result = CmEnv_newvar(); } else { @@ -6046,6 +6043,7 @@ int Compile_term_on_ast(Ast *ptr, int target) { } int id = IdTable_getid_builtin_funcAgent(ptr); + if (id == -1) { id = NameTable_get_set_id_with_IdTable_forAgent((char *)ptr->left->sym); } @@ -6547,7 +6545,7 @@ int Compile_stmlist_on_ast(Ast *at) { } else if (ptr->right->id == AST_INT) { // y is an integer - IMCode_genCode2(OP_LOADI, ptr->right->intval, toRegLeft); + IMCode_genCode2(OP_LOADI, ptr->right->longval, toRegLeft); } else { // y is an expression @@ -7986,8 +7984,8 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("ADD src1 src2 dest"); pc++; { - int i = FIX2INT(reg[(unsigned long)code[pc++]]); - int j = FIX2INT(reg[(unsigned long)code[pc++]]); + long i = FIX2INT(reg[(unsigned long)code[pc++]]); + long j = FIX2INT(reg[(unsigned long)code[pc++]]); reg[(unsigned long)code[pc++]] = INT2FIX(i+j); } @@ -7997,8 +7995,8 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("SUB src1 src2 dest"); pc++; { - int i = FIX2INT(reg[(unsigned long)code[pc++]]); - int j = FIX2INT(reg[(unsigned long)code[pc++]]); + long i = FIX2INT(reg[(unsigned long)code[pc++]]); + long j = FIX2INT(reg[(unsigned long)code[pc++]]); reg[(unsigned long)code[pc++]] = INT2FIX(i-j); } @@ -8009,8 +8007,8 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("ADDI src int dest"); pc++; { - int i = FIX2INT(reg[(unsigned long)code[pc++]]); - int j = (unsigned long)code[pc++]; + long i = FIX2INT(reg[(unsigned long)code[pc++]]); + long j = (unsigned long)code[pc++]; reg[(unsigned long)code[pc++]] = INT2FIX(i+j); } @@ -8021,8 +8019,8 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("SUBI src int dest"); pc++; { - int i = FIX2INT(reg[(unsigned long)code[pc++]]); - int j = (unsigned long)code[pc++]; + long i = FIX2INT(reg[(unsigned long)code[pc++]]); + long j = (unsigned long)code[pc++]; reg[(unsigned long)code[pc++]] = INT2FIX(i-j); } @@ -8033,8 +8031,8 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("MUL src1 src2 dest"); pc++; { - int i = FIX2INT(reg[(unsigned long)code[pc++]]); - int j = FIX2INT(reg[(unsigned long)code[pc++]]); + long i = FIX2INT(reg[(unsigned long)code[pc++]]); + long j = FIX2INT(reg[(unsigned long)code[pc++]]); reg[(unsigned long)code[pc++]] = INT2FIX(i*j); } @@ -8045,8 +8043,8 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("DIV src1 src2 dest"); pc++; { - int i = FIX2INT(reg[(unsigned long)code[pc++]]); - int j = FIX2INT(reg[(unsigned long)code[pc++]]); + long i = FIX2INT(reg[(unsigned long)code[pc++]]); + long j = FIX2INT(reg[(unsigned long)code[pc++]]); reg[(unsigned long)code[pc++]] = INT2FIX(i/j); } @@ -8056,8 +8054,8 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("MOD src1 src2 dest"); pc++; { - int i = FIX2INT(reg[(unsigned long)code[pc++]]); - int j = FIX2INT(reg[(unsigned long)code[pc++]]); + long i = FIX2INT(reg[(unsigned long)code[pc++]]); + long j = FIX2INT(reg[(unsigned long)code[pc++]]); reg[(unsigned long)code[pc++]] = INT2FIX(i%j); } @@ -8069,8 +8067,8 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { { // int i = FIX2INT(reg[(unsigned long)code[pc++]]); // int j = FIX2INT(reg[(unsigned long)code[pc++]]); - int i = reg[(unsigned long)code[pc++]]; - int j = reg[(unsigned long)code[pc++]]; + long i = reg[(unsigned long)code[pc++]]; + long j = reg[(unsigned long)code[pc++]]; if (i<j) { reg[(unsigned long)code[pc++]] = INT2FIX(1); @@ -8085,8 +8083,8 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("LT src1 src2 dest"); pc++; { - int i = reg[(unsigned long)code[pc++]]; - int j = reg[(unsigned long)code[pc++]]; + long i = reg[(unsigned long)code[pc++]]; + long j = reg[(unsigned long)code[pc++]]; if (i<=j) { reg[(unsigned long)code[pc++]] = INT2FIX(1); @@ -8101,8 +8099,8 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("EQ src1 src2 dest"); pc++; { - int i = reg[(unsigned long)code[pc++]]; - int j = reg[(unsigned long)code[pc++]]; + long i = reg[(unsigned long)code[pc++]]; + long j = reg[(unsigned long)code[pc++]]; if (i==j) { reg[(unsigned long)code[pc++]] = INT2FIX(1); @@ -8118,8 +8116,8 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("EQI src1 fixint dest"); pc++; { - int i = reg[(unsigned long)code[pc++]]; - int j = (unsigned long)code[pc++]; + long i = reg[(unsigned long)code[pc++]]; + long j = (unsigned long)code[pc++]; if (i==j) { reg[(unsigned long)code[pc++]] = INT2FIX(1); @@ -8135,8 +8133,8 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("NE src1 src2 dest"); pc++; { - int i = reg[(unsigned long)code[pc++]]; - int j = reg[(unsigned long)code[pc++]]; + long i = reg[(unsigned long)code[pc++]]; + long j = reg[(unsigned long)code[pc++]]; if (i!=j) { reg[(unsigned long)code[pc++]] = INT2FIX(1); @@ -8152,8 +8150,8 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("LT_R0 src1 src2"); pc++; { - int i = reg[(unsigned long)code[pc++]]; - int j = reg[(unsigned long)code[pc++]]; + long i = reg[(unsigned long)code[pc++]]; + long j = reg[(unsigned long)code[pc++]]; if (i<j) { reg[0] = 1; @@ -8168,8 +8166,8 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("LE_R0 src1 src2"); pc++; { - int i = reg[(unsigned long)code[pc++]]; - int j = reg[(unsigned long)code[pc++]]; + long i = reg[(unsigned long)code[pc++]]; + long j = reg[(unsigned long)code[pc++]]; if (i<=j) { reg[0] = 1; @@ -8184,8 +8182,8 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("EQ_R0 src1 src2"); pc++; { - int i = reg[(unsigned long)code[pc++]]; - int j = reg[(unsigned long)code[pc++]]; + long i = reg[(unsigned long)code[pc++]]; + long j = reg[(unsigned long)code[pc++]]; if (i==j) { reg[0] = 1; @@ -8200,8 +8198,8 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("EQI_R0 src1 int"); pc++; { - int i = reg[(unsigned long)code[pc++]]; - int j = (unsigned long)code[pc++]; + long i = reg[(unsigned long)code[pc++]]; + long j = (unsigned long)code[pc++]; if (i==j) { reg[0] = 1; @@ -8218,8 +8216,8 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("NE_R0 src1 src2"); pc++; { - int i = reg[(unsigned long)code[pc++]]; - int j = reg[(unsigned long)code[pc++]]; + long i = reg[(unsigned long)code[pc++]]; + long j = reg[(unsigned long)code[pc++]]; if (i!=j) { reg[0] = 1; @@ -8237,7 +8235,7 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // the pc is a relative address, not absolute one! pc++; { - int i = reg[(unsigned long)code[pc++]]; + long i = reg[(unsigned long)code[pc++]]; if (!FIX2INT(i)) { int j = (unsigned long)code[pc++]; pc += j; @@ -8252,7 +8250,7 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("JMPEQ0_R0 pc"); pc++; { - int i = reg[0]; + long i = reg[0]; if (!i) { int j = (unsigned long)code[pc++]; pc += j; @@ -8269,7 +8267,7 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("JMPNEQ0 reg pc"); pc++; { - int i = reg[(unsigned long)code[pc++]]; + long i = reg[(unsigned long)code[pc++]]; if (FIX2INT(i)) { int j = (unsigned long)code[pc++]; pc += j; @@ -8389,14 +8387,14 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("UNM src dest"); pc++; { - int i = FIX2INT(reg[(unsigned long)code[pc++]]); + long i = FIX2INT(reg[(unsigned long)code[pc++]]); reg[(unsigned long)code[pc++]] = INT2FIX(-1 * i); } #else // puts("UNM dest"); pc++; { - int i = FIX2INT(reg[(unsigned long)code[pc]]); + long i = FIX2INT(reg[(unsigned long)code[pc]]); reg[(unsigned long)code[pc++]] = INT2FIX(-1 * i); } #endif @@ -8408,14 +8406,14 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("RAND src dest"); pc++; { - int i = FIX2INT(reg[(unsigned long)code[pc++]]); + long i = FIX2INT(reg[(unsigned long)code[pc++]]); reg[(unsigned long)code[pc++]] = INT2FIX(rand() % i); } #else // puts("RAND dest"); pc++; { - int i = FIX2INT(reg[(unsigned long)code[pc]]); + long i = FIX2INT(reg[(unsigned long)code[pc]]); reg[(unsigned long)code[pc++]] = INT2FIX(rand() % i); } #endif @@ -8427,14 +8425,14 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("INC src dest"); pc++; { - int i = FIX2INT(reg[(unsigned long)code[pc++]]); + long i = FIX2INT(reg[(unsigned long)code[pc++]]); reg[(unsigned long)code[pc++]] = INT2FIX(++i); } #else // puts("INC src"); pc++; { - int i = FIX2INT(reg[(unsigned long)code[pc]]); + long i = FIX2INT(reg[(unsigned long)code[pc]]); reg[(unsigned long)code[pc++]] = INT2FIX(++i); } #endif @@ -8446,14 +8444,14 @@ void *exec_code(int mode, VirtualMachine * restrict vm, void * restrict *code) { // puts("DEC src dest"); pc++; { - int i = FIX2INT(reg[(unsigned long)code[pc++]]); + long i = FIX2INT(reg[(unsigned long)code[pc++]]); reg[(unsigned long)code[pc++]] = INT2FIX(--i); } #else // puts("DEC dest"); pc++; { - int i = FIX2INT(reg[(unsigned long)code[pc]]); + long i = FIX2INT(reg[(unsigned long)code[pc]]); reg[(unsigned long)code[pc++]] = INT2FIX(--i); } @@ -8519,7 +8517,7 @@ void exec_code_fib(VirtualMachine * restrict vm) { // 0000: jmpneq0 reg12 $4 { - int i = reg[12]; + long i = reg[12]; if (FIX2INT(i)) { goto LABEL_0007; } @@ -8539,8 +8537,8 @@ void exec_code_fib(VirtualMachine * restrict vm) { // 0007: eqi_r0 reg12 $1 LABEL_0007: { - int i = reg[12]; - int j = INT2FIX(1); + long i = reg[12]; + long j = INT2FIX(1); if (i==j) { reg[0] = 1; @@ -8551,7 +8549,7 @@ LABEL_0007: // 0010: jmpeq0_r0 $4 { - int i = reg[0]; + long i = reg[0]; if (!i) { goto LABEL_0016; } @@ -8597,7 +8595,7 @@ LABEL_0016: // 0027: dec reg12 reg15 { - int i = FIX2INT(reg[12]); + long i = FIX2INT(reg[12]); reg[15] = INT2FIX(--i); } @@ -8619,8 +8617,8 @@ LABEL_0016: // 0037: subi reg12 $2 reg14 { - int i = FIX2INT(reg[12]); - int j = 2; + long i = FIX2INT(reg[12]); + long j = 2; reg[14] = INT2FIX(i-j); } @@ -8693,8 +8691,8 @@ loop_a2IsFixnum: COUNTUP_INTERACTION(vm); // r << Add(m,n) - int n = FIX2INT(AGENT(a1)->port[1]); - int m = FIX2INT(a2); + long n = FIX2INT(AGENT(a1)->port[1]); + long m = FIX2INT(a2); a2 = INT2FIX(m+n); VALUE a1port0 = AGENT(a1)->port[0]; free_Agent(a1); @@ -8716,8 +8714,8 @@ loop_a2IsFixnum: COUNTUP_INTERACTION(vm); // r << Sub(m,n) - int n = FIX2INT(AGENT(a1)->port[1]); - int m = FIX2INT(a2); + long n = FIX2INT(AGENT(a1)->port[1]); + long m = FIX2INT(a2); a2 = INT2FIX(m-n); VALUE a1port0 = AGENT(a1)->port[0]; free_Agent(a1); @@ -8739,8 +8737,8 @@ loop_a2IsFixnum: COUNTUP_INTERACTION(vm); // r << Mult(m,n) - int n = FIX2INT(AGENT(a1)->port[1]); - int m = FIX2INT(a2); + long n = FIX2INT(AGENT(a1)->port[1]); + long m = FIX2INT(a2); a2 = INT2FIX(m*n); VALUE a1port0 = AGENT(a1)->port[0]; free_Agent(a1); @@ -8762,8 +8760,8 @@ loop_a2IsFixnum: COUNTUP_INTERACTION(vm); // r << DIV(m,n) - int n = FIX2INT(AGENT(a1)->port[1]); - int m = FIX2INT(a2); + long n = FIX2INT(AGENT(a1)->port[1]); + long m = FIX2INT(a2); a2 = INT2FIX(m/n); VALUE a1port0 = AGENT(a1)->port[0]; free_Agent(a1); @@ -8785,8 +8783,8 @@ loop_a2IsFixnum: COUNTUP_INTERACTION(vm); // r << MOD(m,n) - int n = FIX2INT(AGENT(a1)->port[1]); - int m = FIX2INT(a2); + long n = FIX2INT(AGENT(a1)->port[1]); + long m = FIX2INT(a2); a2 = INT2FIX(m%n); VALUE a1port0 = AGENT(a1)->port[0]; free_Agent(a1); @@ -9567,7 +9565,6 @@ int exec(Ast *at) { Ast_RewriteOptimisation_eqlist(at); - // Syntax error check { Ast *tmp_at=at; @@ -10060,8 +10057,9 @@ int main(int argc, char *argv[]) Hoop_init_size, 1 << Hoop_init_size); printf(" -Xmt <num> Set multiple heap increment to 2^<num> (Defalut: %2u (=%4u))\n", Hoop_increasing_magnitude, 1 << Hoop_increasing_magnitude); - printf(" 0: the same size heap is inserted when it runs up.\n"); - printf(" 1: the twice (=2^1) size heap is inserted.\n"); + printf(" 0: the same (=2^0) size heap is inserted when it runs up.\n"); + printf(" 1: the heap size is twice (=2^1).\n"); + printf(" 2: the size is four times (=2^2).\n"); #else //v0.5.6 printf(" -c <num> Set size of heaps (Defalut: %10u)\n", heap_size); @@ -141,7 +141,7 @@ char *Parse_closeStringBuffer() { return (NAME);} <INITIAL>[A-Z][a-zA-Z0-9_'\.]* { yylval.chval = strdup(yytext); return (AGENT);} -<INITIAL>[0-9]+ { yylval.intval = atoi(yytext); +<INITIAL>[0-9]+ { yylval.longval = atol(yytext); return (INT_LITERAL);} <INITIAL>"//"[^\n]* ; //comment diff --git a/src/linenoise/linenoise.c.o6R1Usg b/src/linenoise/linenoise.c.o6R1Usg new file mode 100644 index 0000000..57a6b7e --- /dev/null +++ b/src/linenoise/linenoise.c.o6R1Usg @@ -0,0 +1,1229 @@ +/* linenoise.c -- guerrilla line editing library against the idea that a + * line editing lib needs to be 20,000 lines of C code. + * + * You can find the latest source code at: + * + * http://github.com/antirez/linenoise + * + * Does a number of crazy assumptions that happen to be true in 99.9999% of + * the 2010 UNIX computers around. + * + * ------------------------------------------------------------------------ + * + * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com> + * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ------------------------------------------------------------------------ + * + * References: + * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html + * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html + * + * Todo list: + * - Filter bogus Ctrl+<char> combinations. + * - Win32 support + * + * Bloat: + * - History search like Ctrl+r in readline? + * + * List of escape sequences used by this program, we do everything just + * with three sequences. In order to be so cheap we may have some + * flickering effect with some slow terminal, but the lesser sequences + * the more compatible. + * + * EL (Erase Line) + * Sequence: ESC [ n K + * Effect: if n is 0 or missing, clear from cursor to end of line + * Effect: if n is 1, clear from beginning of line to cursor + * Effect: if n is 2, clear entire line + * + * CUF (CUrsor Forward) + * Sequence: ESC [ n C + * Effect: moves cursor forward n chars + * + * CUB (CUrsor Backward) + * Sequence: ESC [ n D + * Effect: moves cursor backward n chars + * + * The following is used to get the terminal width if getting + * the width with the TIOCGWINSZ ioctl fails + * + * DSR (Device Status Report) + * Sequence: ESC [ 6 n + * Effect: reports the current cusor position as ESC [ n ; m R + * where n is the row and m is the column + * + * When multi line mode is enabled, we also use an additional escape + * sequence. However multi line editing is disabled by default. + * + * CUU (Cursor Up) + * Sequence: ESC [ n A + * Effect: moves cursor up of n chars. + * + * CUD (Cursor Down) + * Sequence: ESC [ n B + * Effect: moves cursor down of n chars. + * + * When linenoiseClearScreen() is called, two additional escape sequences + * are used in order to clear the screen and position the cursor at home + * position. + * + * CUP (Cursor position) + * Sequence: ESC [ H + * Effect: moves the cursor to upper left corner + * + * ED (Erase display) + * Sequence: ESC [ 2 J + * Effect: clear the whole screen + * + */ + +#include <termios.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include "linenoise.h" + +#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 +#define LINENOISE_MAX_LINE 4096 +static char *unsupported_term[] = {"dumb","cons25","emacs",NULL}; +static linenoiseCompletionCallback *completionCallback = NULL; +static linenoiseHintsCallback *hintsCallback = NULL; +static linenoiseFreeHintsCallback *freeHintsCallback = NULL; + +static struct termios orig_termios; /* In order to restore at exit.*/ +static int maskmode = 0; /* Show "***" instead of input. For passwords. */ +static int rawmode = 0; /* For atexit() function to check if restore is needed*/ +static int mlmode = 0; /* Multi line mode. Default is single line. */ +static int atexit_registered = 0; /* Register atexit just 1 time. */ +static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN; +static int history_len = 0; +static char **history = NULL; + +/* The linenoiseState structure represents the state during line editing. + * We pass this state to functions implementing specific editing + * functionalities. */ +struct linenoiseState { + int ifd; /* Terminal stdin file descriptor. */ + int ofd; /* Terminal stdout file descriptor. */ + char *buf; /* Edited line buffer. */ + size_t buflen; /* Edited line buffer size. */ + const char *prompt; /* Prompt to display. */ + size_t plen; /* Prompt length. */ + size_t pos; /* Current cursor position. */ + size_t oldpos; /* Previous refresh cursor position. */ + size_t len; /* Current edited line length. */ + size_t cols; /* Number of columns in terminal. */ + size_t maxrows; /* Maximum num of rows used so far (multiline mode) */ + int history_index; /* The history index we are currently editing. */ +}; + +enum KEY_ACTION{ + KEY_NULL = 0, /* NULL */ + CTRL_A = 1, /* Ctrl+a */ + CTRL_B = 2, /* Ctrl-b */ + CTRL_C = 3, /* Ctrl-c */ + CTRL_D = 4, /* Ctrl-d */ + CTRL_E = 5, /* Ctrl-e */ + CTRL_F = 6, /* Ctrl-f */ + CTRL_H = 8, /* Ctrl-h */ + TAB = 9, /* Tab */ + CTRL_K = 11, /* Ctrl+k */ + CTRL_L = 12, /* Ctrl+l */ + ENTER = 13, /* Enter */ + CTRL_N = 14, /* Ctrl-n */ + CTRL_P = 16, /* Ctrl-p */ + CTRL_T = 20, /* Ctrl-t */ + CTRL_U = 21, /* Ctrl+u */ + CTRL_W = 23, /* Ctrl+w */ + ESC = 27, /* Escape */ + BACKSPACE = 127 /* Backspace */ +}; + +static void linenoiseAtExit(void); +int linenoiseHistoryAdd(const char *line); +static void refreshLine(struct linenoiseState *l); + +/* Debugging macro. */ +#if 0 +FILE *lndebug_fp = NULL; +#define lndebug(...) \ + do { \ + if (lndebug_fp == NULL) { \ + lndebug_fp = fopen("/tmp/lndebug.txt","a"); \ + fprintf(lndebug_fp, \ + "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \ + (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \ + (int)l->maxrows,old_rows); \ + } \ + fprintf(lndebug_fp, ", " __VA_ARGS__); \ + fflush(lndebug_fp); \ + } while (0) +#else +#define lndebug(fmt, ...) +#endif + +/* ======================= Low level terminal handling ====================== */ + +/* Enable "mask mode". When it is enabled, instead of the input that + * the user is typing, the terminal will just display a corresponding + * number of asterisks, like "****". This is useful for passwords and other + * secrets that should not be displayed. */ +void linenoiseMaskModeEnable(void) { + maskmode = 1; +} + +/* Disable mask mode. */ +void linenoiseMaskModeDisable(void) { + maskmode = 0; +} + +/* Set if to use or not the multi line mode. */ +void linenoiseSetMultiLine(int ml) { + mlmode = ml; +} + +/* Return true if the terminal name is in the list of terminals we know are + * not able to understand basic escape sequences. */ +static int isUnsupportedTerm(void) { + char *term = getenv("TERM"); + int j; + + if (term == NULL) return 0; + for (j = 0; unsupported_term[j]; j++) + if (!strcasecmp(term,unsupported_term[j])) return 1; + return 0; +} + +/* Raw mode: 1960 magic shit. */ +static int enableRawMode(int fd) { + struct termios raw; + + if (!isatty(STDIN_FILENO)) goto fatal; + if (!atexit_registered) { + atexit(linenoiseAtExit); + atexit_registered = 1; + } + if (tcgetattr(fd,&orig_termios) == -1) goto fatal; + + raw = orig_termios; /* modify the original mode */ + /* input modes: no break, no CR to NL, no parity check, no strip char, + * no start/stop output control. */ + raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + /* output modes - disable post processing */ + raw.c_oflag &= ~(OPOST); + /* control modes - set 8 bit chars */ + raw.c_cflag |= (CS8); + /* local modes - choing off, canonical off, no extended functions, + * no signal chars (^Z,^C) */ + raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + /* control chars - set return condition: min number of bytes and timer. + * We want read to return every single byte, without timeout. */ + raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */ + + /* put terminal in raw mode after flushing */ + //if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal; + // https://github.com/antirez/linenoise/issues/43 + if (tcsetattr(fd,TCSADRAIN,&raw) < 0) goto fatal; + rawmode = 1; + return 0; + +fatal: + errno = ENOTTY; + return -1; +} + +static void disableRawMode(int fd) { + /* Don't even check the return value as it's too late. */ + // if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1) + // https://github.com/antirez/linenoise/issues/43 + if (rawmode && tcsetattr(fd,TCSADRAIN,&orig_termios) != -1) + rawmode = 0; +} + +/* Use the ESC [6n escape sequence to query the horizontal cursor position + * and return it. On error -1 is returned, on success the position of the + * cursor. */ +static int getCursorPosition(int ifd, int ofd) { + char buf[32]; + int cols, rows; + unsigned int i = 0; + + /* Report cursor location */ + if (write(ofd, "\x1b[6n", 4) != 4) return -1; + + /* Read the response: ESC [ rows ; cols R */ + while (i < sizeof(buf)-1) { + if (read(ifd,buf+i,1) != 1) break; + if (buf[i] == 'R') break; + i++; + } + buf[i] = '\0'; + + /* Parse it. */ + if (buf[0] != ESC || buf[1] != '[') return -1; + if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1; + return cols; +} + +/* Try to get the number of columns in the current terminal, or assume 80 + * if it fails. */ +static int getColumns(int ifd, int ofd) { + struct winsize ws; + + if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { + /* ioctl() failed. Try to query the terminal itself. */ + int start, cols; + + /* Get the initial position so we can restore it later. */ + start = getCursorPosition(ifd,ofd); + if (start == -1) goto failed; + + /* Go to right margin and get position. */ + if (write(ofd,"\x1b[999C",6) != 6) goto failed; + cols = getCursorPosition(ifd,ofd); + if (cols == -1) goto failed; + + /* Restore position. */ + if (cols > start) { + char seq[32]; + snprintf(seq,32,"\x1b[%dD",cols-start); + if (write(ofd,seq,strlen(seq)) == -1) { + /* Can't recover... */ + } + } + return cols; + } else { + return ws.ws_col; + } + +failed: + return 80; +} + +/* Clear the screen. Used to handle ctrl+l */ +void linenoiseClearScreen(void) { + if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) { + /* nothing to do, just to avoid warning. */ + } +} + +/* Beep, used for completion when there is nothing to complete or when all + * the choices were already shown. */ +static void linenoiseBeep(void) { + fprintf(stderr, "\x7"); + fflush(stderr); +} + +/* ============================== Completion ================================ */ + +/* Free a list of completion option populated by linenoiseAddCompletion(). */ +static void freeCompletions(linenoiseCompletions *lc) { + size_t i; + for (i = 0; i < lc->len; i++) + free(lc->cvec[i]); + if (lc->cvec != NULL) + free(lc->cvec); +} + +/* This is an helper function for linenoiseEdit() and is called when the + * user types the <tab> key in order to complete the string currently in the + * input. + * + * The state of the editing is encapsulated into the pointed linenoiseState + * structure as described in the structure definition. */ +static int completeLine(struct linenoiseState *ls) { + linenoiseCompletions lc = { 0, NULL }; + int nread, nwritten; + char c = 0; + + completionCallback(ls->buf,&lc); + if (lc.len == 0) { + linenoiseBeep(); + } else { + size_t stop = 0, i = 0; + + while(!stop) { + /* Show completion or original buffer */ + if (i < lc.len) { + struct linenoiseState saved = *ls; + + ls->len = ls->pos = strlen(lc.cvec[i]); + ls->buf = lc.cvec[i]; + refreshLine(ls); + ls->len = saved.len; + ls->pos = saved.pos; + ls->buf = saved.buf; + } else { + refreshLine(ls); + } + + nread = read(ls->ifd,&c,1); + if (nread <= 0) { + freeCompletions(&lc); + return -1; + } + + switch(c) { + case 9: /* tab */ + i = (i+1) % (lc.len+1); + if (i == lc.len) linenoiseBeep(); + break; + case 27: /* escape */ + /* Re-show original buffer */ + if (i < lc.len) refreshLine(ls); + stop = 1; + break; + default: + /* Update buffer and return */ + if (i < lc.len) { + nwritten = snprintf(ls->buf,ls->buflen,"%s",lc.cvec[i]); + ls->len = ls->pos = nwritten; + } + stop = 1; + break; + } + } + } + + freeCompletions(&lc); + return c; /* Return last read character */ +} + +/* Register a callback function to be called for tab-completion. */ +void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) { + completionCallback = fn; +} + +/* Register a hits function to be called to show hits to the user at the + * right of the prompt. */ +void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) { + hintsCallback = fn; +} + +/* Register a function to free the hints returned by the hints callback + * registered with linenoiseSetHintsCallback(). */ +void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) { + freeHintsCallback = fn; +} + +/* This function is used by the callback function registered by the user + * in order to add completion options given the input string when the + * user typed <tab>. See the example.c source code for a very easy to + * understand example. */ +void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) { + size_t len = strlen(str); + char *copy, **cvec; + + copy = malloc(len+1); + if (copy == NULL) return; + memcpy(copy,str,len+1); + cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1)); + if (cvec == NULL) { + free(copy); + return; + } + lc->cvec = cvec; + lc->cvec[lc->len++] = copy; +} + +/* =========================== Line editing ================================= */ + +/* We define a very simple "append buffer" structure, that is an heap + * allocated string where we can append to. This is useful in order to + * write all the escape sequences in a buffer and flush them to the standard + * output in a single call, to avoid flickering effects. */ +struct abuf { + char *b; + int len; +}; + +static void abInit(struct abuf *ab) { + ab->b = NULL; + ab->len = 0; +} + +static void abAppend(struct abuf *ab, const char *s, int len) { + char *new = realloc(ab->b,ab->len+len); + + if (new == NULL) return; + memcpy(new+ab->len,s,len); + ab->b = new; + ab->len += len; +} + +static void abFree(struct abuf *ab) { + free(ab->b); +} + +/* Helper of refreshSingleLine() and refreshMultiLine() to show hints + * to the right of the prompt. */ +void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) { + char seq[64]; + if (hintsCallback && plen+l->len < l->cols) { + int color = -1, bold = 0; + char *hint = hintsCallback(l->buf,&color,&bold); + if (hint) { + int hintlen = strlen(hint); + int hintmaxlen = l->cols-(plen+l->len); + if (hintlen > hintmaxlen) hintlen = hintmaxlen; + if (bold == 1 && color == -1) color = 37; + if (color != -1 || bold != 0) + snprintf(seq,64,"\033[%d;%d;49m",bold,color); + else + seq[0] = '\0'; + abAppend(ab,seq,strlen(seq)); + abAppend(ab,hint,hintlen); + if (color != -1 || bold != 0) + abAppend(ab,"\033[0m",4); + /* Call the function to free the hint returned. */ + if (freeHintsCallback) freeHintsCallback(hint); + } + } +} + +/* Single line low level line refresh. + * + * Rewrite the currently edited line accordingly to the buffer content, + * cursor position, and number of columns of the terminal. */ +static void refreshSingleLine(struct linenoiseState *l) { + char seq[64]; + size_t plen = strlen(l->prompt); + int fd = l->ofd; + char *buf = l->buf; + size_t len = l->len; + size_t pos = l->pos; + struct abuf ab; + + while((plen+pos) >= l->cols) { + buf++; + len--; + pos--; + } + while (plen+len > l->cols) { + len--; + } + + abInit(&ab); + /* Cursor to left edge */ + snprintf(seq,64,"\r"); + abAppend(&ab,seq,strlen(seq)); + /* Write the prompt and the current buffer content */ + abAppend(&ab,l->prompt,strlen(l->prompt)); + if (maskmode == 1) { + while (len--) abAppend(&ab,"*",1); + } else { + abAppend(&ab,buf,len); + } + /* Show hits if any. */ + refreshShowHints(&ab,l,plen); + /* Erase to right */ + snprintf(seq,64,"\x1b[0K"); + abAppend(&ab,seq,strlen(seq)); + /* Move cursor to original position. */ + snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen)); + abAppend(&ab,seq,strlen(seq)); + if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */ + abFree(&ab); +} + +/* Multi line low level line refresh. + * + * Rewrite the currently edited line accordingly to the buffer content, + * cursor position, and number of columns of the terminal. */ +static void refreshMultiLine(struct linenoiseState *l) { + char seq[64]; + int plen = strlen(l->prompt); + int rows = (plen+l->len+l->cols-1)/l->cols; /* rows used by current buf. */ + int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */ + int rpos2; /* rpos after refresh. */ + int col; /* colum position, zero-based. */ + int old_rows = l->maxrows; + int fd = l->ofd, j; + struct abuf ab; + + /* Update maxrows if needed. */ + if (rows > (int)l->maxrows) l->maxrows = rows; + + /* First step: clear all the lines used before. To do so start by + * going to the last row. */ + abInit(&ab); + if (old_rows-rpos > 0) { + lndebug("go down %d", old_rows-rpos); + snprintf(seq,64,"\x1b[%dB", old_rows-rpos); + abAppend(&ab,seq,strlen(seq)); + } + + /* Now for every row clear it, go up. */ + for (j = 0; j < old_rows-1; j++) { + lndebug("clear+up"); + snprintf(seq,64,"\r\x1b[0K\x1b[1A"); + abAppend(&ab,seq,strlen(seq)); + } + + /* Clean the top line. */ + lndebug("clear"); + snprintf(seq,64,"\r\x1b[0K"); + abAppend(&ab,seq,strlen(seq)); + + /* Write the prompt and the current buffer content */ + abAppend(&ab,l->prompt,strlen(l->prompt)); + if (maskmode == 1) { + unsigned int i; + for (i = 0; i < l->len; i++) abAppend(&ab,"*",1); + } else { + abAppend(&ab,l->buf,l->len); + } + + /* Show hits if any. */ + refreshShowHints(&ab,l,plen); + + /* If we are at the very end of the screen with our prompt, we need to + * emit a newline and move the prompt to the first column. */ + if (l->pos && + l->pos == l->len && + (l->pos+plen) % l->cols == 0) + { + lndebug("<newline>"); + abAppend(&ab,"\n",1); + snprintf(seq,64,"\r"); + abAppend(&ab,seq,strlen(seq)); + rows++; + if (rows > (int)l->maxrows) l->maxrows = rows; + } + + /* Move cursor to right position. */ + rpos2 = (plen+l->pos+l->cols)/l->cols; /* current cursor relative row. */ + lndebug("rpos2 %d", rpos2); + + /* Go up till we reach the expected positon. */ + if (rows-rpos2 > 0) { + lndebug("go-up %d", rows-rpos2); + snprintf(seq,64,"\x1b[%dA", rows-rpos2); + abAppend(&ab,seq,strlen(seq)); + } + + /* Set column. */ + col = (plen+(int)l->pos) % (int)l->cols; + lndebug("set col %d", 1+col); + if (col) + snprintf(seq,64,"\r\x1b[%dC", col); + else + snprintf(seq,64,"\r"); + abAppend(&ab,seq,strlen(seq)); + + lndebug("\n"); + l->oldpos = l->pos; + + if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */ + abFree(&ab); +} + +/* Calls the two low level functions refreshSingleLine() or + * refreshMultiLine() according to the selected mode. */ +static void refreshLine(struct linenoiseState *l) { + if (mlmode) + refreshMultiLine(l); + else + refreshSingleLine(l); +} + +/* Insert the character 'c' at cursor current position. + * + * On error writing to the terminal -1 is returned, otherwise 0. */ +int linenoiseEditInsert(struct linenoiseState *l, char c) { + if (l->len < l->buflen) { + if (l->len == l->pos) { + l->buf[l->pos] = c; + l->pos++; + l->len++; + l->buf[l->len] = '\0'; + if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) { + /* Avoid a full update of the line in the + * trivial case. */ + char d = (maskmode==1) ? '*' : c; + if (write(l->ofd,&d,1) == -1) return -1; + } else { + refreshLine(l); + } + } else { + memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos); + l->buf[l->pos] = c; + l->len++; + l->pos++; + l->buf[l->len] = '\0'; + refreshLine(l); + } + } + return 0; +} + +/* Move cursor on the left. */ +void linenoiseEditMoveLeft(struct linenoiseState *l) { + if (l->pos > 0) { + l->pos--; + refreshLine(l); + } +} + +/* Move cursor on the right. */ +void linenoiseEditMoveRight(struct linenoiseState *l) { + if (l->pos != l->len) { + l->pos++; + refreshLine(l); + } +} + +/* Move cursor to the start of the line. */ +void linenoiseEditMoveHome(struct linenoiseState *l) { + if (l->pos != 0) { + l->pos = 0; + refreshLine(l); + } +} + +/* Move cursor to the end of the line. */ +void linenoiseEditMoveEnd(struct linenoiseState *l) { + if (l->pos != l->len) { + l->pos = l->len; + refreshLine(l); + } +} + +/* Substitute the currently edited line with the next or previous history + * entry as specified by 'dir'. */ +#define LINENOISE_HISTORY_NEXT 0 +#define LINENOISE_HISTORY_PREV 1 +void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) { + if (history_len > 1) { + /* Update the current history entry before to + * overwrite it with the next one. */ + free(history[history_len - 1 - l->history_index]); + history[history_len - 1 - l->history_index] = strdup(l->buf); + /* Show the new entry */ + l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1; + if (l->history_index < 0) { + l->history_index = 0; + return; + } else if (l->history_index >= history_len) { + l->history_index = history_len-1; + return; + } + strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen); + l->buf[l->buflen-1] = '\0'; + l->len = l->pos = strlen(l->buf); + refreshLine(l); + } +} + +/* Delete the character at the right of the cursor without altering the cursor + * position. Basically this is what happens with the "Delete" keyboard key. */ +void linenoiseEditDelete(struct linenoiseState *l) { + if (l->len > 0 && l->pos < l->len) { + memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1); + l->len--; + l->buf[l->len] = '\0'; + refreshLine(l); + } +} + +/* Backspace implementation. */ +void linenoiseEditBackspace(struct linenoiseState *l) { + if (l->pos > 0 && l->len > 0) { + memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos); + l->pos--; + l->len--; + l->buf[l->len] = '\0'; + refreshLine(l); + } +} + +/* Delete the previosu word, maintaining the cursor at the start of the + * current word. */ +void linenoiseEditDeletePrevWord(struct linenoiseState *l) { + size_t old_pos = l->pos; + size_t diff; + + while (l->pos > 0 && l->buf[l->pos-1] == ' ') + l->pos--; + while (l->pos > 0 && l->buf[l->pos-1] != ' ') + l->pos--; + diff = old_pos - l->pos; + memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1); + l->len -= diff; + refreshLine(l); +} + +/* This function is the core of the line editing capability of linenoise. + * It expects 'fd' to be already in "raw mode" so that every key pressed + * will be returned ASAP to read(). + * + * The resulting string is put into 'buf' when the user type enter, or + * when ctrl+d is typed. + * + * The function returns the length of the current buffer. */ +static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt) +{ + struct linenoiseState l; + + /* Populate the linenoise state that we pass to functions implementing + * specific editing functionalities. */ + l.ifd = stdin_fd; + l.ofd = stdout_fd; + l.buf = buf; + l.buflen = buflen; + l.prompt = prompt; + l.plen = strlen(prompt); + l.oldpos = l.pos = 0; + l.len = 0; + l.cols = getColumns(stdin_fd, stdout_fd); + l.maxrows = 0; + l.history_index = 0; + + /* Buffer starts empty. */ + l.buf[0] = '\0'; + l.buflen--; /* Make sure there is always space for the nulterm */ + + /* The latest history entry is always our current buffer, that + * initially is just an empty string. */ + linenoiseHistoryAdd(""); + + if (write(l.ofd,prompt,l.plen) == -1) return -1; + while(1) { + char c; + int nread; + char seq[3]; + + nread = read(l.ifd,&c,1); + if (nread <= 0) return l.len; + + /* Only autocomplete when the callback is set. It returns < 0 when + * there was an error reading from fd. Otherwise it will return the + * character that should be handled next. */ + if (c == 9 && completionCallback != NULL) { + c = completeLine(&l); + /* Return on errors */ + if (c < 0) return l.len; + /* Read next character when 0 */ + if (c == 0) continue; + } + + switch(c) { + case ENTER: /* enter */ + history_len--; + free(history[history_len]); + if (mlmode) linenoiseEditMoveEnd(&l); + if (hintsCallback) { + /* Force a refresh without hints to leave the previous + * line as the user typed it after a newline. */ + linenoiseHintsCallback *hc = hintsCallback; + hintsCallback = NULL; + refreshLine(&l); + hintsCallback = hc; + } + return (int)l.len; + case CTRL_C: /* ctrl-c */ + errno = EAGAIN; + return -1; + case BACKSPACE: /* backspace */ + case 8: /* ctrl-h */ + linenoiseEditBackspace(&l); + break; + case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the + line is empty, act as end-of-file. */ + if (l.len > 0) { + linenoiseEditDelete(&l); + } else { + history_len--; + free(history[history_len]); + return -1; + } + break; + case CTRL_T: /* ctrl-t, swaps current character with previous. */ + if (l.pos > 0 && l.pos < l.len) { + int aux = buf[l.pos-1]; + buf[l.pos-1] = buf[l.pos]; + buf[l.pos] = aux; + if (l.pos != l.len-1) l.pos++; + refreshLine(&l); + } + break; + case CTRL_B: /* ctrl-b */ + linenoiseEditMoveLeft(&l); + break; + case CTRL_F: /* ctrl-f */ + linenoiseEditMoveRight(&l); + break; + case CTRL_P: /* ctrl-p */ + linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV); + break; + case CTRL_N: /* ctrl-n */ + linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT); + break; + case ESC: /* escape sequence */ + /* Read the next two bytes representing the escape sequence. + * Use two calls to handle slow terminals returning the two + * chars at different times. */ + if (read(l.ifd,seq,1) == -1) break; + if (read(l.ifd,seq+1,1) == -1) break; + + /* ESC [ sequences. */ + if (seq[0] == '[') { + if (seq[1] >= '0' && seq[1] <= '9') { + /* Extended escape, read additional byte. */ + if (read(l.ifd,seq+2,1) == -1) break; + if (seq[2] == '~') { + switch(seq[1]) { + case '3': /* Delete key. */ + linenoiseEditDelete(&l); + break; + } + } + } else { + switch(seq[1]) { + case 'A': /* Up */ + linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV); + break; + case 'B': /* Down */ + linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT); + break; + case 'C': /* Right */ + linenoiseEditMoveRight(&l); + break; + case 'D': /* Left */ + linenoiseEditMoveLeft(&l); + break; + case 'H': /* Home */ + linenoiseEditMoveHome(&l); + break; + case 'F': /* End*/ + linenoiseEditMoveEnd(&l); + break; + } + } + } + + /* ESC O sequences. */ + else if (seq[0] == 'O') { + switch(seq[1]) { + case 'H': /* Home */ + linenoiseEditMoveHome(&l); + break; + case 'F': /* End*/ + linenoiseEditMoveEnd(&l); + break; + } + } + break; + default: + if (linenoiseEditInsert(&l,c)) return -1; + break; + case CTRL_U: /* Ctrl+u, delete the whole line. */ + buf[0] = '\0'; + l.pos = l.len = 0; + refreshLine(&l); + break; + case CTRL_K: /* Ctrl+k, delete from current to end of line. */ + buf[l.pos] = '\0'; + l.len = l.pos; + refreshLine(&l); + break; + case CTRL_A: /* Ctrl+a, go to the start of the line */ + linenoiseEditMoveHome(&l); + break; + case CTRL_E: /* ctrl+e, go to the end of the line */ + linenoiseEditMoveEnd(&l); + break; + case CTRL_L: /* ctrl+l, clear screen */ + linenoiseClearScreen(); + refreshLine(&l); + break; + case CTRL_W: /* ctrl+w, delete previous word */ + linenoiseEditDeletePrevWord(&l); + break; + } + } + return l.len; +} + +/* This special mode is used by linenoise in order to print scan codes + * on screen for debugging / development purposes. It is implemented + * by the linenoise_example program using the --keycodes option. */ +void linenoisePrintKeyCodes(void) { + char quit[4]; + + printf("Linenoise key codes debugging mode.\n" + "Press keys to see scan codes. Type 'quit' at any time to exit.\n"); + if (enableRawMode(STDIN_FILENO) == -1) return; + memset(quit,' ',4); + while(1) { + char c; + int nread; + + nread = read(STDIN_FILENO,&c,1); + if (nread <= 0) continue; + memmove(quit,quit+1,sizeof(quit)-1); /* shift string to left. */ + quit[sizeof(quit)-1] = c; /* Insert current char on the right. */ + if (memcmp(quit,"quit",sizeof(quit)) == 0) break; + + printf("'%c' %02x (%d) (type quit to exit)\n", + isprint(c) ? c : '?', (int)c, (int)c); + printf("\r"); /* Go left edge manually, we are in raw mode. */ + fflush(stdout); + } + disableRawMode(STDIN_FILENO); +} + +/* This function calls the line editing function linenoiseEdit() using + * the STDIN file descriptor set in raw mode. */ +static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) { + int count; + + if (buflen == 0) { + errno = EINVAL; + return -1; + } + + if (enableRawMode(STDIN_FILENO) == -1) return -1; + count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt); + disableRawMode(STDIN_FILENO); + printf("\n"); + return count; +} + +/* This function is called when linenoise() is called with the standard + * input file descriptor not attached to a TTY. So for example when the + * program using linenoise is called in pipe or with a file redirected + * to its standard input. In this case, we want to be able to return the + * line regardless of its length (by default we are limited to 4k). */ +static char *linenoiseNoTTY(void) { + char *line = NULL; + size_t len = 0, maxlen = 0; + + while(1) { + if (len == maxlen) { + if (maxlen == 0) maxlen = 16; + maxlen *= 2; + char *oldval = line; + line = realloc(line,maxlen); + if (line == NULL) { + if (oldval) free(oldval); + return NULL; + } + } + int c = fgetc(stdin); + if (c == EOF || c == '\n') { + if (c == EOF && len == 0) { + free(line); + return NULL; + } else { + line[len] = '\0'; + return line; + } + } else { + line[len] = c; + len++; + } + } +} + +/* The high level function that is the main API of the linenoise library. + * This function checks if the terminal has basic capabilities, just checking + * for a blacklist of stupid terminals, and later either calls the line + * editing function or uses dummy fgets() so that you will be able to type + * something even in the most desperate of the conditions. */ +char *linenoise(const char *prompt) { + char buf[LINENOISE_MAX_LINE]; + int count; + + if (!isatty(STDIN_FILENO)) { + /* Not a tty: read from file / pipe. In this mode we don't want any + * limit to the line size, so we call a function to handle that. */ + return linenoiseNoTTY(); + } else if (isUnsupportedTerm()) { + size_t len; + + printf("%s",prompt); + fflush(stdout); + if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL; + len = strlen(buf); + while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) { + len--; + buf[len] = '\0'; + } + return strdup(buf); + } else { + count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt); + if (count == -1) return NULL; + return strdup(buf); + } +} + +/* This is just a wrapper the user may want to call in order to make sure + * the linenoise returned buffer is freed with the same allocator it was + * created with. Useful when the main program is using an alternative + * allocator. */ +void linenoiseFree(void *ptr) { + free(ptr); +} + +/* ================================ History ================================= */ + +/* Free the history, but does not reset it. Only used when we have to + * exit() to avoid memory leaks are reported by valgrind & co. */ +static void freeHistory(void) { + if (history) { + int j; + + for (j = 0; j < history_len; j++) + free(history[j]); + free(history); + } +} + +/* At exit we'll try to fix the terminal to the initial conditions. */ +static void linenoiseAtExit(void) { + disableRawMode(STDIN_FILENO); + freeHistory(); +} + +/* This is the API call to add a new entry in the linenoise history. + * It uses a fixed array of char pointers that are shifted (memmoved) + * when the history max length is reached in order to remove the older + * entry and make room for the new one, so it is not exactly suitable for huge + * histories, but will work well for a few hundred of entries. + * + * Using a circular buffer is smarter, but a bit more complex to handle. */ +int linenoiseHistoryAdd(const char *line) { + char *linecopy; + + if (history_max_len == 0) return 0; + + /* Initialization on first call. */ + if (history == NULL) { + history = malloc(sizeof(char*)*history_max_len); + if (history == NULL) return 0; + memset(history,0,(sizeof(char*)*history_max_len)); + } + + /* Don't add duplicated lines. */ + if (history_len && !strcmp(history[history_len-1], line)) return 0; + + /* Add an heap allocated copy of the line in the history. + * If we reached the max length, remove the older line. */ + linecopy = strdup(line); + if (!linecopy) return 0; + if (history_len == history_max_len) { + free(history[0]); + memmove(history,history+1,sizeof(char*)*(history_max_len-1)); + history_len--; + } + history[history_len] = linecopy; + history_len++; + return 1; +} + +/* Set the maximum length for the history. This function can be called even + * if there is already some history, the function will make sure to retain + * just the latest 'len' elements if the new history length value is smaller + * than the amount of items already inside the history. */ +int linenoiseHistorySetMaxLen(int len) { + char **new; + + if (len < 1) return 0; + if (history) { + int tocopy = history_len; + + new = malloc(sizeof(char*)*len); + if (new == NULL) return 0; + + /* If we can't copy everything, free the elements we'll not use. */ + if (len < tocopy) { + int j; + + for (j = 0; j < tocopy-len; j++) free(history[j]); + tocopy = len; + } + memset(new,0,sizeof(char*)*len); + memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy); + free(history); + history = new; + } + history_max_len = len; + if (history_len > history_max_len) + history_len = history_max_len; + return 1; +} + +/* Save the history in the specified file. On success 0 is returned + * otherwise -1 is returned. */ +int linenoiseHistorySave(const char *filename) { + mode_t old_umask = umask(S_IXUSR|S_IRWXG|S_IRWXO); + FILE *fp; + int j; + + fp = fopen(filename,"w"); + umask(old_umask); + if (fp == NULL) return -1; + chmod(filename,S_IRUSR|S_IWUSR); + for (j = 0; j < history_len; j++) + fprintf(fp,"%s\n",history[j]); + fclose(fp); + return 0; +} + +/* Load the history from the specified file. If the file does not exist + * zero is returned and no operation is performed. + * + * If the file exists and the operation succeeded 0 is returned, otherwise + * on error -1 is returned. */ +int linenoiseHistoryLoad(const char *filename) { + FILE *fp = fopen(filename,"r"); + char buf[LINENOISE_MAX_LINE]; + + if (fp == NULL) return -1; + + while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) { + char *p; + + p = strchr(buf,'\r'); + if (!p) p = strchr(buf,'\n'); + if (p) *p = '\0'; + linenoiseHistoryAdd(buf); + } + fclose(fp); + return 0; +} |
