Merge branch 'poc-9' into develop

pull/450/head^2
obscuren 10 years ago
commit 0db4a0e898
  1. 5
      .gitignore
  2. 18
      Godeps/Godeps.json
  3. 6
      Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml
  4. 21
      Godeps/_workspace/src/github.com/codegangsta/cli/LICENSE
  5. 298
      Godeps/_workspace/src/github.com/codegangsta/cli/README.md
  6. 296
      Godeps/_workspace/src/github.com/codegangsta/cli/app.go
  7. 619
      Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go
  8. 13
      Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete
  9. 5
      Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/zsh_autocomplete
  10. 19
      Godeps/_workspace/src/github.com/codegangsta/cli/cli.go
  11. 100
      Godeps/_workspace/src/github.com/codegangsta/cli/cli_test.go
  12. 160
      Godeps/_workspace/src/github.com/codegangsta/cli/command.go
  13. 49
      Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go
  14. 339
      Godeps/_workspace/src/github.com/codegangsta/cli/context.go
  15. 99
      Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go
  16. 454
      Godeps/_workspace/src/github.com/codegangsta/cli/flag.go
  17. 742
      Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go
  18. 211
      Godeps/_workspace/src/github.com/codegangsta/cli/help.go
  19. 19
      Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go
  20. 10
      Godeps/_workspace/src/github.com/ethereum/ethash/.gitignore
  21. 6
      Godeps/_workspace/src/github.com/ethereum/ethash/.travis.yml
  22. 15
      Godeps/_workspace/src/github.com/ethereum/ethash/CMakeLists.txt
  23. 3
      Godeps/_workspace/src/github.com/ethereum/ethash/Makefile
  24. 7
      Godeps/_workspace/src/github.com/ethereum/ethash/README.md
  25. 7
      Godeps/_workspace/src/github.com/ethereum/ethash/Vagrantfile
  26. 161
      Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/CMakeParseArguments.cmake
  27. 108
      Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindCryptoPP.cmake
  28. 136
      Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindOpenCL.cmake
  29. 382
      Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageHandleStandardArgs.cmake
  30. 57
      Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageMessage.cmake
  31. 13
      Godeps/_workspace/src/github.com/ethereum/ethash/cryptopp/CMakeLists.txt
  32. 351
      Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go
  33. 22
      Godeps/_workspace/src/github.com/ethereum/ethash/js/LICENSE
  34. 190
      Godeps/_workspace/src/github.com/ethereum/ethash/js/ethash.js
  35. 404
      Godeps/_workspace/src/github.com/ethereum/ethash/js/keccak.js
  36. 201
      Godeps/_workspace/src/github.com/ethereum/ethash/js/makekeccak.js
  37. 53
      Godeps/_workspace/src/github.com/ethereum/ethash/js/test.js
  38. 100
      Godeps/_workspace/src/github.com/ethereum/ethash/js/util.js
  39. 2
      Godeps/_workspace/src/github.com/ethereum/ethash/pyethash/.gitignore
  40. 3
      Godeps/_workspace/src/github.com/ethereum/ethash/pyethash/__init__.py
  41. 21
      Godeps/_workspace/src/github.com/ethereum/ethash/setup.py
  42. 53
      Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/CMakeLists.txt
  43. 260
      Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/benchmark.cpp
  44. 15
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/CMakeLists.txt
  45. 87
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/bin2h.cmake
  46. 12452
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/cl.hpp
  47. 289
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner.cpp
  48. 43
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner.h
  49. 461
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner_kernel.cl
  50. 39
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/CMakeLists.txt
  51. 33
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/compiler.h
  52. 779
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/data_sizes.h
  53. 74
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/endian.h
  54. 95
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/ethash.h
  55. 38
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/fnv.h
  56. 298
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c
  57. 48
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.h
  58. 151
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3.c
  59. 27
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3.h
  60. 34
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3_cryptopp.cpp
  61. 15
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3_cryptopp.h
  62. 41
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/util.c
  63. 47
      Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/util.h
  64. 64
      Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c
  65. 30
      Godeps/_workspace/src/github.com/ethereum/ethash/test/c/CMakeLists.txt
  66. 214
      Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.cpp
  67. 19
      Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.sh
  68. 1
      Godeps/_workspace/src/github.com/ethereum/ethash/test/python/.gitignore
  69. 2
      Godeps/_workspace/src/github.com/ethereum/ethash/test/python/requirements.txt
  70. 19
      Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test.sh
  71. 45
      Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test_pyethash.py
  72. 26
      Godeps/_workspace/src/github.com/ethereum/ethash/test/test.sh
  73. 21
      Godeps/_workspace/src/github.com/peterh/liner/COPYING
  74. 95
      Godeps/_workspace/src/github.com/peterh/liner/README.md
  75. 39
      Godeps/_workspace/src/github.com/peterh/liner/bsdinput.go
  76. 219
      Godeps/_workspace/src/github.com/peterh/liner/common.go
  77. 57
      Godeps/_workspace/src/github.com/peterh/liner/fallbackinput.go
  78. 359
      Godeps/_workspace/src/github.com/peterh/liner/input.go
  79. 39
      Godeps/_workspace/src/github.com/peterh/liner/input_darwin.go
  80. 26
      Godeps/_workspace/src/github.com/peterh/liner/input_linux.go
  81. 61
      Godeps/_workspace/src/github.com/peterh/liner/input_test.go
  82. 313
      Godeps/_workspace/src/github.com/peterh/liner/input_windows.go
  83. 864
      Godeps/_workspace/src/github.com/peterh/liner/line.go
  84. 90
      Godeps/_workspace/src/github.com/peterh/liner/line_test.go
  85. 63
      Godeps/_workspace/src/github.com/peterh/liner/output.go
  86. 54
      Godeps/_workspace/src/github.com/peterh/liner/output_windows.go
  87. 37
      Godeps/_workspace/src/github.com/peterh/liner/prefix_test.go
  88. 44
      Godeps/_workspace/src/github.com/peterh/liner/race_test.go
  89. 12
      Godeps/_workspace/src/github.com/peterh/liner/signal.go
  90. 11
      Godeps/_workspace/src/github.com/peterh/liner/signal_legacy.go
  91. 37
      Godeps/_workspace/src/github.com/peterh/liner/unixmode.go
  92. 47
      Godeps/_workspace/src/github.com/peterh/liner/width.go
  93. 87
      Godeps/_workspace/src/github.com/peterh/liner/width_test.go
  94. 112
      Godeps/_workspace/src/golang.org/x/net/websocket/client.go
  95. 31
      Godeps/_workspace/src/golang.org/x/net/websocket/exampledial_test.go
  96. 26
      Godeps/_workspace/src/golang.org/x/net/websocket/examplehandler_test.go
  97. 564
      Godeps/_workspace/src/golang.org/x/net/websocket/hybi.go
  98. 590
      Godeps/_workspace/src/golang.org/x/net/websocket/hybi_test.go
  99. 114
      Godeps/_workspace/src/golang.org/x/net/websocket/server.go
  100. 411
      Godeps/_workspace/src/golang.org/x/net/websocket/websocket.go
  101. Some files were not shown because too many files have changed in this diff Show More

5
.gitignore vendored

@ -6,10 +6,13 @@
/tmp
*/**/*un~
*/**/*.test
*un~
.DS_Store
*/**/.DS_Store
.ethtest
*/**/*tx_database*
*/**/*dapps*
#*
.#*
@ -20,3 +23,5 @@
cmd/ethereum/ethereum
cmd/mist/mist
deploy/osx/Mist.app
deploy/osx/Mist\ Installer.dmg

18
Godeps/Godeps.json generated vendored

@ -15,6 +15,16 @@
"Comment": "null-15",
"Rev": "12e4b4183793ac4b061921e7980845e750679fd0"
},
{
"ImportPath": "github.com/codegangsta/cli",
"Comment": "1.2.0-74-g50c77ec",
"Rev": "50c77ecec0068c9aef9d90ae0fd0fdf410041da3"
},
{
"ImportPath": "github.com/ethereum/ethash",
"Comment": "v17-64-ga323708",
"Rev": "a323708b8c4d253b8567bf6c72727d1aec302225"
},
{
"ImportPath": "github.com/ethereum/serpent-go",
"Rev": "5767a0dbd759d313df3f404dadb7f98d7ab51443"
@ -44,6 +54,10 @@
"ImportPath": "github.com/obscuren/qml",
"Rev": "c288002b52e905973b131089a8a7c761d4a2c36a"
},
{
"ImportPath": "github.com/peterh/liner",
"Rev": "29f6a646557d83e2b6e9ba05c45fbea9c006dbe8"
},
{
"ImportPath": "github.com/rakyll/globalconf",
"Rev": "415abc325023f1a00cd2d9fa512e0e71745791a2"
@ -92,10 +106,6 @@
"ImportPath": "golang.org/x/crypto/scrypt",
"Rev": "4ed45ec682102c643324fae5dff8dab085b6c300"
},
{
"ImportPath": "golang.org/x/net/websocket",
"Rev": "59b0df9b1f7abda5aab0495ee54f408daf182ce7"
},
{
"ImportPath": "gopkg.in/check.v1",
"Rev": "64131543e7896d5bcc6bd5a76287eb75ea96c673"

@ -0,0 +1,6 @@
language: go
go: 1.1
script:
- go vet ./...
- go test -v ./...

@ -0,0 +1,21 @@
Copyright (C) 2013 Jeremy Saenz
All Rights Reserved.
MIT LICENSE
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -0,0 +1,298 @@
[![Build Status](https://travis-ci.org/codegangsta/cli.png?branch=master)](https://travis-ci.org/codegangsta/cli)
# cli.go
cli.go is simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way.
You can view the API docs here:
http://godoc.org/github.com/codegangsta/cli
## Overview
Command line apps are usually so tiny that there is absolutely no reason why your code should *not* be self-documenting. Things like generating help text and parsing command flags/options should not hinder productivity when writing a command line app.
**This is where cli.go comes into play.** cli.go makes command line programming fun, organized, and expressive!
## Installation
Make sure you have a working Go environment (go 1.1 is *required*). [See the install instructions](http://golang.org/doc/install.html).
To install `cli.go`, simply run:
```
$ go get github.com/codegangsta/cli
```
Make sure your `PATH` includes to the `$GOPATH/bin` directory so your commands can be easily used:
```
export PATH=$PATH:$GOPATH/bin
```
## Getting Started
One of the philosophies behind cli.go is that an API should be playful and full of discovery. So a cli.go app can be as little as one line of code in `main()`.
``` go
package main
import (
"os"
"github.com/codegangsta/cli"
)
func main() {
cli.NewApp().Run(os.Args)
}
```
This app will run and show help text, but is not very useful. Let's give an action to execute and some help documentation:
``` go
package main
import (
"os"
"github.com/codegangsta/cli"
)
func main() {
app := cli.NewApp()
app.Name = "boom"
app.Usage = "make an explosive entrance"
app.Action = func(c *cli.Context) {
println("boom! I say!")
}
app.Run(os.Args)
}
```
Running this already gives you a ton of functionality, plus support for things like subcommands and flags, which are covered below.
## Example
Being a programmer can be a lonely job. Thankfully by the power of automation that is not the case! Let's create a greeter app to fend off our demons of loneliness!
Start by creating a directory named `greet`, and within it, add a file, `greet.go` with the following code in it:
``` go
package main
import (
"os"
"github.com/codegangsta/cli"
)
func main() {
app := cli.NewApp()
app.Name = "greet"
app.Usage = "fight the loneliness!"
app.Action = func(c *cli.Context) {
println("Hello friend!")
}
app.Run(os.Args)
}
```
Install our command to the `$GOPATH/bin` directory:
```
$ go install
```
Finally run our new command:
```
$ greet
Hello friend!
```
cli.go also generates some bitchass help text:
```
$ greet help
NAME:
greet - fight the loneliness!
USAGE:
greet [global options] command [command options] [arguments...]
VERSION:
0.0.0
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS
--version Shows version information
```
### Arguments
You can lookup arguments by calling the `Args` function on `cli.Context`.
``` go
...
app.Action = func(c *cli.Context) {
println("Hello", c.Args()[0])
}
...
```
### Flags
Setting and querying flags is simple.
``` go
...
app.Flags = []cli.Flag {
cli.StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
},
}
app.Action = func(c *cli.Context) {
name := "someone"
if len(c.Args()) > 0 {
name = c.Args()[0]
}
if c.String("lang") == "spanish" {
println("Hola", name)
} else {
println("Hello", name)
}
}
...
```
#### Alternate Names
You can set alternate (or short) names for flags by providing a comma-delimited list for the `Name`. e.g.
``` go
app.Flags = []cli.Flag {
cli.StringFlag{
Name: "lang, l",
Value: "english",
Usage: "language for the greeting",
},
}
```
That flag can then be set with `--lang spanish` or `-l spanish`. Note that giving two different forms of the same flag in the same command invocation is an error.
#### Values from the Environment
You can also have the default value set from the environment via `EnvVar`. e.g.
``` go
app.Flags = []cli.Flag {
cli.StringFlag{
Name: "lang, l",
Value: "english",
Usage: "language for the greeting",
EnvVar: "APP_LANG",
},
}
```
The `EnvVar` may also be given as a comma-delimited "cascade", where the first environment variable that resolves is used as the default.
``` go
app.Flags = []cli.Flag {
cli.StringFlag{
Name: "lang, l",
Value: "english",
Usage: "language for the greeting",
EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG",
},
}
```
### Subcommands
Subcommands can be defined for a more git-like command line app.
```go
...
app.Commands = []cli.Command{
{
Name: "add",
ShortName: "a",
Usage: "add a task to the list",
Action: func(c *cli.Context) {
println("added task: ", c.Args().First())
},
},
{
Name: "complete",
ShortName: "c",
Usage: "complete a task on the list",
Action: func(c *cli.Context) {
println("completed task: ", c.Args().First())
},
},
{
Name: "template",
ShortName: "r",
Usage: "options for task templates",
Subcommands: []cli.Command{
{
Name: "add",
Usage: "add a new template",
Action: func(c *cli.Context) {
println("new task template: ", c.Args().First())
},
},
{
Name: "remove",
Usage: "remove an existing template",
Action: func(c *cli.Context) {
println("removed task template: ", c.Args().First())
},
},
},
},
}
...
```
### Bash Completion
You can enable completion commands by setting the `EnableBashCompletion`
flag on the `App` object. By default, this setting will only auto-complete to
show an app's subcommands, but you can write your own completion methods for
the App or its subcommands.
```go
...
var tasks = []string{"cook", "clean", "laundry", "eat", "sleep", "code"}
app := cli.NewApp()
app.EnableBashCompletion = true
app.Commands = []cli.Command{
{
Name: "complete",
ShortName: "c",
Usage: "complete a task on the list",
Action: func(c *cli.Context) {
println("completed task: ", c.Args().First())
},
BashComplete: func(c *cli.Context) {
// This will complete if no args are passed
if len(c.Args()) > 0 {
return
}
for _, t := range tasks {
fmt.Println(t)
}
},
}
}
...
```
#### To Enable
Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while
setting the `PROG` variable to the name of your program:
`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete`
## Contribution Guidelines
Feel free to put up a pull request to fix a bug or maybe add a feature. I will give it a code review and make sure that it does not break backwards compatibility. If I or any other collaborators agree that it is in line with the vision of the project, we will work with you to get the code into a mergeable state and merge it into the master branch.
If you have contributed something significant to the project, I will most likely add you as a collaborator. As a collaborator you are given the ability to merge others pull requests. It is very important that new code does not break existing code, so be careful about what code you do choose to merge. If you have any questions feel free to link @codegangsta to the issue in question and we can review it together.
If you feel like you have contributed to the project but have not yet been added as a collaborator, I probably forgot to add you. Hit @codegangsta up over email and we will get it figured out.

@ -0,0 +1,296 @@
package cli
import (
"fmt"
"io"
"io/ioutil"
"os"
"text/tabwriter"
"text/template"
"time"
)
// App is the main structure of a cli application. It is recomended that
// and app be created with the cli.NewApp() function
type App struct {
// The name of the program. Defaults to os.Args[0]
Name string
// Description of the program.
Usage string
// Version of the program
Version string
// List of commands to execute
Commands []Command
// List of flags to parse
Flags []Flag
// Boolean to enable bash completion commands
EnableBashCompletion bool
// Boolean to hide built-in help command
HideHelp bool
// Boolean to hide built-in version flag
HideVersion bool
// An action to execute when the bash-completion flag is set
BashComplete func(context *Context)
// An action to execute before any subcommands are run, but after the context is ready
// If a non-nil error is returned, no subcommands are run
Before func(context *Context) error
// An action to execute after any subcommands are run, but after the subcommand has finished
// It is run even if Action() panics
After func(context *Context) error
// The action to execute when no subcommands are specified
Action func(context *Context)
// Execute this function if the proper command cannot be found
CommandNotFound func(context *Context, command string)
// Compilation date
Compiled time.Time
// Author
Author string
// Author e-mail
Email string
// Writer writer to write output to
Writer io.Writer
}
// Tries to find out when this binary was compiled.
// Returns the current time if it fails to find it.
func compileTime() time.Time {
info, err := os.Stat(os.Args[0])
if err != nil {
return time.Now()
}
return info.ModTime()
}
// Creates a new cli Application with some reasonable defaults for Name, Usage, Version and Action.
func NewApp() *App {
return &App{
Name: os.Args[0],
Usage: "A new cli application",
Version: "0.0.0",
BashComplete: DefaultAppComplete,
Action: helpCommand.Action,
Compiled: compileTime(),
Author: "Author",
Email: "unknown@email",
Writer: os.Stdout,
}
}
// Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination
func (a *App) Run(arguments []string) (err error) {
if HelpPrinter == nil {
defer func() {
HelpPrinter = nil
}()
HelpPrinter = func(templ string, data interface{}) {
w := tabwriter.NewWriter(a.Writer, 0, 8, 1, '\t', 0)
t := template.Must(template.New("help").Parse(templ))
err := t.Execute(w, data)
if err != nil {
panic(err)
}
w.Flush()
}
}
// append help to commands
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
a.Commands = append(a.Commands, helpCommand)
if (HelpFlag != BoolFlag{}) {
a.appendFlag(HelpFlag)
}
}
//append version/help flags
if a.EnableBashCompletion {
a.appendFlag(BashCompletionFlag)
}
if !a.HideVersion {
a.appendFlag(VersionFlag)
}
// parse flags
set := flagSet(a.Name, a.Flags)
set.SetOutput(ioutil.Discard)
err = set.Parse(arguments[1:])
nerr := normalizeFlags(a.Flags, set)
if nerr != nil {
fmt.Fprintln(a.Writer, nerr)
context := NewContext(a, set, set)
ShowAppHelp(context)
fmt.Fprintln(a.Writer)
return nerr
}
context := NewContext(a, set, set)
if err != nil {
fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n")
ShowAppHelp(context)
fmt.Fprintln(a.Writer)
return err
}
if checkCompletions(context) {
return nil
}
if checkHelp(context) {
return nil
}
if checkVersion(context) {
return nil
}
if a.After != nil {
defer func() {
// err is always nil here.
// There is a check to see if it is non-nil
// just few lines before.
err = a.After(context)
}()
}
if a.Before != nil {
err := a.Before(context)
if err != nil {
return err
}
}
args := context.Args()
if args.Present() {
name := args.First()
c := a.Command(name)
if c != nil {
return c.Run(context)
}
}
// Run default Action
a.Action(context)
return nil
}
// Another entry point to the cli app, takes care of passing arguments and error handling
func (a *App) RunAndExitOnError() {
if err := a.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
// Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags
func (a *App) RunAsSubcommand(ctx *Context) (err error) {
// append help to commands
if len(a.Commands) > 0 {
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
a.Commands = append(a.Commands, helpCommand)
if (HelpFlag != BoolFlag{}) {
a.appendFlag(HelpFlag)
}
}
}
// append flags
if a.EnableBashCompletion {
a.appendFlag(BashCompletionFlag)
}
// parse flags
set := flagSet(a.Name, a.Flags)
set.SetOutput(ioutil.Discard)
err = set.Parse(ctx.Args().Tail())
nerr := normalizeFlags(a.Flags, set)
context := NewContext(a, set, ctx.globalSet)
if nerr != nil {
fmt.Fprintln(a.Writer, nerr)
if len(a.Commands) > 0 {
ShowSubcommandHelp(context)
} else {
ShowCommandHelp(ctx, context.Args().First())
}
fmt.Fprintln(a.Writer)
return nerr
}
if err != nil {
fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n")
ShowSubcommandHelp(context)
return err
}
if checkCompletions(context) {
return nil
}
if len(a.Commands) > 0 {
if checkSubcommandHelp(context) {
return nil
}
} else {
if checkCommandHelp(ctx, context.Args().First()) {
return nil
}
}
if a.After != nil {
defer func() {
// err is always nil here.
// There is a check to see if it is non-nil
// just few lines before.
err = a.After(context)
}()
}
if a.Before != nil {
err := a.Before(context)
if err != nil {
return err
}
}
args := context.Args()
if args.Present() {
name := args.First()
c := a.Command(name)
if c != nil {
return c.Run(context)
}
}
// Run default Action
a.Action(context)
return nil
}
// Returns the named command on App. Returns nil if the command does not exist
func (a *App) Command(name string) *Command {
for _, c := range a.Commands {
if c.HasName(name) {
return &c
}
}
return nil
}
func (a *App) hasFlag(flag Flag) bool {
for _, f := range a.Flags {
if flag == f {
return true
}
}
return false
}
func (a *App) appendFlag(flag Flag) {
if !a.hasFlag(flag) {
a.Flags = append(a.Flags, flag)
}
}

@ -0,0 +1,619 @@
package cli_test
import (
"flag"
"fmt"
"os"
"testing"
"github.com/codegangsta/cli"
)
func ExampleApp() {
// set args for examples sake
os.Args = []string{"greet", "--name", "Jeremy"}
app := cli.NewApp()
app.Name = "greet"
app.Flags = []cli.Flag{
cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
}
app.Action = func(c *cli.Context) {
fmt.Printf("Hello %v\n", c.String("name"))
}
app.Run(os.Args)
// Output:
// Hello Jeremy
}
func ExampleAppSubcommand() {
// set args for examples sake
os.Args = []string{"say", "hi", "english", "--name", "Jeremy"}
app := cli.NewApp()
app.Name = "say"
app.Commands = []cli.Command{
{
Name: "hello",
ShortName: "hi",
Usage: "use it to see a description",
Description: "This is how we describe hello the function",
Subcommands: []cli.Command{
{
Name: "english",
ShortName: "en",
Usage: "sends a greeting in english",
Description: "greets someone in english",
Flags: []cli.Flag{
cli.StringFlag{
Name: "name",
Value: "Bob",
Usage: "Name of the person to greet",
},
},
Action: func(c *cli.Context) {
fmt.Println("Hello,", c.String("name"))
},
},
},
},
}
app.Run(os.Args)
// Output:
// Hello, Jeremy
}
func ExampleAppHelp() {
// set args for examples sake
os.Args = []string{"greet", "h", "describeit"}
app := cli.NewApp()
app.Name = "greet"
app.Flags = []cli.Flag{
cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
}
app.Commands = []cli.Command{
{
Name: "describeit",
ShortName: "d",
Usage: "use it to see a description",
Description: "This is how we describe describeit the function",
Action: func(c *cli.Context) {
fmt.Printf("i like to describe things")
},
},
}
app.Run(os.Args)
// Output:
// NAME:
// describeit - use it to see a description
//
// USAGE:
// command describeit [arguments...]
//
// DESCRIPTION:
// This is how we describe describeit the function
}
func ExampleAppBashComplete() {
// set args for examples sake
os.Args = []string{"greet", "--generate-bash-completion"}
app := cli.NewApp()
app.Name = "greet"
app.EnableBashCompletion = true
app.Commands = []cli.Command{
{
Name: "describeit",
ShortName: "d",
Usage: "use it to see a description",
Description: "This is how we describe describeit the function",
Action: func(c *cli.Context) {
fmt.Printf("i like to describe things")
},
}, {
Name: "next",
Usage: "next example",
Description: "more stuff to see when generating bash completion",
Action: func(c *cli.Context) {
fmt.Printf("the next example")
},
},
}
app.Run(os.Args)
// Output:
// describeit
// d
// next
// help
// h
}
func TestApp_Run(t *testing.T) {
s := ""
app := cli.NewApp()
app.Action = func(c *cli.Context) {
s = s + c.Args().First()
}
err := app.Run([]string{"command", "foo"})
expect(t, err, nil)
err = app.Run([]string{"command", "bar"})
expect(t, err, nil)
expect(t, s, "foobar")
}
var commandAppTests = []struct {
name string
expected bool
}{
{"foobar", true},
{"batbaz", true},
{"b", true},
{"f", true},
{"bat", false},
{"nothing", false},
}
func TestApp_Command(t *testing.T) {
app := cli.NewApp()
fooCommand := cli.Command{Name: "foobar", ShortName: "f"}
batCommand := cli.Command{Name: "batbaz", ShortName: "b"}
app.Commands = []cli.Command{
fooCommand,
batCommand,
}
for _, test := range commandAppTests {
expect(t, app.Command(test.name) != nil, test.expected)
}
}
func TestApp_CommandWithArgBeforeFlags(t *testing.T) {
var parsedOption, firstArg string
app := cli.NewApp()
command := cli.Command{
Name: "cmd",
Flags: []cli.Flag{
cli.StringFlag{Name: "option", Value: "", Usage: "some option"},
},
Action: func(c *cli.Context) {
parsedOption = c.String("option")
firstArg = c.Args().First()
},
}
app.Commands = []cli.Command{command}
app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"})
expect(t, parsedOption, "my-option")
expect(t, firstArg, "my-arg")
}
func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
var context *cli.Context
a := cli.NewApp()
a.Commands = []cli.Command{
{
Name: "foo",
Action: func(c *cli.Context) {
context = c
},
Flags: []cli.Flag{
cli.StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
},
},
Before: func(_ *cli.Context) error { return nil },
},
}
a.Run([]string{"", "foo", "--lang", "spanish", "abcd"})
expect(t, context.Args().Get(0), "abcd")
expect(t, context.String("lang"), "spanish")
}
func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
var parsedOption string
var args []string
app := cli.NewApp()
command := cli.Command{
Name: "cmd",
Flags: []cli.Flag{
cli.StringFlag{Name: "option", Value: "", Usage: "some option"},
},
Action: func(c *cli.Context) {
parsedOption = c.String("option")
args = c.Args()
},
}
app.Commands = []cli.Command{command}
app.Run([]string{"", "cmd", "my-arg", "--option", "my-option", "--", "--notARealFlag"})
expect(t, parsedOption, "my-option")
expect(t, args[0], "my-arg")
expect(t, args[1], "--")
expect(t, args[2], "--notARealFlag")
}
func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
var args []string
app := cli.NewApp()
command := cli.Command{
Name: "cmd",
Action: func(c *cli.Context) {
args = c.Args()
},
}
app.Commands = []cli.Command{command}
app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"})
expect(t, args[0], "my-arg")
expect(t, args[1], "--")
expect(t, args[2], "notAFlagAtAll")
}
func TestApp_Float64Flag(t *testing.T) {
var meters float64
app := cli.NewApp()
app.Flags = []cli.Flag{
cli.Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
}
app.Action = func(c *cli.Context) {
meters = c.Float64("height")
}
app.Run([]string{"", "--height", "1.93"})
expect(t, meters, 1.93)
}
func TestApp_ParseSliceFlags(t *testing.T) {
var parsedOption, firstArg string
var parsedIntSlice []int
var parsedStringSlice []string
app := cli.NewApp()
command := cli.Command{
Name: "cmd",
Flags: []cli.Flag{
cli.IntSliceFlag{Name: "p", Value: &cli.IntSlice{}, Usage: "set one or more ip addr"},
cli.StringSliceFlag{Name: "ip", Value: &cli.StringSlice{}, Usage: "set one or more ports to open"},
},
Action: func(c *cli.Context) {
parsedIntSlice = c.IntSlice("p")
parsedStringSlice = c.StringSlice("ip")
parsedOption = c.String("option")
firstArg = c.Args().First()
},
}
app.Commands = []cli.Command{command}
app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"})
IntsEquals := func(a, b []int) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
StrsEquals := func(a, b []string) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
var expectedIntSlice = []int{22, 80}
var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"}
if !IntsEquals(parsedIntSlice, expectedIntSlice) {
t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice)
}
if !StrsEquals(parsedStringSlice, expectedStringSlice) {
t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice)
}
}
func TestApp_DefaultStdout(t *testing.T) {
app := cli.NewApp()
if app.Writer != os.Stdout {
t.Error("Default output writer not set.")
}
}
type mockWriter struct {
written []byte
}
func (fw *mockWriter) Write(p []byte) (n int, err error) {
if fw.written == nil {
fw.written = p
} else {
fw.written = append(fw.written, p...)
}
return len(p), nil
}
func (fw *mockWriter) GetWritten() (b []byte) {
return fw.written
}
func TestApp_SetStdout(t *testing.T) {
w := &mockWriter{}
app := cli.NewApp()
app.Name = "test"
app.Writer = w
err := app.Run([]string{"help"})
if err != nil {
t.Fatalf("Run error: %s", err)
}
if len(w.written) == 0 {
t.Error("App did not write output to desired writer.")
}
}
func TestApp_BeforeFunc(t *testing.T) {
beforeRun, subcommandRun := false, false
beforeError := fmt.Errorf("fail")
var err error
app := cli.NewApp()
app.Before = func(c *cli.Context) error {
beforeRun = true
s := c.String("opt")
if s == "fail" {
return beforeError
}
return nil
}
app.Commands = []cli.Command{
cli.Command{
Name: "sub",
Action: func(c *cli.Context) {
subcommandRun = true
},
},
}
app.Flags = []cli.Flag{
cli.StringFlag{Name: "opt"},
}
// run with the Before() func succeeding
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
if err != nil {
t.Fatalf("Run error: %s", err)
}
if beforeRun == false {
t.Errorf("Before() not executed when expected")
}
if subcommandRun == false {
t.Errorf("Subcommand not executed when expected")
}
// reset
beforeRun, subcommandRun = false, false
// run with the Before() func failing
err = app.Run([]string{"command", "--opt", "fail", "sub"})
// should be the same error produced by the Before func
if err != beforeError {
t.Errorf("Run error expected, but not received")
}
if beforeRun == false {
t.Errorf("Before() not executed when expected")
}
if subcommandRun == true {
t.Errorf("Subcommand executed when NOT expected")
}
}
func TestApp_AfterFunc(t *testing.T) {
afterRun, subcommandRun := false, false
afterError := fmt.Errorf("fail")
var err error
app := cli.NewApp()
app.After = func(c *cli.Context) error {
afterRun = true
s := c.String("opt")
if s == "fail" {
return afterError
}
return nil
}
app.Commands = []cli.Command{
cli.Command{
Name: "sub",
Action: func(c *cli.Context) {
subcommandRun = true
},
},
}
app.Flags = []cli.Flag{
cli.StringFlag{Name: "opt"},
}
// run with the After() func succeeding
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
if err != nil {
t.Fatalf("Run error: %s", err)
}
if afterRun == false {
t.Errorf("After() not executed when expected")
}
if subcommandRun == false {
t.Errorf("Subcommand not executed when expected")
}
// reset
afterRun, subcommandRun = false, false
// run with the Before() func failing
err = app.Run([]string{"command", "--opt", "fail", "sub"})
// should be the same error produced by the Before func
if err != afterError {
t.Errorf("Run error expected, but not received")
}
if afterRun == false {
t.Errorf("After() not executed when expected")
}
if subcommandRun == false {
t.Errorf("Subcommand not executed when expected")
}
}
func TestAppNoHelpFlag(t *testing.T) {
oldFlag := cli.HelpFlag
defer func() {
cli.HelpFlag = oldFlag
}()
cli.HelpFlag = cli.BoolFlag{}
app := cli.NewApp()
err := app.Run([]string{"test", "-h"})
if err != flag.ErrHelp {
t.Errorf("expected error about missing help flag, but got: %s (%T)", err, err)
}
}
func TestAppHelpPrinter(t *testing.T) {
oldPrinter := cli.HelpPrinter
defer func() {
cli.HelpPrinter = oldPrinter
}()
var wasCalled = false
cli.HelpPrinter = func(template string, data interface{}) {
wasCalled = true
}
app := cli.NewApp()
app.Run([]string{"-h"})
if wasCalled == false {
t.Errorf("Help printer expected to be called, but was not")
}
}
func TestAppVersionPrinter(t *testing.T) {
oldPrinter := cli.VersionPrinter
defer func() {
cli.VersionPrinter = oldPrinter
}()
var wasCalled = false
cli.VersionPrinter = func(c *cli.Context) {
wasCalled = true
}
app := cli.NewApp()
ctx := cli.NewContext(app, nil, nil)
cli.ShowVersion(ctx)
if wasCalled == false {
t.Errorf("Version printer expected to be called, but was not")
}
}
func TestAppCommandNotFound(t *testing.T) {
beforeRun, subcommandRun := false, false
app := cli.NewApp()
app.CommandNotFound = func(c *cli.Context, command string) {
beforeRun = true
}
app.Commands = []cli.Command{
cli.Command{
Name: "bar",
Action: func(c *cli.Context) {
subcommandRun = true
},
},
}
app.Run([]string{"command", "foo"})
expect(t, beforeRun, true)
expect(t, subcommandRun, false)
}
func TestGlobalFlagsInSubcommands(t *testing.T) {
subcommandRun := false
app := cli.NewApp()
app.Flags = []cli.Flag{
cli.BoolFlag{Name: "debug, d", Usage: "Enable debugging"},
}
app.Commands = []cli.Command{
cli.Command{
Name: "foo",
Subcommands: []cli.Command{
{
Name: "bar",
Action: func(c *cli.Context) {
if c.GlobalBool("debug") {
subcommandRun = true
}
},
},
},
},
}
app.Run([]string{"command", "-d", "foo", "bar"})
expect(t, subcommandRun, true)
}

@ -0,0 +1,13 @@
#! /bin/bash
_cli_bash_autocomplete() {
local cur prev opts base
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
}
complete -F _cli_bash_autocomplete $PROG

@ -0,0 +1,5 @@
autoload -U compinit && compinit
autoload -U bashcompinit && bashcompinit
script_dir=$(dirname $0)
source ${script_dir}/bash_autocomplete

@ -0,0 +1,19 @@
// Package cli provides a minimal framework for creating and organizing command line
// Go applications. cli is designed to be easy to understand and write, the most simple
// cli application can be written as follows:
// func main() {
// cli.NewApp().Run(os.Args)
// }
//
// Of course this application does not do much, so let's make this an actual application:
// func main() {
// app := cli.NewApp()
// app.Name = "greet"
// app.Usage = "say a greeting"
// app.Action = func(c *cli.Context) {
// println("Greetings")
// }
//
// app.Run(os.Args)
// }
package cli

@ -0,0 +1,100 @@
package cli_test
import (
"os"
"github.com/codegangsta/cli"
)
func Example() {
app := cli.NewApp()
app.Name = "todo"
app.Usage = "task list on the command line"
app.Commands = []cli.Command{
{
Name: "add",
ShortName: "a",
Usage: "add a task to the list",
Action: func(c *cli.Context) {
println("added task: ", c.Args().First())
},
},
{
Name: "complete",
ShortName: "c",
Usage: "complete a task on the list",
Action: func(c *cli.Context) {
println("completed task: ", c.Args().First())
},
},
}
app.Run(os.Args)
}
func ExampleSubcommand() {
app := cli.NewApp()
app.Name = "say"
app.Commands = []cli.Command{
{
Name: "hello",
ShortName: "hi",
Usage: "use it to see a description",
Description: "This is how we describe hello the function",
Subcommands: []cli.Command{
{
Name: "english",
ShortName: "en",
Usage: "sends a greeting in english",
Description: "greets someone in english",
Flags: []cli.Flag{
cli.StringFlag{
Name: "name",
Value: "Bob",
Usage: "Name of the person to greet",
},
},
Action: func(c *cli.Context) {
println("Hello, ", c.String("name"))
},
}, {
Name: "spanish",
ShortName: "sp",
Usage: "sends a greeting in spanish",
Flags: []cli.Flag{
cli.StringFlag{
Name: "surname",
Value: "Jones",
Usage: "Surname of the person to greet",
},
},
Action: func(c *cli.Context) {
println("Hola, ", c.String("surname"))
},
}, {
Name: "french",
ShortName: "fr",
Usage: "sends a greeting in french",
Flags: []cli.Flag{
cli.StringFlag{
Name: "nickname",
Value: "Stevie",
Usage: "Nickname of the person to greet",
},
},
Action: func(c *cli.Context) {
println("Bonjour, ", c.String("nickname"))
},
},
},
}, {
Name: "bye",
Usage: "says goodbye",
Action: func(c *cli.Context) {
println("bye")
},
},
}
app.Run(os.Args)
}

@ -0,0 +1,160 @@
package cli
import (
"fmt"
"io/ioutil"
"strings"
)
// Command is a subcommand for a cli.App.
type Command struct {
// The name of the command
Name string
// short name of the command. Typically one character
ShortName string
// A short description of the usage of this command
Usage string
// A longer explanation of how the command works
Description string
// The function to call when checking for bash command completions
BashComplete func(context *Context)
// An action to execute before any sub-subcommands are run, but after the context is ready
// If a non-nil error is returned, no sub-subcommands are run
Before func(context *Context) error
// An action to execute after any subcommands are run, but after the subcommand has finished
// It is run even if Action() panics
After func(context *Context) error
// The function to call when this command is invoked
Action func(context *Context)
// List of child commands
Subcommands []Command
// List of flags to parse
Flags []Flag
// Treat all flags as normal arguments if true
SkipFlagParsing bool
// Boolean to hide built-in help command
HideHelp bool
}
// Invokes the command given the context, parses ctx.Args() to generate command-specific flags
func (c Command) Run(ctx *Context) error {
if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil {
return c.startApp(ctx)
}
if !c.HideHelp && (HelpFlag != BoolFlag{}) {
// append help to flags
c.Flags = append(
c.Flags,
HelpFlag,
)
}
if ctx.App.EnableBashCompletion {
c.Flags = append(c.Flags, BashCompletionFlag)
}
set := flagSet(c.Name, c.Flags)
set.SetOutput(ioutil.Discard)
firstFlagIndex := -1
terminatorIndex := -1
for index, arg := range ctx.Args() {
if arg == "--" {
terminatorIndex = index
break
} else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 {
firstFlagIndex = index
}
}
var err error
if firstFlagIndex > -1 && !c.SkipFlagParsing {
args := ctx.Args()
regularArgs := make([]string, len(args[1:firstFlagIndex]))
copy(regularArgs, args[1:firstFlagIndex])
var flagArgs []string
if terminatorIndex > -1 {
flagArgs = args[firstFlagIndex:terminatorIndex]
regularArgs = append(regularArgs, args[terminatorIndex:]...)
} else {
flagArgs = args[firstFlagIndex:]
}
err = set.Parse(append(flagArgs, regularArgs...))
} else {
err = set.Parse(ctx.Args().Tail())
}
if err != nil {
fmt.Fprint(ctx.App.Writer, "Incorrect Usage.\n\n")
ShowCommandHelp(ctx, c.Name)
fmt.Fprintln(ctx.App.Writer)
return err
}
nerr := normalizeFlags(c.Flags, set)
if nerr != nil {
fmt.Fprintln(ctx.App.Writer, nerr)
fmt.Fprintln(ctx.App.Writer)
ShowCommandHelp(ctx, c.Name)
fmt.Fprintln(ctx.App.Writer)
return nerr
}
context := NewContext(ctx.App, set, ctx.globalSet)
if checkCommandCompletions(context, c.Name) {
return nil
}
if checkCommandHelp(context, c.Name) {
return nil
}
context.Command = c
c.Action(context)
return nil
}
// Returns true if Command.Name or Command.ShortName matches given name
func (c Command) HasName(name string) bool {
return c.Name == name || c.ShortName == name
}
func (c Command) startApp(ctx *Context) error {
app := NewApp()
// set the name and usage
app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
if c.Description != "" {
app.Usage = c.Description
} else {
app.Usage = c.Usage
}
// set CommandNotFound
app.CommandNotFound = ctx.App.CommandNotFound
// set the flags and commands
app.Commands = c.Subcommands
app.Flags = c.Flags
app.HideHelp = c.HideHelp
// bash completion
app.EnableBashCompletion = ctx.App.EnableBashCompletion
if c.BashComplete != nil {
app.BashComplete = c.BashComplete
}
// set the actions
app.Before = c.Before
app.After = c.After
if c.Action != nil {
app.Action = c.Action
} else {
app.Action = helpSubcommand.Action
}
return app.RunAsSubcommand(ctx)
}

@ -0,0 +1,49 @@
package cli_test
import (
"flag"
"testing"
"github.com/codegangsta/cli"
)
func TestCommandDoNotIgnoreFlags(t *testing.T) {
app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
test := []string{"blah", "blah", "-break"}
set.Parse(test)
c := cli.NewContext(app, set, set)
command := cli.Command{
Name: "test-cmd",
ShortName: "tc",
Usage: "this is for testing",
Description: "testing",
Action: func(_ *cli.Context) {},
}
err := command.Run(c)
expect(t, err.Error(), "flag provided but not defined: -break")
}
func TestCommandIgnoreFlags(t *testing.T) {
app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
test := []string{"blah", "blah"}
set.Parse(test)
c := cli.NewContext(app, set, set)
command := cli.Command{
Name: "test-cmd",
ShortName: "tc",
Usage: "this is for testing",
Description: "testing",
Action: func(_ *cli.Context) {},
SkipFlagParsing: true,
}
err := command.Run(c)
expect(t, err, nil)
}

@ -0,0 +1,339 @@
package cli
import (
"errors"
"flag"
"strconv"
"strings"
"time"
)
// Context is a type that is passed through to
// each Handler action in a cli application. Context
// can be used to retrieve context-specific Args and
// parsed command-line options.
type Context struct {
App *App
Command Command
flagSet *flag.FlagSet
globalSet *flag.FlagSet
setFlags map[string]bool
globalSetFlags map[string]bool
}
// Creates a new context. For use in when invoking an App or Command action.
func NewContext(app *App, set *flag.FlagSet, globalSet *flag.FlagSet) *Context {
return &Context{App: app, flagSet: set, globalSet: globalSet}
}
// Looks up the value of a local int flag, returns 0 if no int flag exists
func (c *Context) Int(name string) int {
return lookupInt(name, c.flagSet)
}
// Looks up the value of a local time.Duration flag, returns 0 if no time.Duration flag exists
func (c *Context) Duration(name string) time.Duration {
return lookupDuration(name, c.flagSet)
}
// Looks up the value of a local float64 flag, returns 0 if no float64 flag exists
func (c *Context) Float64(name string) float64 {
return lookupFloat64(name, c.flagSet)
}
// Looks up the value of a local bool flag, returns false if no bool flag exists
func (c *Context) Bool(name string) bool {
return lookupBool(name, c.flagSet)
}
// Looks up the value of a local boolT flag, returns false if no bool flag exists
func (c *Context) BoolT(name string) bool {
return lookupBoolT(name, c.flagSet)
}
// Looks up the value of a local string flag, returns "" if no string flag exists
func (c *Context) String(name string) string {
return lookupString(name, c.flagSet)
}
// Looks up the value of a local string slice flag, returns nil if no string slice flag exists
func (c *Context) StringSlice(name string) []string {
return lookupStringSlice(name, c.flagSet)
}
// Looks up the value of a local int slice flag, returns nil if no int slice flag exists
func (c *Context) IntSlice(name string) []int {
return lookupIntSlice(name, c.flagSet)
}
// Looks up the value of a local generic flag, returns nil if no generic flag exists
func (c *Context) Generic(name string) interface{} {
return lookupGeneric(name, c.flagSet)
}
// Looks up the value of a global int flag, returns 0 if no int flag exists
func (c *Context) GlobalInt(name string) int {
return lookupInt(name, c.globalSet)
}
// Looks up the value of a global time.Duration flag, returns 0 if no time.Duration flag exists
func (c *Context) GlobalDuration(name string) time.Duration {
return lookupDuration(name, c.globalSet)
}
// Looks up the value of a global bool flag, returns false if no bool flag exists
func (c *Context) GlobalBool(name string) bool {
return lookupBool(name, c.globalSet)
}
// Looks up the value of a global string flag, returns "" if no string flag exists
func (c *Context) GlobalString(name string) string {
return lookupString(name, c.globalSet)
}
// Looks up the value of a global string slice flag, returns nil if no string slice flag exists
func (c *Context) GlobalStringSlice(name string) []string {
return lookupStringSlice(name, c.globalSet)
}
// Looks up the value of a global int slice flag, returns nil if no int slice flag exists
func (c *Context) GlobalIntSlice(name string) []int {
return lookupIntSlice(name, c.globalSet)
}
// Looks up the value of a global generic flag, returns nil if no generic flag exists
func (c *Context) GlobalGeneric(name string) interface{} {
return lookupGeneric(name, c.globalSet)
}
// Determines if the flag was actually set
func (c *Context) IsSet(name string) bool {
if c.setFlags == nil {
c.setFlags = make(map[string]bool)
c.flagSet.Visit(func(f *flag.Flag) {
c.setFlags[f.Name] = true
})
}
return c.setFlags[name] == true
}
// Determines if the global flag was actually set
func (c *Context) GlobalIsSet(name string) bool {
if c.globalSetFlags == nil {
c.globalSetFlags = make(map[string]bool)
c.globalSet.Visit(func(f *flag.Flag) {
c.globalSetFlags[f.Name] = true
})
}
return c.globalSetFlags[name] == true
}
// Returns a slice of flag names used in this context.
func (c *Context) FlagNames() (names []string) {
for _, flag := range c.Command.Flags {
name := strings.Split(flag.getName(), ",")[0]
if name == "help" {
continue
}
names = append(names, name)
}
return
}
// Returns a slice of global flag names used by the app.
func (c *Context) GlobalFlagNames() (names []string) {
for _, flag := range c.App.Flags {
name := strings.Split(flag.getName(), ",")[0]
if name == "help" || name == "version" {
continue
}
names = append(names, name)
}
return
}
type Args []string
// Returns the command line arguments associated with the context.
func (c *Context) Args() Args {
args := Args(c.flagSet.Args())
return args
}
// Returns the nth argument, or else a blank string
func (a Args) Get(n int) string {
if len(a) > n {
return a[n]
}
return ""
}
// Returns the first argument, or else a blank string
func (a Args) First() string {
return a.Get(0)
}
// Return the rest of the arguments (not the first one)
// or else an empty string slice
func (a Args) Tail() []string {
if len(a) >= 2 {
return []string(a)[1:]
}
return []string{}
}
// Checks if there are any arguments present
func (a Args) Present() bool {
return len(a) != 0
}
// Swaps arguments at the given indexes
func (a Args) Swap(from, to int) error {
if from >= len(a) || to >= len(a) {
return errors.New("index out of range")
}
a[from], a[to] = a[to], a[from]
return nil
}
func lookupInt(name string, set *flag.FlagSet) int {
f := set.Lookup(name)
if f != nil {
val, err := strconv.Atoi(f.Value.String())
if err != nil {
return 0
}
return val
}
return 0
}
func lookupDuration(name string, set *flag.FlagSet) time.Duration {
f := set.Lookup(name)
if f != nil {
val, err := time.ParseDuration(f.Value.String())
if err == nil {
return val
}
}
return 0
}
func lookupFloat64(name string, set *flag.FlagSet) float64 {
f := set.Lookup(name)
if f != nil {
val, err := strconv.ParseFloat(f.Value.String(), 64)
if err != nil {
return 0
}
return val
}
return 0
}
func lookupString(name string, set *flag.FlagSet) string {
f := set.Lookup(name)
if f != nil {
return f.Value.String()
}
return ""
}
func lookupStringSlice(name string, set *flag.FlagSet) []string {
f := set.Lookup(name)
if f != nil {
return (f.Value.(*StringSlice)).Value()
}
return nil
}
func lookupIntSlice(name string, set *flag.FlagSet) []int {
f := set.Lookup(name)
if f != nil {
return (f.Value.(*IntSlice)).Value()
}
return nil
}
func lookupGeneric(name string, set *flag.FlagSet) interface{} {
f := set.Lookup(name)
if f != nil {
return f.Value
}
return nil
}
func lookupBool(name string, set *flag.FlagSet) bool {
f := set.Lookup(name)
if f != nil {
val, err := strconv.ParseBool(f.Value.String())
if err != nil {
return false
}
return val
}
return false
}
func lookupBoolT(name string, set *flag.FlagSet) bool {
f := set.Lookup(name)
if f != nil {
val, err := strconv.ParseBool(f.Value.String())
if err != nil {
return true
}
return val
}
return false
}
func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
switch ff.Value.(type) {
case *StringSlice:
default:
set.Set(name, ff.Value.String())
}
}
func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
visited := make(map[string]bool)
set.Visit(func(f *flag.Flag) {
visited[f.Name] = true
})
for _, f := range flags {
parts := strings.Split(f.getName(), ",")
if len(parts) == 1 {
continue
}
var ff *flag.Flag
for _, name := range parts {
name = strings.Trim(name, " ")
if visited[name] {
if ff != nil {
return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name)
}
ff = set.Lookup(name)
}
}
if ff == nil {
continue
}
for _, name := range parts {
name = strings.Trim(name, " ")
if !visited[name] {
copyFlag(name, ff, set)
}
}
}
return nil
}

@ -0,0 +1,99 @@
package cli_test
import (
"flag"
"testing"
"time"
"github.com/codegangsta/cli"
)
func TestNewContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Int("myflag", 12, "doc")
globalSet := flag.NewFlagSet("test", 0)
globalSet.Int("myflag", 42, "doc")
command := cli.Command{Name: "mycommand"}
c := cli.NewContext(nil, set, globalSet)
c.Command = command
expect(t, c.Int("myflag"), 12)
expect(t, c.GlobalInt("myflag"), 42)
expect(t, c.Command.Name, "mycommand")
}
func TestContext_Int(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Int("myflag", 12, "doc")
c := cli.NewContext(nil, set, set)
expect(t, c.Int("myflag"), 12)
}
func TestContext_Duration(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Duration("myflag", time.Duration(12*time.Second), "doc")
c := cli.NewContext(nil, set, set)
expect(t, c.Duration("myflag"), time.Duration(12*time.Second))
}
func TestContext_String(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.String("myflag", "hello world", "doc")
c := cli.NewContext(nil, set, set)
expect(t, c.String("myflag"), "hello world")
}
func TestContext_Bool(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
c := cli.NewContext(nil, set, set)
expect(t, c.Bool("myflag"), false)
}
func TestContext_BoolT(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", true, "doc")
c := cli.NewContext(nil, set, set)
expect(t, c.BoolT("myflag"), true)
}
func TestContext_Args(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
c := cli.NewContext(nil, set, set)
set.Parse([]string{"--myflag", "bat", "baz"})
expect(t, len(c.Args()), 2)
expect(t, c.Bool("myflag"), true)
}
func TestContext_IsSet(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
set.String("otherflag", "hello world", "doc")
globalSet := flag.NewFlagSet("test", 0)
globalSet.Bool("myflagGlobal", true, "doc")
c := cli.NewContext(nil, set, globalSet)
set.Parse([]string{"--myflag", "bat", "baz"})
globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
expect(t, c.IsSet("myflag"), true)
expect(t, c.IsSet("otherflag"), false)
expect(t, c.IsSet("bogusflag"), false)
expect(t, c.IsSet("myflagGlobal"), false)
}
func TestContext_GlobalIsSet(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
set.String("otherflag", "hello world", "doc")
globalSet := flag.NewFlagSet("test", 0)
globalSet.Bool("myflagGlobal", true, "doc")
globalSet.Bool("myflagGlobalUnset", true, "doc")
c := cli.NewContext(nil, set, globalSet)
set.Parse([]string{"--myflag", "bat", "baz"})
globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
expect(t, c.GlobalIsSet("myflag"), false)
expect(t, c.GlobalIsSet("otherflag"), false)
expect(t, c.GlobalIsSet("bogusflag"), false)
expect(t, c.GlobalIsSet("myflagGlobal"), true)
expect(t, c.GlobalIsSet("myflagGlobalUnset"), false)
expect(t, c.GlobalIsSet("bogusGlobal"), false)
}

@ -0,0 +1,454 @@
package cli
import (
"flag"
"fmt"
"os"
"strconv"
"strings"
"time"
)
// This flag enables bash-completion for all commands and subcommands
var BashCompletionFlag = BoolFlag{
Name: "generate-bash-completion",
}
// This flag prints the version for the application
var VersionFlag = BoolFlag{
Name: "version, v",
Usage: "print the version",
}
// This flag prints the help for all commands and subcommands
// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand
// unless HideHelp is set to true)
var HelpFlag = BoolFlag{
Name: "help, h",
Usage: "show help",
}
// Flag is a common interface related to parsing flags in cli.
// For more advanced flag parsing techniques, it is recomended that
// this interface be implemented.
type Flag interface {
fmt.Stringer
// Apply Flag settings to the given flag set
Apply(*flag.FlagSet)
getName() string
}
func flagSet(name string, flags []Flag) *flag.FlagSet {
set := flag.NewFlagSet(name, flag.ContinueOnError)
for _, f := range flags {
f.Apply(set)
}
return set
}
func eachName(longName string, fn func(string)) {
parts := strings.Split(longName, ",")
for _, name := range parts {
name = strings.Trim(name, " ")
fn(name)
}
}
// Generic is a generic parseable type identified by a specific flag
type Generic interface {
Set(value string) error
String() string
}
// GenericFlag is the flag type for types implementing Generic
type GenericFlag struct {
Name string
Value Generic
Usage string
EnvVar string
}
// String returns the string representation of the generic flag to display the
// help text to the user (uses the String() method of the generic flag to show
// the value)
func (f GenericFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s%s \"%v\"\t%v", prefixFor(f.Name), f.Name, f.Value, f.Usage))
}
// Apply takes the flagset and calls Set on the generic flag with the value
// provided by the user for parsing by the flag
func (f GenericFlag) Apply(set *flag.FlagSet) {
val := f.Value
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
val.Set(envVal)
break
}
}
}
eachName(f.Name, func(name string) {
set.Var(f.Value, name, f.Usage)
})
}
func (f GenericFlag) getName() string {
return f.Name
}
type StringSlice []string
func (f *StringSlice) Set(value string) error {
*f = append(*f, value)
return nil
}
func (f *StringSlice) String() string {
return fmt.Sprintf("%s", *f)
}
func (f *StringSlice) Value() []string {
return *f
}
type StringSliceFlag struct {
Name string
Value *StringSlice
Usage string
EnvVar string
}
func (f StringSliceFlag) String() string {
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
pref := prefixFor(firstName)
return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
}
func (f StringSliceFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
newVal := &StringSlice{}
for _, s := range strings.Split(envVal, ",") {
s = strings.TrimSpace(s)
newVal.Set(s)
}
f.Value = newVal
break
}
}
}
eachName(f.Name, func(name string) {
set.Var(f.Value, name, f.Usage)
})
}
func (f StringSliceFlag) getName() string {
return f.Name
}
type IntSlice []int
func (f *IntSlice) Set(value string) error {
tmp, err := strconv.Atoi(value)
if err != nil {
return err
} else {
*f = append(*f, tmp)
}
return nil
}
func (f *IntSlice) String() string {
return fmt.Sprintf("%d", *f)
}
func (f *IntSlice) Value() []int {
return *f
}
type IntSliceFlag struct {
Name string
Value *IntSlice
Usage string
EnvVar string
}
func (f IntSliceFlag) String() string {
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
pref := prefixFor(firstName)
return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
}
func (f IntSliceFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
newVal := &IntSlice{}
for _, s := range strings.Split(envVal, ",") {
s = strings.TrimSpace(s)
err := newVal.Set(s)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
}
}
f.Value = newVal
break
}
}
}
eachName(f.Name, func(name string) {
set.Var(f.Value, name, f.Usage)
})
}
func (f IntSliceFlag) getName() string {
return f.Name
}
type BoolFlag struct {
Name string
Usage string
EnvVar string
}
func (f BoolFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
}
func (f BoolFlag) Apply(set *flag.FlagSet) {
val := false
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
envValBool, err := strconv.ParseBool(envVal)
if err == nil {
val = envValBool
}
break
}
}
}
eachName(f.Name, func(name string) {
set.Bool(name, val, f.Usage)
})
}
func (f BoolFlag) getName() string {
return f.Name
}
type BoolTFlag struct {
Name string
Usage string
EnvVar string
}
func (f BoolTFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
}
func (f BoolTFlag) Apply(set *flag.FlagSet) {
val := true
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
envValBool, err := strconv.ParseBool(envVal)
if err == nil {
val = envValBool
break
}
}
}
}
eachName(f.Name, func(name string) {
set.Bool(name, val, f.Usage)
})
}
func (f BoolTFlag) getName() string {
return f.Name
}
type StringFlag struct {
Name string
Value string
Usage string
EnvVar string
}
func (f StringFlag) String() string {
var fmtString string
fmtString = "%s %v\t%v"
if len(f.Value) > 0 {
fmtString = "%s \"%v\"\t%v"
} else {
fmtString = "%s %v\t%v"
}
return withEnvHint(f.EnvVar, fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage))
}
func (f StringFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
f.Value = envVal
break
}
}
}
eachName(f.Name, func(name string) {
set.String(name, f.Value, f.Usage)
})
}
func (f StringFlag) getName() string {
return f.Name
}
type IntFlag struct {
Name string
Value int
Usage string
EnvVar string
}
func (f IntFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
}
func (f IntFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
envValInt, err := strconv.ParseInt(envVal, 0, 64)
if err == nil {
f.Value = int(envValInt)
break
}
}
}
}
eachName(f.Name, func(name string) {
set.Int(name, f.Value, f.Usage)
})
}
func (f IntFlag) getName() string {
return f.Name
}
type DurationFlag struct {
Name string
Value time.Duration
Usage string
EnvVar string
}
func (f DurationFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
}
func (f DurationFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
envValDuration, err := time.ParseDuration(envVal)
if err == nil {
f.Value = envValDuration
break
}
}
}
}
eachName(f.Name, func(name string) {
set.Duration(name, f.Value, f.Usage)
})
}
func (f DurationFlag) getName() string {
return f.Name
}
type Float64Flag struct {
Name string
Value float64
Usage string
EnvVar string
}
func (f Float64Flag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
}
func (f Float64Flag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" {
envValFloat, err := strconv.ParseFloat(envVal, 10)
if err == nil {
f.Value = float64(envValFloat)
}
}
}
}
eachName(f.Name, func(name string) {
set.Float64(name, f.Value, f.Usage)
})
}
func (f Float64Flag) getName() string {
return f.Name
}
func prefixFor(name string) (prefix string) {
if len(name) == 1 {
prefix = "-"
} else {
prefix = "--"
}
return
}
func prefixedNames(fullName string) (prefixed string) {
parts := strings.Split(fullName, ",")
for i, name := range parts {
name = strings.Trim(name, " ")
prefixed += prefixFor(name) + name
if i < len(parts)-1 {
prefixed += ", "
}
}
return
}
func withEnvHint(envVar, str string) string {
envText := ""
if envVar != "" {
envText = fmt.Sprintf(" [$%s]", strings.Join(strings.Split(envVar, ","), ", $"))
}
return str + envText
}

@ -0,0 +1,742 @@
package cli_test
import (
"fmt"
"os"
"reflect"
"strings"
"testing"
"github.com/codegangsta/cli"
)
var boolFlagTests = []struct {
name string
expected string
}{
{"help", "--help\t"},
{"h", "-h\t"},
}
func TestBoolFlagHelpOutput(t *testing.T) {
for _, test := range boolFlagTests {
flag := cli.BoolFlag{Name: test.name}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
var stringFlagTests = []struct {
name string
value string
expected string
}{
{"help", "", "--help \t"},
{"h", "", "-h \t"},
{"h", "", "-h \t"},
{"test", "Something", "--test \"Something\"\t"},
}
func TestStringFlagHelpOutput(t *testing.T) {
for _, test := range stringFlagTests {
flag := cli.StringFlag{Name: test.name, Value: test.value}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_FOO", "derp")
for _, test := range stringFlagTests {
flag := cli.StringFlag{Name: test.name, Value: test.value, EnvVar: "APP_FOO"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_FOO]") {
t.Errorf("%s does not end with [$APP_FOO]", output)
}
}
}
var stringSliceFlagTests = []struct {
name string
value *cli.StringSlice
expected string
}{
{"help", func() *cli.StringSlice {
s := &cli.StringSlice{}
s.Set("")
return s
}(), "--help [--help option --help option]\t"},
{"h", func() *cli.StringSlice {
s := &cli.StringSlice{}
s.Set("")
return s
}(), "-h [-h option -h option]\t"},
{"h", func() *cli.StringSlice {
s := &cli.StringSlice{}
s.Set("")
return s
}(), "-h [-h option -h option]\t"},
{"test", func() *cli.StringSlice {
s := &cli.StringSlice{}
s.Set("Something")
return s
}(), "--test [--test option --test option]\t"},
}
func TestStringSliceFlagHelpOutput(t *testing.T) {
for _, test := range stringSliceFlagTests {
flag := cli.StringSliceFlag{Name: test.name, Value: test.value}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_QWWX", "11,4")
for _, test := range stringSliceFlagTests {
flag := cli.StringSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_QWWX"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_QWWX]") {
t.Errorf("%q does not end with [$APP_QWWX]", output)
}
}
}
var intFlagTests = []struct {
name string
expected string
}{
{"help", "--help \"0\"\t"},
{"h", "-h \"0\"\t"},
}
func TestIntFlagHelpOutput(t *testing.T) {
for _, test := range intFlagTests {
flag := cli.IntFlag{Name: test.name}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestIntFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAR", "2")
for _, test := range intFlagTests {
flag := cli.IntFlag{Name: test.name, EnvVar: "APP_BAR"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_BAR]") {
t.Errorf("%s does not end with [$APP_BAR]", output)
}
}
}
var durationFlagTests = []struct {
name string
expected string
}{
{"help", "--help \"0\"\t"},
{"h", "-h \"0\"\t"},
}
func TestDurationFlagHelpOutput(t *testing.T) {
for _, test := range durationFlagTests {
flag := cli.DurationFlag{Name: test.name}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAR", "2h3m6s")
for _, test := range durationFlagTests {
flag := cli.DurationFlag{Name: test.name, EnvVar: "APP_BAR"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_BAR]") {
t.Errorf("%s does not end with [$APP_BAR]", output)
}
}
}
var intSliceFlagTests = []struct {
name string
value *cli.IntSlice
expected string
}{
{"help", &cli.IntSlice{}, "--help [--help option --help option]\t"},
{"h", &cli.IntSlice{}, "-h [-h option -h option]\t"},
{"h", &cli.IntSlice{}, "-h [-h option -h option]\t"},
{"test", func() *cli.IntSlice {
i := &cli.IntSlice{}
i.Set("9")
return i
}(), "--test [--test option --test option]\t"},
}
func TestIntSliceFlagHelpOutput(t *testing.T) {
for _, test := range intSliceFlagTests {
flag := cli.IntSliceFlag{Name: test.name, Value: test.value}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_SMURF", "42,3")
for _, test := range intSliceFlagTests {
flag := cli.IntSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_SMURF"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_SMURF]") {
t.Errorf("%q does not end with [$APP_SMURF]", output)
}
}
}
var float64FlagTests = []struct {
name string
expected string
}{
{"help", "--help \"0\"\t"},
{"h", "-h \"0\"\t"},
}
func TestFloat64FlagHelpOutput(t *testing.T) {
for _, test := range float64FlagTests {
flag := cli.Float64Flag{Name: test.name}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAZ", "99.4")
for _, test := range float64FlagTests {
flag := cli.Float64Flag{Name: test.name, EnvVar: "APP_BAZ"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_BAZ]") {
t.Errorf("%s does not end with [$APP_BAZ]", output)
}
}
}
var genericFlagTests = []struct {
name string
value cli.Generic
expected string
}{
{"test", &Parser{"abc", "def"}, "--test \"abc,def\"\ttest flag"},
{"t", &Parser{"abc", "def"}, "-t \"abc,def\"\ttest flag"},
}
func TestGenericFlagHelpOutput(t *testing.T) {
for _, test := range genericFlagTests {
flag := cli.GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_ZAP", "3")
for _, test := range genericFlagTests {
flag := cli.GenericFlag{Name: test.name, EnvVar: "APP_ZAP"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_ZAP]") {
t.Errorf("%s does not end with [$APP_ZAP]", output)
}
}
}
func TestParseMultiString(t *testing.T) {
(&cli.App{
Flags: []cli.Flag{
cli.StringFlag{Name: "serve, s"},
},
Action: func(ctx *cli.Context) {
if ctx.String("serve") != "10" {
t.Errorf("main name not set")
}
if ctx.String("s") != "10" {
t.Errorf("short name not set")
}
},
}).Run([]string{"run", "-s", "10"})
}
func TestParseMultiStringFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_COUNT", "20")
(&cli.App{
Flags: []cli.Flag{
cli.StringFlag{Name: "count, c", EnvVar: "APP_COUNT"},
},
Action: func(ctx *cli.Context) {
if ctx.String("count") != "20" {
t.Errorf("main name not set")
}
if ctx.String("c") != "20" {
t.Errorf("short name not set")
}
},
}).Run([]string{"run"})
}
func TestParseMultiStringFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_COUNT", "20")
(&cli.App{
Flags: []cli.Flag{
cli.StringFlag{Name: "count, c", EnvVar: "COMPAT_COUNT,APP_COUNT"},
},
Action: func(ctx *cli.Context) {
if ctx.String("count") != "20" {
t.Errorf("main name not set")
}
if ctx.String("c") != "20" {
t.Errorf("short name not set")
}
},
}).Run([]string{"run"})
}
func TestParseMultiStringSlice(t *testing.T) {
(&cli.App{
Flags: []cli.Flag{
cli.StringSliceFlag{Name: "serve, s", Value: &cli.StringSlice{}},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"10", "20"}) {
t.Errorf("main name not set")
}
if !reflect.DeepEqual(ctx.StringSlice("s"), []string{"10", "20"}) {
t.Errorf("short name not set")
}
},
}).Run([]string{"run", "-s", "10", "-s", "20"})
}
func TestParseMultiStringSliceFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&cli.App{
Flags: []cli.Flag{
cli.StringSliceFlag{Name: "intervals, i", Value: &cli.StringSlice{}, EnvVar: "APP_INTERVALS"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
t.Errorf("short name not set from env")
}
},
}).Run([]string{"run"})
}
func TestParseMultiStringSliceFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&cli.App{
Flags: []cli.Flag{
cli.StringSliceFlag{Name: "intervals, i", Value: &cli.StringSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
t.Errorf("short name not set from env")
}
},
}).Run([]string{"run"})
}
func TestParseMultiInt(t *testing.T) {
a := cli.App{
Flags: []cli.Flag{
cli.IntFlag{Name: "serve, s"},
},
Action: func(ctx *cli.Context) {
if ctx.Int("serve") != 10 {
t.Errorf("main name not set")
}
if ctx.Int("s") != 10 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "-s", "10"})
}
func TestParseMultiIntFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "10")
a := cli.App{
Flags: []cli.Flag{
cli.IntFlag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
},
Action: func(ctx *cli.Context) {
if ctx.Int("timeout") != 10 {
t.Errorf("main name not set")
}
if ctx.Int("t") != 10 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiIntFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "10")
a := cli.App{
Flags: []cli.Flag{
cli.IntFlag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
},
Action: func(ctx *cli.Context) {
if ctx.Int("timeout") != 10 {
t.Errorf("main name not set")
}
if ctx.Int("t") != 10 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiIntSlice(t *testing.T) {
(&cli.App{
Flags: []cli.Flag{
cli.IntSliceFlag{Name: "serve, s", Value: &cli.IntSlice{}},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
t.Errorf("main name not set")
}
if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) {
t.Errorf("short name not set")
}
},
}).Run([]string{"run", "-s", "10", "-s", "20"})
}
func TestParseMultiIntSliceFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&cli.App{
Flags: []cli.Flag{
cli.IntSliceFlag{Name: "intervals, i", Value: &cli.IntSlice{}, EnvVar: "APP_INTERVALS"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
t.Errorf("short name not set from env")
}
},
}).Run([]string{"run"})
}
func TestParseMultiIntSliceFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&cli.App{
Flags: []cli.Flag{
cli.IntSliceFlag{Name: "intervals, i", Value: &cli.IntSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
t.Errorf("short name not set from env")
}
},
}).Run([]string{"run"})
}
func TestParseMultiFloat64(t *testing.T) {
a := cli.App{
Flags: []cli.Flag{
cli.Float64Flag{Name: "serve, s"},
},
Action: func(ctx *cli.Context) {
if ctx.Float64("serve") != 10.2 {
t.Errorf("main name not set")
}
if ctx.Float64("s") != 10.2 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "-s", "10.2"})
}
func TestParseMultiFloat64FromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
a := cli.App{
Flags: []cli.Flag{
cli.Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
},
Action: func(ctx *cli.Context) {
if ctx.Float64("timeout") != 15.5 {
t.Errorf("main name not set")
}
if ctx.Float64("t") != 15.5 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiFloat64FromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
a := cli.App{
Flags: []cli.Flag{
cli.Float64Flag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
},
Action: func(ctx *cli.Context) {
if ctx.Float64("timeout") != 15.5 {
t.Errorf("main name not set")
}
if ctx.Float64("t") != 15.5 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiBool(t *testing.T) {
a := cli.App{
Flags: []cli.Flag{
cli.BoolFlag{Name: "serve, s"},
},
Action: func(ctx *cli.Context) {
if ctx.Bool("serve") != true {
t.Errorf("main name not set")
}
if ctx.Bool("s") != true {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "--serve"})
}
func TestParseMultiBoolFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "1")
a := cli.App{
Flags: []cli.Flag{
cli.BoolFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
},
Action: func(ctx *cli.Context) {
if ctx.Bool("debug") != true {
t.Errorf("main name not set from env")
}
if ctx.Bool("d") != true {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiBoolFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "1")
a := cli.App{
Flags: []cli.Flag{
cli.BoolFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"},
},
Action: func(ctx *cli.Context) {
if ctx.Bool("debug") != true {
t.Errorf("main name not set from env")
}
if ctx.Bool("d") != true {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiBoolT(t *testing.T) {
a := cli.App{
Flags: []cli.Flag{
cli.BoolTFlag{Name: "serve, s"},
},
Action: func(ctx *cli.Context) {
if ctx.BoolT("serve") != true {
t.Errorf("main name not set")
}
if ctx.BoolT("s") != true {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "--serve"})
}
func TestParseMultiBoolTFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "0")
a := cli.App{
Flags: []cli.Flag{
cli.BoolTFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
},
Action: func(ctx *cli.Context) {
if ctx.BoolT("debug") != false {
t.Errorf("main name not set from env")
}
if ctx.BoolT("d") != false {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiBoolTFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "0")
a := cli.App{
Flags: []cli.Flag{
cli.BoolTFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"},
},
Action: func(ctx *cli.Context) {
if ctx.BoolT("debug") != false {
t.Errorf("main name not set from env")
}
if ctx.BoolT("d") != false {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
type Parser [2]string
func (p *Parser) Set(value string) error {
parts := strings.Split(value, ",")
if len(parts) != 2 {
return fmt.Errorf("invalid format")
}
(*p)[0] = parts[0]
(*p)[1] = parts[1]
return nil
}
func (p *Parser) String() string {
return fmt.Sprintf("%s,%s", p[0], p[1])
}
func TestParseGeneric(t *testing.T) {
a := cli.App{
Flags: []cli.Flag{
cli.GenericFlag{Name: "serve, s", Value: &Parser{}},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) {
t.Errorf("main name not set")
}
if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"10", "20"}) {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "-s", "10,20"})
}
func TestParseGenericFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_SERVE", "20,30")
a := cli.App{
Flags: []cli.Flag{
cli.GenericFlag{Name: "serve, s", Value: &Parser{}, EnvVar: "APP_SERVE"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"20", "30"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"20", "30"}) {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
func TestParseGenericFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_FOO", "99,2000")
a := cli.App{
Flags: []cli.Flag{
cli.GenericFlag{Name: "foos", Value: &Parser{}, EnvVar: "COMPAT_FOO,APP_FOO"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.Generic("foos"), &Parser{"99", "2000"}) {
t.Errorf("value not set from env")
}
},
}
a.Run([]string{"run"})
}

@ -0,0 +1,211 @@
package cli
import "fmt"
// The text template for the Default help topic.
// cli.go uses text/template to render templates. You can
// render custom help text by setting this variable.
var AppHelpTemplate = `NAME:
{{.Name}} - {{.Usage}}
USAGE:
{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...]
VERSION:
{{.Version}}{{if or .Author .Email}}
AUTHOR:{{if .Author}}
{{.Author}}{{if .Email}} - <{{.Email}}>{{end}}{{else}}
{{.Email}}{{end}}{{end}}
COMMANDS:
{{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
{{end}}{{if .Flags}}
GLOBAL OPTIONS:
{{range .Flags}}{{.}}
{{end}}{{end}}
`
// The text template for the command help topic.
// cli.go uses text/template to render templates. You can
// render custom help text by setting this variable.
var CommandHelpTemplate = `NAME:
{{.Name}} - {{.Usage}}
USAGE:
command {{.Name}}{{if .Flags}} [command options]{{end}} [arguments...]{{if .Description}}
DESCRIPTION:
{{.Description}}{{end}}{{if .Flags}}
OPTIONS:
{{range .Flags}}{{.}}
{{end}}{{ end }}
`
// The text template for the subcommand help topic.
// cli.go uses text/template to render templates. You can
// render custom help text by setting this variable.
var SubcommandHelpTemplate = `NAME:
{{.Name}} - {{.Usage}}
USAGE:
{{.Name}} command{{if .Flags}} [command options]{{end}} [arguments...]
COMMANDS:
{{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
{{end}}{{if .Flags}}
OPTIONS:
{{range .Flags}}{{.}}
{{end}}{{end}}
`
var helpCommand = Command{
Name: "help",
ShortName: "h",
Usage: "Shows a list of commands or help for one command",
Action: func(c *Context) {
args := c.Args()
if args.Present() {
ShowCommandHelp(c, args.First())
} else {
ShowAppHelp(c)
}
},
}
var helpSubcommand = Command{
Name: "help",
ShortName: "h",
Usage: "Shows a list of commands or help for one command",
Action: func(c *Context) {
args := c.Args()
if args.Present() {
ShowCommandHelp(c, args.First())
} else {
ShowSubcommandHelp(c)
}
},
}
// Prints help for the App
type helpPrinter func(templ string, data interface{})
var HelpPrinter helpPrinter = nil
// Prints version for the App
var VersionPrinter = printVersion
func ShowAppHelp(c *Context) {
HelpPrinter(AppHelpTemplate, c.App)
}
// Prints the list of subcommands as the default app completion method
func DefaultAppComplete(c *Context) {
for _, command := range c.App.Commands {
fmt.Fprintln(c.App.Writer, command.Name)
if command.ShortName != "" {
fmt.Fprintln(c.App.Writer, command.ShortName)
}
}
}
// Prints help for the given command
func ShowCommandHelp(c *Context, command string) {
for _, c := range c.App.Commands {
if c.HasName(command) {
HelpPrinter(CommandHelpTemplate, c)
return
}
}
if c.App.CommandNotFound != nil {
c.App.CommandNotFound(c, command)
} else {
fmt.Fprintf(c.App.Writer, "No help topic for '%v'\n", command)
}
}
// Prints help for the given subcommand
func ShowSubcommandHelp(c *Context) {
ShowCommandHelp(c, c.Command.Name)
}
// Prints the version number of the App
func ShowVersion(c *Context) {
VersionPrinter(c)
}
func printVersion(c *Context) {
fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version)
}
// Prints the lists of commands within a given context
func ShowCompletions(c *Context) {
a := c.App
if a != nil && a.BashComplete != nil {
a.BashComplete(c)
}
}
// Prints the custom completions for a given command
func ShowCommandCompletions(ctx *Context, command string) {
c := ctx.App.Command(command)
if c != nil && c.BashComplete != nil {
c.BashComplete(ctx)
}
}
func checkVersion(c *Context) bool {
if c.GlobalBool("version") {
ShowVersion(c)
return true
}
return false
}
func checkHelp(c *Context) bool {
if c.GlobalBool("h") || c.GlobalBool("help") {
ShowAppHelp(c)
return true
}
return false
}
func checkCommandHelp(c *Context, name string) bool {
if c.Bool("h") || c.Bool("help") {
ShowCommandHelp(c, name)
return true
}
return false
}
func checkSubcommandHelp(c *Context) bool {
if c.GlobalBool("h") || c.GlobalBool("help") {
ShowSubcommandHelp(c)
return true
}
return false
}
func checkCompletions(c *Context) bool {
if (c.GlobalBool(BashCompletionFlag.Name) || c.Bool(BashCompletionFlag.Name)) && c.App.EnableBashCompletion {
ShowCompletions(c)
return true
}
return false
}
func checkCommandCompletions(c *Context, name string) bool {
if c.Bool(BashCompletionFlag.Name) && c.App.EnableBashCompletion {
ShowCommandCompletions(c, name)
return true
}
return false
}

@ -0,0 +1,19 @@
package cli_test
import (
"reflect"
"testing"
)
/* Test Helpers */
func expect(t *testing.T, a interface{}, b interface{}) {
if a != b {
t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
}
}
func refute(t *testing.T, a interface{}, b interface{}) {
if a == b {
t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
}
}

@ -0,0 +1,10 @@
.idea/
.DS_Store
*/**/*un~
.vagrant/
*.pyc
build/
pyethash.egg-info/
*.so
*~
*.swp

@ -0,0 +1,6 @@
before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq wget cmake gcc bash libboost-test-dev nodejs python-pip python-dev
- sudo pip install virtualenv -q
script: "./test/test.sh"

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 2.8.7)
project(ethash)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
set(ETHHASH_LIBS ethash)
if (WIN32 AND WANT_CRYPTOPP)
add_subdirectory(cryptopp)
endif()
add_subdirectory(src/libethash)
# bin2h.cmake doesn't work
#add_subdirectory(src/libethash-cl EXCLUDE_FROM_ALL)
add_subdirectory(src/benchmark EXCLUDE_FROM_ALL)
add_subdirectory(test/c EXCLUDE_FROM_ALL)

@ -0,0 +1,3 @@
.PHONY: clean
clean:
rm -rf *.so pyethash.egg-info/ build/ test/python/python-virtual-env/ test/c/build/ pyethash/*.{so,pyc}

@ -0,0 +1,7 @@
[![Build Status](https://travis-ci.org/ethereum/ethash.svg?branch=master)](https://travis-ci.org/ethereum/ethash)
# Ethash
For details on this project, please see the Ethereum wiki:
https://github.com/ethereum/wiki/wiki/Ethash

@ -0,0 +1,7 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure(2) do |config|
config.vm.box = "Ubuntu 12.04"
config.vm.box_url = "https://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-amd64-vagrant-disk1.box"
end

@ -0,0 +1,161 @@
#.rst:
# CMakeParseArguments
# -------------------
#
#
#
# CMAKE_PARSE_ARGUMENTS(<prefix> <options> <one_value_keywords>
# <multi_value_keywords> args...)
#
# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions
# for parsing the arguments given to that macro or function. It
# processes the arguments and defines a set of variables which hold the
# values of the respective options.
#
# The <options> argument contains all options for the respective macro,
# i.e. keywords which can be used when calling the macro without any
# value following, like e.g. the OPTIONAL keyword of the install()
# command.
#
# The <one_value_keywords> argument contains all keywords for this macro
# which are followed by one value, like e.g. DESTINATION keyword of the
# install() command.
#
# The <multi_value_keywords> argument contains all keywords for this
# macro which can be followed by more than one value, like e.g. the
# TARGETS or FILES keywords of the install() command.
#
# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the
# keywords listed in <options>, <one_value_keywords> and
# <multi_value_keywords> a variable composed of the given <prefix>
# followed by "_" and the name of the respective keyword. These
# variables will then hold the respective value from the argument list.
# For the <options> keywords this will be TRUE or FALSE.
#
# All remaining arguments are collected in a variable
# <prefix>_UNPARSED_ARGUMENTS, this can be checked afterwards to see
# whether your macro was called with unrecognized parameters.
#
# As an example here a my_install() macro, which takes similar arguments
# as the real install() command:
#
# ::
#
# function(MY_INSTALL)
# set(options OPTIONAL FAST)
# set(oneValueArgs DESTINATION RENAME)
# set(multiValueArgs TARGETS CONFIGURATIONS)
# cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}"
# "${multiValueArgs}" ${ARGN} )
# ...
#
#
#
# Assume my_install() has been called like this:
#
# ::
#
# my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub)
#
#
#
# After the cmake_parse_arguments() call the macro will have set the
# following variables:
#
# ::
#
# MY_INSTALL_OPTIONAL = TRUE
# MY_INSTALL_FAST = FALSE (this option was not used when calling my_install()
# MY_INSTALL_DESTINATION = "bin"
# MY_INSTALL_RENAME = "" (was not used)
# MY_INSTALL_TARGETS = "foo;bar"
# MY_INSTALL_CONFIGURATIONS = "" (was not used)
# MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL"
#
#
#
# You can then continue and process these variables.
#
# Keywords terminate lists of values, e.g. if directly after a
# one_value_keyword another recognized keyword follows, this is
# interpreted as the beginning of the new option. E.g.
# my_install(TARGETS foo DESTINATION OPTIONAL) would result in
# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION
# would be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor.
#=============================================================================
# Copyright 2010 Alexander Neundorf <neundorf@kde.org>
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
if(__CMAKE_PARSE_ARGUMENTS_INCLUDED)
return()
endif()
set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE)
function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames)
# first set all result variables to empty/FALSE
foreach(arg_name ${_singleArgNames} ${_multiArgNames})
set(${prefix}_${arg_name})
endforeach()
foreach(option ${_optionNames})
set(${prefix}_${option} FALSE)
endforeach()
set(${prefix}_UNPARSED_ARGUMENTS)
set(insideValues FALSE)
set(currentArgName)
# now iterate over all arguments and fill the result variables
foreach(currentArg ${ARGN})
list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword
list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword
list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword
if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1)
if(insideValues)
if("${insideValues}" STREQUAL "SINGLE")
set(${prefix}_${currentArgName} ${currentArg})
set(insideValues FALSE)
elseif("${insideValues}" STREQUAL "MULTI")
list(APPEND ${prefix}_${currentArgName} ${currentArg})
endif()
else()
list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg})
endif()
else()
if(NOT ${optionIndex} EQUAL -1)
set(${prefix}_${currentArg} TRUE)
set(insideValues FALSE)
elseif(NOT ${singleArgIndex} EQUAL -1)
set(currentArgName ${currentArg})
set(${prefix}_${currentArgName})
set(insideValues "SINGLE")
elseif(NOT ${multiArgIndex} EQUAL -1)
set(currentArgName ${currentArg})
set(${prefix}_${currentArgName})
set(insideValues "MULTI")
endif()
endif()
endforeach()
# propagate the result variables to the caller:
foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames})
set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE)
endforeach()
set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE)
endfunction()

@ -0,0 +1,108 @@
# Module for locating the Crypto++ encryption library.
#
# Customizable variables:
# CRYPTOPP_ROOT_DIR
# This variable points to the CryptoPP root directory. On Windows the
# library location typically will have to be provided explicitly using the
# -D command-line option. The directory should include the include/cryptopp,
# lib and/or bin sub-directories.
#
# Read-only variables:
# CRYPTOPP_FOUND
# Indicates whether the library has been found.
#
# CRYPTOPP_INCLUDE_DIRS
# Points to the CryptoPP include directory.
#
# CRYPTOPP_LIBRARIES
# Points to the CryptoPP libraries that should be passed to
# target_link_libararies.
#
#
# Copyright (c) 2012 Sergiu Dotenco
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
INCLUDE (FindPackageHandleStandardArgs)
FIND_PATH (CRYPTOPP_ROOT_DIR
NAMES cryptopp/cryptlib.h include/cryptopp/cryptlib.h
PATHS ENV CRYPTOPPROOT
DOC "CryptoPP root directory")
# Re-use the previous path:
FIND_PATH (CRYPTOPP_INCLUDE_DIR
NAMES cryptopp/cryptlib.h
HINTS ${CRYPTOPP_ROOT_DIR}
PATH_SUFFIXES include
DOC "CryptoPP include directory")
FIND_LIBRARY (CRYPTOPP_LIBRARY_DEBUG
NAMES cryptlibd cryptoppd
HINTS ${CRYPTOPP_ROOT_DIR}
PATH_SUFFIXES lib
DOC "CryptoPP debug library")
FIND_LIBRARY (CRYPTOPP_LIBRARY_RELEASE
NAMES cryptlib cryptopp
HINTS ${CRYPTOPP_ROOT_DIR}
PATH_SUFFIXES lib
DOC "CryptoPP release library")
IF (CRYPTOPP_LIBRARY_DEBUG AND CRYPTOPP_LIBRARY_RELEASE)
SET (CRYPTOPP_LIBRARY
optimized ${CRYPTOPP_LIBRARY_RELEASE}
debug ${CRYPTOPP_LIBRARY_DEBUG} CACHE DOC "CryptoPP library")
ELSEIF (CRYPTOPP_LIBRARY_RELEASE)
SET (CRYPTOPP_LIBRARY ${CRYPTOPP_LIBRARY_RELEASE} CACHE DOC
"CryptoPP library")
ENDIF (CRYPTOPP_LIBRARY_DEBUG AND CRYPTOPP_LIBRARY_RELEASE)
IF (CRYPTOPP_INCLUDE_DIR)
SET (_CRYPTOPP_VERSION_HEADER ${CRYPTOPP_INCLUDE_DIR}/cryptopp/config.h)
IF (EXISTS ${_CRYPTOPP_VERSION_HEADER})
FILE (STRINGS ${_CRYPTOPP_VERSION_HEADER} _CRYPTOPP_VERSION_TMP REGEX
"^#define CRYPTOPP_VERSION[ \t]+[0-9]+$")
STRING (REGEX REPLACE
"^#define CRYPTOPP_VERSION[ \t]+([0-9]+)" "\\1" _CRYPTOPP_VERSION_TMP
${_CRYPTOPP_VERSION_TMP})
STRING (REGEX REPLACE "([0-9]+)[0-9][0-9]" "\\1" CRYPTOPP_VERSION_MAJOR
${_CRYPTOPP_VERSION_TMP})
STRING (REGEX REPLACE "[0-9]([0-9])[0-9]" "\\1" CRYPTOPP_VERSION_MINOR
${_CRYPTOPP_VERSION_TMP})
STRING (REGEX REPLACE "[0-9][0-9]([0-9])" "\\1" CRYPTOPP_VERSION_PATCH
${_CRYPTOPP_VERSION_TMP})
SET (CRYPTOPP_VERSION_COUNT 3)
SET (CRYPTOPP_VERSION
${CRYPTOPP_VERSION_MAJOR}.${CRYPTOPP_VERSION_MINOR}.${CRYPTOPP_VERSION_PATCH})
ENDIF (EXISTS ${_CRYPTOPP_VERSION_HEADER})
ENDIF (CRYPTOPP_INCLUDE_DIR)
SET (CRYPTOPP_INCLUDE_DIRS ${CRYPTOPP_INCLUDE_DIR})
SET (CRYPTOPP_LIBRARIES ${CRYPTOPP_LIBRARY})
MARK_AS_ADVANCED (CRYPTOPP_INCLUDE_DIR CRYPTOPP_LIBRARY CRYPTOPP_LIBRARY_DEBUG
CRYPTOPP_LIBRARY_RELEASE)
FIND_PACKAGE_HANDLE_STANDARD_ARGS (CryptoPP REQUIRED_VARS CRYPTOPP_ROOT_DIR
CRYPTOPP_INCLUDE_DIR CRYPTOPP_LIBRARY VERSION_VAR CRYPTOPP_VERSION)

@ -0,0 +1,136 @@
#.rst:
# FindOpenCL
# ----------
#
# Try to find OpenCL
#
# Once done this will define::
#
# OpenCL_FOUND - True if OpenCL was found
# OpenCL_INCLUDE_DIRS - include directories for OpenCL
# OpenCL_LIBRARIES - link against this library to use OpenCL
# OpenCL_VERSION_STRING - Highest supported OpenCL version (eg. 1.2)
# OpenCL_VERSION_MAJOR - The major version of the OpenCL implementation
# OpenCL_VERSION_MINOR - The minor version of the OpenCL implementation
#
# The module will also define two cache variables::
#
# OpenCL_INCLUDE_DIR - the OpenCL include directory
# OpenCL_LIBRARY - the path to the OpenCL library
#
#=============================================================================
# Copyright 2014 Matthaeus G. Chajdas
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
function(_FIND_OPENCL_VERSION)
include(CheckSymbolExists)
include(CMakePushCheckState)
set(CMAKE_REQUIRED_QUIET ${OpenCL_FIND_QUIETLY})
CMAKE_PUSH_CHECK_STATE()
foreach(VERSION "2_0" "1_2" "1_1" "1_0")
set(CMAKE_REQUIRED_INCLUDES "${OpenCL_INCLUDE_DIR}")
if(APPLE)
CHECK_SYMBOL_EXISTS(
CL_VERSION_${VERSION}
"${OpenCL_INCLUDE_DIR}/OpenCL/cl.h"
OPENCL_VERSION_${VERSION})
else()
CHECK_SYMBOL_EXISTS(
CL_VERSION_${VERSION}
"${OpenCL_INCLUDE_DIR}/CL/cl.h"
OPENCL_VERSION_${VERSION})
endif()
if(OPENCL_VERSION_${VERSION})
string(REPLACE "_" "." VERSION "${VERSION}")
set(OpenCL_VERSION_STRING ${VERSION} PARENT_SCOPE)
string(REGEX MATCHALL "[0-9]+" version_components "${VERSION}")
list(GET version_components 0 major_version)
list(GET version_components 1 minor_version)
set(OpenCL_VERSION_MAJOR ${major_version} PARENT_SCOPE)
set(OpenCL_VERSION_MINOR ${minor_version} PARENT_SCOPE)
break()
endif()
endforeach()
CMAKE_POP_CHECK_STATE()
endfunction()
find_path(OpenCL_INCLUDE_DIR
NAMES
CL/cl.h OpenCL/cl.h
PATHS
ENV "PROGRAMFILES(X86)"
ENV AMDAPPSDKROOT
ENV INTELOCLSDKROOT
ENV NVSDKCOMPUTE_ROOT
ENV CUDA_PATH
ENV ATISTREAMSDKROOT
PATH_SUFFIXES
include
OpenCL/common/inc
"AMD APP/include")
_FIND_OPENCL_VERSION()
if(WIN32)
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
find_library(OpenCL_LIBRARY
NAMES OpenCL
PATHS
ENV "PROGRAMFILES(X86)"
ENV AMDAPPSDKROOT
ENV INTELOCLSDKROOT
ENV CUDA_PATH
ENV NVSDKCOMPUTE_ROOT
ENV ATISTREAMSDKROOT
PATH_SUFFIXES
"AMD APP/lib/x86"
lib/x86
lib/Win32
OpenCL/common/lib/Win32)
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
find_library(OpenCL_LIBRARY
NAMES OpenCL
PATHS
ENV "PROGRAMFILES(X86)"
ENV AMDAPPSDKROOT
ENV INTELOCLSDKROOT
ENV CUDA_PATH
ENV NVSDKCOMPUTE_ROOT
ENV ATISTREAMSDKROOT
PATH_SUFFIXES
"AMD APP/lib/x86_64"
lib/x86_64
lib/x64
OpenCL/common/lib/x64)
endif()
else()
find_library(OpenCL_LIBRARY
NAMES OpenCL)
endif()
set(OpenCL_LIBRARIES ${OpenCL_LIBRARY})
set(OpenCL_INCLUDE_DIRS ${OpenCL_INCLUDE_DIR})
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
find_package_handle_standard_args(
OpenCL
FOUND_VAR OpenCL_FOUND
REQUIRED_VARS OpenCL_LIBRARY OpenCL_INCLUDE_DIR
VERSION_VAR OpenCL_VERSION_STRING)
mark_as_advanced(
OpenCL_INCLUDE_DIR
OpenCL_LIBRARY)

@ -0,0 +1,382 @@
#.rst:
# FindPackageHandleStandardArgs
# -----------------------------
#
#
#
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(<name> ... )
#
# This function is intended to be used in FindXXX.cmake modules files.
# It handles the REQUIRED, QUIET and version-related arguments to
# find_package(). It also sets the <packagename>_FOUND variable. The
# package is considered found if all variables <var1>... listed contain
# valid results, e.g. valid filepaths.
#
# There are two modes of this function. The first argument in both
# modes is the name of the Find-module where it is called (in original
# casing).
#
# The first simple mode looks like this:
#
# ::
#
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(<name>
# (DEFAULT_MSG|"Custom failure message") <var1>...<varN> )
#
# If the variables <var1> to <varN> are all valid, then
# <UPPERCASED_NAME>_FOUND will be set to TRUE. If DEFAULT_MSG is given
# as second argument, then the function will generate itself useful
# success and error messages. You can also supply a custom error
# message for the failure case. This is not recommended.
#
# The second mode is more powerful and also supports version checking:
#
# ::
#
# FIND_PACKAGE_HANDLE_STANDARD_ARGS(NAME
# [FOUND_VAR <resultVar>]
# [REQUIRED_VARS <var1>...<varN>]
# [VERSION_VAR <versionvar>]
# [HANDLE_COMPONENTS]
# [CONFIG_MODE]
# [FAIL_MESSAGE "Custom failure message"] )
#
# In this mode, the name of the result-variable can be set either to
# either <UPPERCASED_NAME>_FOUND or <OriginalCase_Name>_FOUND using the
# FOUND_VAR option. Other names for the result-variable are not
# allowed. So for a Find-module named FindFooBar.cmake, the two
# possible names are FooBar_FOUND and FOOBAR_FOUND. It is recommended
# to use the original case version. If the FOUND_VAR option is not
# used, the default is <UPPERCASED_NAME>_FOUND.
#
# As in the simple mode, if <var1> through <varN> are all valid,
# <packagename>_FOUND will be set to TRUE. After REQUIRED_VARS the
# variables which are required for this package are listed. Following
# VERSION_VAR the name of the variable can be specified which holds the
# version of the package which has been found. If this is done, this
# version will be checked against the (potentially) specified required
# version used in the find_package() call. The EXACT keyword is also
# handled. The default messages include information about the required
# version and the version which has been actually found, both if the
# version is ok or not. If the package supports components, use the
# HANDLE_COMPONENTS option to enable handling them. In this case,
# find_package_handle_standard_args() will report which components have
# been found and which are missing, and the <packagename>_FOUND variable
# will be set to FALSE if any of the required components (i.e. not the
# ones listed after OPTIONAL_COMPONENTS) are missing. Use the option
# CONFIG_MODE if your FindXXX.cmake module is a wrapper for a
# find_package(... NO_MODULE) call. In this case VERSION_VAR will be
# set to <NAME>_VERSION and the macro will automatically check whether
# the Config module was found. Via FAIL_MESSAGE a custom failure
# message can be specified, if this is not used, the default message
# will be displayed.
#
# Example for mode 1:
#
# ::
#
# find_package_handle_standard_args(LibXml2 DEFAULT_MSG
# LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)
#
#
#
# LibXml2 is considered to be found, if both LIBXML2_LIBRARY and
# LIBXML2_INCLUDE_DIR are valid. Then also LIBXML2_FOUND is set to
# TRUE. If it is not found and REQUIRED was used, it fails with
# FATAL_ERROR, independent whether QUIET was used or not. If it is
# found, success will be reported, including the content of <var1>. On
# repeated Cmake runs, the same message won't be printed again.
#
# Example for mode 2:
#
# ::
#
# find_package_handle_standard_args(LibXslt
# FOUND_VAR LibXslt_FOUND
# REQUIRED_VARS LibXslt_LIBRARIES LibXslt_INCLUDE_DIRS
# VERSION_VAR LibXslt_VERSION_STRING)
#
# In this case, LibXslt is considered to be found if the variable(s)
# listed after REQUIRED_VAR are all valid, i.e. LibXslt_LIBRARIES and
# LibXslt_INCLUDE_DIRS in this case. The result will then be stored in
# LibXslt_FOUND . Also the version of LibXslt will be checked by using
# the version contained in LibXslt_VERSION_STRING. Since no
# FAIL_MESSAGE is given, the default messages will be printed.
#
# Another example for mode 2:
#
# ::
#
# find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4)
# find_package_handle_standard_args(Automoc4 CONFIG_MODE)
#
# In this case, FindAutmoc4.cmake wraps a call to find_package(Automoc4
# NO_MODULE) and adds an additional search directory for automoc4. Here
# the result will be stored in AUTOMOC4_FOUND. The following
# FIND_PACKAGE_HANDLE_STANDARD_ARGS() call produces a proper
# success/error message.
#=============================================================================
# Copyright 2007-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/CMakeParseArguments.cmake)
# internal helper macro
macro(_FPHSA_FAILURE_MESSAGE _msg)
if (${_NAME}_FIND_REQUIRED)
message(FATAL_ERROR "${_msg}")
else ()
if (NOT ${_NAME}_FIND_QUIETLY)
message(STATUS "${_msg}")
endif ()
endif ()
endmacro()
# internal helper macro to generate the failure message when used in CONFIG_MODE:
macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)
# <name>_CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found:
if(${_NAME}_CONFIG)
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing: ${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})")
else()
# If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version.
# List them all in the error message:
if(${_NAME}_CONSIDERED_CONFIGS)
set(configsText "")
list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount)
math(EXPR configsCount "${configsCount} - 1")
foreach(currentConfigIndex RANGE ${configsCount})
list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename)
list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version)
set(configsText "${configsText} ${filename} (version ${version})\n")
endforeach()
if (${_NAME}_NOT_FOUND_MESSAGE)
set(configsText "${configsText} Reason given by package: ${${_NAME}_NOT_FOUND_MESSAGE}\n")
endif()
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}")
else()
# Simple case: No Config-file was found at all:
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}")
endif()
endif()
endmacro()
function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)
# set up the arguments for CMAKE_PARSE_ARGUMENTS and check whether we are in
# new extended or in the "old" mode:
set(options CONFIG_MODE HANDLE_COMPONENTS)
set(oneValueArgs FAIL_MESSAGE VERSION_VAR FOUND_VAR)
set(multiValueArgs REQUIRED_VARS)
set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} )
list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX)
if(${INDEX} EQUAL -1)
set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG})
set(FPHSA_REQUIRED_VARS ${ARGN})
set(FPHSA_VERSION_VAR)
else()
CMAKE_PARSE_ARGUMENTS(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN})
if(FPHSA_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"")
endif()
if(NOT FPHSA_FAIL_MESSAGE)
set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG")
endif()
endif()
# now that we collected all arguments, process them
if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG")
set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}")
endif()
# In config-mode, we rely on the variable <package>_CONFIG, which is set by find_package()
# when it successfully found the config-file, including version checking:
if(FPHSA_CONFIG_MODE)
list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG)
list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS)
set(FPHSA_VERSION_VAR ${_NAME}_VERSION)
endif()
if(NOT FPHSA_REQUIRED_VARS)
message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()")
endif()
list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR)
string(TOUPPER ${_NAME} _NAME_UPPER)
string(TOLOWER ${_NAME} _NAME_LOWER)
if(FPHSA_FOUND_VAR)
if(FPHSA_FOUND_VAR MATCHES "^${_NAME}_FOUND$" OR FPHSA_FOUND_VAR MATCHES "^${_NAME_UPPER}_FOUND$")
set(_FOUND_VAR ${FPHSA_FOUND_VAR})
else()
message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_NAME}_FOUND\" and \"${_NAME_UPPER}_FOUND\" are valid names.")
endif()
else()
set(_FOUND_VAR ${_NAME_UPPER}_FOUND)
endif()
# collect all variables which were not found, so they can be printed, so the
# user knows better what went wrong (#6375)
set(MISSING_VARS "")
set(DETAILS "")
# check if all passed variables are valid
unset(${_FOUND_VAR})
foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS})
if(NOT ${_CURRENT_VAR})
set(${_FOUND_VAR} FALSE)
set(MISSING_VARS "${MISSING_VARS} ${_CURRENT_VAR}")
else()
set(DETAILS "${DETAILS}[${${_CURRENT_VAR}}]")
endif()
endforeach()
if(NOT "${${_FOUND_VAR}}" STREQUAL "FALSE")
set(${_FOUND_VAR} TRUE)
endif()
# component handling
unset(FOUND_COMPONENTS_MSG)
unset(MISSING_COMPONENTS_MSG)
if(FPHSA_HANDLE_COMPONENTS)
foreach(comp ${${_NAME}_FIND_COMPONENTS})
if(${_NAME}_${comp}_FOUND)
if(NOT DEFINED FOUND_COMPONENTS_MSG)
set(FOUND_COMPONENTS_MSG "found components: ")
endif()
set(FOUND_COMPONENTS_MSG "${FOUND_COMPONENTS_MSG} ${comp}")
else()
if(NOT DEFINED MISSING_COMPONENTS_MSG)
set(MISSING_COMPONENTS_MSG "missing components: ")
endif()
set(MISSING_COMPONENTS_MSG "${MISSING_COMPONENTS_MSG} ${comp}")
if(${_NAME}_FIND_REQUIRED_${comp})
set(${_FOUND_VAR} FALSE)
set(MISSING_VARS "${MISSING_VARS} ${comp}")
endif()
endif()
endforeach()
set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}")
set(DETAILS "${DETAILS}[c${COMPONENT_MSG}]")
endif()
# version handling:
set(VERSION_MSG "")
set(VERSION_OK TRUE)
set(VERSION ${${FPHSA_VERSION_VAR}})
# check with DEFINED here as the requested or found version may be "0"
if (DEFINED ${_NAME}_FIND_VERSION)
if(DEFINED ${FPHSA_VERSION_VAR})
if(${_NAME}_FIND_VERSION_EXACT) # exact version required
# count the dots in the version string
string(REGEX REPLACE "[^.]" "" _VERSION_DOTS "${VERSION}")
# add one dot because there is one dot more than there are components
string(LENGTH "${_VERSION_DOTS}." _VERSION_DOTS)
if (_VERSION_DOTS GREATER ${_NAME}_FIND_VERSION_COUNT)
# Because of the C++ implementation of find_package() ${_NAME}_FIND_VERSION_COUNT
# is at most 4 here. Therefore a simple lookup table is used.
if (${_NAME}_FIND_VERSION_COUNT EQUAL 1)
set(_VERSION_REGEX "[^.]*")
elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 2)
set(_VERSION_REGEX "[^.]*\\.[^.]*")
elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 3)
set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*")
else ()
set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*")
endif ()
string(REGEX REPLACE "^(${_VERSION_REGEX})\\..*" "\\1" _VERSION_HEAD "${VERSION}")
unset(_VERSION_REGEX)
if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _VERSION_HEAD)
set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"")
set(VERSION_OK FALSE)
else ()
set(VERSION_MSG "(found suitable exact version \"${VERSION}\")")
endif ()
unset(_VERSION_HEAD)
else ()
if (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}")
set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"")
set(VERSION_OK FALSE)
else ()
set(VERSION_MSG "(found suitable exact version \"${VERSION}\")")
endif ()
endif ()
unset(_VERSION_DOTS)
else() # minimum version specified:
if ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}")
set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"")
set(VERSION_OK FALSE)
else ()
set(VERSION_MSG "(found suitable version \"${VERSION}\", minimum required is \"${${_NAME}_FIND_VERSION}\")")
endif ()
endif()
else()
# if the package was not found, but a version was given, add that to the output:
if(${_NAME}_FIND_VERSION_EXACT)
set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")")
else()
set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")")
endif()
endif()
else ()
if(VERSION)
set(VERSION_MSG "(found version \"${VERSION}\")")
endif()
endif ()
if(VERSION_OK)
set(DETAILS "${DETAILS}[v${VERSION}(${${_NAME}_FIND_VERSION})]")
else()
set(${_FOUND_VAR} FALSE)
endif()
# print the result:
if (${_FOUND_VAR})
FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}")
else ()
if(FPHSA_CONFIG_MODE)
_FPHSA_HANDLE_FAILURE_CONFIG_MODE()
else()
if(NOT VERSION_OK)
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})")
else()
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing: ${MISSING_VARS}) ${VERSION_MSG}")
endif()
endif()
endif ()
set(${_FOUND_VAR} ${${_FOUND_VAR}} PARENT_SCOPE)
endfunction()

@ -0,0 +1,57 @@
#.rst:
# FindPackageMessage
# ------------------
#
#
#
# FIND_PACKAGE_MESSAGE(<name> "message for user" "find result details")
#
# This macro is intended to be used in FindXXX.cmake modules files. It
# will print a message once for each unique find result. This is useful
# for telling the user where a package was found. The first argument
# specifies the name (XXX) of the package. The second argument
# specifies the message to display. The third argument lists details
# about the find result so that if they change the message will be
# displayed again. The macro also obeys the QUIET argument to the
# find_package command.
#
# Example:
#
# ::
#
# if(X11_FOUND)
# FIND_PACKAGE_MESSAGE(X11 "Found X11: ${X11_X11_LIB}"
# "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]")
# else()
# ...
# endif()
#=============================================================================
# Copyright 2008-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
function(FIND_PACKAGE_MESSAGE pkg msg details)
# Avoid printing a message repeatedly for the same find result.
if(NOT ${pkg}_FIND_QUIETLY)
string(REPLACE "\n" "" details "${details}")
set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg})
if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}")
# The message has not yet been printed.
message(STATUS "${msg}")
# Save the find details in the cache to avoid printing the same
# message again.
set("${DETAILS_VAR}" "${details}"
CACHE INTERNAL "Details about finding ${pkg}")
endif()
endif()
endfunction()

@ -0,0 +1,13 @@
set(LIBRARY cryptopp)
include_directories(../../cryptopp)
# todo, subset
file(GLOB HEADERS "../../cryptopp/*.h")
file(GLOB SOURCE "../../cryptopp/*.cpp")
add_library(${LIBRARY} ${HEADERS} ${SOURCE})
set(CRYPTOPP_INCLUDE_DIRS "../.." PARENT_SCOPE)
set(CRYPTOPP_LIBRARIES ${LIBRARY} PARENT_SCOPE)
set(CRYPTOPP_FOUND TRUE PARENT_SCOPE)

@ -0,0 +1,351 @@
package ethash
/*
#cgo CFLAGS: -std=gnu99 -Wall
#include "src/libethash/util.c"
#include "src/libethash/internal.c"
#include "src/libethash/sha3.c"
*/
import "C"
import (
"bytes"
"encoding/binary"
"io/ioutil"
"log"
"math/big"
"math/rand"
"os"
"path"
"sync"
"time"
"unsafe"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/pow"
)
var tt256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
var powlogger = logger.NewLogger("POW")
type DAG struct {
SeedBlockNum uint64
dag unsafe.Pointer // full GB of memory for dag
file bool
}
type ParamsAndCache struct {
params *C.ethash_params
cache *C.ethash_cache
SeedBlockNum uint64
}
type Ethash struct {
turbo bool
HashRate int64
chainManager pow.ChainManager
dag *DAG
paramsAndCache *ParamsAndCache
nextdag unsafe.Pointer
ret *C.ethash_return_value
dagMutex *sync.Mutex
cacheMutex *sync.Mutex
}
func parseNonce(nonce []byte) (uint64, error) {
nonceBuf := bytes.NewBuffer(nonce)
nonceInt, err := binary.ReadUvarint(nonceBuf)
if err != nil {
return 0, err
}
return nonceInt, nil
}
const epochLength uint64 = 30000
func GetSeedBlockNum(blockNum uint64) uint64 {
var seedBlockNum uint64 = 0
if blockNum > epochLength {
seedBlockNum = ((blockNum - 1) / epochLength) * epochLength
}
return seedBlockNum
}
/*
XXX THIS DOESN'T WORK!! NEEDS FIXING
blockEpoch will underflow and wrap around causing massive issues
func GetSeedBlockNum(blockNum uint64) uint64 {
var seedBlockNum uint64 = 0
if blockNum > epochLength {
seedBlockNum = ((blockNum - 1) / epochLength) * epochLength
}
return seedBlockNum
}
*/
func makeParamsAndCache(chainManager pow.ChainManager, blockNum uint64) *ParamsAndCache {
seedBlockNum := GetSeedBlockNum(blockNum)
paramsAndCache := &ParamsAndCache{
params: new(C.ethash_params),
cache: new(C.ethash_cache),
SeedBlockNum: seedBlockNum,
}
C.ethash_params_init(paramsAndCache.params, C.uint32_t(seedBlockNum))
paramsAndCache.cache.mem = C.malloc(paramsAndCache.params.cache_size)
seedHash := chainManager.GetBlockByNumber(seedBlockNum).SeedHash()
log.Println("Making Cache")
start := time.Now()
C.ethash_mkcache(paramsAndCache.cache, paramsAndCache.params, (*C.uint8_t)(unsafe.Pointer(&seedHash[0])))
log.Println("Took:", time.Since(start))
return paramsAndCache
}
func (pow *Ethash) updateCache() {
pow.cacheMutex.Lock()
seedNum := GetSeedBlockNum(pow.chainManager.CurrentBlock().NumberU64())
if pow.paramsAndCache.SeedBlockNum != seedNum {
pow.paramsAndCache = makeParamsAndCache(pow.chainManager, pow.chainManager.CurrentBlock().NumberU64())
}
pow.cacheMutex.Unlock()
}
func makeDAG(p *ParamsAndCache) *DAG {
d := &DAG{
dag: C.malloc(p.params.full_size),
SeedBlockNum: p.SeedBlockNum,
}
C.ethash_compute_full_data(d.dag, p.params, p.cache)
return d
}
func (pow *Ethash) writeDagToDisk(dag *DAG, seedNum uint64) *os.File {
data := C.GoBytes(unsafe.Pointer(dag.dag), C.int(pow.paramsAndCache.params.full_size))
file, err := os.Create("/tmp/dag")
if err != nil {
panic(err)
}
num := make([]byte, 8)
binary.BigEndian.PutUint64(num, seedNum)
file.Write(num)
file.Write(data)
return file
}
func (pow *Ethash) UpdateDAG() {
pow.cacheMutex.Lock()
pow.dagMutex.Lock()
seedNum := GetSeedBlockNum(pow.chainManager.CurrentBlock().NumberU64())
if pow.dag == nil || pow.dag.SeedBlockNum != seedNum {
if pow.dag != nil && pow.dag.dag != nil {
C.free(pow.dag.dag)
pow.dag.dag = nil
}
path := path.Join("/", "tmp", "dag")
pow.dag = nil
log.Println("Generating dag")
start := time.Now()
file, err := os.Open(path)
if err != nil {
log.Printf("No dag found in '%s'. Generating new dago(takes a while)...", path)
pow.dag = makeDAG(pow.paramsAndCache)
file = pow.writeDagToDisk(pow.dag, seedNum)
} else {
data, err := ioutil.ReadAll(file)
if err != nil {
panic(err)
}
num := binary.BigEndian.Uint64(data[0:8])
if num < seedNum {
log.Printf("Old found. Generating new dag (takes a while)...")
pow.dag = makeDAG(pow.paramsAndCache)
file = pow.writeDagToDisk(pow.dag, seedNum)
} else {
data = data[8:]
pow.dag = &DAG{
dag: unsafe.Pointer(&data[0]),
file: true,
SeedBlockNum: pow.paramsAndCache.SeedBlockNum,
}
}
}
log.Println("Took:", time.Since(start))
file.Close()
}
pow.dagMutex.Unlock()
pow.cacheMutex.Unlock()
}
func New(chainManager pow.ChainManager) *Ethash {
return &Ethash{
turbo: true,
paramsAndCache: makeParamsAndCache(chainManager, chainManager.CurrentBlock().NumberU64()),
chainManager: chainManager,
dag: nil,
cacheMutex: new(sync.Mutex),
dagMutex: new(sync.Mutex),
}
}
func (pow *Ethash) DAGSize() uint64 {
return uint64(pow.paramsAndCache.params.full_size)
}
func (pow *Ethash) CacheSize() uint64 {
return uint64(pow.paramsAndCache.params.cache_size)
}
func (pow *Ethash) GetSeedHash(blockNum uint64) []byte {
seednum := GetSeedBlockNum(blockNum)
return pow.chainManager.GetBlockByNumber(seednum).SeedHash()
}
func (pow *Ethash) Stop() {
pow.cacheMutex.Lock()
pow.dagMutex.Lock()
defer pow.dagMutex.Unlock()
defer pow.cacheMutex.Unlock()
if pow.paramsAndCache.cache != nil {
C.free(pow.paramsAndCache.cache.mem)
}
if pow.dag.dag != nil && !pow.dag.file {
C.free(pow.dag.dag)
}
pow.dag.dag = nil
}
func (pow *Ethash) Search(block pow.Block, stop <-chan struct{}) (uint64, []byte, []byte) {
//pow.UpdateDAG()
// Not very elegant, multiple mining instances are not supported
//pow.dagMutex.Lock()
//pow.cacheMutex.Lock()
//defer pow.cacheMutex.Unlock()
//defer pow.dagMutex.Unlock()
r := rand.New(rand.NewSource(time.Now().UnixNano()))
miningHash := block.HashNoNonce()
diff := block.Difficulty()
i := int64(0)
starti := i
start := time.Now().UnixNano()
nonce := uint64(r.Int63())
cMiningHash := (*C.uint8_t)(unsafe.Pointer(&miningHash[0]))
target := new(big.Int).Div(tt256, diff)
var ret C.ethash_return_value
for {
select {
case <-stop:
powlogger.Infoln("Breaking from mining")
pow.HashRate = 0
return 0, nil, nil
default:
i++
elapsed := time.Now().UnixNano() - start
hashes := ((float64(1e9) / float64(elapsed)) * float64(i-starti)) / 1000
pow.HashRate = int64(hashes)
C.ethash_full(&ret, pow.dag.dag, pow.paramsAndCache.params, cMiningHash, C.uint64_t(nonce))
result := ethutil.Bytes2Big(C.GoBytes(unsafe.Pointer(&ret.result[0]), C.int(32)))
if result.Cmp(target) <= 0 {
mixDigest := C.GoBytes(unsafe.Pointer(&ret.mix_hash[0]), C.int(32))
return nonce, mixDigest, pow.GetSeedHash(block.NumberU64())
}
nonce += 1
}
if !pow.turbo {
time.Sleep(20 * time.Microsecond)
}
}
}
func (pow *Ethash) Verify(block pow.Block) bool {
// Make sure the SeedHash is set correctly
if bytes.Compare(block.SeedHash(), pow.GetSeedHash(block.NumberU64())) != 0 {
return false
}
return pow.verify(block.HashNoNonce(), block.MixDigest(), block.Difficulty(), block.NumberU64(), block.Nonce())
}
func (pow *Ethash) verify(hash []byte, mixDigest []byte, difficulty *big.Int, blockNum uint64, nonce uint64) bool {
// First check: make sure header, mixDigest, nonce are correct without hitting the DAG
// This is to prevent DOS attacks
chash := (*C.uint8_t)(unsafe.Pointer(&hash[0]))
cnonce := C.uint64_t(nonce)
target := new(big.Int).Div(tt256, difficulty)
var pAc *ParamsAndCache
// If its an old block (doesn't use the current cache)
// get the cache for it but don't update (so we don't need the mutex)
// Otherwise, it's the current block or a future.
// If current, updateCache will do nothing.
if GetSeedBlockNum(blockNum) < pow.paramsAndCache.SeedBlockNum {
pAc = makeParamsAndCache(pow.chainManager, blockNum)
} else {
pow.updateCache()
pow.cacheMutex.Lock()
defer pow.cacheMutex.Unlock()
pAc = pow.paramsAndCache
}
ret := new(C.ethash_return_value)
C.ethash_light(ret, pAc.cache, pAc.params, chash, cnonce)
result := ethutil.Bytes2Big(C.GoBytes(unsafe.Pointer(&ret.result[0]), C.int(32)))
return result.Cmp(target) <= 0
}
func (pow *Ethash) GetHashrate() int64 {
return pow.HashRate
}
func (pow *Ethash) Turbo(on bool) {
pow.turbo = on
}
func (pow *Ethash) FullHash(nonce uint64, miningHash []byte) []byte {
pow.UpdateDAG()
pow.dagMutex.Lock()
defer pow.dagMutex.Unlock()
cMiningHash := (*C.uint8_t)(unsafe.Pointer(&miningHash[0]))
cnonce := C.uint64_t(nonce)
ret := new(C.ethash_return_value)
// pow.hash is the output/return of ethash_full
C.ethash_full(ret, pow.dag.dag, pow.paramsAndCache.params, cMiningHash, cnonce)
ghash_full := C.GoBytes(unsafe.Pointer(&ret.result), 32)
return ghash_full
}
func (pow *Ethash) LightHash(nonce uint64, miningHash []byte) []byte {
cMiningHash := (*C.uint8_t)(unsafe.Pointer(&miningHash[0]))
cnonce := C.uint64_t(nonce)
ret := new(C.ethash_return_value)
C.ethash_light(ret, pow.paramsAndCache.cache, pow.paramsAndCache.params, cMiningHash, cnonce)
ghash_light := C.GoBytes(unsafe.Pointer(&ret.result), 32)
return ghash_light
}

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Tim Hughes
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,190 @@
// ethash.js
// Tim Hughes <tim@twistedfury.com>
// Revision 19
/*jslint node: true, shadow:true */
"use strict";
var Keccak = require('./keccak');
var util = require('./util');
// 32-bit unsigned modulo
function mod32(x, n)
{
return (x>>>0) % (n>>>0);
}
function fnv(x, y)
{
// js integer multiply by 0x01000193 will lose precision
return ((x*0x01000000 | 0) + (x*0x193 | 0)) ^ y;
}
function computeCache(params, seedWords)
{
var cache = new Uint32Array(params.cacheSize >> 2);
var cacheNodeCount = params.cacheSize >> 6;
// Initialize cache
var keccak = new Keccak();
keccak.digestWords(cache, 0, 16, seedWords, 0, seedWords.length);
for (var n = 1; n < cacheNodeCount; ++n)
{
keccak.digestWords(cache, n<<4, 16, cache, (n-1)<<4, 16);
}
var tmp = new Uint32Array(16);
// Do randmemohash passes
for (var r = 0; r < params.cacheRounds; ++r)
{
for (var n = 0; n < cacheNodeCount; ++n)
{
var p0 = mod32(n + cacheNodeCount - 1, cacheNodeCount) << 4;
var p1 = mod32(cache[n<<4|0], cacheNodeCount) << 4;
for (var w = 0; w < 16; w=(w+1)|0)
{
tmp[w] = cache[p0 | w] ^ cache[p1 | w];
}
keccak.digestWords(cache, n<<4, 16, tmp, 0, tmp.length);
}
}
return cache;
}
function computeDagNode(o_node, params, cache, keccak, nodeIndex)
{
var cacheNodeCount = params.cacheSize >> 6;
var dagParents = params.dagParents;
var c = (nodeIndex % cacheNodeCount) << 4;
var mix = o_node;
for (var w = 0; w < 16; ++w)
{
mix[w] = cache[c|w];
}
mix[0] ^= nodeIndex;
keccak.digestWords(mix, 0, 16, mix, 0, 16);
for (var p = 0; p < dagParents; ++p)
{
// compute cache node (word) index
c = mod32(fnv(nodeIndex ^ p, mix[p&15]), cacheNodeCount) << 4;
for (var w = 0; w < 16; ++w)
{
mix[w] = fnv(mix[w], cache[c|w]);
}
}
keccak.digestWords(mix, 0, 16, mix, 0, 16);
}
function computeHashInner(mix, params, cache, keccak, tempNode)
{
var mixParents = params.mixParents|0;
var mixWordCount = params.mixSize >> 2;
var mixNodeCount = mixWordCount >> 4;
var dagPageCount = (params.dagSize / params.mixSize) >> 0;
// grab initial first word
var s0 = mix[0];
// initialise mix from initial 64 bytes
for (var w = 16; w < mixWordCount; ++w)
{
mix[w] = mix[w & 15];
}
for (var a = 0; a < mixParents; ++a)
{
var p = mod32(fnv(s0 ^ a, mix[a & (mixWordCount-1)]), dagPageCount);
var d = (p * mixNodeCount)|0;
for (var n = 0, w = 0; n < mixNodeCount; ++n, w += 16)
{
computeDagNode(tempNode, params, cache, keccak, (d + n)|0);
for (var v = 0; v < 16; ++v)
{
mix[w|v] = fnv(mix[w|v], tempNode[v]);
}
}
}
}
function convertSeed(seed)
{
// todo, reconcile with spec, byte ordering?
// todo, big-endian conversion
var newSeed = util.toWords(seed);
if (newSeed === null)
throw Error("Invalid seed '" + seed + "'");
return newSeed;
}
exports.defaultParams = function()
{
return {
cacheSize: 1048384,
cacheRounds: 3,
dagSize: 1073739904,
dagParents: 256,
mixSize: 128,
mixParents: 64,
};
};
exports.Ethash = function(params, seed)
{
// precompute cache and related values
seed = convertSeed(seed);
var cache = computeCache(params, seed);
// preallocate buffers/etc
var initBuf = new ArrayBuffer(96);
var initBytes = new Uint8Array(initBuf);
var initWords = new Uint32Array(initBuf);
var mixWords = new Uint32Array(params.mixSize / 4);
var tempNode = new Uint32Array(16);
var keccak = new Keccak();
var retWords = new Uint32Array(8);
var retBytes = new Uint8Array(retWords.buffer); // supposedly read-only
this.hash = function(header, nonce)
{
// compute initial hash
initBytes.set(header, 0);
initBytes.set(nonce, 32);
keccak.digestWords(initWords, 0, 16, initWords, 0, 8 + nonce.length/4);
// compute mix
for (var i = 0; i != 16; ++i)
{
mixWords[i] = initWords[i];
}
computeHashInner(mixWords, params, cache, keccak, tempNode);
// compress mix and append to initWords
for (var i = 0; i != mixWords.length; i += 4)
{
initWords[16 + i/4] = fnv(fnv(fnv(mixWords[i], mixWords[i+1]), mixWords[i+2]), mixWords[i+3]);
}
// final Keccak hashes
keccak.digestWords(retWords, 0, 8, initWords, 0, 24); // Keccak-256(s + cmix)
return retBytes;
};
this.cacheDigest = function()
{
return keccak.digest(32, new Uint8Array(cache.buffer));
};
};

@ -0,0 +1,404 @@
// keccak.js
// Tim Hughes <tim@twistedfury.com>
// derived from Markku-Juhani O. Saarinen's C code (http://keccak.noekeon.org/readable_code.html)
/*jslint node: true, shadow:true */
"use strict";
var Keccak_f1600_RC = new Uint32Array([
0x00000001, 0x00000000,
0x00008082, 0x00000000,
0x0000808a, 0x80000000,
0x80008000, 0x80000000,
0x0000808b, 0x00000000,
0x80000001, 0x00000000,
0x80008081, 0x80000000,
0x00008009, 0x80000000,
0x0000008a, 0x00000000,
0x00000088, 0x00000000,
0x80008009, 0x00000000,
0x8000000a, 0x00000000,
0x8000808b, 0x00000000,
0x0000008b, 0x80000000,
0x00008089, 0x80000000,
0x00008003, 0x80000000,
0x00008002, 0x80000000,
0x00000080, 0x80000000,
0x0000800a, 0x00000000,
0x8000000a, 0x80000000,
0x80008081, 0x80000000,
0x00008080, 0x80000000,
0x80000001, 0x00000000,
0x80008008, 0x80000000
]);
function keccak_f1600(outState, outOffset, outSize, inState)
{
// todo, handle big endian loads
var a00l = inState[0]|0;
var a00h = inState[1]|0;
var a01l = inState[2]|0;
var a01h = inState[3]|0;
var a02l = inState[4]|0;
var a02h = inState[5]|0;
var a03l = inState[6]|0;
var a03h = inState[7]|0;
var a04l = inState[8]|0;
var a04h = inState[9]|0;
var a05l = inState[10]|0;
var a05h = inState[11]|0;
var a06l = inState[12]|0;
var a06h = inState[13]|0;
var a07l = inState[14]|0;
var a07h = inState[15]|0;
var a08l = inState[16]|0;
var a08h = inState[17]|0;
var a09l = inState[18]|0;
var a09h = inState[19]|0;
var a10l = inState[20]|0;
var a10h = inState[21]|0;
var a11l = inState[22]|0;
var a11h = inState[23]|0;
var a12l = inState[24]|0;
var a12h = inState[25]|0;
var a13l = inState[26]|0;
var a13h = inState[27]|0;
var a14l = inState[28]|0;
var a14h = inState[29]|0;
var a15l = inState[30]|0;
var a15h = inState[31]|0;
var a16l = inState[32]|0;
var a16h = inState[33]|0;
var a17l = inState[34]|0;
var a17h = inState[35]|0;
var a18l = inState[36]|0;
var a18h = inState[37]|0;
var a19l = inState[38]|0;
var a19h = inState[39]|0;
var a20l = inState[40]|0;
var a20h = inState[41]|0;
var a21l = inState[42]|0;
var a21h = inState[43]|0;
var a22l = inState[44]|0;
var a22h = inState[45]|0;
var a23l = inState[46]|0;
var a23h = inState[47]|0;
var a24l = inState[48]|0;
var a24h = inState[49]|0;
var b00l, b00h, b01l, b01h, b02l, b02h, b03l, b03h, b04l, b04h;
var b05l, b05h, b06l, b06h, b07l, b07h, b08l, b08h, b09l, b09h;
var b10l, b10h, b11l, b11h, b12l, b12h, b13l, b13h, b14l, b14h;
var b15l, b15h, b16l, b16h, b17l, b17h, b18l, b18h, b19l, b19h;
var b20l, b20h, b21l, b21h, b22l, b22h, b23l, b23h, b24l, b24h;
var tl, nl;
var th, nh;
for (var r = 0; r < 48; r = (r+2)|0)
{
// Theta
b00l = a00l ^ a05l ^ a10l ^ a15l ^ a20l;
b00h = a00h ^ a05h ^ a10h ^ a15h ^ a20h;
b01l = a01l ^ a06l ^ a11l ^ a16l ^ a21l;
b01h = a01h ^ a06h ^ a11h ^ a16h ^ a21h;
b02l = a02l ^ a07l ^ a12l ^ a17l ^ a22l;
b02h = a02h ^ a07h ^ a12h ^ a17h ^ a22h;
b03l = a03l ^ a08l ^ a13l ^ a18l ^ a23l;
b03h = a03h ^ a08h ^ a13h ^ a18h ^ a23h;
b04l = a04l ^ a09l ^ a14l ^ a19l ^ a24l;
b04h = a04h ^ a09h ^ a14h ^ a19h ^ a24h;
tl = b04l ^ (b01l << 1 | b01h >>> 31);
th = b04h ^ (b01h << 1 | b01l >>> 31);
a00l ^= tl;
a00h ^= th;
a05l ^= tl;
a05h ^= th;
a10l ^= tl;
a10h ^= th;
a15l ^= tl;
a15h ^= th;
a20l ^= tl;
a20h ^= th;
tl = b00l ^ (b02l << 1 | b02h >>> 31);
th = b00h ^ (b02h << 1 | b02l >>> 31);
a01l ^= tl;
a01h ^= th;
a06l ^= tl;
a06h ^= th;
a11l ^= tl;
a11h ^= th;
a16l ^= tl;
a16h ^= th;
a21l ^= tl;
a21h ^= th;
tl = b01l ^ (b03l << 1 | b03h >>> 31);
th = b01h ^ (b03h << 1 | b03l >>> 31);
a02l ^= tl;
a02h ^= th;
a07l ^= tl;
a07h ^= th;
a12l ^= tl;
a12h ^= th;
a17l ^= tl;
a17h ^= th;
a22l ^= tl;
a22h ^= th;
tl = b02l ^ (b04l << 1 | b04h >>> 31);
th = b02h ^ (b04h << 1 | b04l >>> 31);
a03l ^= tl;
a03h ^= th;
a08l ^= tl;
a08h ^= th;
a13l ^= tl;
a13h ^= th;
a18l ^= tl;
a18h ^= th;
a23l ^= tl;
a23h ^= th;
tl = b03l ^ (b00l << 1 | b00h >>> 31);
th = b03h ^ (b00h << 1 | b00l >>> 31);
a04l ^= tl;
a04h ^= th;
a09l ^= tl;
a09h ^= th;
a14l ^= tl;
a14h ^= th;
a19l ^= tl;
a19h ^= th;
a24l ^= tl;
a24h ^= th;
// Rho Pi
b00l = a00l;
b00h = a00h;
b10l = a01l << 1 | a01h >>> 31;
b10h = a01h << 1 | a01l >>> 31;
b07l = a10l << 3 | a10h >>> 29;
b07h = a10h << 3 | a10l >>> 29;
b11l = a07l << 6 | a07h >>> 26;
b11h = a07h << 6 | a07l >>> 26;
b17l = a11l << 10 | a11h >>> 22;
b17h = a11h << 10 | a11l >>> 22;
b18l = a17l << 15 | a17h >>> 17;
b18h = a17h << 15 | a17l >>> 17;
b03l = a18l << 21 | a18h >>> 11;
b03h = a18h << 21 | a18l >>> 11;
b05l = a03l << 28 | a03h >>> 4;
b05h = a03h << 28 | a03l >>> 4;
b16l = a05h << 4 | a05l >>> 28;
b16h = a05l << 4 | a05h >>> 28;
b08l = a16h << 13 | a16l >>> 19;
b08h = a16l << 13 | a16h >>> 19;
b21l = a08h << 23 | a08l >>> 9;
b21h = a08l << 23 | a08h >>> 9;
b24l = a21l << 2 | a21h >>> 30;
b24h = a21h << 2 | a21l >>> 30;
b04l = a24l << 14 | a24h >>> 18;
b04h = a24h << 14 | a24l >>> 18;
b15l = a04l << 27 | a04h >>> 5;
b15h = a04h << 27 | a04l >>> 5;
b23l = a15h << 9 | a15l >>> 23;
b23h = a15l << 9 | a15h >>> 23;
b19l = a23h << 24 | a23l >>> 8;
b19h = a23l << 24 | a23h >>> 8;
b13l = a19l << 8 | a19h >>> 24;
b13h = a19h << 8 | a19l >>> 24;
b12l = a13l << 25 | a13h >>> 7;
b12h = a13h << 25 | a13l >>> 7;
b02l = a12h << 11 | a12l >>> 21;
b02h = a12l << 11 | a12h >>> 21;
b20l = a02h << 30 | a02l >>> 2;
b20h = a02l << 30 | a02h >>> 2;
b14l = a20l << 18 | a20h >>> 14;
b14h = a20h << 18 | a20l >>> 14;
b22l = a14h << 7 | a14l >>> 25;
b22h = a14l << 7 | a14h >>> 25;
b09l = a22h << 29 | a22l >>> 3;
b09h = a22l << 29 | a22h >>> 3;
b06l = a09l << 20 | a09h >>> 12;
b06h = a09h << 20 | a09l >>> 12;
b01l = a06h << 12 | a06l >>> 20;
b01h = a06l << 12 | a06h >>> 20;
// Chi
a00l = b00l ^ ~b01l & b02l;
a00h = b00h ^ ~b01h & b02h;
a01l = b01l ^ ~b02l & b03l;
a01h = b01h ^ ~b02h & b03h;
a02l = b02l ^ ~b03l & b04l;
a02h = b02h ^ ~b03h & b04h;
a03l = b03l ^ ~b04l & b00l;
a03h = b03h ^ ~b04h & b00h;
a04l = b04l ^ ~b00l & b01l;
a04h = b04h ^ ~b00h & b01h;
a05l = b05l ^ ~b06l & b07l;
a05h = b05h ^ ~b06h & b07h;
a06l = b06l ^ ~b07l & b08l;
a06h = b06h ^ ~b07h & b08h;
a07l = b07l ^ ~b08l & b09l;
a07h = b07h ^ ~b08h & b09h;
a08l = b08l ^ ~b09l & b05l;
a08h = b08h ^ ~b09h & b05h;
a09l = b09l ^ ~b05l & b06l;
a09h = b09h ^ ~b05h & b06h;
a10l = b10l ^ ~b11l & b12l;
a10h = b10h ^ ~b11h & b12h;
a11l = b11l ^ ~b12l & b13l;
a11h = b11h ^ ~b12h & b13h;
a12l = b12l ^ ~b13l & b14l;
a12h = b12h ^ ~b13h & b14h;
a13l = b13l ^ ~b14l & b10l;
a13h = b13h ^ ~b14h & b10h;
a14l = b14l ^ ~b10l & b11l;
a14h = b14h ^ ~b10h & b11h;
a15l = b15l ^ ~b16l & b17l;
a15h = b15h ^ ~b16h & b17h;
a16l = b16l ^ ~b17l & b18l;
a16h = b16h ^ ~b17h & b18h;
a17l = b17l ^ ~b18l & b19l;
a17h = b17h ^ ~b18h & b19h;
a18l = b18l ^ ~b19l & b15l;
a18h = b18h ^ ~b19h & b15h;
a19l = b19l ^ ~b15l & b16l;
a19h = b19h ^ ~b15h & b16h;
a20l = b20l ^ ~b21l & b22l;
a20h = b20h ^ ~b21h & b22h;
a21l = b21l ^ ~b22l & b23l;
a21h = b21h ^ ~b22h & b23h;
a22l = b22l ^ ~b23l & b24l;
a22h = b22h ^ ~b23h & b24h;
a23l = b23l ^ ~b24l & b20l;
a23h = b23h ^ ~b24h & b20h;
a24l = b24l ^ ~b20l & b21l;
a24h = b24h ^ ~b20h & b21h;
// Iota
a00l ^= Keccak_f1600_RC[r|0];
a00h ^= Keccak_f1600_RC[r|1];
}
// todo, handle big-endian stores
outState[outOffset|0] = a00l;
outState[outOffset|1] = a00h;
outState[outOffset|2] = a01l;
outState[outOffset|3] = a01h;
outState[outOffset|4] = a02l;
outState[outOffset|5] = a02h;
outState[outOffset|6] = a03l;
outState[outOffset|7] = a03h;
if (outSize == 8)
return;
outState[outOffset|8] = a04l;
outState[outOffset|9] = a04h;
outState[outOffset|10] = a05l;
outState[outOffset|11] = a05h;
outState[outOffset|12] = a06l;
outState[outOffset|13] = a06h;
outState[outOffset|14] = a07l;
outState[outOffset|15] = a07h;
if (outSize == 16)
return;
outState[outOffset|16] = a08l;
outState[outOffset|17] = a08h;
outState[outOffset|18] = a09l;
outState[outOffset|19] = a09h;
outState[outOffset|20] = a10l;
outState[outOffset|21] = a10h;
outState[outOffset|22] = a11l;
outState[outOffset|23] = a11h;
outState[outOffset|24] = a12l;
outState[outOffset|25] = a12h;
outState[outOffset|26] = a13l;
outState[outOffset|27] = a13h;
outState[outOffset|28] = a14l;
outState[outOffset|29] = a14h;
outState[outOffset|30] = a15l;
outState[outOffset|31] = a15h;
outState[outOffset|32] = a16l;
outState[outOffset|33] = a16h;
outState[outOffset|34] = a17l;
outState[outOffset|35] = a17h;
outState[outOffset|36] = a18l;
outState[outOffset|37] = a18h;
outState[outOffset|38] = a19l;
outState[outOffset|39] = a19h;
outState[outOffset|40] = a20l;
outState[outOffset|41] = a20h;
outState[outOffset|42] = a21l;
outState[outOffset|43] = a21h;
outState[outOffset|44] = a22l;
outState[outOffset|45] = a22h;
outState[outOffset|46] = a23l;
outState[outOffset|47] = a23h;
outState[outOffset|48] = a24l;
outState[outOffset|49] = a24h;
}
var Keccak = function()
{
var stateBuf = new ArrayBuffer(200);
var stateBytes = new Uint8Array(stateBuf);
var stateWords = new Uint32Array(stateBuf);
this.digest = function(oSize, iBytes)
{
for (var i = 0; i < 50; ++i)
{
stateWords[i] = 0;
}
var r = 200 - oSize*2;
var iLength = iBytes.length;
var iOffset = 0;
for ( ; ;)
{
var len = iLength < r ? iLength : r;
for (i = 0; i < len; ++i, ++iOffset)
{
stateBytes[i] ^= iBytes[iOffset];
}
if (iLength < r)
break;
iLength -= len;
keccak_f1600(stateWords, 0, 50, stateWords);
}
stateBytes[iLength] ^= 1;
stateBytes[r-1] ^= 0x80;
keccak_f1600(stateWords, 0, 50, stateWords);
return stateBytes.subarray(0, oSize);
};
this.digestWords = function(oWords, oOffset, oLength, iWords, iOffset, iLength)
{
for (var i = 0; i < 50; ++i)
{
stateWords[i] = 0;
}
var r = 50 - oLength*2;
for (; ; )
{
var len = iLength < r ? iLength : r;
for (i = 0; i < len; ++i, ++iOffset)
{
stateWords[i] ^= iWords[iOffset];
}
if (iLength < r)
break;
iLength -= len;
keccak_f1600(stateWords, 0, 50, stateWords);
}
stateBytes[iLength<<2] ^= 1;
stateBytes[(r<<2) - 1] ^= 0x80;
keccak_f1600(oWords, oOffset, oLength, stateWords);
};
};
module.exports = Keccak;

@ -0,0 +1,201 @@
#!/usr/bin/env node
// makekeccak.js
// Tim Hughes <tim@twistedfury.com>
/*jslint node: true, shadow:true */
"use strict";
var Keccak_f1600_Rho = [
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44
];
var Keccak_f1600_Pi= [
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1
];
var Keccak_f1600_RC = [
0x00000001, 0x00000000,
0x00008082, 0x00000000,
0x0000808a, 0x80000000,
0x80008000, 0x80000000,
0x0000808b, 0x00000000,
0x80000001, 0x00000000,
0x80008081, 0x80000000,
0x00008009, 0x80000000,
0x0000008a, 0x00000000,
0x00000088, 0x00000000,
0x80008009, 0x00000000,
0x8000000a, 0x00000000,
0x8000808b, 0x00000000,
0x0000008b, 0x80000000,
0x00008089, 0x80000000,
0x00008003, 0x80000000,
0x00008002, 0x80000000,
0x00000080, 0x80000000,
0x0000800a, 0x00000000,
0x8000000a, 0x80000000,
0x80008081, 0x80000000,
0x00008080, 0x80000000,
0x80000001, 0x00000000,
0x80008008, 0x80000000,
];
function makeRotLow(lo, hi, n)
{
if (n === 0 || n === 32) throw Error("unsupported");
if ((n & 0x20) !== 0)
{
n &= ~0x20;
var t = hi;
hi = lo;
lo = t;
}
var hir = hi + " >>> " + (32 - n);
var los = lo + " << " + n;
return los + " | " + hir;
}
function makeRotHigh(lo, hi, n)
{
if (n === 0 || n === 32) throw Error("unsupported");
if ((n & 0x20) !== 0)
{
n &= ~0x20;
var t = hi;
hi = lo;
lo = t;
}
var his = hi + " << " + n;
var lor = lo + " >>> " + (32 - n);
return his + " | " + lor;
}
function makeKeccak_f1600()
{
var format = function(n)
{
return n < 10 ? "0"+n : ""+n;
};
var a = function(n, w)
{
return "a" + format(n) + (w !== 0?'h':'l');
};
var b = function(n, w)
{
return "b" + format(n) + (w !== 0?'h':'l');
};
var str = "";
str += "function keccak_f1600(outState, outOffset, outSize, inState)\n";
str += "{\n";
for (var i = 0; i < 25; ++i)
{
for (var w = 0; w <= 1; ++w)
{
str += "\tvar " + a(i,w) + " = inState["+(i<<1|w)+"]|0;\n";
}
}
for (var j = 0; j < 5; ++j)
{
str += "\tvar ";
for (var i = 0; i < 5; ++i)
{
if (i !== 0)
str += ", ";
str += b(j*5+i,0) + ", " + b(j*5+i,1);
}
str += ";\n";
}
str += "\tvar tl, th;\n";
str += "\n";
str += "\tfor (var r = 0; r < 48; r = (r+2)|0)\n";
str += "\t{\n";
// Theta
str += "\t\t// Theta\n";
for (var i = 0; i < 5; ++i)
{
for (var w = 0; w <= 1; ++w)
{
str += "\t\t" + b(i,w) + " = " + a(i,w) + " ^ " + a(i+5,w) + " ^ " + a(i+10,w) + " ^ " + a(i+15,w) + " ^ " + a(i+20,w) + ";\n";
}
}
for (var i = 0; i < 5; ++i)
{
var i4 = (i + 4) % 5;
var i1 = (i + 1) % 5;
str += "\t\ttl = " + b(i4,0) + " ^ (" + b(i1,0) + " << 1 | " + b(i1,1) + " >>> 31);\n";
str += "\t\tth = " + b(i4,1) + " ^ (" + b(i1,1) + " << 1 | " + b(i1,0) + " >>> 31);\n";
for (var j = 0; j < 25; j = (j+5)|0)
{
str += "\t\t" + a((j+i),0) + " ^= tl;\n";
str += "\t\t" + a((j+i),1) + " ^= th;\n";
}
}
// Rho Pi
str += "\n\t\t// Rho Pi\n";
for (var w = 0; w <= 1; ++w)
{
str += "\t\t" + b(0,w) + " = " + a(0,w) + ";\n";
}
var opi = 1;
for (var i = 0; i < 24; ++i)
{
var pi = Keccak_f1600_Pi[i];
str += "\t\t" + b(pi,0) + " = " + makeRotLow(a(opi,0), a(opi,1), Keccak_f1600_Rho[i]) + ";\n";
str += "\t\t" + b(pi,1) + " = " + makeRotHigh(a(opi,0), a(opi,1), Keccak_f1600_Rho[i]) + ";\n";
opi = pi;
}
// Chi
str += "\n\t\t// Chi\n";
for (var j = 0; j < 25; j += 5)
{
for (var i = 0; i < 5; ++i)
{
for (var w = 0; w <= 1; ++w)
{
str += "\t\t" + a(j+i,w) + " = " + b(j+i,w) + " ^ ~" + b(j+(i+1)%5,w) + " & " + b(j+(i+2)%5,w) + ";\n";
}
}
}
// Iota
str += "\n\t\t// Iota\n";
for (var w = 0; w <= 1; ++w)
{
str += "\t\t" + a(0,w) + " ^= Keccak_f1600_RC[r|" + w + "];\n";
}
str += "\t}\n";
for (var i = 0; i < 25; ++i)
{
if (i == 4 || i == 8)
{
str += "\tif (outSize == " + i*2 + ")\n\t\treturn;\n";
}
for (var w = 0; w <= 1; ++w)
{
str += "\toutState[outOffset|"+(i<<1|w)+"] = " + a(i,w) + ";\n";
}
}
str += "}\n";
return str;
}
console.log(makeKeccak_f1600());

@ -0,0 +1,53 @@
// test.js
// Tim Hughes <tim@twistedfury.com>
/*jslint node: true, shadow:true */
"use strict";
var ethash = require('./ethash');
var util = require('./util');
var Keccak = require('./keccak');
// sanity check hash functions
var src = util.stringToBytes("");
if (util.bytesToHexString(new Keccak().digest(32, src)) != "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") throw Error("Keccak-256 failed");
if (util.bytesToHexString(new Keccak().digest(64, src)) != "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e") throw Error("Keccak-512 failed");
src = new Uint32Array(src.buffer);
var dst = new Uint32Array(8);
new Keccak().digestWords(dst, 0, dst.length, src, 0, src.length);
if (util.wordsToHexString(dst) != "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") throw Error("Keccak-256 Fast failed");
var dst = new Uint32Array(16);
new Keccak().digestWords(dst, 0, dst.length, src, 0, src.length);
if (util.wordsToHexString(dst) != "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e") throw Error("Keccak-512 Fast failed");
// init params
var ethashParams = ethash.defaultParams();
//ethashParams.cacheRounds = 0;
// create hasher
var seed = util.hexStringToBytes("9410b944535a83d9adf6bbdcc80e051f30676173c16ca0d32d6f1263fc246466")
var startTime = new Date().getTime();
var hasher = new ethash.Ethash(ethashParams, seed);
console.log('Ethash startup took: '+(new Date().getTime() - startTime) + "ms");
console.log('Ethash cache hash: ' + util.bytesToHexString(hasher.cacheDigest()));
var testHexString = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470";
if (testHexString != util.bytesToHexString(util.hexStringToBytes(testHexString)))
throw Error("bytesToHexString or hexStringToBytes broken");
var header = util.hexStringToBytes("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
var nonce = util.hexStringToBytes("0000000000000000");
var hash;
startTime = new Date().getTime();
var trials = 10;
for (var i = 0; i < trials; ++i)
{
hash = hasher.hash(header, nonce);
}
console.log("Light client hashes averaged: " + (new Date().getTime() - startTime)/trials + "ms");
console.log("Hash = " + util.bytesToHexString(hash));

@ -0,0 +1,100 @@
// util.js
// Tim Hughes <tim@twistedfury.com>
/*jslint node: true, shadow:true */
"use strict";
function nibbleToChar(nibble)
{
return String.fromCharCode((nibble < 10 ? 48 : 87) + nibble);
}
function charToNibble(chr)
{
if (chr >= 48 && chr <= 57)
{
return chr - 48;
}
if (chr >= 65 && chr <= 70)
{
return chr - 65 + 10;
}
if (chr >= 97 && chr <= 102)
{
return chr - 97 + 10;
}
return 0;
}
function stringToBytes(str)
{
var bytes = new Uint8Array(str.length);
for (var i = 0; i != str.length; ++i)
{
bytes[i] = str.charCodeAt(i);
}
return bytes;
}
function hexStringToBytes(str)
{
var bytes = new Uint8Array(str.length>>>1);
for (var i = 0; i != bytes.length; ++i)
{
bytes[i] = charToNibble(str.charCodeAt(i<<1 | 0)) << 4;
bytes[i] |= charToNibble(str.charCodeAt(i<<1 | 1));
}
return bytes;
}
function bytesToHexString(bytes)
{
var str = "";
for (var i = 0; i != bytes.length; ++i)
{
str += nibbleToChar(bytes[i] >>> 4);
str += nibbleToChar(bytes[i] & 0xf);
}
return str;
}
function wordsToHexString(words)
{
return bytesToHexString(new Uint8Array(words.buffer));
}
function uint32ToHexString(num)
{
var buf = new Uint8Array(4);
buf[0] = (num >> 24) & 0xff;
buf[1] = (num >> 16) & 0xff;
buf[2] = (num >> 8) & 0xff;
buf[3] = (num >> 0) & 0xff;
return bytesToHexString(buf);
}
function toWords(input)
{
if (input instanceof Uint32Array)
{
return input;
}
else if (input instanceof Uint8Array)
{
var tmp = new Uint8Array((input.length + 3) & ~3);
tmp.set(input);
return new Uint32Array(tmp.buffer);
}
else if (typeof input === typeof "")
{
return toWords(stringToBytes(input));
}
return null;
}
exports.stringToBytes = stringToBytes;
exports.hexStringToBytes = hexStringToBytes;
exports.bytesToHexString = bytesToHexString;
exports.wordsToHexString = wordsToHexString;
exports.uint32ToHexString = uint32ToHexString;
exports.toWords = toWords;

@ -0,0 +1,2 @@
pyethash.egg-info/
*.so

@ -0,0 +1,3 @@
import pyethash.core
core = pyethash.core
EPOCH_LENGTH = 30000

@ -0,0 +1,21 @@
#!/usr/bin/env python
from distutils.core import setup, Extension
pyethash_core = Extension('pyethash.core',
sources = [
'src/python/core.c',
'src/libethash/util.c',
'src/libethash/internal.c',
'src/libethash/sha3.c'
],
extra_compile_args = ["-std=gnu99"])
setup (
name = 'pyethash',
author = "Matthew Wampler-Doty",
author_email = "matthew.wampler.doty@gmail.com",
license = 'GPL',
version = '1.0',
description = 'Python wrappers for ethash, the ethereum proof of work hashing function',
ext_modules = [pyethash_core],
)

@ -0,0 +1,53 @@
include_directories(..)
set(CMAKE_BUILD_TYPE Release)
if (MSVC)
add_definitions("/openmp")
endif()
if (NOT MPI_FOUND)
find_package(MPI)
endif()
if (NOT CRYPTOPP_FOUND)
find_package(CryptoPP 5.6.2)
endif()
if (CRYPTOPP_FOUND)
add_definitions(-DWITH_CRYPTOPP)
endif()
if (NOT OpenCL_FOUND)
find_package(OpenCL)
endif()
if (OpenCL_FOUND)
add_definitions(-DWITH_OPENCL)
include_directories(${OpenCL_INCLUDE_DIRS})
list(APPEND FILES ethash_cl_miner.cpp ethash_cl_miner.h)
endif()
if (MPI_FOUND)
include_directories(${MPI_INCLUDE_PATH})
add_executable (Benchmark_MPI_FULL benchmark.cpp)
target_link_libraries (Benchmark_MPI_FULL ${ETHHASH_LIBS} ${MPI_LIBRARIES})
SET_TARGET_PROPERTIES(Benchmark_MPI_FULL PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} ${MPI_COMPILE_FLAGS} -DFULL -DMPI")
add_executable (Benchmark_MPI_LIGHT benchmark.cpp)
target_link_libraries (Benchmark_MPI_LIGHT ${ETHHASH_LIBS} ${MPI_LIBRARIES})
SET_TARGET_PROPERTIES(Benchmark_MPI_LIGHT PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} ${MPI_COMPILE_FLAGS} -DMPI")
endif()
add_executable (Benchmark_FULL benchmark.cpp)
target_link_libraries (Benchmark_FULL ${ETHHASH_LIBS})
SET_TARGET_PROPERTIES(Benchmark_FULL PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -DFULL")
add_executable (Benchmark_LIGHT benchmark.cpp)
target_link_libraries (Benchmark_LIGHT ${ETHHASH_LIBS})
if (OpenCL_FOUND)
add_executable (Benchmark_CL benchmark.cpp)
target_link_libraries (Benchmark_CL ${ETHHASH_LIBS} ethash-cl)
SET_TARGET_PROPERTIES(Benchmark_CL PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -DOPENCL")
endif()

@ -0,0 +1,260 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file benchmark.cpp
* @author Tim Hughes <tim@twistedfury.com>
* @date 2015
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <libethash/ethash.h>
#include <libethash/util.h>
#ifdef OPENCL
#include <libethash-cl/ethash_cl_miner.h>
#endif
#include <vector>
#include <algorithm>
#ifdef WITH_CRYPTOPP
#include <libethash/SHA3_cryptopp.h>
#include <string>
#else
#include "libethash/sha3.h"
#endif // WITH_CRYPTOPP
#undef min
#undef max
#if defined(OPENCL)
const unsigned trials = 1024*1024*32;
#elif defined(FULL)
const unsigned trials = 1024*1024/8;
#else
const unsigned trials = 1024*1024/1024;
#endif
uint8_t g_hashes[1024*32];
static char nibbleToChar(unsigned nibble)
{
return (char) ((nibble >= 10 ? 'a'-10 : '0') + nibble);
}
static uint8_t charToNibble(char chr)
{
if (chr >= '0' && chr <= '9')
{
return (uint8_t) (chr - '0');
}
if (chr >= 'a' && chr <= 'z')
{
return (uint8_t) (chr - 'a' + 10);
}
if (chr >= 'A' && chr <= 'Z')
{
return (uint8_t) (chr - 'A' + 10);
}
return 0;
}
static std::vector<uint8_t> hexStringToBytes(char const* str)
{
std::vector<uint8_t> bytes(strlen(str) >> 1);
for (unsigned i = 0; i != bytes.size(); ++i)
{
bytes[i] = charToNibble(str[i*2 | 0]) << 4;
bytes[i] |= charToNibble(str[i*2 | 1]);
}
return bytes;
}
static std::string bytesToHexString(uint8_t const* bytes, unsigned size)
{
std::string str;
for (unsigned i = 0; i != size; ++i)
{
str += nibbleToChar(bytes[i] >> 4);
str += nibbleToChar(bytes[i] & 0xf);
}
return str;
}
extern "C" int main(void)
{
// params for ethash
ethash_params params;
ethash_params_init(&params, 0);
//params.full_size = 262147 * 4096; // 1GBish;
//params.full_size = 32771 * 4096; // 128MBish;
//params.full_size = 8209 * 4096; // 8MBish;
//params.cache_size = 8209*4096;
//params.cache_size = 2053*4096;
uint8_t seed[32], previous_hash[32];
memcpy(seed, hexStringToBytes("9410b944535a83d9adf6bbdcc80e051f30676173c16ca0d32d6f1263fc246466").data(), 32);
memcpy(previous_hash, hexStringToBytes("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").data(), 32);
// allocate page aligned buffer for dataset
#ifdef FULL
void* full_mem_buf = malloc(params.full_size + 4095);
void* full_mem = (void*)((uintptr_t(full_mem_buf) + 4095) & ~4095);
#endif
void* cache_mem_buf = malloc(params.cache_size + 63);
void* cache_mem = (void*)((uintptr_t(cache_mem_buf) + 63) & ~63);
ethash_cache cache;
cache.mem = cache_mem;
// compute cache or full data
{
clock_t startTime = clock();
ethash_mkcache(&cache, &params, seed);
clock_t time = clock() - startTime;
uint8_t cache_hash[32];
SHA3_256(cache_hash, (uint8_t const*)cache_mem, params.cache_size);
debugf("ethash_mkcache: %ums, sha3: %s\n", (unsigned)((time*1000)/CLOCKS_PER_SEC), bytesToHexString(cache_hash,sizeof(cache_hash)).data());
// print a couple of test hashes
{
const clock_t startTime = clock();
ethash_return_value hash;
ethash_light(&hash, &cache, &params, previous_hash, 0);
const clock_t time = clock() - startTime;
debugf("ethash_light test: %ums, %s\n", (unsigned)((time*1000)/CLOCKS_PER_SEC), bytesToHexString(hash.result, 32).data());
}
#ifdef FULL
startTime = clock();
ethash_compute_full_data(full_mem, &params, &cache);
time = clock() - startTime;
debugf("ethash_compute_full_data: %ums\n", (unsigned)((time*1000)/CLOCKS_PER_SEC));
#endif // FULL
}
#ifdef OPENCL
ethash_cl_miner miner;
{
const clock_t startTime = clock();
if (!miner.init(params, seed))
exit(-1);
const clock_t time = clock() - startTime;
debugf("ethash_cl_miner init: %ums\n", (unsigned)((time*1000)/CLOCKS_PER_SEC));
}
#endif
#ifdef FULL
{
const clock_t startTime = clock();
ethash_return_value hash;
ethash_full(&hash, full_mem, &params, previous_hash, 0);
const clock_t time = clock() - startTime;
debugf("ethash_full test: %uns, %s\n", (unsigned)((time*1000000)/CLOCKS_PER_SEC), bytesToHexString(hash.result, 32).data());
}
#endif
#ifdef OPENCL
// validate 1024 hashes against CPU
miner.hash(g_hashes, previous_hash, 0, 1024);
for (unsigned i = 0; i != 1024; ++i)
{
ethash_return_value hash;
ethash_light(&hash, &cache, &params, previous_hash, i);
if (memcmp(hash.result, g_hashes + 32*i, 32) != 0)
{
debugf("nonce %u failed: %s %s\n", i, bytesToHexString(g_hashes + 32*i, 32).c_str(), bytesToHexString(hash.result, 32).c_str());
static unsigned c = 0;
if (++c == 16)
{
exit(-1);
}
}
}
#endif
clock_t startTime = clock();
unsigned hash_count = trials;
#ifdef OPENCL
{
struct search_hook : ethash_cl_miner::search_hook
{
unsigned hash_count;
std::vector<uint64_t> nonce_vec;
virtual bool found(uint64_t const* nonces, uint32_t count)
{
nonce_vec.assign(nonces, nonces + count);
return false;
}
virtual bool searched(uint64_t start_nonce, uint32_t count)
{
// do nothing
hash_count += count;
return hash_count >= trials;
}
};
search_hook hook;
hook.hash_count = 0;
miner.search(previous_hash, 0x000000ffffffffff, hook);
for (unsigned i = 0; i != hook.nonce_vec.size(); ++i)
{
uint64_t nonce = hook.nonce_vec[i];
ethash_return_value hash;
ethash_light(&hash, &cache, &params, previous_hash, nonce);
debugf("found: %.8x%.8x -> %s\n", unsigned(nonce>>32), unsigned(nonce), bytesToHexString(hash.result, 32).c_str());
}
hash_count = hook.hash_count;
}
#else
{
//#pragma omp parallel for
for (int nonce = 0; nonce < trials; ++nonce)
{
ethash_return_value hash;
#ifdef FULL
ethash_full(&hash, full_mem, &params, previous_hash, nonce);
#else
ethash_light(&hash, &cache, &params, previous_hash, nonce);
#endif // FULL
}
}
#endif
clock_t time = std::max((clock_t)1u, clock() - startTime);
unsigned read_size = ACCESSES * MIX_BYTES;
debugf(
"hashrate: %8u, bw: %6u MB/s\n",
(unsigned)(((uint64_t)hash_count*CLOCKS_PER_SEC)/time),
(unsigned)((((uint64_t)hash_count*read_size*CLOCKS_PER_SEC)/time) / (1024*1024))
);
free(cache_mem_buf);
#ifdef FULL
free(full_mem_buf);
#endif
return 0;
}

@ -0,0 +1,15 @@
set(LIBRARY ethash-cl)
set(CMAKE_BUILD_TYPE Release)
include(bin2h.cmake)
bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl VARIABLE_NAME ethash_cl_miner_kernel HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h)
if (NOT OpenCL_FOUND)
find_package(OpenCL)
endif()
if (OpenCL_FOUND)
include_directories(${OpenCL_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
include_directories(..)
add_library(${LIBRARY} ethash_cl_miner.cpp ethash_cl_miner.h)
TARGET_LINK_LIBRARIES(${LIBRARY} ${OpenCL_LIBRARIES} ethash)
endif()

@ -0,0 +1,87 @@
# https://gist.github.com/sivachandran/3a0de157dccef822a230
include(CMakeParseArguments)
# Function to wrap a given string into multiple lines at the given column position.
# Parameters:
# VARIABLE - The name of the CMake variable holding the string.
# AT_COLUMN - The column position at which string will be wrapped.
function(WRAP_STRING)
set(oneValueArgs VARIABLE AT_COLUMN)
cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN})
string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength)
math(EXPR offset "0")
while(stringLength GREATER 0)
if(stringLength GREATER ${WRAP_STRING_AT_COLUMN})
math(EXPR length "${WRAP_STRING_AT_COLUMN}")
else()
math(EXPR length "${stringLength}")
endif()
string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line)
set(lines "${lines}\n${line}")
math(EXPR stringLength "${stringLength} - ${length}")
math(EXPR offset "${offset} + ${length}")
endwhile()
set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE)
endfunction()
# Function to embed contents of a file as byte array in C/C++ header file(.h). The header file
# will contain a byte array and integer variable holding the size of the array.
# Parameters
# SOURCE_FILE - The path of source file whose contents will be embedded in the header file.
# VARIABLE_NAME - The name of the variable for the byte array. The string "_SIZE" will be append
# to this name and will be used a variable name for size variable.
# HEADER_FILE - The path of header file.
# APPEND - If specified appends to the header file instead of overwriting it
# NULL_TERMINATE - If specified a null byte(zero) will be append to the byte array. This will be
# useful if the source file is a text file and we want to use the file contents
# as string. But the size variable holds size of the byte array without this
# null byte.
# Usage:
# bin2h(SOURCE_FILE "Logo.png" HEADER_FILE "Logo.h" VARIABLE_NAME "LOGO_PNG")
function(BIN2H)
set(options APPEND NULL_TERMINATE)
set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE)
cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN})
# reads source file contents as hex string
file(READ ${BIN2H_SOURCE_FILE} hexString HEX)
string(LENGTH ${hexString} hexStringLength)
# appends null byte if asked
if(BIN2H_NULL_TERMINATE)
set(hexString "${hexString}00")
endif()
# wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line)
wrap_string(VARIABLE hexString AT_COLUMN 32)
math(EXPR arraySize "${hexStringLength} / 2")
# adds '0x' prefix and comma suffix before and after every byte respectively
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString})
# removes trailing comma
string(REGEX REPLACE ", $" "" arrayValues ${arrayValues})
# converts the variable name into proper C identifier
# TODO: fix for legacy cmake
IF (${CMAKE_VERSION} GREATER 2.8.10)
string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
ENDIF()
string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
# declares byte array and the length variables
set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };")
set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};")
set(declarations "${arrayDefinition}\n\n${arraySizeDefinition}\n\n")
if(BIN2H_APPEND)
file(APPEND ${BIN2H_HEADER_FILE} "${declarations}")
else()
file(WRITE ${BIN2H_HEADER_FILE} "${declarations}")
endif()
endfunction()

File diff suppressed because it is too large Load Diff

@ -0,0 +1,289 @@
/*
This file is part of c-ethash.
c-ethash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
c-ethash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ethash_cl_miner.cpp
* @author Tim Hughes <tim@twistedfury.com>
* @date 2015
*/
#define _CRT_SECURE_NO_WARNINGS
#include <assert.h>
#include <queue>
#include "ethash_cl_miner.h"
#include "ethash_cl_miner_kernel.h"
#include <libethash/util.h>
#undef min
#undef max
#define HASH_BYTES 32
static void add_definition(std::string& source, char const* id, unsigned value)
{
char buf[256];
sprintf(buf, "#define %s %uu\n", id, value);
source.insert(source.begin(), buf, buf + strlen(buf));
}
ethash_cl_miner::ethash_cl_miner()
{
}
bool ethash_cl_miner::init(ethash_params const& params, const uint8_t seed[32], unsigned workgroup_size)
{
// store params
m_params = params;
// get all platforms
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
if (platforms.empty())
{
debugf("No OpenCL platforms found.\n");
return false;
}
// use default platform
debugf("Using platform: %s\n", platforms[0].getInfo<CL_PLATFORM_NAME>().c_str());
// get GPU device of the default platform
std::vector<cl::Device> devices;
platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty())
{
debugf("No OpenCL devices found.\n");
return false;
}
// use default device
cl::Device& device = devices[0];
debugf("Using device: %s\n", device.getInfo<CL_DEVICE_NAME>().c_str());
// create context
m_context = cl::Context({device});
m_queue = cl::CommandQueue(m_context, device);
// use requested workgroup size, but we require multiple of 8
m_workgroup_size = ((workgroup_size + 7) / 8) * 8;
// patch source code
std::string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE);
add_definition(code, "GROUP_SIZE", m_workgroup_size);
add_definition(code, "DAG_SIZE", (unsigned)(params.full_size / MIX_BYTES));
add_definition(code, "ACCESSES", ACCESSES);
add_definition(code, "MAX_OUTPUTS", c_max_search_results);
//debugf("%s", code.c_str());
// create miner OpenCL program
cl::Program::Sources sources;
sources.push_back({code.c_str(), code.size()});
cl::Program program(m_context, sources);
try
{
program.build({device});
}
catch (cl::Error err)
{
debugf("%s\n", program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device).c_str());
return false;
}
m_hash_kernel = cl::Kernel(program, "ethash_hash");
m_search_kernel = cl::Kernel(program, "ethash_search");
// create buffer for dag
m_dag = cl::Buffer(m_context, CL_MEM_READ_ONLY, params.full_size);
// create buffer for header
m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32);
// compute dag on CPU
{
void* cache_mem = malloc(params.cache_size + 63);
ethash_cache cache;
cache.mem = (void*)(((uintptr_t)cache_mem + 63) & ~63);
ethash_mkcache(&cache, &params, seed);
// if this throws then it's because we probably need to subdivide the dag uploads for compatibility
void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, CL_MAP_WRITE_INVALIDATE_REGION, 0, params.full_size);
ethash_compute_full_data(dag_ptr, &params, &cache);
m_queue.enqueueUnmapMemObject(m_dag, dag_ptr);
free(cache_mem);
}
// create mining buffers
for (unsigned i = 0; i != c_num_buffers; ++i)
{
m_hash_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | CL_MEM_HOST_READ_ONLY, 32*c_hash_batch_size);
m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t));
}
return true;
}
void ethash_cl_miner::hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count)
{
struct pending_batch
{
unsigned base;
unsigned count;
unsigned buf;
};
std::queue<pending_batch> pending;
// update header constant buffer
m_queue.enqueueWriteBuffer(m_header, true, 0, 32, header);
/*
__kernel void ethash_combined_hash(
__global hash32_t* g_hashes,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong start_nonce,
uint isolate
)
*/
m_hash_kernel.setArg(1, m_header);
m_hash_kernel.setArg(2, m_dag);
m_hash_kernel.setArg(3, nonce);
m_hash_kernel.setArg(4, ~0u); // have to pass this to stop the compile unrolling the loop
unsigned buf = 0;
for (unsigned i = 0; i < count || !pending.empty(); )
{
// how many this batch
if (i < count)
{
unsigned const this_count = std::min(count - i, c_hash_batch_size);
unsigned const batch_count = std::max(this_count, m_workgroup_size);
// supply output hash buffer to kernel
m_hash_kernel.setArg(0, m_hash_buf[buf]);
// execute it!
clock_t start_time = clock();
m_queue.enqueueNDRangeKernel(
m_hash_kernel,
cl::NullRange,
cl::NDRange(batch_count),
cl::NDRange(m_workgroup_size)
);
m_queue.flush();
pending.push({i, this_count, buf});
i += this_count;
buf = (buf + 1) % c_num_buffers;
}
// read results
if (i == count || pending.size() == c_num_buffers)
{
pending_batch const& batch = pending.front();
// could use pinned host pointer instead, but this path isn't that important.
uint8_t* hashes = (uint8_t*)m_queue.enqueueMapBuffer(m_hash_buf[batch.buf], true, CL_MAP_READ, 0, batch.count * HASH_BYTES);
memcpy(ret + batch.base*HASH_BYTES, hashes, batch.count*HASH_BYTES);
m_queue.enqueueUnmapMemObject(m_hash_buf[batch.buf], hashes);
pending.pop();
}
}
}
void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook& hook)
{
struct pending_batch
{
uint64_t start_nonce;
unsigned buf;
};
std::queue<pending_batch> pending;
static uint32_t const c_zero = 0;
// update header constant buffer
m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header);
for (unsigned i = 0; i != c_num_buffers; ++i)
{
m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero);
}
cl::Event pre_return_event;
m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event);
/*
__kernel void ethash_combined_search(
__global hash32_t* g_hashes, // 0
__constant hash32_t const* g_header, // 1
__global hash128_t const* g_dag, // 2
ulong start_nonce, // 3
ulong target, // 4
uint isolate // 5
)
*/
m_search_kernel.setArg(1, m_header);
m_search_kernel.setArg(2, m_dag);
// pass these to stop the compiler unrolling the loops
m_search_kernel.setArg(4, target);
m_search_kernel.setArg(5, ~0u);
unsigned buf = 0;
for (uint64_t start_nonce = 0; ; start_nonce += c_search_batch_size)
{
// supply output buffer to kernel
m_search_kernel.setArg(0, m_search_buf[buf]);
m_search_kernel.setArg(3, start_nonce);
// execute it!
m_queue.enqueueNDRangeKernel(m_search_kernel, cl::NullRange, c_search_batch_size, m_workgroup_size);
pending.push({start_nonce, buf});
buf = (buf + 1) % c_num_buffers;
// read results
if (pending.size() == c_num_buffers)
{
pending_batch const& batch = pending.front();
// could use pinned host pointer instead
uint32_t* results = (uint32_t*)m_queue.enqueueMapBuffer(m_search_buf[batch.buf], true, CL_MAP_READ, 0, (1+c_max_search_results) * sizeof(uint32_t));
unsigned num_found = std::min(results[0], c_max_search_results);
uint64_t nonces[c_max_search_results];
for (unsigned i = 0; i != num_found; ++i)
{
nonces[i] = batch.start_nonce + results[i+1];
}
m_queue.enqueueUnmapMemObject(m_search_buf[batch.buf], results);
bool exit = num_found && hook.found(nonces, num_found);
exit |= hook.searched(batch.start_nonce, c_search_batch_size); // always report searched before exit
if (exit)
break;
pending.pop();
}
}
// not safe to return until this is ready
pre_return_event.wait();
}

@ -0,0 +1,43 @@
#pragma once
#define __CL_ENABLE_EXCEPTIONS
#define CL_USE_DEPRECATED_OPENCL_2_0_APIS
#include "cl.hpp"
#include <time.h>
#include <libethash/ethash.h>
class ethash_cl_miner
{
public:
struct search_hook
{
// reports progress, return true to abort
virtual bool found(uint64_t const* nonces, uint32_t count) = 0;
virtual bool searched(uint64_t start_nonce, uint32_t count) = 0;
};
public:
ethash_cl_miner();
bool init(ethash_params const& params, const uint8_t seed[32], unsigned workgroup_size = 64);
void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count);
void search(uint8_t const* header, uint64_t target, search_hook& hook);
private:
static unsigned const c_max_search_results = 63;
static unsigned const c_num_buffers = 2;
static unsigned const c_hash_batch_size = 1024;
static unsigned const c_search_batch_size = 1024*256;
ethash_params m_params;
cl::Context m_context;
cl::CommandQueue m_queue;
cl::Kernel m_hash_kernel;
cl::Kernel m_search_kernel;
cl::Buffer m_dag;
cl::Buffer m_header;
cl::Buffer m_hash_buf[c_num_buffers];
cl::Buffer m_search_buf[c_num_buffers];
unsigned m_workgroup_size;
};

@ -0,0 +1,461 @@
// author Tim Hughes <tim@twistedfury.com>
// Tested on Radeon HD 7850
// Hashrate: 15940347 hashes/s
// Bandwidth: 124533 MB/s
// search kernel should fit in <= 84 VGPRS (3 wavefronts)
#define THREADS_PER_HASH (128 / 16)
#define HASHES_PER_LOOP (GROUP_SIZE / THREADS_PER_HASH)
#define FNV_PRIME 0x01000193
__constant uint2 const Keccak_f1600_RC[24] = {
(uint2)(0x00000001, 0x00000000),
(uint2)(0x00008082, 0x00000000),
(uint2)(0x0000808a, 0x80000000),
(uint2)(0x80008000, 0x80000000),
(uint2)(0x0000808b, 0x00000000),
(uint2)(0x80000001, 0x00000000),
(uint2)(0x80008081, 0x80000000),
(uint2)(0x00008009, 0x80000000),
(uint2)(0x0000008a, 0x00000000),
(uint2)(0x00000088, 0x00000000),
(uint2)(0x80008009, 0x00000000),
(uint2)(0x8000000a, 0x00000000),
(uint2)(0x8000808b, 0x00000000),
(uint2)(0x0000008b, 0x80000000),
(uint2)(0x00008089, 0x80000000),
(uint2)(0x00008003, 0x80000000),
(uint2)(0x00008002, 0x80000000),
(uint2)(0x00000080, 0x80000000),
(uint2)(0x0000800a, 0x00000000),
(uint2)(0x8000000a, 0x80000000),
(uint2)(0x80008081, 0x80000000),
(uint2)(0x00008080, 0x80000000),
(uint2)(0x80000001, 0x00000000),
(uint2)(0x80008008, 0x80000000),
};
void keccak_f1600_round(uint2* a, uint r, uint out_size)
{
#if !__ENDIAN_LITTLE__
for (uint i = 0; i != 25; ++i)
a[i] = a[i].yx;
#endif
uint2 b[25];
uint2 t;
// Theta
b[0] = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20];
b[1] = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21];
b[2] = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22];
b[3] = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23];
b[4] = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24];
t = b[4] ^ (uint2)(b[1].x << 1 | b[1].y >> 31, b[1].y << 1 | b[1].x >> 31);
a[0] ^= t;
a[5] ^= t;
a[10] ^= t;
a[15] ^= t;
a[20] ^= t;
t = b[0] ^ (uint2)(b[2].x << 1 | b[2].y >> 31, b[2].y << 1 | b[2].x >> 31);
a[1] ^= t;
a[6] ^= t;
a[11] ^= t;
a[16] ^= t;
a[21] ^= t;
t = b[1] ^ (uint2)(b[3].x << 1 | b[3].y >> 31, b[3].y << 1 | b[3].x >> 31);
a[2] ^= t;
a[7] ^= t;
a[12] ^= t;
a[17] ^= t;
a[22] ^= t;
t = b[2] ^ (uint2)(b[4].x << 1 | b[4].y >> 31, b[4].y << 1 | b[4].x >> 31);
a[3] ^= t;
a[8] ^= t;
a[13] ^= t;
a[18] ^= t;
a[23] ^= t;
t = b[3] ^ (uint2)(b[0].x << 1 | b[0].y >> 31, b[0].y << 1 | b[0].x >> 31);
a[4] ^= t;
a[9] ^= t;
a[14] ^= t;
a[19] ^= t;
a[24] ^= t;
// Rho Pi
b[0] = a[0];
b[10] = (uint2)(a[1].x << 1 | a[1].y >> 31, a[1].y << 1 | a[1].x >> 31);
b[7] = (uint2)(a[10].x << 3 | a[10].y >> 29, a[10].y << 3 | a[10].x >> 29);
b[11] = (uint2)(a[7].x << 6 | a[7].y >> 26, a[7].y << 6 | a[7].x >> 26);
b[17] = (uint2)(a[11].x << 10 | a[11].y >> 22, a[11].y << 10 | a[11].x >> 22);
b[18] = (uint2)(a[17].x << 15 | a[17].y >> 17, a[17].y << 15 | a[17].x >> 17);
b[3] = (uint2)(a[18].x << 21 | a[18].y >> 11, a[18].y << 21 | a[18].x >> 11);
b[5] = (uint2)(a[3].x << 28 | a[3].y >> 4, a[3].y << 28 | a[3].x >> 4);
b[16] = (uint2)(a[5].y << 4 | a[5].x >> 28, a[5].x << 4 | a[5].y >> 28);
b[8] = (uint2)(a[16].y << 13 | a[16].x >> 19, a[16].x << 13 | a[16].y >> 19);
b[21] = (uint2)(a[8].y << 23 | a[8].x >> 9, a[8].x << 23 | a[8].y >> 9);
b[24] = (uint2)(a[21].x << 2 | a[21].y >> 30, a[21].y << 2 | a[21].x >> 30);
b[4] = (uint2)(a[24].x << 14 | a[24].y >> 18, a[24].y << 14 | a[24].x >> 18);
b[15] = (uint2)(a[4].x << 27 | a[4].y >> 5, a[4].y << 27 | a[4].x >> 5);
b[23] = (uint2)(a[15].y << 9 | a[15].x >> 23, a[15].x << 9 | a[15].y >> 23);
b[19] = (uint2)(a[23].y << 24 | a[23].x >> 8, a[23].x << 24 | a[23].y >> 8);
b[13] = (uint2)(a[19].x << 8 | a[19].y >> 24, a[19].y << 8 | a[19].x >> 24);
b[12] = (uint2)(a[13].x << 25 | a[13].y >> 7, a[13].y << 25 | a[13].x >> 7);
b[2] = (uint2)(a[12].y << 11 | a[12].x >> 21, a[12].x << 11 | a[12].y >> 21);
b[20] = (uint2)(a[2].y << 30 | a[2].x >> 2, a[2].x << 30 | a[2].y >> 2);
b[14] = (uint2)(a[20].x << 18 | a[20].y >> 14, a[20].y << 18 | a[20].x >> 14);
b[22] = (uint2)(a[14].y << 7 | a[14].x >> 25, a[14].x << 7 | a[14].y >> 25);
b[9] = (uint2)(a[22].y << 29 | a[22].x >> 3, a[22].x << 29 | a[22].y >> 3);
b[6] = (uint2)(a[9].x << 20 | a[9].y >> 12, a[9].y << 20 | a[9].x >> 12);
b[1] = (uint2)(a[6].y << 12 | a[6].x >> 20, a[6].x << 12 | a[6].y >> 20);
// Chi
a[0] = bitselect(b[0] ^ b[2], b[0], b[1]);
a[1] = bitselect(b[1] ^ b[3], b[1], b[2]);
a[2] = bitselect(b[2] ^ b[4], b[2], b[3]);
a[3] = bitselect(b[3] ^ b[0], b[3], b[4]);
if (out_size >= 4)
{
a[4] = bitselect(b[4] ^ b[1], b[4], b[0]);
a[5] = bitselect(b[5] ^ b[7], b[5], b[6]);
a[6] = bitselect(b[6] ^ b[8], b[6], b[7]);
a[7] = bitselect(b[7] ^ b[9], b[7], b[8]);
a[8] = bitselect(b[8] ^ b[5], b[8], b[9]);
if (out_size >= 8)
{
a[9] = bitselect(b[9] ^ b[6], b[9], b[5]);
a[10] = bitselect(b[10] ^ b[12], b[10], b[11]);
a[11] = bitselect(b[11] ^ b[13], b[11], b[12]);
a[12] = bitselect(b[12] ^ b[14], b[12], b[13]);
a[13] = bitselect(b[13] ^ b[10], b[13], b[14]);
a[14] = bitselect(b[14] ^ b[11], b[14], b[10]);
a[15] = bitselect(b[15] ^ b[17], b[15], b[16]);
a[16] = bitselect(b[16] ^ b[18], b[16], b[17]);
a[17] = bitselect(b[17] ^ b[19], b[17], b[18]);
a[18] = bitselect(b[18] ^ b[15], b[18], b[19]);
a[19] = bitselect(b[19] ^ b[16], b[19], b[15]);
a[20] = bitselect(b[20] ^ b[22], b[20], b[21]);
a[21] = bitselect(b[21] ^ b[23], b[21], b[22]);
a[22] = bitselect(b[22] ^ b[24], b[22], b[23]);
a[23] = bitselect(b[23] ^ b[20], b[23], b[24]);
a[24] = bitselect(b[24] ^ b[21], b[24], b[20]);
}
}
// Iota
a[0] ^= Keccak_f1600_RC[r];
#if !__ENDIAN_LITTLE__
for (uint i = 0; i != 25; ++i)
a[i] = a[i].yx;
#endif
}
void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate)
{
for (uint i = in_size; i != 25; ++i)
{
a[i] = 0;
}
#if __ENDIAN_LITTLE__
a[in_size] ^= 0x0000000000000001;
a[24-out_size*2] ^= 0x8000000000000000;
#else
a[in_size] ^= 0x0100000000000000;
a[24-out_size*2] ^= 0x0000000000000080;
#endif
// Originally I unrolled the first and last rounds to interface
// better with surrounding code, however I haven't done this
// without causing the AMD compiler to blow up the VGPR usage.
uint r = 0;
do
{
// This dynamic branch stops the AMD compiler unrolling the loop
// and additionally saves about 33% of the VGPRs, enough to gain another
// wavefront. Ideally we'd get 4 in flight, but 3 is the best I can
// massage out of the compiler. It doesn't really seem to matter how
// much we try and help the compiler save VGPRs because it seems to throw
// that information away, hence the implementation of keccak here
// doesn't bother.
if (isolate)
{
keccak_f1600_round((uint2*)a, r++, 25);
}
}
while (r < 23);
// final round optimised for digest size
keccak_f1600_round((uint2*)a, r++, out_size);
}
#define copy(dst, src, count) for (uint i = 0; i != count; ++i) { (dst)[i] = (src)[i]; }
#define countof(x) (sizeof(x) / sizeof(x[0]))
uint fnv(uint x, uint y)
{
return x * FNV_PRIME ^ y;
}
uint4 fnv4(uint4 x, uint4 y)
{
return x * FNV_PRIME ^ y;
}
uint fnv_reduce(uint4 v)
{
return fnv(fnv(fnv(v.x, v.y), v.z), v.w);
}
typedef union
{
ulong ulongs[32 / sizeof(ulong)];
uint uints[32 / sizeof(uint)];
} hash32_t;
typedef union
{
ulong ulongs[64 / sizeof(ulong)];
uint4 uint4s[64 / sizeof(uint4)];
} hash64_t;
typedef union
{
uint uints[128 / sizeof(uint)];
uint4 uint4s[128 / sizeof(uint4)];
} hash128_t;
hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate)
{
hash64_t init;
uint const init_size = countof(init.ulongs);
uint const hash_size = countof(header->ulongs);
// sha3_512(header .. nonce)
ulong state[25];
copy(state, header->ulongs, hash_size);
state[hash_size] = nonce;
keccak_f1600_no_absorb(state, hash_size + 1, init_size, isolate);
copy(init.ulongs, state, init_size);
return init;
}
uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate)
{
uint4 mix = init;
// share init0
if (thread_id == 0)
*share = mix.x;
barrier(CLK_LOCAL_MEM_FENCE);
uint init0 = *share;
uint a = 0;
do
{
bool update_share = thread_id == (a/4) % THREADS_PER_HASH;
#pragma unroll
for (uint i = 0; i != 4; ++i)
{
if (update_share)
{
uint m[4] = { mix.x, mix.y, mix.z, mix.w };
*share = fnv(init0 ^ (a+i), m[i]) % DAG_SIZE;
}
barrier(CLK_LOCAL_MEM_FENCE);
mix = fnv4(mix, g_dag[*share].uint4s[thread_id]);
}
}
while ((a += 4) != (ACCESSES & isolate));
return fnv_reduce(mix);
}
hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate)
{
ulong state[25];
hash32_t hash;
uint const hash_size = countof(hash.ulongs);
uint const init_size = countof(init->ulongs);
uint const mix_size = countof(mix->ulongs);
// keccak_256(keccak_512(header..nonce) .. mix);
copy(state, init->ulongs, init_size);
copy(state + init_size, mix->ulongs, mix_size);
keccak_f1600_no_absorb(state, init_size+mix_size, hash_size, isolate);
// copy out
copy(hash.ulongs, state, hash_size);
return hash;
}
hash32_t compute_hash_simple(
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong nonce,
uint isolate
)
{
hash64_t init = init_hash(g_header, nonce, isolate);
hash128_t mix;
for (uint i = 0; i != countof(mix.uint4s); ++i)
{
mix.uint4s[i] = init.uint4s[i % countof(init.uint4s)];
}
uint mix_val = mix.uints[0];
uint init0 = mix.uints[0];
uint a = 0;
do
{
uint pi = fnv(init0 ^ a, mix_val) % DAG_SIZE;
uint n = (a+1) % countof(mix.uints);
#pragma unroll
for (uint i = 0; i != countof(mix.uints); ++i)
{
mix.uints[i] = fnv(mix.uints[i], g_dag[pi].uints[i]);
mix_val = i == n ? mix.uints[i] : mix_val;
}
}
while (++a != (ACCESSES & isolate));
// reduce to output
hash32_t fnv_mix;
for (uint i = 0; i != countof(fnv_mix.uints); ++i)
{
fnv_mix.uints[i] = fnv_reduce(mix.uint4s[i]);
}
return final_hash(&init, &fnv_mix, isolate);
}
typedef union
{
struct
{
hash64_t init;
uint pad; // avoid lds bank conflicts
};
hash32_t mix;
} compute_hash_share;
hash32_t compute_hash(
__local compute_hash_share* share,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong nonce,
uint isolate
)
{
uint const gid = get_global_id(0);
// Compute one init hash per work item.
hash64_t init = init_hash(g_header, nonce, isolate);
// Threads work together in this phase in groups of 8.
uint const thread_id = gid % THREADS_PER_HASH;
uint const hash_id = (gid % GROUP_SIZE) / THREADS_PER_HASH;
hash32_t mix;
uint i = 0;
do
{
// share init with other threads
if (i == thread_id)
share[hash_id].init = init;
barrier(CLK_LOCAL_MEM_FENCE);
uint4 thread_init = share[hash_id].init.uint4s[thread_id % (64 / sizeof(uint4))];
barrier(CLK_LOCAL_MEM_FENCE);
uint thread_mix = inner_loop(thread_init, thread_id, share[hash_id].mix.uints, g_dag, isolate);
share[hash_id].mix.uints[thread_id] = thread_mix;
barrier(CLK_LOCAL_MEM_FENCE);
if (i == thread_id)
mix = share[hash_id].mix;
barrier(CLK_LOCAL_MEM_FENCE);
}
while (++i != (THREADS_PER_HASH & isolate));
return final_hash(&init, &mix, isolate);
}
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
__kernel void ethash_hash_simple(
__global hash32_t* g_hashes,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong start_nonce,
uint isolate
)
{
uint const gid = get_global_id(0);
g_hashes[gid] = compute_hash_simple(g_header, g_dag, start_nonce + gid, isolate);
}
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
__kernel void ethash_search_simple(
__global volatile uint* restrict g_output,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong start_nonce,
ulong target,
uint isolate
)
{
uint const gid = get_global_id(0);
hash32_t hash = compute_hash_simple(g_header, g_dag, start_nonce + gid, isolate);
if (hash.ulongs[countof(hash.ulongs)-1] < target)
{
uint slot = min(MAX_OUTPUTS, atomic_inc(&g_output[0]) + 1);
g_output[slot] = gid;
}
}
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
__kernel void ethash_hash(
__global hash32_t* g_hashes,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong start_nonce,
uint isolate
)
{
__local compute_hash_share share[HASHES_PER_LOOP];
uint const gid = get_global_id(0);
g_hashes[gid] = compute_hash(share, g_header, g_dag, start_nonce + gid, isolate);
}
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
__kernel void ethash_search(
__global volatile uint* restrict g_output,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong start_nonce,
ulong target,
uint isolate
)
{
__local compute_hash_share share[HASHES_PER_LOOP];
uint const gid = get_global_id(0);
hash32_t hash = compute_hash(share, g_header, g_dag, start_nonce + gid, isolate);
if (hash.ulongs[countof(hash.ulongs)-1] < target)
{
uint slot = min(MAX_OUTPUTS, atomic_inc(&g_output[0]) + 1);
g_output[slot] = gid;
}
}

@ -0,0 +1,39 @@
set(LIBRARY ethash)
if (CPPETHEREUM)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
#else ()
endif ()
set(CMAKE_BUILD_TYPE Release)
if (NOT MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
endif()
set(FILES util.c
util.h
internal.c
ethash.h
endian.h
compiler.h
fnv.h
data_sizes.h)
if (NOT CRYPTOPP_FOUND)
find_package(CryptoPP 5.6.2)
endif()
if (CRYPTOPP_FOUND)
add_definitions(-DWITH_CRYPTOPP)
include_directories( ${CRYPTOPP_INCLUDE_DIRS} )
list(APPEND FILES sha3_cryptopp.cpp sha3_cryptopp.h)
else()
list(APPEND FILES sha3.c sha3.h)
endif()
add_library(${LIBRARY} ${FILES})
if (CRYPTOPP_FOUND)
TARGET_LINK_LIBRARIES(${LIBRARY} ${CRYPTOPP_LIBRARIES})
endif()

@ -0,0 +1,33 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file compiler.h
* @date 2014
*/
#pragma once
// Visual Studio doesn't support the inline keyword in C mode
#if defined(_MSC_VER) && !defined(__cplusplus)
#define inline __inline
#endif
// pretend restrict is a standard keyword
#if defined(_MSC_VER)
#define restrict __restrict
#else
#define restrict __restrict__
#endif

@ -0,0 +1,779 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software FoundationUUU,either version 3 of the LicenseUUU,or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be usefulU,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If notUUU,see <http://www.gnu.org/licenses/>.
*/
/** @file data_sizes.h
* @author Matthew Wampler-Doty <negacthulhu@gmail.com>
* @date 2015
*/
// TODO: Update this after ~3.5 years
#pragma once
#include <stdint.h>
#include "compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
// 2048 Epochs worth of tabulated DAG sizes
// Generated with the following Mathematica Code:
// GetDataSizes[n_] := Module[{
// DataSetSizeBytesInit = 2^30,
// MixBytes = 128,
// DataSetGrowth = 2^23,
// j = 0},
// Reap[
// While[j < n,
// Module[{i =
// Floor[(DataSetSizeBytesInit + DataSetGrowth * j) / MixBytes]},
// While[! PrimeQ[i], i--];
// Sow[i*MixBytes]; j++]]]][[2]][[1]]
static const size_t dag_sizes[] = {
1073739904U, 1082130304U, 1090514816U, 1098906752U, 1107293056U,
1115684224U, 1124070016U, 1132461952U, 1140849536U, 1149232768U,
1157627776U, 1166013824U, 1174404736U, 1182786944U, 1191180416U,
1199568512U, 1207958912U, 1216345216U, 1224732032U, 1233124736U,
1241513344U, 1249902464U, 1258290304U, 1266673792U, 1275067264U,
1283453312U, 1291844992U, 1300234112U, 1308619904U, 1317010048U,
1325397376U, 1333787776U, 1342176128U, 1350561664U, 1358954368U,
1367339392U, 1375731584U, 1384118144U, 1392507008U, 1400897408U,
1409284736U, 1417673344U, 1426062464U, 1434451072U, 1442839168U,
1451229056U, 1459615616U, 1468006016U, 1476394112U, 1484782976U,
1493171584U, 1501559168U, 1509948032U, 1518337664U, 1526726528U,
1535114624U, 1543503488U, 1551892096U, 1560278656U, 1568669056U,
1577056384U, 1585446272U, 1593831296U, 1602219392U, 1610610304U,
1619000192U, 1627386752U, 1635773824U, 1644164224U, 1652555648U,
1660943488U, 1669332608U, 1677721216U, 1686109312U, 1694497664U,
1702886272U, 1711274624U, 1719661184U, 1728047744U, 1736434816U,
1744829056U, 1753218944U, 1761606272U, 1769995904U, 1778382464U,
1786772864U, 1795157888U, 1803550592U, 1811937664U, 1820327552U,
1828711552U, 1837102976U, 1845488768U, 1853879936U, 1862269312U,
1870656896U, 1879048064U, 1887431552U, 1895825024U, 1904212096U,
1912601216U, 1920988544U, 1929379456U, 1937765504U, 1946156672U,
1954543232U, 1962932096U, 1971321728U, 1979707264U, 1988093056U,
1996487552U, 2004874624U, 2013262208U, 2021653888U, 2030039936U,
2038430848U, 2046819968U, 2055208576U, 2063596672U, 2071981952U,
2080373632U, 2088762752U, 2097149056U, 2105539712U, 2113928576U,
2122315136U, 2130700672U, 2139092608U, 2147483264U, 2155872128U,
2164257664U, 2172642176U, 2181035392U, 2189426048U, 2197814912U,
2206203008U, 2214587264U, 2222979712U, 2231367808U, 2239758208U,
2248145024U, 2256527744U, 2264922752U, 2273312128U, 2281701248U,
2290086272U, 2298476672U, 2306867072U, 2315251072U, 2323639168U,
2332032128U, 2340420224U, 2348808064U, 2357196416U, 2365580416U,
2373966976U, 2382363008U, 2390748544U, 2399139968U, 2407530368U,
2415918976U, 2424307328U, 2432695424U, 2441084288U, 2449472384U,
2457861248U, 2466247808U, 2474637184U, 2483026816U, 2491414144U,
2499803776U, 2508191872U, 2516582272U, 2524970368U, 2533359232U,
2541743488U, 2550134144U, 2558525056U, 2566913408U, 2575301504U,
2583686528U, 2592073856U, 2600467328U, 2608856192U, 2617240448U,
2625631616U, 2634022016U, 2642407552U, 2650796416U, 2659188352U,
2667574912U, 2675965312U, 2684352896U, 2692738688U, 2701130624U,
2709518464U, 2717907328U, 2726293376U, 2734685056U, 2743073152U,
2751462016U, 2759851648U, 2768232832U, 2776625536U, 2785017728U,
2793401984U, 2801794432U, 2810182016U, 2818571648U, 2826959488U,
2835349376U, 2843734144U, 2852121472U, 2860514432U, 2868900992U,
2877286784U, 2885676928U, 2894069632U, 2902451584U, 2910843008U,
2919234688U, 2927622784U, 2936011648U, 2944400768U, 2952789376U,
2961177728U, 2969565568U, 2977951616U, 2986338944U, 2994731392U,
3003120256U, 3011508352U, 3019895936U, 3028287104U, 3036675968U,
3045063808U, 3053452928U, 3061837696U, 3070228352U, 3078615424U,
3087003776U, 3095394944U, 3103782272U, 3112173184U, 3120562048U,
3128944768U, 3137339264U, 3145725056U, 3154109312U, 3162505088U,
3170893184U, 3179280256U, 3187669376U, 3196056704U, 3204445568U,
3212836736U, 3221224064U, 3229612928U, 3238002304U, 3246391168U,
3254778496U, 3263165824U, 3271556224U, 3279944576U, 3288332416U,
3296719232U, 3305110912U, 3313500032U, 3321887104U, 3330273152U,
3338658944U, 3347053184U, 3355440512U, 3363827072U, 3372220288U,
3380608384U, 3388997504U, 3397384576U, 3405774208U, 3414163072U,
3422551936U, 3430937984U, 3439328384U, 3447714176U, 3456104576U,
3464493952U, 3472883584U, 3481268864U, 3489655168U, 3498048896U,
3506434432U, 3514826368U, 3523213952U, 3531603584U, 3539987072U,
3548380288U, 3556763264U, 3565157248U, 3573545344U, 3581934464U,
3590324096U, 3598712704U, 3607098752U, 3615488384U, 3623877248U,
3632265856U, 3640646528U, 3649043584U, 3657430144U, 3665821568U,
3674207872U, 3682597504U, 3690984832U, 3699367808U, 3707764352U,
3716152448U, 3724541056U, 3732925568U, 3741318016U, 3749706368U,
3758091136U, 3766481536U, 3774872704U, 3783260032U, 3791650432U,
3800036224U, 3808427648U, 3816815488U, 3825204608U, 3833592704U,
3841981568U, 3850370432U, 3858755968U, 3867147904U, 3875536256U,
3883920512U, 3892313728U, 3900702592U, 3909087872U, 3917478784U,
3925868416U, 3934256512U, 3942645376U, 3951032192U, 3959422336U,
3967809152U, 3976200064U, 3984588416U, 3992974976U, 4001363584U,
4009751168U, 4018141312U, 4026530432U, 4034911616U, 4043308928U,
4051695488U, 4060084352U, 4068472448U, 4076862848U, 4085249408U,
4093640576U, 4102028416U, 4110413696U, 4118805632U, 4127194496U,
4135583104U, 4143971968U, 4152360832U, 4160746112U, 4169135744U,
4177525888U, 4185912704U, 4194303616U, 4202691968U, 4211076736U,
4219463552U, 4227855488U, 4236246656U, 4244633728U, 4253022848U,
4261412224U, 4269799808U, 4278184832U, 4286578048U, 4294962304U,
4303349632U, 4311743104U, 4320130432U, 4328521088U, 4336909184U,
4345295488U, 4353687424U, 4362073472U, 4370458496U, 4378852736U,
4387238528U, 4395630208U, 4404019072U, 4412407424U, 4420790656U,
4429182848U, 4437571456U, 4445962112U, 4454344064U, 4462738048U,
4471119232U, 4479516544U, 4487904128U, 4496289664U, 4504682368U,
4513068416U, 4521459584U, 4529846144U, 4538232704U, 4546619776U,
4555010176U, 4563402112U, 4571790208U, 4580174464U, 4588567936U,
4596957056U, 4605344896U, 4613734016U, 4622119808U, 4630511488U,
4638898816U, 4647287936U, 4655675264U, 4664065664U, 4672451968U,
4680842624U, 4689231488U, 4697620352U, 4706007424U, 4714397056U,
4722786176U, 4731173248U, 4739562368U, 4747951744U, 4756340608U,
4764727936U, 4773114496U, 4781504384U, 4789894784U, 4798283648U,
4806667648U, 4815059584U, 4823449472U, 4831835776U, 4840226176U,
4848612224U, 4857003392U, 4865391488U, 4873780096U, 4882169728U,
4890557312U, 4898946944U, 4907333248U, 4915722368U, 4924110976U,
4932499328U, 4940889728U, 4949276032U, 4957666432U, 4966054784U,
4974438016U, 4982831488U, 4991221376U, 4999607168U, 5007998848U,
5016386432U, 5024763776U, 5033164672U, 5041544576U, 5049941888U,
5058329728U, 5066717056U, 5075107456U, 5083494272U, 5091883904U,
5100273536U, 5108662144U, 5117048192U, 5125436032U, 5133827456U,
5142215296U, 5150605184U, 5158993024U, 5167382144U, 5175769472U,
5184157568U, 5192543872U, 5200936064U, 5209324928U, 5217711232U,
5226102656U, 5234490496U, 5242877312U, 5251263872U, 5259654016U,
5268040832U, 5276434304U, 5284819328U, 5293209728U, 5301598592U,
5309986688U, 5318374784U, 5326764416U, 5335151488U, 5343542144U,
5351929472U, 5360319872U, 5368706944U, 5377096576U, 5385484928U,
5393871232U, 5402263424U, 5410650496U, 5419040384U, 5427426944U,
5435816576U, 5444205952U, 5452594816U, 5460981376U, 5469367936U,
5477760896U, 5486148736U, 5494536832U, 5502925952U, 5511315328U,
5519703424U, 5528089984U, 5536481152U, 5544869504U, 5553256064U,
5561645696U, 5570032768U, 5578423936U, 5586811264U, 5595193216U,
5603585408U, 5611972736U, 5620366208U, 5628750464U, 5637143936U,
5645528192U, 5653921408U, 5662310272U, 5670694784U, 5679082624U,
5687474048U, 5695864448U, 5704251008U, 5712641408U, 5721030272U,
5729416832U, 5737806208U, 5746194304U, 5754583936U, 5762969984U,
5771358592U, 5779748224U, 5788137856U, 5796527488U, 5804911232U,
5813300608U, 5821692544U, 5830082176U, 5838468992U, 5846855552U,
5855247488U, 5863636096U, 5872024448U, 5880411008U, 5888799872U,
5897186432U, 5905576832U, 5913966976U, 5922352768U, 5930744704U,
5939132288U, 5947522432U, 5955911296U, 5964299392U, 5972688256U,
5981074304U, 5989465472U, 5997851008U, 6006241408U, 6014627968U,
6023015552U, 6031408256U, 6039796096U, 6048185216U, 6056574848U,
6064963456U, 6073351808U, 6081736064U, 6090128768U, 6098517632U,
6106906496U, 6115289216U, 6123680896U, 6132070016U, 6140459648U,
6148849024U, 6157237376U, 6165624704U, 6174009728U, 6182403712U,
6190792064U, 6199176064U, 6207569792U, 6215952256U, 6224345216U,
6232732544U, 6241124224U, 6249510272U, 6257899136U, 6266287744U,
6274676864U, 6283065728U, 6291454336U, 6299843456U, 6308232064U,
6316620928U, 6325006208U, 6333395584U, 6341784704U, 6350174848U,
6358562176U, 6366951296U, 6375337856U, 6383729536U, 6392119168U,
6400504192U, 6408895616U, 6417283456U, 6425673344U, 6434059136U,
6442444672U, 6450837376U, 6459223424U, 6467613056U, 6476004224U,
6484393088U, 6492781952U, 6501170048U, 6509555072U, 6517947008U,
6526336384U, 6534725504U, 6543112832U, 6551500672U, 6559888768U,
6568278656U, 6576662912U, 6585055616U, 6593443456U, 6601834112U,
6610219648U, 6618610304U, 6626999168U, 6635385472U, 6643777408U,
6652164224U, 6660552832U, 6668941952U, 6677330048U, 6685719424U,
6694107776U, 6702493568U, 6710882176U, 6719274112U, 6727662976U,
6736052096U, 6744437632U, 6752825984U, 6761213824U, 6769604224U,
6777993856U, 6786383488U, 6794770816U, 6803158144U, 6811549312U,
6819937664U, 6828326528U, 6836706176U, 6845101696U, 6853491328U,
6861880448U, 6870269312U, 6878655104U, 6887046272U, 6895433344U,
6903822208U, 6912212864U, 6920596864U, 6928988288U, 6937377152U,
6945764992U, 6954149248U, 6962544256U, 6970928768U, 6979317376U,
6987709312U, 6996093824U, 7004487296U, 7012875392U, 7021258624U,
7029652352U, 7038038912U, 7046427776U, 7054818944U, 7063207808U,
7071595136U, 7079980928U, 7088372608U, 7096759424U, 7105149824U,
7113536896U, 7121928064U, 7130315392U, 7138699648U, 7147092352U,
7155479168U, 7163865728U, 7172249984U, 7180648064U, 7189036672U,
7197424768U, 7205810816U, 7214196608U, 7222589824U, 7230975104U,
7239367552U, 7247755904U, 7256145536U, 7264533376U, 7272921472U,
7281308032U, 7289694848U, 7298088832U, 7306471808U, 7314864512U,
7323253888U, 7331643008U, 7340029568U, 7348419712U, 7356808832U,
7365196672U, 7373585792U, 7381973888U, 7390362752U, 7398750592U,
7407138944U, 7415528576U, 7423915648U, 7432302208U, 7440690304U,
7449080192U, 7457472128U, 7465860992U, 7474249088U, 7482635648U,
7491023744U, 7499412608U, 7507803008U, 7516192384U, 7524579968U,
7532967296U, 7541358464U, 7549745792U, 7558134656U, 7566524032U,
7574912896U, 7583300992U, 7591690112U, 7600075136U, 7608466816U,
7616854912U, 7625244544U, 7633629824U, 7642020992U, 7650410368U,
7658794112U, 7667187328U, 7675574912U, 7683961984U, 7692349568U,
7700739712U, 7709130368U, 7717519232U, 7725905536U, 7734295424U,
7742683264U, 7751069056U, 7759457408U, 7767849088U, 7776238208U,
7784626816U, 7793014912U, 7801405312U, 7809792128U, 7818179968U,
7826571136U, 7834957184U, 7843347328U, 7851732352U, 7860124544U,
7868512384U, 7876902016U, 7885287808U, 7893679744U, 7902067072U,
7910455936U, 7918844288U, 7927230848U, 7935622784U, 7944009344U,
7952400256U, 7960786048U, 7969176704U, 7977565312U, 7985953408U,
7994339968U, 8002730368U, 8011119488U, 8019508096U, 8027896192U,
8036285056U, 8044674688U, 8053062272U, 8061448832U, 8069838464U,
8078227328U, 8086616704U, 8095006592U, 8103393664U, 8111783552U,
8120171392U, 8128560256U, 8136949376U, 8145336704U, 8153726848U,
8162114944U, 8170503296U, 8178891904U, 8187280768U, 8195669632U,
8204058496U, 8212444544U, 8220834176U, 8229222272U, 8237612672U,
8246000768U, 8254389376U, 8262775168U, 8271167104U, 8279553664U,
8287944064U, 8296333184U, 8304715136U, 8313108352U, 8321497984U,
8329885568U, 8338274432U, 8346663296U, 8355052928U, 8363441536U,
8371828352U, 8380217984U, 8388606592U, 8396996224U, 8405384576U,
8413772672U, 8422161536U, 8430549376U, 8438939008U, 8447326592U,
8455715456U, 8464104832U, 8472492928U, 8480882048U, 8489270656U,
8497659776U, 8506045312U, 8514434944U, 8522823808U, 8531208832U,
8539602304U, 8547990656U, 8556378752U, 8564768384U, 8573154176U,
8581542784U, 8589933952U, 8598322816U, 8606705024U, 8615099264U,
8623487872U, 8631876992U, 8640264064U, 8648653952U, 8657040256U,
8665430656U, 8673820544U, 8682209152U, 8690592128U, 8698977152U,
8707374464U, 8715763328U, 8724151424U, 8732540032U, 8740928384U,
8749315712U, 8757704576U, 8766089344U, 8774480768U, 8782871936U,
8791260032U, 8799645824U, 8808034432U, 8816426368U, 8824812928U,
8833199488U, 8841591424U, 8849976448U, 8858366336U, 8866757248U,
8875147136U, 8883532928U, 8891923328U, 8900306816U, 8908700288U,
8917088384U, 8925478784U, 8933867392U, 8942250368U, 8950644608U,
8959032704U, 8967420544U, 8975809664U, 8984197504U, 8992584064U,
9000976256U, 9009362048U, 9017752448U, 9026141312U, 9034530688U,
9042917504U, 9051307904U, 9059694208U, 9068084864U, 9076471424U,
9084861824U, 9093250688U, 9101638528U, 9110027648U, 9118416512U,
9126803584U, 9135188096U, 9143581312U, 9151969664U, 9160356224U,
9168747136U, 9177134464U, 9185525632U, 9193910144U, 9202302848U,
9210690688U, 9219079552U, 9227465344U, 9235854464U, 9244244864U,
9252633472U, 9261021824U, 9269411456U, 9277799296U, 9286188928U,
9294574208U, 9302965888U, 9311351936U, 9319740032U, 9328131968U,
9336516736U, 9344907392U, 9353296768U, 9361685888U, 9370074752U,
9378463616U, 9386849408U, 9395239808U, 9403629184U, 9412016512U,
9420405376U, 9428795008U, 9437181568U, 9445570688U, 9453960832U,
9462346624U, 9470738048U, 9479121536U, 9487515008U, 9495903616U,
9504289664U, 9512678528U, 9521067904U, 9529456256U, 9537843584U,
9546233728U, 9554621312U, 9563011456U, 9571398784U, 9579788672U,
9588178304U, 9596567168U, 9604954496U, 9613343104U, 9621732992U,
9630121856U, 9638508416U, 9646898816U, 9655283584U, 9663675776U,
9672061312U, 9680449664U, 9688840064U, 9697230464U, 9705617536U,
9714003584U, 9722393984U, 9730772608U, 9739172224U, 9747561088U,
9755945344U, 9764338816U, 9772726144U, 9781116544U, 9789503872U,
9797892992U, 9806282624U, 9814670464U, 9823056512U, 9831439232U,
9839833984U, 9848224384U, 9856613504U, 9865000576U, 9873391232U,
9881772416U, 9890162816U, 9898556288U, 9906940544U, 9915333248U,
9923721088U, 9932108672U, 9940496512U, 9948888448U, 9957276544U,
9965666176U, 9974048384U, 9982441088U, 9990830464U, 9999219584U,
10007602816U, 10015996544U, 10024385152U, 10032774016U, 10041163648U,
10049548928U, 10057940096U, 10066329472U, 10074717824U, 10083105152U,
10091495296U, 10099878784U, 10108272256U, 10116660608U, 10125049216U,
10133437312U, 10141825664U, 10150213504U, 10158601088U, 10166991232U,
10175378816U, 10183766144U, 10192157312U, 10200545408U, 10208935552U,
10217322112U, 10225712768U, 10234099328U, 10242489472U, 10250876032U,
10259264896U, 10267656064U, 10276042624U, 10284429184U, 10292820352U,
10301209472U, 10309598848U, 10317987712U, 10326375296U, 10334763392U,
10343153536U, 10351541632U, 10359930752U, 10368318592U, 10376707456U,
10385096576U, 10393484672U, 10401867136U, 10410262144U, 10418647424U,
10427039104U, 10435425664U, 10443810176U, 10452203648U, 10460589952U,
10468982144U, 10477369472U, 10485759104U, 10494147712U, 10502533504U,
10510923392U, 10519313536U, 10527702656U, 10536091264U, 10544478592U,
10552867712U, 10561255808U, 10569642368U, 10578032768U, 10586423168U,
10594805632U, 10603200128U, 10611588992U, 10619976064U, 10628361344U,
10636754048U, 10645143424U, 10653531776U, 10661920384U, 10670307968U,
10678696832U, 10687086464U, 10695475072U, 10703863168U, 10712246144U,
10720639616U, 10729026688U, 10737414784U, 10745806208U, 10754190976U,
10762581376U, 10770971264U, 10779356288U, 10787747456U, 10796135552U,
10804525184U, 10812915584U, 10821301888U, 10829692288U, 10838078336U,
10846469248U, 10854858368U, 10863247232U, 10871631488U, 10880023424U,
10888412032U, 10896799616U, 10905188992U, 10913574016U, 10921964672U,
10930352768U, 10938742912U, 10947132544U, 10955518592U, 10963909504U,
10972298368U, 10980687488U, 10989074816U, 10997462912U, 11005851776U,
11014241152U, 11022627712U, 11031017344U, 11039403904U, 11047793024U,
11056184704U, 11064570752U, 11072960896U, 11081343872U, 11089737856U,
11098128256U, 11106514816U, 11114904448U, 11123293568U, 11131680128U,
11140065152U, 11148458368U, 11156845696U, 11165236864U, 11173624192U,
11182013824U, 11190402688U, 11198790784U, 11207179136U, 11215568768U,
11223957376U, 11232345728U, 11240734592U, 11249122688U, 11257511296U,
11265899648U, 11274285952U, 11282675584U, 11291065472U, 11299452544U,
11307842432U, 11316231296U, 11324616832U, 11333009024U, 11341395584U,
11349782656U, 11358172288U, 11366560384U, 11374950016U, 11383339648U,
11391721856U, 11400117376U, 11408504192U, 11416893568U, 11425283456U,
11433671552U, 11442061184U, 11450444672U, 11458837888U, 11467226752U,
11475611776U, 11484003968U, 11492392064U, 11500780672U, 11509169024U,
11517550976U, 11525944448U, 11534335616U, 11542724224U, 11551111808U,
11559500672U, 11567890304U, 11576277376U, 11584667008U, 11593056128U,
11601443456U, 11609830016U, 11618221952U, 11626607488U, 11634995072U,
11643387776U, 11651775104U, 11660161664U, 11668552576U, 11676940928U,
11685330304U, 11693718656U, 11702106496U, 11710496128U, 11718882688U,
11727273088U, 11735660416U, 11744050048U, 11752437376U, 11760824704U,
11769216128U, 11777604736U, 11785991296U, 11794381952U, 11802770048U,
11811157888U, 11819548544U, 11827932544U, 11836324736U, 11844713344U,
11853100928U, 11861486464U, 11869879936U, 11878268032U, 11886656896U,
11895044992U, 11903433088U, 11911822976U, 11920210816U, 11928600448U,
11936987264U, 11945375872U, 11953761152U, 11962151296U, 11970543488U,
11978928512U, 11987320448U, 11995708288U, 12004095104U, 12012486272U,
12020875136U, 12029255552U, 12037652096U, 12046039168U, 12054429568U,
12062813824U, 12071206528U, 12079594624U, 12087983744U, 12096371072U,
12104759936U, 12113147264U, 12121534592U, 12129924992U, 12138314624U,
12146703232U, 12155091584U, 12163481216U, 12171864704U, 12180255872U,
12188643968U, 12197034112U, 12205424512U, 12213811328U, 12222199424U,
12230590336U, 12238977664U, 12247365248U, 12255755392U, 12264143488U,
12272531584U, 12280920448U, 12289309568U, 12297694592U, 12306086528U,
12314475392U, 12322865024U, 12331253632U, 12339640448U, 12348029312U,
12356418944U, 12364805248U, 12373196672U, 12381580928U, 12389969024U,
12398357632U, 12406750592U, 12415138432U, 12423527552U, 12431916416U,
12440304512U, 12448692352U, 12457081216U, 12465467776U, 12473859968U,
12482245504U, 12490636672U, 12499025536U, 12507411584U, 12515801728U,
12524190592U, 12532577152U, 12540966272U, 12549354368U, 12557743232U,
12566129536U, 12574523264U, 12582911872U, 12591299456U, 12599688064U,
12608074624U, 12616463488U, 12624845696U, 12633239936U, 12641631616U,
12650019968U, 12658407296U, 12666795136U, 12675183232U, 12683574656U,
12691960192U, 12700350592U, 12708740224U, 12717128576U, 12725515904U,
12733906816U, 12742295168U, 12750680192U, 12759071872U, 12767460736U,
12775848832U, 12784236928U, 12792626816U, 12801014656U, 12809404288U,
12817789312U, 12826181504U, 12834568832U, 12842954624U, 12851345792U,
12859732352U, 12868122496U, 12876512128U, 12884901248U, 12893289088U,
12901672832U, 12910067584U, 12918455168U, 12926842496U, 12935232896U,
12943620736U, 12952009856U, 12960396928U, 12968786816U, 12977176192U,
12985563776U, 12993951104U, 13002341504U, 13010730368U, 13019115392U,
13027506304U, 13035895168U, 13044272512U, 13052673152U, 13061062528U,
13069446272U, 13077838976U, 13086227072U, 13094613632U, 13103000192U,
13111393664U, 13119782528U, 13128157568U, 13136559232U, 13144945024U,
13153329536U, 13161724288U, 13170111872U, 13178502784U, 13186884736U,
13195279744U, 13203667072U, 13212057472U, 13220445824U, 13228832128U,
13237221248U, 13245610624U, 13254000512U, 13262388352U, 13270777472U,
13279166336U, 13287553408U, 13295943296U, 13304331904U, 13312719488U,
13321108096U, 13329494656U, 13337885824U, 13346274944U, 13354663808U,
13363051136U, 13371439232U, 13379825024U, 13388210816U, 13396605056U,
13404995456U, 13413380224U, 13421771392U, 13430159744U, 13438546048U,
13446937216U, 13455326848U, 13463708288U, 13472103808U, 13480492672U,
13488875648U, 13497269888U, 13505657728U, 13514045312U, 13522435712U,
13530824576U, 13539210112U, 13547599232U, 13555989376U, 13564379008U,
13572766336U, 13581154432U, 13589544832U, 13597932928U, 13606320512U,
13614710656U, 13623097472U, 13631477632U, 13639874944U, 13648264064U,
13656652928U, 13665041792U, 13673430656U, 13681818496U, 13690207616U,
13698595712U, 13706982272U, 13715373184U, 13723762048U, 13732150144U,
13740536704U, 13748926592U, 13757316224U, 13765700992U, 13774090112U,
13782477952U, 13790869376U, 13799259008U, 13807647872U, 13816036736U,
13824425344U, 13832814208U, 13841202304U, 13849591424U, 13857978752U,
13866368896U, 13874754688U, 13883145344U, 13891533184U, 13899919232U,
13908311168U, 13916692096U, 13925085056U, 13933473152U, 13941866368U,
13950253696U, 13958643584U, 13967032192U, 13975417216U, 13983807616U,
13992197504U, 14000582272U, 14008973696U, 14017363072U, 14025752192U,
14034137984U, 14042528384U, 14050918016U, 14059301504U, 14067691648U,
14076083584U, 14084470144U, 14092852352U, 14101249664U, 14109635968U,
14118024832U, 14126407552U, 14134804352U, 14143188608U, 14151577984U,
14159968384U, 14168357248U, 14176741504U, 14185127296U, 14193521024U,
14201911424U, 14210301824U, 14218685056U, 14227067264U, 14235467392U,
14243855488U, 14252243072U, 14260630144U, 14269021568U, 14277409408U,
14285799296U, 14294187904U, 14302571392U, 14310961792U, 14319353728U,
14327738752U, 14336130944U, 14344518784U, 14352906368U, 14361296512U,
14369685376U, 14378071424U, 14386462592U, 14394848128U, 14403230848U,
14411627392U, 14420013952U, 14428402304U, 14436793472U, 14445181568U,
14453569664U, 14461959808U, 14470347904U, 14478737024U, 14487122816U,
14495511424U, 14503901824U, 14512291712U, 14520677504U, 14529064832U,
14537456768U, 14545845632U, 14554234496U, 14562618496U, 14571011456U,
14579398784U, 14587789184U, 14596172672U, 14604564608U, 14612953984U,
14621341312U, 14629724288U, 14638120832U, 14646503296U, 14654897536U,
14663284864U, 14671675264U, 14680061056U, 14688447616U, 14696835968U,
14705228416U, 14713616768U, 14722003328U, 14730392192U, 14738784128U,
14747172736U, 14755561088U, 14763947648U, 14772336512U, 14780725376U,
14789110144U, 14797499776U, 14805892736U, 14814276992U, 14822670208U,
14831056256U, 14839444352U, 14847836032U, 14856222848U, 14864612992U,
14872997504U, 14881388672U, 14889775744U, 14898165376U, 14906553472U,
14914944896U, 14923329664U, 14931721856U, 14940109696U, 14948497024U,
14956887424U, 14965276544U, 14973663616U, 14982053248U, 14990439808U,
14998830976U, 15007216768U, 15015605888U, 15023995264U, 15032385152U,
15040768384U, 15049154944U, 15057549184U, 15065939072U, 15074328448U,
15082715008U, 15091104128U, 15099493504U, 15107879296U, 15116269184U,
15124659584U, 15133042304U, 15141431936U, 15149824384U, 15158214272U,
15166602368U, 15174991232U, 15183378304U, 15191760512U, 15200154496U,
15208542592U, 15216931712U, 15225323392U, 15233708416U, 15242098048U,
15250489216U, 15258875264U, 15267265408U, 15275654528U, 15284043136U,
15292431488U, 15300819584U, 15309208192U, 15317596544U, 15325986176U,
15334374784U, 15342763648U, 15351151744U, 15359540608U, 15367929728U,
15376318336U, 15384706432U, 15393092992U, 15401481856U, 15409869952U,
15418258816U, 15426649984U, 15435037568U, 15443425664U, 15451815296U,
15460203392U, 15468589184U, 15476979328U, 15485369216U, 15493755776U,
15502146944U, 15510534272U, 15518924416U, 15527311232U, 15535699072U,
15544089472U, 15552478336U, 15560866688U, 15569254528U, 15577642624U,
15586031488U, 15594419072U, 15602809472U, 15611199104U, 15619586432U,
15627975296U, 15636364928U, 15644753792U, 15653141888U, 15661529216U,
15669918848U, 15678305152U, 15686696576U, 15695083136U, 15703474048U,
15711861632U, 15720251264U, 15728636288U, 15737027456U, 15745417088U,
15753804928U, 15762194048U, 15770582656U, 15778971008U, 15787358336U,
15795747712U, 15804132224U, 15812523392U, 15820909696U, 15829300096U,
15837691264U, 15846071936U, 15854466944U, 15862855808U, 15871244672U,
15879634816U, 15888020608U, 15896409728U, 15904799104U, 15913185152U,
15921577088U, 15929966464U, 15938354816U, 15946743424U, 15955129472U,
15963519872U, 15971907968U, 15980296064U, 15988684928U, 15997073024U,
16005460864U, 16013851264U, 16022241152U, 16030629248U, 16039012736U,
16047406976U, 16055794816U, 16064181376U, 16072571264U, 16080957824U,
16089346688U, 16097737856U, 16106125184U, 16114514816U, 16122904192U,
16131292544U, 16139678848U, 16148066944U, 16156453504U, 16164839552U,
16173236096U, 16181623424U, 16190012032U, 16198401152U, 16206790528U,
16215177344U, 16223567744U, 16231956352U, 16240344704U, 16248731008U,
16257117824U, 16265504384U, 16273898624U, 16282281856U, 16290668672U,
16299064192U, 16307449216U, 16315842176U, 16324230016U, 16332613504U,
16341006464U, 16349394304U, 16357783168U, 16366172288U, 16374561664U,
16382951296U, 16391337856U, 16399726208U, 16408116352U, 16416505472U,
16424892032U, 16433282176U, 16441668224U, 16450058624U, 16458448768U,
16466836864U, 16475224448U, 16483613056U, 16492001408U, 16500391808U,
16508779648U, 16517166976U, 16525555328U, 16533944192U, 16542330752U,
16550719616U, 16559110528U, 16567497088U, 16575888512U, 16584274816U,
16592665472U, 16601051008U, 16609442944U, 16617832064U, 16626218624U,
16634607488U, 16642996096U, 16651385728U, 16659773824U, 16668163712U,
16676552576U, 16684938112U, 16693328768U, 16701718144U, 16710095488U,
16718492288U, 16726883968U, 16735272832U, 16743661184U, 16752049792U,
16760436608U, 16768827008U, 16777214336U, 16785599104U, 16793992832U,
16802381696U, 16810768768U, 16819151744U, 16827542656U, 16835934848U,
16844323712U, 16852711552U, 16861101952U, 16869489536U, 16877876864U,
16886265728U, 16894653056U, 16903044736U, 16911431296U, 16919821696U,
16928207488U, 16936592768U, 16944987776U, 16953375616U, 16961763968U,
16970152832U, 16978540928U, 16986929536U, 16995319168U, 17003704448U,
17012096896U, 17020481152U, 17028870784U, 17037262208U, 17045649536U,
17054039936U, 17062426496U, 17070814336U, 17079205504U, 17087592064U,
17095978112U, 17104369024U, 17112759424U, 17121147776U, 17129536384U,
17137926016U, 17146314368U, 17154700928U, 17163089792U, 17171480192U,
17179864192U, 17188256896U, 17196644992U, 17205033856U, 17213423488U,
17221811072U, 17230198912U, 17238588032U, 17246976896U, 17255360384U,
17263754624U, 17272143232U, 17280530048U, 17288918912U, 17297309312U,
17305696384U, 17314085504U, 17322475136U, 17330863744U, 17339252096U,
17347640192U, 17356026496U, 17364413824U, 17372796544U, 17381190016U,
17389583488U, 17397972608U, 17406360704U, 17414748544U, 17423135872U,
17431527296U, 17439915904U, 17448303232U, 17456691584U, 17465081728U,
17473468288U, 17481857408U, 17490247552U, 17498635904U, 17507022464U,
17515409024U, 17523801728U, 17532189824U, 17540577664U, 17548966016U,
17557353344U, 17565741184U, 17574131584U, 17582519168U, 17590907008U,
17599296128U, 17607687808U, 17616076672U, 17624455808U, 17632852352U,
17641238656U, 17649630848U, 17658018944U, 17666403968U, 17674794112U,
17683178368U, 17691573376U, 17699962496U, 17708350592U, 17716739968U,
17725126528U, 17733517184U, 17741898112U, 17750293888U, 17758673024U,
17767070336U, 17775458432U, 17783848832U, 17792236928U, 17800625536U,
17809012352U, 17817402752U, 17825785984U, 17834178944U, 17842563968U,
17850955648U, 17859344512U, 17867732864U, 17876119424U, 17884511872U,
17892900224U, 17901287296U, 17909677696U, 17918058112U, 17926451072U,
17934843776U, 17943230848U, 17951609216U, 17960008576U, 17968397696U,
17976784256U, 17985175424U, 17993564032U, 18001952128U, 18010339712U,
18018728576U, 18027116672U, 18035503232U, 18043894144U, 18052283264U,
18060672128U, 18069056384U, 18077449856U, 18085837184U, 18094225792U,
18102613376U, 18111004544U, 18119388544U, 18127781248U, 18136170368U,
18144558976U, 18152947328U, 18161336192U, 18169724288U, 18178108544U,
18186498944U, 18194886784U, 18203275648U, 18211666048U, 18220048768U,
18228444544U, 18236833408U, 18245220736U
};
// Generated with the following Mathematica Code:
// GetCacheSizes[n_] := Module[{
// DataSetSizeBytesInit = 2^30,
// MixBytes = 128,
// DataSetGrowth = 2^23,
// HashBytes = 64,
// CacheMultiplier = 1024,
// j = 0},
// Reap[
// While[j < n,
// Module[{i = Floor[(DataSetSizeBytesInit + DataSetGrowth * j) / (CacheMultiplier * HashBytes)]},
// While[! PrimeQ[i], i--];
// Sow[i*HashBytes]; j++]]]][[2]][[1]]
const size_t cache_sizes[] = {
1048384U, 1055552U, 1064512U, 1072832U, 1080896U, 1089344U, 1096768U,
1104448U, 1113664U, 1121216U, 1130176U, 1138624U, 1146304U, 1155008U,
1162816U, 1171264U, 1179328U, 1187392U, 1195456U, 1203392U, 1210816U,
1220416U, 1227712U, 1236416U, 1244608U, 1253312U, 1261376U, 1268416U,
1277632U, 1285696U, 1294016U, 1302208U, 1310656U, 1318336U, 1326784U,
1334848U, 1342912U, 1350848U, 1359808U, 1366208U, 1376192U, 1383488U,
1392448U, 1400384U, 1408832U, 1416512U, 1425344U, 1433408U, 1440704U,
1449664U, 1458112U, 1466048U, 1474496U, 1482688U, 1490752U, 1498688U,
1507136U, 1515328U, 1523264U, 1531456U, 1539904U, 1547584U, 1556288U,
1564352U, 1572544U, 1580608U, 1588544U, 1596992U, 1605568U, 1612096U,
1621952U, 1630144U, 1637696U, 1645888U, 1654336U, 1662784U, 1671104U,
1679168U, 1686848U, 1695296U, 1702208U, 1711168U, 1720256U, 1727552U,
1736128U, 1744576U, 1751488U, 1760576U, 1769408U, 1777472U, 1785664U,
1793984U, 1801664U, 1810112U, 1818304U, 1826624U, 1834816U, 1842752U,
1851328U, 1858112U, 1867456U, 1875904U, 1883968U, 1892288U, 1899712U,
1908416U, 1916608U, 1924544U, 1932992U, 1940672U, 1948736U, 1956928U,
1965632U, 1973824U, 1982144U, 1989824U, 1998784U, 2006848U, 2014784U,
2022848U, 2031424U, 2038976U, 2047424U, 2055616U, 2064064U, 2072384U,
2080448U, 2088512U, 2095936U, 2104768U, 2113472U, 2121664U, 2127808U,
2137792U, 2146112U, 2153408U, 2162624U, 2170304U, 2178496U, 2186944U,
2195392U, 2203456U, 2211136U, 2219968U, 2227648U, 2236096U, 2244416U,
2250944U, 2260928U, 2268736U, 2276672U, 2283328U, 2293696U, 2301632U,
2309312U, 2317888U, 2325952U, 2334656U, 2342848U, 2350144U, 2358848U,
2366656U, 2375488U, 2383552U, 2391616U, 2400064U, 2407616U, 2415808U,
2424256U, 2432704U, 2439616U, 2448704U, 2457152U, 2464064U, 2473792U,
2482112U, 2489792U, 2497472U, 2506432U, 2514752U, 2522816U, 2531264U,
2539456U, 2547136U, 2555456U, 2564032U, 2572096U, 2578496U, 2587712U,
2595776U, 2604736U, 2613056U, 2620736U, 2629184U, 2637632U, 2645824U,
2653888U, 2662208U, 2670016U, 2678464U, 2686912U, 2694464U, 2703296U,
2710976U, 2719424U, 2727104U, 2736064U, 2743232U, 2752192U, 2760512U,
2768704U, 2777024U, 2785088U, 2792512U, 2800576U, 2809024U, 2817856U,
2826176U, 2833984U, 2840896U, 2850752U, 2858048U, 2867008U, 2875328U,
2883392U, 2891584U, 2899648U, 2908096U, 2915648U, 2924224U, 2932672U,
2940736U, 2948672U, 2956736U, 2964928U, 2973248U, 2981824U, 2988992U,
2997184U, 3005248U, 3013952U, 3022144U, 3030592U, 3037376U, 3046976U,
3055552U, 3063616U, 3070784U, 3079744U, 3087808U, 3096512U, 3103808U,
3111872U, 3121088U, 3128896U, 3137216U, 3144896U, 3153856U, 3161152U,
3169984U, 3178432U, 3186496U, 3194816U, 3203008U, 3210176U, 3218624U,
3227072U, 3235264U, 3243712U, 3250496U, 3259456U, 3268544U, 3276736U,
3283648U, 3292736U, 3301184U, 3308224U, 3317696U, 3324736U, 3333184U,
3342272U, 3348544U, 3357248U, 3365312U, 3374912U, 3383104U, 3390784U,
3399488U, 3407296U, 3414976U, 3424192U, 3432256U, 3440576U, 3448768U,
3456832U, 3464896U, 3473216U, 3480128U, 3489344U, 3497408U, 3505856U,
3514048U, 3521344U, 3530432U, 3538624U, 3546304U, 3555008U, 3563072U,
3571648U, 3579712U, 3587392U, 3595456U, 3603904U, 3612352U, 3620416U,
3628864U, 3636928U, 3645248U, 3652928U, 3660992U, 3669184U, 3677888U,
3685952U, 3694528U, 3702592U, 3710528U, 3719104U, 3727168U, 3735488U,
3742784U, 3751232U, 3759424U, 3765184U, 3775808U, 3783872U, 3792832U,
3800768U, 3808832U, 3816256U, 3825344U, 3832768U, 3841856U, 3849536U,
3857344U, 3866432U, 3874496U, 3882304U, 3890752U, 3899072U, 3907264U,
3914816U, 3923008U, 3930688U, 3939904U, 3947968U, 3956416U, 3964736U,
3972544U, 3981248U, 3988928U, 3997376U, 4005824U, 4012864U, 4020928U,
4030144U, 4038592U, 4045504U, 4054592U, 4063168U, 4071104U, 4079552U,
4087232U, 4095808U, 4103872U, 4111168U, 4120384U, 4127936U, 4136512U,
4144832U, 4153024U, 4160704U, 4169408U, 4177216U, 4186048U, 4193344U,
4202048U, 4210496U, 4217536U, 4227008U, 4235072U, 4243264U, 4251584U,
4259392U, 4267712U, 4275776U, 4284352U, 4291904U, 4300096U, 4307648U,
4316992U, 4325056U, 4333376U, 4341056U, 4349888U, 4357568U, 4366016U,
4374464U, 4382528U, 4390208U, 4398656U, 4407232U, 4413632U, 4423616U,
4431808U, 4439744U, 4447936U, 4455872U, 4463296U, 4472128U, 4480576U,
4489024U, 4497344U, 4505152U, 4512448U, 4520896U, 4530112U, 4537664U,
4546496U, 4554688U, 4562752U, 4570816U, 4579264U, 4586944U, 4595648U,
4603712U, 4611392U, 4619072U, 4628032U, 4635584U, 4643776U, 4652864U,
4660672U, 4669376U, 4677056U, 4684096U, 4693184U, 4702144U, 4710208U,
4718528U, 4726336U, 4734272U, 4742464U, 4750784U, 4759232U, 4767296U,
4775872U, 4783808U, 4791872U, 4797376U, 4808512U, 4816192U, 4825024U,
4832704U, 4841024U, 4849472U, 4856512U, 4865984U, 4874176U, 4882112U,
4889792U, 4898752U, 4906688U, 4913984U, 4922816U, 4931008U, 4938944U,
4946624U, 4955584U, 4964032U, 4972096U, 4980032U, 4988864U, 4997056U,
5004992U, 5012288U, 5020096U, 5029312U, 5037632U, 5045696U, 5052224U,
5062592U, 5070784U, 5078848U, 5086784U, 5095232U, 5100736U, 5111488U,
5119936U, 5127104U, 5136064U, 5143616U, 5151424U, 5160256U, 5168704U,
5175232U, 5185472U, 5192384U, 5199296U, 5209664U, 5218112U, 5225536U,
5233472U, 5242816U, 5250496U, 5258944U, 5267264U, 5274944U, 5283776U,
5290048U, 5300032U, 5308096U, 5316544U, 5323328U, 5331904U, 5340736U,
5349056U, 5356864U, 5365312U, 5372096U, 5381696U, 5390272U, 5398336U,
5405888U, 5413696U, 5422784U, 5430976U, 5439424U, 5446976U, 5455808U,
5463616U, 5471168U, 5480128U, 5488064U, 5494592U, 5504704U, 5513152U,
5521216U, 5529536U, 5536576U, 5544256U, 5554112U, 5559616U, 5570368U,
5577664U, 5586752U, 5594944U, 5603008U, 5611456U, 5619392U, 5627584U,
5634368U, 5643328U, 5651264U, 5659328U, 5667008U, 5675584U, 5684416U,
5692864U, 5701568U, 5709632U, 5717056U, 5725376U, 5734336U, 5740096U,
5750336U, 5758912U, 5766848U, 5775296U, 5782976U, 5790784U, 5799616U,
5807936U, 5815232U, 5823808U, 5832256U, 5840192U, 5848768U, 5856832U,
5864896U, 5873344U, 5879872U, 5888576U, 5897792U, 5905216U, 5914432U,
5920448U, 5930944U, 5938624U, 5947328U, 5955392U, 5963456U, 5971648U,
5979328U, 5988032U, 5995712U, 6003904U, 6012736U, 6021056U, 6029248U,
6037184U, 6045632U, 6053312U, 6061376U, 6070208U, 6077504U, 6086464U,
6094784U, 6101696U, 6110912U, 6118592U, 6127168U, 6135616U, 6143296U,
6150208U, 6158912U, 6168128U, 6175808U, 6182464U, 6192832U, 6201152U,
6209344U, 6217664U, 6224576U, 6233408U, 6241472U, 6249664U, 6258496U,
6266816U, 6275008U, 6281152U, 6291136U, 6299456U, 6306752U, 6314816U,
6323776U, 6332096U, 6339392U, 6348224U, 6356288U, 6364096U, 6373184U,
6381376U, 6389696U, 6397504U, 6404416U, 6413632U, 6421952U, 6430016U,
6437824U, 6446912U, 6454592U, 6463168U, 6471616U, 6478144U, 6487232U,
6496192U, 6504128U, 6511936U, 6520256U, 6528832U, 6536896U, 6544576U,
6553408U, 6561472U, 6569792U, 6577216U, 6586304U, 6592448U, 6601024U,
6610624U, 6619072U, 6627136U, 6634816U, 6643264U, 6650816U, 6659776U,
6667712U, 6675904U, 6682688U, 6691904U, 6700864U, 6709184U, 6717376U,
6724544U, 6733504U, 6741824U, 6749888U, 6756032U, 6766528U, 6773056U,
6782912U, 6790976U, 6798016U, 6807488U, 6815168U, 6823744U, 6832064U,
6840128U, 6847552U, 6855872U, 6864064U, 6872128U, 6880576U, 6889408U,
6897472U, 6905792U, 6913472U, 6920896U, 6930368U, 6938432U, 6946624U,
6953536U, 6963136U, 6971072U, 6979136U, 6986944U, 6995392U, 7003712U,
7012288U, 7019072U, 7028416U, 7036352U, 7044416U, 7051712U, 7060672U,
7069376U, 7077568U, 7085504U, 7092544U, 7102016U, 7110592U, 7118656U,
7126208U, 7135168U, 7143104U, 7150912U, 7159744U, 7167808U, 7175744U,
7184192U, 7191232U, 7200448U, 7207744U, 7216576U, 7224128U, 7233472U,
7241536U, 7249856U, 7256512U, 7264832U, 7274048U, 7282112U, 7290176U,
7298752U, 7306688U, 7315136U, 7322816U, 7331392U, 7339456U, 7347776U,
7356224U, 7364288U, 7371712U, 7380928U, 7387456U, 7396544U, 7404352U,
7413568U, 7421632U, 7429696U, 7436864U, 7446464U, 7454144U, 7461952U,
7470784U, 7478336U, 7487296U, 7495616U, 7503424U, 7511872U, 7520192U,
7527616U, 7536448U, 7544512U, 7551424U, 7560128U, 7568576U, 7577536U,
7583552U, 7592512U, 7600448U, 7610048U, 7618496U, 7626176U, 7634752U,
7642816U, 7651264U, 7659328U, 7667008U, 7675456U, 7683136U, 7691584U,
7700416U, 7707584U, 7716416U, 7724224U, 7733056U, 7740608U, 7749184U,
7756096U, 7765952U, 7774016U, 7781824U, 7790528U, 7798592U, 7805888U,
7814336U, 7822784U, 7831232U, 7839296U, 7847104U, 7855552U, 7863616U,
7872448U, 7880128U, 7888576U, 7896256U, 7905088U, 7912768U, 7920448U,
7928768U, 7937344U, 7945792U, 7953728U, 7959488U, 7970752U, 7978816U,
7987136U, 7994816U, 8003392U, 8011712U, 8019904U, 8027456U, 8035264U,
8044352U, 8052544U, 8060224U, 8069056U, 8076736U, 8084672U, 8093504U,
8101312U, 8110016U, 8117696U, 8125888U, 8134592U, 8142016U, 8149952U,
8159168U, 8166976U, 8175296U, 8183488U, 8191808U, 8199616U, 8207296U,
8216128U, 8224576U, 8232256U, 8241088U, 8248256U, 8257472U, 8264128U,
8273728U, 8281792U, 8290112U, 8297152U, 8305216U, 8314816U, 8322752U,
8330944U, 8339392U, 8347072U, 8355392U, 8363968U, 8371904U, 8379328U,
8388544U, 8394944U, 8404544U, 8412736U, 8421184U, 8429504U, 8437696U,
8445376U, 8452544U, 8460736U, 8470208U, 8478016U, 8486848U, 8494144U,
8503232U, 8511296U, 8519488U, 8527424U, 8534464U, 8543936U, 8552384U,
8558912U, 8568128U, 8575936U, 8584256U, 8593216U, 8601536U, 8608832U,
8616896U, 8625728U, 8634176U, 8641856U, 8649664U, 8658112U, 8666176U,
8674112U, 8682944U, 8691136U, 8699456U, 8707648U, 8716096U, 8724416U,
8732608U, 8740672U, 8748352U, 8756032U, 8764864U, 8773568U, 8781376U,
8789824U, 8796992U, 8806208U, 8814272U, 8822336U, 8830912U, 8838848U,
8847296U, 8854336U, 8863552U, 8871488U, 8879296U, 8887616U, 8894528U,
8904512U, 8911424U, 8920768U, 8928704U, 8936128U, 8944576U, 8953664U,
8960576U, 8970176U, 8977984U, 8986304U, 8994112U, 9002432U, 9011008U,
9018176U, 9026624U, 9035584U, 9043904U, 9052096U, 9059264U, 9068096U,
9075904U, 9084224U, 9092288U, 9100352U, 9108928U, 9116992U, 9125824U,
9133504U, 9141824U, 9150272U, 9157952U, 9164608U, 9174848U, 9182912U,
9190976U, 9199552U, 9205312U, 9215936U, 9222592U, 9232192U, 9240512U,
9248704U, 9256256U, 9264832U, 9272896U, 9281344U, 9288896U, 9297088U,
9305536U, 9313984U, 9322304U, 9329728U, 9337792U, 9346112U, 9355072U,
9363136U, 9371072U, 9378752U, 9387712U, 9395648U, 9404224U, 9411008U,
9420608U, 9428416U, 9436864U, 9445312U, 9453376U, 9460928U, 9468736U,
9477824U, 9485248U, 9493696U, 9502144U, 9509056U, 9518528U, 9527104U,
9535424U, 9543616U, 9551296U, 9559744U, 9568192U, 9576256U, 9584576U,
9591872U, 9600704U, 9608384U, 9615808U, 9624512U, 9633472U, 9641536U,
9649856U, 9658048U, 9665728U, 9674432U, 9682496U, 9691072U, 9699136U,
9707072U, 9715136U, 9722176U, 9732032U, 9740096U, 9747904U, 9756352U,
9764288U, 9771584U, 9780544U, 9789376U, 9796928U, 9804224U, 9813952U,
9822016U, 9829696U, 9838016U, 9845824U, 9852992U, 9863104U, 9870656U,
9878464U, 9887552U, 9895744U, 9903808U, 9912128U, 9920192U, 9927616U,
9936064U, 9944768U, 9952576U, 9960128U, 9969472U, 9977152U, 9985216U,
9994048U, 10001216U, 10007744U, 10018496U, 10026944U, 10035136U, 10042432U,
10051264U, 10059584U, 10067648U, 10075712U, 10083904U, 10091456U, 10100672U,
10108864U, 10116928U, 10124864U, 10133056U, 10140736U, 10149824U, 10156736U,
10165952U, 10173376U, 10182208U, 10190528U, 10198336U, 10206272U, 10213696U,
10223296U, 10231744U, 10238656U, 10247488U, 10256192U, 10263872U, 10272448U,
10280896U, 10288448U, 10296512U, 10305088U, 10313536U, 10321088U, 10330048U,
10337984U, 10346176U, 10354112U, 10362304U, 10369088U, 10377152U, 10386752U,
10394816U, 10403648U, 10411712U, 10418624U, 10427968U, 10436032U, 10444736U,
10452928U, 10459712U, 10468672U, 10476608U, 10484416U, 10491328U, 10501952U,
10509376U, 10517824U, 10526528U, 10534336U, 10542656U, 10549696U, 10559168U,
10566592U, 10575808U, 10583488U, 10590656U, 10599488U, 10607936U, 10616768U,
10624832U, 10630336U, 10640576U, 10649536U, 10655168U, 10665152U, 10674112U,
10682176U, 10690496U, 10698176U, 10705216U, 10715072U, 10722752U, 10731328U,
10739264U, 10746688U, 10754752U, 10761664U, 10770752U, 10779712U, 10787776U,
10796608U, 10803392U, 10812352U, 10821056U, 10828736U, 10837952U, 10846144U,
10853824U, 10861376U, 10869952U, 10877248U, 10887104U, 10895296U, 10903232U,
10910912U, 10918976U, 10927936U, 10935872U, 10944448U, 10952384U, 10960832U,
10968512U, 10977088U, 10985024U, 10992832U, 11000896U, 11009984U, 11018048U,
11026112U, 11034304U, 11042624U, 11050432U, 11058368U, 11064512U, 11075392U,
11083712U, 11091776U, 11099584U, 11107904U, 11115968U, 11124416U, 11131712U,
11141056U, 11148608U, 11157184U, 11165248U, 11173312U, 11180992U, 11189056U,
11197376U, 11206592U, 11214656U, 11222336U, 11230784U, 11238464U, 11246528U,
11254976U, 11263552U, 11271872U, 11279552U, 11288512U, 11296576U, 11304256U,
11312192U, 11320768U, 11329216U, 11336384U, 11345216U, 11352512U, 11362112U,
11369408U, 11378624U, 11386688U, 11394496U, 11402816U, 11411264U, 11418688U,
11427776U, 11435584U, 11444032U, 11452096U, 11459648U, 11467072U, 11476928U,
11484992U, 11493184U, 11500352U, 11509312U, 11517248U, 11524928U, 11534144U,
11542208U, 11550272U, 11556416U, 11566784U, 11574208U, 11581376U, 11589568U,
11599552U, 11607104U, 11616064U, 11623616U, 11632576U, 11639872U, 11648704U,
11657024U, 11664704U, 11672896U, 11681216U, 11689792U, 11697856U, 11705536U,
11714368U, 11722688U, 11730496U, 11737408U, 11745728U, 11754304U, 11763008U,
11770816U, 11779648U, 11788096U, 11795776U, 11804608U, 11812544U, 11820992U,
11829184U, 11837248U, 11844928U, 11852096U, 11860928U, 11869888U, 11878336U,
11886272U, 11894336U, 11902144U, 11910848U, 11919296U, 11925952U, 11934784U,
11943616U, 11951552U, 11960128U, 11968192U, 11976512U, 11983168U, 11992768U,
12000832U, 12008896U, 12016832U, 12025408U, 12033856U, 12042176U, 12049984U,
12058048U, 12066112U, 12073792U, 12082624U, 12091328U, 12098752U, 12106816U,
12115904U, 12124096U, 12131776U, 12140224U, 12148672U, 12156736U, 12164032U,
12173248U, 12181184U, 12186176U, 12197824U, 12205888U, 12213952U, 12218944U,
12230336U, 12238784U, 12246592U, 12254272U, 12262336U, 12269888U, 12279104U,
12287936U, 12295744U, 12304064U, 12312512U, 12319936U, 12328768U, 12337088U,
12344896U, 12352832U, 12361408U, 12368704U, 12377152U, 12384832U, 12394432U,
12402496U, 12409024U, 12417728U, 12426688U, 12433216U, 12443584U, 12450752U,
12459968U, 12468032U, 12475712U, 12484544U, 12492608U, 12500416U, 12508352U,
12517184U, 12525376U, 12532288U, 12541888U, 12549568U, 12556864U, 12565568U,
12574528U, 12582208U, 12590528U, 12598592U, 12607424U, 12615488U, 12623552U,
12631744U, 12638656U, 12647744U, 12656576U, 12664768U, 12672832U, 12680896U,
12688576U, 12697408U, 12704192U, 12713408U, 12721216U, 12729664U, 12738496U,
12745792U, 12754496U, 12762688U, 12769472U, 12779456U, 12787648U, 12795712U,
12804032U, 12812224U, 12819008U, 12828352U, 12836672U, 12844736U, 12851648U,
12859456U, 12868672U, 12877504U, 12885568U, 12892864U, 12902336U, 12909376U,
12918208U, 12926656U, 12934976U, 12942784U, 12951104U, 12959552U, 12967744U,
12976064U, 12984256U, 12991936U, 12999488U, 13007936U, 13016768U, 13021504U,
13033024U, 13041472U, 13049408U, 13057472U, 13065664U, 13072064U, 13081408U,
13089344U, 13098688U, 13107008U, 13115072U, 13122752U, 13130944U, 13139648U,
13147712U, 13155776U, 13162432U, 13172672U, 13180864U, 13188928U, 13196992U,
13203392U, 13213504U, 13219264U, 13228736U, 13236928U, 13244992U, 13253056U,
13262528U, 13269952U, 13278784U, 13285952U, 13295552U, 13303616U, 13311808U,
13319744U, 13328192U, 13336256U, 13344704U, 13352384U, 13360576U, 13369024U,
13377344U, 13385408U, 13393216U, 13401664U, 13410112U, 13418176U, 13426496U,
13434688U, 13442368U, 13451072U, 13459136U, 13466944U, 13475648U, 13482944U,
13491904U, 13500352U, 13508288U, 13516736U, 13524416U, 13532224U, 13541312U,
13549504U, 13556288U, 13564736U, 13573184U, 13581376U, 13587008U, 13598656U,
13605952U, 13612864U, 13622464U, 13631168U, 13639616U, 13647808U, 13655104U,
13663424U, 13671872U, 13680064U, 13688768U, 13696576U, 13705024U, 13712576U,
13721536U, 13729216U, 13737664U, 13746112U, 13753024U, 13759552U, 13770304U,
13777856U, 13786688U, 13793984U, 13802176U, 13811264U, 13819328U, 13827904U,
13835456U, 13844416U, 13851584U, 13860544U, 13868992U, 13877056U, 13884608U,
13893184U, 13901248U, 13909696U, 13917632U, 13925056U, 13934528U, 13942336U,
13950784U, 13959104U, 13966912U, 13975232U, 13982656U, 13991872U, 13999936U,
14007872U, 14016064U, 14024512U, 14032064U, 14040896U, 14049088U, 14057408U,
14065088U, 14072896U, 14081344U, 14089664U, 14097856U, 14106304U, 14114752U,
14122688U, 14130752U, 14138816U, 14147008U, 14155072U, 14163904U, 14170432U,
14180288U, 14187328U, 14196032U, 14204864U, 14212672U, 14220736U, 14229056U,
14237504U, 14245568U, 14253632U, 14261824U, 14269888U, 14278592U, 14286656U,
14293696U, 14302784U, 14309696U, 14317504U, 14326336U, 14335936U, 14343232U,
14352064U, 14359232U, 14368064U, 14376512U, 14384576U, 14393024U, 14401472U,
14409536U, 14416832U, 14424512U, 14433856U, 14440768U, 14449984U, 14458816U,
14465728U, 14474816U, 14482112U, 14491328U, 14499392U, 14506816U, 14516032U,
14524352U, 14531392U, 14540224U, 14547392U, 14556992U, 14565184U, 14573248U,
14580928U, 14588864U, 14596928U, 14606272U, 14613824U, 14622656U, 14630464U,
14638912U, 14646976U, 14655296U, 14661952U, 14671808U, 14679872U, 14687936U,
14696384U, 14704576U, 14710336U, 14720192U, 14729152U, 14736448U, 14745152U,
14752448U, 14761792U, 14769856U, 14777024U, 14785984U, 14792384U, 14802752U,
14810816U, 14819264U, 14827328U, 14835136U, 14843072U, 14851264U, 14860096U,
14867648U, 14876096U, 14884544U, 14892736U, 14900672U, 14907968U, 14917312U,
14924864U, 14933824U, 14939968U, 14950336U, 14957632U, 14966464U, 14974912U,
14982592U, 14991296U, 14999104U, 15006272U, 15015232U, 15023936U, 15031616U,
15040448U, 15047488U, 15055552U, 15063616U, 15073216U, 15079744U, 15088064U,
15097664U, 15105344U, 15113792U, 15122368U, 15130048U, 15137728U, 15146176U,
15154112U, 15162688U, 15171392U, 15179456U, 15187264U, 15194176U, 15204032U,
15212224U, 15220544U, 15227456U, 15237056U, 15245248U, 15253184U, 15261632U,
15269824U, 15277376U, 15285824U, 15293888U, 15301568U, 15310784U, 15318848U,
15325504U, 15335104U, 15343168U, 15350848U, 15359936U, 15367232U, 15373376U,
15384256U, 15392576U, 15400384U, 15408832U, 15417152U, 15424832U, 15433024U,
15441344U, 15449152U, 15457088U, 15466432U, 15474112U, 15482816U, 15488576U,
15499072U, 15505856U, 15514816U, 15523264U, 15531584U, 15540032U, 15547328U,
15553984U, 15564608U, 15571904U, 15579968U, 15589312U, 15597376U, 15605696U,
15612992U, 15621824U, 15630016U, 15638464U, 15646144U, 15654592U, 15662912U,
15671104U, 15677248U, 15686848U, 15693376U, 15701696U, 15712064U, 15720256U,
15728576U, 15736384U, 15744704U, 15752512U, 15761344U, 15769024U, 15777728U,
15785152U, 15793984U, 15802048U, 15809984U, 15817024U, 15825856U, 15834944U,
15843008U, 15849664U, 15859136U, 15866432U, 15876032U, 15884096U, 15892288U,
15900608U, 15908416U, 15916864U, 15924928U, 15930176U, 15941056U, 15949504U,
15957824U, 15965632U, 15973952U, 15982528U, 15990592U, 15998272U, 16006976U,
16012736U, 16023104U, 16031296U, 16039616U, 16048064U, 16055744U, 16064192U,
16071488U, 16080832U, 16088768U, 16097216U, 16104896U, 16112704U, 16121792U,
16129856U, 16138048U, 16146112U, 16154176U, 16162624U, 16170688U, 16177856U,
16186816U, 16195136U, 16202176U, 16211648U, 16220096U, 16228288U, 16235584U,
16244672U, 16252864U, 16260544U, 16269248U, 16277056U, 16285504U, 16291648U,
16301632U, 16309312U, 16318144U, 16326208U, 16333888U, 16342336U, 16351168U,
16359232U, 16367552U, 16375616U, 16383296U, 16391744U, 16398016U, 16407616U,
16415936U, 16424896U, 16432448U, 16440896U, 16449088U, 16457024U, 16465472U,
16474048U, 16481216U, 16490048U, 16498624U, 16505792U, 16513984U, 16523072U,
16531136U, 16538944U, 16547264U, 16555328U, 16563776U, 16570816U, 16578112U,
16587712U, 16596544U, 16604992U, 16613312U, 16620608U, 16629568U, 16637888U,
16645696U, 16653632U, 16661696U, 16669888U, 16677568U, 16686272U, 16695232U,
16703168U, 16710464U, 16719424U, 16726592U, 16733888U, 16744384U, 16752448U,
16760768U, 16768448U, 16776896U, 16785344U, 16793536U, 16801216U, 16809664U,
16818112U, 16826176U, 16833472U, 16842688U, 16850752U, 16859072U, 16866368U,
16875328U, 16883392U, 16891712U, 16899776U, 16907456U, 16915264U, 16924352U,
16931776U, 16940608U, 16949056U, 16957376U, 16965056U, 16973248U, 16981696U,
16990144U, 16997056U, 17005888U, 17014208U, 17021504U, 17031104U, 17039296U,
17046976U, 17055424U, 17062592U, 17070016U, 17079488U, 17087936U, 17096512U,
17104576U, 17113024U, 17121088U, 17129408U, 17136832U, 17145664U, 17152832U,
17161792U, 17170112U, 17177792U, 17186368U, 17194304U, 17202496U, 17211328U,
17218624U, 17227712U, 17233984U, 17243584U, 17251904U, 17259712U, 17266624U,
17276608U, 17284672U, 17292224U, 17301056U, 17309632U, 17317568U, 17326016U,
17333824U, 17342272U, 17350208U, 17358784U, 17366848U, 17374912U, 17382592U,
17390656U, 17399488U, 17406784U, 17413952U, 17423936U, 17432512U, 17440448U,
17447744U, 17456704U, 17464768U, 17472064U, 17481536U, 17489344U, 17495488U,
17505728U, 17513792U, 17522368U, 17530816U, 17538112U, 17546944U, 17555264U,
17563072U, 17569856U, 17579456U, 17587904U, 17596352U, 17603776U, 17611712U,
17620672U, 17628992U, 17637184U, 17645504U, 17653568U, 17661632U, 17669824U,
17677376U, 17686208U, 17693888U, 17702336U, 17710144U, 17718208U, 17726528U,
17734336U, 17743808U, 17751872U, 17759936U, 17766592U, 17776448U, 17784512U,
17791936U, 17801152U, 17809216U, 17817152U
};
#ifdef __cplusplus
}
#endif

@ -0,0 +1,74 @@
#pragma once
#include <stdint.h>
#include "compiler.h"
static const uint8_t BitReverseTable256[] =
{
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};
static inline uint32_t bitfn_swap32(uint32_t a) {
return (BitReverseTable256[a & 0xff] << 24) |
(BitReverseTable256[(a >> 8) & 0xff] << 16) |
(BitReverseTable256[(a >> 16) & 0xff] << 8) |
(BitReverseTable256[(a >> 24) & 0xff]);
}
static inline uint64_t bitfn_swap64(uint64_t a) {
return ((uint64_t) bitfn_swap32((uint32_t) (a >> 32))) |
(((uint64_t) bitfn_swap32((uint32_t) a)) << 32);
}
#if defined(__MINGW32__) || defined(_WIN32)
# define LITTLE_ENDIAN 1234
# define BYTE_ORDER LITTLE_ENDIAN
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
# include <sys/endian.h>
#elif defined(__OpenBSD__) || defined(__SVR4)
# include <sys/types.h>
#elif defined(__APPLE__)
# include <machine/endian.h>
#elif defined( BSD ) && (BSD >= 199103)
# include <machine/endian.h>
#elif defined( __QNXNTO__ ) && defined( __LITTLEENDIAN__ )
# define LITTLE_ENDIAN 1234
# define BYTE_ORDER LITTLE_ENDIAN
#elif defined( __QNXNTO__ ) && defined( __BIGENDIAN__ )
# define BIG_ENDIAN 1234
# define BYTE_ORDER BIG_ENDIAN
#else
# include <endian.h>
#endif
#if LITTLE_ENDIAN == BYTE_ORDER
#define fix_endian32(x) (x)
#define fix_endian64(x) (x)
#elif BIG_ENDIAN == BYTE_ORDER
#define fix_endian32(x) bitfn_swap32(x)
#define fix_endian64(x) bitfn_swap64(x)
#else
# error "endian not supported"
#endif // BYTE_ORDER

@ -0,0 +1,95 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ethash.h
* @date 2015
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stddef.h>
#include "compiler.h"
#define REVISION 20
#define DAGSIZE_BYTES_INIT 1073741824U // 2**30
#define DAG_GROWTH 8388608U // 2**23
#define CACHE_MULTIPLIER 1024
#define EPOCH_LENGTH 30000U
#define MIX_BYTES 128
#define DAG_PARENTS 256
#define CACHE_ROUNDS 3
#define ACCESSES 64
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ethash_params {
size_t full_size; // Size of full data set (in bytes, multiple of mix size (128)).
size_t cache_size; // Size of compute cache (in bytes, multiple of node size (64)).
} ethash_params;
typedef struct ethash_return_value {
uint8_t result[32];
uint8_t mix_hash[32];
} ethash_return_value;
size_t ethash_get_datasize(const uint32_t block_number);
size_t ethash_get_cachesize(const uint32_t block_number);
// initialize the parameters
static inline void ethash_params_init(ethash_params *params, const uint32_t block_number) {
params->full_size = ethash_get_datasize(block_number);
params->cache_size = ethash_get_cachesize(block_number);
}
typedef struct ethash_cache {
void *mem;
} ethash_cache;
void ethash_mkcache(ethash_cache *cache, ethash_params const *params, const uint8_t seed[32]);
void ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cache const *cache);
void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
static inline void ethash_prep_light(void *cache, ethash_params const *params, const uint8_t seed[32]) { ethash_cache c; c.mem = cache; ethash_mkcache(&c, params, seed); }
static inline void ethash_compute_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { ethash_cache c; c.mem = (void*)cache; ethash_light(ret, &c, params, header_hash, nonce); }
static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) { ethash_cache c; c.mem = (void*)cache; ethash_compute_full_data(full, params, &c); }
static inline void ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { ethash_full(ret, full, params, header_hash, nonce); }
static inline int ethash_check_difficulty(
const uint8_t hash[32],
const uint8_t difficulty[32]) {
// Difficulty is big endian
for (int i = 0; i < 32; i++) {
if (hash[i] == difficulty[i]) continue;
return hash[i] < difficulty[i];
}
return 0;
}
int ethash_quick_check_difficulty(
const uint8_t header_hash[32],
const uint64_t nonce,
const uint8_t mix_hash[32],
const uint8_t difficulty[32]);
#ifdef __cplusplus
}
#endif

@ -0,0 +1,38 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file fnv.h
* @author Matthew Wampler-Doty <negacthulhu@gmail.com>
* @date 2015
*/
#pragma once
#include <stdint.h>
#include "compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
#define FNV_PRIME 0x01000193
static inline uint32_t fnv_hash(const uint32_t x, const uint32_t y) {
return x*FNV_PRIME ^ y;
}
#ifdef __cplusplus
}
#endif

@ -0,0 +1,298 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file dash.cpp
* @author Tim Hughes <tim@twistedfury.com>
* @author Matthew Wampler-Doty
* @date 2015
*/
#include <assert.h>
#include <inttypes.h>
#include <stddef.h>
#include "ethash.h"
#include "fnv.h"
#include "endian.h"
#include "internal.h"
#include "data_sizes.h"
#ifdef WITH_CRYPTOPP
#include "sha3_cryptopp.h"
#else
#include "sha3.h"
#endif // WITH_CRYPTOPP
size_t ethash_get_datasize(const uint32_t block_number) {
assert(block_number / EPOCH_LENGTH < 500);
return dag_sizes[block_number / EPOCH_LENGTH];
}
size_t ethash_get_cachesize(const uint32_t block_number) {
assert(block_number / EPOCH_LENGTH < 500);
return cache_sizes[block_number / EPOCH_LENGTH];
}
// Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014)
// https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf
// SeqMemoHash(s, R, N)
void static ethash_compute_cache_nodes(
node *const nodes,
ethash_params const *params,
const uint8_t seed[32]) {
assert((params->cache_size % sizeof(node)) == 0);
uint32_t const num_nodes = (uint32_t)(params->cache_size / sizeof(node));
SHA3_512(nodes[0].bytes, seed, 32);
for (unsigned i = 1; i != num_nodes; ++i) {
SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64);
}
for (unsigned j = 0; j != CACHE_ROUNDS; j++) {
for (unsigned i = 0; i != num_nodes; i++) {
uint32_t const idx = nodes[i].words[0] % num_nodes;
node data;
data = nodes[(num_nodes - 1 + i) % num_nodes];
for (unsigned w = 0; w != NODE_WORDS; ++w)
{
data.words[w] ^= nodes[idx].words[w];
}
SHA3_512(nodes[i].bytes, data.bytes, sizeof(data));
}
}
// now perform endian conversion
#if BYTE_ORDER != LITTLE_ENDIAN
for (unsigned w = 0; w != (num_nodes*NODE_WORDS); ++w)
{
nodes->words[w] = fix_endian32(nodes->words[w]);
}
#endif
}
void ethash_mkcache(
ethash_cache *cache,
ethash_params const *params,
const uint8_t seed[32]) {
node *nodes = (node *) cache->mem;
ethash_compute_cache_nodes(nodes, params, seed);
}
void ethash_calculate_dag_item(
node *const ret,
const unsigned node_index,
const struct ethash_params *params,
const struct ethash_cache *cache) {
uint32_t num_parent_nodes = (uint32_t)(params->cache_size / sizeof(node));
node const *cache_nodes = (node const *) cache->mem;
node const *init = &cache_nodes[node_index % num_parent_nodes];
memcpy(ret, init, sizeof(node));
ret->words[0] ^= node_index;
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
#if defined(_M_X64) && ENABLE_SSE
__m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME);
__m128i xmm0 = ret->xmm[0];
__m128i xmm1 = ret->xmm[1];
__m128i xmm2 = ret->xmm[2];
__m128i xmm3 = ret->xmm[3];
#endif
for (unsigned i = 0; i != DAG_PARENTS; ++i)
{
uint32_t parent_index = ((node_index ^ i)*FNV_PRIME ^ ret->words[i % NODE_WORDS]) % num_parent_nodes;
node const *parent = &cache_nodes[parent_index];
#if defined(_M_X64) && ENABLE_SSE
{
xmm0 = _mm_mullo_epi32(xmm0, fnv_prime);
xmm1 = _mm_mullo_epi32(xmm1, fnv_prime);
xmm2 = _mm_mullo_epi32(xmm2, fnv_prime);
xmm3 = _mm_mullo_epi32(xmm3, fnv_prime);
xmm0 = _mm_xor_si128(xmm0, parent->xmm[0]);
xmm1 = _mm_xor_si128(xmm1, parent->xmm[1]);
xmm2 = _mm_xor_si128(xmm2, parent->xmm[2]);
xmm3 = _mm_xor_si128(xmm3, parent->xmm[3]);
// have to write to ret as values are used to compute index
ret->xmm[0] = xmm0;
ret->xmm[1] = xmm1;
ret->xmm[2] = xmm2;
ret->xmm[3] = xmm3;
}
#else
{
for (unsigned w = 0; w != NODE_WORDS; ++w) {
ret->words[w] = fnv_hash(ret->words[w], parent->words[w]);
}
}
#endif
}
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
}
void ethash_compute_full_data(
void *mem,
ethash_params const *params,
ethash_cache const *cache) {
assert((params->full_size % (sizeof(uint32_t) * MIX_WORDS)) == 0);
assert((params->full_size % sizeof(node)) == 0);
node *full_nodes = mem;
// now compute full nodes
for (unsigned n = 0; n != (params->full_size / sizeof(node)); ++n) {
ethash_calculate_dag_item(&(full_nodes[n]), n, params, cache);
}
}
static void ethash_hash(
ethash_return_value * ret,
node const *full_nodes,
ethash_cache const *cache,
ethash_params const *params,
const uint8_t header_hash[32],
const uint64_t nonce) {
assert((params->full_size % MIX_WORDS) == 0);
// pack hash and nonce together into first 40 bytes of s_mix
assert(sizeof(node)*8 == 512);
node s_mix[MIX_NODES + 1];
memcpy(s_mix[0].bytes, header_hash, 32);
#if BYTE_ORDER != LITTLE_ENDIAN
s_mix[0].double_words[4] = fix_endian64(nonce);
#else
s_mix[0].double_words[4] = nonce;
#endif
// compute sha3-512 hash and replicate across mix
SHA3_512(s_mix->bytes, s_mix->bytes, 40);
#if BYTE_ORDER != LITTLE_ENDIAN
for (unsigned w = 0; w != 16; ++w) {
s_mix[0].words[w] = fix_endian32(s_mix[0].words[w]);
}
#endif
node* const mix = s_mix + 1;
for (unsigned w = 0; w != MIX_WORDS; ++w) {
mix->words[w] = s_mix[0].words[w % NODE_WORDS];
}
unsigned const
page_size = sizeof(uint32_t) * MIX_WORDS,
num_full_pages = (unsigned)(params->full_size / page_size);
for (unsigned i = 0; i != ACCESSES; ++i)
{
uint32_t const index = ((s_mix->words[0] ^ i)*FNV_PRIME ^ mix->words[i % MIX_WORDS]) % num_full_pages;
for (unsigned n = 0; n != MIX_NODES; ++n)
{
const node * dag_node = &full_nodes[MIX_NODES * index + n];
if (!full_nodes) {
node tmp_node;
ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, params, cache);
dag_node = &tmp_node;
}
#if defined(_M_X64) && ENABLE_SSE
{
__m128i fnv_prime = _mm_set1_epi32(FNV_PRIME);
__m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]);
__m128i xmm1 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[1]);
__m128i xmm2 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[2]);
__m128i xmm3 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[3]);
mix[n].xmm[0] = _mm_xor_si128(xmm0, dag_node->xmm[0]);
mix[n].xmm[1] = _mm_xor_si128(xmm1, dag_node->xmm[1]);
mix[n].xmm[2] = _mm_xor_si128(xmm2, dag_node->xmm[2]);
mix[n].xmm[3] = _mm_xor_si128(xmm3, dag_node->xmm[3]);
}
#else
{
for (unsigned w = 0; w != NODE_WORDS; ++w) {
mix[n].words[w] = fnv_hash(mix[n].words[w], dag_node->words[w]);
}
}
#endif
}
}
// compress mix
for (unsigned w = 0; w != MIX_WORDS; w += 4)
{
uint32_t reduction = mix->words[w+0];
reduction = reduction*FNV_PRIME ^ mix->words[w+1];
reduction = reduction*FNV_PRIME ^ mix->words[w+2];
reduction = reduction*FNV_PRIME ^ mix->words[w+3];
mix->words[w/4] = reduction;
}
#if BYTE_ORDER != LITTLE_ENDIAN
for (unsigned w = 0; w != MIX_WORDS/4; ++w) {
mix->words[w] = fix_endian32(mix->words[w]);
}
#endif
memcpy(ret->mix_hash, mix->bytes, 32);
// final Keccak hash
SHA3_256(ret->result, s_mix->bytes, 64+32); // Keccak-256(s + compressed_mix)
}
void ethash_quick_hash(
uint8_t return_hash[32],
const uint8_t header_hash[32],
const uint64_t nonce,
const uint8_t mix_hash[32]) {
uint8_t buf[64+32];
memcpy(buf, header_hash, 32);
#if BYTE_ORDER != LITTLE_ENDIAN
nonce = fix_endian64(nonce);
#endif
memcpy(&(buf[32]), &nonce, 8);
SHA3_512(buf, buf, 40);
memcpy(&(buf[64]), mix_hash, 32);
SHA3_256(return_hash, buf, 64+32);
}
int ethash_quick_check_difficulty(
const uint8_t header_hash[32],
const uint64_t nonce,
const uint8_t mix_hash[32],
const uint8_t difficulty[32]) {
uint8_t return_hash[32];
ethash_quick_hash(return_hash, header_hash, nonce, mix_hash);
return ethash_check_difficulty(return_hash, difficulty);
}
void ethash_full(ethash_return_value * ret, void const *full_mem, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) {
ethash_hash(ret, (node const *) full_mem, NULL, params, previous_hash, nonce);
}
void ethash_light(ethash_return_value * ret, ethash_cache const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) {
ethash_hash(ret, NULL, cache, params, previous_hash, nonce);
}

@ -0,0 +1,48 @@
#pragma once
#include "compiler.h"
#include "endian.h"
#include "ethash.h"
#define ENABLE_SSE 1
#if defined(_M_X64) && ENABLE_SSE
#include <smmintrin.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
// compile time settings
#define NODE_WORDS (64/4)
#define MIX_WORDS (MIX_BYTES/4)
#define MIX_NODES (MIX_WORDS / NODE_WORDS)
#include <stdint.h>
typedef union node {
uint8_t bytes[NODE_WORDS * 4];
uint32_t words[NODE_WORDS];
uint64_t double_words[NODE_WORDS / 2];
#if defined(_M_X64) && ENABLE_SSE
__m128i xmm[NODE_WORDS/4];
#endif
} node;
void ethash_calculate_dag_item(
node *const ret,
const unsigned node_index,
ethash_params const *params,
ethash_cache const *cache
);
void ethash_quick_hash(
uint8_t return_hash[32],
const uint8_t header_hash[32],
const uint64_t nonce,
const uint8_t mix_hash[32]);
#ifdef __cplusplus
}
#endif

@ -0,0 +1,151 @@
/** libkeccak-tiny
*
* A single-file implementation of SHA-3 and SHAKE.
*
* Implementor: David Leon Gil
* License: CC0, attribution kindly requested. Blame taken too,
* but not liability.
*/
#include "sha3.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/******** The Keccak-f[1600] permutation ********/
/*** Constants. ***/
static const uint8_t rho[24] = \
{ 1, 3, 6, 10, 15, 21,
28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43,
62, 18, 39, 61, 20, 44};
static const uint8_t pi[24] = \
{10, 7, 11, 17, 18, 3,
5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2,
20, 14, 22, 9, 6, 1};
static const uint64_t RC[24] = \
{1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,
0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,
0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL,
0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,
0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL,
0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL};
/*** Helper macros to unroll the permutation. ***/
#define rol(x, s) (((x) << s) | ((x) >> (64 - s)))
#define REPEAT6(e) e e e e e e
#define REPEAT24(e) REPEAT6(e e e e)
#define REPEAT5(e) e e e e e
#define FOR5(v, s, e) \
v = 0; \
REPEAT5(e; v += s;)
/*** Keccak-f[1600] ***/
static inline void keccakf(void* state) {
uint64_t* a = (uint64_t*)state;
uint64_t b[5] = {0};
uint64_t t = 0;
uint8_t x, y;
for (int i = 0; i < 24; i++) {
// Theta
FOR5(x, 1,
b[x] = 0;
FOR5(y, 5,
b[x] ^= a[x + y]; ))
FOR5(x, 1,
FOR5(y, 5,
a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
// Rho and pi
t = a[1];
x = 0;
REPEAT24(b[0] = a[pi[x]];
a[pi[x]] = rol(t, rho[x]);
t = b[0];
x++; )
// Chi
FOR5(y,
5,
FOR5(x, 1,
b[x] = a[y + x];)
FOR5(x, 1,
a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
// Iota
a[0] ^= RC[i];
}
}
/******** The FIPS202-defined functions. ********/
/*** Some helper macros. ***/
#define _(S) do { S } while (0)
#define FOR(i, ST, L, S) \
_(for (size_t i = 0; i < L; i += ST) { S; })
#define mkapply_ds(NAME, S) \
static inline void NAME(uint8_t* dst, \
const uint8_t* src, \
size_t len) { \
FOR(i, 1, len, S); \
}
#define mkapply_sd(NAME, S) \
static inline void NAME(const uint8_t* src, \
uint8_t* dst, \
size_t len) { \
FOR(i, 1, len, S); \
}
mkapply_ds(xorin, dst[i] ^= src[i]) // xorin
mkapply_sd(setout, dst[i] = src[i]) // setout
#define P keccakf
#define Plen 200
// Fold P*F over the full blocks of an input.
#define foldP(I, L, F) \
while (L >= rate) { \
F(a, I, rate); \
P(a); \
I += rate; \
L -= rate; \
}
/** The sponge-based hash construction. **/
static inline int hash(uint8_t* out, size_t outlen,
const uint8_t* in, size_t inlen,
size_t rate, uint8_t delim) {
if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) {
return -1;
}
uint8_t a[Plen] = {0};
// Absorb input.
foldP(in, inlen, xorin);
// Xor in the DS and pad frame.
a[inlen] ^= delim;
a[rate - 1] ^= 0x80;
// Xor in the last block.
xorin(a, in, inlen);
// Apply P
P(a);
// Squeeze output.
foldP(out, outlen, setout);
setout(a, out, outlen);
memset(a, 0, 200);
return 0;
}
#define defsha3(bits) \
int sha3_##bits(uint8_t* out, size_t outlen, \
const uint8_t* in, size_t inlen) { \
if (outlen > (bits/8)) { \
return -1; \
} \
return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \
}
/*** FIPS202 SHA3 FOFs ***/
defsha3(256)
defsha3(512)

@ -0,0 +1,27 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "compiler.h"
#include <stdint.h>
#include <stdlib.h>
#define decsha3(bits) \
int sha3_##bits(uint8_t*, size_t, const uint8_t*, size_t);
decsha3(256)
decsha3(512)
static inline void SHA3_256(uint8_t * const ret, uint8_t const *data, const size_t size) {
sha3_256(ret, 32, data, size);
}
static inline void SHA3_512(uint8_t * const ret, uint8_t const *data, const size_t size) {
sha3_512(ret, 64, data, size);
}
#ifdef __cplusplus
}
#endif

@ -0,0 +1,34 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file sha3.cpp
* @author Tim Hughes <tim@twistedfury.com>
* @date 2015
*/
#include <stdint.h>
#include <cryptopp/sha3.h>
extern "C" {
void SHA3_256(uint8_t *const ret, const uint8_t *data, size_t size) {
CryptoPP::SHA3_256().CalculateDigest(ret, data, size);
}
void SHA3_512(uint8_t *const ret, const uint8_t *data, size_t size) {
CryptoPP::SHA3_512().CalculateDigest(ret, data, size);
}
}

@ -0,0 +1,15 @@
#pragma once
#include "compiler.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
void SHA3_256(uint8_t *const ret, const uint8_t *data, size_t size);
void SHA3_512(uint8_t *const ret, const uint8_t *data, size_t size);
#ifdef __cplusplus
}
#endif

@ -0,0 +1,41 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file util.c
* @author Tim Hughes <tim@twistedfury.com>
* @date 2015
*/
#include <stdarg.h>
#include <stdio.h>
#include "util.h"
#ifdef _MSC_VER
// foward declare without all of Windows.h
__declspec(dllimport) void __stdcall OutputDebugStringA(const char* lpOutputString);
void debugf(const char *str, ...)
{
va_list args;
va_start(args, str);
char buf[1<<16];
_vsnprintf_s(buf, sizeof(buf), sizeof(buf), str, args);
buf[sizeof(buf)-1] = '\0';
OutputDebugStringA(buf);
}
#endif

@ -0,0 +1,47 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file util.h
* @author Tim Hughes <tim@twistedfury.com>
* @date 2015
*/
#pragma once
#include <stdint.h>
#include "compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _MSC_VER
void debugf(const char *str, ...);
#else
#define debugf printf
#endif
static inline uint32_t min_u32(uint32_t a, uint32_t b)
{
return a < b ? a : b;
}
static inline uint32_t clamp_u32(uint32_t x, uint32_t min_, uint32_t max_)
{
return x < min_ ? min_ : (x > max_ ? max_ : x);
}
#ifdef __cplusplus
}
#endif

@ -0,0 +1,64 @@
#include <Python.h>
#include <alloca.h>
#include <stdint.h>
#include "../libethash/ethash.h"
static PyObject*
get_cache_size(PyObject* self, PyObject* args)
{
unsigned long block_number;
if (!PyArg_ParseTuple(args, "k", &block_number))
return 0;
return Py_BuildValue("i", ethash_get_cachesize(block_number));
}
static PyObject*
get_full_size(PyObject* self, PyObject* args)
{
unsigned long block_number;
if (!PyArg_ParseTuple(args, "k", &block_number))
return 0;
return Py_BuildValue("i", ethash_get_datasize(block_number));
}
static PyObject*
mkcache(PyObject* self, PyObject* args)
{
char * seed;
unsigned long cache_size;
int seed_len;
if (!PyArg_ParseTuple(args, "ks#", &cache_size, &seed, &seed_len))
return 0;
if (seed_len != 32)
{
PyErr_SetString(PyExc_ValueError,
"Seed must be 32 bytes long");
return 0;
}
printf("cache size: %lu\n", cache_size);
ethash_params params;
params.cache_size = (size_t) cache_size;
ethash_cache cache;
cache.mem = alloca(cache_size);
ethash_mkcache(&cache, &params, (uint8_t *) seed);
return PyString_FromStringAndSize(cache.mem, cache_size);
}
static PyMethodDef CoreMethods[] =
{
{"get_cache_size", get_cache_size, METH_VARARGS, "Get the cache size for a given block number"},
{"get_full_size", get_full_size, METH_VARARGS, "Get the full size for a given block number"},
{"mkcache", mkcache, METH_VARARGS, "Makes the cache for given parameters and seed hash"},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC
initcore(void)
{
(void) Py_InitModule("core", CoreMethods);
}

@ -0,0 +1,30 @@
IF( NOT Boost_FOUND )
find_package(Boost COMPONENTS unit_test_framework)
ENDIF()
IF( Boost_FOUND )
include_directories( ${Boost_INCLUDE_DIR} )
include_directories(../../src)
link_directories ( ${Boost_LIBRARY_DIRS} )
file(GLOB HEADERS "*.h")
ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK)
if (NOT CRYPTOPP_FOUND)
find_package (CryptoPP)
endif()
if (CRYPTOPP_FOUND)
add_definitions(-DWITH_CRYPTOPP)
endif()
add_executable (Test test.cpp ${HEADERS})
target_link_libraries (Test ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ${ETHHASH_LIBS})
if (CRYPTOPP_FOUND)
TARGET_LINK_LIBRARIES(Test ${CRYPTOPP_LIBRARIES})
endif()
enable_testing ()
add_test(NAME ethash COMMAND Test)
ENDIF()

@ -0,0 +1,214 @@
#include <iomanip>
#include <libethash/fnv.h>
#include <libethash/ethash.h>
#include <libethash/internal.h>
#ifdef WITH_CRYPTOPP
#include <libethash/sha3_cryptopp.h>
#else
#include <libethash/sha3.h>
#endif // WITH_CRYPTOPP
#define BOOST_TEST_MODULE Daggerhashimoto
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <iostream>
std::string bytesToHexString(const uint8_t *str, const size_t s) {
std::ostringstream ret;
for (int i = 0; i < s; ++i)
ret << std::hex << std::setfill('0') << std::setw(2) << std::nouppercase << (int) str[i];
return ret.str();
}
BOOST_AUTO_TEST_CASE(fnv_hash_check) {
uint32_t x = 1235U;
const uint32_t
y = 9999999U,
expected = (FNV_PRIME * x) ^ y;
x = fnv_hash(x, y);
BOOST_REQUIRE_MESSAGE(x == expected,
"\nexpected: " << expected << "\n"
<< "actual: " << x << "\n");
}
BOOST_AUTO_TEST_CASE(SHA256_check) {
uint8_t input[32], out[32];
memcpy(input, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
SHA3_256(out, input, 32);
const std::string
expected = "2b5ddf6f4d21c23de216f44d5e4bdc68e044b71897837ea74c83908be7037cd7",
actual = bytesToHexString(out, 32);
BOOST_REQUIRE_MESSAGE(expected == actual,
"\nexpected: " << expected.c_str() << "\n"
<< "actual: " << actual.c_str() << "\n");
}
BOOST_AUTO_TEST_CASE(SHA512_check) {
uint8_t input[64], out[64];
memcpy(input, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 64);
SHA3_512(out, input, 64);
const std::string
expected = "0be8a1d334b4655fe58c6b38789f984bb13225684e86b20517a55ab2386c7b61c306f25e0627c60064cecd6d80cd67a82b3890bd1289b7ceb473aad56a359405",
actual = bytesToHexString(out, 64);
BOOST_REQUIRE_MESSAGE(expected == actual,
"\nexpected: " << expected.c_str() << "\n"
<< "actual: " << actual.c_str() << "\n");
}
BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_check) {
ethash_params params;
ethash_params_init(&params, 0);
BOOST_REQUIRE_MESSAGE(params.full_size < DAGSIZE_BYTES_INIT,
"\nfull size: " << params.full_size << "\n"
<< "should be less than or equal to: " << DAGSIZE_BYTES_INIT << "\n");
BOOST_REQUIRE_MESSAGE(params.full_size + 20*MIX_BYTES >= DAGSIZE_BYTES_INIT,
"\nfull size + 20*MIX_BYTES: " << params.full_size + 20*MIX_BYTES << "\n"
<< "should be greater than or equal to: " << DAGSIZE_BYTES_INIT << "\n");
BOOST_REQUIRE_MESSAGE(params.cache_size < DAGSIZE_BYTES_INIT / 32,
"\ncache size: " << params.cache_size << "\n"
<< "should be less than or equal to: " << DAGSIZE_BYTES_INIT / 32 << "\n");
}
BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_calcifide_check) {
ethash_params params;
ethash_params_init(&params, 0);
const uint32_t expected_full_size = 1073739904;
const uint32_t expected_cache_size = 1048384;
BOOST_REQUIRE_MESSAGE(params.full_size == expected_full_size,
"\nexpected: " << expected_cache_size << "\n"
<< "actual: " << params.full_size << "\n");
BOOST_REQUIRE_MESSAGE(params.cache_size == expected_cache_size,
"\nexpected: " << expected_cache_size << "\n"
<< "actual: " << params.cache_size << "\n");
}
BOOST_AUTO_TEST_CASE(light_and_full_client_checks) {
ethash_params params;
uint8_t seed[32], hash[32];
ethash_return_value light_out, full_out;
memcpy(seed, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
memcpy(hash, "~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
ethash_params_init(&params, 0);
params.cache_size = 1024;
params.full_size = 1024 * 32;
ethash_cache cache;
cache.mem = alloca(params.cache_size);
ethash_mkcache(&cache, &params, seed);
node * full_mem = (node *) alloca(params.full_size);
ethash_compute_full_data(full_mem, &params, &cache);
{
const std::string
expected = "2da2b506f21070e1143d908e867962486d6b0a02e31d468fd5e3a7143aafa76a14201f63374314e2a6aaf84ad2eb57105dea3378378965a1b3873453bb2b78f9a8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995c259440b89fa3481c2c33171477c305c8e1e421f8d8f6d59585449d0034f3e421808d8da6bbd0b6378f567647cc6c4ba6c434592b198ad444e7284905b7c6adaf70bf43ec2daa7bd5e8951aa609ab472c124cf9eba3d38cff5091dc3f58409edcc386c743c3bd66f92408796ee1e82dd149eaefbf52b00ce33014a6eb3e50625413b072a58bc01da28262f42cbe4f87d4abc2bf287d15618405a1fe4e386fcdafbb171064bd99901d8f81dd6789396ce5e364ac944bbbd75a7827291c70b42d26385910cd53ca535ab29433dd5c5714d26e0dce95514c5ef866329c12e958097e84462197c2b32087849dab33e88b11da61d52f9dbc0b92cc61f742c07dbbf751c49d7678624ee60dfbe62e5e8c47a03d8247643f3d16ad8c8e663953bcda1f59d7e2d4a9bf0768e789432212621967a8f41121ad1df6ae1fa78782530695414c6213942865b2730375019105cae91a4c17a558d4b63059661d9f108362143107babe0b848de412e4da59168cce82bfbff3c99e022dd6ac1e559db991f2e3f7bb910cefd173e65ed00a8d5d416534e2c8416ff23977dbf3eb7180b75c71580d08ce95efeb9b0afe904ea12285a392aff0c8561ff79fca67f694a62b9e52377485c57cc3598d84cac0a9d27960de0cc31ff9bbfe455acaa62c8aa5d2cce96f345da9afe843d258a99c4eaf3650fc62efd81c7b81cd0d534d2d71eeda7a6e315d540b4473c80f8730037dc2ae3e47b986240cfc65ccc565f0d8cde0bc68a57e39a271dda57440b3598bee19f799611d25731a96b5dbbbefdff6f4f656161462633030d62560ea4e9c161cf78fc96a2ca5aaa32453a6c5dea206f766244e8c9d9a8dc61185ce37f1fc804459c5f07434f8ecb34141b8dcae7eae704c950b55556c5f40140c3714b45eddb02637513268778cbf937a33e4e33183685f9deb31ef54e90161e76d969587dd782eaa94e289420e7c2ee908517f5893a26fdb5873d68f92d118d4bcf98d7a4916794d6ab290045e30f9ea00ca547c584b8482b0331ba1539a0f2714fddc3a0b06b0cfbb6a607b8339c39bcfd6640b1f653e9d70ef6c985b",
actual = bytesToHexString((uint8_t const *) cache.mem, params.cache_size);
BOOST_REQUIRE_MESSAGE(expected == actual,
"\nexpected: " << expected.c_str() << "\n"
<< "actual: " << actual.c_str() << "\n");
}
{
node node;
ethash_calculate_dag_item(&node, 0, &params, &cache);
const std::string
actual = bytesToHexString((uint8_t const *) &node, sizeof(node)),
expected = "b1698f829f90b35455804e5185d78f549fcb1bdce2bee006d4d7e68eb154b596be1427769eb1c3c3e93180c760af75f81d1023da6a0ffbe321c153a7c0103597";
BOOST_REQUIRE_MESSAGE(actual == expected,
"\n" << "expected: " << expected.c_str() << "\n"
<< "actual: " << actual.c_str() << "\n");
}
{
for (int i = 0 ; i < params.full_size / sizeof(node) ; ++i ) {
for (uint32_t j = 0; j < 32; ++j) {
node expected_node;
ethash_calculate_dag_item(&expected_node, j, &params, &cache);
const std::string
actual = bytesToHexString((uint8_t const *) &(full_mem[j]), sizeof(node)),
expected = bytesToHexString((uint8_t const *) &expected_node, sizeof(node));
BOOST_REQUIRE_MESSAGE(actual == expected,
"\ni: " << j << "\n"
<< "expected: " << expected.c_str() << "\n"
<< "actual: " << actual.c_str() << "\n");
}
}
}
{
uint64_t nonce = 0x7c7c597c;
ethash_full(&full_out, full_mem, &params, hash, nonce);
ethash_light(&light_out, &cache, &params, hash, nonce);
const std::string
light_result_string = bytesToHexString(light_out.result, 32),
full_result_string = bytesToHexString(full_out.result, 32);
BOOST_REQUIRE_MESSAGE(light_result_string == full_result_string,
"\nlight result: " << light_result_string.c_str() << "\n"
<< "full result: " << full_result_string.c_str() << "\n");
const std::string
light_mix_hash_string = bytesToHexString(light_out.mix_hash, 32),
full_mix_hash_string = bytesToHexString(full_out.mix_hash, 32);
BOOST_REQUIRE_MESSAGE(full_mix_hash_string == light_mix_hash_string,
"\nlight mix hash: " << light_mix_hash_string.c_str() << "\n"
<< "full mix hash: " << full_mix_hash_string.c_str() << "\n");
uint8_t check_hash[32];
ethash_quick_hash(check_hash, hash, nonce, full_out.mix_hash);
const std::string check_hash_string = bytesToHexString(check_hash, 32);
BOOST_REQUIRE_MESSAGE(check_hash_string == full_result_string,
"\ncheck hash string: " << check_hash_string.c_str() << "\n"
<< "full result: " << full_result_string.c_str() << "\n");
}
{
ethash_full(&full_out, full_mem, &params, hash, 5);
std::string
light_result_string = bytesToHexString(light_out.result, 32),
full_result_string = bytesToHexString(full_out.result, 32);
BOOST_REQUIRE_MESSAGE(light_result_string != full_result_string,
"\nlight result and full result should differ: " << light_result_string.c_str() << "\n");
ethash_light(&light_out, &cache, &params, hash, 5);
light_result_string = bytesToHexString(light_out.result, 32);
BOOST_REQUIRE_MESSAGE(light_result_string == full_result_string,
"\nlight result and full result should be the same\n"
<< "light result: " << light_result_string.c_str() << "\n"
<< "full result: " << full_result_string.c_str() << "\n");
std::string
light_mix_hash_string = bytesToHexString(light_out.mix_hash, 32),
full_mix_hash_string = bytesToHexString(full_out.mix_hash, 32);
BOOST_REQUIRE_MESSAGE(full_mix_hash_string == light_mix_hash_string,
"\nlight mix hash: " << light_mix_hash_string.c_str() << "\n"
<< "full mix hash: " << full_mix_hash_string.c_str() << "\n");
}
}
BOOST_AUTO_TEST_CASE(ethash_check_difficulty_check) {
uint8_t hash[32], target[32];
memset(hash, 0, 32);
memset(target, 0, 32);
memcpy(hash, "11111111111111111111111111111111", 32);
memcpy(target, "22222222222222222222222222222222", 32);
BOOST_REQUIRE_MESSAGE(
ethash_check_difficulty(hash, target),
"\nexpected \"" << hash << "\" to have less difficulty than \"" << target << "\"\n");
BOOST_REQUIRE_MESSAGE(
!ethash_check_difficulty(hash, hash),
"\nexpected \"" << hash << "\" to have the same difficulty as \"" << hash << "\"\n");
memcpy(target, "11111111111111111111111111111112", 32);
BOOST_REQUIRE_MESSAGE(
ethash_check_difficulty(hash, target),
"\nexpected \"" << hash << "\" to have less difficulty than \"" << target << "\"\n");
memcpy(target, "11111111111111111111111111111110", 32);
BOOST_REQUIRE_MESSAGE(
!ethash_check_difficulty(hash, target),
"\nexpected \"" << hash << "\" to have more difficulty than \"" << target << "\"\n");
}

@ -0,0 +1,19 @@
#!/bin/bash
# Strict mode
set -e
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
done
TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
rm -rf $TEST_DIR/build
mkdir -p $TEST_DIR/build
cd $TEST_DIR/build ;
cmake ../../.. > /dev/null
make Test
./test/c/Test

@ -0,0 +1,2 @@
pyethereum==0.7.522
nose==1.3.4

@ -0,0 +1,19 @@
#!/bin/bash
# Strict mode
set -e
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
done
TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
[ -d $TEST_DIR/python-virtual-env ] || virtualenv --system-site-packages $TEST_DIR/python-virtual-env
source $TEST_DIR/python-virtual-env/bin/activate
pip install -r $TEST_DIR/requirements.txt > /dev/null
pip install -e $TEST_DIR/../.. > /dev/null
cd $TEST_DIR
nosetests --with-doctest -v

@ -0,0 +1,45 @@
import pyethash
from random import randint
def test_get_cache_size_not_None():
for _ in range(100):
block_num = randint(0,12456789)
out = pyethash.core.get_cache_size(block_num)
assert out != None
def test_get_full_size_not_None():
for _ in range(100):
block_num = randint(0,12456789)
out = pyethash.core.get_full_size(block_num)
assert out != None
def test_get_cache_size_based_on_EPOCH():
for _ in range(100):
block_num = randint(0,12456789)
out1 = pyethash.core.get_cache_size(block_num)
out2 = pyethash.core.get_cache_size((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH)
assert out1 == out2
def test_get_full_size_based_on_EPOCH():
for _ in range(100):
block_num = randint(0,12456789)
out1 = pyethash.core.get_full_size(block_num)
out2 = pyethash.core.get_full_size((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH)
assert out1 == out2
#def test_get_params_based_on_EPOCH():
# block_num = 123456
# out1 = pyethash.core.get_params(block_num)
# out2 = pyethash.core.get_params((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH)
# assert out1["DAG Size"] == out2["DAG Size"]
# assert out1["Cache Size"] == out2["Cache Size"]
#
#def test_get_params_returns_different_values_based_on_different_block_input():
# out1 = pyethash.core.get_params(123456)
# out2 = pyethash.core.get_params(12345)
# assert out1["DAG Size"] != out2["DAG Size"]
# assert out1["Cache Size"] != out2["Cache Size"]
#
#def test_get_cache_smoke_test():
# params = pyethash.core.get_params(123456)
# assert pyethash.core.mkcache(params, "~~~~") != None

@ -0,0 +1,26 @@
#!/bin/bash
# Strict mode
set -e
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
done
TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
echo -e "\n################# Testing JS ##################"
# TODO: Use mocha and real testing tools instead of rolling our own
cd $TEST_DIR/../js
node test.js
echo -e "\n################# Testing C ##################"
$TEST_DIR/c/test.sh
echo -e "\n################# Testing Python ##################"
$TEST_DIR/python/test.sh
#echo "################# Testing Go ##################"
#$TEST_DIR/go/test.sh

@ -0,0 +1,21 @@
Copyright © 2012 Peter Harris
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

@ -0,0 +1,95 @@
Liner
=====
Liner is a command line editor with history. It was inspired by linenoise;
everything Unix-like is a VT100 (or is trying very hard to be). If your
terminal is not pretending to be a VT100, change it. Liner also support
Windows.
Liner is released under the X11 license (which is similar to the new BSD
license).
Line Editing
------------
The following line editing commands are supported on platforms and terminals
that Liner supports:
Keystroke | Action
--------- | ------
Ctrl-A, Home | Move cursor to beginning of line
Ctrl-E, End | Move cursor to end of line
Ctrl-B, Left | Move cursor one character left
Ctrl-F, Right| Move cursor one character right
Ctrl-Left | Move cursor to previous word
Ctrl-Right | Move cursor to next word
Ctrl-D, Del | (if line is *not* empty) Delete character under cursor
Ctrl-D | (if line *is* empty) End of File - usually quits application
Ctrl-C | Reset input (create new empty prompt)
Ctrl-L | Clear screen (line is unmodified)
Ctrl-T | Transpose previous character with current character
Ctrl-H, BackSpace | Delete character before cursor
Ctrl-W | Delete word leading up to cursor
Ctrl-K | Delete from cursor to end of line
Ctrl-U | Delete from start of line to cursor
Ctrl-P, Up | Previous match from history
Ctrl-N, Down | Next match from history
Ctrl-R | Reverse Search history (Ctrl-S forward, Ctrl-G cancel)
Ctrl-Y | Paste from Yank buffer (Alt-Y to paste next yank instead)
Tab | Next completion
Shift-Tab | (after Tab) Previous completion
Getting started
-----------------
```go
package main
import (
"log"
"os"
"strings"
"github.com/peterh/liner"
)
var (
history_fn = "/tmp/.liner_history"
names = []string{"john", "james", "mary", "nancy"}
)
func main() {
line := liner.NewLiner()
defer line.Close()
line.SetCompleter(func(line string) (c []string) {
for _, n := range names {
if strings.HasPrefix(n, strings.ToLower(line)) {
c = append(c, n)
}
}
return
})
if f, err := os.Open(history_fn); err == nil {
line.ReadHistory(f)
f.Close()
}
if name, err := line.Prompt("What is your name? "); err != nil {
log.Print("Error reading line: ", err)
} else {
log.Print("Got: ", name)
line.AppendHistory(name)
}
if f, err := os.Create(history_fn); err != nil {
log.Print("Error writing history file: ", err)
} else {
line.WriteHistory(f)
f.Close()
}
}
```
For documentation, see http://godoc.org/github.com/peterh/liner

@ -0,0 +1,39 @@
// +build openbsd freebsd netbsd
package liner
import "syscall"
const (
getTermios = syscall.TIOCGETA
setTermios = syscall.TIOCSETA
)
const (
// Input flags
inpck = 0x010
istrip = 0x020
icrnl = 0x100
ixon = 0x200
// Output flags
opost = 0x1
// Control flags
cs8 = 0x300
// Local flags
isig = 0x080
icanon = 0x100
iexten = 0x400
)
type termios struct {
Iflag uint32
Oflag uint32
Cflag uint32
Lflag uint32
Cc [20]byte
Ispeed int32
Ospeed int32
}

@ -0,0 +1,219 @@
/*
Package liner implements a simple command line editor, inspired by linenoise
(https://github.com/antirez/linenoise/). This package supports WIN32 in
addition to the xterm codes supported by everything else.
*/
package liner
import (
"bufio"
"bytes"
"container/ring"
"errors"
"fmt"
"io"
"strings"
"sync"
"unicode/utf8"
)
type commonState struct {
terminalSupported bool
outputRedirected bool
inputRedirected bool
history []string
historyMutex sync.RWMutex
completer WordCompleter
columns int
killRing *ring.Ring
ctrlCAborts bool
r *bufio.Reader
tabStyle TabStyle
}
// TabStyle is used to select how tab completions are displayed.
type TabStyle int
// Two tab styles are currently available:
//
// TabCircular cycles through each completion item and displays it directly on
// the prompt
//
// TabPrints prints the list of completion items to the screen after a second
// tab key is pressed. This behaves similar to GNU readline and BASH (which
// uses readline)
const (
TabCircular TabStyle = iota
TabPrints
)
// ErrPromptAborted is returned from Prompt or PasswordPrompt when the user presses Ctrl-C
// if SetCtrlCAborts(true) has been called on the State
var ErrPromptAborted = errors.New("prompt aborted")
// ErrNotTerminalOutput is returned from Prompt or PasswordPrompt if the
// platform is normally supported, but stdout has been redirected
var ErrNotTerminalOutput = errors.New("standard output is not a terminal")
// Max elements to save on the killring
const KillRingMax = 60
// HistoryLimit is the maximum number of entries saved in the scrollback history.
const HistoryLimit = 1000
// ReadHistory reads scrollback history from r. Returns the number of lines
// read, and any read error (except io.EOF).
func (s *State) ReadHistory(r io.Reader) (num int, err error) {
s.historyMutex.Lock()
defer s.historyMutex.Unlock()
in := bufio.NewReader(r)
num = 0
for {
line, part, err := in.ReadLine()
if err == io.EOF {
break
}
if err != nil {
return num, err
}
if part {
return num, fmt.Errorf("line %d is too long", num+1)
}
if !utf8.Valid(line) {
return num, fmt.Errorf("invalid string at line %d", num+1)
}
num++
s.history = append(s.history, string(line))
if len(s.history) > HistoryLimit {
s.history = s.history[1:]
}
}
return num, nil
}
// WriteHistory writes scrollback history to w. Returns the number of lines
// successfully written, and any write error.
//
// Unlike the rest of liner's API, WriteHistory is safe to call
// from another goroutine while Prompt is in progress.
// This exception is to facilitate the saving of the history buffer
// during an unexpected exit (for example, due to Ctrl-C being invoked)
func (s *State) WriteHistory(w io.Writer) (num int, err error) {
s.historyMutex.RLock()
defer s.historyMutex.RUnlock()
for _, item := range s.history {
_, err := fmt.Fprintln(w, item)
if err != nil {
return num, err
}
num++
}
return num, nil
}
// AppendHistory appends an entry to the scrollback history. AppendHistory
// should be called iff Prompt returns a valid command.
func (s *State) AppendHistory(item string) {
s.historyMutex.Lock()
defer s.historyMutex.Unlock()
if len(s.history) > 0 {
if item == s.history[len(s.history)-1] {
return
}
}
s.history = append(s.history, item)
if len(s.history) > HistoryLimit {
s.history = s.history[1:]
}
}
// Returns the history lines starting with prefix
func (s *State) getHistoryByPrefix(prefix string) (ph []string) {
for _, h := range s.history {
if strings.HasPrefix(h, prefix) {
ph = append(ph, h)
}
}
return
}
// Returns the history lines matching the inteligent search
func (s *State) getHistoryByPattern(pattern string) (ph []string, pos []int) {
if pattern == "" {
return
}
for _, h := range s.history {
if i := strings.Index(h, pattern); i >= 0 {
ph = append(ph, h)
pos = append(pos, i)
}
}
return
}
// Completer takes the currently edited line content at the left of the cursor
// and returns a list of completion candidates.
// If the line is "Hello, wo!!!" and the cursor is before the first '!', "Hello, wo" is passed
// to the completer which may return {"Hello, world", "Hello, Word"} to have "Hello, world!!!".
type Completer func(line string) []string
// WordCompleter takes the currently edited line with the cursor position and
// returns the completion candidates for the partial word to be completed.
// If the line is "Hello, wo!!!" and the cursor is before the first '!', ("Hello, wo!!!", 9) is passed
// to the completer which may returns ("Hello, ", {"world", "Word"}, "!!!") to have "Hello, world!!!".
type WordCompleter func(line string, pos int) (head string, completions []string, tail string)
// SetCompleter sets the completion function that Liner will call to
// fetch completion candidates when the user presses tab.
func (s *State) SetCompleter(f Completer) {
if f == nil {
s.completer = nil
return
}
s.completer = func(line string, pos int) (string, []string, string) {
return "", f(line[:pos]), line[pos:]
}
}
// SetWordCompleter sets the completion function that Liner will call to
// fetch completion candidates when the user presses tab.
func (s *State) SetWordCompleter(f WordCompleter) {
s.completer = f
}
// SetTabCompletionStyle sets the behvavior when the Tab key is pressed
// for auto-completion. TabCircular is the default behavior and cycles
// through the list of candidates at the prompt. TabPrints will print
// the available completion candidates to the screen similar to BASH
// and GNU Readline
func (s *State) SetTabCompletionStyle(tabStyle TabStyle) {
s.tabStyle = tabStyle
}
// ModeApplier is the interface that wraps a representation of the terminal
// mode. ApplyMode sets the terminal to this mode.
type ModeApplier interface {
ApplyMode() error
}
// SetCtrlCAborts sets whether Prompt on a supported terminal will return an
// ErrPromptAborted when Ctrl-C is pressed. The default is false (will not
// return when Ctrl-C is pressed). Unsupported terminals typically raise SIGINT
// (and Prompt does not return) regardless of the value passed to SetCtrlCAborts.
func (s *State) SetCtrlCAborts(aborts bool) {
s.ctrlCAborts = aborts
}
func (s *State) promptUnsupported(p string) (string, error) {
if !s.inputRedirected {
fmt.Print(p)
}
linebuf, _, err := s.r.ReadLine()
if err != nil {
return "", err
}
return string(bytes.TrimSpace(linebuf)), nil
}

@ -0,0 +1,57 @@
// +build !windows,!linux,!darwin,!openbsd,!freebsd,!netbsd
package liner
import (
"bufio"
"errors"
"os"
)
// State represents an open terminal
type State struct {
commonState
}
// Prompt displays p, and then waits for user input. Prompt does not support
// line editing on this operating system.
func (s *State) Prompt(p string) (string, error) {
return s.promptUnsupported(p)
}
// PasswordPrompt is not supported in this OS.
func (s *State) PasswordPrompt(p string) (string, error) {
return "", errors.New("liner: function not supported in this terminal")
}
// NewLiner initializes a new *State
//
// Note that this operating system uses a fallback mode without line
// editing. Patches welcome.
func NewLiner() *State {
var s State
s.r = bufio.NewReader(os.Stdin)
return &s
}
// Close returns the terminal to its previous mode
func (s *State) Close() error {
return nil
}
// TerminalSupported returns false because line editing is not
// supported on this platform.
func TerminalSupported() bool {
return false
}
type noopMode struct{}
func (n noopMode) ApplyMode() error {
return nil
}
// TerminalMode returns a noop InputModeSetter on this platform.
func TerminalMode() (ModeApplier, error) {
return noopMode{}, nil
}

@ -0,0 +1,359 @@
// +build linux darwin openbsd freebsd netbsd
package liner
import (
"bufio"
"errors"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"time"
)
type nexter struct {
r rune
err error
}
// State represents an open terminal
type State struct {
commonState
origMode termios
defaultMode termios
next <-chan nexter
winch chan os.Signal
pending []rune
useCHA bool
}
// NewLiner initializes a new *State, and sets the terminal into raw mode. To
// restore the terminal to its previous state, call State.Close().
//
// Note if you are still using Go 1.0: NewLiner handles SIGWINCH, so it will
// leak a channel every time you call it. Therefore, it is recommened that you
// upgrade to a newer release of Go, or ensure that NewLiner is only called
// once.
func NewLiner() *State {
var s State
s.r = bufio.NewReader(os.Stdin)
s.terminalSupported = TerminalSupported()
if m, err := TerminalMode(); err == nil {
s.origMode = *m.(*termios)
} else {
s.terminalSupported = false
s.inputRedirected = true
}
if _, err := getMode(syscall.Stdout); err != 0 {
s.terminalSupported = false
s.outputRedirected = true
}
if s.terminalSupported {
mode := s.origMode
mode.Iflag &^= icrnl | inpck | istrip | ixon
mode.Cflag |= cs8
mode.Lflag &^= syscall.ECHO | icanon | iexten
mode.ApplyMode()
winch := make(chan os.Signal, 1)
signal.Notify(winch, syscall.SIGWINCH)
s.winch = winch
s.checkOutput()
}
if !s.outputRedirected {
s.getColumns()
s.outputRedirected = s.columns <= 0
}
return &s
}
var errTimedOut = errors.New("timeout")
func (s *State) startPrompt() {
if s.terminalSupported {
if m, err := TerminalMode(); err == nil {
s.defaultMode = *m.(*termios)
mode := s.defaultMode
mode.Lflag &^= isig
mode.ApplyMode()
}
}
s.restartPrompt()
}
func (s *State) restartPrompt() {
next := make(chan nexter)
go func() {
for {
var n nexter
n.r, _, n.err = s.r.ReadRune()
next <- n
// Shut down nexter loop when an end condition has been reached
if n.err != nil || n.r == '\n' || n.r == '\r' || n.r == ctrlC || n.r == ctrlD {
close(next)
return
}
}
}()
s.next = next
}
func (s *State) stopPrompt() {
if s.terminalSupported {
s.defaultMode.ApplyMode()
}
}
func (s *State) nextPending(timeout <-chan time.Time) (rune, error) {
select {
case thing, ok := <-s.next:
if !ok {
return 0, errors.New("liner: internal error")
}
if thing.err != nil {
return 0, thing.err
}
s.pending = append(s.pending, thing.r)
return thing.r, nil
case <-timeout:
rv := s.pending[0]
s.pending = s.pending[1:]
return rv, errTimedOut
}
// not reached
return 0, nil
}
func (s *State) readNext() (interface{}, error) {
if len(s.pending) > 0 {
rv := s.pending[0]
s.pending = s.pending[1:]
return rv, nil
}
var r rune
select {
case thing, ok := <-s.next:
if !ok {
return 0, errors.New("liner: internal error")
}
if thing.err != nil {
return nil, thing.err
}
r = thing.r
case <-s.winch:
s.getColumns()
return winch, nil
}
if r != esc {
return r, nil
}
s.pending = append(s.pending, r)
// Wait at most 50 ms for the rest of the escape sequence
// If nothing else arrives, it was an actual press of the esc key
timeout := time.After(50 * time.Millisecond)
flag, err := s.nextPending(timeout)
if err != nil {
if err == errTimedOut {
return flag, nil
}
return unknown, err
}
switch flag {
case '[':
code, err := s.nextPending(timeout)
if err != nil {
if err == errTimedOut {
return code, nil
}
return unknown, err
}
switch code {
case 'A':
s.pending = s.pending[:0] // escape code complete
return up, nil
case 'B':
s.pending = s.pending[:0] // escape code complete
return down, nil
case 'C':
s.pending = s.pending[:0] // escape code complete
return right, nil
case 'D':
s.pending = s.pending[:0] // escape code complete
return left, nil
case 'F':
s.pending = s.pending[:0] // escape code complete
return end, nil
case 'H':
s.pending = s.pending[:0] // escape code complete
return home, nil
case 'Z':
s.pending = s.pending[:0] // escape code complete
return shiftTab, nil
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
num := []rune{code}
for {
code, err := s.nextPending(timeout)
if err != nil {
if err == errTimedOut {
return code, nil
}
return nil, err
}
switch code {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
num = append(num, code)
case ';':
// Modifier code to follow
// This only supports Ctrl-left and Ctrl-right for now
x, _ := strconv.ParseInt(string(num), 10, 32)
if x != 1 {
// Can't be left or right
rv := s.pending[0]
s.pending = s.pending[1:]
return rv, nil
}
num = num[:0]
for {
code, err = s.nextPending(timeout)
if err != nil {
if err == errTimedOut {
rv := s.pending[0]
s.pending = s.pending[1:]
return rv, nil
}
return nil, err
}
switch code {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
num = append(num, code)
case 'C', 'D':
// right, left
mod, _ := strconv.ParseInt(string(num), 10, 32)
if mod != 5 {
// Not bare Ctrl
rv := s.pending[0]
s.pending = s.pending[1:]
return rv, nil
}
s.pending = s.pending[:0] // escape code complete
if code == 'C' {
return wordRight, nil
}
return wordLeft, nil
default:
// Not left or right
rv := s.pending[0]
s.pending = s.pending[1:]
return rv, nil
}
}
case '~':
s.pending = s.pending[:0] // escape code complete
x, _ := strconv.ParseInt(string(num), 10, 32)
switch x {
case 2:
return insert, nil
case 3:
return del, nil
case 5:
return pageUp, nil
case 6:
return pageDown, nil
case 7:
return home, nil
case 8:
return end, nil
case 15:
return f5, nil
case 17:
return f6, nil
case 18:
return f7, nil
case 19:
return f8, nil
case 20:
return f9, nil
case 21:
return f10, nil
case 23:
return f11, nil
case 24:
return f12, nil
default:
return unknown, nil
}
default:
// unrecognized escape code
rv := s.pending[0]
s.pending = s.pending[1:]
return rv, nil
}
}
}
case 'O':
code, err := s.nextPending(timeout)
if err != nil {
if err == errTimedOut {
return code, nil
}
return nil, err
}
s.pending = s.pending[:0] // escape code complete
switch code {
case 'c':
return wordRight, nil
case 'd':
return wordLeft, nil
case 'H':
return home, nil
case 'F':
return end, nil
case 'P':
return f1, nil
case 'Q':
return f2, nil
case 'R':
return f3, nil
case 'S':
return f4, nil
default:
return unknown, nil
}
case 'y':
s.pending = s.pending[:0] // escape code complete
return altY, nil
default:
rv := s.pending[0]
s.pending = s.pending[1:]
return rv, nil
}
// not reached
return r, nil
}
// Close returns the terminal to its previous mode
func (s *State) Close() error {
stopSignal(s.winch)
if s.terminalSupported {
s.origMode.ApplyMode()
}
return nil
}
// TerminalSupported returns true if the current terminal supports
// line editing features, and false if liner will use the 'dumb'
// fallback for input.
func TerminalSupported() bool {
bad := map[string]bool{"": true, "dumb": true, "cons25": true}
return !bad[strings.ToLower(os.Getenv("TERM"))]
}

@ -0,0 +1,39 @@
// +build darwin
package liner
import "syscall"
const (
getTermios = syscall.TIOCGETA
setTermios = syscall.TIOCSETA
)
const (
// Input flags
inpck = 0x010
istrip = 0x020
icrnl = 0x100
ixon = 0x200
// Output flags
opost = 0x1
// Control flags
cs8 = 0x300
// Local flags
isig = 0x080
icanon = 0x100
iexten = 0x400
)
type termios struct {
Iflag uintptr
Oflag uintptr
Cflag uintptr
Lflag uintptr
Cc [20]byte
Ispeed uintptr
Ospeed uintptr
}

@ -0,0 +1,26 @@
// +build linux
package liner
import "syscall"
const (
getTermios = syscall.TCGETS
setTermios = syscall.TCSETS
)
const (
icrnl = syscall.ICRNL
inpck = syscall.INPCK
istrip = syscall.ISTRIP
ixon = syscall.IXON
opost = syscall.OPOST
cs8 = syscall.CS8
isig = syscall.ISIG
icanon = syscall.ICANON
iexten = syscall.IEXTEN
)
type termios struct {
syscall.Termios
}

@ -0,0 +1,61 @@
// +build !windows
package liner
import (
"bufio"
"bytes"
"testing"
)
func (s *State) expectRune(t *testing.T, r rune) {
item, err := s.readNext()
if err != nil {
t.Fatalf("Expected rune '%c', got error %s\n", r, err)
}
if v, ok := item.(rune); !ok {
t.Fatalf("Expected rune '%c', got non-rune %v\n", r, v)
} else {
if v != r {
t.Fatalf("Expected rune '%c', got rune '%c'\n", r, v)
}
}
}
func (s *State) expectAction(t *testing.T, a action) {
item, err := s.readNext()
if err != nil {
t.Fatalf("Expected Action %d, got error %s\n", a, err)
}
if v, ok := item.(action); !ok {
t.Fatalf("Expected Action %d, got non-Action %v\n", a, v)
} else {
if v != a {
t.Fatalf("Expected Action %d, got Action %d\n", a, v)
}
}
}
func TestTypes(t *testing.T) {
input := []byte{'A', 27, 'B', 27, 91, 68, 27, '[', '1', ';', '5', 'D', 'e'}
var s State
s.r = bufio.NewReader(bytes.NewBuffer(input))
next := make(chan nexter)
go func() {
for {
var n nexter
n.r, _, n.err = s.r.ReadRune()
next <- n
}
}()
s.next = next
s.expectRune(t, 'A')
s.expectRune(t, 27)
s.expectRune(t, 'B')
s.expectAction(t, left)
s.expectAction(t, wordLeft)
s.expectRune(t, 'e')
}

@ -0,0 +1,313 @@
package liner
import (
"bufio"
"os"
"syscall"
"unsafe"
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetStdHandle = kernel32.NewProc("GetStdHandle")
procReadConsoleInput = kernel32.NewProc("ReadConsoleInputW")
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
)
// These names are from the Win32 api, so they use underscores (contrary to
// what golint suggests)
const (
std_input_handle = uint32(-10 & 0xFFFFFFFF)
std_output_handle = uint32(-11 & 0xFFFFFFFF)
std_error_handle = uint32(-12 & 0xFFFFFFFF)
invalid_handle_value = ^uintptr(0)
)
type inputMode uint32
// State represents an open terminal
type State struct {
commonState
handle syscall.Handle
hOut syscall.Handle
origMode inputMode
defaultMode inputMode
key interface{}
repeat uint16
}
const (
enableEchoInput = 0x4
enableInsertMode = 0x20
enableLineInput = 0x2
enableMouseInput = 0x10
enableProcessedInput = 0x1
enableQuickEditMode = 0x40
enableWindowInput = 0x8
)
// NewLiner initializes a new *State, and sets the terminal into raw mode. To
// restore the terminal to its previous state, call State.Close().
func NewLiner() *State {
var s State
hIn, _, _ := procGetStdHandle.Call(uintptr(std_input_handle))
s.handle = syscall.Handle(hIn)
hOut, _, _ := procGetStdHandle.Call(uintptr(std_output_handle))
s.hOut = syscall.Handle(hOut)
s.terminalSupported = true
if m, err := TerminalMode(); err == nil {
s.origMode = m.(inputMode)
mode := s.origMode
mode &^= enableEchoInput
mode &^= enableInsertMode
mode &^= enableLineInput
mode &^= enableMouseInput
mode |= enableWindowInput
mode.ApplyMode()
} else {
s.inputRedirected = true
s.r = bufio.NewReader(os.Stdin)
}
s.getColumns()
s.outputRedirected = s.columns <= 0
return &s
}
// These names are from the Win32 api, so they use underscores (contrary to
// what golint suggests)
const (
focus_event = 0x0010
key_event = 0x0001
menu_event = 0x0008
mouse_event = 0x0002
window_buffer_size_event = 0x0004
)
type input_record struct {
eventType uint16
pad uint16
blob [16]byte
}
type key_event_record struct {
KeyDown int32
RepeatCount uint16
VirtualKeyCode uint16
VirtualScanCode uint16
Char int16
ControlKeyState uint32
}
// These names are from the Win32 api, so they use underscores (contrary to
// what golint suggests)
const (
vk_tab = 0x09
vk_prior = 0x21
vk_next = 0x22
vk_end = 0x23
vk_home = 0x24
vk_left = 0x25
vk_up = 0x26
vk_right = 0x27
vk_down = 0x28
vk_insert = 0x2d
vk_delete = 0x2e
vk_f1 = 0x70
vk_f2 = 0x71
vk_f3 = 0x72
vk_f4 = 0x73
vk_f5 = 0x74
vk_f6 = 0x75
vk_f7 = 0x76
vk_f8 = 0x77
vk_f9 = 0x78
vk_f10 = 0x79
vk_f11 = 0x7a
vk_f12 = 0x7b
yKey = 0x59
)
const (
shiftPressed = 0x0010
leftAltPressed = 0x0002
leftCtrlPressed = 0x0008
rightAltPressed = 0x0001
rightCtrlPressed = 0x0004
modKeys = shiftPressed | leftAltPressed | rightAltPressed | leftCtrlPressed | rightCtrlPressed
)
func (s *State) readNext() (interface{}, error) {
if s.repeat > 0 {
s.repeat--
return s.key, nil
}
var input input_record
pbuf := uintptr(unsafe.Pointer(&input))
var rv uint32
prv := uintptr(unsafe.Pointer(&rv))
for {
ok, _, err := procReadConsoleInput.Call(uintptr(s.handle), pbuf, 1, prv)
if ok == 0 {
return nil, err
}
if input.eventType == window_buffer_size_event {
xy := (*coord)(unsafe.Pointer(&input.blob[0]))
s.columns = int(xy.x)
return winch, nil
}
if input.eventType != key_event {
continue
}
ke := (*key_event_record)(unsafe.Pointer(&input.blob[0]))
if ke.KeyDown == 0 {
continue
}
if ke.VirtualKeyCode == vk_tab && ke.ControlKeyState&modKeys == shiftPressed {
s.key = shiftTab
} else if ke.VirtualKeyCode == yKey && (ke.ControlKeyState&modKeys == leftAltPressed ||
ke.ControlKeyState&modKeys == rightAltPressed) {
s.key = altY
} else if ke.Char > 0 {
s.key = rune(ke.Char)
} else {
switch ke.VirtualKeyCode {
case vk_prior:
s.key = pageUp
case vk_next:
s.key = pageDown
case vk_end:
s.key = end
case vk_home:
s.key = home
case vk_left:
s.key = left
if ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) != 0 {
if ke.ControlKeyState&modKeys == ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) {
s.key = wordLeft
}
}
case vk_right:
s.key = right
if ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) != 0 {
if ke.ControlKeyState&modKeys == ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) {
s.key = wordRight
}
}
case vk_up:
s.key = up
case vk_down:
s.key = down
case vk_insert:
s.key = insert
case vk_delete:
s.key = del
case vk_f1:
s.key = f1
case vk_f2:
s.key = f2
case vk_f3:
s.key = f3
case vk_f4:
s.key = f4
case vk_f5:
s.key = f5
case vk_f6:
s.key = f6
case vk_f7:
s.key = f7
case vk_f8:
s.key = f8
case vk_f9:
s.key = f9
case vk_f10:
s.key = f10
case vk_f11:
s.key = f11
case vk_f12:
s.key = f12
default:
// Eat modifier keys
// TODO: return Action(Unknown) if the key isn't a
// modifier.
continue
}
}
if ke.RepeatCount > 1 {
s.repeat = ke.RepeatCount - 1
}
return s.key, nil
}
return unknown, nil
}
// Close returns the terminal to its previous mode
func (s *State) Close() error {
s.origMode.ApplyMode()
return nil
}
func (s *State) startPrompt() {
if m, err := TerminalMode(); err == nil {
s.defaultMode = m.(inputMode)
mode := s.defaultMode
mode &^= enableProcessedInput
mode.ApplyMode()
}
}
func (s *State) restartPrompt() {
}
func (s *State) stopPrompt() {
s.defaultMode.ApplyMode()
}
// TerminalSupported returns true because line editing is always
// supported on Windows.
func TerminalSupported() bool {
return true
}
func (mode inputMode) ApplyMode() error {
hIn, _, err := procGetStdHandle.Call(uintptr(std_input_handle))
if hIn == invalid_handle_value || hIn == 0 {
return err
}
ok, _, err := procSetConsoleMode.Call(hIn, uintptr(mode))
if ok != 0 {
err = nil
}
return err
}
// TerminalMode returns the current terminal input mode as an InputModeSetter.
//
// This function is provided for convenience, and should
// not be necessary for most users of liner.
func TerminalMode() (ModeApplier, error) {
var mode inputMode
hIn, _, err := procGetStdHandle.Call(uintptr(std_input_handle))
if hIn == invalid_handle_value || hIn == 0 {
return nil, err
}
ok, _, err := procGetConsoleMode.Call(hIn, uintptr(unsafe.Pointer(&mode)))
if ok != 0 {
err = nil
}
return mode, err
}

@ -0,0 +1,864 @@
// +build windows linux darwin openbsd freebsd netbsd
package liner
import (
"container/ring"
"errors"
"fmt"
"io"
"strings"
"unicode"
"unicode/utf8"
)
type action int
const (
left action = iota
right
up
down
home
end
insert
del
pageUp
pageDown
f1
f2
f3
f4
f5
f6
f7
f8
f9
f10
f11
f12
altY
shiftTab
wordLeft
wordRight
winch
unknown
)
const (
ctrlA = 1
ctrlB = 2
ctrlC = 3
ctrlD = 4
ctrlE = 5
ctrlF = 6
ctrlG = 7
ctrlH = 8
tab = 9
lf = 10
ctrlK = 11
ctrlL = 12
cr = 13
ctrlN = 14
ctrlO = 15
ctrlP = 16
ctrlQ = 17
ctrlR = 18
ctrlS = 19
ctrlT = 20
ctrlU = 21
ctrlV = 22
ctrlW = 23
ctrlX = 24
ctrlY = 25
ctrlZ = 26
esc = 27
bs = 127
)
const (
beep = "\a"
)
type tabDirection int
const (
tabForward tabDirection = iota
tabReverse
)
func (s *State) refresh(prompt []rune, buf []rune, pos int) error {
s.cursorPos(0)
_, err := fmt.Print(string(prompt))
if err != nil {
return err
}
pLen := countGlyphs(prompt)
bLen := countGlyphs(buf)
pos = countGlyphs(buf[:pos])
if pLen+bLen < s.columns {
_, err = fmt.Print(string(buf))
s.eraseLine()
s.cursorPos(pLen + pos)
} else {
// Find space available
space := s.columns - pLen
space-- // space for cursor
start := pos - space/2
end := start + space
if end > bLen {
end = bLen
start = end - space
}
if start < 0 {
start = 0
end = space
}
pos -= start
// Leave space for markers
if start > 0 {
start++
}
if end < bLen {
end--
}
startRune := len(getPrefixGlyphs(buf, start))
line := getPrefixGlyphs(buf[startRune:], end-start)
// Output
if start > 0 {
fmt.Print("{")
}
fmt.Print(string(line))
if end < bLen {
fmt.Print("}")
}
// Set cursor position
s.eraseLine()
s.cursorPos(pLen + pos)
}
return err
}
func longestCommonPrefix(strs []string) string {
if len(strs) == 0 {
return ""
}
longest := strs[0]
for _, str := range strs[1:] {
for !strings.HasPrefix(str, longest) {
longest = longest[:len(longest)-1]
}
}
// Remove trailing partial runes
longest = strings.TrimRight(longest, "\uFFFD")
return longest
}
func (s *State) circularTabs(items []string) func(tabDirection) (string, error) {
item := -1
return func(direction tabDirection) (string, error) {
if direction == tabForward {
if item < len(items)-1 {
item++
} else {
item = 0
}
} else if direction == tabReverse {
if item > 0 {
item--
} else {
item = len(items) - 1
}
}
return items[item], nil
}
}
func (s *State) printedTabs(items []string) func(tabDirection) (string, error) {
numTabs := 1
prefix := longestCommonPrefix(items)
return func(direction tabDirection) (string, error) {
if len(items) == 1 {
return items[0], nil
}
if numTabs == 2 {
if len(items) > 100 {
fmt.Printf("\nDisplay all %d possibilities? (y or n) ", len(items))
for {
next, err := s.readNext()
if err != nil {
return prefix, err
}
if key, ok := next.(rune); ok {
if unicode.ToLower(key) == 'n' {
return prefix, nil
} else if unicode.ToLower(key) == 'y' {
break
}
}
}
}
fmt.Println("")
maxWidth := 0
for _, item := range items {
if len(item) >= maxWidth {
maxWidth = len(item) + 1
}
}
numColumns := s.columns / maxWidth
numRows := len(items) / numColumns
if len(items)%numColumns > 0 {
numRows++
}
if len(items) <= numColumns {
maxWidth = 0
}
for i := 0; i < numRows; i++ {
for j := 0; j < numColumns*numRows; j += numRows {
if i+j < len(items) {
if maxWidth > 0 {
fmt.Printf("%-*s", maxWidth, items[i+j])
} else {
fmt.Printf("%v ", items[i+j])
}
}
}
fmt.Println("")
}
} else {
numTabs++
}
return prefix, nil
}
}
func (s *State) tabComplete(p []rune, line []rune, pos int) ([]rune, int, interface{}, error) {
if s.completer == nil {
return line, pos, rune(esc), nil
}
head, list, tail := s.completer(string(line), pos)
if len(list) <= 0 {
return line, pos, rune(esc), nil
}
hl := utf8.RuneCountInString(head)
if len(list) == 1 {
s.refresh(p, []rune(head+list[0]+tail), hl+utf8.RuneCountInString(list[0]))
return []rune(head + list[0] + tail), hl + utf8.RuneCountInString(list[0]), rune(esc), nil
}
direction := tabForward
tabPrinter := s.circularTabs(list)
if s.tabStyle == TabPrints {
tabPrinter = s.printedTabs(list)
}
for {
pick, err := tabPrinter(direction)
if err != nil {
return line, pos, rune(esc), err
}
s.refresh(p, []rune(head+pick+tail), hl+utf8.RuneCountInString(pick))
next, err := s.readNext()
if err != nil {
return line, pos, rune(esc), err
}
if key, ok := next.(rune); ok {
if key == tab {
direction = tabForward
continue
}
if key == esc {
return line, pos, rune(esc), nil
}
}
if a, ok := next.(action); ok && a == shiftTab {
direction = tabReverse
continue
}
return []rune(head + pick + tail), hl + utf8.RuneCountInString(pick), next, nil
}
// Not reached
return line, pos, rune(esc), nil
}
// reverse intelligent search, implements a bash-like history search.
func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, interface{}, error) {
p := "(reverse-i-search)`': "
s.refresh([]rune(p), origLine, origPos)
line := []rune{}
pos := 0
foundLine := string(origLine)
foundPos := origPos
getLine := func() ([]rune, []rune, int) {
search := string(line)
prompt := "(reverse-i-search)`%s': "
return []rune(fmt.Sprintf(prompt, search)), []rune(foundLine), foundPos
}
history, positions := s.getHistoryByPattern(string(line))
historyPos := len(history) - 1
for {
next, err := s.readNext()
if err != nil {
return []rune(foundLine), foundPos, rune(esc), err
}
switch v := next.(type) {
case rune:
switch v {
case ctrlR: // Search backwards
if historyPos > 0 && historyPos < len(history) {
historyPos--
foundLine = history[historyPos]
foundPos = positions[historyPos]
} else {
fmt.Print(beep)
}
case ctrlS: // Search forward
if historyPos < len(history)-1 && historyPos >= 0 {
historyPos++
foundLine = history[historyPos]
foundPos = positions[historyPos]
} else {
fmt.Print(beep)
}
case ctrlH, bs: // Backspace
if pos <= 0 {
fmt.Print(beep)
} else {
n := len(getSuffixGlyphs(line[:pos], 1))
line = append(line[:pos-n], line[pos:]...)
pos -= n
// For each char deleted, display the last matching line of history
history, positions := s.getHistoryByPattern(string(line))
historyPos = len(history) - 1
if len(history) > 0 {
foundLine = history[historyPos]
foundPos = positions[historyPos]
} else {
foundLine = ""
foundPos = 0
}
}
case ctrlG: // Cancel
return origLine, origPos, rune(esc), err
case tab, cr, lf, ctrlA, ctrlB, ctrlD, ctrlE, ctrlF, ctrlK,
ctrlL, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY, ctrlZ:
fallthrough
case 0, ctrlC, esc, 28, 29, 30, 31:
return []rune(foundLine), foundPos, next, err
default:
line = append(line[:pos], append([]rune{v}, line[pos:]...)...)
pos++
// For each keystroke typed, display the last matching line of history
history, positions = s.getHistoryByPattern(string(line))
historyPos = len(history) - 1
if len(history) > 0 {
foundLine = history[historyPos]
foundPos = positions[historyPos]
} else {
foundLine = ""
foundPos = 0
}
}
case action:
return []rune(foundLine), foundPos, next, err
}
s.refresh(getLine())
}
}
// addToKillRing adds some text to the kill ring. If mode is 0 it adds it to a
// new node in the end of the kill ring, and move the current pointer to the new
// node. If mode is 1 or 2 it appends or prepends the text to the current entry
// of the killRing.
func (s *State) addToKillRing(text []rune, mode int) {
// Don't use the same underlying array as text
killLine := make([]rune, len(text))
copy(killLine, text)
// Point killRing to a newNode, procedure depends on the killring state and
// append mode.
if mode == 0 { // Add new node to killRing
if s.killRing == nil { // if killring is empty, create a new one
s.killRing = ring.New(1)
} else if s.killRing.Len() >= KillRingMax { // if killring is "full"
s.killRing = s.killRing.Next()
} else { // Normal case
s.killRing.Link(ring.New(1))
s.killRing = s.killRing.Next()
}
} else {
if s.killRing == nil { // if killring is empty, create a new one
s.killRing = ring.New(1)
s.killRing.Value = []rune{}
}
if mode == 1 { // Append to last entry
killLine = append(s.killRing.Value.([]rune), killLine...)
} else if mode == 2 { // Prepend to last entry
killLine = append(killLine, s.killRing.Value.([]rune)...)
}
}
// Save text in the current killring node
s.killRing.Value = killLine
}
func (s *State) yank(p []rune, text []rune, pos int) ([]rune, int, interface{}, error) {
if s.killRing == nil {
return text, pos, rune(esc), nil
}
lineStart := text[:pos]
lineEnd := text[pos:]
var line []rune
for {
value := s.killRing.Value.([]rune)
line = make([]rune, 0)
line = append(line, lineStart...)
line = append(line, value...)
line = append(line, lineEnd...)
pos = len(lineStart) + len(value)
s.refresh(p, line, pos)
next, err := s.readNext()
if err != nil {
return line, pos, next, err
}
switch v := next.(type) {
case rune:
return line, pos, next, nil
case action:
switch v {
case altY:
s.killRing = s.killRing.Prev()
default:
return line, pos, next, nil
}
}
}
return line, pos, esc, nil
}
// Prompt displays p, and then waits for user input. Prompt allows line editing
// if the terminal supports it.
func (s *State) Prompt(prompt string) (string, error) {
if s.inputRedirected {
return s.promptUnsupported(prompt)
}
if s.outputRedirected {
return "", ErrNotTerminalOutput
}
if !s.terminalSupported {
return s.promptUnsupported(prompt)
}
s.historyMutex.RLock()
defer s.historyMutex.RUnlock()
s.startPrompt()
defer s.stopPrompt()
s.getColumns()
fmt.Print(prompt)
p := []rune(prompt)
var line []rune
pos := 0
historyEnd := ""
prefixHistory := s.getHistoryByPrefix(string(line))
historyPos := len(prefixHistory)
historyAction := false // used to mark history related actions
killAction := 0 // used to mark kill related actions
mainLoop:
for {
next, err := s.readNext()
haveNext:
if err != nil {
return "", err
}
historyAction = false
switch v := next.(type) {
case rune:
switch v {
case cr, lf:
fmt.Println()
break mainLoop
case ctrlA: // Start of line
pos = 0
s.refresh(p, line, pos)
case ctrlE: // End of line
pos = len(line)
s.refresh(p, line, pos)
case ctrlB: // left
if pos > 0 {
pos -= len(getSuffixGlyphs(line[:pos], 1))
s.refresh(p, line, pos)
} else {
fmt.Print(beep)
}
case ctrlF: // right
if pos < len(line) {
pos += len(getPrefixGlyphs(line[pos:], 1))
s.refresh(p, line, pos)
} else {
fmt.Print(beep)
}
case ctrlD: // del
if pos == 0 && len(line) == 0 {
// exit
return "", io.EOF
}
// ctrlD is a potential EOF, so the rune reader shuts down.
// Therefore, if it isn't actually an EOF, we must re-startPrompt.
s.restartPrompt()
if pos >= len(line) {
fmt.Print(beep)
} else {
n := len(getPrefixGlyphs(line[pos:], 1))
line = append(line[:pos], line[pos+n:]...)
s.refresh(p, line, pos)
}
case ctrlK: // delete remainder of line
if pos >= len(line) {
fmt.Print(beep)
} else {
if killAction > 0 {
s.addToKillRing(line[pos:], 1) // Add in apend mode
} else {
s.addToKillRing(line[pos:], 0) // Add in normal mode
}
killAction = 2 // Mark that there was a kill action
line = line[:pos]
s.refresh(p, line, pos)
}
case ctrlP: // up
historyAction = true
if historyPos > 0 {
if historyPos == len(prefixHistory) {
historyEnd = string(line)
}
historyPos--
line = []rune(prefixHistory[historyPos])
pos = len(line)
s.refresh(p, line, pos)
} else {
fmt.Print(beep)
}
case ctrlN: // down
historyAction = true
if historyPos < len(prefixHistory) {
historyPos++
if historyPos == len(prefixHistory) {
line = []rune(historyEnd)
} else {
line = []rune(prefixHistory[historyPos])
}
pos = len(line)
s.refresh(p, line, pos)
} else {
fmt.Print(beep)
}
case ctrlT: // transpose prev glyph with glyph under cursor
if len(line) < 2 || pos < 1 {
fmt.Print(beep)
} else {
if pos == len(line) {
pos -= len(getSuffixGlyphs(line, 1))
}
prev := getSuffixGlyphs(line[:pos], 1)
next := getPrefixGlyphs(line[pos:], 1)
scratch := make([]rune, len(prev))
copy(scratch, prev)
copy(line[pos-len(prev):], next)
copy(line[pos-len(prev)+len(next):], scratch)
pos += len(next)
s.refresh(p, line, pos)
}
case ctrlL: // clear screen
s.eraseScreen()
s.refresh(p, line, pos)
case ctrlC: // reset
fmt.Println("^C")
if s.ctrlCAborts {
return "", ErrPromptAborted
}
line = line[:0]
pos = 0
fmt.Print(prompt)
s.restartPrompt()
case ctrlH, bs: // Backspace
if pos <= 0 {
fmt.Print(beep)
} else {
n := len(getSuffixGlyphs(line[:pos], 1))
line = append(line[:pos-n], line[pos:]...)
pos -= n
s.refresh(p, line, pos)
}
case ctrlU: // Erase line before cursor
if killAction > 0 {
s.addToKillRing(line[:pos], 2) // Add in prepend mode
} else {
s.addToKillRing(line[:pos], 0) // Add in normal mode
}
killAction = 2 // Mark that there was some killing
line = line[pos:]
pos = 0
s.refresh(p, line, pos)
case ctrlW: // Erase word
if pos == 0 {
fmt.Print(beep)
break
}
// Remove whitespace to the left
var buf []rune // Store the deleted chars in a buffer
for {
if pos == 0 || !unicode.IsSpace(line[pos-1]) {
break
}
buf = append(buf, line[pos-1])
line = append(line[:pos-1], line[pos:]...)
pos--
}
// Remove non-whitespace to the left
for {
if pos == 0 || unicode.IsSpace(line[pos-1]) {
break
}
buf = append(buf, line[pos-1])
line = append(line[:pos-1], line[pos:]...)
pos--
}
// Invert the buffer and save the result on the killRing
var newBuf []rune
for i := len(buf) - 1; i >= 0; i-- {
newBuf = append(newBuf, buf[i])
}
if killAction > 0 {
s.addToKillRing(newBuf, 2) // Add in prepend mode
} else {
s.addToKillRing(newBuf, 0) // Add in normal mode
}
killAction = 2 // Mark that there was some killing
s.refresh(p, line, pos)
case ctrlY: // Paste from Yank buffer
line, pos, next, err = s.yank(p, line, pos)
goto haveNext
case ctrlR: // Reverse Search
line, pos, next, err = s.reverseISearch(line, pos)
s.refresh(p, line, pos)
goto haveNext
case tab: // Tab completion
line, pos, next, err = s.tabComplete(p, line, pos)
goto haveNext
// Catch keys that do nothing, but you don't want them to beep
case esc:
// DO NOTHING
// Unused keys
case ctrlG, ctrlO, ctrlQ, ctrlS, ctrlV, ctrlX, ctrlZ:
fallthrough
// Catch unhandled control codes (anything <= 31)
case 0, 28, 29, 30, 31:
fmt.Print(beep)
default:
if pos == len(line) && len(p)+len(line) < s.columns-1 {
line = append(line, v)
fmt.Printf("%c", v)
pos++
} else {
line = append(line[:pos], append([]rune{v}, line[pos:]...)...)
pos++
s.refresh(p, line, pos)
}
}
case action:
switch v {
case del:
if pos >= len(line) {
fmt.Print(beep)
} else {
n := len(getPrefixGlyphs(line[pos:], 1))
line = append(line[:pos], line[pos+n:]...)
}
case left:
if pos > 0 {
pos -= len(getSuffixGlyphs(line[:pos], 1))
} else {
fmt.Print(beep)
}
case wordLeft:
if pos > 0 {
for {
pos--
if pos == 0 || unicode.IsSpace(line[pos-1]) {
break
}
}
} else {
fmt.Print(beep)
}
case right:
if pos < len(line) {
pos += len(getPrefixGlyphs(line[pos:], 1))
} else {
fmt.Print(beep)
}
case wordRight:
if pos < len(line) {
for {
pos++
if pos == len(line) || unicode.IsSpace(line[pos]) {
break
}
}
} else {
fmt.Print(beep)
}
case up:
historyAction = true
if historyPos > 0 {
if historyPos == len(prefixHistory) {
historyEnd = string(line)
}
historyPos--
line = []rune(prefixHistory[historyPos])
pos = len(line)
} else {
fmt.Print(beep)
}
case down:
historyAction = true
if historyPos < len(prefixHistory) {
historyPos++
if historyPos == len(prefixHistory) {
line = []rune(historyEnd)
} else {
line = []rune(prefixHistory[historyPos])
}
pos = len(line)
} else {
fmt.Print(beep)
}
case home: // Start of line
pos = 0
case end: // End of line
pos = len(line)
}
s.refresh(p, line, pos)
}
if !historyAction {
prefixHistory = s.getHistoryByPrefix(string(line))
historyPos = len(prefixHistory)
}
if killAction > 0 {
killAction--
}
}
return string(line), nil
}
// PasswordPrompt displays p, and then waits for user input. The input typed by
// the user is not displayed in the terminal.
func (s *State) PasswordPrompt(prompt string) (string, error) {
if s.inputRedirected {
return s.promptUnsupported(prompt)
}
if s.outputRedirected {
return "", ErrNotTerminalOutput
}
if !s.terminalSupported {
return "", errors.New("liner: function not supported in this terminal")
}
s.startPrompt()
defer s.stopPrompt()
s.getColumns()
fmt.Print(prompt)
p := []rune(prompt)
var line []rune
pos := 0
mainLoop:
for {
next, err := s.readNext()
if err != nil {
return "", err
}
switch v := next.(type) {
case rune:
switch v {
case cr, lf:
fmt.Println()
break mainLoop
case ctrlD: // del
if pos == 0 && len(line) == 0 {
// exit
return "", io.EOF
}
// ctrlD is a potential EOF, so the rune reader shuts down.
// Therefore, if it isn't actually an EOF, we must re-startPrompt.
s.restartPrompt()
case ctrlL: // clear screen
s.eraseScreen()
s.refresh(p, []rune{}, 0)
case ctrlH, bs: // Backspace
if pos <= 0 {
fmt.Print(beep)
} else {
n := len(getSuffixGlyphs(line[:pos], 1))
line = append(line[:pos-n], line[pos:]...)
pos -= n
}
case ctrlC:
fmt.Println("^C")
if s.ctrlCAborts {
return "", ErrPromptAborted
}
line = line[:0]
pos = 0
fmt.Print(prompt)
s.restartPrompt()
// Unused keys
case esc, tab, ctrlA, ctrlB, ctrlE, ctrlF, ctrlG, ctrlK, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlR, ctrlS,
ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY, ctrlZ:
fallthrough
// Catch unhandled control codes (anything <= 31)
case 0, 28, 29, 30, 31:
fmt.Print(beep)
default:
line = append(line[:pos], append([]rune{v}, line[pos:]...)...)
pos++
}
}
}
return string(line), nil
}

@ -0,0 +1,90 @@
package liner
import (
"bytes"
"strings"
"testing"
)
func TestAppend(t *testing.T) {
var s State
s.AppendHistory("foo")
s.AppendHistory("bar")
var out bytes.Buffer
num, err := s.WriteHistory(&out)
if err != nil {
t.Fatal("Unexpected error writing history", err)
}
if num != 2 {
t.Fatalf("Expected 2 history entries, got %d", num)
}
s.AppendHistory("baz")
num, err = s.WriteHistory(&out)
if err != nil {
t.Fatal("Unexpected error writing history", err)
}
if num != 3 {
t.Fatalf("Expected 3 history entries, got %d", num)
}
s.AppendHistory("baz")
num, err = s.WriteHistory(&out)
if err != nil {
t.Fatal("Unexpected error writing history", err)
}
if num != 3 {
t.Fatalf("Expected 3 history entries after duplicate append, got %d", num)
}
s.AppendHistory("baz")
}
func TestHistory(t *testing.T) {
input := `foo
bar
baz
quux
dingle`
var s State
num, err := s.ReadHistory(strings.NewReader(input))
if err != nil {
t.Fatal("Unexpected error reading history", err)
}
if num != 5 {
t.Fatal("Wrong number of history entries read")
}
var out bytes.Buffer
num, err = s.WriteHistory(&out)
if err != nil {
t.Fatal("Unexpected error writing history", err)
}
if num != 5 {
t.Fatal("Wrong number of history entries written")
}
if strings.TrimSpace(out.String()) != input {
t.Fatal("Round-trip failure")
}
// Test reading with a trailing newline present
var s2 State
num, err = s2.ReadHistory(&out)
if err != nil {
t.Fatal("Unexpected error reading history the 2nd time", err)
}
if num != 5 {
t.Fatal("Wrong number of history entries read the 2nd time")
}
num, err = s.ReadHistory(strings.NewReader(input + "\n\xff"))
if err == nil {
t.Fatal("Unexpected success reading corrupted history", err)
}
if num != 5 {
t.Fatal("Wrong number of history entries read the 3rd time")
}
}

@ -0,0 +1,63 @@
// +build linux darwin openbsd freebsd netbsd
package liner
import (
"fmt"
"os"
"strings"
"syscall"
"unsafe"
)
func (s *State) cursorPos(x int) {
if s.useCHA {
// 'G' is "Cursor Character Absolute (CHA)"
fmt.Printf("\x1b[%dG", x+1)
} else {
// 'C' is "Cursor Forward (CUF)"
fmt.Print("\r")
if x > 0 {
fmt.Printf("\x1b[%dC", x)
}
}
}
func (s *State) eraseLine() {
fmt.Print("\x1b[0K")
}
func (s *State) eraseScreen() {
fmt.Print("\x1b[H\x1b[2J")
}
type winSize struct {
row, col uint16
xpixel, ypixel uint16
}
func (s *State) getColumns() {
var ws winSize
ok, _, _ := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdout),
syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&ws)))
if ok < 0 {
s.columns = 80
}
s.columns = int(ws.col)
}
func (s *State) checkOutput() {
// xterm is known to support CHA
if strings.Contains(strings.ToLower(os.Getenv("TERM")), "xterm") {
s.useCHA = true
return
}
// The test for functional ANSI CHA is unreliable (eg the Windows
// telnet command does not support reading the cursor position with
// an ANSI DSR request, despite setting TERM=ansi)
// Assume CHA isn't supported (which should be safe, although it
// does result in occasional visible cursor jitter)
s.useCHA = false
}

@ -0,0 +1,54 @@
package liner
import (
"unsafe"
)
type coord struct {
x, y int16
}
type smallRect struct {
left, top, right, bottom int16
}
type consoleScreenBufferInfo struct {
dwSize coord
dwCursorPosition coord
wAttributes int16
srWindow smallRect
dwMaximumWindowSize coord
}
func (s *State) cursorPos(x int) {
var sbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
procSetConsoleCursorPosition.Call(uintptr(s.hOut),
uintptr(int(x)&0xFFFF|int(sbi.dwCursorPosition.y)<<16))
}
func (s *State) eraseLine() {
var sbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
var numWritten uint32
procFillConsoleOutputCharacter.Call(uintptr(s.hOut), uintptr(' '),
uintptr(sbi.dwSize.x-sbi.dwCursorPosition.x),
uintptr(int(sbi.dwCursorPosition.x)&0xFFFF|int(sbi.dwCursorPosition.y)<<16),
uintptr(unsafe.Pointer(&numWritten)))
}
func (s *State) eraseScreen() {
var sbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
var numWritten uint32
procFillConsoleOutputCharacter.Call(uintptr(s.hOut), uintptr(' '),
uintptr(sbi.dwSize.x)*uintptr(sbi.dwSize.y),
0,
uintptr(unsafe.Pointer(&numWritten)))
procSetConsoleCursorPosition.Call(uintptr(s.hOut), 0)
}
func (s *State) getColumns() {
var sbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
s.columns = int(sbi.dwSize.x)
}

@ -0,0 +1,37 @@
// +build windows linux darwin openbsd freebsd netbsd
package liner
import "testing"
type testItem struct {
list []string
prefix string
}
func TestPrefix(t *testing.T) {
list := []testItem{
{[]string{"food", "foot"}, "foo"},
{[]string{"foo", "foot"}, "foo"},
{[]string{"food", "foo"}, "foo"},
{[]string{"food", "foe", "foot"}, "fo"},
{[]string{"food", "foot", "barbeque"}, ""},
{[]string{"cafeteria", "café"}, "caf"},
{[]string{"cafe", "café"}, "caf"},
{[]string{"cafè", "café"}, "caf"},
{[]string{"cafés", "café"}, "café"},
{[]string{"áéíóú", "áéíóú"}, "áéíóú"},
{[]string{"éclairs", "éclairs"}, "éclairs"},
{[]string{"éclairs are the best", "éclairs are great", "éclairs"}, "éclairs"},
{[]string{"éclair", "éclairs"}, "éclair"},
{[]string{"éclairs", "éclair"}, "éclair"},
{[]string{"éclair", "élan"}, "é"},
}
for _, test := range list {
lcp := longestCommonPrefix(test.list)
if lcp != test.prefix {
t.Errorf("%s != %s for %+v", lcp, test.prefix, test.list)
}
}
}

@ -0,0 +1,44 @@
// +build race
package liner
import (
"io/ioutil"
"os"
"sync"
"testing"
)
func TestWriteHistory(t *testing.T) {
oldout := os.Stdout
defer func() { os.Stdout = oldout }()
oldin := os.Stdout
defer func() { os.Stdin = oldin }()
newinr, newinw, err := os.Pipe()
if err != nil {
t.Fatal(err)
}
os.Stdin = newinr
newoutr, newoutw, err := os.Pipe()
if err != nil {
t.Fatal(err)
}
defer newoutr.Close()
os.Stdout = newoutw
var wait sync.WaitGroup
wait.Add(1)
s := NewLiner()
go func() {
s.AppendHistory("foo")
s.AppendHistory("bar")
s.Prompt("")
wait.Done()
}()
s.WriteHistory(ioutil.Discard)
newinw.Close()
wait.Wait()
}

@ -0,0 +1,12 @@
// +build go1.1,!windows
package liner
import (
"os"
"os/signal"
)
func stopSignal(c chan<- os.Signal) {
signal.Stop(c)
}

@ -0,0 +1,11 @@
// +build !go1.1,!windows
package liner
import (
"os"
)
func stopSignal(c chan<- os.Signal) {
// signal.Stop does not exist before Go 1.1
}

@ -0,0 +1,37 @@
// +build linux darwin freebsd openbsd netbsd
package liner
import (
"syscall"
"unsafe"
)
func (mode *termios) ApplyMode() error {
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdin), setTermios, uintptr(unsafe.Pointer(mode)))
if errno != 0 {
return errno
}
return nil
}
// TerminalMode returns the current terminal input mode as an InputModeSetter.
//
// This function is provided for convenience, and should
// not be necessary for most users of liner.
func TerminalMode() (ModeApplier, error) {
mode, errno := getMode(syscall.Stdin)
if errno != 0 {
return nil, errno
}
return mode, nil
}
func getMode(handle int) (*termios, syscall.Errno) {
var mode termios
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(handle), getTermios, uintptr(unsafe.Pointer(&mode)))
return &mode, errno
}

@ -0,0 +1,47 @@
package liner
import "unicode"
// These character classes are mostly zero width (when combined).
// A few might not be, depending on the user's font. Fixing this
// is non-trivial, given that some terminals don't support
// ANSI DSR/CPR
var zeroWidth = []*unicode.RangeTable{
unicode.Mn,
unicode.Me,
unicode.Cc,
unicode.Cf,
}
func countGlyphs(s []rune) int {
n := 0
for _, r := range s {
if !unicode.IsOneOf(zeroWidth, r) {
n++
}
}
return n
}
func getPrefixGlyphs(s []rune, num int) []rune {
p := 0
for n := 0; n < num && p < len(s); p++ {
if !unicode.IsOneOf(zeroWidth, s[p]) {
n++
}
}
for p < len(s) && unicode.IsOneOf(zeroWidth, s[p]) {
p++
}
return s[:p]
}
func getSuffixGlyphs(s []rune, num int) []rune {
p := len(s)
for n := 0; n < num && p > 0; p-- {
if !unicode.IsOneOf(zeroWidth, s[p-1]) {
n++
}
}
return s[p:]
}

@ -0,0 +1,87 @@
package liner
import (
"strconv"
"testing"
)
func accent(in []rune) []rune {
var out []rune
for _, r := range in {
out = append(out, r)
out = append(out, '\u0301')
}
return out
}
var testString = []rune("query")
func TestCountGlyphs(t *testing.T) {
count := countGlyphs(testString)
if count != len(testString) {
t.Errorf("ASCII count incorrect. %d != %d", count, len(testString))
}
count = countGlyphs(accent(testString))
if count != len(testString) {
t.Errorf("Accent count incorrect. %d != %d", count, len(testString))
}
}
func compare(a, b []rune, name string, t *testing.T) {
if len(a) != len(b) {
t.Errorf(`"%s" != "%s" in %s"`, string(a), string(b), name)
return
}
for i := range a {
if a[i] != b[i] {
t.Errorf(`"%s" != "%s" in %s"`, string(a), string(b), name)
return
}
}
}
func TestPrefixGlyphs(t *testing.T) {
for i := 0; i <= len(testString); i++ {
iter := strconv.Itoa(i)
out := getPrefixGlyphs(testString, i)
compare(out, testString[:i], "ascii prefix "+iter, t)
out = getPrefixGlyphs(accent(testString), i)
compare(out, accent(testString[:i]), "accent prefix "+iter, t)
}
out := getPrefixGlyphs(testString, 999)
compare(out, testString, "ascii prefix overflow", t)
out = getPrefixGlyphs(accent(testString), 999)
compare(out, accent(testString), "accent prefix overflow", t)
out = getPrefixGlyphs(testString, -3)
if len(out) != 0 {
t.Error("ascii prefix negative")
}
out = getPrefixGlyphs(accent(testString), -3)
if len(out) != 0 {
t.Error("accent prefix negative")
}
}
func TestSuffixGlyphs(t *testing.T) {
for i := 0; i <= len(testString); i++ {
iter := strconv.Itoa(i)
out := getSuffixGlyphs(testString, i)
compare(out, testString[len(testString)-i:], "ascii suffix "+iter, t)
out = getSuffixGlyphs(accent(testString), i)
compare(out, accent(testString[len(testString)-i:]), "accent suffix "+iter, t)
}
out := getSuffixGlyphs(testString, 999)
compare(out, testString, "ascii suffix overflow", t)
out = getSuffixGlyphs(accent(testString), 999)
compare(out, accent(testString), "accent suffix overflow", t)
out = getSuffixGlyphs(testString, -3)
if len(out) != 0 {
t.Error("ascii suffix negative")
}
out = getSuffixGlyphs(accent(testString), -3)
if len(out) != 0 {
t.Error("accent suffix negative")
}
}

@ -1,112 +0,0 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"bufio"
"crypto/tls"
"io"
"net"
"net/http"
"net/url"
)
// DialError is an error that occurs while dialling a websocket server.
type DialError struct {
*Config
Err error
}
func (e *DialError) Error() string {
return "websocket.Dial " + e.Config.Location.String() + ": " + e.Err.Error()
}
// NewConfig creates a new WebSocket config for client connection.
func NewConfig(server, origin string) (config *Config, err error) {
config = new(Config)
config.Version = ProtocolVersionHybi13
config.Location, err = url.ParseRequestURI(server)
if err != nil {
return
}
config.Origin, err = url.ParseRequestURI(origin)
if err != nil {
return
}
config.Header = http.Header(make(map[string][]string))
return
}
// NewClient creates a new WebSocket client connection over rwc.
func NewClient(config *Config, rwc io.ReadWriteCloser) (ws *Conn, err error) {
br := bufio.NewReader(rwc)
bw := bufio.NewWriter(rwc)
err = hybiClientHandshake(config, br, bw)
if err != nil {
return
}
buf := bufio.NewReadWriter(br, bw)
ws = newHybiClientConn(config, buf, rwc)
return
}
// Dial opens a new client connection to a WebSocket.
func Dial(url_, protocol, origin string) (ws *Conn, err error) {
config, err := NewConfig(url_, origin)
if err != nil {
return nil, err
}
if protocol != "" {
config.Protocol = []string{protocol}
}
return DialConfig(config)
}
var portMap = map[string]string{
"ws": "80",
"wss": "443",
}
func parseAuthority(location *url.URL) string {
if _, ok := portMap[location.Scheme]; ok {
if _, _, err := net.SplitHostPort(location.Host); err != nil {
return net.JoinHostPort(location.Host, portMap[location.Scheme])
}
}
return location.Host
}
// DialConfig opens a new client connection to a WebSocket with a config.
func DialConfig(config *Config) (ws *Conn, err error) {
var client net.Conn
if config.Location == nil {
return nil, &DialError{config, ErrBadWebSocketLocation}
}
if config.Origin == nil {
return nil, &DialError{config, ErrBadWebSocketOrigin}
}
switch config.Location.Scheme {
case "ws":
client, err = net.Dial("tcp", parseAuthority(config.Location))
case "wss":
client, err = tls.Dial("tcp", parseAuthority(config.Location), config.TlsConfig)
default:
err = ErrBadScheme
}
if err != nil {
goto Error
}
ws, err = NewClient(config, client)
if err != nil {
goto Error
}
return
Error:
return nil, &DialError{config, err}
}

@ -1,31 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket_test
import (
"fmt"
"log"
"golang.org/x/net/websocket"
)
// This example demonstrates a trivial client.
func ExampleDial() {
origin := "http://localhost/"
url := "ws://localhost:12345/ws"
ws, err := websocket.Dial(url, "", origin)
if err != nil {
log.Fatal(err)
}
if _, err := ws.Write([]byte("hello, world!\n")); err != nil {
log.Fatal(err)
}
var msg = make([]byte, 512)
var n int
if n, err = ws.Read(msg); err != nil {
log.Fatal(err)
}
fmt.Printf("Received: %s.\n", msg[:n])
}

@ -1,26 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket_test
import (
"io"
"net/http"
"golang.org/x/net/websocket"
)
// Echo the data received on the WebSocket.
func EchoServer(ws *websocket.Conn) {
io.Copy(ws, ws)
}
// This example demonstrates a trivial echo server.
func ExampleHandler() {
http.Handle("/echo", websocket.Handler(EchoServer))
err := http.ListenAndServe(":12345", nil)
if err != nil {
panic("ListenAndServe: " + err.Error())
}
}

@ -1,564 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
// This file implements a protocol of hybi draft.
// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17
import (
"bufio"
"bytes"
"crypto/rand"
"crypto/sha1"
"encoding/base64"
"encoding/binary"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
)
const (
websocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
closeStatusNormal = 1000
closeStatusGoingAway = 1001
closeStatusProtocolError = 1002
closeStatusUnsupportedData = 1003
closeStatusFrameTooLarge = 1004
closeStatusNoStatusRcvd = 1005
closeStatusAbnormalClosure = 1006
closeStatusBadMessageData = 1007
closeStatusPolicyViolation = 1008
closeStatusTooBigData = 1009
closeStatusExtensionMismatch = 1010
maxControlFramePayloadLength = 125
)
var (
ErrBadMaskingKey = &ProtocolError{"bad masking key"}
ErrBadPongMessage = &ProtocolError{"bad pong message"}
ErrBadClosingStatus = &ProtocolError{"bad closing status"}
ErrUnsupportedExtensions = &ProtocolError{"unsupported extensions"}
ErrNotImplemented = &ProtocolError{"not implemented"}
handshakeHeader = map[string]bool{
"Host": true,
"Upgrade": true,
"Connection": true,
"Sec-Websocket-Key": true,
"Sec-Websocket-Origin": true,
"Sec-Websocket-Version": true,
"Sec-Websocket-Protocol": true,
"Sec-Websocket-Accept": true,
}
)
// A hybiFrameHeader is a frame header as defined in hybi draft.
type hybiFrameHeader struct {
Fin bool
Rsv [3]bool
OpCode byte
Length int64
MaskingKey []byte
data *bytes.Buffer
}
// A hybiFrameReader is a reader for hybi frame.
type hybiFrameReader struct {
reader io.Reader
header hybiFrameHeader
pos int64
length int
}
func (frame *hybiFrameReader) Read(msg []byte) (n int, err error) {
n, err = frame.reader.Read(msg)
if err != nil {
return 0, err
}
if frame.header.MaskingKey != nil {
for i := 0; i < n; i++ {
msg[i] = msg[i] ^ frame.header.MaskingKey[frame.pos%4]
frame.pos++
}
}
return n, err
}
func (frame *hybiFrameReader) PayloadType() byte { return frame.header.OpCode }
func (frame *hybiFrameReader) HeaderReader() io.Reader {
if frame.header.data == nil {
return nil
}
if frame.header.data.Len() == 0 {
return nil
}
return frame.header.data
}
func (frame *hybiFrameReader) TrailerReader() io.Reader { return nil }
func (frame *hybiFrameReader) Len() (n int) { return frame.length }
// A hybiFrameReaderFactory creates new frame reader based on its frame type.
type hybiFrameReaderFactory struct {
*bufio.Reader
}
// NewFrameReader reads a frame header from the connection, and creates new reader for the frame.
// See Section 5.2 Base Framing protocol for detail.
// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5.2
func (buf hybiFrameReaderFactory) NewFrameReader() (frame frameReader, err error) {
hybiFrame := new(hybiFrameReader)
frame = hybiFrame
var header []byte
var b byte
// First byte. FIN/RSV1/RSV2/RSV3/OpCode(4bits)
b, err = buf.ReadByte()
if err != nil {
return
}
header = append(header, b)
hybiFrame.header.Fin = ((header[0] >> 7) & 1) != 0
for i := 0; i < 3; i++ {
j := uint(6 - i)
hybiFrame.header.Rsv[i] = ((header[0] >> j) & 1) != 0
}
hybiFrame.header.OpCode = header[0] & 0x0f
// Second byte. Mask/Payload len(7bits)
b, err = buf.ReadByte()
if err != nil {
return
}
header = append(header, b)
mask := (b & 0x80) != 0
b &= 0x7f
lengthFields := 0
switch {
case b <= 125: // Payload length 7bits.
hybiFrame.header.Length = int64(b)
case b == 126: // Payload length 7+16bits
lengthFields = 2
case b == 127: // Payload length 7+64bits
lengthFields = 8
}
for i := 0; i < lengthFields; i++ {
b, err = buf.ReadByte()
if err != nil {
return
}
header = append(header, b)
hybiFrame.header.Length = hybiFrame.header.Length*256 + int64(b)
}
if mask {
// Masking key. 4 bytes.
for i := 0; i < 4; i++ {
b, err = buf.ReadByte()
if err != nil {
return
}
header = append(header, b)
hybiFrame.header.MaskingKey = append(hybiFrame.header.MaskingKey, b)
}
}
hybiFrame.reader = io.LimitReader(buf.Reader, hybiFrame.header.Length)
hybiFrame.header.data = bytes.NewBuffer(header)
hybiFrame.length = len(header) + int(hybiFrame.header.Length)
return
}
// A HybiFrameWriter is a writer for hybi frame.
type hybiFrameWriter struct {
writer *bufio.Writer
header *hybiFrameHeader
}
func (frame *hybiFrameWriter) Write(msg []byte) (n int, err error) {
var header []byte
var b byte
if frame.header.Fin {
b |= 0x80
}
for i := 0; i < 3; i++ {
if frame.header.Rsv[i] {
j := uint(6 - i)
b |= 1 << j
}
}
b |= frame.header.OpCode
header = append(header, b)
if frame.header.MaskingKey != nil {
b = 0x80
} else {
b = 0
}
lengthFields := 0
length := len(msg)
switch {
case length <= 125:
b |= byte(length)
case length < 65536:
b |= 126
lengthFields = 2
default:
b |= 127
lengthFields = 8
}
header = append(header, b)
for i := 0; i < lengthFields; i++ {
j := uint((lengthFields - i - 1) * 8)
b = byte((length >> j) & 0xff)
header = append(header, b)
}
if frame.header.MaskingKey != nil {
if len(frame.header.MaskingKey) != 4 {
return 0, ErrBadMaskingKey
}
header = append(header, frame.header.MaskingKey...)
frame.writer.Write(header)
data := make([]byte, length)
for i := range data {
data[i] = msg[i] ^ frame.header.MaskingKey[i%4]
}
frame.writer.Write(data)
err = frame.writer.Flush()
return length, err
}
frame.writer.Write(header)
frame.writer.Write(msg)
err = frame.writer.Flush()
return length, err
}
func (frame *hybiFrameWriter) Close() error { return nil }
type hybiFrameWriterFactory struct {
*bufio.Writer
needMaskingKey bool
}
func (buf hybiFrameWriterFactory) NewFrameWriter(payloadType byte) (frame frameWriter, err error) {
frameHeader := &hybiFrameHeader{Fin: true, OpCode: payloadType}
if buf.needMaskingKey {
frameHeader.MaskingKey, err = generateMaskingKey()
if err != nil {
return nil, err
}
}
return &hybiFrameWriter{writer: buf.Writer, header: frameHeader}, nil
}
type hybiFrameHandler struct {
conn *Conn
payloadType byte
}
func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (r frameReader, err error) {
if handler.conn.IsServerConn() {
// The client MUST mask all frames sent to the server.
if frame.(*hybiFrameReader).header.MaskingKey == nil {
handler.WriteClose(closeStatusProtocolError)
return nil, io.EOF
}
} else {
// The server MUST NOT mask all frames.
if frame.(*hybiFrameReader).header.MaskingKey != nil {
handler.WriteClose(closeStatusProtocolError)
return nil, io.EOF
}
}
if header := frame.HeaderReader(); header != nil {
io.Copy(ioutil.Discard, header)
}
switch frame.PayloadType() {
case ContinuationFrame:
frame.(*hybiFrameReader).header.OpCode = handler.payloadType
case TextFrame, BinaryFrame:
handler.payloadType = frame.PayloadType()
case CloseFrame:
return nil, io.EOF
case PingFrame:
pingMsg := make([]byte, maxControlFramePayloadLength)
n, err := io.ReadFull(frame, pingMsg)
if err != nil && err != io.ErrUnexpectedEOF {
return nil, err
}
io.Copy(ioutil.Discard, frame)
n, err = handler.WritePong(pingMsg[:n])
if err != nil {
return nil, err
}
return nil, nil
case PongFrame:
return nil, ErrNotImplemented
}
return frame, nil
}
func (handler *hybiFrameHandler) WriteClose(status int) (err error) {
handler.conn.wio.Lock()
defer handler.conn.wio.Unlock()
w, err := handler.conn.frameWriterFactory.NewFrameWriter(CloseFrame)
if err != nil {
return err
}
msg := make([]byte, 2)
binary.BigEndian.PutUint16(msg, uint16(status))
_, err = w.Write(msg)
w.Close()
return err
}
func (handler *hybiFrameHandler) WritePong(msg []byte) (n int, err error) {
handler.conn.wio.Lock()
defer handler.conn.wio.Unlock()
w, err := handler.conn.frameWriterFactory.NewFrameWriter(PongFrame)
if err != nil {
return 0, err
}
n, err = w.Write(msg)
w.Close()
return n, err
}
// newHybiConn creates a new WebSocket connection speaking hybi draft protocol.
func newHybiConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
if buf == nil {
br := bufio.NewReader(rwc)
bw := bufio.NewWriter(rwc)
buf = bufio.NewReadWriter(br, bw)
}
ws := &Conn{config: config, request: request, buf: buf, rwc: rwc,
frameReaderFactory: hybiFrameReaderFactory{buf.Reader},
frameWriterFactory: hybiFrameWriterFactory{
buf.Writer, request == nil},
PayloadType: TextFrame,
defaultCloseStatus: closeStatusNormal}
ws.frameHandler = &hybiFrameHandler{conn: ws}
return ws
}
// generateMaskingKey generates a masking key for a frame.
func generateMaskingKey() (maskingKey []byte, err error) {
maskingKey = make([]byte, 4)
if _, err = io.ReadFull(rand.Reader, maskingKey); err != nil {
return
}
return
}
// generateNonce generates a nonce consisting of a randomly selected 16-byte
// value that has been base64-encoded.
func generateNonce() (nonce []byte) {
key := make([]byte, 16)
if _, err := io.ReadFull(rand.Reader, key); err != nil {
panic(err)
}
nonce = make([]byte, 24)
base64.StdEncoding.Encode(nonce, key)
return
}
// getNonceAccept computes the base64-encoded SHA-1 of the concatenation of
// the nonce ("Sec-WebSocket-Key" value) with the websocket GUID string.
func getNonceAccept(nonce []byte) (expected []byte, err error) {
h := sha1.New()
if _, err = h.Write(nonce); err != nil {
return
}
if _, err = h.Write([]byte(websocketGUID)); err != nil {
return
}
expected = make([]byte, 28)
base64.StdEncoding.Encode(expected, h.Sum(nil))
return
}
// Client handshake described in draft-ietf-hybi-thewebsocket-protocol-17
func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) {
bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n")
bw.WriteString("Host: " + config.Location.Host + "\r\n")
bw.WriteString("Upgrade: websocket\r\n")
bw.WriteString("Connection: Upgrade\r\n")
nonce := generateNonce()
if config.handshakeData != nil {
nonce = []byte(config.handshakeData["key"])
}
bw.WriteString("Sec-WebSocket-Key: " + string(nonce) + "\r\n")
bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n")
if config.Version != ProtocolVersionHybi13 {
return ErrBadProtocolVersion
}
bw.WriteString("Sec-WebSocket-Version: " + fmt.Sprintf("%d", config.Version) + "\r\n")
if len(config.Protocol) > 0 {
bw.WriteString("Sec-WebSocket-Protocol: " + strings.Join(config.Protocol, ", ") + "\r\n")
}
// TODO(ukai): send Sec-WebSocket-Extensions.
err = config.Header.WriteSubset(bw, handshakeHeader)
if err != nil {
return err
}
bw.WriteString("\r\n")
if err = bw.Flush(); err != nil {
return err
}
resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
if err != nil {
return err
}
if resp.StatusCode != 101 {
return ErrBadStatus
}
if strings.ToLower(resp.Header.Get("Upgrade")) != "websocket" ||
strings.ToLower(resp.Header.Get("Connection")) != "upgrade" {
return ErrBadUpgrade
}
expectedAccept, err := getNonceAccept(nonce)
if err != nil {
return err
}
if resp.Header.Get("Sec-WebSocket-Accept") != string(expectedAccept) {
return ErrChallengeResponse
}
if resp.Header.Get("Sec-WebSocket-Extensions") != "" {
return ErrUnsupportedExtensions
}
offeredProtocol := resp.Header.Get("Sec-WebSocket-Protocol")
if offeredProtocol != "" {
protocolMatched := false
for i := 0; i < len(config.Protocol); i++ {
if config.Protocol[i] == offeredProtocol {
protocolMatched = true
break
}
}
if !protocolMatched {
return ErrBadWebSocketProtocol
}
config.Protocol = []string{offeredProtocol}
}
return nil
}
// newHybiClientConn creates a client WebSocket connection after handshake.
func newHybiClientConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn {
return newHybiConn(config, buf, rwc, nil)
}
// A HybiServerHandshaker performs a server handshake using hybi draft protocol.
type hybiServerHandshaker struct {
*Config
accept []byte
}
func (c *hybiServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) {
c.Version = ProtocolVersionHybi13
if req.Method != "GET" {
return http.StatusMethodNotAllowed, ErrBadRequestMethod
}
// HTTP version can be safely ignored.
if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" ||
!strings.Contains(strings.ToLower(req.Header.Get("Connection")), "upgrade") {
return http.StatusBadRequest, ErrNotWebSocket
}
key := req.Header.Get("Sec-Websocket-Key")
if key == "" {
return http.StatusBadRequest, ErrChallengeResponse
}
version := req.Header.Get("Sec-Websocket-Version")
switch version {
case "13":
c.Version = ProtocolVersionHybi13
default:
return http.StatusBadRequest, ErrBadWebSocketVersion
}
var scheme string
if req.TLS != nil {
scheme = "wss"
} else {
scheme = "ws"
}
c.Location, err = url.ParseRequestURI(scheme + "://" + req.Host + req.URL.RequestURI())
if err != nil {
return http.StatusBadRequest, err
}
protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol"))
if protocol != "" {
protocols := strings.Split(protocol, ",")
for i := 0; i < len(protocols); i++ {
c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i]))
}
}
c.accept, err = getNonceAccept([]byte(key))
if err != nil {
return http.StatusInternalServerError, err
}
return http.StatusSwitchingProtocols, nil
}
// Origin parses Origin header in "req".
// If origin is "null", returns (nil, nil).
func Origin(config *Config, req *http.Request) (*url.URL, error) {
var origin string
switch config.Version {
case ProtocolVersionHybi13:
origin = req.Header.Get("Origin")
}
if origin == "null" {
return nil, nil
}
return url.ParseRequestURI(origin)
}
func (c *hybiServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) {
if len(c.Protocol) > 0 {
if len(c.Protocol) != 1 {
// You need choose a Protocol in Handshake func in Server.
return ErrBadWebSocketProtocol
}
}
buf.WriteString("HTTP/1.1 101 Switching Protocols\r\n")
buf.WriteString("Upgrade: websocket\r\n")
buf.WriteString("Connection: Upgrade\r\n")
buf.WriteString("Sec-WebSocket-Accept: " + string(c.accept) + "\r\n")
if len(c.Protocol) > 0 {
buf.WriteString("Sec-WebSocket-Protocol: " + c.Protocol[0] + "\r\n")
}
// TODO(ukai): send Sec-WebSocket-Extensions.
if c.Header != nil {
err := c.Header.WriteSubset(buf, handshakeHeader)
if err != nil {
return err
}
}
buf.WriteString("\r\n")
return buf.Flush()
}
func (c *hybiServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
return newHybiServerConn(c.Config, buf, rwc, request)
}
// newHybiServerConn returns a new WebSocket connection speaking hybi draft protocol.
func newHybiServerConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
return newHybiConn(config, buf, rwc, request)
}

@ -1,590 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"bufio"
"bytes"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"testing"
)
// Test the getNonceAccept function with values in
// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17
func TestSecWebSocketAccept(t *testing.T) {
nonce := []byte("dGhlIHNhbXBsZSBub25jZQ==")
expected := []byte("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
accept, err := getNonceAccept(nonce)
if err != nil {
t.Errorf("getNonceAccept: returned error %v", err)
return
}
if !bytes.Equal(expected, accept) {
t.Errorf("getNonceAccept: expected %q got %q", expected, accept)
}
}
func TestHybiClientHandshake(t *testing.T) {
b := bytes.NewBuffer([]byte{})
bw := bufio.NewWriter(b)
br := bufio.NewReader(strings.NewReader(`HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
`))
var err error
config := new(Config)
config.Location, err = url.ParseRequestURI("ws://server.example.com/chat")
if err != nil {
t.Fatal("location url", err)
}
config.Origin, err = url.ParseRequestURI("http://example.com")
if err != nil {
t.Fatal("origin url", err)
}
config.Protocol = append(config.Protocol, "chat")
config.Protocol = append(config.Protocol, "superchat")
config.Version = ProtocolVersionHybi13
config.handshakeData = map[string]string{
"key": "dGhlIHNhbXBsZSBub25jZQ==",
}
err = hybiClientHandshake(config, br, bw)
if err != nil {
t.Errorf("handshake failed: %v", err)
}
req, err := http.ReadRequest(bufio.NewReader(b))
if err != nil {
t.Fatalf("read request: %v", err)
}
if req.Method != "GET" {
t.Errorf("request method expected GET, but got %q", req.Method)
}
if req.URL.Path != "/chat" {
t.Errorf("request path expected /chat, but got %q", req.URL.Path)
}
if req.Proto != "HTTP/1.1" {
t.Errorf("request proto expected HTTP/1.1, but got %q", req.Proto)
}
if req.Host != "server.example.com" {
t.Errorf("request Host expected server.example.com, but got %v", req.Host)
}
var expectedHeader = map[string]string{
"Connection": "Upgrade",
"Upgrade": "websocket",
"Sec-Websocket-Key": config.handshakeData["key"],
"Origin": config.Origin.String(),
"Sec-Websocket-Protocol": "chat, superchat",
"Sec-Websocket-Version": fmt.Sprintf("%d", ProtocolVersionHybi13),
}
for k, v := range expectedHeader {
if req.Header.Get(k) != v {
t.Errorf(fmt.Sprintf("%s expected %q but got %q", k, v, req.Header.Get(k)))
}
}
}
func TestHybiClientHandshakeWithHeader(t *testing.T) {
b := bytes.NewBuffer([]byte{})
bw := bufio.NewWriter(b)
br := bufio.NewReader(strings.NewReader(`HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
`))
var err error
config := new(Config)
config.Location, err = url.ParseRequestURI("ws://server.example.com/chat")
if err != nil {
t.Fatal("location url", err)
}
config.Origin, err = url.ParseRequestURI("http://example.com")
if err != nil {
t.Fatal("origin url", err)
}
config.Protocol = append(config.Protocol, "chat")
config.Protocol = append(config.Protocol, "superchat")
config.Version = ProtocolVersionHybi13
config.Header = http.Header(make(map[string][]string))
config.Header.Add("User-Agent", "test")
config.handshakeData = map[string]string{
"key": "dGhlIHNhbXBsZSBub25jZQ==",
}
err = hybiClientHandshake(config, br, bw)
if err != nil {
t.Errorf("handshake failed: %v", err)
}
req, err := http.ReadRequest(bufio.NewReader(b))
if err != nil {
t.Fatalf("read request: %v", err)
}
if req.Method != "GET" {
t.Errorf("request method expected GET, but got %q", req.Method)
}
if req.URL.Path != "/chat" {
t.Errorf("request path expected /chat, but got %q", req.URL.Path)
}
if req.Proto != "HTTP/1.1" {
t.Errorf("request proto expected HTTP/1.1, but got %q", req.Proto)
}
if req.Host != "server.example.com" {
t.Errorf("request Host expected server.example.com, but got %v", req.Host)
}
var expectedHeader = map[string]string{
"Connection": "Upgrade",
"Upgrade": "websocket",
"Sec-Websocket-Key": config.handshakeData["key"],
"Origin": config.Origin.String(),
"Sec-Websocket-Protocol": "chat, superchat",
"Sec-Websocket-Version": fmt.Sprintf("%d", ProtocolVersionHybi13),
"User-Agent": "test",
}
for k, v := range expectedHeader {
if req.Header.Get(k) != v {
t.Errorf(fmt.Sprintf("%s expected %q but got %q", k, v, req.Header.Get(k)))
}
}
}
func TestHybiServerHandshake(t *testing.T) {
config := new(Config)
handshaker := &hybiServerHandshaker{Config: config}
br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
`))
req, err := http.ReadRequest(br)
if err != nil {
t.Fatal("request", err)
}
code, err := handshaker.ReadHandshake(br, req)
if err != nil {
t.Errorf("handshake failed: %v", err)
}
if code != http.StatusSwitchingProtocols {
t.Errorf("status expected %q but got %q", http.StatusSwitchingProtocols, code)
}
expectedProtocols := []string{"chat", "superchat"}
if fmt.Sprintf("%v", config.Protocol) != fmt.Sprintf("%v", expectedProtocols) {
t.Errorf("protocol expected %q but got %q", expectedProtocols, config.Protocol)
}
b := bytes.NewBuffer([]byte{})
bw := bufio.NewWriter(b)
config.Protocol = config.Protocol[:1]
err = handshaker.AcceptHandshake(bw)
if err != nil {
t.Errorf("handshake response failed: %v", err)
}
expectedResponse := strings.Join([]string{
"HTTP/1.1 101 Switching Protocols",
"Upgrade: websocket",
"Connection: Upgrade",
"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",
"Sec-WebSocket-Protocol: chat",
"", ""}, "\r\n")
if b.String() != expectedResponse {
t.Errorf("handshake expected %q but got %q", expectedResponse, b.String())
}
}
func TestHybiServerHandshakeNoSubProtocol(t *testing.T) {
config := new(Config)
handshaker := &hybiServerHandshaker{Config: config}
br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Version: 13
`))
req, err := http.ReadRequest(br)
if err != nil {
t.Fatal("request", err)
}
code, err := handshaker.ReadHandshake(br, req)
if err != nil {
t.Errorf("handshake failed: %v", err)
}
if code != http.StatusSwitchingProtocols {
t.Errorf("status expected %q but got %q", http.StatusSwitchingProtocols, code)
}
if len(config.Protocol) != 0 {
t.Errorf("len(config.Protocol) expected 0, but got %q", len(config.Protocol))
}
b := bytes.NewBuffer([]byte{})
bw := bufio.NewWriter(b)
err = handshaker.AcceptHandshake(bw)
if err != nil {
t.Errorf("handshake response failed: %v", err)
}
expectedResponse := strings.Join([]string{
"HTTP/1.1 101 Switching Protocols",
"Upgrade: websocket",
"Connection: Upgrade",
"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",
"", ""}, "\r\n")
if b.String() != expectedResponse {
t.Errorf("handshake expected %q but got %q", expectedResponse, b.String())
}
}
func TestHybiServerHandshakeHybiBadVersion(t *testing.T) {
config := new(Config)
handshaker := &hybiServerHandshaker{Config: config}
br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 9
`))
req, err := http.ReadRequest(br)
if err != nil {
t.Fatal("request", err)
}
code, err := handshaker.ReadHandshake(br, req)
if err != ErrBadWebSocketVersion {
t.Errorf("handshake expected err %q but got %q", ErrBadWebSocketVersion, err)
}
if code != http.StatusBadRequest {
t.Errorf("status expected %q but got %q", http.StatusBadRequest, code)
}
}
func testHybiFrame(t *testing.T, testHeader, testPayload, testMaskedPayload []byte, frameHeader *hybiFrameHeader) {
b := bytes.NewBuffer([]byte{})
frameWriterFactory := &hybiFrameWriterFactory{bufio.NewWriter(b), false}
w, _ := frameWriterFactory.NewFrameWriter(TextFrame)
w.(*hybiFrameWriter).header = frameHeader
_, err := w.Write(testPayload)
w.Close()
if err != nil {
t.Errorf("Write error %q", err)
}
var expectedFrame []byte
expectedFrame = append(expectedFrame, testHeader...)
expectedFrame = append(expectedFrame, testMaskedPayload...)
if !bytes.Equal(expectedFrame, b.Bytes()) {
t.Errorf("frame expected %q got %q", expectedFrame, b.Bytes())
}
frameReaderFactory := &hybiFrameReaderFactory{bufio.NewReader(b)}
r, err := frameReaderFactory.NewFrameReader()
if err != nil {
t.Errorf("Read error %q", err)
}
if header := r.HeaderReader(); header == nil {
t.Errorf("no header")
} else {
actualHeader := make([]byte, r.Len())
n, err := header.Read(actualHeader)
if err != nil {
t.Errorf("Read header error %q", err)
} else {
if n < len(testHeader) {
t.Errorf("header too short %q got %q", testHeader, actualHeader[:n])
}
if !bytes.Equal(testHeader, actualHeader[:n]) {
t.Errorf("header expected %q got %q", testHeader, actualHeader[:n])
}
}
}
if trailer := r.TrailerReader(); trailer != nil {
t.Errorf("unexpected trailer %q", trailer)
}
frame := r.(*hybiFrameReader)
if frameHeader.Fin != frame.header.Fin ||
frameHeader.OpCode != frame.header.OpCode ||
len(testPayload) != int(frame.header.Length) {
t.Errorf("mismatch %v (%d) vs %v", frameHeader, len(testPayload), frame)
}
payload := make([]byte, len(testPayload))
_, err = r.Read(payload)
if err != nil {
t.Errorf("read %v", err)
}
if !bytes.Equal(testPayload, payload) {
t.Errorf("payload %q vs %q", testPayload, payload)
}
}
func TestHybiShortTextFrame(t *testing.T) {
frameHeader := &hybiFrameHeader{Fin: true, OpCode: TextFrame}
payload := []byte("hello")
testHybiFrame(t, []byte{0x81, 0x05}, payload, payload, frameHeader)
payload = make([]byte, 125)
testHybiFrame(t, []byte{0x81, 125}, payload, payload, frameHeader)
}
func TestHybiShortMaskedTextFrame(t *testing.T) {
frameHeader := &hybiFrameHeader{Fin: true, OpCode: TextFrame,
MaskingKey: []byte{0xcc, 0x55, 0x80, 0x20}}
payload := []byte("hello")
maskedPayload := []byte{0xa4, 0x30, 0xec, 0x4c, 0xa3}
header := []byte{0x81, 0x85}
header = append(header, frameHeader.MaskingKey...)
testHybiFrame(t, header, payload, maskedPayload, frameHeader)
}
func TestHybiShortBinaryFrame(t *testing.T) {
frameHeader := &hybiFrameHeader{Fin: true, OpCode: BinaryFrame}
payload := []byte("hello")
testHybiFrame(t, []byte{0x82, 0x05}, payload, payload, frameHeader)
payload = make([]byte, 125)
testHybiFrame(t, []byte{0x82, 125}, payload, payload, frameHeader)
}
func TestHybiControlFrame(t *testing.T) {
frameHeader := &hybiFrameHeader{Fin: true, OpCode: PingFrame}
payload := []byte("hello")
testHybiFrame(t, []byte{0x89, 0x05}, payload, payload, frameHeader)
frameHeader = &hybiFrameHeader{Fin: true, OpCode: PongFrame}
testHybiFrame(t, []byte{0x8A, 0x05}, payload, payload, frameHeader)
frameHeader = &hybiFrameHeader{Fin: true, OpCode: CloseFrame}
payload = []byte{0x03, 0xe8} // 1000
testHybiFrame(t, []byte{0x88, 0x02}, payload, payload, frameHeader)
}
func TestHybiLongFrame(t *testing.T) {
frameHeader := &hybiFrameHeader{Fin: true, OpCode: TextFrame}
payload := make([]byte, 126)
testHybiFrame(t, []byte{0x81, 126, 0x00, 126}, payload, payload, frameHeader)
payload = make([]byte, 65535)
testHybiFrame(t, []byte{0x81, 126, 0xff, 0xff}, payload, payload, frameHeader)
payload = make([]byte, 65536)
testHybiFrame(t, []byte{0x81, 127, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}, payload, payload, frameHeader)
}
func TestHybiClientRead(t *testing.T) {
wireData := []byte{0x81, 0x05, 'h', 'e', 'l', 'l', 'o',
0x89, 0x05, 'h', 'e', 'l', 'l', 'o', // ping
0x81, 0x05, 'w', 'o', 'r', 'l', 'd'}
br := bufio.NewReader(bytes.NewBuffer(wireData))
bw := bufio.NewWriter(bytes.NewBuffer([]byte{}))
conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, nil)
msg := make([]byte, 512)
n, err := conn.Read(msg)
if err != nil {
t.Errorf("read 1st frame, error %q", err)
}
if n != 5 {
t.Errorf("read 1st frame, expect 5, got %d", n)
}
if !bytes.Equal(wireData[2:7], msg[:n]) {
t.Errorf("read 1st frame %v, got %v", wireData[2:7], msg[:n])
}
n, err = conn.Read(msg)
if err != nil {
t.Errorf("read 2nd frame, error %q", err)
}
if n != 5 {
t.Errorf("read 2nd frame, expect 5, got %d", n)
}
if !bytes.Equal(wireData[16:21], msg[:n]) {
t.Errorf("read 2nd frame %v, got %v", wireData[16:21], msg[:n])
}
n, err = conn.Read(msg)
if err == nil {
t.Errorf("read not EOF")
}
if n != 0 {
t.Errorf("expect read 0, got %d", n)
}
}
func TestHybiShortRead(t *testing.T) {
wireData := []byte{0x81, 0x05, 'h', 'e', 'l', 'l', 'o',
0x89, 0x05, 'h', 'e', 'l', 'l', 'o', // ping
0x81, 0x05, 'w', 'o', 'r', 'l', 'd'}
br := bufio.NewReader(bytes.NewBuffer(wireData))
bw := bufio.NewWriter(bytes.NewBuffer([]byte{}))
conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, nil)
step := 0
pos := 0
expectedPos := []int{2, 5, 16, 19}
expectedLen := []int{3, 2, 3, 2}
for {
msg := make([]byte, 3)
n, err := conn.Read(msg)
if step >= len(expectedPos) {
if err == nil {
t.Errorf("read not EOF")
}
if n != 0 {
t.Errorf("expect read 0, got %d", n)
}
return
}
pos = expectedPos[step]
endPos := pos + expectedLen[step]
if err != nil {
t.Errorf("read from %d, got error %q", pos, err)
return
}
if n != endPos-pos {
t.Errorf("read from %d, expect %d, got %d", pos, endPos-pos, n)
}
if !bytes.Equal(wireData[pos:endPos], msg[:n]) {
t.Errorf("read from %d, frame %v, got %v", pos, wireData[pos:endPos], msg[:n])
}
step++
}
}
func TestHybiServerRead(t *testing.T) {
wireData := []byte{0x81, 0x85, 0xcc, 0x55, 0x80, 0x20,
0xa4, 0x30, 0xec, 0x4c, 0xa3, // hello
0x89, 0x85, 0xcc, 0x55, 0x80, 0x20,
0xa4, 0x30, 0xec, 0x4c, 0xa3, // ping: hello
0x81, 0x85, 0xed, 0x83, 0xb4, 0x24,
0x9a, 0xec, 0xc6, 0x48, 0x89, // world
}
br := bufio.NewReader(bytes.NewBuffer(wireData))
bw := bufio.NewWriter(bytes.NewBuffer([]byte{}))
conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, new(http.Request))
expected := [][]byte{[]byte("hello"), []byte("world")}
msg := make([]byte, 512)
n, err := conn.Read(msg)
if err != nil {
t.Errorf("read 1st frame, error %q", err)
}
if n != 5 {
t.Errorf("read 1st frame, expect 5, got %d", n)
}
if !bytes.Equal(expected[0], msg[:n]) {
t.Errorf("read 1st frame %q, got %q", expected[0], msg[:n])
}
n, err = conn.Read(msg)
if err != nil {
t.Errorf("read 2nd frame, error %q", err)
}
if n != 5 {
t.Errorf("read 2nd frame, expect 5, got %d", n)
}
if !bytes.Equal(expected[1], msg[:n]) {
t.Errorf("read 2nd frame %q, got %q", expected[1], msg[:n])
}
n, err = conn.Read(msg)
if err == nil {
t.Errorf("read not EOF")
}
if n != 0 {
t.Errorf("expect read 0, got %d", n)
}
}
func TestHybiServerReadWithoutMasking(t *testing.T) {
wireData := []byte{0x81, 0x05, 'h', 'e', 'l', 'l', 'o'}
br := bufio.NewReader(bytes.NewBuffer(wireData))
bw := bufio.NewWriter(bytes.NewBuffer([]byte{}))
conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, new(http.Request))
// server MUST close the connection upon receiving a non-masked frame.
msg := make([]byte, 512)
_, err := conn.Read(msg)
if err != io.EOF {
t.Errorf("read 1st frame, expect %q, but got %q", io.EOF, err)
}
}
func TestHybiClientReadWithMasking(t *testing.T) {
wireData := []byte{0x81, 0x85, 0xcc, 0x55, 0x80, 0x20,
0xa4, 0x30, 0xec, 0x4c, 0xa3, // hello
}
br := bufio.NewReader(bytes.NewBuffer(wireData))
bw := bufio.NewWriter(bytes.NewBuffer([]byte{}))
conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, nil)
// client MUST close the connection upon receiving a masked frame.
msg := make([]byte, 512)
_, err := conn.Read(msg)
if err != io.EOF {
t.Errorf("read 1st frame, expect %q, but got %q", io.EOF, err)
}
}
// Test the hybiServerHandshaker supports firefox implementation and
// checks Connection request header include (but it's not necessary
// equal to) "upgrade"
func TestHybiServerFirefoxHandshake(t *testing.T) {
config := new(Config)
handshaker := &hybiServerHandshaker{Config: config}
br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: keep-alive, upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
`))
req, err := http.ReadRequest(br)
if err != nil {
t.Fatal("request", err)
}
code, err := handshaker.ReadHandshake(br, req)
if err != nil {
t.Errorf("handshake failed: %v", err)
}
if code != http.StatusSwitchingProtocols {
t.Errorf("status expected %q but got %q", http.StatusSwitchingProtocols, code)
}
b := bytes.NewBuffer([]byte{})
bw := bufio.NewWriter(b)
config.Protocol = []string{"chat"}
err = handshaker.AcceptHandshake(bw)
if err != nil {
t.Errorf("handshake response failed: %v", err)
}
expectedResponse := strings.Join([]string{
"HTTP/1.1 101 Switching Protocols",
"Upgrade: websocket",
"Connection: Upgrade",
"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",
"Sec-WebSocket-Protocol: chat",
"", ""}, "\r\n")
if b.String() != expectedResponse {
t.Errorf("handshake expected %q but got %q", expectedResponse, b.String())
}
}

@ -1,114 +0,0 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package websocket
import (
"bufio"
"fmt"
"io"
"net/http"
)
func newServerConn(rwc io.ReadWriteCloser, buf *bufio.ReadWriter, req *http.Request, config *Config, handshake func(*Config, *http.Request) error) (conn *Conn, err error) {
var hs serverHandshaker = &hybiServerHandshaker{Config: config}
code, err := hs.ReadHandshake(buf.Reader, req)
if err == ErrBadWebSocketVersion {
fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
fmt.Fprintf(buf, "Sec-WebSocket-Version: %s\r\n", SupportedProtocolVersion)
buf.WriteString("\r\n")
buf.WriteString(err.Error())
buf.Flush()
return
}
if err != nil {
fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
buf.WriteString("\r\n")
buf.WriteString(err.Error())
buf.Flush()
return
}
if handshake != nil {
err = handshake(config, req)
if err != nil {
code = http.StatusForbidden
fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
buf.WriteString("\r\n")
buf.Flush()
return
}
}
err = hs.AcceptHandshake(buf.Writer)
if err != nil {
code = http.StatusBadRequest
fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
buf.WriteString("\r\n")
buf.Flush()
return
}
conn = hs.NewServerConn(buf, rwc, req)
return
}
// Server represents a server of a WebSocket.
type Server struct {
// Config is a WebSocket configuration for new WebSocket connection.
Config
// Handshake is an optional function in WebSocket handshake.
// For example, you can check, or don't check Origin header.
// Another example, you can select config.Protocol.
Handshake func(*Config, *http.Request) error
// Handler handles a WebSocket connection.
Handler
}
// ServeHTTP implements the http.Handler interface for a WebSocket
func (s Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
s.serveWebSocket(w, req)
}
func (s Server) serveWebSocket(w http.ResponseWriter, req *http.Request) {
rwc, buf, err := w.(http.Hijacker).Hijack()
if err != nil {
panic("Hijack failed: " + err.Error())
return
}
// The server should abort the WebSocket connection if it finds
// the client did not send a handshake that matches with protocol
// specification.
defer rwc.Close()
conn, err := newServerConn(rwc, buf, req, &s.Config, s.Handshake)
if err != nil {
return
}
if conn == nil {
panic("unexpected nil conn")
}
s.Handler(conn)
}
// Handler is a simple interface to a WebSocket browser client.
// It checks if Origin header is valid URL by default.
// You might want to verify websocket.Conn.Config().Origin in the func.
// If you use Server instead of Handler, you could call websocket.Origin and
// check the origin in your Handshake func. So, if you want to accept
// non-browser client, which doesn't send Origin header, you could use Server
//. that doesn't check origin in its Handshake.
type Handler func(*Conn)
func checkOrigin(config *Config, req *http.Request) (err error) {
config.Origin, err = Origin(config, req)
if err == nil && config.Origin == nil {
return fmt.Errorf("null origin")
}
return err
}
// ServeHTTP implements the http.Handler interface for a WebSocket
func (h Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
s := Server{Handler: h, Handshake: checkOrigin}
s.serveWebSocket(w, req)
}

@ -1,411 +0,0 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package websocket implements a client and server for the WebSocket protocol
// as specified in RFC 6455.
package websocket
import (
"bufio"
"crypto/tls"
"encoding/json"
"errors"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"sync"
"time"
)
const (
ProtocolVersionHybi13 = 13
ProtocolVersionHybi = ProtocolVersionHybi13
SupportedProtocolVersion = "13"
ContinuationFrame = 0
TextFrame = 1
BinaryFrame = 2
CloseFrame = 8
PingFrame = 9
PongFrame = 10
UnknownFrame = 255
)
// ProtocolError represents WebSocket protocol errors.
type ProtocolError struct {
ErrorString string
}
func (err *ProtocolError) Error() string { return err.ErrorString }
var (
ErrBadProtocolVersion = &ProtocolError{"bad protocol version"}
ErrBadScheme = &ProtocolError{"bad scheme"}
ErrBadStatus = &ProtocolError{"bad status"}
ErrBadUpgrade = &ProtocolError{"missing or bad upgrade"}
ErrBadWebSocketOrigin = &ProtocolError{"missing or bad WebSocket-Origin"}
ErrBadWebSocketLocation = &ProtocolError{"missing or bad WebSocket-Location"}
ErrBadWebSocketProtocol = &ProtocolError{"missing or bad WebSocket-Protocol"}
ErrBadWebSocketVersion = &ProtocolError{"missing or bad WebSocket Version"}
ErrChallengeResponse = &ProtocolError{"mismatch challenge/response"}
ErrBadFrame = &ProtocolError{"bad frame"}
ErrBadFrameBoundary = &ProtocolError{"not on frame boundary"}
ErrNotWebSocket = &ProtocolError{"not websocket protocol"}
ErrBadRequestMethod = &ProtocolError{"bad method"}
ErrNotSupported = &ProtocolError{"not supported"}
)
// Addr is an implementation of net.Addr for WebSocket.
type Addr struct {
*url.URL
}
// Network returns the network type for a WebSocket, "websocket".
func (addr *Addr) Network() string { return "websocket" }
// Config is a WebSocket configuration
type Config struct {
// A WebSocket server address.
Location *url.URL
// A Websocket client origin.
Origin *url.URL
// WebSocket subprotocols.
Protocol []string
// WebSocket protocol version.
Version int
// TLS config for secure WebSocket (wss).
TlsConfig *tls.Config
// Additional header fields to be sent in WebSocket opening handshake.
Header http.Header
handshakeData map[string]string
}
// serverHandshaker is an interface to handle WebSocket server side handshake.
type serverHandshaker interface {
// ReadHandshake reads handshake request message from client.
// Returns http response code and error if any.
ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error)
// AcceptHandshake accepts the client handshake request and sends
// handshake response back to client.
AcceptHandshake(buf *bufio.Writer) (err error)
// NewServerConn creates a new WebSocket connection.
NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) (conn *Conn)
}
// frameReader is an interface to read a WebSocket frame.
type frameReader interface {
// Reader is to read payload of the frame.
io.Reader
// PayloadType returns payload type.
PayloadType() byte
// HeaderReader returns a reader to read header of the frame.
HeaderReader() io.Reader
// TrailerReader returns a reader to read trailer of the frame.
// If it returns nil, there is no trailer in the frame.
TrailerReader() io.Reader
// Len returns total length of the frame, including header and trailer.
Len() int
}
// frameReaderFactory is an interface to creates new frame reader.
type frameReaderFactory interface {
NewFrameReader() (r frameReader, err error)
}
// frameWriter is an interface to write a WebSocket frame.
type frameWriter interface {
// Writer is to write payload of the frame.
io.WriteCloser
}
// frameWriterFactory is an interface to create new frame writer.
type frameWriterFactory interface {
NewFrameWriter(payloadType byte) (w frameWriter, err error)
}
type frameHandler interface {
HandleFrame(frame frameReader) (r frameReader, err error)
WriteClose(status int) (err error)
}
// Conn represents a WebSocket connection.
type Conn struct {
config *Config
request *http.Request
buf *bufio.ReadWriter
rwc io.ReadWriteCloser
rio sync.Mutex
frameReaderFactory
frameReader
wio sync.Mutex
frameWriterFactory
frameHandler
PayloadType byte
defaultCloseStatus int
}
// Read implements the io.Reader interface:
// it reads data of a frame from the WebSocket connection.
// if msg is not large enough for the frame data, it fills the msg and next Read
// will read the rest of the frame data.
// it reads Text frame or Binary frame.
func (ws *Conn) Read(msg []byte) (n int, err error) {
ws.rio.Lock()
defer ws.rio.Unlock()
again:
if ws.frameReader == nil {
frame, err := ws.frameReaderFactory.NewFrameReader()
if err != nil {
return 0, err
}
ws.frameReader, err = ws.frameHandler.HandleFrame(frame)
if err != nil {
return 0, err
}
if ws.frameReader == nil {
goto again
}
}
n, err = ws.frameReader.Read(msg)
if err == io.EOF {
if trailer := ws.frameReader.TrailerReader(); trailer != nil {
io.Copy(ioutil.Discard, trailer)
}
ws.frameReader = nil
goto again
}
return n, err
}
// Write implements the io.Writer interface:
// it writes data as a frame to the WebSocket connection.
func (ws *Conn) Write(msg []byte) (n int, err error) {
ws.wio.Lock()
defer ws.wio.Unlock()
w, err := ws.frameWriterFactory.NewFrameWriter(ws.PayloadType)
if err != nil {
return 0, err
}
n, err = w.Write(msg)
w.Close()
if err != nil {
return n, err
}
return n, err
}
// Close implements the io.Closer interface.
func (ws *Conn) Close() error {
err := ws.frameHandler.WriteClose(ws.defaultCloseStatus)
if err != nil {
return err
}
return ws.rwc.Close()
}
func (ws *Conn) IsClientConn() bool { return ws.request == nil }
func (ws *Conn) IsServerConn() bool { return ws.request != nil }
// LocalAddr returns the WebSocket Origin for the connection for client, or
// the WebSocket location for server.
func (ws *Conn) LocalAddr() net.Addr {
if ws.IsClientConn() {
return &Addr{ws.config.Origin}
}
return &Addr{ws.config.Location}
}
// RemoteAddr returns the WebSocket location for the connection for client, or
// the Websocket Origin for server.
func (ws *Conn) RemoteAddr() net.Addr {
if ws.IsClientConn() {
return &Addr{ws.config.Location}
}
return &Addr{ws.config.Origin}
}
var errSetDeadline = errors.New("websocket: cannot set deadline: not using a net.Conn")
// SetDeadline sets the connection's network read & write deadlines.
func (ws *Conn) SetDeadline(t time.Time) error {
if conn, ok := ws.rwc.(net.Conn); ok {
return conn.SetDeadline(t)
}
return errSetDeadline
}
// SetReadDeadline sets the connection's network read deadline.
func (ws *Conn) SetReadDeadline(t time.Time) error {
if conn, ok := ws.rwc.(net.Conn); ok {
return conn.SetReadDeadline(t)
}
return errSetDeadline
}
// SetWriteDeadline sets the connection's network write deadline.
func (ws *Conn) SetWriteDeadline(t time.Time) error {
if conn, ok := ws.rwc.(net.Conn); ok {
return conn.SetWriteDeadline(t)
}
return errSetDeadline
}
// Config returns the WebSocket config.
func (ws *Conn) Config() *Config { return ws.config }
// Request returns the http request upgraded to the WebSocket.
// It is nil for client side.
func (ws *Conn) Request() *http.Request { return ws.request }
// Codec represents a symmetric pair of functions that implement a codec.
type Codec struct {
Marshal func(v interface{}) (data []byte, payloadType byte, err error)
Unmarshal func(data []byte, payloadType byte, v interface{}) (err error)
}
// Send sends v marshaled by cd.Marshal as single frame to ws.
func (cd Codec) Send(ws *Conn, v interface{}) (err error) {
data, payloadType, err := cd.Marshal(v)
if err != nil {
return err
}
ws.wio.Lock()
defer ws.wio.Unlock()
w, err := ws.frameWriterFactory.NewFrameWriter(payloadType)
if err != nil {
return err
}
_, err = w.Write(data)
w.Close()
return err
}
// Receive receives single frame from ws, unmarshaled by cd.Unmarshal and stores in v.
func (cd Codec) Receive(ws *Conn, v interface{}) (err error) {
ws.rio.Lock()
defer ws.rio.Unlock()
if ws.frameReader != nil {
_, err = io.Copy(ioutil.Discard, ws.frameReader)
if err != nil {
return err
}
ws.frameReader = nil
}
again:
frame, err := ws.frameReaderFactory.NewFrameReader()
if err != nil {
return err
}
frame, err = ws.frameHandler.HandleFrame(frame)
if err != nil {
return err
}
if frame == nil {
goto again
}
payloadType := frame.PayloadType()
data, err := ioutil.ReadAll(frame)
if err != nil {
return err
}
return cd.Unmarshal(data, payloadType, v)
}
func marshal(v interface{}) (msg []byte, payloadType byte, err error) {
switch data := v.(type) {
case string:
return []byte(data), TextFrame, nil
case []byte:
return data, BinaryFrame, nil
}
return nil, UnknownFrame, ErrNotSupported
}
func unmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
switch data := v.(type) {
case *string:
*data = string(msg)
return nil
case *[]byte:
*data = msg
return nil
}
return ErrNotSupported
}
/*
Message is a codec to send/receive text/binary data in a frame on WebSocket connection.
To send/receive text frame, use string type.
To send/receive binary frame, use []byte type.
Trivial usage:
import "websocket"
// receive text frame
var message string
websocket.Message.Receive(ws, &message)
// send text frame
message = "hello"
websocket.Message.Send(ws, message)
// receive binary frame
var data []byte
websocket.Message.Receive(ws, &data)
// send binary frame
data = []byte{0, 1, 2}
websocket.Message.Send(ws, data)
*/
var Message = Codec{marshal, unmarshal}
func jsonMarshal(v interface{}) (msg []byte, payloadType byte, err error) {
msg, err = json.Marshal(v)
return msg, TextFrame, err
}
func jsonUnmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
return json.Unmarshal(msg, v)
}
/*
JSON is a codec to send/receive JSON data in a frame from a WebSocket connection.
Trivial usage:
import "websocket"
type T struct {
Msg string
Count int
}
// receive JSON type T
var data T
websocket.JSON.Receive(ws, &data)
// send JSON type T
websocket.JSON.Send(ws, data)
*/
var JSON = Codec{jsonMarshal, jsonUnmarshal}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save