mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
1) Change default gofmt default settings for
parsing and printing to new syntax. Use -oldparser to parse the old syntax, use -oldprinter to print the old syntax. 2) Change default gofmt formatting settings to use tabs for indentation only and to use spaces for alignment. This will make the code alignment insensitive to an editor's tabwidth. Use -spaces=false to use tabs for alignment. 3) Manually changed src/exp/parser/parser_test.go so that it doesn't try to parse the parser's source files using the old syntax (they have new syntax now). 4) gofmt -w src misc test/bench 5th and last set of files. R=rsc CC=golang-dev https://golang.org/cl/180050
This commit is contained in:
parent
d65a5cce89
commit
45ca9f7a9e
59 changed files with 5907 additions and 5907 deletions
|
|
@ -9,10 +9,10 @@
|
||||||
package syslog
|
package syslog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt";
|
"fmt"
|
||||||
"log";
|
"log"
|
||||||
"net";
|
"net"
|
||||||
"os";
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Priority int
|
type Priority int
|
||||||
|
|
@ -20,21 +20,21 @@ type Priority int
|
||||||
const (
|
const (
|
||||||
// From /usr/include/sys/syslog.h.
|
// From /usr/include/sys/syslog.h.
|
||||||
// These are the same on Linux, BSD, and OS X.
|
// These are the same on Linux, BSD, and OS X.
|
||||||
LOG_EMERG Priority = iota;
|
LOG_EMERG Priority = iota
|
||||||
LOG_ALERT;
|
LOG_ALERT
|
||||||
LOG_CRIT;
|
LOG_CRIT
|
||||||
LOG_ERR;
|
LOG_ERR
|
||||||
LOG_WARNING;
|
LOG_WARNING
|
||||||
LOG_NOTICE;
|
LOG_NOTICE
|
||||||
LOG_INFO;
|
LOG_INFO
|
||||||
LOG_DEBUG;
|
LOG_DEBUG
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Writer is a connection to a syslog server.
|
// A Writer is a connection to a syslog server.
|
||||||
type Writer struct {
|
type Writer struct {
|
||||||
priority Priority;
|
priority Priority
|
||||||
prefix string;
|
prefix string
|
||||||
conn net.Conn;
|
conn net.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
// New establishes a new connection to the system log daemon.
|
// New establishes a new connection to the system log daemon.
|
||||||
|
|
@ -52,23 +52,23 @@ func Dial(network, raddr string, priority Priority, prefix string) (w *Writer, e
|
||||||
if prefix == "" {
|
if prefix == "" {
|
||||||
prefix = os.Args[0]
|
prefix = os.Args[0]
|
||||||
}
|
}
|
||||||
var conn net.Conn;
|
var conn net.Conn
|
||||||
if network == "" {
|
if network == "" {
|
||||||
conn, err = unixSyslog()
|
conn, err = unixSyslog()
|
||||||
} else {
|
} else {
|
||||||
conn, err = net.Dial(network, "", raddr)
|
conn, err = net.Dial(network, "", raddr)
|
||||||
}
|
}
|
||||||
return &Writer{priority, prefix, conn}, err;
|
return &Writer{priority, prefix, conn}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func unixSyslog() (conn net.Conn, err os.Error) {
|
func unixSyslog() (conn net.Conn, err os.Error) {
|
||||||
logTypes := []string{"unixgram", "unix"};
|
logTypes := []string{"unixgram", "unix"}
|
||||||
logPaths := []string{"/dev/log", "/var/run/syslog"};
|
logPaths := []string{"/dev/log", "/var/run/syslog"}
|
||||||
var raddr string;
|
var raddr string
|
||||||
for _, network := range logTypes {
|
for _, network := range logTypes {
|
||||||
for _, path := range logPaths {
|
for _, path := range logPaths {
|
||||||
raddr = path;
|
raddr = path
|
||||||
conn, err := net.Dial(network, "", raddr);
|
conn, err := net.Dial(network, "", raddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -76,7 +76,7 @@ func unixSyslog() (conn net.Conn, err os.Error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, os.ErrorString("Unix syslog delivery error");
|
return nil, os.ErrorString("Unix syslog delivery error")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write sends a log message to the syslog daemon.
|
// Write sends a log message to the syslog daemon.
|
||||||
|
|
@ -84,7 +84,7 @@ func (w *Writer) Write(b []byte) (int, os.Error) {
|
||||||
if w.priority > LOG_DEBUG || w.priority < LOG_EMERG {
|
if w.priority > LOG_DEBUG || w.priority < LOG_EMERG {
|
||||||
return 0, os.EINVAL
|
return 0, os.EINVAL
|
||||||
}
|
}
|
||||||
return fmt.Fprintf(w.conn, "<%d>%s: %s\n", w.priority, w.prefix, b);
|
return fmt.Fprintf(w.conn, "<%d>%s: %s\n", w.priority, w.prefix, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) writeString(p Priority, s string) (int, os.Error) {
|
func (w *Writer) writeString(p Priority, s string) (int, os.Error) {
|
||||||
|
|
@ -95,40 +95,40 @@ func (w *Writer) Close() os.Error { return w.conn.Close() }
|
||||||
|
|
||||||
// Emerg logs a message using the LOG_EMERG priority.
|
// Emerg logs a message using the LOG_EMERG priority.
|
||||||
func (w *Writer) Emerg(m string) (err os.Error) {
|
func (w *Writer) Emerg(m string) (err os.Error) {
|
||||||
_, err = w.writeString(LOG_EMERG, m);
|
_, err = w.writeString(LOG_EMERG, m)
|
||||||
return err;
|
return err
|
||||||
}
|
}
|
||||||
// Crit logs a message using the LOG_CRIT priority.
|
// Crit logs a message using the LOG_CRIT priority.
|
||||||
func (w *Writer) Crit(m string) (err os.Error) {
|
func (w *Writer) Crit(m string) (err os.Error) {
|
||||||
_, err = w.writeString(LOG_CRIT, m);
|
_, err = w.writeString(LOG_CRIT, m)
|
||||||
return err;
|
return err
|
||||||
}
|
}
|
||||||
// ERR logs a message using the LOG_ERR priority.
|
// ERR logs a message using the LOG_ERR priority.
|
||||||
func (w *Writer) Err(m string) (err os.Error) {
|
func (w *Writer) Err(m string) (err os.Error) {
|
||||||
_, err = w.writeString(LOG_ERR, m);
|
_, err = w.writeString(LOG_ERR, m)
|
||||||
return err;
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warning logs a message using the LOG_WARNING priority.
|
// Warning logs a message using the LOG_WARNING priority.
|
||||||
func (w *Writer) Warning(m string) (err os.Error) {
|
func (w *Writer) Warning(m string) (err os.Error) {
|
||||||
_, err = w.writeString(LOG_WARNING, m);
|
_, err = w.writeString(LOG_WARNING, m)
|
||||||
return err;
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notice logs a message using the LOG_NOTICE priority.
|
// Notice logs a message using the LOG_NOTICE priority.
|
||||||
func (w *Writer) Notice(m string) (err os.Error) {
|
func (w *Writer) Notice(m string) (err os.Error) {
|
||||||
_, err = w.writeString(LOG_NOTICE, m);
|
_, err = w.writeString(LOG_NOTICE, m)
|
||||||
return err;
|
return err
|
||||||
}
|
}
|
||||||
// Info logs a message using the LOG_INFO priority.
|
// Info logs a message using the LOG_INFO priority.
|
||||||
func (w *Writer) Info(m string) (err os.Error) {
|
func (w *Writer) Info(m string) (err os.Error) {
|
||||||
_, err = w.writeString(LOG_INFO, m);
|
_, err = w.writeString(LOG_INFO, m)
|
||||||
return err;
|
return err
|
||||||
}
|
}
|
||||||
// Debug logs a message using the LOG_DEBUG priority.
|
// Debug logs a message using the LOG_DEBUG priority.
|
||||||
func (w *Writer) Debug(m string) (err os.Error) {
|
func (w *Writer) Debug(m string) (err os.Error) {
|
||||||
_, err = w.writeString(LOG_DEBUG, m);
|
_, err = w.writeString(LOG_DEBUG, m)
|
||||||
return err;
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLogger provides an object that implements the full log.Logger interface,
|
// NewLogger provides an object that implements the full log.Logger interface,
|
||||||
|
|
@ -136,9 +136,9 @@ func (w *Writer) Debug(m string) (err os.Error) {
|
||||||
// priority will be used for all messages sent using this interface.
|
// priority will be used for all messages sent using this interface.
|
||||||
// All messages are logged with priority p.
|
// All messages are logged with priority p.
|
||||||
func NewLogger(p Priority, flag int) *log.Logger {
|
func NewLogger(p Priority, flag int) *log.Logger {
|
||||||
s, err := New(p, "");
|
s, err := New(p, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return log.New(s, nil, "", flag);
|
return log.New(s, nil, "", flag)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,91 +4,91 @@
|
||||||
package syslog
|
package syslog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io";
|
"io"
|
||||||
"log";
|
"log"
|
||||||
"net";
|
"net"
|
||||||
"testing";
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
var serverAddr string
|
var serverAddr string
|
||||||
|
|
||||||
func runSyslog(c net.PacketConn, done chan<- string) {
|
func runSyslog(c net.PacketConn, done chan<- string) {
|
||||||
var buf [4096]byte;
|
var buf [4096]byte
|
||||||
var rcvd string = "";
|
var rcvd string = ""
|
||||||
for {
|
for {
|
||||||
n, _, err := c.ReadFrom(&buf);
|
n, _, err := c.ReadFrom(&buf)
|
||||||
if err != nil || n == 0 {
|
if err != nil || n == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
rcvd += string(buf[0:n]);
|
rcvd += string(buf[0:n])
|
||||||
}
|
}
|
||||||
done <- rcvd;
|
done <- rcvd
|
||||||
}
|
}
|
||||||
|
|
||||||
func startServer(done chan<- string) {
|
func startServer(done chan<- string) {
|
||||||
c, e := net.ListenPacket("udp", ":0");
|
c, e := net.ListenPacket("udp", ":0")
|
||||||
if e != nil {
|
if e != nil {
|
||||||
log.Exitf("net.ListenPacket failed udp :0 %v", e)
|
log.Exitf("net.ListenPacket failed udp :0 %v", e)
|
||||||
}
|
}
|
||||||
serverAddr = c.LocalAddr().String();
|
serverAddr = c.LocalAddr().String()
|
||||||
c.SetReadTimeout(10e6); // 10ms
|
c.SetReadTimeout(10e6) // 10ms
|
||||||
go runSyslog(c, done);
|
go runSyslog(c, done)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNew(t *testing.T) {
|
func TestNew(t *testing.T) {
|
||||||
s, err := New(LOG_INFO, "");
|
s, err := New(LOG_INFO, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("New() failed: %s", err)
|
t.Fatalf("New() failed: %s", err)
|
||||||
}
|
}
|
||||||
// Don't send any messages.
|
// Don't send any messages.
|
||||||
s.Close();
|
s.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewLogger(t *testing.T) {
|
func TestNewLogger(t *testing.T) {
|
||||||
f := NewLogger(LOG_INFO, 0);
|
f := NewLogger(LOG_INFO, 0)
|
||||||
if f == nil {
|
if f == nil {
|
||||||
t.Errorf("NewLogger() failed\n")
|
t.Errorf("NewLogger() failed\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDial(t *testing.T) {
|
func TestDial(t *testing.T) {
|
||||||
l, err := Dial("", "", LOG_ERR, "syslog_test");
|
l, err := Dial("", "", LOG_ERR, "syslog_test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Dial() failed: %s", err)
|
t.Fatalf("Dial() failed: %s", err)
|
||||||
}
|
}
|
||||||
l.Close();
|
l.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUDPDial(t *testing.T) {
|
func TestUDPDial(t *testing.T) {
|
||||||
done := make(chan string);
|
done := make(chan string)
|
||||||
startServer(done);
|
startServer(done)
|
||||||
l, err := Dial("udp", serverAddr, LOG_INFO, "syslog_test");
|
l, err := Dial("udp", serverAddr, LOG_INFO, "syslog_test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("syslog.Dial() failed: %s", err)
|
t.Fatalf("syslog.Dial() failed: %s", err)
|
||||||
}
|
}
|
||||||
msg := "udp test";
|
msg := "udp test"
|
||||||
l.Info(msg);
|
l.Info(msg)
|
||||||
expected := "<6>syslog_test: udp test\n";
|
expected := "<6>syslog_test: udp test\n"
|
||||||
rcvd := <-done;
|
rcvd := <-done
|
||||||
if rcvd != expected {
|
if rcvd != expected {
|
||||||
t.Fatalf("s.Info() = '%q', but wanted '%q'", rcvd, expected)
|
t.Fatalf("s.Info() = '%q', but wanted '%q'", rcvd, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWrite(t *testing.T) {
|
func TestWrite(t *testing.T) {
|
||||||
done := make(chan string);
|
done := make(chan string)
|
||||||
startServer(done);
|
startServer(done)
|
||||||
l, err := Dial("udp", serverAddr, LOG_ERR, "syslog_test");
|
l, err := Dial("udp", serverAddr, LOG_ERR, "syslog_test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("syslog.Dial() failed: %s", err)
|
t.Fatalf("syslog.Dial() failed: %s", err)
|
||||||
}
|
}
|
||||||
msg := "write test";
|
msg := "write test"
|
||||||
_, err = io.WriteString(l, msg);
|
_, err = io.WriteString(l, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("WriteString() failed: %s", err)
|
t.Fatalf("WriteString() failed: %s", err)
|
||||||
}
|
}
|
||||||
expected := "<3>syslog_test: write test\n";
|
expected := "<3>syslog_test: write test\n"
|
||||||
rcvd := <-done;
|
rcvd := <-done
|
||||||
if rcvd != expected {
|
if rcvd != expected {
|
||||||
t.Fatalf("s.Info() = '%q', but wanted '%q'", rcvd, expected)
|
t.Fatalf("s.Info() = '%q', but wanted '%q'", rcvd, expected)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,11 @@
|
||||||
package tabwriter
|
package tabwriter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes";
|
"bytes"
|
||||||
"container/vector";
|
"container/vector"
|
||||||
"io";
|
"io"
|
||||||
"os";
|
"os"
|
||||||
"utf8";
|
"utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -28,9 +28,9 @@ import (
|
||||||
// ('\t') terminated cell.
|
// ('\t') terminated cell.
|
||||||
//
|
//
|
||||||
type cell struct {
|
type cell struct {
|
||||||
size int; // cell size in bytes
|
size int // cell size in bytes
|
||||||
width int; // cell width in runes
|
width int // cell width in runes
|
||||||
htab bool; // true if the cell is terminated by an htab ('\t')
|
htab bool // true if the cell is terminated by an htab ('\t')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -78,20 +78,20 @@ type cell struct {
|
||||||
//
|
//
|
||||||
type Writer struct {
|
type Writer struct {
|
||||||
// configuration
|
// configuration
|
||||||
output io.Writer;
|
output io.Writer
|
||||||
minwidth int;
|
minwidth int
|
||||||
tabwidth int;
|
tabwidth int
|
||||||
padding int;
|
padding int
|
||||||
padbytes [8]byte;
|
padbytes [8]byte
|
||||||
flags uint;
|
flags uint
|
||||||
|
|
||||||
// current state
|
// current state
|
||||||
buf bytes.Buffer; // collected text excluding tabs or line breaks
|
buf bytes.Buffer // collected text excluding tabs or line breaks
|
||||||
pos int; // buffer position up to which cell.width of incomplete cell has been computed
|
pos int // buffer position up to which cell.width of incomplete cell has been computed
|
||||||
cell cell; // current incomplete cell; cell.width is up to buf[pos] excluding ignored sections
|
cell cell // current incomplete cell; cell.width is up to buf[pos] excluding ignored sections
|
||||||
endChar byte; // terminating char of escaped sequence (Escape for escapes, '>', ';' for HTML tags/entities, or 0)
|
endChar byte // terminating char of escaped sequence (Escape for escapes, '>', ';' for HTML tags/entities, or 0)
|
||||||
lines vector.Vector; // list of lines; each line is a list of cells
|
lines vector.Vector // list of lines; each line is a list of cells
|
||||||
widths vector.IntVector; // list of column widths in runes - re-used during formatting
|
widths vector.IntVector // list of column widths in runes - re-used during formatting
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -103,13 +103,13 @@ func (b *Writer) line(i int) *vector.Vector { return b.lines.At(i).(*vector.Vect
|
||||||
|
|
||||||
// Reset the current state.
|
// Reset the current state.
|
||||||
func (b *Writer) reset() {
|
func (b *Writer) reset() {
|
||||||
b.buf.Reset();
|
b.buf.Reset()
|
||||||
b.pos = 0;
|
b.pos = 0
|
||||||
b.cell = cell{};
|
b.cell = cell{}
|
||||||
b.endChar = 0;
|
b.endChar = 0
|
||||||
b.lines.Resize(0, 0);
|
b.lines.Resize(0, 0)
|
||||||
b.widths.Resize(0, 0);
|
b.widths.Resize(0, 0)
|
||||||
b.addLine();
|
b.addLine()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -141,23 +141,23 @@ func (b *Writer) reset() {
|
||||||
const (
|
const (
|
||||||
// Ignore html tags and treat entities (starting with '&'
|
// Ignore html tags and treat entities (starting with '&'
|
||||||
// and ending in ';') as single characters (width = 1).
|
// and ending in ';') as single characters (width = 1).
|
||||||
FilterHTML uint = 1 << iota;
|
FilterHTML uint = 1 << iota
|
||||||
|
|
||||||
// Force right-alignment of cell content.
|
// Force right-alignment of cell content.
|
||||||
// Default is left-alignment.
|
// Default is left-alignment.
|
||||||
AlignRight;
|
AlignRight
|
||||||
|
|
||||||
// Handle empty columns as if they were not present in
|
// Handle empty columns as if they were not present in
|
||||||
// the input in the first place.
|
// the input in the first place.
|
||||||
DiscardEmptyColumns;
|
DiscardEmptyColumns
|
||||||
|
|
||||||
// Always use tabs for indentation columns (i.e., padding of
|
// Always use tabs for indentation columns (i.e., padding of
|
||||||
// leading empty cells on the left) independent of padchar.
|
// leading empty cells on the left) independent of padchar.
|
||||||
TabIndent;
|
TabIndent
|
||||||
|
|
||||||
// Print a vertical bar ('|') between columns (after formatting).
|
// Print a vertical bar ('|') between columns (after formatting).
|
||||||
// Discarded colums appear as zero-width columns ("||").
|
// Discarded colums appear as zero-width columns ("||").
|
||||||
Debug;
|
Debug
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -185,10 +185,10 @@ func (b *Writer) Init(output io.Writer, minwidth, tabwidth, padding int, padchar
|
||||||
if minwidth < 0 || tabwidth < 0 || padding < 0 {
|
if minwidth < 0 || tabwidth < 0 || padding < 0 {
|
||||||
panic("negative minwidth, tabwidth, or padding")
|
panic("negative minwidth, tabwidth, or padding")
|
||||||
}
|
}
|
||||||
b.output = output;
|
b.output = output
|
||||||
b.minwidth = minwidth;
|
b.minwidth = minwidth
|
||||||
b.tabwidth = tabwidth;
|
b.tabwidth = tabwidth
|
||||||
b.padding = padding;
|
b.padding = padding
|
||||||
for i := range b.padbytes {
|
for i := range b.padbytes {
|
||||||
b.padbytes[i] = padchar
|
b.padbytes[i] = padchar
|
||||||
}
|
}
|
||||||
|
|
@ -196,37 +196,37 @@ func (b *Writer) Init(output io.Writer, minwidth, tabwidth, padding int, padchar
|
||||||
// tab padding enforces left-alignment
|
// tab padding enforces left-alignment
|
||||||
flags &^= AlignRight
|
flags &^= AlignRight
|
||||||
}
|
}
|
||||||
b.flags = flags;
|
b.flags = flags
|
||||||
|
|
||||||
b.reset();
|
b.reset()
|
||||||
|
|
||||||
return b;
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// debugging support (keep code around)
|
// debugging support (keep code around)
|
||||||
func (b *Writer) dump() {
|
func (b *Writer) dump() {
|
||||||
pos := 0;
|
pos := 0
|
||||||
for i := 0; i < b.lines.Len(); i++ {
|
for i := 0; i < b.lines.Len(); i++ {
|
||||||
line := b.line(i);
|
line := b.line(i)
|
||||||
print("(", i, ") ");
|
print("(", i, ") ")
|
||||||
for j := 0; j < line.Len(); j++ {
|
for j := 0; j < line.Len(); j++ {
|
||||||
c := line.At(j).(cell);
|
c := line.At(j).(cell)
|
||||||
print("[", string(b.buf.Bytes()[pos:pos+c.size]), "]");
|
print("[", string(b.buf.Bytes()[pos:pos+c.size]), "]")
|
||||||
pos += c.size;
|
pos += c.size
|
||||||
}
|
}
|
||||||
print("\n");
|
print("\n")
|
||||||
}
|
}
|
||||||
print("\n");
|
print("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (b *Writer) write0(buf []byte) os.Error {
|
func (b *Writer) write0(buf []byte) os.Error {
|
||||||
n, err := b.output.Write(buf);
|
n, err := b.output.Write(buf)
|
||||||
if n != len(buf) && err == nil {
|
if n != len(buf) && err == nil {
|
||||||
err = os.EIO
|
err = os.EIO
|
||||||
}
|
}
|
||||||
return err;
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -235,15 +235,15 @@ func (b *Writer) writeN(src []byte, n int) os.Error {
|
||||||
if err := b.write0(src); err != nil {
|
if err := b.write0(src); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
n -= len(src);
|
n -= len(src)
|
||||||
}
|
}
|
||||||
return b.write0(src[0:n]);
|
return b.write0(src[0:n])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
newline = []byte{'\n'};
|
newline = []byte{'\n'}
|
||||||
tabs = []byte{'\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t'};
|
tabs = []byte{'\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t'}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -254,31 +254,31 @@ func (b *Writer) writePadding(textw, cellw int, useTabs bool) os.Error {
|
||||||
return nil // tabs have no width - can't do any padding
|
return nil // tabs have no width - can't do any padding
|
||||||
}
|
}
|
||||||
// make cellw the smallest multiple of b.tabwidth
|
// make cellw the smallest multiple of b.tabwidth
|
||||||
cellw = (cellw + b.tabwidth - 1) / b.tabwidth * b.tabwidth;
|
cellw = (cellw + b.tabwidth - 1) / b.tabwidth * b.tabwidth
|
||||||
n := cellw - textw; // amount of padding
|
n := cellw - textw // amount of padding
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
panic("internal error")
|
panic("internal error")
|
||||||
}
|
}
|
||||||
return b.writeN(tabs, (n+b.tabwidth-1)/b.tabwidth);
|
return b.writeN(tabs, (n+b.tabwidth-1)/b.tabwidth)
|
||||||
}
|
}
|
||||||
|
|
||||||
// padding is done with non-tab characters
|
// padding is done with non-tab characters
|
||||||
return b.writeN(&b.padbytes, cellw-textw);
|
return b.writeN(&b.padbytes, cellw-textw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var vbar = []byte{'|'}
|
var vbar = []byte{'|'}
|
||||||
|
|
||||||
func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int, err os.Error) {
|
func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int, err os.Error) {
|
||||||
pos = pos0;
|
pos = pos0
|
||||||
for i := line0; i < line1; i++ {
|
for i := line0; i < line1; i++ {
|
||||||
line := b.line(i);
|
line := b.line(i)
|
||||||
|
|
||||||
// if TabIndent is set, use tabs to pad leading empty cells
|
// if TabIndent is set, use tabs to pad leading empty cells
|
||||||
useTabs := b.flags&TabIndent != 0;
|
useTabs := b.flags&TabIndent != 0
|
||||||
|
|
||||||
for j := 0; j < line.Len(); j++ {
|
for j := 0; j < line.Len(); j++ {
|
||||||
c := line.At(j).(cell);
|
c := line.At(j).(cell)
|
||||||
|
|
||||||
if j > 0 && b.flags&Debug != 0 {
|
if j > 0 && b.flags&Debug != 0 {
|
||||||
if err = b.write0(vbar); err != nil {
|
if err = b.write0(vbar); err != nil {
|
||||||
|
|
@ -295,12 +295,12 @@ func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int, err os.Error)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// non-empty cell
|
// non-empty cell
|
||||||
useTabs = false;
|
useTabs = false
|
||||||
if b.flags&AlignRight == 0 { // align left
|
if b.flags&AlignRight == 0 { // align left
|
||||||
if err = b.write0(b.buf.Bytes()[pos : pos+c.size]); err != nil {
|
if err = b.write0(b.buf.Bytes()[pos : pos+c.size]); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pos += c.size;
|
pos += c.size
|
||||||
if j < b.widths.Len() {
|
if j < b.widths.Len() {
|
||||||
if err = b.writePadding(c.width, b.widths.At(j), false); err != nil {
|
if err = b.writePadding(c.width, b.widths.At(j), false); err != nil {
|
||||||
return
|
return
|
||||||
|
|
@ -315,7 +315,7 @@ func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int, err os.Error)
|
||||||
if err = b.write0(b.buf.Bytes()[pos : pos+c.size]); err != nil {
|
if err = b.write0(b.buf.Bytes()[pos : pos+c.size]); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pos += c.size;
|
pos += c.size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -326,7 +326,7 @@ func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int, err os.Error)
|
||||||
if err = b.write0(b.buf.Bytes()[pos : pos+b.cell.size]); err != nil {
|
if err = b.write0(b.buf.Bytes()[pos : pos+b.cell.size]); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pos += b.cell.size;
|
pos += b.cell.size
|
||||||
} else {
|
} else {
|
||||||
// not the last line - write newline
|
// not the last line - write newline
|
||||||
if err = b.write0(newline); err != nil {
|
if err = b.write0(newline); err != nil {
|
||||||
|
|
@ -334,7 +334,7 @@ func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int, err os.Error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -344,10 +344,10 @@ func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int, err os.Error)
|
||||||
// line1 and an error, if any.
|
// line1 and an error, if any.
|
||||||
//
|
//
|
||||||
func (b *Writer) format(pos0 int, line0, line1 int) (pos int, err os.Error) {
|
func (b *Writer) format(pos0 int, line0, line1 int) (pos int, err os.Error) {
|
||||||
pos = pos0;
|
pos = pos0
|
||||||
column := b.widths.Len();
|
column := b.widths.Len()
|
||||||
for this := line0; this < line1; this++ {
|
for this := line0; this < line1; this++ {
|
||||||
line := b.line(this);
|
line := b.line(this)
|
||||||
|
|
||||||
if column < line.Len()-1 {
|
if column < line.Len()-1 {
|
||||||
// cell exists in this column => this line
|
// cell exists in this column => this line
|
||||||
|
|
@ -361,16 +361,16 @@ func (b *Writer) format(pos0 int, line0, line1 int) (pos int, err os.Error) {
|
||||||
if pos, err = b.writeLines(pos, line0, this); err != nil {
|
if pos, err = b.writeLines(pos, line0, this); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
line0 = this;
|
line0 = this
|
||||||
|
|
||||||
// column block begin
|
// column block begin
|
||||||
width := b.minwidth; // minimal column width
|
width := b.minwidth // minimal column width
|
||||||
discardable := true; // true if all cells in this column are empty and "soft"
|
discardable := true // true if all cells in this column are empty and "soft"
|
||||||
for ; this < line1; this++ {
|
for ; this < line1; this++ {
|
||||||
line = b.line(this);
|
line = b.line(this)
|
||||||
if column < line.Len()-1 {
|
if column < line.Len()-1 {
|
||||||
// cell exists in this column
|
// cell exists in this column
|
||||||
c := line.At(column).(cell);
|
c := line.At(column).(cell)
|
||||||
// update width
|
// update width
|
||||||
if w := c.width + b.padding; w > width {
|
if w := c.width + b.padding; w > width {
|
||||||
width = w
|
width = w
|
||||||
|
|
@ -392,29 +392,29 @@ func (b *Writer) format(pos0 int, line0, line1 int) (pos int, err os.Error) {
|
||||||
|
|
||||||
// format and print all columns to the right of this column
|
// format and print all columns to the right of this column
|
||||||
// (we know the widths of this column and all columns to the left)
|
// (we know the widths of this column and all columns to the left)
|
||||||
b.widths.Push(width);
|
b.widths.Push(width)
|
||||||
pos, err = b.format(pos, line0, this);
|
pos, err = b.format(pos, line0, this)
|
||||||
b.widths.Pop();
|
b.widths.Pop()
|
||||||
line0 = this;
|
line0 = this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// print unprinted lines until end
|
// print unprinted lines until end
|
||||||
return b.writeLines(pos, line0, line1);
|
return b.writeLines(pos, line0, line1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Append text to current cell.
|
// Append text to current cell.
|
||||||
func (b *Writer) append(text []byte) {
|
func (b *Writer) append(text []byte) {
|
||||||
b.buf.Write(text);
|
b.buf.Write(text)
|
||||||
b.cell.size += len(text);
|
b.cell.size += len(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Update the cell width.
|
// Update the cell width.
|
||||||
func (b *Writer) updateWidth() {
|
func (b *Writer) updateWidth() {
|
||||||
b.cell.width += utf8.RuneCount(b.buf.Bytes()[b.pos:b.buf.Len()]);
|
b.cell.width += utf8.RuneCount(b.buf.Bytes()[b.pos:b.buf.Len()])
|
||||||
b.pos = b.buf.Len();
|
b.pos = b.buf.Len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -454,8 +454,8 @@ func (b *Writer) endEscape() {
|
||||||
case ';':
|
case ';':
|
||||||
b.cell.width++ // entity, count as one rune
|
b.cell.width++ // entity, count as one rune
|
||||||
}
|
}
|
||||||
b.pos = b.buf.Len();
|
b.pos = b.buf.Len()
|
||||||
b.endChar = 0;
|
b.endChar = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -463,11 +463,11 @@ func (b *Writer) endEscape() {
|
||||||
// current line. Returns the number of cells in that line.
|
// current line. Returns the number of cells in that line.
|
||||||
//
|
//
|
||||||
func (b *Writer) terminateCell(htab bool) int {
|
func (b *Writer) terminateCell(htab bool) int {
|
||||||
b.cell.htab = htab;
|
b.cell.htab = htab
|
||||||
line := b.line(b.lines.Len() - 1);
|
line := b.line(b.lines.Len() - 1)
|
||||||
line.Push(b.cell);
|
line.Push(b.cell)
|
||||||
b.cell = cell{};
|
b.cell = cell{}
|
||||||
return line.Len();
|
return line.Len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -483,16 +483,16 @@ func (b *Writer) Flush() os.Error {
|
||||||
// inside escape - terminate it even if incomplete
|
// inside escape - terminate it even if incomplete
|
||||||
b.endEscape()
|
b.endEscape()
|
||||||
}
|
}
|
||||||
b.terminateCell(false);
|
b.terminateCell(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// format contents of buffer
|
// format contents of buffer
|
||||||
_, err := b.format(0, 0, b.lines.Len());
|
_, err := b.format(0, 0, b.lines.Len())
|
||||||
|
|
||||||
// reset, even in the presence of errors
|
// reset, even in the presence of errors
|
||||||
b.reset();
|
b.reset()
|
||||||
|
|
||||||
return err;
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -502,20 +502,20 @@ func (b *Writer) Flush() os.Error {
|
||||||
//
|
//
|
||||||
func (b *Writer) Write(buf []byte) (n int, err os.Error) {
|
func (b *Writer) Write(buf []byte) (n int, err os.Error) {
|
||||||
// split text into cells
|
// split text into cells
|
||||||
n = 0;
|
n = 0
|
||||||
for i, ch := range buf {
|
for i, ch := range buf {
|
||||||
if b.endChar == 0 {
|
if b.endChar == 0 {
|
||||||
// outside escape
|
// outside escape
|
||||||
switch ch {
|
switch ch {
|
||||||
case '\t', '\v', '\n', '\f':
|
case '\t', '\v', '\n', '\f':
|
||||||
// end of cell
|
// end of cell
|
||||||
b.append(buf[n:i]);
|
b.append(buf[n:i])
|
||||||
b.updateWidth();
|
b.updateWidth()
|
||||||
n = i + 1; // ch consumed
|
n = i + 1 // ch consumed
|
||||||
ncells := b.terminateCell(ch == '\t');
|
ncells := b.terminateCell(ch == '\t')
|
||||||
if ch == '\n' || ch == '\f' {
|
if ch == '\n' || ch == '\f' {
|
||||||
// terminate line
|
// terminate line
|
||||||
b.addLine();
|
b.addLine()
|
||||||
if ch == '\f' || ncells == 1 {
|
if ch == '\f' || ncells == 1 {
|
||||||
// A '\f' always forces a flush. Otherwise, if the previous
|
// A '\f' always forces a flush. Otherwise, if the previous
|
||||||
// line has only one cell which does not have an impact on
|
// line has only one cell which does not have an impact on
|
||||||
|
|
@ -530,19 +530,19 @@ func (b *Writer) Write(buf []byte) (n int, err os.Error) {
|
||||||
|
|
||||||
case Escape:
|
case Escape:
|
||||||
// start of escaped sequence
|
// start of escaped sequence
|
||||||
b.append(buf[n:i]);
|
b.append(buf[n:i])
|
||||||
b.updateWidth();
|
b.updateWidth()
|
||||||
n = i + 1; // exclude Escape
|
n = i + 1 // exclude Escape
|
||||||
b.startEscape(Escape);
|
b.startEscape(Escape)
|
||||||
|
|
||||||
case '<', '&':
|
case '<', '&':
|
||||||
// possibly an html tag/entity
|
// possibly an html tag/entity
|
||||||
if b.flags&FilterHTML != 0 {
|
if b.flags&FilterHTML != 0 {
|
||||||
// begin of tag/entity
|
// begin of tag/entity
|
||||||
b.append(buf[n:i]);
|
b.append(buf[n:i])
|
||||||
b.updateWidth();
|
b.updateWidth()
|
||||||
n = i;
|
n = i
|
||||||
b.startEscape(ch);
|
b.startEscape(ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -550,21 +550,21 @@ func (b *Writer) Write(buf []byte) (n int, err os.Error) {
|
||||||
// inside escape
|
// inside escape
|
||||||
if ch == b.endChar {
|
if ch == b.endChar {
|
||||||
// end of tag/entity
|
// end of tag/entity
|
||||||
j := i + 1;
|
j := i + 1
|
||||||
if ch == Escape {
|
if ch == Escape {
|
||||||
j = i // exclude Escape
|
j = i // exclude Escape
|
||||||
}
|
}
|
||||||
b.append(buf[n:j]);
|
b.append(buf[n:j])
|
||||||
n = i + 1; // ch consumed
|
n = i + 1 // ch consumed
|
||||||
b.endEscape();
|
b.endEscape()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// append leftover text
|
// append leftover text
|
||||||
b.append(buf[n:]);
|
b.append(buf[n:])
|
||||||
n = len(buf);
|
n = len(buf)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,14 @@
|
||||||
package tabwriter
|
package tabwriter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io";
|
"io"
|
||||||
"os";
|
"os"
|
||||||
"testing";
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
type buffer struct {
|
type buffer struct {
|
||||||
a []byte;
|
a []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -23,17 +23,17 @@ func (b *buffer) clear() { b.a = b.a[0:0] }
|
||||||
|
|
||||||
|
|
||||||
func (b *buffer) Write(buf []byte) (written int, err os.Error) {
|
func (b *buffer) Write(buf []byte) (written int, err os.Error) {
|
||||||
n := len(b.a);
|
n := len(b.a)
|
||||||
m := len(buf);
|
m := len(buf)
|
||||||
if n+m <= cap(b.a) {
|
if n+m <= cap(b.a) {
|
||||||
b.a = b.a[0 : n+m];
|
b.a = b.a[0 : n+m]
|
||||||
for i := 0; i < m; i++ {
|
for i := 0; i < m; i++ {
|
||||||
b.a[n+i] = buf[i]
|
b.a[n+i] = buf[i]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panicln("buffer.Write: buffer too small", n, m, cap(b.a))
|
panicln("buffer.Write: buffer too small", n, m, cap(b.a))
|
||||||
}
|
}
|
||||||
return len(buf), nil;
|
return len(buf), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ func (b *buffer) String() string { return string(b.a) }
|
||||||
|
|
||||||
|
|
||||||
func write(t *testing.T, testname string, w *Writer, src string) {
|
func write(t *testing.T, testname string, w *Writer, src string) {
|
||||||
written, err := io.WriteString(w, src);
|
written, err := io.WriteString(w, src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("--- test: %s\n--- src:\n%s\n--- write error: %v\n", testname, src, err)
|
t.Errorf("--- test: %s\n--- src:\n%s\n--- write error: %v\n", testname, src, err)
|
||||||
}
|
}
|
||||||
|
|
@ -52,12 +52,12 @@ func write(t *testing.T, testname string, w *Writer, src string) {
|
||||||
|
|
||||||
|
|
||||||
func verify(t *testing.T, testname string, w *Writer, b *buffer, src, expected string) {
|
func verify(t *testing.T, testname string, w *Writer, b *buffer, src, expected string) {
|
||||||
err := w.Flush();
|
err := w.Flush()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("--- test: %s\n--- src:\n%s\n--- flush error: %v\n", testname, src, err)
|
t.Errorf("--- test: %s\n--- src:\n%s\n--- flush error: %v\n", testname, src, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
res := b.String();
|
res := b.String()
|
||||||
if res != expected {
|
if res != expected {
|
||||||
t.Errorf("--- test: %s\n--- src:\n%s\n--- found:\n%s\n--- expected:\n%s\n", testname, src, res, expected)
|
t.Errorf("--- test: %s\n--- src:\n%s\n--- found:\n%s\n--- expected:\n%s\n", testname, src, res, expected)
|
||||||
}
|
}
|
||||||
|
|
@ -65,43 +65,43 @@ func verify(t *testing.T, testname string, w *Writer, b *buffer, src, expected s
|
||||||
|
|
||||||
|
|
||||||
func check(t *testing.T, testname string, minwidth, tabwidth, padding int, padchar byte, flags uint, src, expected string) {
|
func check(t *testing.T, testname string, minwidth, tabwidth, padding int, padchar byte, flags uint, src, expected string) {
|
||||||
var b buffer;
|
var b buffer
|
||||||
b.init(1000);
|
b.init(1000)
|
||||||
|
|
||||||
var w Writer;
|
var w Writer
|
||||||
w.Init(&b, minwidth, tabwidth, padding, padchar, flags);
|
w.Init(&b, minwidth, tabwidth, padding, padchar, flags)
|
||||||
|
|
||||||
// write all at once
|
// write all at once
|
||||||
b.clear();
|
b.clear()
|
||||||
write(t, testname, &w, src);
|
write(t, testname, &w, src)
|
||||||
verify(t, testname, &w, &b, src, expected);
|
verify(t, testname, &w, &b, src, expected)
|
||||||
|
|
||||||
// write byte-by-byte
|
// write byte-by-byte
|
||||||
b.clear();
|
b.clear()
|
||||||
for i := 0; i < len(src); i++ {
|
for i := 0; i < len(src); i++ {
|
||||||
write(t, testname, &w, src[i:i+1])
|
write(t, testname, &w, src[i:i+1])
|
||||||
}
|
}
|
||||||
verify(t, testname, &w, &b, src, expected);
|
verify(t, testname, &w, &b, src, expected)
|
||||||
|
|
||||||
// write using Fibonacci slice sizes
|
// write using Fibonacci slice sizes
|
||||||
b.clear();
|
b.clear()
|
||||||
for i, d := 0, 0; i < len(src); {
|
for i, d := 0, 0; i < len(src); {
|
||||||
write(t, testname, &w, src[i:i+d]);
|
write(t, testname, &w, src[i:i+d])
|
||||||
i, d = i+d, d+1;
|
i, d = i+d, d+1
|
||||||
if i+d > len(src) {
|
if i+d > len(src) {
|
||||||
d = len(src) - i
|
d = len(src) - i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
verify(t, testname, &w, &b, src, expected);
|
verify(t, testname, &w, &b, src, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type entry struct {
|
type entry struct {
|
||||||
testname string;
|
testname string
|
||||||
minwidth, tabwidth, padding int;
|
minwidth, tabwidth, padding int
|
||||||
padchar byte;
|
padchar byte
|
||||||
flags uint;
|
flags uint
|
||||||
src, expected string;
|
src, expected string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@
|
||||||
package template
|
package template
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes";
|
"bytes"
|
||||||
"fmt";
|
"fmt"
|
||||||
"io";
|
"io"
|
||||||
"strings";
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StringFormatter formats into the default string representation.
|
// StringFormatter formats into the default string representation.
|
||||||
|
|
@ -19,25 +19,25 @@ import (
|
||||||
// under the name "" in your custom formatter map.
|
// under the name "" in your custom formatter map.
|
||||||
func StringFormatter(w io.Writer, value interface{}, format string) {
|
func StringFormatter(w io.Writer, value interface{}, format string) {
|
||||||
if b, ok := value.([]byte); ok {
|
if b, ok := value.([]byte); ok {
|
||||||
w.Write(b);
|
w.Write(b)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprint(w, value);
|
fmt.Fprint(w, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
esc_quot = strings.Bytes("""); // shorter than """
|
esc_quot = strings.Bytes(""") // shorter than """
|
||||||
esc_apos = strings.Bytes("'"); // shorter than "'"
|
esc_apos = strings.Bytes("'") // shorter than "'"
|
||||||
esc_amp = strings.Bytes("&");
|
esc_amp = strings.Bytes("&")
|
||||||
esc_lt = strings.Bytes("<");
|
esc_lt = strings.Bytes("<")
|
||||||
esc_gt = strings.Bytes(">");
|
esc_gt = strings.Bytes(">")
|
||||||
)
|
)
|
||||||
|
|
||||||
// HTMLEscape writes to w the properly escaped HTML equivalent
|
// HTMLEscape writes to w the properly escaped HTML equivalent
|
||||||
// of the plain text data s.
|
// of the plain text data s.
|
||||||
func HTMLEscape(w io.Writer, s []byte) {
|
func HTMLEscape(w io.Writer, s []byte) {
|
||||||
var esc []byte;
|
var esc []byte
|
||||||
last := 0;
|
last := 0
|
||||||
for i, c := range s {
|
for i, c := range s {
|
||||||
switch c {
|
switch c {
|
||||||
case '"':
|
case '"':
|
||||||
|
|
@ -53,16 +53,16 @@ func HTMLEscape(w io.Writer, s []byte) {
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
w.Write(s[last:i]);
|
w.Write(s[last:i])
|
||||||
w.Write(esc);
|
w.Write(esc)
|
||||||
last = i + 1;
|
last = i + 1
|
||||||
}
|
}
|
||||||
w.Write(s[last:]);
|
w.Write(s[last:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTMLFormatter formats arbitrary values for HTML
|
// HTMLFormatter formats arbitrary values for HTML
|
||||||
func HTMLFormatter(w io.Writer, value interface{}, format string) {
|
func HTMLFormatter(w io.Writer, value interface{}, format string) {
|
||||||
var b bytes.Buffer;
|
var b bytes.Buffer
|
||||||
fmt.Fprint(&b, value);
|
fmt.Fprint(&b, value)
|
||||||
HTMLEscape(w, b.Bytes());
|
HTMLEscape(w, b.Bytes())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,20 +57,20 @@
|
||||||
package template
|
package template
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"container/vector";
|
"container/vector"
|
||||||
"fmt";
|
"fmt"
|
||||||
"io";
|
"io"
|
||||||
"os";
|
"os"
|
||||||
"reflect";
|
"reflect"
|
||||||
"runtime";
|
"runtime"
|
||||||
"strings";
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Errors returned during parsing and execution. Users may extract the information and reformat
|
// Errors returned during parsing and execution. Users may extract the information and reformat
|
||||||
// if they desire.
|
// if they desire.
|
||||||
type Error struct {
|
type Error struct {
|
||||||
Line int;
|
Line int
|
||||||
Msg string;
|
Msg string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Error) String() string { return fmt.Sprintf("line %d: %s", e.Line, e.Msg) }
|
func (e *Error) String() string { return fmt.Sprintf("line %d: %s", e.Line, e.Msg) }
|
||||||
|
|
@ -83,15 +83,15 @@ var tab = []byte{'\t'}
|
||||||
|
|
||||||
// The various types of "tokens", which are plain text or (usually) brace-delimited descriptors
|
// The various types of "tokens", which are plain text or (usually) brace-delimited descriptors
|
||||||
const (
|
const (
|
||||||
tokAlternates = iota;
|
tokAlternates = iota
|
||||||
tokComment;
|
tokComment
|
||||||
tokEnd;
|
tokEnd
|
||||||
tokLiteral;
|
tokLiteral
|
||||||
tokOr;
|
tokOr
|
||||||
tokRepeated;
|
tokRepeated
|
||||||
tokSection;
|
tokSection
|
||||||
tokText;
|
tokText
|
||||||
tokVariable;
|
tokVariable
|
||||||
)
|
)
|
||||||
|
|
||||||
// FormatterMap is the type describing the mapping from formatter
|
// FormatterMap is the type describing the mapping from formatter
|
||||||
|
|
@ -110,59 +110,59 @@ var builtins = FormatterMap{
|
||||||
|
|
||||||
// Plain text.
|
// Plain text.
|
||||||
type textElement struct {
|
type textElement struct {
|
||||||
text []byte;
|
text []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// A literal such as .meta-left or .meta-right
|
// A literal such as .meta-left or .meta-right
|
||||||
type literalElement struct {
|
type literalElement struct {
|
||||||
text []byte;
|
text []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// A variable to be evaluated
|
// A variable to be evaluated
|
||||||
type variableElement struct {
|
type variableElement struct {
|
||||||
linenum int;
|
linenum int
|
||||||
name string;
|
name string
|
||||||
formatter string; // TODO(r): implement pipelines
|
formatter string // TODO(r): implement pipelines
|
||||||
}
|
}
|
||||||
|
|
||||||
// A .section block, possibly with a .or
|
// A .section block, possibly with a .or
|
||||||
type sectionElement struct {
|
type sectionElement struct {
|
||||||
linenum int; // of .section itself
|
linenum int // of .section itself
|
||||||
field string; // cursor field for this block
|
field string // cursor field for this block
|
||||||
start int; // first element
|
start int // first element
|
||||||
or int; // first element of .or block
|
or int // first element of .or block
|
||||||
end int; // one beyond last element
|
end int // one beyond last element
|
||||||
}
|
}
|
||||||
|
|
||||||
// A .repeated block, possibly with a .or and a .alternates
|
// A .repeated block, possibly with a .or and a .alternates
|
||||||
type repeatedElement struct {
|
type repeatedElement struct {
|
||||||
sectionElement; // It has the same structure...
|
sectionElement // It has the same structure...
|
||||||
altstart int; // ... except for alternates
|
altstart int // ... except for alternates
|
||||||
altend int;
|
altend int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Template is the type that represents a template definition.
|
// Template is the type that represents a template definition.
|
||||||
// It is unchanged after parsing.
|
// It is unchanged after parsing.
|
||||||
type Template struct {
|
type Template struct {
|
||||||
fmap FormatterMap; // formatters for variables
|
fmap FormatterMap // formatters for variables
|
||||||
// Used during parsing:
|
// Used during parsing:
|
||||||
ldelim, rdelim []byte; // delimiters; default {}
|
ldelim, rdelim []byte // delimiters; default {}
|
||||||
buf []byte; // input text to process
|
buf []byte // input text to process
|
||||||
p int; // position in buf
|
p int // position in buf
|
||||||
linenum int; // position in input
|
linenum int // position in input
|
||||||
error os.Error; // error during parsing (only)
|
error os.Error // error during parsing (only)
|
||||||
// Parsed results:
|
// Parsed results:
|
||||||
elems *vector.Vector;
|
elems *vector.Vector
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal state for executing a Template. As we evaluate the struct,
|
// Internal state for executing a Template. As we evaluate the struct,
|
||||||
// the data item descends into the fields associated with sections, etc.
|
// the data item descends into the fields associated with sections, etc.
|
||||||
// Parent is used to walk upwards to find variables higher in the tree.
|
// Parent is used to walk upwards to find variables higher in the tree.
|
||||||
type state struct {
|
type state struct {
|
||||||
parent *state; // parent in hierarchy
|
parent *state // parent in hierarchy
|
||||||
data reflect.Value; // the driver data for this section etc.
|
data reflect.Value // the driver data for this section etc.
|
||||||
wr io.Writer; // where to send output
|
wr io.Writer // where to send output
|
||||||
errors chan os.Error; // for reporting errors during execute
|
errors chan os.Error // for reporting errors during execute
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parent *state) clone(data reflect.Value) *state {
|
func (parent *state) clone(data reflect.Value) *state {
|
||||||
|
|
@ -172,18 +172,18 @@ func (parent *state) clone(data reflect.Value) *state {
|
||||||
// New creates a new template with the specified formatter map (which
|
// New creates a new template with the specified formatter map (which
|
||||||
// may be nil) to define auxiliary functions for formatting variables.
|
// may be nil) to define auxiliary functions for formatting variables.
|
||||||
func New(fmap FormatterMap) *Template {
|
func New(fmap FormatterMap) *Template {
|
||||||
t := new(Template);
|
t := new(Template)
|
||||||
t.fmap = fmap;
|
t.fmap = fmap
|
||||||
t.ldelim = lbrace;
|
t.ldelim = lbrace
|
||||||
t.rdelim = rbrace;
|
t.rdelim = rbrace
|
||||||
t.elems = new(vector.Vector);
|
t.elems = new(vector.Vector)
|
||||||
return t;
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report error and stop executing. The line number must be provided explicitly.
|
// Report error and stop executing. The line number must be provided explicitly.
|
||||||
func (t *Template) execError(st *state, line int, err string, args ...) {
|
func (t *Template) execError(st *state, line int, err string, args ...) {
|
||||||
st.errors <- &Error{line, fmt.Sprintf(err, args)};
|
st.errors <- &Error{line, fmt.Sprintf(err, args)}
|
||||||
runtime.Goexit();
|
runtime.Goexit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report error, save in Template to terminate parsing.
|
// Report error, save in Template to terminate parsing.
|
||||||
|
|
@ -199,7 +199,7 @@ func white(c uint8) bool { return c == ' ' || c == '\t' || c == '\r' || c == '\n
|
||||||
|
|
||||||
// Safely, does s[n:n+len(t)] == t?
|
// Safely, does s[n:n+len(t)] == t?
|
||||||
func equal(s []byte, n int, t []byte) bool {
|
func equal(s []byte, n int, t []byte) bool {
|
||||||
b := s[n:];
|
b := s[n:]
|
||||||
if len(t) > len(b) { // not enough space left for a match.
|
if len(t) > len(b) { // not enough space left for a match.
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -208,7 +208,7 @@ func equal(s []byte, n int, t []byte) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// nextItem returns the next item from the input buffer. If the returned
|
// nextItem returns the next item from the input buffer. If the returned
|
||||||
|
|
@ -218,20 +218,20 @@ func equal(s []byte, n int, t []byte) bool {
|
||||||
// Action tokens on a line by themselves drop the white space on
|
// Action tokens on a line by themselves drop the white space on
|
||||||
// either side, up to and including the newline.
|
// either side, up to and including the newline.
|
||||||
func (t *Template) nextItem() []byte {
|
func (t *Template) nextItem() []byte {
|
||||||
sawLeft := false; // are we waiting for an opening delimiter?
|
sawLeft := false // are we waiting for an opening delimiter?
|
||||||
special := false; // is this a {.foo} directive, which means trim white space?
|
special := false // is this a {.foo} directive, which means trim white space?
|
||||||
// Delete surrounding white space if this {.foo} is the only thing on the line.
|
// Delete surrounding white space if this {.foo} is the only thing on the line.
|
||||||
trim_white := t.p == 0 || t.buf[t.p-1] == '\n';
|
trim_white := t.p == 0 || t.buf[t.p-1] == '\n'
|
||||||
only_white := true; // we have seen only white space so far
|
only_white := true // we have seen only white space so far
|
||||||
var i int;
|
var i int
|
||||||
start := t.p;
|
start := t.p
|
||||||
Loop:
|
Loop:
|
||||||
for i = t.p; i < len(t.buf); i++ {
|
for i = t.p; i < len(t.buf); i++ {
|
||||||
switch {
|
switch {
|
||||||
case t.buf[i] == '\n':
|
case t.buf[i] == '\n':
|
||||||
t.linenum++;
|
t.linenum++
|
||||||
i++;
|
i++
|
||||||
break Loop;
|
break Loop
|
||||||
case white(t.buf[i]):
|
case white(t.buf[i]):
|
||||||
// white space, do nothing
|
// white space, do nothing
|
||||||
case !sawLeft && equal(t.buf, i, t.ldelim): // sawLeft checked because delims may be equal
|
case !sawLeft && equal(t.buf, i, t.ldelim): // sawLeft checked because delims may be equal
|
||||||
|
|
@ -240,75 +240,75 @@ Loop:
|
||||||
break Loop
|
break Loop
|
||||||
}
|
}
|
||||||
// is it a directive or comment?
|
// is it a directive or comment?
|
||||||
j := i + len(t.ldelim); // position after delimiter
|
j := i + len(t.ldelim) // position after delimiter
|
||||||
if j+1 < len(t.buf) && (t.buf[j] == '.' || t.buf[j] == '#') {
|
if j+1 < len(t.buf) && (t.buf[j] == '.' || t.buf[j] == '#') {
|
||||||
special = true;
|
special = true
|
||||||
if trim_white && only_white {
|
if trim_white && only_white {
|
||||||
start = i
|
start = i
|
||||||
}
|
}
|
||||||
} else if i > t.p { // have some text accumulated so stop before delimiter
|
} else if i > t.p { // have some text accumulated so stop before delimiter
|
||||||
break Loop
|
break Loop
|
||||||
}
|
}
|
||||||
sawLeft = true;
|
sawLeft = true
|
||||||
i = j - 1;
|
i = j - 1
|
||||||
case equal(t.buf, i, t.rdelim):
|
case equal(t.buf, i, t.rdelim):
|
||||||
if !sawLeft {
|
if !sawLeft {
|
||||||
t.parseError("unmatched closing delimiter");
|
t.parseError("unmatched closing delimiter")
|
||||||
return nil;
|
return nil
|
||||||
}
|
}
|
||||||
sawLeft = false;
|
sawLeft = false
|
||||||
i += len(t.rdelim);
|
i += len(t.rdelim)
|
||||||
break Loop;
|
break Loop
|
||||||
default:
|
default:
|
||||||
only_white = false
|
only_white = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if sawLeft {
|
if sawLeft {
|
||||||
t.parseError("unmatched opening delimiter");
|
t.parseError("unmatched opening delimiter")
|
||||||
return nil;
|
return nil
|
||||||
}
|
}
|
||||||
item := t.buf[start:i];
|
item := t.buf[start:i]
|
||||||
if special && trim_white {
|
if special && trim_white {
|
||||||
// consume trailing white space
|
// consume trailing white space
|
||||||
for ; i < len(t.buf) && white(t.buf[i]); i++ {
|
for ; i < len(t.buf) && white(t.buf[i]); i++ {
|
||||||
if t.buf[i] == '\n' {
|
if t.buf[i] == '\n' {
|
||||||
t.linenum++;
|
t.linenum++
|
||||||
i++;
|
i++
|
||||||
break; // stop after newline
|
break // stop after newline
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.p = i;
|
t.p = i
|
||||||
return item;
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn a byte array into a white-space-split array of strings.
|
// Turn a byte array into a white-space-split array of strings.
|
||||||
func words(buf []byte) []string {
|
func words(buf []byte) []string {
|
||||||
s := make([]string, 0, 5);
|
s := make([]string, 0, 5)
|
||||||
p := 0; // position in buf
|
p := 0 // position in buf
|
||||||
// one word per loop
|
// one word per loop
|
||||||
for i := 0; ; i++ {
|
for i := 0; ; i++ {
|
||||||
// skip white space
|
// skip white space
|
||||||
for ; p < len(buf) && white(buf[p]); p++ {
|
for ; p < len(buf) && white(buf[p]); p++ {
|
||||||
}
|
}
|
||||||
// grab word
|
// grab word
|
||||||
start := p;
|
start := p
|
||||||
for ; p < len(buf) && !white(buf[p]); p++ {
|
for ; p < len(buf) && !white(buf[p]); p++ {
|
||||||
}
|
}
|
||||||
if start == p { // no text left
|
if start == p { // no text left
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if i == cap(s) {
|
if i == cap(s) {
|
||||||
ns := make([]string, 2*cap(s));
|
ns := make([]string, 2*cap(s))
|
||||||
for j := range s {
|
for j := range s {
|
||||||
ns[j] = s[j]
|
ns[j] = s[j]
|
||||||
}
|
}
|
||||||
s = ns;
|
s = ns
|
||||||
}
|
}
|
||||||
s = s[0 : i+1];
|
s = s[0 : i+1]
|
||||||
s[i] = string(buf[start:p]);
|
s[i] = string(buf[start:p])
|
||||||
}
|
}
|
||||||
return s;
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Analyze an item and return its token type and, if it's an action item, an array of
|
// Analyze an item and return its token type and, if it's an action item, an array of
|
||||||
|
|
@ -316,81 +316,81 @@ func words(buf []byte) []string {
|
||||||
func (t *Template) analyze(item []byte) (tok int, w []string) {
|
func (t *Template) analyze(item []byte) (tok int, w []string) {
|
||||||
// item is known to be non-empty
|
// item is known to be non-empty
|
||||||
if !equal(item, 0, t.ldelim) { // doesn't start with left delimiter
|
if !equal(item, 0, t.ldelim) { // doesn't start with left delimiter
|
||||||
tok = tokText;
|
tok = tokText
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
if !equal(item, len(item)-len(t.rdelim), t.rdelim) { // doesn't end with right delimiter
|
if !equal(item, len(item)-len(t.rdelim), t.rdelim) { // doesn't end with right delimiter
|
||||||
t.parseError("internal error: unmatched opening delimiter"); // lexing should prevent this
|
t.parseError("internal error: unmatched opening delimiter") // lexing should prevent this
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
if len(item) <= len(t.ldelim)+len(t.rdelim) { // no contents
|
if len(item) <= len(t.ldelim)+len(t.rdelim) { // no contents
|
||||||
t.parseError("empty directive");
|
t.parseError("empty directive")
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
// Comment
|
// Comment
|
||||||
if item[len(t.ldelim)] == '#' {
|
if item[len(t.ldelim)] == '#' {
|
||||||
tok = tokComment;
|
tok = tokComment
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
// Split into words
|
// Split into words
|
||||||
w = words(item[len(t.ldelim) : len(item)-len(t.rdelim)]); // drop final delimiter
|
w = words(item[len(t.ldelim) : len(item)-len(t.rdelim)]) // drop final delimiter
|
||||||
if len(w) == 0 {
|
if len(w) == 0 {
|
||||||
t.parseError("empty directive");
|
t.parseError("empty directive")
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
if len(w) == 1 && w[0][0] != '.' {
|
if len(w) == 1 && w[0][0] != '.' {
|
||||||
tok = tokVariable;
|
tok = tokVariable
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
switch w[0] {
|
switch w[0] {
|
||||||
case ".meta-left", ".meta-right", ".space", ".tab":
|
case ".meta-left", ".meta-right", ".space", ".tab":
|
||||||
tok = tokLiteral;
|
tok = tokLiteral
|
||||||
return;
|
return
|
||||||
case ".or":
|
case ".or":
|
||||||
tok = tokOr;
|
tok = tokOr
|
||||||
return;
|
return
|
||||||
case ".end":
|
case ".end":
|
||||||
tok = tokEnd;
|
tok = tokEnd
|
||||||
return;
|
return
|
||||||
case ".section":
|
case ".section":
|
||||||
if len(w) != 2 {
|
if len(w) != 2 {
|
||||||
t.parseError("incorrect fields for .section: %s", item);
|
t.parseError("incorrect fields for .section: %s", item)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
tok = tokSection;
|
tok = tokSection
|
||||||
return;
|
return
|
||||||
case ".repeated":
|
case ".repeated":
|
||||||
if len(w) != 3 || w[1] != "section" {
|
if len(w) != 3 || w[1] != "section" {
|
||||||
t.parseError("incorrect fields for .repeated: %s", item);
|
t.parseError("incorrect fields for .repeated: %s", item)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
tok = tokRepeated;
|
tok = tokRepeated
|
||||||
return;
|
return
|
||||||
case ".alternates":
|
case ".alternates":
|
||||||
if len(w) != 2 || w[1] != "with" {
|
if len(w) != 2 || w[1] != "with" {
|
||||||
t.parseError("incorrect fields for .alternates: %s", item);
|
t.parseError("incorrect fields for .alternates: %s", item)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
tok = tokAlternates;
|
tok = tokAlternates
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
t.parseError("bad directive: %s", item);
|
t.parseError("bad directive: %s", item)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Parsing
|
// -- Parsing
|
||||||
|
|
||||||
// Allocate a new variable-evaluation element.
|
// Allocate a new variable-evaluation element.
|
||||||
func (t *Template) newVariable(name_formatter string) (v *variableElement) {
|
func (t *Template) newVariable(name_formatter string) (v *variableElement) {
|
||||||
name := name_formatter;
|
name := name_formatter
|
||||||
formatter := "";
|
formatter := ""
|
||||||
bar := strings.Index(name_formatter, "|");
|
bar := strings.Index(name_formatter, "|")
|
||||||
if bar >= 0 {
|
if bar >= 0 {
|
||||||
name = name_formatter[0:bar];
|
name = name_formatter[0:bar]
|
||||||
formatter = name_formatter[bar+1:];
|
formatter = name_formatter[bar+1:]
|
||||||
}
|
}
|
||||||
// Probably ok, so let's build it.
|
// Probably ok, so let's build it.
|
||||||
v = &variableElement{t.linenum, name, formatter};
|
v = &variableElement{t.linenum, name, formatter}
|
||||||
|
|
||||||
// We could remember the function address here and avoid the lookup later,
|
// We could remember the function address here and avoid the lookup later,
|
||||||
// but it's more dynamic to let the user change the map contents underfoot.
|
// but it's more dynamic to let the user change the map contents underfoot.
|
||||||
|
|
@ -406,24 +406,24 @@ func (t *Template) newVariable(name_formatter string) (v *variableElement) {
|
||||||
if _, ok := builtins[formatter]; ok {
|
if _, ok := builtins[formatter]; ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t.parseError("unknown formatter: %s", formatter);
|
t.parseError("unknown formatter: %s", formatter)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab the next item. If it's simple, just append it to the template.
|
// Grab the next item. If it's simple, just append it to the template.
|
||||||
// Otherwise return its details.
|
// Otherwise return its details.
|
||||||
func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
|
func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
|
||||||
tok, w = t.analyze(item);
|
tok, w = t.analyze(item)
|
||||||
if t.error != nil {
|
if t.error != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
done = true; // assume for simplicity
|
done = true // assume for simplicity
|
||||||
switch tok {
|
switch tok {
|
||||||
case tokComment:
|
case tokComment:
|
||||||
return
|
return
|
||||||
case tokText:
|
case tokText:
|
||||||
t.elems.Push(&textElement{item});
|
t.elems.Push(&textElement{item})
|
||||||
return;
|
return
|
||||||
case tokLiteral:
|
case tokLiteral:
|
||||||
switch w[0] {
|
switch w[0] {
|
||||||
case ".meta-left":
|
case ".meta-left":
|
||||||
|
|
@ -435,40 +435,40 @@ func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
|
||||||
case ".tab":
|
case ".tab":
|
||||||
t.elems.Push(&literalElement{tab})
|
t.elems.Push(&literalElement{tab})
|
||||||
default:
|
default:
|
||||||
t.parseError("internal error: unknown literal: %s", w[0]);
|
t.parseError("internal error: unknown literal: %s", w[0])
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
case tokVariable:
|
case tokVariable:
|
||||||
t.elems.Push(t.newVariable(w[0]));
|
t.elems.Push(t.newVariable(w[0]))
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
return false, tok, w;
|
return false, tok, w
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseRepeated and parseSection are mutually recursive
|
// parseRepeated and parseSection are mutually recursive
|
||||||
|
|
||||||
func (t *Template) parseRepeated(words []string) *repeatedElement {
|
func (t *Template) parseRepeated(words []string) *repeatedElement {
|
||||||
r := new(repeatedElement);
|
r := new(repeatedElement)
|
||||||
t.elems.Push(r);
|
t.elems.Push(r)
|
||||||
r.linenum = t.linenum;
|
r.linenum = t.linenum
|
||||||
r.field = words[2];
|
r.field = words[2]
|
||||||
// Scan section, collecting true and false (.or) blocks.
|
// Scan section, collecting true and false (.or) blocks.
|
||||||
r.start = t.elems.Len();
|
r.start = t.elems.Len()
|
||||||
r.or = -1;
|
r.or = -1
|
||||||
r.altstart = -1;
|
r.altstart = -1
|
||||||
r.altend = -1;
|
r.altend = -1
|
||||||
Loop:
|
Loop:
|
||||||
for t.error == nil {
|
for t.error == nil {
|
||||||
item := t.nextItem();
|
item := t.nextItem()
|
||||||
if t.error != nil {
|
if t.error != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if len(item) == 0 {
|
if len(item) == 0 {
|
||||||
t.parseError("missing .end for .repeated section");
|
t.parseError("missing .end for .repeated section")
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
done, tok, w := t.parseSimple(item);
|
done, tok, w := t.parseSimple(item)
|
||||||
if t.error != nil {
|
if t.error != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -480,28 +480,28 @@ Loop:
|
||||||
break Loop
|
break Loop
|
||||||
case tokOr:
|
case tokOr:
|
||||||
if r.or >= 0 {
|
if r.or >= 0 {
|
||||||
t.parseError("extra .or in .repeated section");
|
t.parseError("extra .or in .repeated section")
|
||||||
break Loop;
|
break Loop
|
||||||
}
|
}
|
||||||
r.altend = t.elems.Len();
|
r.altend = t.elems.Len()
|
||||||
r.or = t.elems.Len();
|
r.or = t.elems.Len()
|
||||||
case tokSection:
|
case tokSection:
|
||||||
t.parseSection(w)
|
t.parseSection(w)
|
||||||
case tokRepeated:
|
case tokRepeated:
|
||||||
t.parseRepeated(w)
|
t.parseRepeated(w)
|
||||||
case tokAlternates:
|
case tokAlternates:
|
||||||
if r.altstart >= 0 {
|
if r.altstart >= 0 {
|
||||||
t.parseError("extra .alternates in .repeated section");
|
t.parseError("extra .alternates in .repeated section")
|
||||||
break Loop;
|
break Loop
|
||||||
}
|
}
|
||||||
if r.or >= 0 {
|
if r.or >= 0 {
|
||||||
t.parseError(".alternates inside .or block in .repeated section");
|
t.parseError(".alternates inside .or block in .repeated section")
|
||||||
break Loop;
|
break Loop
|
||||||
}
|
}
|
||||||
r.altstart = t.elems.Len();
|
r.altstart = t.elems.Len()
|
||||||
default:
|
default:
|
||||||
t.parseError("internal error: unknown repeated section item: %s", item);
|
t.parseError("internal error: unknown repeated section item: %s", item)
|
||||||
break Loop;
|
break Loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if t.error != nil {
|
if t.error != nil {
|
||||||
|
|
@ -510,29 +510,29 @@ Loop:
|
||||||
if r.altend < 0 {
|
if r.altend < 0 {
|
||||||
r.altend = t.elems.Len()
|
r.altend = t.elems.Len()
|
||||||
}
|
}
|
||||||
r.end = t.elems.Len();
|
r.end = t.elems.Len()
|
||||||
return r;
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Template) parseSection(words []string) *sectionElement {
|
func (t *Template) parseSection(words []string) *sectionElement {
|
||||||
s := new(sectionElement);
|
s := new(sectionElement)
|
||||||
t.elems.Push(s);
|
t.elems.Push(s)
|
||||||
s.linenum = t.linenum;
|
s.linenum = t.linenum
|
||||||
s.field = words[1];
|
s.field = words[1]
|
||||||
// Scan section, collecting true and false (.or) blocks.
|
// Scan section, collecting true and false (.or) blocks.
|
||||||
s.start = t.elems.Len();
|
s.start = t.elems.Len()
|
||||||
s.or = -1;
|
s.or = -1
|
||||||
Loop:
|
Loop:
|
||||||
for t.error == nil {
|
for t.error == nil {
|
||||||
item := t.nextItem();
|
item := t.nextItem()
|
||||||
if t.error != nil {
|
if t.error != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if len(item) == 0 {
|
if len(item) == 0 {
|
||||||
t.parseError("missing .end for .section");
|
t.parseError("missing .end for .section")
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
done, tok, w := t.parseSimple(item);
|
done, tok, w := t.parseSimple(item)
|
||||||
if t.error != nil {
|
if t.error != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -544,10 +544,10 @@ Loop:
|
||||||
break Loop
|
break Loop
|
||||||
case tokOr:
|
case tokOr:
|
||||||
if s.or >= 0 {
|
if s.or >= 0 {
|
||||||
t.parseError("extra .or in .section");
|
t.parseError("extra .or in .section")
|
||||||
break Loop;
|
break Loop
|
||||||
}
|
}
|
||||||
s.or = t.elems.Len();
|
s.or = t.elems.Len()
|
||||||
case tokSection:
|
case tokSection:
|
||||||
t.parseSection(w)
|
t.parseSection(w)
|
||||||
case tokRepeated:
|
case tokRepeated:
|
||||||
|
|
@ -561,20 +561,20 @@ Loop:
|
||||||
if t.error != nil {
|
if t.error != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
s.end = t.elems.Len();
|
s.end = t.elems.Len()
|
||||||
return s;
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Template) parse() {
|
func (t *Template) parse() {
|
||||||
for t.error == nil {
|
for t.error == nil {
|
||||||
item := t.nextItem();
|
item := t.nextItem()
|
||||||
if t.error != nil {
|
if t.error != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if len(item) == 0 {
|
if len(item) == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
done, tok, w := t.parseSimple(item);
|
done, tok, w := t.parseSimple(item)
|
||||||
if done {
|
if done {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -603,34 +603,34 @@ func (st *state) findVar(s string) reflect.Value {
|
||||||
if s == "@" {
|
if s == "@" {
|
||||||
return st.data
|
return st.data
|
||||||
}
|
}
|
||||||
data := st.data;
|
data := st.data
|
||||||
elems := strings.Split(s, ".", 0);
|
elems := strings.Split(s, ".", 0)
|
||||||
for i := 0; i < len(elems); i++ {
|
for i := 0; i < len(elems); i++ {
|
||||||
// Look up field; data must be a struct or map.
|
// Look up field; data must be a struct or map.
|
||||||
data = reflect.Indirect(data);
|
data = reflect.Indirect(data)
|
||||||
if data == nil {
|
if data == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch typ := data.Type().(type) {
|
switch typ := data.Type().(type) {
|
||||||
case *reflect.StructType:
|
case *reflect.StructType:
|
||||||
field, ok := typ.FieldByName(elems[i]);
|
field, ok := typ.FieldByName(elems[i])
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
data = data.(*reflect.StructValue).FieldByIndex(field.Index);
|
data = data.(*reflect.StructValue).FieldByIndex(field.Index)
|
||||||
case *reflect.MapType:
|
case *reflect.MapType:
|
||||||
data = data.(*reflect.MapValue).Elem(reflect.NewValue(elems[i]))
|
data = data.(*reflect.MapValue).Elem(reflect.NewValue(elems[i]))
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return data;
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is there no data to look at?
|
// Is there no data to look at?
|
||||||
func empty(v reflect.Value) bool {
|
func empty(v reflect.Value) bool {
|
||||||
v = reflect.Indirect(v);
|
v = reflect.Indirect(v)
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -646,63 +646,63 @@ func empty(v reflect.Value) bool {
|
||||||
case *reflect.SliceValue:
|
case *reflect.SliceValue:
|
||||||
return v.Len() == 0
|
return v.Len() == 0
|
||||||
}
|
}
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look up a variable, up through the parent if necessary.
|
// Look up a variable, up through the parent if necessary.
|
||||||
func (t *Template) varValue(name string, st *state) reflect.Value {
|
func (t *Template) varValue(name string, st *state) reflect.Value {
|
||||||
field := st.findVar(name);
|
field := st.findVar(name)
|
||||||
if field == nil {
|
if field == nil {
|
||||||
if st.parent == nil {
|
if st.parent == nil {
|
||||||
t.execError(st, t.linenum, "name not found: %s", name)
|
t.execError(st, t.linenum, "name not found: %s", name)
|
||||||
}
|
}
|
||||||
return t.varValue(name, st.parent);
|
return t.varValue(name, st.parent)
|
||||||
}
|
}
|
||||||
return field;
|
return field
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate a variable, looking up through the parent if necessary.
|
// Evaluate a variable, looking up through the parent if necessary.
|
||||||
// If it has a formatter attached ({var|formatter}) run that too.
|
// If it has a formatter attached ({var|formatter}) run that too.
|
||||||
func (t *Template) writeVariable(v *variableElement, st *state) {
|
func (t *Template) writeVariable(v *variableElement, st *state) {
|
||||||
formatter := v.formatter;
|
formatter := v.formatter
|
||||||
val := t.varValue(v.name, st).Interface();
|
val := t.varValue(v.name, st).Interface()
|
||||||
// is it in user-supplied map?
|
// is it in user-supplied map?
|
||||||
if t.fmap != nil {
|
if t.fmap != nil {
|
||||||
if fn, ok := t.fmap[formatter]; ok {
|
if fn, ok := t.fmap[formatter]; ok {
|
||||||
fn(st.wr, val, formatter);
|
fn(st.wr, val, formatter)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// is it in builtin map?
|
// is it in builtin map?
|
||||||
if fn, ok := builtins[formatter]; ok {
|
if fn, ok := builtins[formatter]; ok {
|
||||||
fn(st.wr, val, formatter);
|
fn(st.wr, val, formatter)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
t.execError(st, v.linenum, "missing formatter %s for variable %s", formatter, v.name);
|
t.execError(st, v.linenum, "missing formatter %s for variable %s", formatter, v.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute element i. Return next index to execute.
|
// Execute element i. Return next index to execute.
|
||||||
func (t *Template) executeElement(i int, st *state) int {
|
func (t *Template) executeElement(i int, st *state) int {
|
||||||
switch elem := t.elems.At(i).(type) {
|
switch elem := t.elems.At(i).(type) {
|
||||||
case *textElement:
|
case *textElement:
|
||||||
st.wr.Write(elem.text);
|
st.wr.Write(elem.text)
|
||||||
return i + 1;
|
return i + 1
|
||||||
case *literalElement:
|
case *literalElement:
|
||||||
st.wr.Write(elem.text);
|
st.wr.Write(elem.text)
|
||||||
return i + 1;
|
return i + 1
|
||||||
case *variableElement:
|
case *variableElement:
|
||||||
t.writeVariable(elem, st);
|
t.writeVariable(elem, st)
|
||||||
return i + 1;
|
return i + 1
|
||||||
case *sectionElement:
|
case *sectionElement:
|
||||||
t.executeSection(elem, st);
|
t.executeSection(elem, st)
|
||||||
return elem.end;
|
return elem.end
|
||||||
case *repeatedElement:
|
case *repeatedElement:
|
||||||
t.executeRepeated(elem, st);
|
t.executeRepeated(elem, st)
|
||||||
return elem.end;
|
return elem.end
|
||||||
}
|
}
|
||||||
e := t.elems.At(i);
|
e := t.elems.At(i)
|
||||||
t.execError(st, 0, "internal error: bad directive in execute: %v %T\n", reflect.NewValue(e).Interface(), e);
|
t.execError(st, 0, "internal error: bad directive in execute: %v %T\n", reflect.NewValue(e).Interface(), e)
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the template.
|
// Execute the template.
|
||||||
|
|
@ -715,12 +715,12 @@ func (t *Template) execute(start, end int, st *state) {
|
||||||
// Execute a .section
|
// Execute a .section
|
||||||
func (t *Template) executeSection(s *sectionElement, st *state) {
|
func (t *Template) executeSection(s *sectionElement, st *state) {
|
||||||
// Find driver data for this section. It must be in the current struct.
|
// Find driver data for this section. It must be in the current struct.
|
||||||
field := t.varValue(s.field, st);
|
field := t.varValue(s.field, st)
|
||||||
if field == nil {
|
if field == nil {
|
||||||
t.execError(st, s.linenum, ".section: cannot find field %s in %s", s.field, reflect.Indirect(st.data).Type())
|
t.execError(st, s.linenum, ".section: cannot find field %s in %s", s.field, reflect.Indirect(st.data).Type())
|
||||||
}
|
}
|
||||||
st = st.clone(field);
|
st = st.clone(field)
|
||||||
start, end := s.start, s.or;
|
start, end := s.start, s.or
|
||||||
if !empty(field) {
|
if !empty(field) {
|
||||||
// Execute the normal block.
|
// Execute the normal block.
|
||||||
if end < 0 {
|
if end < 0 {
|
||||||
|
|
@ -728,7 +728,7 @@ func (t *Template) executeSection(s *sectionElement, st *state) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Execute the .or block. If it's missing, do nothing.
|
// Execute the .or block. If it's missing, do nothing.
|
||||||
start, end = s.or, s.end;
|
start, end = s.or, s.end
|
||||||
if start < 0 {
|
if start < 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -741,42 +741,42 @@ func (t *Template) executeSection(s *sectionElement, st *state) {
|
||||||
// Return the result of calling the Iter method on v, or nil.
|
// Return the result of calling the Iter method on v, or nil.
|
||||||
func iter(v reflect.Value) *reflect.ChanValue {
|
func iter(v reflect.Value) *reflect.ChanValue {
|
||||||
for j := 0; j < v.Type().NumMethod(); j++ {
|
for j := 0; j < v.Type().NumMethod(); j++ {
|
||||||
mth := v.Type().Method(j);
|
mth := v.Type().Method(j)
|
||||||
fv := v.Method(j);
|
fv := v.Method(j)
|
||||||
ft := fv.Type().(*reflect.FuncType);
|
ft := fv.Type().(*reflect.FuncType)
|
||||||
// TODO(rsc): NumIn() should return 0 here, because ft is from a curried FuncValue.
|
// TODO(rsc): NumIn() should return 0 here, because ft is from a curried FuncValue.
|
||||||
if mth.Name != "Iter" || ft.NumIn() != 1 || ft.NumOut() != 1 {
|
if mth.Name != "Iter" || ft.NumIn() != 1 || ft.NumOut() != 1 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ct, ok := ft.Out(0).(*reflect.ChanType);
|
ct, ok := ft.Out(0).(*reflect.ChanType)
|
||||||
if !ok || ct.Dir()&reflect.RecvDir == 0 {
|
if !ok || ct.Dir()&reflect.RecvDir == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return fv.Call(nil)[0].(*reflect.ChanValue);
|
return fv.Call(nil)[0].(*reflect.ChanValue)
|
||||||
}
|
}
|
||||||
return nil;
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute a .repeated section
|
// Execute a .repeated section
|
||||||
func (t *Template) executeRepeated(r *repeatedElement, st *state) {
|
func (t *Template) executeRepeated(r *repeatedElement, st *state) {
|
||||||
// Find driver data for this section. It must be in the current struct.
|
// Find driver data for this section. It must be in the current struct.
|
||||||
field := t.varValue(r.field, st);
|
field := t.varValue(r.field, st)
|
||||||
if field == nil {
|
if field == nil {
|
||||||
t.execError(st, r.linenum, ".repeated: cannot find field %s in %s", r.field, reflect.Indirect(st.data).Type())
|
t.execError(st, r.linenum, ".repeated: cannot find field %s in %s", r.field, reflect.Indirect(st.data).Type())
|
||||||
}
|
}
|
||||||
|
|
||||||
start, end := r.start, r.or;
|
start, end := r.start, r.or
|
||||||
if end < 0 {
|
if end < 0 {
|
||||||
end = r.end
|
end = r.end
|
||||||
}
|
}
|
||||||
if r.altstart >= 0 {
|
if r.altstart >= 0 {
|
||||||
end = r.altstart
|
end = r.altstart
|
||||||
}
|
}
|
||||||
first := true;
|
first := true
|
||||||
|
|
||||||
if array, ok := field.(reflect.ArrayOrSliceValue); ok {
|
if array, ok := field.(reflect.ArrayOrSliceValue); ok {
|
||||||
for j := 0; j < array.Len(); j++ {
|
for j := 0; j < array.Len(); j++ {
|
||||||
newst := st.clone(array.Elem(j));
|
newst := st.clone(array.Elem(j))
|
||||||
|
|
||||||
// .alternates between elements
|
// .alternates between elements
|
||||||
if !first && r.altstart >= 0 {
|
if !first && r.altstart >= 0 {
|
||||||
|
|
@ -784,7 +784,7 @@ func (t *Template) executeRepeated(r *repeatedElement, st *state) {
|
||||||
i = t.executeElement(i, newst)
|
i = t.executeElement(i, newst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
first = false;
|
first = false
|
||||||
|
|
||||||
for i := start; i < end; {
|
for i := start; i < end; {
|
||||||
i = t.executeElement(i, newst)
|
i = t.executeElement(i, newst)
|
||||||
|
|
@ -792,11 +792,11 @@ func (t *Template) executeRepeated(r *repeatedElement, st *state) {
|
||||||
}
|
}
|
||||||
} else if ch := iter(field); ch != nil {
|
} else if ch := iter(field); ch != nil {
|
||||||
for {
|
for {
|
||||||
e := ch.Recv();
|
e := ch.Recv()
|
||||||
if ch.Closed() {
|
if ch.Closed() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
newst := st.clone(e);
|
newst := st.clone(e)
|
||||||
|
|
||||||
// .alternates between elements
|
// .alternates between elements
|
||||||
if !first && r.altstart >= 0 {
|
if !first && r.altstart >= 0 {
|
||||||
|
|
@ -804,7 +804,7 @@ func (t *Template) executeRepeated(r *repeatedElement, st *state) {
|
||||||
i = t.executeElement(i, newst)
|
i = t.executeElement(i, newst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
first = false;
|
first = false
|
||||||
|
|
||||||
for i := start; i < end; {
|
for i := start; i < end; {
|
||||||
i = t.executeElement(i, newst)
|
i = t.executeElement(i, newst)
|
||||||
|
|
@ -817,14 +817,14 @@ func (t *Template) executeRepeated(r *repeatedElement, st *state) {
|
||||||
|
|
||||||
if first {
|
if first {
|
||||||
// Empty. Execute the .or block, once. If it's missing, do nothing.
|
// Empty. Execute the .or block, once. If it's missing, do nothing.
|
||||||
start, end := r.or, r.end;
|
start, end := r.or, r.end
|
||||||
if start >= 0 {
|
if start >= 0 {
|
||||||
newst := st.clone(field);
|
newst := st.clone(field)
|
||||||
for i := start; i < end; {
|
for i := start; i < end; {
|
||||||
i = t.executeElement(i, newst)
|
i = t.executeElement(i, newst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -838,7 +838,7 @@ func validDelim(d []byte) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Public interface
|
// -- Public interface
|
||||||
|
|
@ -853,25 +853,25 @@ func (t *Template) Parse(s string) os.Error {
|
||||||
if !validDelim(t.ldelim) || !validDelim(t.rdelim) {
|
if !validDelim(t.ldelim) || !validDelim(t.rdelim) {
|
||||||
return &Error{1, fmt.Sprintf("bad delimiter strings %q %q", t.ldelim, t.rdelim)}
|
return &Error{1, fmt.Sprintf("bad delimiter strings %q %q", t.ldelim, t.rdelim)}
|
||||||
}
|
}
|
||||||
t.buf = strings.Bytes(s);
|
t.buf = strings.Bytes(s)
|
||||||
t.p = 0;
|
t.p = 0
|
||||||
t.linenum = 1;
|
t.linenum = 1
|
||||||
t.parse();
|
t.parse()
|
||||||
return t.error;
|
return t.error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute applies a parsed template to the specified data object,
|
// Execute applies a parsed template to the specified data object,
|
||||||
// generating output to wr.
|
// generating output to wr.
|
||||||
func (t *Template) Execute(data interface{}, wr io.Writer) os.Error {
|
func (t *Template) Execute(data interface{}, wr io.Writer) os.Error {
|
||||||
// Extract the driver data.
|
// Extract the driver data.
|
||||||
val := reflect.NewValue(data);
|
val := reflect.NewValue(data)
|
||||||
errors := make(chan os.Error);
|
errors := make(chan os.Error)
|
||||||
go func() {
|
go func() {
|
||||||
t.p = 0;
|
t.p = 0
|
||||||
t.execute(0, t.elems.Len(), &state{nil, val, wr, errors});
|
t.execute(0, t.elems.Len(), &state{nil, val, wr, errors})
|
||||||
errors <- nil; // clean return;
|
errors <- nil // clean return;
|
||||||
}();
|
}()
|
||||||
return <-errors;
|
return <-errors
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDelims sets the left and right delimiters for operations in the
|
// SetDelims sets the left and right delimiters for operations in the
|
||||||
|
|
@ -880,8 +880,8 @@ func (t *Template) Execute(data interface{}, wr io.Writer) os.Error {
|
||||||
// delimiters are very rarely invalid and Parse has the necessary
|
// delimiters are very rarely invalid and Parse has the necessary
|
||||||
// error-handling interface already.
|
// error-handling interface already.
|
||||||
func (t *Template) SetDelims(left, right string) {
|
func (t *Template) SetDelims(left, right string) {
|
||||||
t.ldelim = strings.Bytes(left);
|
t.ldelim = strings.Bytes(left)
|
||||||
t.rdelim = strings.Bytes(right);
|
t.rdelim = strings.Bytes(right)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse creates a Template with default parameters (such as {} for
|
// Parse creates a Template with default parameters (such as {} for
|
||||||
|
|
@ -890,19 +890,19 @@ func (t *Template) SetDelims(left, right string) {
|
||||||
// for formatting variables. The template is returned. If any errors
|
// for formatting variables. The template is returned. If any errors
|
||||||
// occur, err will be non-nil.
|
// occur, err will be non-nil.
|
||||||
func Parse(s string, fmap FormatterMap) (t *Template, err os.Error) {
|
func Parse(s string, fmap FormatterMap) (t *Template, err os.Error) {
|
||||||
t = New(fmap);
|
t = New(fmap)
|
||||||
err = t.Parse(s);
|
err = t.Parse(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t = nil
|
t = nil
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// MustParse is like Parse but panics if the template cannot be parsed.
|
// MustParse is like Parse but panics if the template cannot be parsed.
|
||||||
func MustParse(s string, fmap FormatterMap) *Template {
|
func MustParse(s string, fmap FormatterMap) *Template {
|
||||||
t, err := Parse(s, fmap);
|
t, err := Parse(s, fmap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("template parse error: ", err.String())
|
panic("template parse error: ", err.String())
|
||||||
}
|
}
|
||||||
return t;
|
return t
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,65 +5,65 @@
|
||||||
package template
|
package template
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes";
|
"bytes"
|
||||||
"container/vector";
|
"container/vector"
|
||||||
"fmt";
|
"fmt"
|
||||||
"io";
|
"io"
|
||||||
"strings";
|
"strings"
|
||||||
"testing";
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Test struct {
|
type Test struct {
|
||||||
in, out, err string;
|
in, out, err string
|
||||||
}
|
}
|
||||||
|
|
||||||
type T struct {
|
type T struct {
|
||||||
item string;
|
item string
|
||||||
value string;
|
value string
|
||||||
}
|
}
|
||||||
|
|
||||||
type U struct {
|
type U struct {
|
||||||
mp map[string]int;
|
mp map[string]int
|
||||||
}
|
}
|
||||||
|
|
||||||
type S struct {
|
type S struct {
|
||||||
header string;
|
header string
|
||||||
integer int;
|
integer int
|
||||||
raw string;
|
raw string
|
||||||
innerT T;
|
innerT T
|
||||||
innerPointerT *T;
|
innerPointerT *T
|
||||||
data []T;
|
data []T
|
||||||
pdata []*T;
|
pdata []*T
|
||||||
empty []*T;
|
empty []*T
|
||||||
emptystring string;
|
emptystring string
|
||||||
null []*T;
|
null []*T
|
||||||
vec *vector.Vector;
|
vec *vector.Vector
|
||||||
true bool;
|
true bool
|
||||||
false bool;
|
false bool
|
||||||
mp map[string]string;
|
mp map[string]string
|
||||||
innermap U;
|
innermap U
|
||||||
bytes []byte;
|
bytes []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
var t1 = T{"ItemNumber1", "ValueNumber1"}
|
var t1 = T{"ItemNumber1", "ValueNumber1"}
|
||||||
var t2 = T{"ItemNumber2", "ValueNumber2"}
|
var t2 = T{"ItemNumber2", "ValueNumber2"}
|
||||||
|
|
||||||
func uppercase(v interface{}) string {
|
func uppercase(v interface{}) string {
|
||||||
s := v.(string);
|
s := v.(string)
|
||||||
t := "";
|
t := ""
|
||||||
for i := 0; i < len(s); i++ {
|
for i := 0; i < len(s); i++ {
|
||||||
c := s[i];
|
c := s[i]
|
||||||
if 'a' <= c && c <= 'z' {
|
if 'a' <= c && c <= 'z' {
|
||||||
c = c + 'A' - 'a'
|
c = c + 'A' - 'a'
|
||||||
}
|
}
|
||||||
t += string(c);
|
t += string(c)
|
||||||
}
|
}
|
||||||
return t;
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func plus1(v interface{}) string {
|
func plus1(v interface{}) string {
|
||||||
i := v.(int);
|
i := v.(int)
|
||||||
return fmt.Sprint(i + 1);
|
return fmt.Sprint(i + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func writer(f func(interface{}) string) (func(io.Writer, interface{}, string)) {
|
func writer(f func(interface{}) string) (func(io.Writer, interface{}, string)) {
|
||||||
|
|
@ -306,36 +306,36 @@ var tests = []*Test{
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAll(t *testing.T) {
|
func TestAll(t *testing.T) {
|
||||||
s := new(S);
|
s := new(S)
|
||||||
// initialized by hand for clarity.
|
// initialized by hand for clarity.
|
||||||
s.header = "Header";
|
s.header = "Header"
|
||||||
s.integer = 77;
|
s.integer = 77
|
||||||
s.raw = "&<>!@ #$%^";
|
s.raw = "&<>!@ #$%^"
|
||||||
s.innerT = t1;
|
s.innerT = t1
|
||||||
s.data = []T{t1, t2};
|
s.data = []T{t1, t2}
|
||||||
s.pdata = []*T{&t1, &t2};
|
s.pdata = []*T{&t1, &t2}
|
||||||
s.empty = []*T{};
|
s.empty = []*T{}
|
||||||
s.null = nil;
|
s.null = nil
|
||||||
s.vec = new(vector.Vector);
|
s.vec = new(vector.Vector)
|
||||||
s.vec.Push("elt1");
|
s.vec.Push("elt1")
|
||||||
s.vec.Push("elt2");
|
s.vec.Push("elt2")
|
||||||
s.true = true;
|
s.true = true
|
||||||
s.false = false;
|
s.false = false
|
||||||
s.mp = make(map[string]string);
|
s.mp = make(map[string]string)
|
||||||
s.mp["mapkey"] = "Ahoy!";
|
s.mp["mapkey"] = "Ahoy!"
|
||||||
s.innermap.mp = make(map[string]int);
|
s.innermap.mp = make(map[string]int)
|
||||||
s.innermap.mp["innerkey"] = 55;
|
s.innermap.mp["innerkey"] = 55
|
||||||
s.bytes = strings.Bytes("hello");
|
s.bytes = strings.Bytes("hello")
|
||||||
|
|
||||||
var buf bytes.Buffer;
|
var buf bytes.Buffer
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
buf.Reset();
|
buf.Reset()
|
||||||
tmpl, err := Parse(test.in, formatters);
|
tmpl, err := Parse(test.in, formatters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("unexpected parse error:", err);
|
t.Error("unexpected parse error:", err)
|
||||||
continue;
|
continue
|
||||||
}
|
}
|
||||||
err = tmpl.Execute(s, &buf);
|
err = tmpl.Execute(s, &buf)
|
||||||
if test.err == "" {
|
if test.err == "" {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("unexpected execute error:", err)
|
t.Error("unexpected execute error:", err)
|
||||||
|
|
@ -352,60 +352,60 @@ func TestAll(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMapDriverType(t *testing.T) {
|
func TestMapDriverType(t *testing.T) {
|
||||||
mp := map[string]string{"footer": "Ahoy!"};
|
mp := map[string]string{"footer": "Ahoy!"}
|
||||||
tmpl, err := Parse("template: {footer}", nil);
|
tmpl, err := Parse("template: {footer}", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("unexpected parse error:", err)
|
t.Error("unexpected parse error:", err)
|
||||||
}
|
}
|
||||||
var b bytes.Buffer;
|
var b bytes.Buffer
|
||||||
err = tmpl.Execute(mp, &b);
|
err = tmpl.Execute(mp, &b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("unexpected execute error:", err)
|
t.Error("unexpected execute error:", err)
|
||||||
}
|
}
|
||||||
s := b.String();
|
s := b.String()
|
||||||
expected := "template: Ahoy!";
|
expected := "template: Ahoy!"
|
||||||
if s != expected {
|
if s != expected {
|
||||||
t.Errorf("failed passing string as data: expected %q got %q", "template: Ahoy!", s)
|
t.Errorf("failed passing string as data: expected %q got %q", "template: Ahoy!", s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStringDriverType(t *testing.T) {
|
func TestStringDriverType(t *testing.T) {
|
||||||
tmpl, err := Parse("template: {@}", nil);
|
tmpl, err := Parse("template: {@}", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("unexpected parse error:", err)
|
t.Error("unexpected parse error:", err)
|
||||||
}
|
}
|
||||||
var b bytes.Buffer;
|
var b bytes.Buffer
|
||||||
err = tmpl.Execute("hello", &b);
|
err = tmpl.Execute("hello", &b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("unexpected execute error:", err)
|
t.Error("unexpected execute error:", err)
|
||||||
}
|
}
|
||||||
s := b.String();
|
s := b.String()
|
||||||
if s != "template: hello" {
|
if s != "template: hello" {
|
||||||
t.Errorf("failed passing string as data: expected %q got %q", "template: hello", s)
|
t.Errorf("failed passing string as data: expected %q got %q", "template: hello", s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTwice(t *testing.T) {
|
func TestTwice(t *testing.T) {
|
||||||
tmpl, err := Parse("template: {@}", nil);
|
tmpl, err := Parse("template: {@}", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("unexpected parse error:", err)
|
t.Error("unexpected parse error:", err)
|
||||||
}
|
}
|
||||||
var b bytes.Buffer;
|
var b bytes.Buffer
|
||||||
err = tmpl.Execute("hello", &b);
|
err = tmpl.Execute("hello", &b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("unexpected parse error:", err)
|
t.Error("unexpected parse error:", err)
|
||||||
}
|
}
|
||||||
s := b.String();
|
s := b.String()
|
||||||
text := "template: hello";
|
text := "template: hello"
|
||||||
if s != text {
|
if s != text {
|
||||||
t.Errorf("failed passing string as data: expected %q got %q", text, s)
|
t.Errorf("failed passing string as data: expected %q got %q", text, s)
|
||||||
}
|
}
|
||||||
err = tmpl.Execute("hello", &b);
|
err = tmpl.Execute("hello", &b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("unexpected parse error:", err)
|
t.Error("unexpected parse error:", err)
|
||||||
}
|
}
|
||||||
s = b.String();
|
s = b.String()
|
||||||
text += text;
|
text += text
|
||||||
if s != text {
|
if s != text {
|
||||||
t.Errorf("failed passing string as data: expected %q got %q", text, s)
|
t.Errorf("failed passing string as data: expected %q got %q", text, s)
|
||||||
}
|
}
|
||||||
|
|
@ -415,29 +415,29 @@ func TestCustomDelims(t *testing.T) {
|
||||||
// try various lengths. zero should catch error.
|
// try various lengths. zero should catch error.
|
||||||
for i := 0; i < 7; i++ {
|
for i := 0; i < 7; i++ {
|
||||||
for j := 0; j < 7; j++ {
|
for j := 0; j < 7; j++ {
|
||||||
tmpl := New(nil);
|
tmpl := New(nil)
|
||||||
// first two chars deliberately the same to test equal left and right delims
|
// first two chars deliberately the same to test equal left and right delims
|
||||||
ldelim := "$!#$%^&"[0:i];
|
ldelim := "$!#$%^&"[0:i]
|
||||||
rdelim := "$*&^%$!"[0:j];
|
rdelim := "$*&^%$!"[0:j]
|
||||||
tmpl.SetDelims(ldelim, rdelim);
|
tmpl.SetDelims(ldelim, rdelim)
|
||||||
// if braces, this would be template: {@}{.meta-left}{.meta-right}
|
// if braces, this would be template: {@}{.meta-left}{.meta-right}
|
||||||
text := "template: " +
|
text := "template: " +
|
||||||
ldelim + "@" + rdelim +
|
ldelim + "@" + rdelim +
|
||||||
ldelim + ".meta-left" + rdelim +
|
ldelim + ".meta-left" + rdelim +
|
||||||
ldelim + ".meta-right" + rdelim;
|
ldelim + ".meta-right" + rdelim
|
||||||
err := tmpl.Parse(text);
|
err := tmpl.Parse(text)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if i == 0 || j == 0 { // expected
|
if i == 0 || j == 0 { // expected
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
t.Error("unexpected parse error:", err);
|
t.Error("unexpected parse error:", err)
|
||||||
} else if i == 0 || j == 0 {
|
} else if i == 0 || j == 0 {
|
||||||
t.Errorf("expected parse error for empty delimiter: %d %d %q %q", i, j, ldelim, rdelim);
|
t.Errorf("expected parse error for empty delimiter: %d %d %q %q", i, j, ldelim, rdelim)
|
||||||
continue;
|
continue
|
||||||
}
|
}
|
||||||
var b bytes.Buffer;
|
var b bytes.Buffer
|
||||||
err = tmpl.Execute("hello", &b);
|
err = tmpl.Execute("hello", &b)
|
||||||
s := b.String();
|
s := b.String()
|
||||||
if s != "template: hello"+ldelim+rdelim {
|
if s != "template: hello"+ldelim+rdelim {
|
||||||
t.Errorf("failed delim check(%q %q) %q got %q", ldelim, rdelim, text, s)
|
t.Errorf("failed delim check(%q %q) %q got %q", ldelim, rdelim, text, s)
|
||||||
}
|
}
|
||||||
|
|
@ -447,21 +447,21 @@ func TestCustomDelims(t *testing.T) {
|
||||||
|
|
||||||
// Test that a variable evaluates to the field itself and does not further indirection
|
// Test that a variable evaluates to the field itself and does not further indirection
|
||||||
func TestVarIndirection(t *testing.T) {
|
func TestVarIndirection(t *testing.T) {
|
||||||
s := new(S);
|
s := new(S)
|
||||||
// initialized by hand for clarity.
|
// initialized by hand for clarity.
|
||||||
s.innerPointerT = &t1;
|
s.innerPointerT = &t1
|
||||||
|
|
||||||
var buf bytes.Buffer;
|
var buf bytes.Buffer
|
||||||
input := "{.section @}{innerPointerT}{.end}";
|
input := "{.section @}{innerPointerT}{.end}"
|
||||||
tmpl, err := Parse(input, nil);
|
tmpl, err := Parse(input, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unexpected parse error:", err)
|
t.Fatal("unexpected parse error:", err)
|
||||||
}
|
}
|
||||||
err = tmpl.Execute(s, &buf);
|
err = tmpl.Execute(s, &buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("unexpected execute error:", err)
|
t.Fatal("unexpected execute error:", err)
|
||||||
}
|
}
|
||||||
expect := fmt.Sprintf("%v", &t1); // output should be hex address of t1
|
expect := fmt.Sprintf("%v", &t1) // output should be hex address of t1
|
||||||
if buf.String() != expect {
|
if buf.String() != expect {
|
||||||
t.Errorf("for %q: expected %q got %q", input, expect, buf.String())
|
t.Errorf("for %q: expected %q got %q", input, expect, buf.String())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@
|
||||||
package testing
|
package testing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag";
|
"flag"
|
||||||
"fmt";
|
"fmt"
|
||||||
"os";
|
"os"
|
||||||
"time";
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var matchBenchmarks = flag.String("benchmarks", "", "regular expression to select benchmarks to run")
|
var matchBenchmarks = flag.String("benchmarks", "", "regular expression to select benchmarks to run")
|
||||||
|
|
@ -16,18 +16,18 @@ var matchBenchmarks = flag.String("benchmarks", "", "regular expression to selec
|
||||||
// An internal type but exported because it is cross-package; part of the implementation
|
// An internal type but exported because it is cross-package; part of the implementation
|
||||||
// of gotest.
|
// of gotest.
|
||||||
type Benchmark struct {
|
type Benchmark struct {
|
||||||
Name string;
|
Name string
|
||||||
F func(b *B);
|
F func(b *B)
|
||||||
}
|
}
|
||||||
|
|
||||||
// B is a type passed to Benchmark functions to manage benchmark
|
// B is a type passed to Benchmark functions to manage benchmark
|
||||||
// timing and to specify the number of iterations to run.
|
// timing and to specify the number of iterations to run.
|
||||||
type B struct {
|
type B struct {
|
||||||
N int;
|
N int
|
||||||
benchmark Benchmark;
|
benchmark Benchmark
|
||||||
ns int64;
|
ns int64
|
||||||
bytes int64;
|
bytes int64
|
||||||
start int64;
|
start int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartTimer starts timing a test. This function is called automatically
|
// StartTimer starts timing a test. This function is called automatically
|
||||||
|
|
@ -42,13 +42,13 @@ func (b *B) StopTimer() {
|
||||||
if b.start > 0 {
|
if b.start > 0 {
|
||||||
b.ns += time.Nanoseconds() - b.start
|
b.ns += time.Nanoseconds() - b.start
|
||||||
}
|
}
|
||||||
b.start = 0;
|
b.start = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetTimer stops the timer and sets the elapsed benchmark time to zero.
|
// ResetTimer stops the timer and sets the elapsed benchmark time to zero.
|
||||||
func (b *B) ResetTimer() {
|
func (b *B) ResetTimer() {
|
||||||
b.start = 0;
|
b.start = 0
|
||||||
b.ns = 0;
|
b.ns = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetBytes records the number of bytes processed in a single operation.
|
// SetBytes records the number of bytes processed in a single operation.
|
||||||
|
|
@ -59,51 +59,51 @@ func (b *B) nsPerOp() int64 {
|
||||||
if b.N <= 0 {
|
if b.N <= 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return b.ns / int64(b.N);
|
return b.ns / int64(b.N)
|
||||||
}
|
}
|
||||||
|
|
||||||
// runN runs a single benchmark for the specified number of iterations.
|
// runN runs a single benchmark for the specified number of iterations.
|
||||||
func (b *B) runN(n int) {
|
func (b *B) runN(n int) {
|
||||||
b.N = n;
|
b.N = n
|
||||||
b.ResetTimer();
|
b.ResetTimer()
|
||||||
b.StartTimer();
|
b.StartTimer()
|
||||||
b.benchmark.F(b);
|
b.benchmark.F(b)
|
||||||
b.StopTimer();
|
b.StopTimer()
|
||||||
}
|
}
|
||||||
|
|
||||||
func min(x, y int) int {
|
func min(x, y int) int {
|
||||||
if x > y {
|
if x > y {
|
||||||
return y
|
return y
|
||||||
}
|
}
|
||||||
return x;
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
// roundDown10 rounds a number down to the nearest power of 10.
|
// roundDown10 rounds a number down to the nearest power of 10.
|
||||||
func roundDown10(n int) int {
|
func roundDown10(n int) int {
|
||||||
var tens = 0;
|
var tens = 0
|
||||||
// tens = floor(log_10(n))
|
// tens = floor(log_10(n))
|
||||||
for n > 10 {
|
for n > 10 {
|
||||||
n = n / 10;
|
n = n / 10
|
||||||
tens++;
|
tens++
|
||||||
}
|
}
|
||||||
// result = 10^tens
|
// result = 10^tens
|
||||||
result := 1;
|
result := 1
|
||||||
for i := 0; i < tens; i++ {
|
for i := 0; i < tens; i++ {
|
||||||
result *= 10
|
result *= 10
|
||||||
}
|
}
|
||||||
return result;
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// roundUp rounds x up to a number of the form [1eX, 2eX, 5eX].
|
// roundUp rounds x up to a number of the form [1eX, 2eX, 5eX].
|
||||||
func roundUp(n int) int {
|
func roundUp(n int) int {
|
||||||
base := roundDown10(n);
|
base := roundDown10(n)
|
||||||
if n < (2 * base) {
|
if n < (2 * base) {
|
||||||
return 2 * base
|
return 2 * base
|
||||||
}
|
}
|
||||||
if n < (5 * base) {
|
if n < (5 * base) {
|
||||||
return 5 * base
|
return 5 * base
|
||||||
}
|
}
|
||||||
return 10 * base;
|
return 10 * base
|
||||||
}
|
}
|
||||||
|
|
||||||
// run times the benchmark function. It gradually increases the number
|
// run times the benchmark function. It gradually increases the number
|
||||||
|
|
@ -112,11 +112,11 @@ func roundUp(n int) int {
|
||||||
// testing.BenchmarkHello 100000 19 ns/op
|
// testing.BenchmarkHello 100000 19 ns/op
|
||||||
func (b *B) run() {
|
func (b *B) run() {
|
||||||
// Run the benchmark for a single iteration in case it's expensive.
|
// Run the benchmark for a single iteration in case it's expensive.
|
||||||
n := 1;
|
n := 1
|
||||||
b.runN(n);
|
b.runN(n)
|
||||||
// Run the benchmark for at least a second.
|
// Run the benchmark for at least a second.
|
||||||
for b.ns < 1e9 && n < 1e9 {
|
for b.ns < 1e9 && n < 1e9 {
|
||||||
last := n;
|
last := n
|
||||||
// Predict iterations/sec.
|
// Predict iterations/sec.
|
||||||
if b.nsPerOp() == 0 {
|
if b.nsPerOp() == 0 {
|
||||||
n = 1e9
|
n = 1e9
|
||||||
|
|
@ -125,17 +125,17 @@ func (b *B) run() {
|
||||||
}
|
}
|
||||||
// Run more iterations than we think we'll need for a second (1.5x).
|
// Run more iterations than we think we'll need for a second (1.5x).
|
||||||
// Don't grow too fast in case we had timing errors previously.
|
// Don't grow too fast in case we had timing errors previously.
|
||||||
n = min(int(1.5*float(n)), 100*last);
|
n = min(int(1.5*float(n)), 100*last)
|
||||||
// Round up to something easy to read.
|
// Round up to something easy to read.
|
||||||
n = roundUp(n);
|
n = roundUp(n)
|
||||||
b.runN(n);
|
b.runN(n)
|
||||||
}
|
}
|
||||||
ns := b.nsPerOp();
|
ns := b.nsPerOp()
|
||||||
mb := "";
|
mb := ""
|
||||||
if ns > 0 && b.bytes > 0 {
|
if ns > 0 && b.bytes > 0 {
|
||||||
mb = fmt.Sprintf("\t%7.2f MB/s", (float64(b.bytes)/1e6)/(float64(ns)/1e9))
|
mb = fmt.Sprintf("\t%7.2f MB/s", (float64(b.bytes)/1e6)/(float64(ns)/1e9))
|
||||||
}
|
}
|
||||||
fmt.Printf("%s\t%8d\t%10d ns/op%s\n", b.benchmark.Name, b.N, b.nsPerOp(), mb);
|
fmt.Printf("%s\t%8d\t%10d ns/op%s\n", b.benchmark.Name, b.N, b.nsPerOp(), mb)
|
||||||
}
|
}
|
||||||
|
|
||||||
// An internal function but exported because it is cross-package; part of the implementation
|
// An internal function but exported because it is cross-package; part of the implementation
|
||||||
|
|
@ -145,16 +145,16 @@ func RunBenchmarks(benchmarks []Benchmark) {
|
||||||
if len(*matchBenchmarks) == 0 {
|
if len(*matchBenchmarks) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
re, err := CompileRegexp(*matchBenchmarks);
|
re, err := CompileRegexp(*matchBenchmarks)
|
||||||
if err != "" {
|
if err != "" {
|
||||||
println("invalid regexp for -benchmarks:", err);
|
println("invalid regexp for -benchmarks:", err)
|
||||||
os.Exit(1);
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
for _, Benchmark := range benchmarks {
|
for _, Benchmark := range benchmarks {
|
||||||
if !re.MatchString(Benchmark.Name) {
|
if !re.MatchString(Benchmark.Name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
b := &B{benchmark: Benchmark};
|
b := &B{benchmark: Benchmark}
|
||||||
b.run();
|
b.run()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,24 +5,24 @@
|
||||||
package iotest
|
package iotest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io";
|
"io"
|
||||||
"log";
|
"log"
|
||||||
"os";
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type writeLogger struct {
|
type writeLogger struct {
|
||||||
prefix string;
|
prefix string
|
||||||
w io.Writer;
|
w io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *writeLogger) Write(p []byte) (n int, err os.Error) {
|
func (l *writeLogger) Write(p []byte) (n int, err os.Error) {
|
||||||
n, err = l.w.Write(p);
|
n, err = l.w.Write(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Stdoutf("%s %x: %v", l.prefix, p[0:n], err)
|
log.Stdoutf("%s %x: %v", l.prefix, p[0:n], err)
|
||||||
} else {
|
} else {
|
||||||
log.Stdoutf("%s %x", l.prefix, p[0:n])
|
log.Stdoutf("%s %x", l.prefix, p[0:n])
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWriteLogger returns a writer that behaves like w except
|
// NewWriteLogger returns a writer that behaves like w except
|
||||||
|
|
@ -33,18 +33,18 @@ func NewWriteLogger(prefix string, w io.Writer) io.Writer {
|
||||||
}
|
}
|
||||||
|
|
||||||
type readLogger struct {
|
type readLogger struct {
|
||||||
prefix string;
|
prefix string
|
||||||
r io.Reader;
|
r io.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *readLogger) Read(p []byte) (n int, err os.Error) {
|
func (l *readLogger) Read(p []byte) (n int, err os.Error) {
|
||||||
n, err = l.r.Read(p);
|
n, err = l.r.Read(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Stdoutf("%s %x: %v", l.prefix, p[0:n], err)
|
log.Stdoutf("%s %x: %v", l.prefix, p[0:n], err)
|
||||||
} else {
|
} else {
|
||||||
log.Stdoutf("%s %x", l.prefix, p[0:n])
|
log.Stdoutf("%s %x", l.prefix, p[0:n])
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewReadLogger returns a reader that behaves like r except
|
// NewReadLogger returns a reader that behaves like r except
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@
|
||||||
package iotest
|
package iotest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io";
|
"io"
|
||||||
"os";
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OneByteReader returns a Reader that implements
|
// OneByteReader returns a Reader that implements
|
||||||
|
|
@ -16,14 +16,14 @@ import (
|
||||||
func OneByteReader(r io.Reader) io.Reader { return &oneByteReader{r} }
|
func OneByteReader(r io.Reader) io.Reader { return &oneByteReader{r} }
|
||||||
|
|
||||||
type oneByteReader struct {
|
type oneByteReader struct {
|
||||||
r io.Reader;
|
r io.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *oneByteReader) Read(p []byte) (int, os.Error) {
|
func (r *oneByteReader) Read(p []byte) (int, os.Error) {
|
||||||
if len(p) == 0 {
|
if len(p) == 0 {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
return r.r.Read(p[0:1]);
|
return r.r.Read(p[0:1])
|
||||||
}
|
}
|
||||||
|
|
||||||
// HalfReader returns a Reader that implements Read
|
// HalfReader returns a Reader that implements Read
|
||||||
|
|
@ -31,7 +31,7 @@ func (r *oneByteReader) Read(p []byte) (int, os.Error) {
|
||||||
func HalfReader(r io.Reader) io.Reader { return &halfReader{r} }
|
func HalfReader(r io.Reader) io.Reader { return &halfReader{r} }
|
||||||
|
|
||||||
type halfReader struct {
|
type halfReader struct {
|
||||||
r io.Reader;
|
r io.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *halfReader) Read(p []byte) (int, os.Error) {
|
func (r *halfReader) Read(p []byte) (int, os.Error) {
|
||||||
|
|
@ -45,9 +45,9 @@ func (r *halfReader) Read(p []byte) (int, os.Error) {
|
||||||
func DataErrReader(r io.Reader) io.Reader { return &dataErrReader{r, nil, make([]byte, 1024)} }
|
func DataErrReader(r io.Reader) io.Reader { return &dataErrReader{r, nil, make([]byte, 1024)} }
|
||||||
|
|
||||||
type dataErrReader struct {
|
type dataErrReader struct {
|
||||||
r io.Reader;
|
r io.Reader
|
||||||
unread []byte;
|
unread []byte
|
||||||
data []byte;
|
data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *dataErrReader) Read(p []byte) (n int, err os.Error) {
|
func (r *dataErrReader) Read(p []byte) (n int, err os.Error) {
|
||||||
|
|
@ -55,15 +55,15 @@ func (r *dataErrReader) Read(p []byte) (n int, err os.Error) {
|
||||||
// one to get data and a second to look for an error.
|
// one to get data and a second to look for an error.
|
||||||
for {
|
for {
|
||||||
if len(r.unread) == 0 {
|
if len(r.unread) == 0 {
|
||||||
n1, err1 := r.r.Read(r.data);
|
n1, err1 := r.r.Read(r.data)
|
||||||
r.unread = r.data[0:n1];
|
r.unread = r.data[0:n1]
|
||||||
err = err1;
|
err = err1
|
||||||
}
|
}
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
n = copy(p, r.unread);
|
n = copy(p, r.unread)
|
||||||
r.unread = r.unread[n:];
|
r.unread = r.unread[n:]
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
package iotest
|
package iotest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io";
|
"io"
|
||||||
"os";
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TruncateWriter returns a Writer that writes to w
|
// TruncateWriter returns a Writer that writes to w
|
||||||
|
|
@ -16,8 +16,8 @@ func TruncateWriter(w io.Writer, n int64) io.Writer {
|
||||||
}
|
}
|
||||||
|
|
||||||
type truncateWriter struct {
|
type truncateWriter struct {
|
||||||
w io.Writer;
|
w io.Writer
|
||||||
n int64;
|
n int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *truncateWriter) Write(p []byte) (n int, err os.Error) {
|
func (t *truncateWriter) Write(p []byte) (n int, err os.Error) {
|
||||||
|
|
@ -25,14 +25,14 @@ func (t *truncateWriter) Write(p []byte) (n int, err os.Error) {
|
||||||
return len(p), nil
|
return len(p), nil
|
||||||
}
|
}
|
||||||
// real write
|
// real write
|
||||||
n = len(p);
|
n = len(p)
|
||||||
if int64(n) > t.n {
|
if int64(n) > t.n {
|
||||||
n = int(t.n)
|
n = int(t.n)
|
||||||
}
|
}
|
||||||
n, err = t.w.Write(p[0:n]);
|
n, err = t.w.Write(p[0:n])
|
||||||
t.n -= int64(n);
|
t.n -= int64(n)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
n = len(p)
|
n = len(p)
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,13 @@
|
||||||
package quick
|
package quick
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag";
|
"flag"
|
||||||
"fmt";
|
"fmt"
|
||||||
"math";
|
"math"
|
||||||
"os";
|
"os"
|
||||||
"rand";
|
"rand"
|
||||||
"reflect";
|
"reflect"
|
||||||
"strings";
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var defaultMaxCount *int = flag.Int("quickchecks", 100, "The default number of iterations for each check")
|
var defaultMaxCount *int = flag.Int("quickchecks", 100, "The default number of iterations for each check")
|
||||||
|
|
@ -21,25 +21,25 @@ var defaultMaxCount *int = flag.Int("quickchecks", 100, "The default number of i
|
||||||
type Generator interface {
|
type Generator interface {
|
||||||
// Generate returns a random instance of the type on which it is a
|
// Generate returns a random instance of the type on which it is a
|
||||||
// method using the size as a size hint.
|
// method using the size as a size hint.
|
||||||
Generate(rand *rand.Rand, size int) reflect.Value;
|
Generate(rand *rand.Rand, size int) reflect.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
// randFloat32 generates a random float taking the full range of a float32.
|
// randFloat32 generates a random float taking the full range of a float32.
|
||||||
func randFloat32(rand *rand.Rand) float32 {
|
func randFloat32(rand *rand.Rand) float32 {
|
||||||
f := rand.Float64() * math.MaxFloat32;
|
f := rand.Float64() * math.MaxFloat32
|
||||||
if rand.Int()&1 == 1 {
|
if rand.Int()&1 == 1 {
|
||||||
f = -f
|
f = -f
|
||||||
}
|
}
|
||||||
return float32(f);
|
return float32(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// randFloat64 generates a random float taking the full range of a float64.
|
// randFloat64 generates a random float taking the full range of a float64.
|
||||||
func randFloat64(rand *rand.Rand) float64 {
|
func randFloat64(rand *rand.Rand) float64 {
|
||||||
f := rand.Float64();
|
f := rand.Float64()
|
||||||
if rand.Int()&1 == 1 {
|
if rand.Int()&1 == 1 {
|
||||||
f = -f
|
f = -f
|
||||||
}
|
}
|
||||||
return f;
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
// randInt64 returns a random integer taking half the range of an int64.
|
// randInt64 returns a random integer taking half the range of an int64.
|
||||||
|
|
@ -81,53 +81,53 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
|
||||||
case *reflect.IntType:
|
case *reflect.IntType:
|
||||||
return reflect.NewValue(int(randInt64(rand))), true
|
return reflect.NewValue(int(randInt64(rand))), true
|
||||||
case *reflect.MapType:
|
case *reflect.MapType:
|
||||||
numElems := rand.Intn(complexSize);
|
numElems := rand.Intn(complexSize)
|
||||||
m := reflect.MakeMap(concrete);
|
m := reflect.MakeMap(concrete)
|
||||||
for i := 0; i < numElems; i++ {
|
for i := 0; i < numElems; i++ {
|
||||||
key, ok1 := Value(concrete.Key(), rand);
|
key, ok1 := Value(concrete.Key(), rand)
|
||||||
value, ok2 := Value(concrete.Elem(), rand);
|
value, ok2 := Value(concrete.Elem(), rand)
|
||||||
if !ok1 || !ok2 {
|
if !ok1 || !ok2 {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
m.SetElem(key, value);
|
m.SetElem(key, value)
|
||||||
}
|
}
|
||||||
return m, true;
|
return m, true
|
||||||
case *reflect.PtrType:
|
case *reflect.PtrType:
|
||||||
v, ok := Value(concrete.Elem(), rand);
|
v, ok := Value(concrete.Elem(), rand)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
p := reflect.MakeZero(concrete);
|
p := reflect.MakeZero(concrete)
|
||||||
p.(*reflect.PtrValue).PointTo(v);
|
p.(*reflect.PtrValue).PointTo(v)
|
||||||
return p, true;
|
return p, true
|
||||||
case *reflect.SliceType:
|
case *reflect.SliceType:
|
||||||
numElems := rand.Intn(complexSize);
|
numElems := rand.Intn(complexSize)
|
||||||
s := reflect.MakeSlice(concrete, numElems, numElems);
|
s := reflect.MakeSlice(concrete, numElems, numElems)
|
||||||
for i := 0; i < numElems; i++ {
|
for i := 0; i < numElems; i++ {
|
||||||
v, ok := Value(concrete.Elem(), rand);
|
v, ok := Value(concrete.Elem(), rand)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
s.Elem(i).SetValue(v);
|
s.Elem(i).SetValue(v)
|
||||||
}
|
}
|
||||||
return s, true;
|
return s, true
|
||||||
case *reflect.StringType:
|
case *reflect.StringType:
|
||||||
numChars := rand.Intn(complexSize);
|
numChars := rand.Intn(complexSize)
|
||||||
codePoints := make([]int, numChars);
|
codePoints := make([]int, numChars)
|
||||||
for i := 0; i < numChars; i++ {
|
for i := 0; i < numChars; i++ {
|
||||||
codePoints[i] = rand.Intn(0x10ffff)
|
codePoints[i] = rand.Intn(0x10ffff)
|
||||||
}
|
}
|
||||||
return reflect.NewValue(string(codePoints)), true;
|
return reflect.NewValue(string(codePoints)), true
|
||||||
case *reflect.StructType:
|
case *reflect.StructType:
|
||||||
s := reflect.MakeZero(t).(*reflect.StructValue);
|
s := reflect.MakeZero(t).(*reflect.StructValue)
|
||||||
for i := 0; i < s.NumField(); i++ {
|
for i := 0; i < s.NumField(); i++ {
|
||||||
v, ok := Value(concrete.Field(i).Type, rand);
|
v, ok := Value(concrete.Field(i).Type, rand)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
s.Field(i).SetValue(v);
|
s.Field(i).SetValue(v)
|
||||||
}
|
}
|
||||||
return s, true;
|
return s, true
|
||||||
case *reflect.Uint16Type:
|
case *reflect.Uint16Type:
|
||||||
return reflect.NewValue(uint16(randInt64(rand))), true
|
return reflect.NewValue(uint16(randInt64(rand))), true
|
||||||
case *reflect.Uint32Type:
|
case *reflect.Uint32Type:
|
||||||
|
|
@ -144,24 +144,24 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Config structure contains options for running a test.
|
// A Config structure contains options for running a test.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// MaxCount sets the maximum number of iterations. If zero,
|
// MaxCount sets the maximum number of iterations. If zero,
|
||||||
// MaxCountScale is used.
|
// MaxCountScale is used.
|
||||||
MaxCount int;
|
MaxCount int
|
||||||
// MaxCountScale is a non-negative scale factor applied to the default
|
// MaxCountScale is a non-negative scale factor applied to the default
|
||||||
// maximum. If zero, the default is unchanged.
|
// maximum. If zero, the default is unchanged.
|
||||||
MaxCountScale float;
|
MaxCountScale float
|
||||||
// If non-nil, rand is a source of random numbers. Otherwise a default
|
// If non-nil, rand is a source of random numbers. Otherwise a default
|
||||||
// pseudo-random source will be used.
|
// pseudo-random source will be used.
|
||||||
Rand *rand.Rand;
|
Rand *rand.Rand
|
||||||
// If non-nil, Values is a function which generates a slice of arbitrary
|
// If non-nil, Values is a function which generates a slice of arbitrary
|
||||||
// Values that are congruent with the arguments to the function being
|
// Values that are congruent with the arguments to the function being
|
||||||
// tested. Otherwise, Values is used to generate the values.
|
// tested. Otherwise, Values is used to generate the values.
|
||||||
Values func([]reflect.Value, *rand.Rand);
|
Values func([]reflect.Value, *rand.Rand)
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultConfig Config
|
var defaultConfig Config
|
||||||
|
|
@ -171,13 +171,13 @@ func (c *Config) getRand() *rand.Rand {
|
||||||
if c.Rand == nil {
|
if c.Rand == nil {
|
||||||
return rand.New(rand.NewSource(0))
|
return rand.New(rand.NewSource(0))
|
||||||
}
|
}
|
||||||
return c.Rand;
|
return c.Rand
|
||||||
}
|
}
|
||||||
|
|
||||||
// getMaxCount returns the maximum number of iterations to run for a given
|
// getMaxCount returns the maximum number of iterations to run for a given
|
||||||
// Config.
|
// Config.
|
||||||
func (c *Config) getMaxCount() (maxCount int) {
|
func (c *Config) getMaxCount() (maxCount int) {
|
||||||
maxCount = c.MaxCount;
|
maxCount = c.MaxCount
|
||||||
if maxCount == 0 {
|
if maxCount == 0 {
|
||||||
if c.MaxCountScale != 0 {
|
if c.MaxCountScale != 0 {
|
||||||
maxCount = int(c.MaxCountScale * float(*defaultMaxCount))
|
maxCount = int(c.MaxCountScale * float(*defaultMaxCount))
|
||||||
|
|
@ -186,7 +186,7 @@ func (c *Config) getMaxCount() (maxCount int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// A SetupError is the result of an error in the way that check is being
|
// A SetupError is the result of an error in the way that check is being
|
||||||
|
|
@ -197,8 +197,8 @@ func (s SetupError) String() string { return string(s) }
|
||||||
|
|
||||||
// A CheckError is the result of Check finding an error.
|
// A CheckError is the result of Check finding an error.
|
||||||
type CheckError struct {
|
type CheckError struct {
|
||||||
Count int;
|
Count int
|
||||||
In []interface{};
|
In []interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CheckError) String() string {
|
func (s *CheckError) String() string {
|
||||||
|
|
@ -207,9 +207,9 @@ func (s *CheckError) String() string {
|
||||||
|
|
||||||
// A CheckEqualError is the result CheckEqual finding an error.
|
// A CheckEqualError is the result CheckEqual finding an error.
|
||||||
type CheckEqualError struct {
|
type CheckEqualError struct {
|
||||||
CheckError;
|
CheckError
|
||||||
Out1 []interface{};
|
Out1 []interface{}
|
||||||
Out2 []interface{};
|
Out2 []interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CheckEqualError) String() string {
|
func (s *CheckEqualError) String() string {
|
||||||
|
|
@ -236,38 +236,38 @@ func Check(function interface{}, config *Config) (err os.Error) {
|
||||||
config = &defaultConfig
|
config = &defaultConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
f, fType, ok := functionAndType(function);
|
f, fType, ok := functionAndType(function)
|
||||||
if !ok {
|
if !ok {
|
||||||
err = SetupError("argument is not a function");
|
err = SetupError("argument is not a function")
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if fType.NumOut() != 1 {
|
if fType.NumOut() != 1 {
|
||||||
err = SetupError("function returns more than one value.");
|
err = SetupError("function returns more than one value.")
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
if _, ok := fType.Out(0).(*reflect.BoolType); !ok {
|
if _, ok := fType.Out(0).(*reflect.BoolType); !ok {
|
||||||
err = SetupError("function does not return a bool");
|
err = SetupError("function does not return a bool")
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
arguments := make([]reflect.Value, fType.NumIn());
|
arguments := make([]reflect.Value, fType.NumIn())
|
||||||
rand := config.getRand();
|
rand := config.getRand()
|
||||||
maxCount := config.getMaxCount();
|
maxCount := config.getMaxCount()
|
||||||
|
|
||||||
for i := 0; i < maxCount; i++ {
|
for i := 0; i < maxCount; i++ {
|
||||||
err = arbitraryValues(arguments, fType, config, rand);
|
err = arbitraryValues(arguments, fType, config, rand)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !f.Call(arguments)[0].(*reflect.BoolValue).Get() {
|
if !f.Call(arguments)[0].(*reflect.BoolValue).Get() {
|
||||||
err = &CheckError{i + 1, toInterfaces(arguments)};
|
err = &CheckError{i + 1, toInterfaces(arguments)}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckEqual looks for an input on which f and g return different results.
|
// CheckEqual looks for an input on which f and g return different results.
|
||||||
|
|
@ -279,85 +279,85 @@ func CheckEqual(f, g interface{}, config *Config) (err os.Error) {
|
||||||
config = &defaultConfig
|
config = &defaultConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
x, xType, ok := functionAndType(f);
|
x, xType, ok := functionAndType(f)
|
||||||
if !ok {
|
if !ok {
|
||||||
err = SetupError("f is not a function");
|
err = SetupError("f is not a function")
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
y, yType, ok := functionAndType(g);
|
y, yType, ok := functionAndType(g)
|
||||||
if !ok {
|
if !ok {
|
||||||
err = SetupError("g is not a function");
|
err = SetupError("g is not a function")
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if xType != yType {
|
if xType != yType {
|
||||||
err = SetupError("functions have different types");
|
err = SetupError("functions have different types")
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
arguments := make([]reflect.Value, xType.NumIn());
|
arguments := make([]reflect.Value, xType.NumIn())
|
||||||
rand := config.getRand();
|
rand := config.getRand()
|
||||||
maxCount := config.getMaxCount();
|
maxCount := config.getMaxCount()
|
||||||
|
|
||||||
for i := 0; i < maxCount; i++ {
|
for i := 0; i < maxCount; i++ {
|
||||||
err = arbitraryValues(arguments, xType, config, rand);
|
err = arbitraryValues(arguments, xType, config, rand)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
xOut := toInterfaces(x.Call(arguments));
|
xOut := toInterfaces(x.Call(arguments))
|
||||||
yOut := toInterfaces(y.Call(arguments));
|
yOut := toInterfaces(y.Call(arguments))
|
||||||
|
|
||||||
if !reflect.DeepEqual(xOut, yOut) {
|
if !reflect.DeepEqual(xOut, yOut) {
|
||||||
err = &CheckEqualError{CheckError{i + 1, toInterfaces(arguments)}, xOut, yOut};
|
err = &CheckEqualError{CheckError{i + 1, toInterfaces(arguments)}, xOut, yOut}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// arbitraryValues writes Values to args such that args contains Values
|
// arbitraryValues writes Values to args such that args contains Values
|
||||||
// suitable for calling f.
|
// suitable for calling f.
|
||||||
func arbitraryValues(args []reflect.Value, f *reflect.FuncType, config *Config, rand *rand.Rand) (err os.Error) {
|
func arbitraryValues(args []reflect.Value, f *reflect.FuncType, config *Config, rand *rand.Rand) (err os.Error) {
|
||||||
if config.Values != nil {
|
if config.Values != nil {
|
||||||
config.Values(args, rand);
|
config.Values(args, rand)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for j := 0; j < len(args); j++ {
|
for j := 0; j < len(args); j++ {
|
||||||
var ok bool;
|
var ok bool
|
||||||
args[j], ok = Value(f.In(j), rand);
|
args[j], ok = Value(f.In(j), rand)
|
||||||
if !ok {
|
if !ok {
|
||||||
err = SetupError(fmt.Sprintf("cannot create arbitrary value of type %s for argument %d", f.In(j), j));
|
err = SetupError(fmt.Sprintf("cannot create arbitrary value of type %s for argument %d", f.In(j), j))
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func functionAndType(f interface{}) (v *reflect.FuncValue, t *reflect.FuncType, ok bool) {
|
func functionAndType(f interface{}) (v *reflect.FuncValue, t *reflect.FuncType, ok bool) {
|
||||||
v, ok = reflect.NewValue(f).(*reflect.FuncValue);
|
v, ok = reflect.NewValue(f).(*reflect.FuncValue)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t = v.Type().(*reflect.FuncType);
|
t = v.Type().(*reflect.FuncType)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func toInterfaces(values []reflect.Value) []interface{} {
|
func toInterfaces(values []reflect.Value) []interface{} {
|
||||||
ret := make([]interface{}, len(values));
|
ret := make([]interface{}, len(values))
|
||||||
for i, v := range values {
|
for i, v := range values {
|
||||||
ret[i] = v.Interface()
|
ret[i] = v.Interface()
|
||||||
}
|
}
|
||||||
return ret;
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func toString(interfaces []interface{}) string {
|
func toString(interfaces []interface{}) string {
|
||||||
s := make([]string, len(interfaces));
|
s := make([]string, len(interfaces))
|
||||||
for i, v := range interfaces {
|
for i, v := range interfaces {
|
||||||
s[i] = fmt.Sprintf("%#v", v)
|
s[i] = fmt.Sprintf("%#v", v)
|
||||||
}
|
}
|
||||||
return strings.Join(s, ", ");
|
return strings.Join(s, ", ")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@
|
||||||
package quick
|
package quick
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"rand";
|
"rand"
|
||||||
"reflect";
|
"reflect"
|
||||||
"testing";
|
"testing"
|
||||||
"os";
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func fBool(a bool) bool { return a }
|
func fBool(a bool) bool { return a }
|
||||||
|
|
@ -38,8 +38,8 @@ func fSlice(a []byte) []byte { return a }
|
||||||
func fString(a string) string { return a }
|
func fString(a string) string { return a }
|
||||||
|
|
||||||
type TestStruct struct {
|
type TestStruct struct {
|
||||||
A int;
|
A int
|
||||||
B string;
|
B string
|
||||||
}
|
}
|
||||||
|
|
||||||
func fStruct(a TestStruct) TestStruct { return a }
|
func fStruct(a TestStruct) TestStruct { return a }
|
||||||
|
|
@ -57,8 +57,8 @@ func fUint(a uint) uint { return a }
|
||||||
func fUintptr(a uintptr) uintptr { return a }
|
func fUintptr(a uintptr) uintptr { return a }
|
||||||
|
|
||||||
func fIntptr(a *int) *int {
|
func fIntptr(a *int) *int {
|
||||||
b := *a;
|
b := *a
|
||||||
return &b;
|
return &b
|
||||||
}
|
}
|
||||||
|
|
||||||
func reportError(property string, err os.Error, t *testing.T) {
|
func reportError(property string, err os.Error, t *testing.T) {
|
||||||
|
|
@ -68,34 +68,34 @@ func reportError(property string, err os.Error, t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckEqual(t *testing.T) {
|
func TestCheckEqual(t *testing.T) {
|
||||||
reportError("fBool", CheckEqual(fBool, fBool, nil), t);
|
reportError("fBool", CheckEqual(fBool, fBool, nil), t)
|
||||||
reportError("fFloat32", CheckEqual(fFloat32, fFloat32, nil), t);
|
reportError("fFloat32", CheckEqual(fFloat32, fFloat32, nil), t)
|
||||||
reportError("fFloat64", CheckEqual(fFloat64, fFloat64, nil), t);
|
reportError("fFloat64", CheckEqual(fFloat64, fFloat64, nil), t)
|
||||||
reportError("fFloat", CheckEqual(fFloat, fFloat, nil), t);
|
reportError("fFloat", CheckEqual(fFloat, fFloat, nil), t)
|
||||||
reportError("fInt16", CheckEqual(fInt16, fInt16, nil), t);
|
reportError("fInt16", CheckEqual(fInt16, fInt16, nil), t)
|
||||||
reportError("fInt32", CheckEqual(fInt32, fInt32, nil), t);
|
reportError("fInt32", CheckEqual(fInt32, fInt32, nil), t)
|
||||||
reportError("fInt64", CheckEqual(fInt64, fInt64, nil), t);
|
reportError("fInt64", CheckEqual(fInt64, fInt64, nil), t)
|
||||||
reportError("fInt8", CheckEqual(fInt8, fInt8, nil), t);
|
reportError("fInt8", CheckEqual(fInt8, fInt8, nil), t)
|
||||||
reportError("fInt", CheckEqual(fInt, fInt, nil), t);
|
reportError("fInt", CheckEqual(fInt, fInt, nil), t)
|
||||||
reportError("fUInt8", CheckEqual(fUInt8, fUInt8, nil), t);
|
reportError("fUInt8", CheckEqual(fUInt8, fUInt8, nil), t)
|
||||||
reportError("fInt32", CheckEqual(fInt32, fInt32, nil), t);
|
reportError("fInt32", CheckEqual(fInt32, fInt32, nil), t)
|
||||||
reportError("fMap", CheckEqual(fMap, fMap, nil), t);
|
reportError("fMap", CheckEqual(fMap, fMap, nil), t)
|
||||||
reportError("fSlice", CheckEqual(fSlice, fSlice, nil), t);
|
reportError("fSlice", CheckEqual(fSlice, fSlice, nil), t)
|
||||||
reportError("fString", CheckEqual(fString, fString, nil), t);
|
reportError("fString", CheckEqual(fString, fString, nil), t)
|
||||||
reportError("fStruct", CheckEqual(fStruct, fStruct, nil), t);
|
reportError("fStruct", CheckEqual(fStruct, fStruct, nil), t)
|
||||||
reportError("fUint16", CheckEqual(fUint16, fUint16, nil), t);
|
reportError("fUint16", CheckEqual(fUint16, fUint16, nil), t)
|
||||||
reportError("fUint32", CheckEqual(fUint32, fUint32, nil), t);
|
reportError("fUint32", CheckEqual(fUint32, fUint32, nil), t)
|
||||||
reportError("fUint64", CheckEqual(fUint64, fUint64, nil), t);
|
reportError("fUint64", CheckEqual(fUint64, fUint64, nil), t)
|
||||||
reportError("fUint8", CheckEqual(fUint8, fUint8, nil), t);
|
reportError("fUint8", CheckEqual(fUint8, fUint8, nil), t)
|
||||||
reportError("fUint", CheckEqual(fUint, fUint, nil), t);
|
reportError("fUint", CheckEqual(fUint, fUint, nil), t)
|
||||||
reportError("fUintptr", CheckEqual(fUintptr, fUintptr, nil), t);
|
reportError("fUintptr", CheckEqual(fUintptr, fUintptr, nil), t)
|
||||||
reportError("fIntptr", CheckEqual(fIntptr, fIntptr, nil), t);
|
reportError("fIntptr", CheckEqual(fIntptr, fIntptr, nil), t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This tests that ArbitraryValue is working by checking that all the arbitrary
|
// This tests that ArbitraryValue is working by checking that all the arbitrary
|
||||||
// values of type MyStruct have x = 42.
|
// values of type MyStruct have x = 42.
|
||||||
type myStruct struct {
|
type myStruct struct {
|
||||||
x int;
|
x int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m myStruct) Generate(r *rand.Rand, _ int) reflect.Value {
|
func (m myStruct) Generate(r *rand.Rand, _ int) reflect.Value {
|
||||||
|
|
@ -109,8 +109,8 @@ func TestCheckProperty(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFailure(t *testing.T) {
|
func TestFailure(t *testing.T) {
|
||||||
f := func(x int) bool { return false };
|
f := func(x int) bool { return false }
|
||||||
err := Check(f, nil);
|
err := Check(f, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Check didn't return an error")
|
t.Errorf("Check didn't return an error")
|
||||||
}
|
}
|
||||||
|
|
@ -118,7 +118,7 @@ func TestFailure(t *testing.T) {
|
||||||
t.Errorf("Error was not a CheckError: %s", err)
|
t.Errorf("Error was not a CheckError: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = CheckEqual(fUint, fUint32, nil);
|
err = CheckEqual(fUint, fUint32, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("#1 CheckEqual didn't return an error")
|
t.Errorf("#1 CheckEqual didn't return an error")
|
||||||
}
|
}
|
||||||
|
|
@ -126,7 +126,7 @@ func TestFailure(t *testing.T) {
|
||||||
t.Errorf("#1 Error was not a SetupError: %s", err)
|
t.Errorf("#1 Error was not a SetupError: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = CheckEqual(func(x, y int) {}, func(x int) {}, nil);
|
err = CheckEqual(func(x, y int) {}, func(x int) {}, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("#2 CheckEqual didn't return an error")
|
t.Errorf("#2 CheckEqual didn't return an error")
|
||||||
}
|
}
|
||||||
|
|
@ -134,7 +134,7 @@ func TestFailure(t *testing.T) {
|
||||||
t.Errorf("#2 Error was not a SetupError: %s", err)
|
t.Errorf("#2 Error was not a SetupError: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = CheckEqual(func(x int) int { return 0 }, func(x int) int32 { return 0 }, nil);
|
err = CheckEqual(func(x int) int { return 0 }, func(x int) int32 { return 0 }, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("#3 CheckEqual didn't return an error")
|
t.Errorf("#3 CheckEqual didn't return an error")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -5,7 +5,7 @@
|
||||||
package testing
|
package testing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings";
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var good_re = []string{
|
var good_re = []string{
|
||||||
|
|
@ -30,8 +30,8 @@ var good_re = []string{
|
||||||
|
|
||||||
// TODO: nice to do this with a map
|
// TODO: nice to do this with a map
|
||||||
type stringError struct {
|
type stringError struct {
|
||||||
re string;
|
re string
|
||||||
err string;
|
err string
|
||||||
}
|
}
|
||||||
|
|
||||||
var bad_re = []stringError{
|
var bad_re = []stringError{
|
||||||
|
|
@ -52,9 +52,9 @@ var bad_re = []stringError{
|
||||||
type vec []int
|
type vec []int
|
||||||
|
|
||||||
type tester struct {
|
type tester struct {
|
||||||
re string;
|
re string
|
||||||
text string;
|
text string
|
||||||
match vec;
|
match vec
|
||||||
}
|
}
|
||||||
|
|
||||||
var matches = []tester{
|
var matches = []tester{
|
||||||
|
|
@ -87,15 +87,15 @@ var matches = []tester{
|
||||||
}
|
}
|
||||||
|
|
||||||
func compileTest(t *T, expr string, error string) *Regexp {
|
func compileTest(t *T, expr string, error string) *Regexp {
|
||||||
re, err := CompileRegexp(expr);
|
re, err := CompileRegexp(expr)
|
||||||
if err != error {
|
if err != error {
|
||||||
t.Error("compiling `", expr, "`; unexpected error: ", err)
|
t.Error("compiling `", expr, "`; unexpected error: ", err)
|
||||||
}
|
}
|
||||||
return re;
|
return re
|
||||||
}
|
}
|
||||||
|
|
||||||
func printVec(t *T, m []int) {
|
func printVec(t *T, m []int) {
|
||||||
l := len(m);
|
l := len(m)
|
||||||
if l == 0 {
|
if l == 0 {
|
||||||
t.Log("\t<no match>")
|
t.Log("\t<no match>")
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -106,7 +106,7 @@ func printVec(t *T, m []int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func printStrings(t *T, m []string) {
|
func printStrings(t *T, m []string) {
|
||||||
l := len(m);
|
l := len(m)
|
||||||
if l == 0 {
|
if l == 0 {
|
||||||
t.Log("\t<no match>")
|
t.Log("\t<no match>")
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -117,7 +117,7 @@ func printStrings(t *T, m []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func printBytes(t *T, b [][]byte) {
|
func printBytes(t *T, b [][]byte) {
|
||||||
l := len(b);
|
l := len(b)
|
||||||
if l == 0 {
|
if l == 0 {
|
||||||
t.Log("\t<no match>")
|
t.Log("\t<no match>")
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -128,7 +128,7 @@ func printBytes(t *T, b [][]byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func equal(m1, m2 []int) bool {
|
func equal(m1, m2 []int) bool {
|
||||||
l := len(m1);
|
l := len(m1)
|
||||||
if l != len(m2) {
|
if l != len(m2) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -137,11 +137,11 @@ func equal(m1, m2 []int) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func equalStrings(m1, m2 []string) bool {
|
func equalStrings(m1, m2 []string) bool {
|
||||||
l := len(m1);
|
l := len(m1)
|
||||||
if l != len(m2) {
|
if l != len(m2) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -150,11 +150,11 @@ func equalStrings(m1, m2 []string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func equalBytes(m1 [][]byte, m2 []string) bool {
|
func equalBytes(m1 [][]byte, m2 []string) bool {
|
||||||
l := len(m1);
|
l := len(m1)
|
||||||
if l != len(m2) {
|
if l != len(m2) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -163,28 +163,28 @@ func equalBytes(m1 [][]byte, m2 []string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeTest(t *T, expr string, str string, match []int) {
|
func executeTest(t *T, expr string, str string, match []int) {
|
||||||
re := compileTest(t, expr, "");
|
re := compileTest(t, expr, "")
|
||||||
if re == nil {
|
if re == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
m := re.ExecuteString(str);
|
m := re.ExecuteString(str)
|
||||||
if !equal(m, match) {
|
if !equal(m, match) {
|
||||||
t.Error("ExecuteString failure on `", expr, "` matching `", str, "`:");
|
t.Error("ExecuteString failure on `", expr, "` matching `", str, "`:")
|
||||||
printVec(t, m);
|
printVec(t, m)
|
||||||
t.Log("should be:");
|
t.Log("should be:")
|
||||||
printVec(t, match);
|
printVec(t, match)
|
||||||
}
|
}
|
||||||
// now try bytes
|
// now try bytes
|
||||||
m = re.Execute(strings.Bytes(str));
|
m = re.Execute(strings.Bytes(str))
|
||||||
if !equal(m, match) {
|
if !equal(m, match) {
|
||||||
t.Error("Execute failure on `", expr, "` matching `", str, "`:");
|
t.Error("Execute failure on `", expr, "` matching `", str, "`:")
|
||||||
printVec(t, m);
|
printVec(t, m)
|
||||||
t.Log("should be:");
|
t.Log("should be:")
|
||||||
printVec(t, match);
|
printVec(t, match)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -202,22 +202,22 @@ func TestBadCompile(t *T) {
|
||||||
|
|
||||||
func TestExecute(t *T) {
|
func TestExecute(t *T) {
|
||||||
for i := 0; i < len(matches); i++ {
|
for i := 0; i < len(matches); i++ {
|
||||||
test := &matches[i];
|
test := &matches[i]
|
||||||
executeTest(t, test.re, test.text, test.match);
|
executeTest(t, test.re, test.text, test.match)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchTest(t *T, expr string, str string, match []int) {
|
func matchTest(t *T, expr string, str string, match []int) {
|
||||||
re := compileTest(t, expr, "");
|
re := compileTest(t, expr, "")
|
||||||
if re == nil {
|
if re == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
m := re.MatchString(str);
|
m := re.MatchString(str)
|
||||||
if m != (len(match) > 0) {
|
if m != (len(match) > 0) {
|
||||||
t.Error("MatchString failure on `", expr, "` matching `", str, "`:", m, "should be", len(match) > 0)
|
t.Error("MatchString failure on `", expr, "` matching `", str, "`:", m, "should be", len(match) > 0)
|
||||||
}
|
}
|
||||||
// now try bytes
|
// now try bytes
|
||||||
m = re.Match(strings.Bytes(str));
|
m = re.Match(strings.Bytes(str))
|
||||||
if m != (len(match) > 0) {
|
if m != (len(match) > 0) {
|
||||||
t.Error("Match failure on `", expr, "` matching `", str, "`:", m, "should be", len(match) > 0)
|
t.Error("Match failure on `", expr, "` matching `", str, "`:", m, "should be", len(match) > 0)
|
||||||
}
|
}
|
||||||
|
|
@ -225,46 +225,46 @@ func matchTest(t *T, expr string, str string, match []int) {
|
||||||
|
|
||||||
func TestMatch(t *T) {
|
func TestMatch(t *T) {
|
||||||
for i := 0; i < len(matches); i++ {
|
for i := 0; i < len(matches); i++ {
|
||||||
test := &matches[i];
|
test := &matches[i]
|
||||||
matchTest(t, test.re, test.text, test.match);
|
matchTest(t, test.re, test.text, test.match)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchStringsTest(t *T, expr string, str string, match []int) {
|
func matchStringsTest(t *T, expr string, str string, match []int) {
|
||||||
re := compileTest(t, expr, "");
|
re := compileTest(t, expr, "")
|
||||||
if re == nil {
|
if re == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strs := make([]string, len(match)/2);
|
strs := make([]string, len(match)/2)
|
||||||
for i := 0; i < len(match); i++ {
|
for i := 0; i < len(match); i++ {
|
||||||
strs[i/2] = str[match[i]:match[i+1]]
|
strs[i/2] = str[match[i]:match[i+1]]
|
||||||
}
|
}
|
||||||
m := re.MatchStrings(str);
|
m := re.MatchStrings(str)
|
||||||
if !equalStrings(m, strs) {
|
if !equalStrings(m, strs) {
|
||||||
t.Error("MatchStrings failure on `", expr, "` matching `", str, "`:");
|
t.Error("MatchStrings failure on `", expr, "` matching `", str, "`:")
|
||||||
printStrings(t, m);
|
printStrings(t, m)
|
||||||
t.Log("should be:");
|
t.Log("should be:")
|
||||||
printStrings(t, strs);
|
printStrings(t, strs)
|
||||||
}
|
}
|
||||||
// now try bytes
|
// now try bytes
|
||||||
s := re.MatchSlices(strings.Bytes(str));
|
s := re.MatchSlices(strings.Bytes(str))
|
||||||
if !equalBytes(s, strs) {
|
if !equalBytes(s, strs) {
|
||||||
t.Error("MatchSlices failure on `", expr, "` matching `", str, "`:");
|
t.Error("MatchSlices failure on `", expr, "` matching `", str, "`:")
|
||||||
printBytes(t, s);
|
printBytes(t, s)
|
||||||
t.Log("should be:");
|
t.Log("should be:")
|
||||||
printStrings(t, strs);
|
printStrings(t, strs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMatchStrings(t *T) {
|
func TestMatchStrings(t *T) {
|
||||||
for i := 0; i < len(matches); i++ {
|
for i := 0; i < len(matches); i++ {
|
||||||
test := &matches[i];
|
test := &matches[i]
|
||||||
matchTest(t, test.re, test.text, test.match);
|
matchTest(t, test.re, test.text, test.match)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchFunctionTest(t *T, expr string, str string, match []int) {
|
func matchFunctionTest(t *T, expr string, str string, match []int) {
|
||||||
m, err := MatchString(expr, str);
|
m, err := MatchString(expr, str)
|
||||||
if err == "" {
|
if err == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -275,15 +275,15 @@ func matchFunctionTest(t *T, expr string, str string, match []int) {
|
||||||
|
|
||||||
func TestMatchFunction(t *T) {
|
func TestMatchFunction(t *T) {
|
||||||
for i := 0; i < len(matches); i++ {
|
for i := 0; i < len(matches); i++ {
|
||||||
test := &matches[i];
|
test := &matches[i]
|
||||||
matchFunctionTest(t, test.re, test.text, test.match);
|
matchFunctionTest(t, test.re, test.text, test.match)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkSimpleMatch(b *B) {
|
func BenchmarkSimpleMatch(b *B) {
|
||||||
b.StopTimer();
|
b.StopTimer()
|
||||||
re, _ := CompileRegexp("a");
|
re, _ := CompileRegexp("a")
|
||||||
b.StartTimer();
|
b.StartTimer()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
re.MatchString("a")
|
re.MatchString("a")
|
||||||
|
|
@ -291,9 +291,9 @@ func BenchmarkSimpleMatch(b *B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkUngroupedMatch(b *B) {
|
func BenchmarkUngroupedMatch(b *B) {
|
||||||
b.StopTimer();
|
b.StopTimer()
|
||||||
re, _ := CompileRegexp("[a-z]+ [0-9]+ [a-z]+");
|
re, _ := CompileRegexp("[a-z]+ [0-9]+ [a-z]+")
|
||||||
b.StartTimer();
|
b.StartTimer()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
re.MatchString("word 123 other")
|
re.MatchString("word 123 other")
|
||||||
|
|
@ -301,9 +301,9 @@ func BenchmarkUngroupedMatch(b *B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkGroupedMatch(b *B) {
|
func BenchmarkGroupedMatch(b *B) {
|
||||||
b.StopTimer();
|
b.StopTimer()
|
||||||
re, _ := CompileRegexp("([a-z]+) ([0-9]+) ([a-z]+)");
|
re, _ := CompileRegexp("([a-z]+) ([0-9]+) ([a-z]+)")
|
||||||
b.StartTimer();
|
b.StartTimer()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
re.MatchString("word 123 other")
|
re.MatchString("word 123 other")
|
||||||
|
|
|
||||||
|
|
@ -6,37 +6,37 @@
|
||||||
package script
|
package script
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt";
|
"fmt"
|
||||||
"os";
|
"os"
|
||||||
"rand";
|
"rand"
|
||||||
"reflect";
|
"reflect"
|
||||||
"strings";
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// An Event is an element in a partially ordered set that either sends a value
|
// An Event is an element in a partially ordered set that either sends a value
|
||||||
// to a channel or expects a value from a channel.
|
// to a channel or expects a value from a channel.
|
||||||
type Event struct {
|
type Event struct {
|
||||||
name string;
|
name string
|
||||||
occurred bool;
|
occurred bool
|
||||||
predecessors []*Event;
|
predecessors []*Event
|
||||||
action action;
|
action action
|
||||||
}
|
}
|
||||||
|
|
||||||
type action interface {
|
type action interface {
|
||||||
// getSend returns nil if the action is not a send action.
|
// getSend returns nil if the action is not a send action.
|
||||||
getSend() sendAction;
|
getSend() sendAction
|
||||||
// getRecv returns nil if the action is not a receive action.
|
// getRecv returns nil if the action is not a receive action.
|
||||||
getRecv() recvAction;
|
getRecv() recvAction
|
||||||
// getChannel returns the channel that the action operates on.
|
// getChannel returns the channel that the action operates on.
|
||||||
getChannel() interface{};
|
getChannel() interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type recvAction interface {
|
type recvAction interface {
|
||||||
recvMatch(interface{}) bool;
|
recvMatch(interface{}) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type sendAction interface {
|
type sendAction interface {
|
||||||
send();
|
send()
|
||||||
}
|
}
|
||||||
|
|
||||||
// isReady returns true if all the predecessors of an Event have occurred.
|
// isReady returns true if all the predecessors of an Event have occurred.
|
||||||
|
|
@ -47,14 +47,14 @@ func (e Event) isReady() bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Recv action reads a value from a channel and uses reflect.DeepMatch to
|
// A Recv action reads a value from a channel and uses reflect.DeepMatch to
|
||||||
// compare it with an expected value.
|
// compare it with an expected value.
|
||||||
type Recv struct {
|
type Recv struct {
|
||||||
Channel interface{};
|
Channel interface{}
|
||||||
Expected interface{};
|
Expected interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Recv) getRecv() recvAction { return r }
|
func (r Recv) getRecv() recvAction { return r }
|
||||||
|
|
@ -64,19 +64,19 @@ func (Recv) getSend() sendAction { return nil }
|
||||||
func (r Recv) getChannel() interface{} { return r.Channel }
|
func (r Recv) getChannel() interface{} { return r.Channel }
|
||||||
|
|
||||||
func (r Recv) recvMatch(chanEvent interface{}) bool {
|
func (r Recv) recvMatch(chanEvent interface{}) bool {
|
||||||
c, ok := chanEvent.(channelRecv);
|
c, ok := chanEvent.(channelRecv)
|
||||||
if !ok || c.channel != r.Channel {
|
if !ok || c.channel != r.Channel {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return reflect.DeepEqual(c.value, r.Expected);
|
return reflect.DeepEqual(c.value, r.Expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A RecvMatch action reads a value from a channel and calls a function to
|
// A RecvMatch action reads a value from a channel and calls a function to
|
||||||
// determine if the value matches.
|
// determine if the value matches.
|
||||||
type RecvMatch struct {
|
type RecvMatch struct {
|
||||||
Channel interface{};
|
Channel interface{}
|
||||||
Match func(interface{}) bool;
|
Match func(interface{}) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r RecvMatch) getRecv() recvAction { return r }
|
func (r RecvMatch) getRecv() recvAction { return r }
|
||||||
|
|
@ -86,19 +86,19 @@ func (RecvMatch) getSend() sendAction { return nil }
|
||||||
func (r RecvMatch) getChannel() interface{} { return r.Channel }
|
func (r RecvMatch) getChannel() interface{} { return r.Channel }
|
||||||
|
|
||||||
func (r RecvMatch) recvMatch(chanEvent interface{}) bool {
|
func (r RecvMatch) recvMatch(chanEvent interface{}) bool {
|
||||||
c, ok := chanEvent.(channelRecv);
|
c, ok := chanEvent.(channelRecv)
|
||||||
if !ok || c.channel != r.Channel {
|
if !ok || c.channel != r.Channel {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.Match(c.value);
|
return r.Match(c.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Closed action matches if the given channel is closed. The closing is
|
// A Closed action matches if the given channel is closed. The closing is
|
||||||
// treated as an event, not a state, thus Closed will only match once for a
|
// treated as an event, not a state, thus Closed will only match once for a
|
||||||
// given channel.
|
// given channel.
|
||||||
type Closed struct {
|
type Closed struct {
|
||||||
Channel interface{};
|
Channel interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Closed) getRecv() recvAction { return r }
|
func (r Closed) getRecv() recvAction { return r }
|
||||||
|
|
@ -108,19 +108,19 @@ func (Closed) getSend() sendAction { return nil }
|
||||||
func (r Closed) getChannel() interface{} { return r.Channel }
|
func (r Closed) getChannel() interface{} { return r.Channel }
|
||||||
|
|
||||||
func (r Closed) recvMatch(chanEvent interface{}) bool {
|
func (r Closed) recvMatch(chanEvent interface{}) bool {
|
||||||
c, ok := chanEvent.(channelClosed);
|
c, ok := chanEvent.(channelClosed)
|
||||||
if !ok || c.channel != r.Channel {
|
if !ok || c.channel != r.Channel {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Send action sends a value to a channel. The value must match the
|
// A Send action sends a value to a channel. The value must match the
|
||||||
// type of the channel exactly unless the channel if of type chan interface{}.
|
// type of the channel exactly unless the channel if of type chan interface{}.
|
||||||
type Send struct {
|
type Send struct {
|
||||||
Channel interface{};
|
Channel interface{}
|
||||||
Value interface{};
|
Value interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Send) getRecv() recvAction { return nil }
|
func (Send) getRecv() recvAction { return nil }
|
||||||
|
|
@ -137,19 +137,19 @@ func (s Send) send() {
|
||||||
// With reflect.ChanValue.Send, we must match the types exactly. So, if
|
// With reflect.ChanValue.Send, we must match the types exactly. So, if
|
||||||
// s.Channel is a chan interface{} we convert s.Value to an interface{}
|
// s.Channel is a chan interface{} we convert s.Value to an interface{}
|
||||||
// first.
|
// first.
|
||||||
c := reflect.NewValue(s.Channel).(*reflect.ChanValue);
|
c := reflect.NewValue(s.Channel).(*reflect.ChanValue)
|
||||||
var v reflect.Value;
|
var v reflect.Value
|
||||||
if iface, ok := c.Type().(*reflect.ChanType).Elem().(*reflect.InterfaceType); ok && iface.NumMethod() == 0 {
|
if iface, ok := c.Type().(*reflect.ChanType).Elem().(*reflect.InterfaceType); ok && iface.NumMethod() == 0 {
|
||||||
v = newEmptyInterface(s.Value)
|
v = newEmptyInterface(s.Value)
|
||||||
} else {
|
} else {
|
||||||
v = reflect.NewValue(s.Value)
|
v = reflect.NewValue(s.Value)
|
||||||
}
|
}
|
||||||
c.Send(v);
|
c.Send(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Close action closes the given channel.
|
// A Close action closes the given channel.
|
||||||
type Close struct {
|
type Close struct {
|
||||||
Channel interface{};
|
Channel interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Close) getRecv() recvAction { return nil }
|
func (Close) getRecv() recvAction { return nil }
|
||||||
|
|
@ -163,16 +163,16 @@ func (s Close) send() { reflect.NewValue(s.Channel).(*reflect.ChanValue).Close()
|
||||||
// A ReceivedUnexpected error results if no active Events match a value
|
// A ReceivedUnexpected error results if no active Events match a value
|
||||||
// received from a channel.
|
// received from a channel.
|
||||||
type ReceivedUnexpected struct {
|
type ReceivedUnexpected struct {
|
||||||
Value interface{};
|
Value interface{}
|
||||||
ready []*Event;
|
ready []*Event
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r ReceivedUnexpected) String() string {
|
func (r ReceivedUnexpected) String() string {
|
||||||
names := make([]string, len(r.ready));
|
names := make([]string, len(r.ready))
|
||||||
for i, v := range r.ready {
|
for i, v := range r.ready {
|
||||||
names[i] = v.name
|
names[i] = v.name
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("received unexpected value on one of the channels: %#v. Runnable events: %s", r.Value, strings.Join(names, ", "));
|
return fmt.Sprintf("received unexpected value on one of the channels: %#v. Runnable events: %s", r.Value, strings.Join(names, ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
// A SetupError results if there is a error with the configuration of a set of
|
// A SetupError results if there is a error with the configuration of a set of
|
||||||
|
|
@ -182,8 +182,8 @@ type SetupError string
|
||||||
func (s SetupError) String() string { return string(s) }
|
func (s SetupError) String() string { return string(s) }
|
||||||
|
|
||||||
func NewEvent(name string, predecessors []*Event, action action) *Event {
|
func NewEvent(name string, predecessors []*Event, action action) *Event {
|
||||||
e := &Event{name, false, predecessors, action};
|
e := &Event{name, false, predecessors, action}
|
||||||
return e;
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a set of Events, Perform repeatedly iterates over the set and finds the
|
// Given a set of Events, Perform repeatedly iterates over the set and finds the
|
||||||
|
|
@ -220,20 +220,20 @@ func NewEvent(name string, predecessors []*Event, action action) *Event {
|
||||||
// thus Perform may see a value from a channel that is not in the current ready
|
// thus Perform may see a value from a channel that is not in the current ready
|
||||||
// set and fail.
|
// set and fail.
|
||||||
func Perform(seed int64, events []*Event) (err os.Error) {
|
func Perform(seed int64, events []*Event) (err os.Error) {
|
||||||
r := rand.New(rand.NewSource(seed));
|
r := rand.New(rand.NewSource(seed))
|
||||||
|
|
||||||
channels, err := getChannels(events);
|
channels, err := getChannels(events)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
multiplex := make(chan interface{});
|
multiplex := make(chan interface{})
|
||||||
for _, channel := range channels {
|
for _, channel := range channels {
|
||||||
go recvValues(multiplex, channel)
|
go recvValues(multiplex, channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
Outer:
|
Outer:
|
||||||
for {
|
for {
|
||||||
ready, err := readyEvents(events);
|
ready, err := readyEvents(events)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -243,113 +243,113 @@ Outer:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
event := ready[r.Intn(len(ready))];
|
event := ready[r.Intn(len(ready))]
|
||||||
if send := event.action.getSend(); send != nil {
|
if send := event.action.getSend(); send != nil {
|
||||||
send.send();
|
send.send()
|
||||||
event.occurred = true;
|
event.occurred = true
|
||||||
continue;
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
v := <-multiplex;
|
v := <-multiplex
|
||||||
for _, event := range ready {
|
for _, event := range ready {
|
||||||
if recv := event.action.getRecv(); recv != nil && recv.recvMatch(v) {
|
if recv := event.action.getRecv(); recv != nil && recv.recvMatch(v) {
|
||||||
event.occurred = true;
|
event.occurred = true
|
||||||
continue Outer;
|
continue Outer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ReceivedUnexpected{v, ready};
|
return ReceivedUnexpected{v, ready}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil;
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getChannels returns all the channels listed in any receive events.
|
// getChannels returns all the channels listed in any receive events.
|
||||||
func getChannels(events []*Event) ([]interface{}, os.Error) {
|
func getChannels(events []*Event) ([]interface{}, os.Error) {
|
||||||
channels := make([]interface{}, len(events));
|
channels := make([]interface{}, len(events))
|
||||||
|
|
||||||
j := 0;
|
j := 0
|
||||||
for _, event := range events {
|
for _, event := range events {
|
||||||
if recv := event.action.getRecv(); recv == nil {
|
if recv := event.action.getRecv(); recv == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c := event.action.getChannel();
|
c := event.action.getChannel()
|
||||||
if _, ok := reflect.NewValue(c).(*reflect.ChanValue); !ok {
|
if _, ok := reflect.NewValue(c).(*reflect.ChanValue); !ok {
|
||||||
return nil, SetupError("one of the channel values is not a channel")
|
return nil, SetupError("one of the channel values is not a channel")
|
||||||
}
|
}
|
||||||
|
|
||||||
duplicate := false;
|
duplicate := false
|
||||||
for _, other := range channels[0:j] {
|
for _, other := range channels[0:j] {
|
||||||
if c == other {
|
if c == other {
|
||||||
duplicate = true;
|
duplicate = true
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !duplicate {
|
if !duplicate {
|
||||||
channels[j] = c;
|
channels[j] = c
|
||||||
j++;
|
j++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return channels[0:j], nil;
|
return channels[0:j], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// recvValues is a multiplexing helper function. It reads values from the given
|
// recvValues is a multiplexing helper function. It reads values from the given
|
||||||
// channel repeatedly, wrapping them up as either a channelRecv or
|
// channel repeatedly, wrapping them up as either a channelRecv or
|
||||||
// channelClosed structure, and forwards them to the multiplex channel.
|
// channelClosed structure, and forwards them to the multiplex channel.
|
||||||
func recvValues(multiplex chan<- interface{}, channel interface{}) {
|
func recvValues(multiplex chan<- interface{}, channel interface{}) {
|
||||||
c := reflect.NewValue(channel).(*reflect.ChanValue);
|
c := reflect.NewValue(channel).(*reflect.ChanValue)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
v := c.Recv();
|
v := c.Recv()
|
||||||
if c.Closed() {
|
if c.Closed() {
|
||||||
multiplex <- channelClosed{channel};
|
multiplex <- channelClosed{channel}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
multiplex <- channelRecv{channel, v.Interface()};
|
multiplex <- channelRecv{channel, v.Interface()}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type channelClosed struct {
|
type channelClosed struct {
|
||||||
channel interface{};
|
channel interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type channelRecv struct {
|
type channelRecv struct {
|
||||||
channel interface{};
|
channel interface{}
|
||||||
value interface{};
|
value interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// readyEvents returns the subset of events that are ready.
|
// readyEvents returns the subset of events that are ready.
|
||||||
func readyEvents(events []*Event) ([]*Event, os.Error) {
|
func readyEvents(events []*Event) ([]*Event, os.Error) {
|
||||||
ready := make([]*Event, len(events));
|
ready := make([]*Event, len(events))
|
||||||
|
|
||||||
j := 0;
|
j := 0
|
||||||
eventsWaiting := false;
|
eventsWaiting := false
|
||||||
for _, event := range events {
|
for _, event := range events {
|
||||||
if event.occurred {
|
if event.occurred {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
eventsWaiting = true;
|
eventsWaiting = true
|
||||||
if event.isReady() {
|
if event.isReady() {
|
||||||
ready[j] = event;
|
ready[j] = event
|
||||||
j++;
|
j++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if j == 0 && eventsWaiting {
|
if j == 0 && eventsWaiting {
|
||||||
names := make([]string, len(events));
|
names := make([]string, len(events))
|
||||||
for _, event := range events {
|
for _, event := range events {
|
||||||
if event.occurred {
|
if event.occurred {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
names[j] = event.name;
|
names[j] = event.name
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, SetupError("dependency cycle in events. These events are waiting to run but cannot: " + strings.Join(names, ", "));
|
return nil, SetupError("dependency cycle in events. These events are waiting to run but cannot: " + strings.Join(names, ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
return ready[0:j], nil;
|
return ready[0:j], nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,37 +5,37 @@
|
||||||
package script
|
package script
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing";
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNoop(t *testing.T) {
|
func TestNoop(t *testing.T) {
|
||||||
err := Perform(0, nil);
|
err := Perform(0, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Got error: %s", err)
|
t.Errorf("Got error: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSimple(t *testing.T) {
|
func TestSimple(t *testing.T) {
|
||||||
c := make(chan int);
|
c := make(chan int)
|
||||||
defer close(c);
|
defer close(c)
|
||||||
|
|
||||||
a := NewEvent("send", nil, Send{c, 1});
|
a := NewEvent("send", nil, Send{c, 1})
|
||||||
b := NewEvent("recv", []*Event{a}, Recv{c, 1});
|
b := NewEvent("recv", []*Event{a}, Recv{c, 1})
|
||||||
|
|
||||||
err := Perform(0, []*Event{a, b});
|
err := Perform(0, []*Event{a, b})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Got error: %s", err)
|
t.Errorf("Got error: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFail(t *testing.T) {
|
func TestFail(t *testing.T) {
|
||||||
c := make(chan int);
|
c := make(chan int)
|
||||||
defer close(c);
|
defer close(c)
|
||||||
|
|
||||||
a := NewEvent("send", nil, Send{c, 2});
|
a := NewEvent("send", nil, Send{c, 2})
|
||||||
b := NewEvent("recv", []*Event{a}, Recv{c, 1});
|
b := NewEvent("recv", []*Event{a}, Recv{c, 1})
|
||||||
|
|
||||||
err := Perform(0, []*Event{a, b});
|
err := Perform(0, []*Event{a, b})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Failed to get expected error")
|
t.Errorf("Failed to get expected error")
|
||||||
} else if _, ok := err.(ReceivedUnexpected); !ok {
|
} else if _, ok := err.(ReceivedUnexpected); !ok {
|
||||||
|
|
@ -44,12 +44,12 @@ func TestFail(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClose(t *testing.T) {
|
func TestClose(t *testing.T) {
|
||||||
c := make(chan int);
|
c := make(chan int)
|
||||||
|
|
||||||
a := NewEvent("close", nil, Close{c});
|
a := NewEvent("close", nil, Close{c})
|
||||||
b := NewEvent("closed", []*Event{a}, Closed{c});
|
b := NewEvent("closed", []*Event{a}, Closed{c})
|
||||||
|
|
||||||
err := Perform(0, []*Event{a, b});
|
err := Perform(0, []*Event{a, b})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Got error: %s", err)
|
t.Errorf("Got error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
@ -59,16 +59,16 @@ func matchOne(v interface{}) bool {
|
||||||
if i, ok := v.(int); ok && i == 1 {
|
if i, ok := v.(int); ok && i == 1 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRecvMatch(t *testing.T) {
|
func TestRecvMatch(t *testing.T) {
|
||||||
c := make(chan int);
|
c := make(chan int)
|
||||||
|
|
||||||
a := NewEvent("send", nil, Send{c, 1});
|
a := NewEvent("send", nil, Send{c, 1})
|
||||||
b := NewEvent("recv", []*Event{a}, RecvMatch{c, matchOne});
|
b := NewEvent("recv", []*Event{a}, RecvMatch{c, matchOne})
|
||||||
|
|
||||||
err := Perform(0, []*Event{a, b});
|
err := Perform(0, []*Event{a, b})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Got error: %s", err)
|
t.Errorf("Got error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,10 +39,10 @@
|
||||||
package testing
|
package testing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag";
|
"flag"
|
||||||
"fmt";
|
"fmt"
|
||||||
"os";
|
"os"
|
||||||
"runtime";
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Report as tests are run; default is silent for success.
|
// Report as tests are run; default is silent for success.
|
||||||
|
|
@ -52,25 +52,25 @@ var match = flag.String("match", "", "regular expression to select tests to run"
|
||||||
|
|
||||||
// Insert final newline if needed and tabs after internal newlines.
|
// Insert final newline if needed and tabs after internal newlines.
|
||||||
func tabify(s string) string {
|
func tabify(s string) string {
|
||||||
n := len(s);
|
n := len(s)
|
||||||
if n > 0 && s[n-1] != '\n' {
|
if n > 0 && s[n-1] != '\n' {
|
||||||
s += "\n";
|
s += "\n"
|
||||||
n++;
|
n++
|
||||||
}
|
}
|
||||||
for i := 0; i < n-1; i++ { // -1 to avoid final newline
|
for i := 0; i < n-1; i++ { // -1 to avoid final newline
|
||||||
if s[i] == '\n' {
|
if s[i] == '\n' {
|
||||||
return s[0:i+1] + "\t" + tabify(s[i+1:n])
|
return s[0:i+1] + "\t" + tabify(s[i+1:n])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s;
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// T is a type passed to Test functions to manage test state and support formatted test logs.
|
// T is a type passed to Test functions to manage test state and support formatted test logs.
|
||||||
// Logs are accumulated during execution and dumped to standard error when done.
|
// Logs are accumulated during execution and dumped to standard error when done.
|
||||||
type T struct {
|
type T struct {
|
||||||
errors string;
|
errors string
|
||||||
failed bool;
|
failed bool
|
||||||
ch chan *T;
|
ch chan *T
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fail marks the Test function as having failed but continues execution.
|
// Fail marks the Test function as having failed but continues execution.
|
||||||
|
|
@ -82,9 +82,9 @@ func (t *T) Failed() bool { return t.failed }
|
||||||
// FailNow marks the Test function as having failed and stops its execution.
|
// FailNow marks the Test function as having failed and stops its execution.
|
||||||
// Execution will continue at the next Test.
|
// Execution will continue at the next Test.
|
||||||
func (t *T) FailNow() {
|
func (t *T) FailNow() {
|
||||||
t.Fail();
|
t.Fail()
|
||||||
t.ch <- t;
|
t.ch <- t
|
||||||
runtime.Goexit();
|
runtime.Goexit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log formats its arguments using default formatting, analogous to Print(),
|
// Log formats its arguments using default formatting, analogous to Print(),
|
||||||
|
|
@ -99,52 +99,52 @@ func (t *T) Logf(format string, args ...) {
|
||||||
|
|
||||||
// Error is equivalent to Log() followed by Fail().
|
// Error is equivalent to Log() followed by Fail().
|
||||||
func (t *T) Error(args ...) {
|
func (t *T) Error(args ...) {
|
||||||
t.Log(args);
|
t.Log(args)
|
||||||
t.Fail();
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errorf is equivalent to Logf() followed by Fail().
|
// Errorf is equivalent to Logf() followed by Fail().
|
||||||
func (t *T) Errorf(format string, args ...) {
|
func (t *T) Errorf(format string, args ...) {
|
||||||
t.Logf(format, args);
|
t.Logf(format, args)
|
||||||
t.Fail();
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatal is equivalent to Log() followed by FailNow().
|
// Fatal is equivalent to Log() followed by FailNow().
|
||||||
func (t *T) Fatal(args ...) {
|
func (t *T) Fatal(args ...) {
|
||||||
t.Log(args);
|
t.Log(args)
|
||||||
t.FailNow();
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatalf is equivalent to Logf() followed by FailNow().
|
// Fatalf is equivalent to Logf() followed by FailNow().
|
||||||
func (t *T) Fatalf(format string, args ...) {
|
func (t *T) Fatalf(format string, args ...) {
|
||||||
t.Logf(format, args);
|
t.Logf(format, args)
|
||||||
t.FailNow();
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
// An internal type but exported because it is cross-package; part of the implementation
|
// An internal type but exported because it is cross-package; part of the implementation
|
||||||
// of gotest.
|
// of gotest.
|
||||||
type Test struct {
|
type Test struct {
|
||||||
Name string;
|
Name string
|
||||||
F func(*T);
|
F func(*T)
|
||||||
}
|
}
|
||||||
|
|
||||||
func tRunner(t *T, test *Test) {
|
func tRunner(t *T, test *Test) {
|
||||||
test.F(t);
|
test.F(t)
|
||||||
t.ch <- t;
|
t.ch <- t
|
||||||
}
|
}
|
||||||
|
|
||||||
// An internal function but exported because it is cross-package; part of the implementation
|
// An internal function but exported because it is cross-package; part of the implementation
|
||||||
// of gotest.
|
// of gotest.
|
||||||
func Main(tests []Test) {
|
func Main(tests []Test) {
|
||||||
flag.Parse();
|
flag.Parse()
|
||||||
ok := true;
|
ok := true
|
||||||
if len(tests) == 0 {
|
if len(tests) == 0 {
|
||||||
println("testing: warning: no tests to run")
|
println("testing: warning: no tests to run")
|
||||||
}
|
}
|
||||||
re, err := CompileRegexp(*match);
|
re, err := CompileRegexp(*match)
|
||||||
if err != "" {
|
if err != "" {
|
||||||
println("invalid regexp for -match:", err);
|
println("invalid regexp for -match:", err)
|
||||||
os.Exit(1);
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
for i := 0; i < len(tests); i++ {
|
for i := 0; i < len(tests); i++ {
|
||||||
if !re.MatchString(tests[i].Name) {
|
if !re.MatchString(tests[i].Name) {
|
||||||
|
|
@ -153,22 +153,22 @@ func Main(tests []Test) {
|
||||||
if *chatty {
|
if *chatty {
|
||||||
println("=== RUN ", tests[i].Name)
|
println("=== RUN ", tests[i].Name)
|
||||||
}
|
}
|
||||||
t := new(T);
|
t := new(T)
|
||||||
t.ch = make(chan *T);
|
t.ch = make(chan *T)
|
||||||
go tRunner(t, &tests[i]);
|
go tRunner(t, &tests[i])
|
||||||
<-t.ch;
|
<-t.ch
|
||||||
if t.failed {
|
if t.failed {
|
||||||
println("--- FAIL:", tests[i].Name);
|
println("--- FAIL:", tests[i].Name)
|
||||||
print(t.errors);
|
print(t.errors)
|
||||||
ok = false;
|
ok = false
|
||||||
} else if *chatty {
|
} else if *chatty {
|
||||||
println("--- PASS:", tests[i].Name);
|
println("--- PASS:", tests[i].Name)
|
||||||
print(t.errors);
|
print(t.errors)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
println("FAIL");
|
println("FAIL")
|
||||||
os.Exit(1);
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
println("PASS");
|
println("PASS")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
package time
|
package time
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os";
|
"os"
|
||||||
"syscall";
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Sleep pauses the current goroutine for ns nanoseconds.
|
// Sleep pauses the current goroutine for ns nanoseconds.
|
||||||
|
|
|
||||||
|
|
@ -23,19 +23,19 @@ package time
|
||||||
// A Ticker holds a synchronous channel that delivers `ticks' of a clock
|
// A Ticker holds a synchronous channel that delivers `ticks' of a clock
|
||||||
// at intervals.
|
// at intervals.
|
||||||
type Ticker struct {
|
type Ticker struct {
|
||||||
C <-chan int64; // The channel on which the ticks are delivered.
|
C <-chan int64 // The channel on which the ticks are delivered.
|
||||||
ns int64;
|
ns int64
|
||||||
shutdown bool;
|
shutdown bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop turns off a ticker. After Stop, no more ticks will be delivered.
|
// Stop turns off a ticker. After Stop, no more ticks will be delivered.
|
||||||
func (t *Ticker) Stop() { t.shutdown = true }
|
func (t *Ticker) Stop() { t.shutdown = true }
|
||||||
|
|
||||||
func (t *Ticker) ticker(c chan<- int64) {
|
func (t *Ticker) ticker(c chan<- int64) {
|
||||||
now := Nanoseconds();
|
now := Nanoseconds()
|
||||||
when := now;
|
when := now
|
||||||
for !t.shutdown {
|
for !t.shutdown {
|
||||||
when += t.ns; // next alarm
|
when += t.ns // next alarm
|
||||||
|
|
||||||
// if c <- now took too long, skip ahead
|
// if c <- now took too long, skip ahead
|
||||||
if when < now {
|
if when < now {
|
||||||
|
|
@ -47,12 +47,12 @@ func (t *Ticker) ticker(c chan<- int64) {
|
||||||
when += t.ns
|
when += t.ns
|
||||||
}
|
}
|
||||||
|
|
||||||
Sleep(when - now);
|
Sleep(when - now)
|
||||||
now = Nanoseconds();
|
now = Nanoseconds()
|
||||||
if t.shutdown {
|
if t.shutdown {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c <- now;
|
c <- now
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,7 +62,7 @@ func Tick(ns int64) <-chan int64 {
|
||||||
if ns <= 0 {
|
if ns <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return NewTicker(ns).C;
|
return NewTicker(ns).C
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ticker returns a new Ticker containing a synchronous channel that will
|
// Ticker returns a new Ticker containing a synchronous channel that will
|
||||||
|
|
@ -72,8 +72,8 @@ func NewTicker(ns int64) *Ticker {
|
||||||
if ns <= 0 {
|
if ns <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
c := make(chan int64);
|
c := make(chan int64)
|
||||||
t := &Ticker{c, ns, false};
|
t := &Ticker{c, ns, false}
|
||||||
go t.ticker(c);
|
go t.ticker(c)
|
||||||
return t;
|
return t
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,31 +5,31 @@
|
||||||
package time_test
|
package time_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing";
|
"testing"
|
||||||
. "time";
|
. "time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTicker(t *testing.T) {
|
func TestTicker(t *testing.T) {
|
||||||
const (
|
const (
|
||||||
Delta = 100 * 1e6;
|
Delta = 100 * 1e6
|
||||||
Count = 10;
|
Count = 10
|
||||||
)
|
)
|
||||||
ticker := NewTicker(Delta);
|
ticker := NewTicker(Delta)
|
||||||
t0 := Nanoseconds();
|
t0 := Nanoseconds()
|
||||||
for i := 0; i < Count; i++ {
|
for i := 0; i < Count; i++ {
|
||||||
<-ticker.C
|
<-ticker.C
|
||||||
}
|
}
|
||||||
ticker.Stop();
|
ticker.Stop()
|
||||||
t1 := Nanoseconds();
|
t1 := Nanoseconds()
|
||||||
ns := t1 - t0;
|
ns := t1 - t0
|
||||||
target := int64(Delta * Count);
|
target := int64(Delta * Count)
|
||||||
slop := target * 2 / 10;
|
slop := target * 2 / 10
|
||||||
if ns < target-slop || ns > target+slop {
|
if ns < target-slop || ns > target+slop {
|
||||||
t.Fatalf("%d ticks of %g ns took %g ns, expected %g", Count, float64(Delta), float64(ns), float64(target))
|
t.Fatalf("%d ticks of %g ns took %g ns, expected %g", Count, float64(Delta), float64(ns), float64(target))
|
||||||
}
|
}
|
||||||
// Now test that the ticker stopped
|
// Now test that the ticker stopped
|
||||||
Sleep(2 * Delta);
|
Sleep(2 * Delta)
|
||||||
_, received := <-ticker.C;
|
_, received := <-ticker.C
|
||||||
if received {
|
if received {
|
||||||
t.Fatalf("Ticker did not shut down")
|
t.Fatalf("Ticker did not shut down")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,48 +7,48 @@
|
||||||
package time
|
package time
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os";
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Seconds reports the number of seconds since the Unix epoch,
|
// Seconds reports the number of seconds since the Unix epoch,
|
||||||
// January 1, 1970 00:00:00 UTC.
|
// January 1, 1970 00:00:00 UTC.
|
||||||
func Seconds() int64 {
|
func Seconds() int64 {
|
||||||
sec, _, err := os.Time();
|
sec, _, err := os.Time()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("time: os.Time: ", err.String())
|
panic("time: os.Time: ", err.String())
|
||||||
}
|
}
|
||||||
return sec;
|
return sec
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nanoseconds reports the number of nanoseconds since the Unix epoch,
|
// Nanoseconds reports the number of nanoseconds since the Unix epoch,
|
||||||
// January 1, 1970 00:00:00 UTC.
|
// January 1, 1970 00:00:00 UTC.
|
||||||
func Nanoseconds() int64 {
|
func Nanoseconds() int64 {
|
||||||
sec, nsec, err := os.Time();
|
sec, nsec, err := os.Time()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("time: os.Time: ", err.String())
|
panic("time: os.Time: ", err.String())
|
||||||
}
|
}
|
||||||
return sec*1e9 + nsec;
|
return sec*1e9 + nsec
|
||||||
}
|
}
|
||||||
|
|
||||||
// Days of the week.
|
// Days of the week.
|
||||||
const (
|
const (
|
||||||
Sunday = iota;
|
Sunday = iota
|
||||||
Monday;
|
Monday
|
||||||
Tuesday;
|
Tuesday
|
||||||
Wednesday;
|
Wednesday
|
||||||
Thursday;
|
Thursday
|
||||||
Friday;
|
Friday
|
||||||
Saturday;
|
Saturday
|
||||||
)
|
)
|
||||||
|
|
||||||
// Time is the struct representing a parsed time value.
|
// Time is the struct representing a parsed time value.
|
||||||
type Time struct {
|
type Time struct {
|
||||||
Year int64; // 2008 is 2008
|
Year int64 // 2008 is 2008
|
||||||
Month, Day int; // Sep-17 is 9, 17
|
Month, Day int // Sep-17 is 9, 17
|
||||||
Hour, Minute, Second int; // 10:43:12 is 10, 43, 12
|
Hour, Minute, Second int // 10:43:12 is 10, 43, 12
|
||||||
Weekday int; // Sunday, Monday, ...
|
Weekday int // Sunday, Monday, ...
|
||||||
ZoneOffset int; // seconds east of UTC
|
ZoneOffset int // seconds east of UTC
|
||||||
Zone string;
|
Zone string
|
||||||
}
|
}
|
||||||
|
|
||||||
var nonleapyear = []int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
|
var nonleapyear = []int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
|
||||||
|
|
@ -58,37 +58,37 @@ func months(year int64) []int {
|
||||||
if year%4 == 0 && (year%100 != 0 || year%400 == 0) {
|
if year%4 == 0 && (year%100 != 0 || year%400 == 0) {
|
||||||
return leapyear
|
return leapyear
|
||||||
}
|
}
|
||||||
return nonleapyear;
|
return nonleapyear
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
secondsPerDay = 24 * 60 * 60;
|
secondsPerDay = 24 * 60 * 60
|
||||||
daysPer400Years = 365*400 + 97;
|
daysPer400Years = 365*400 + 97
|
||||||
daysPer100Years = 365*100 + 24;
|
daysPer100Years = 365*100 + 24
|
||||||
daysPer4Years = 365*4 + 1;
|
daysPer4Years = 365*4 + 1
|
||||||
days1970To2001 = 31*365 + 8;
|
days1970To2001 = 31*365 + 8
|
||||||
)
|
)
|
||||||
|
|
||||||
// SecondsToUTC converts sec, in number of seconds since the Unix epoch,
|
// SecondsToUTC converts sec, in number of seconds since the Unix epoch,
|
||||||
// into a parsed Time value in the UTC time zone.
|
// into a parsed Time value in the UTC time zone.
|
||||||
func SecondsToUTC(sec int64) *Time {
|
func SecondsToUTC(sec int64) *Time {
|
||||||
t := new(Time);
|
t := new(Time)
|
||||||
|
|
||||||
// Split into time and day.
|
// Split into time and day.
|
||||||
day := sec / secondsPerDay;
|
day := sec / secondsPerDay
|
||||||
sec -= day * secondsPerDay;
|
sec -= day * secondsPerDay
|
||||||
if sec < 0 {
|
if sec < 0 {
|
||||||
day--;
|
day--
|
||||||
sec += secondsPerDay;
|
sec += secondsPerDay
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time
|
// Time
|
||||||
t.Hour = int(sec / 3600);
|
t.Hour = int(sec / 3600)
|
||||||
t.Minute = int((sec / 60) % 60);
|
t.Minute = int((sec / 60) % 60)
|
||||||
t.Second = int(sec % 60);
|
t.Second = int(sec % 60)
|
||||||
|
|
||||||
// Day 0 = January 1, 1970 was a Thursday
|
// Day 0 = January 1, 1970 was a Thursday
|
||||||
t.Weekday = int((day + Thursday) % 7);
|
t.Weekday = int((day + Thursday) % 7)
|
||||||
if t.Weekday < 0 {
|
if t.Weekday < 0 {
|
||||||
t.Weekday += 7
|
t.Weekday += 7
|
||||||
}
|
}
|
||||||
|
|
@ -96,61 +96,61 @@ func SecondsToUTC(sec int64) *Time {
|
||||||
// Change day from 0 = 1970 to 0 = 2001,
|
// Change day from 0 = 1970 to 0 = 2001,
|
||||||
// to make leap year calculations easier
|
// to make leap year calculations easier
|
||||||
// (2001 begins 4-, 100-, and 400-year cycles ending in a leap year.)
|
// (2001 begins 4-, 100-, and 400-year cycles ending in a leap year.)
|
||||||
day -= days1970To2001;
|
day -= days1970To2001
|
||||||
|
|
||||||
year := int64(2001);
|
year := int64(2001)
|
||||||
if day < 0 {
|
if day < 0 {
|
||||||
// Go back enough 400 year cycles to make day positive.
|
// Go back enough 400 year cycles to make day positive.
|
||||||
n := -day/daysPer400Years + 1;
|
n := -day/daysPer400Years + 1
|
||||||
year -= 400 * n;
|
year -= 400 * n
|
||||||
day += daysPer400Years * n;
|
day += daysPer400Years * n
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cut off 400 year cycles.
|
// Cut off 400 year cycles.
|
||||||
n := day / daysPer400Years;
|
n := day / daysPer400Years
|
||||||
year += 400 * n;
|
year += 400 * n
|
||||||
day -= daysPer400Years * n;
|
day -= daysPer400Years * n
|
||||||
|
|
||||||
// Cut off 100-year cycles
|
// Cut off 100-year cycles
|
||||||
n = day / daysPer100Years;
|
n = day / daysPer100Years
|
||||||
if n > 3 { // happens on last day of 400th year
|
if n > 3 { // happens on last day of 400th year
|
||||||
n = 3
|
n = 3
|
||||||
}
|
}
|
||||||
year += 100 * n;
|
year += 100 * n
|
||||||
day -= daysPer100Years * n;
|
day -= daysPer100Years * n
|
||||||
|
|
||||||
// Cut off 4-year cycles
|
// Cut off 4-year cycles
|
||||||
n = day / daysPer4Years;
|
n = day / daysPer4Years
|
||||||
if n > 24 { // happens on last day of 100th year
|
if n > 24 { // happens on last day of 100th year
|
||||||
n = 24
|
n = 24
|
||||||
}
|
}
|
||||||
year += 4 * n;
|
year += 4 * n
|
||||||
day -= daysPer4Years * n;
|
day -= daysPer4Years * n
|
||||||
|
|
||||||
// Cut off non-leap years.
|
// Cut off non-leap years.
|
||||||
n = day / 365;
|
n = day / 365
|
||||||
if n > 3 { // happens on last day of 4th year
|
if n > 3 { // happens on last day of 4th year
|
||||||
n = 3
|
n = 3
|
||||||
}
|
}
|
||||||
year += n;
|
year += n
|
||||||
day -= 365 * n;
|
day -= 365 * n
|
||||||
|
|
||||||
t.Year = year;
|
t.Year = year
|
||||||
|
|
||||||
// If someone ever needs yearday,
|
// If someone ever needs yearday,
|
||||||
// tyearday = day (+1?)
|
// tyearday = day (+1?)
|
||||||
|
|
||||||
months := months(year);
|
months := months(year)
|
||||||
var m int;
|
var m int
|
||||||
yday := int(day);
|
yday := int(day)
|
||||||
for m = 0; m < 12 && yday >= months[m]; m++ {
|
for m = 0; m < 12 && yday >= months[m]; m++ {
|
||||||
yday -= months[m]
|
yday -= months[m]
|
||||||
}
|
}
|
||||||
t.Month = m + 1;
|
t.Month = m + 1
|
||||||
t.Day = yday + 1;
|
t.Day = yday + 1
|
||||||
t.Zone = "UTC";
|
t.Zone = "UTC"
|
||||||
|
|
||||||
return t;
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
// UTC returns the current time as a parsed Time value in the UTC time zone.
|
// UTC returns the current time as a parsed Time value in the UTC time zone.
|
||||||
|
|
@ -159,11 +159,11 @@ func UTC() *Time { return SecondsToUTC(Seconds()) }
|
||||||
// SecondsToLocalTime converts sec, in number of seconds since the Unix epoch,
|
// SecondsToLocalTime converts sec, in number of seconds since the Unix epoch,
|
||||||
// into a parsed Time value in the local time zone.
|
// into a parsed Time value in the local time zone.
|
||||||
func SecondsToLocalTime(sec int64) *Time {
|
func SecondsToLocalTime(sec int64) *Time {
|
||||||
z, offset := lookupTimezone(sec);
|
z, offset := lookupTimezone(sec)
|
||||||
t := SecondsToUTC(sec + int64(offset));
|
t := SecondsToUTC(sec + int64(offset))
|
||||||
t.Zone = z;
|
t.Zone = z
|
||||||
t.ZoneOffset = offset;
|
t.ZoneOffset = offset
|
||||||
return t;
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalTime returns the current time as a parsed Time value in the local time zone.
|
// LocalTime returns the current time as a parsed Time value in the local time zone.
|
||||||
|
|
@ -176,56 +176,56 @@ func (t *Time) Seconds() int64 {
|
||||||
// Using 2001 instead of 1970 makes the leap-year
|
// Using 2001 instead of 1970 makes the leap-year
|
||||||
// handling easier (see SecondsToUTC), because
|
// handling easier (see SecondsToUTC), because
|
||||||
// it is at the beginning of the 4-, 100-, and 400-year cycles.
|
// it is at the beginning of the 4-, 100-, and 400-year cycles.
|
||||||
day := int64(0);
|
day := int64(0)
|
||||||
|
|
||||||
// Rewrite year to be >= 2001.
|
// Rewrite year to be >= 2001.
|
||||||
year := t.Year;
|
year := t.Year
|
||||||
if year < 2001 {
|
if year < 2001 {
|
||||||
n := (2001-year)/400 + 1;
|
n := (2001-year)/400 + 1
|
||||||
year += 400 * n;
|
year += 400 * n
|
||||||
day -= daysPer400Years * n;
|
day -= daysPer400Years * n
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add in days from 400-year cycles.
|
// Add in days from 400-year cycles.
|
||||||
n := (year - 2001) / 400;
|
n := (year - 2001) / 400
|
||||||
year -= 400 * n;
|
year -= 400 * n
|
||||||
day += daysPer400Years * n;
|
day += daysPer400Years * n
|
||||||
|
|
||||||
// Add in 100-year cycles.
|
// Add in 100-year cycles.
|
||||||
n = (year - 2001) / 100;
|
n = (year - 2001) / 100
|
||||||
year -= 100 * n;
|
year -= 100 * n
|
||||||
day += daysPer100Years * n;
|
day += daysPer100Years * n
|
||||||
|
|
||||||
// Add in 4-year cycles.
|
// Add in 4-year cycles.
|
||||||
n = (year - 2001) / 4;
|
n = (year - 2001) / 4
|
||||||
year -= 4 * n;
|
year -= 4 * n
|
||||||
day += daysPer4Years * n;
|
day += daysPer4Years * n
|
||||||
|
|
||||||
// Add in non-leap years.
|
// Add in non-leap years.
|
||||||
n = year - 2001;
|
n = year - 2001
|
||||||
day += 365 * n;
|
day += 365 * n
|
||||||
|
|
||||||
// Add in days this year.
|
// Add in days this year.
|
||||||
months := months(t.Year);
|
months := months(t.Year)
|
||||||
for m := 0; m < t.Month-1; m++ {
|
for m := 0; m < t.Month-1; m++ {
|
||||||
day += int64(months[m])
|
day += int64(months[m])
|
||||||
}
|
}
|
||||||
day += int64(t.Day - 1);
|
day += int64(t.Day - 1)
|
||||||
|
|
||||||
// Convert days to seconds since January 1, 2001.
|
// Convert days to seconds since January 1, 2001.
|
||||||
sec := day * secondsPerDay;
|
sec := day * secondsPerDay
|
||||||
|
|
||||||
// Add in time elapsed today.
|
// Add in time elapsed today.
|
||||||
sec += int64(t.Hour) * 3600;
|
sec += int64(t.Hour) * 3600
|
||||||
sec += int64(t.Minute) * 60;
|
sec += int64(t.Minute) * 60
|
||||||
sec += int64(t.Second);
|
sec += int64(t.Second)
|
||||||
|
|
||||||
// Convert from seconds since 2001 to seconds since 1970.
|
// Convert from seconds since 2001 to seconds since 1970.
|
||||||
sec += days1970To2001 * secondsPerDay;
|
sec += days1970To2001 * secondsPerDay
|
||||||
|
|
||||||
// Account for local time zone.
|
// Account for local time zone.
|
||||||
sec -= int64(t.ZoneOffset);
|
sec -= int64(t.ZoneOffset)
|
||||||
return sec;
|
return sec
|
||||||
}
|
}
|
||||||
|
|
||||||
var longDayNames = []string{
|
var longDayNames = []string{
|
||||||
|
|
@ -275,26 +275,26 @@ func decimal(dst []byte, n int) {
|
||||||
n = 0
|
n = 0
|
||||||
}
|
}
|
||||||
for i := len(dst) - 1; i >= 0; i-- {
|
for i := len(dst) - 1; i >= 0; i-- {
|
||||||
dst[i] = byte(n%10 + '0');
|
dst[i] = byte(n%10 + '0')
|
||||||
n /= 10;
|
n /= 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addString(buf []byte, bp int, s string) int {
|
func addString(buf []byte, bp int, s string) int {
|
||||||
n := len(s);
|
n := len(s)
|
||||||
copy(buf[bp:bp+n], s);
|
copy(buf[bp:bp+n], s)
|
||||||
return bp + n;
|
return bp + n
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just enough of strftime to implement the date formats below.
|
// Just enough of strftime to implement the date formats below.
|
||||||
// Not exported.
|
// Not exported.
|
||||||
func format(t *Time, fmt string) string {
|
func format(t *Time, fmt string) string {
|
||||||
buf := make([]byte, 128);
|
buf := make([]byte, 128)
|
||||||
bp := 0;
|
bp := 0
|
||||||
|
|
||||||
for i := 0; i < len(fmt); i++ {
|
for i := 0; i < len(fmt); i++ {
|
||||||
if fmt[i] == '%' {
|
if fmt[i] == '%' {
|
||||||
i++;
|
i++
|
||||||
switch fmt[i] {
|
switch fmt[i] {
|
||||||
case 'A': // %A full weekday name
|
case 'A': // %A full weekday name
|
||||||
bp = addString(buf, bp, longDayNames[t.Weekday])
|
bp = addString(buf, bp, longDayNames[t.Weekday])
|
||||||
|
|
@ -303,44 +303,44 @@ func format(t *Time, fmt string) string {
|
||||||
case 'b': // %b abbreviated month name
|
case 'b': // %b abbreviated month name
|
||||||
bp = addString(buf, bp, shortMonthNames[t.Month])
|
bp = addString(buf, bp, shortMonthNames[t.Month])
|
||||||
case 'd': // %d day of month (01-31)
|
case 'd': // %d day of month (01-31)
|
||||||
decimal(buf[bp:bp+2], t.Day);
|
decimal(buf[bp:bp+2], t.Day)
|
||||||
bp += 2;
|
bp += 2
|
||||||
case 'e': // %e day of month ( 1-31)
|
case 'e': // %e day of month ( 1-31)
|
||||||
if t.Day >= 10 {
|
if t.Day >= 10 {
|
||||||
decimal(buf[bp:bp+2], t.Day)
|
decimal(buf[bp:bp+2], t.Day)
|
||||||
} else {
|
} else {
|
||||||
buf[bp] = ' ';
|
buf[bp] = ' '
|
||||||
buf[bp+1] = byte(t.Day + '0');
|
buf[bp+1] = byte(t.Day + '0')
|
||||||
}
|
}
|
||||||
bp += 2;
|
bp += 2
|
||||||
case 'H': // %H hour 00-23
|
case 'H': // %H hour 00-23
|
||||||
decimal(buf[bp:bp+2], t.Hour);
|
decimal(buf[bp:bp+2], t.Hour)
|
||||||
bp += 2;
|
bp += 2
|
||||||
case 'M': // %M minute 00-59
|
case 'M': // %M minute 00-59
|
||||||
decimal(buf[bp:bp+2], t.Minute);
|
decimal(buf[bp:bp+2], t.Minute)
|
||||||
bp += 2;
|
bp += 2
|
||||||
case 'S': // %S second 00-59
|
case 'S': // %S second 00-59
|
||||||
decimal(buf[bp:bp+2], t.Second);
|
decimal(buf[bp:bp+2], t.Second)
|
||||||
bp += 2;
|
bp += 2
|
||||||
case 'Y': // %Y year 2008
|
case 'Y': // %Y year 2008
|
||||||
decimal(buf[bp:bp+4], int(t.Year));
|
decimal(buf[bp:bp+4], int(t.Year))
|
||||||
bp += 4;
|
bp += 4
|
||||||
case 'y': // %y year 08
|
case 'y': // %y year 08
|
||||||
decimal(buf[bp:bp+2], int(t.Year%100));
|
decimal(buf[bp:bp+2], int(t.Year%100))
|
||||||
bp += 2;
|
bp += 2
|
||||||
case 'Z':
|
case 'Z':
|
||||||
bp = addString(buf, bp, t.Zone)
|
bp = addString(buf, bp, t.Zone)
|
||||||
default:
|
default:
|
||||||
buf[bp] = '%';
|
buf[bp] = '%'
|
||||||
buf[bp+1] = fmt[i];
|
buf[bp+1] = fmt[i]
|
||||||
bp += 2;
|
bp += 2
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
buf[bp] = fmt[i];
|
buf[bp] = fmt[i]
|
||||||
bp++;
|
bp++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return string(buf[0:bp]);
|
return string(buf[0:bp])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Asctime formats the parsed time value in the style of
|
// Asctime formats the parsed time value in the style of
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@
|
||||||
package time_test
|
package time_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os";
|
"os"
|
||||||
"testing";
|
"testing"
|
||||||
"testing/quick";
|
"testing/quick"
|
||||||
. "time";
|
. "time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
@ -19,8 +19,8 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
type TimeTest struct {
|
type TimeTest struct {
|
||||||
seconds int64;
|
seconds int64
|
||||||
golden Time;
|
golden Time
|
||||||
}
|
}
|
||||||
|
|
||||||
var utctests = []TimeTest{
|
var utctests = []TimeTest{
|
||||||
|
|
@ -55,42 +55,42 @@ func same(t, u *Time) bool {
|
||||||
|
|
||||||
func TestSecondsToUTC(t *testing.T) {
|
func TestSecondsToUTC(t *testing.T) {
|
||||||
for i := 0; i < len(utctests); i++ {
|
for i := 0; i < len(utctests); i++ {
|
||||||
sec := utctests[i].seconds;
|
sec := utctests[i].seconds
|
||||||
golden := &utctests[i].golden;
|
golden := &utctests[i].golden
|
||||||
tm := SecondsToUTC(sec);
|
tm := SecondsToUTC(sec)
|
||||||
newsec := tm.Seconds();
|
newsec := tm.Seconds()
|
||||||
if newsec != sec {
|
if newsec != sec {
|
||||||
t.Errorf("SecondsToUTC(%d).Seconds() = %d", sec, newsec)
|
t.Errorf("SecondsToUTC(%d).Seconds() = %d", sec, newsec)
|
||||||
}
|
}
|
||||||
if !same(tm, golden) {
|
if !same(tm, golden) {
|
||||||
t.Errorf("SecondsToUTC(%d):", sec);
|
t.Errorf("SecondsToUTC(%d):", sec)
|
||||||
t.Errorf(" want=%+v", *golden);
|
t.Errorf(" want=%+v", *golden)
|
||||||
t.Errorf(" have=%+v", *tm);
|
t.Errorf(" have=%+v", *tm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSecondsToLocalTime(t *testing.T) {
|
func TestSecondsToLocalTime(t *testing.T) {
|
||||||
for i := 0; i < len(localtests); i++ {
|
for i := 0; i < len(localtests); i++ {
|
||||||
sec := localtests[i].seconds;
|
sec := localtests[i].seconds
|
||||||
golden := &localtests[i].golden;
|
golden := &localtests[i].golden
|
||||||
tm := SecondsToLocalTime(sec);
|
tm := SecondsToLocalTime(sec)
|
||||||
newsec := tm.Seconds();
|
newsec := tm.Seconds()
|
||||||
if newsec != sec {
|
if newsec != sec {
|
||||||
t.Errorf("SecondsToLocalTime(%d).Seconds() = %d", sec, newsec)
|
t.Errorf("SecondsToLocalTime(%d).Seconds() = %d", sec, newsec)
|
||||||
}
|
}
|
||||||
if !same(tm, golden) {
|
if !same(tm, golden) {
|
||||||
t.Errorf("SecondsToLocalTime(%d):", sec);
|
t.Errorf("SecondsToLocalTime(%d):", sec)
|
||||||
t.Errorf(" want=%+v", *golden);
|
t.Errorf(" want=%+v", *golden)
|
||||||
t.Errorf(" have=%+v", *tm);
|
t.Errorf(" have=%+v", *tm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSecondsToUTCAndBack(t *testing.T) {
|
func TestSecondsToUTCAndBack(t *testing.T) {
|
||||||
f := func(sec int64) bool { return SecondsToUTC(sec).Seconds() == sec };
|
f := func(sec int64) bool { return SecondsToUTC(sec).Seconds() == sec }
|
||||||
f32 := func(sec int32) bool { return f(int64(sec)) };
|
f32 := func(sec int32) bool { return f(int64(sec)) }
|
||||||
cfg := &quick.Config{MaxCount: 10000};
|
cfg := &quick.Config{MaxCount: 10000}
|
||||||
|
|
||||||
// Try a reasonable date first, then the huge ones.
|
// Try a reasonable date first, then the huge ones.
|
||||||
if err := quick.Check(f32, cfg); err != nil {
|
if err := quick.Check(f32, cfg); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -10,50 +10,50 @@
|
||||||
package time
|
package time
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil";
|
"io/ioutil"
|
||||||
"once";
|
"once"
|
||||||
"os";
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
headerSize = 4 + 16 + 4*7;
|
headerSize = 4 + 16 + 4*7
|
||||||
zoneDir = "/usr/share/zoneinfo/";
|
zoneDir = "/usr/share/zoneinfo/"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Simple I/O interface to binary blob of data.
|
// Simple I/O interface to binary blob of data.
|
||||||
type data struct {
|
type data struct {
|
||||||
p []byte;
|
p []byte
|
||||||
error bool;
|
error bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (d *data) read(n int) []byte {
|
func (d *data) read(n int) []byte {
|
||||||
if len(d.p) < n {
|
if len(d.p) < n {
|
||||||
d.p = nil;
|
d.p = nil
|
||||||
d.error = true;
|
d.error = true
|
||||||
return nil;
|
return nil
|
||||||
}
|
}
|
||||||
p := d.p[0:n];
|
p := d.p[0:n]
|
||||||
d.p = d.p[n:];
|
d.p = d.p[n:]
|
||||||
return p;
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *data) big4() (n uint32, ok bool) {
|
func (d *data) big4() (n uint32, ok bool) {
|
||||||
p := d.read(4);
|
p := d.read(4)
|
||||||
if len(p) < 4 {
|
if len(p) < 4 {
|
||||||
d.error = true;
|
d.error = true
|
||||||
return 0, false;
|
return 0, false
|
||||||
}
|
}
|
||||||
return uint32(p[0])<<24 | uint32(p[1])<<16 | uint32(p[2])<<8 | uint32(p[3]), true;
|
return uint32(p[0])<<24 | uint32(p[1])<<16 | uint32(p[2])<<8 | uint32(p[3]), true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *data) byte() (n byte, ok bool) {
|
func (d *data) byte() (n byte, ok bool) {
|
||||||
p := d.read(1);
|
p := d.read(1)
|
||||||
if len(p) < 1 {
|
if len(p) < 1 {
|
||||||
d.error = true;
|
d.error = true
|
||||||
return 0, false;
|
return 0, false
|
||||||
}
|
}
|
||||||
return p[0], true;
|
return p[0], true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -64,24 +64,24 @@ func byteString(p []byte) string {
|
||||||
return string(p[0:i])
|
return string(p[0:i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return string(p);
|
return string(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parsed representation
|
// Parsed representation
|
||||||
type zone struct {
|
type zone struct {
|
||||||
utcoff int;
|
utcoff int
|
||||||
isdst bool;
|
isdst bool
|
||||||
name string;
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
type zonetime struct {
|
type zonetime struct {
|
||||||
time int32; // transition time, in seconds since 1970 GMT
|
time int32 // transition time, in seconds since 1970 GMT
|
||||||
zone *zone; // the zone that goes into effect at that time
|
zone *zone // the zone that goes into effect at that time
|
||||||
isstd, isutc bool; // ignored - no idea what these mean
|
isstd, isutc bool // ignored - no idea what these mean
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
|
func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
|
||||||
d := data{bytes, false};
|
d := data{bytes, false}
|
||||||
|
|
||||||
// 4-byte magic "TZif"
|
// 4-byte magic "TZif"
|
||||||
if magic := d.read(4); string(magic) != "TZif" {
|
if magic := d.read(4); string(magic) != "TZif" {
|
||||||
|
|
@ -89,7 +89,7 @@ func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1-byte version, then 15 bytes of padding
|
// 1-byte version, then 15 bytes of padding
|
||||||
var p []byte;
|
var p []byte
|
||||||
if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
|
if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
@ -102,44 +102,44 @@ func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
|
||||||
// number of local time zones
|
// number of local time zones
|
||||||
// number of characters of time zone abbrev strings
|
// number of characters of time zone abbrev strings
|
||||||
const (
|
const (
|
||||||
NUTCLocal = iota;
|
NUTCLocal = iota
|
||||||
NStdWall;
|
NStdWall
|
||||||
NLeap;
|
NLeap
|
||||||
NTime;
|
NTime
|
||||||
NZone;
|
NZone
|
||||||
NChar;
|
NChar
|
||||||
)
|
)
|
||||||
var n [6]int;
|
var n [6]int
|
||||||
for i := 0; i < 6; i++ {
|
for i := 0; i < 6; i++ {
|
||||||
nn, ok := d.big4();
|
nn, ok := d.big4()
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
n[i] = int(nn);
|
n[i] = int(nn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transition times.
|
// Transition times.
|
||||||
txtimes := data{d.read(n[NTime] * 4), false};
|
txtimes := data{d.read(n[NTime] * 4), false}
|
||||||
|
|
||||||
// Time zone indices for transition times.
|
// Time zone indices for transition times.
|
||||||
txzones := d.read(n[NTime]);
|
txzones := d.read(n[NTime])
|
||||||
|
|
||||||
// Zone info structures
|
// Zone info structures
|
||||||
zonedata := data{d.read(n[NZone] * 6), false};
|
zonedata := data{d.read(n[NZone] * 6), false}
|
||||||
|
|
||||||
// Time zone abbreviations.
|
// Time zone abbreviations.
|
||||||
abbrev := d.read(n[NChar]);
|
abbrev := d.read(n[NChar])
|
||||||
|
|
||||||
// Leap-second time pairs
|
// Leap-second time pairs
|
||||||
d.read(n[NLeap] * 8);
|
d.read(n[NLeap] * 8)
|
||||||
|
|
||||||
// Whether tx times associated with local time types
|
// Whether tx times associated with local time types
|
||||||
// are specified as standard time or wall time.
|
// are specified as standard time or wall time.
|
||||||
isstd := d.read(n[NStdWall]);
|
isstd := d.read(n[NStdWall])
|
||||||
|
|
||||||
// Whether tx times associated with local time types
|
// Whether tx times associated with local time types
|
||||||
// are specified as UTC or local time.
|
// are specified as UTC or local time.
|
||||||
isutc := d.read(n[NUTCLocal]);
|
isutc := d.read(n[NUTCLocal])
|
||||||
|
|
||||||
if d.error { // ran out of data
|
if d.error { // ran out of data
|
||||||
return nil, false
|
return nil, false
|
||||||
|
|
@ -152,38 +152,38 @@ func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
|
||||||
// Now we can build up a useful data structure.
|
// Now we can build up a useful data structure.
|
||||||
// First the zone information.
|
// First the zone information.
|
||||||
// utcoff[4] isdst[1] nameindex[1]
|
// utcoff[4] isdst[1] nameindex[1]
|
||||||
z := make([]zone, n[NZone]);
|
z := make([]zone, n[NZone])
|
||||||
for i := 0; i < len(z); i++ {
|
for i := 0; i < len(z); i++ {
|
||||||
var ok bool;
|
var ok bool
|
||||||
var n uint32;
|
var n uint32
|
||||||
if n, ok = zonedata.big4(); !ok {
|
if n, ok = zonedata.big4(); !ok {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
z[i].utcoff = int(n);
|
z[i].utcoff = int(n)
|
||||||
var b byte;
|
var b byte
|
||||||
if b, ok = zonedata.byte(); !ok {
|
if b, ok = zonedata.byte(); !ok {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
z[i].isdst = b != 0;
|
z[i].isdst = b != 0
|
||||||
if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
|
if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
z[i].name = byteString(abbrev[b:]);
|
z[i].name = byteString(abbrev[b:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now the transition time info.
|
// Now the transition time info.
|
||||||
zt = make([]zonetime, n[NTime]);
|
zt = make([]zonetime, n[NTime])
|
||||||
for i := 0; i < len(zt); i++ {
|
for i := 0; i < len(zt); i++ {
|
||||||
var ok bool;
|
var ok bool
|
||||||
var n uint32;
|
var n uint32
|
||||||
if n, ok = txtimes.big4(); !ok {
|
if n, ok = txtimes.big4(); !ok {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
zt[i].time = int32(n);
|
zt[i].time = int32(n)
|
||||||
if int(txzones[i]) >= len(z) {
|
if int(txzones[i]) >= len(z) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
zt[i].zone = &z[txzones[i]];
|
zt[i].zone = &z[txzones[i]]
|
||||||
if i < len(isstd) {
|
if i < len(isstd) {
|
||||||
zt[i].isstd = isstd[i] != 0
|
zt[i].isstd = isstd[i] != 0
|
||||||
}
|
}
|
||||||
|
|
@ -191,15 +191,15 @@ func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
|
||||||
zt[i].isutc = isutc[i] != 0
|
zt[i].isutc = isutc[i] != 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return zt, true;
|
return zt, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func readinfofile(name string) ([]zonetime, bool) {
|
func readinfofile(name string) ([]zonetime, bool) {
|
||||||
buf, err := ioutil.ReadFile(name);
|
buf, err := ioutil.ReadFile(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
return parseinfo(buf);
|
return parseinfo(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
var zones []zonetime
|
var zones []zonetime
|
||||||
|
|
@ -210,7 +210,7 @@ func setupZone() {
|
||||||
// $TZ="" means use UTC.
|
// $TZ="" means use UTC.
|
||||||
// $TZ="foo" means use /usr/share/zoneinfo/foo.
|
// $TZ="foo" means use /usr/share/zoneinfo/foo.
|
||||||
|
|
||||||
tz, err := os.Getenverror("TZ");
|
tz, err := os.Getenverror("TZ")
|
||||||
switch {
|
switch {
|
||||||
case err == os.ENOENV:
|
case err == os.ENOENV:
|
||||||
zones, _ = readinfofile("/etc/localtime")
|
zones, _ = readinfofile("/etc/localtime")
|
||||||
|
|
@ -222,21 +222,21 @@ func setupZone() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookupTimezone(sec int64) (zone string, offset int) {
|
func lookupTimezone(sec int64) (zone string, offset int) {
|
||||||
once.Do(setupZone);
|
once.Do(setupZone)
|
||||||
if len(zones) == 0 {
|
if len(zones) == 0 {
|
||||||
return "UTC", 0
|
return "UTC", 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Binary search for entry with largest time <= sec
|
// Binary search for entry with largest time <= sec
|
||||||
tz := zones;
|
tz := zones
|
||||||
for len(tz) > 1 {
|
for len(tz) > 1 {
|
||||||
m := len(tz) / 2;
|
m := len(tz) / 2
|
||||||
if sec < int64(tz[m].time) {
|
if sec < int64(tz[m].time) {
|
||||||
tz = tz[0:m]
|
tz = tz[0:m]
|
||||||
} else {
|
} else {
|
||||||
tz = tz[m:]
|
tz = tz[m:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
z := tz[0].zone;
|
z := tz[0].zone
|
||||||
return z.name, z.utcoff;
|
return z.name, z.utcoff
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,5 +9,5 @@ func IsDigit(rune int) bool {
|
||||||
if rune < 0x100 { // quick ASCII (Latin-1, really) check
|
if rune < 0x100 { // quick ASCII (Latin-1, really) check
|
||||||
return '0' <= rune && rune <= '9'
|
return '0' <= rune && rune <= '9'
|
||||||
}
|
}
|
||||||
return Is(Digit, rune);
|
return Is(Digit, rune)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
package unicode_test
|
package unicode_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing";
|
"testing"
|
||||||
. "unicode";
|
. "unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testDigit = []int{
|
var testDigit = []int{
|
||||||
|
|
|
||||||
|
|
@ -6,17 +6,17 @@
|
||||||
package unicode
|
package unicode
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MaxRune = 0x10FFFF; // Maximum valid Unicode code point.
|
MaxRune = 0x10FFFF // Maximum valid Unicode code point.
|
||||||
ReplacementChar = 0xFFFD; // Represents invalid code points.
|
ReplacementChar = 0xFFFD // Represents invalid code points.
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
// The representation of a range of Unicode code points. The range runs from Lo to Hi
|
// The representation of a range of Unicode code points. The range runs from Lo to Hi
|
||||||
// inclusive and has the specified stride.
|
// inclusive and has the specified stride.
|
||||||
type Range struct {
|
type Range struct {
|
||||||
Lo int;
|
Lo int
|
||||||
Hi int;
|
Hi int
|
||||||
Stride int;
|
Stride int
|
||||||
}
|
}
|
||||||
|
|
||||||
// The representation of a range of Unicode code points for case conversion.
|
// The representation of a range of Unicode code points for case conversion.
|
||||||
|
|
@ -29,17 +29,17 @@ type Range struct {
|
||||||
// {UpperLower, UpperLower, UpperLower}
|
// {UpperLower, UpperLower, UpperLower}
|
||||||
// The constant UpperLower has an otherwise impossible delta value.
|
// The constant UpperLower has an otherwise impossible delta value.
|
||||||
type CaseRange struct {
|
type CaseRange struct {
|
||||||
Lo int;
|
Lo int
|
||||||
Hi int;
|
Hi int
|
||||||
Delta d;
|
Delta d
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indices into the Delta arrays inside CaseRanges for case mapping.
|
// Indices into the Delta arrays inside CaseRanges for case mapping.
|
||||||
const (
|
const (
|
||||||
UpperCase = iota;
|
UpperCase = iota
|
||||||
LowerCase;
|
LowerCase
|
||||||
TitleCase;
|
TitleCase
|
||||||
MaxCase;
|
MaxCase
|
||||||
)
|
)
|
||||||
|
|
||||||
type d [MaxCase]int32 // to make the CaseRanges text shorter
|
type d [MaxCase]int32 // to make the CaseRanges text shorter
|
||||||
|
|
@ -48,7 +48,7 @@ type d [MaxCase]int32 // to make the CaseRanges text shorter
|
||||||
// this CaseRange represents a sequence of the form (say)
|
// this CaseRange represents a sequence of the form (say)
|
||||||
// Upper Lower Upper Lower.
|
// Upper Lower Upper Lower.
|
||||||
const (
|
const (
|
||||||
UpperLower = MaxRune + 1; // (Cannot be a valid delta.)
|
UpperLower = MaxRune + 1 // (Cannot be a valid delta.)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Is tests whether rune is in the specified table of ranges.
|
// Is tests whether rune is in the specified table of ranges.
|
||||||
|
|
@ -62,17 +62,17 @@ func Is(ranges []Range, rune int) bool {
|
||||||
if rune < r.Lo {
|
if rune < r.Lo {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return (rune-r.Lo)%r.Stride == 0;
|
return (rune-r.Lo)%r.Stride == 0
|
||||||
}
|
}
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// binary search over ranges
|
// binary search over ranges
|
||||||
lo := 0;
|
lo := 0
|
||||||
hi := len(ranges);
|
hi := len(ranges)
|
||||||
for lo < hi {
|
for lo < hi {
|
||||||
m := lo + (hi-lo)/2;
|
m := lo + (hi-lo)/2
|
||||||
r := ranges[m];
|
r := ranges[m]
|
||||||
if r.Lo <= rune && rune <= r.Hi {
|
if r.Lo <= rune && rune <= r.Hi {
|
||||||
return (rune-r.Lo)%r.Stride == 0
|
return (rune-r.Lo)%r.Stride == 0
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +82,7 @@ func Is(ranges []Range, rune int) bool {
|
||||||
lo = m + 1
|
lo = m + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsUpper reports whether the rune is an upper case letter.
|
// IsUpper reports whether the rune is an upper case letter.
|
||||||
|
|
@ -90,7 +90,7 @@ func IsUpper(rune int) bool {
|
||||||
if rune < 0x80 { // quick ASCII check
|
if rune < 0x80 { // quick ASCII check
|
||||||
return 'A' <= rune && rune <= 'Z'
|
return 'A' <= rune && rune <= 'Z'
|
||||||
}
|
}
|
||||||
return Is(Upper, rune);
|
return Is(Upper, rune)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsLower reports whether the rune is a lower case letter.
|
// IsLower reports whether the rune is a lower case letter.
|
||||||
|
|
@ -98,7 +98,7 @@ func IsLower(rune int) bool {
|
||||||
if rune < 0x80 { // quick ASCII check
|
if rune < 0x80 { // quick ASCII check
|
||||||
return 'a' <= rune && rune <= 'z'
|
return 'a' <= rune && rune <= 'z'
|
||||||
}
|
}
|
||||||
return Is(Lower, rune);
|
return Is(Lower, rune)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsTitle reports whether the rune is a title case letter.
|
// IsTitle reports whether the rune is a title case letter.
|
||||||
|
|
@ -106,16 +106,16 @@ func IsTitle(rune int) bool {
|
||||||
if rune < 0x80 { // quick ASCII check
|
if rune < 0x80 { // quick ASCII check
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return Is(Title, rune);
|
return Is(Title, rune)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsLetter reports whether the rune is a letter.
|
// IsLetter reports whether the rune is a letter.
|
||||||
func IsLetter(rune int) bool {
|
func IsLetter(rune int) bool {
|
||||||
if rune < 0x80 { // quick ASCII check
|
if rune < 0x80 { // quick ASCII check
|
||||||
rune &^= 'a' - 'A';
|
rune &^= 'a' - 'A'
|
||||||
return 'A' <= rune && rune <= 'Z';
|
return 'A' <= rune && rune <= 'Z'
|
||||||
}
|
}
|
||||||
return Is(Letter, rune);
|
return Is(Letter, rune)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSpace reports whether the rune is a white space character.
|
// IsSpace reports whether the rune is a white space character.
|
||||||
|
|
@ -125,9 +125,9 @@ func IsSpace(rune int) bool {
|
||||||
case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0:
|
case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
return Is(White_Space, rune);
|
return Is(White_Space, rune)
|
||||||
}
|
}
|
||||||
|
|
||||||
// To maps the rune to the specified case: UpperCase, LowerCase, or TitleCase
|
// To maps the rune to the specified case: UpperCase, LowerCase, or TitleCase
|
||||||
|
|
@ -136,13 +136,13 @@ func To(_case int, rune int) int {
|
||||||
return ReplacementChar // as reasonable an error as any
|
return ReplacementChar // as reasonable an error as any
|
||||||
}
|
}
|
||||||
// binary search over ranges
|
// binary search over ranges
|
||||||
lo := 0;
|
lo := 0
|
||||||
hi := len(CaseRanges);
|
hi := len(CaseRanges)
|
||||||
for lo < hi {
|
for lo < hi {
|
||||||
m := lo + (hi-lo)/2;
|
m := lo + (hi-lo)/2
|
||||||
r := CaseRanges[m];
|
r := CaseRanges[m]
|
||||||
if r.Lo <= rune && rune <= r.Hi {
|
if r.Lo <= rune && rune <= r.Hi {
|
||||||
delta := int(r.Delta[_case]);
|
delta := int(r.Delta[_case])
|
||||||
if delta > MaxRune {
|
if delta > MaxRune {
|
||||||
// In an Upper-Lower sequence, which always starts with
|
// In an Upper-Lower sequence, which always starts with
|
||||||
// an UpperCase letter, the real deltas always look like:
|
// an UpperCase letter, the real deltas always look like:
|
||||||
|
|
@ -156,7 +156,7 @@ func To(_case int, rune int) int {
|
||||||
// is odd so we take the low bit from _case.
|
// is odd so we take the low bit from _case.
|
||||||
return r.Lo + ((rune-r.Lo)&^1 | _case&1)
|
return r.Lo + ((rune-r.Lo)&^1 | _case&1)
|
||||||
}
|
}
|
||||||
return rune + delta;
|
return rune + delta
|
||||||
}
|
}
|
||||||
if rune < r.Lo {
|
if rune < r.Lo {
|
||||||
hi = m
|
hi = m
|
||||||
|
|
@ -164,7 +164,7 @@ func To(_case int, rune int) int {
|
||||||
lo = m + 1
|
lo = m + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rune;
|
return rune
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToUpper maps the rune to upper case
|
// ToUpper maps the rune to upper case
|
||||||
|
|
@ -173,9 +173,9 @@ func ToUpper(rune int) int {
|
||||||
if 'a' <= rune && rune <= 'z' {
|
if 'a' <= rune && rune <= 'z' {
|
||||||
rune -= 'a' - 'A'
|
rune -= 'a' - 'A'
|
||||||
}
|
}
|
||||||
return rune;
|
return rune
|
||||||
}
|
}
|
||||||
return To(UpperCase, rune);
|
return To(UpperCase, rune)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToLower maps the rune to lower case
|
// ToLower maps the rune to lower case
|
||||||
|
|
@ -184,9 +184,9 @@ func ToLower(rune int) int {
|
||||||
if 'A' <= rune && rune <= 'Z' {
|
if 'A' <= rune && rune <= 'Z' {
|
||||||
rune += 'a' - 'A'
|
rune += 'a' - 'A'
|
||||||
}
|
}
|
||||||
return rune;
|
return rune
|
||||||
}
|
}
|
||||||
return To(LowerCase, rune);
|
return To(LowerCase, rune)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToTitle maps the rune to title case
|
// ToTitle maps the rune to title case
|
||||||
|
|
@ -195,7 +195,7 @@ func ToTitle(rune int) int {
|
||||||
if 'a' <= rune && rune <= 'z' { // title case is upper case for ASCII
|
if 'a' <= rune && rune <= 'z' { // title case is upper case for ASCII
|
||||||
rune -= 'a' - 'A'
|
rune -= 'a' - 'A'
|
||||||
}
|
}
|
||||||
return rune;
|
return rune
|
||||||
}
|
}
|
||||||
return To(TitleCase, rune);
|
return To(TitleCase, rune)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
package unicode_test
|
package unicode_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing";
|
"testing"
|
||||||
. "unicode";
|
. "unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
var upperTest = []int{
|
var upperTest = []int{
|
||||||
|
|
@ -107,7 +107,7 @@ var spaceTest = []int{
|
||||||
}
|
}
|
||||||
|
|
||||||
type caseT struct {
|
type caseT struct {
|
||||||
cas, in, out int;
|
cas, in, out int
|
||||||
}
|
}
|
||||||
|
|
||||||
var caseTest = []caseT{
|
var caseTest = []caseT{
|
||||||
|
|
@ -258,12 +258,12 @@ func caseString(c int) string {
|
||||||
case TitleCase:
|
case TitleCase:
|
||||||
return "TitleCase"
|
return "TitleCase"
|
||||||
}
|
}
|
||||||
return "ErrorCase";
|
return "ErrorCase"
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTo(t *testing.T) {
|
func TestTo(t *testing.T) {
|
||||||
for _, c := range caseTest {
|
for _, c := range caseTest {
|
||||||
r := To(c.cas, c.in);
|
r := To(c.cas, c.in)
|
||||||
if c.out != r {
|
if c.out != r {
|
||||||
t.Errorf("To(U+%04X, %s) = U+%04X want U+%04X\n", c.in, caseString(c.cas), r, c.out)
|
t.Errorf("To(U+%04X, %s) = U+%04X want U+%04X\n", c.in, caseString(c.cas), r, c.out)
|
||||||
}
|
}
|
||||||
|
|
@ -275,7 +275,7 @@ func TestToUpperCase(t *testing.T) {
|
||||||
if c.cas != UpperCase {
|
if c.cas != UpperCase {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
r := ToUpper(c.in);
|
r := ToUpper(c.in)
|
||||||
if c.out != r {
|
if c.out != r {
|
||||||
t.Errorf("ToUpper(U+%04X) = U+%04X want U+%04X\n", c.in, r, c.out)
|
t.Errorf("ToUpper(U+%04X) = U+%04X want U+%04X\n", c.in, r, c.out)
|
||||||
}
|
}
|
||||||
|
|
@ -287,7 +287,7 @@ func TestToLowerCase(t *testing.T) {
|
||||||
if c.cas != LowerCase {
|
if c.cas != LowerCase {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
r := ToLower(c.in);
|
r := ToLower(c.in)
|
||||||
if c.out != r {
|
if c.out != r {
|
||||||
t.Errorf("ToLower(U+%04X) = U+%04X want U+%04X\n", c.in, r, c.out)
|
t.Errorf("ToLower(U+%04X) = U+%04X want U+%04X\n", c.in, r, c.out)
|
||||||
}
|
}
|
||||||
|
|
@ -299,7 +299,7 @@ func TestToTitleCase(t *testing.T) {
|
||||||
if c.cas != TitleCase {
|
if c.cas != TitleCase {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
r := ToTitle(c.in);
|
r := ToTitle(c.in)
|
||||||
if c.out != r {
|
if c.out != r {
|
||||||
t.Errorf("ToTitle(U+%04X) = U+%04X want U+%04X\n", c.in, r, c.out)
|
t.Errorf("ToTitle(U+%04X) = U+%04X want U+%04X\n", c.in, r, c.out)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,26 +8,26 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio";
|
"bufio"
|
||||||
"flag";
|
"flag"
|
||||||
"fmt";
|
"fmt"
|
||||||
"http";
|
"http"
|
||||||
"log";
|
"log"
|
||||||
"os";
|
"os"
|
||||||
"sort";
|
"sort"
|
||||||
"strconv";
|
"strconv"
|
||||||
"strings";
|
"strings"
|
||||||
"regexp";
|
"regexp"
|
||||||
"unicode";
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse();
|
flag.Parse()
|
||||||
loadChars(); // always needed
|
loadChars() // always needed
|
||||||
printCategories();
|
printCategories()
|
||||||
printScriptOrProperty(false);
|
printScriptOrProperty(false)
|
||||||
printScriptOrProperty(true);
|
printScriptOrProperty(true)
|
||||||
printCases();
|
printCases()
|
||||||
}
|
}
|
||||||
|
|
||||||
var dataURL = flag.String("data", "", "full URL for UnicodeData.txt; defaults to --url/UnicodeData.txt")
|
var dataURL = flag.String("data", "", "full URL for UnicodeData.txt; defaults to --url/UnicodeData.txt")
|
||||||
|
|
@ -61,24 +61,24 @@ var category = map[string]bool{"letter": true} // Nd Lu etc. letter is a special
|
||||||
// See http://www.unicode.org/Public/5.1.0/ucd/UCD.html for full explanation
|
// See http://www.unicode.org/Public/5.1.0/ucd/UCD.html for full explanation
|
||||||
// The fields:
|
// The fields:
|
||||||
const (
|
const (
|
||||||
FCodePoint = iota;
|
FCodePoint = iota
|
||||||
FName;
|
FName
|
||||||
FGeneralCategory;
|
FGeneralCategory
|
||||||
FCanonicalCombiningClass;
|
FCanonicalCombiningClass
|
||||||
FBidiClass;
|
FBidiClass
|
||||||
FDecompositionType;
|
FDecompositionType
|
||||||
FDecompositionMapping;
|
FDecompositionMapping
|
||||||
FNumericType;
|
FNumericType
|
||||||
FNumericValue;
|
FNumericValue
|
||||||
FBidiMirrored;
|
FBidiMirrored
|
||||||
FUnicode1Name;
|
FUnicode1Name
|
||||||
FISOComment;
|
FISOComment
|
||||||
FSimpleUppercaseMapping;
|
FSimpleUppercaseMapping
|
||||||
FSimpleLowercaseMapping;
|
FSimpleLowercaseMapping
|
||||||
FSimpleTitlecaseMapping;
|
FSimpleTitlecaseMapping
|
||||||
NumField;
|
NumField
|
||||||
|
|
||||||
MaxChar = 0x10FFFF; // anything above this shouldn't exist
|
MaxChar = 0x10FFFF // anything above this shouldn't exist
|
||||||
)
|
)
|
||||||
|
|
||||||
var fieldName = []string{
|
var fieldName = []string{
|
||||||
|
|
@ -101,12 +101,12 @@ var fieldName = []string{
|
||||||
|
|
||||||
// This contains only the properties we're interested in.
|
// This contains only the properties we're interested in.
|
||||||
type Char struct {
|
type Char struct {
|
||||||
field []string; // debugging only; could be deleted if we take out char.dump()
|
field []string // debugging only; could be deleted if we take out char.dump()
|
||||||
codePoint uint32; // if zero, this index is not a valid code point.
|
codePoint uint32 // if zero, this index is not a valid code point.
|
||||||
category string;
|
category string
|
||||||
upperCase int;
|
upperCase int
|
||||||
lowerCase int;
|
lowerCase int
|
||||||
titleCase int;
|
titleCase int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scripts.txt has form:
|
// Scripts.txt has form:
|
||||||
|
|
@ -115,8 +115,8 @@ type Char struct {
|
||||||
// See http://www.unicode.org/Public/5.1.0/ucd/UCD.html for full explanation
|
// See http://www.unicode.org/Public/5.1.0/ucd/UCD.html for full explanation
|
||||||
|
|
||||||
type Script struct {
|
type Script struct {
|
||||||
lo, hi uint32; // range of code points
|
lo, hi uint32 // range of code points
|
||||||
script string;
|
script string
|
||||||
}
|
}
|
||||||
|
|
||||||
var chars = make([]Char, MaxChar+1)
|
var chars = make([]Char, MaxChar+1)
|
||||||
|
|
@ -132,40 +132,40 @@ var lastChar uint32 = 0
|
||||||
type State int
|
type State int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SNormal State = iota; // known to be zero for the type
|
SNormal State = iota // known to be zero for the type
|
||||||
SFirst;
|
SFirst
|
||||||
SLast;
|
SLast
|
||||||
SMissing;
|
SMissing
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseCategory(line string) (state State) {
|
func parseCategory(line string) (state State) {
|
||||||
field := strings.Split(line, ";", -1);
|
field := strings.Split(line, ";", -1)
|
||||||
if len(field) != NumField {
|
if len(field) != NumField {
|
||||||
die.Logf("%5s: %d fields (expected %d)\n", line, len(field), NumField)
|
die.Logf("%5s: %d fields (expected %d)\n", line, len(field), NumField)
|
||||||
}
|
}
|
||||||
point, err := strconv.Btoui64(field[FCodePoint], 16);
|
point, err := strconv.Btoui64(field[FCodePoint], 16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
die.Log("%.5s...:", err)
|
die.Log("%.5s...:", err)
|
||||||
}
|
}
|
||||||
lastChar = uint32(point);
|
lastChar = uint32(point)
|
||||||
if point == 0 {
|
if point == 0 {
|
||||||
return // not interesting and we use 0 as unset
|
return // not interesting and we use 0 as unset
|
||||||
}
|
}
|
||||||
if point > MaxChar {
|
if point > MaxChar {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
char := &chars[point];
|
char := &chars[point]
|
||||||
char.field = field;
|
char.field = field
|
||||||
if char.codePoint != 0 {
|
if char.codePoint != 0 {
|
||||||
die.Logf("point U+%04x reused\n")
|
die.Logf("point U+%04x reused\n")
|
||||||
}
|
}
|
||||||
char.codePoint = lastChar;
|
char.codePoint = lastChar
|
||||||
char.category = field[FGeneralCategory];
|
char.category = field[FGeneralCategory]
|
||||||
category[char.category] = true;
|
category[char.category] = true
|
||||||
switch char.category {
|
switch char.category {
|
||||||
case "Nd":
|
case "Nd":
|
||||||
// Decimal digit
|
// Decimal digit
|
||||||
_, err := strconv.Atoi(field[FNumericValue]);
|
_, err := strconv.Atoi(field[FNumericValue])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
die.Log("U+%04x: bad numeric field: %s", point, err)
|
die.Log("U+%04x: bad numeric field: %s", point, err)
|
||||||
}
|
}
|
||||||
|
|
@ -184,66 +184,66 @@ func parseCategory(line string) (state State) {
|
||||||
case strings.Index(field[FName], ", Last>") > 0:
|
case strings.Index(field[FName], ", Last>") > 0:
|
||||||
state = SLast
|
state = SLast
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (char *Char) dump(s string) {
|
func (char *Char) dump(s string) {
|
||||||
fmt.Print(s, " ");
|
fmt.Print(s, " ")
|
||||||
for i := 0; i < len(char.field); i++ {
|
for i := 0; i < len(char.field); i++ {
|
||||||
fmt.Printf("%s:%q ", fieldName[i], char.field[i])
|
fmt.Printf("%s:%q ", fieldName[i], char.field[i])
|
||||||
}
|
}
|
||||||
fmt.Print("\n");
|
fmt.Print("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (char *Char) letter(u, l, t string) {
|
func (char *Char) letter(u, l, t string) {
|
||||||
char.upperCase = char.letterValue(u, "U");
|
char.upperCase = char.letterValue(u, "U")
|
||||||
char.lowerCase = char.letterValue(l, "L");
|
char.lowerCase = char.letterValue(l, "L")
|
||||||
char.titleCase = char.letterValue(t, "T");
|
char.titleCase = char.letterValue(t, "T")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (char *Char) letterValue(s string, cas string) int {
|
func (char *Char) letterValue(s string, cas string) int {
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
v, err := strconv.Btoui64(s, 16);
|
v, err := strconv.Btoui64(s, 16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
char.dump(cas);
|
char.dump(cas)
|
||||||
die.Logf("U+%04x: bad letter(%s): %s", char.codePoint, s, err);
|
die.Logf("U+%04x: bad letter(%s): %s", char.codePoint, s, err)
|
||||||
}
|
}
|
||||||
return int(v);
|
return int(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func allCategories() []string {
|
func allCategories() []string {
|
||||||
a := make([]string, len(category));
|
a := make([]string, len(category))
|
||||||
i := 0;
|
i := 0
|
||||||
for k := range category {
|
for k := range category {
|
||||||
a[i] = k;
|
a[i] = k
|
||||||
i++;
|
i++
|
||||||
}
|
}
|
||||||
return a;
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
func all(scripts map[string][]Script) []string {
|
func all(scripts map[string][]Script) []string {
|
||||||
a := make([]string, len(scripts));
|
a := make([]string, len(scripts))
|
||||||
i := 0;
|
i := 0
|
||||||
for k := range scripts {
|
for k := range scripts {
|
||||||
a[i] = k;
|
a[i] = k
|
||||||
i++;
|
i++
|
||||||
}
|
}
|
||||||
return a;
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the version number from the URL
|
// Extract the version number from the URL
|
||||||
func version() string {
|
func version() string {
|
||||||
// Break on slashes and look for the first numeric field
|
// Break on slashes and look for the first numeric field
|
||||||
fields := strings.Split(*url, "/", 0);
|
fields := strings.Split(*url, "/", 0)
|
||||||
for _, f := range fields {
|
for _, f := range fields {
|
||||||
if len(f) > 0 && '0' <= f[0] && f[0] <= '9' {
|
if len(f) > 0 && '0' <= f[0] && f[0] <= '9' {
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
die.Log("unknown version");
|
die.Log("unknown version")
|
||||||
return "Unknown";
|
return "Unknown"
|
||||||
}
|
}
|
||||||
|
|
||||||
func letterOp(code int) bool {
|
func letterOp(code int) bool {
|
||||||
|
|
@ -251,29 +251,29 @@ func letterOp(code int) bool {
|
||||||
case "Lu", "Ll", "Lt", "Lm", "Lo":
|
case "Lu", "Ll", "Lt", "Lm", "Lo":
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadChars() {
|
func loadChars() {
|
||||||
if *dataURL == "" {
|
if *dataURL == "" {
|
||||||
flag.Set("data", *url+"UnicodeData.txt")
|
flag.Set("data", *url+"UnicodeData.txt")
|
||||||
}
|
}
|
||||||
resp, _, err := http.Get(*dataURL);
|
resp, _, err := http.Get(*dataURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
die.Log(err)
|
die.Log(err)
|
||||||
}
|
}
|
||||||
if resp.StatusCode != 200 {
|
if resp.StatusCode != 200 {
|
||||||
die.Log("bad GET status for UnicodeData.txt", resp.Status)
|
die.Log("bad GET status for UnicodeData.txt", resp.Status)
|
||||||
}
|
}
|
||||||
input := bufio.NewReader(resp.Body);
|
input := bufio.NewReader(resp.Body)
|
||||||
var first uint32 = 0;
|
var first uint32 = 0
|
||||||
for {
|
for {
|
||||||
line, err := input.ReadString('\n');
|
line, err := input.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == os.EOF {
|
if err == os.EOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
die.Log(err);
|
die.Log(err)
|
||||||
}
|
}
|
||||||
switch parseCategory(line[0 : len(line)-1]) {
|
switch parseCategory(line[0 : len(line)-1]) {
|
||||||
case SNormal:
|
case SNormal:
|
||||||
|
|
@ -284,19 +284,19 @@ func loadChars() {
|
||||||
if first != 0 {
|
if first != 0 {
|
||||||
die.Logf("bad state first at U+%04X", lastChar)
|
die.Logf("bad state first at U+%04X", lastChar)
|
||||||
}
|
}
|
||||||
first = lastChar;
|
first = lastChar
|
||||||
case SLast:
|
case SLast:
|
||||||
if first == 0 {
|
if first == 0 {
|
||||||
die.Logf("bad state last at U+%04X", lastChar)
|
die.Logf("bad state last at U+%04X", lastChar)
|
||||||
}
|
}
|
||||||
for i := first + 1; i <= lastChar; i++ {
|
for i := first + 1; i <= lastChar; i++ {
|
||||||
chars[i] = chars[first];
|
chars[i] = chars[first]
|
||||||
chars[i].codePoint = i;
|
chars[i].codePoint = i
|
||||||
}
|
}
|
||||||
first = 0;
|
first = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp.Body.Close();
|
resp.Body.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func printCategories() {
|
func printCategories() {
|
||||||
|
|
@ -304,13 +304,13 @@ func printCategories() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Find out which categories to dump
|
// Find out which categories to dump
|
||||||
list := strings.Split(*tablelist, ",", 0);
|
list := strings.Split(*tablelist, ",", 0)
|
||||||
if *tablelist == "all" {
|
if *tablelist == "all" {
|
||||||
list = allCategories()
|
list = allCategories()
|
||||||
}
|
}
|
||||||
if *test {
|
if *test {
|
||||||
fullCategoryTest(list);
|
fullCategoryTest(list)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
fmt.Printf(
|
fmt.Printf(
|
||||||
"// Generated by running\n"+
|
"// Generated by running\n"+
|
||||||
|
|
@ -318,22 +318,22 @@ func printCategories() {
|
||||||
"// DO NOT EDIT\n\n"+
|
"// DO NOT EDIT\n\n"+
|
||||||
"package unicode\n\n",
|
"package unicode\n\n",
|
||||||
*tablelist,
|
*tablelist,
|
||||||
*dataURL);
|
*dataURL)
|
||||||
|
|
||||||
fmt.Println("// Version is the Unicode edition from which the tables are derived.");
|
fmt.Println("// Version is the Unicode edition from which the tables are derived.")
|
||||||
fmt.Printf("const Version = %q\n\n", version());
|
fmt.Printf("const Version = %q\n\n", version())
|
||||||
|
|
||||||
if *tablelist == "all" {
|
if *tablelist == "all" {
|
||||||
fmt.Println("// Categories is the set of Unicode data tables.");
|
fmt.Println("// Categories is the set of Unicode data tables.")
|
||||||
fmt.Println("var Categories = map[string] []Range {");
|
fmt.Println("var Categories = map[string] []Range {")
|
||||||
for k, _ := range category {
|
for k, _ := range category {
|
||||||
fmt.Printf("\t%q: %s,\n", k, k)
|
fmt.Printf("\t%q: %s,\n", k, k)
|
||||||
}
|
}
|
||||||
fmt.Printf("}\n\n");
|
fmt.Printf("}\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
decl := make(sort.StringArray, len(list));
|
decl := make(sort.StringArray, len(list))
|
||||||
ndecl := 0;
|
ndecl := 0
|
||||||
for _, name := range list {
|
for _, name := range list {
|
||||||
if _, ok := category[name]; !ok {
|
if _, ok := category[name]; !ok {
|
||||||
die.Log("unknown category", name)
|
die.Log("unknown category", name)
|
||||||
|
|
@ -342,7 +342,7 @@ func printCategories() {
|
||||||
// name to store the data. This stops godoc dumping all the tables but keeps them
|
// name to store the data. This stops godoc dumping all the tables but keeps them
|
||||||
// available to clients.
|
// available to clients.
|
||||||
// Cases deserving special comments
|
// Cases deserving special comments
|
||||||
varDecl := "";
|
varDecl := ""
|
||||||
switch name {
|
switch name {
|
||||||
case "letter":
|
case "letter":
|
||||||
varDecl = "\tLetter = letter; // Letter is the set of Unicode letters.\n"
|
varDecl = "\tLetter = letter; // Letter is the set of Unicode letters.\n"
|
||||||
|
|
@ -360,24 +360,24 @@ func printCategories() {
|
||||||
"\t%s = _%s; // %s is the set of Unicode characters in category %s.\n",
|
"\t%s = _%s; // %s is the set of Unicode characters in category %s.\n",
|
||||||
name, name, name, name)
|
name, name, name, name)
|
||||||
}
|
}
|
||||||
decl[ndecl] = varDecl;
|
decl[ndecl] = varDecl
|
||||||
ndecl++;
|
ndecl++
|
||||||
if name == "letter" { // special case
|
if name == "letter" { // special case
|
||||||
dumpRange(
|
dumpRange(
|
||||||
"var letter = []Range {\n",
|
"var letter = []Range {\n",
|
||||||
letterOp);
|
letterOp)
|
||||||
continue;
|
continue
|
||||||
}
|
}
|
||||||
dumpRange(
|
dumpRange(
|
||||||
fmt.Sprintf("var _%s = []Range {\n", name),
|
fmt.Sprintf("var _%s = []Range {\n", name),
|
||||||
func(code int) bool { return chars[code].category == name });
|
func(code int) bool { return chars[code].category == name })
|
||||||
}
|
}
|
||||||
decl.Sort();
|
decl.Sort()
|
||||||
fmt.Println("var (");
|
fmt.Println("var (")
|
||||||
for _, d := range decl {
|
for _, d := range decl {
|
||||||
fmt.Print(d)
|
fmt.Print(d)
|
||||||
}
|
}
|
||||||
fmt.Println(")\n");
|
fmt.Println(")\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
type Op func(code int) bool
|
type Op func(code int) bool
|
||||||
|
|
@ -385,8 +385,8 @@ type Op func(code int) bool
|
||||||
const format = "\tRange{0x%04x, 0x%04x, %d},\n"
|
const format = "\tRange{0x%04x, 0x%04x, %d},\n"
|
||||||
|
|
||||||
func dumpRange(header string, inCategory Op) {
|
func dumpRange(header string, inCategory Op) {
|
||||||
fmt.Print(header);
|
fmt.Print(header)
|
||||||
next := 0;
|
next := 0
|
||||||
// one Range for each iteration
|
// one Range for each iteration
|
||||||
for {
|
for {
|
||||||
// look for start of range
|
// look for start of range
|
||||||
|
|
@ -399,22 +399,22 @@ func dumpRange(header string, inCategory Op) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// start of range
|
// start of range
|
||||||
lo := next;
|
lo := next
|
||||||
hi := next;
|
hi := next
|
||||||
stride := 1;
|
stride := 1
|
||||||
// accept lo
|
// accept lo
|
||||||
next++;
|
next++
|
||||||
// look for another character to set the stride
|
// look for another character to set the stride
|
||||||
for next < len(chars) && !inCategory(next) {
|
for next < len(chars) && !inCategory(next) {
|
||||||
next++
|
next++
|
||||||
}
|
}
|
||||||
if next >= len(chars) {
|
if next >= len(chars) {
|
||||||
// no more characters
|
// no more characters
|
||||||
fmt.Printf(format, lo, hi, stride);
|
fmt.Printf(format, lo, hi, stride)
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
// set stride
|
// set stride
|
||||||
stride = next - lo;
|
stride = next - lo
|
||||||
// check for length of run. next points to first jump in stride
|
// check for length of run. next points to first jump in stride
|
||||||
for i := next; i < len(chars); i++ {
|
for i := next; i < len(chars); i++ {
|
||||||
if inCategory(i) == (((i - lo) % stride) == 0) {
|
if inCategory(i) == (((i - lo) % stride) == 0) {
|
||||||
|
|
@ -427,11 +427,11 @@ func dumpRange(header string, inCategory Op) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Printf(format, lo, hi, stride);
|
fmt.Printf(format, lo, hi, stride)
|
||||||
// next range: start looking where this range ends
|
// next range: start looking where this range ends
|
||||||
next = hi + 1;
|
next = hi + 1
|
||||||
}
|
}
|
||||||
fmt.Print("}\n\n");
|
fmt.Print("}\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func fullCategoryTest(list []string) {
|
func fullCategoryTest(list []string) {
|
||||||
|
|
@ -439,7 +439,7 @@ func fullCategoryTest(list []string) {
|
||||||
if _, ok := category[name]; !ok {
|
if _, ok := category[name]; !ok {
|
||||||
die.Log("unknown category", name)
|
die.Log("unknown category", name)
|
||||||
}
|
}
|
||||||
r, ok := unicode.Categories[name];
|
r, ok := unicode.Categories[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
die.Log("unknown table", name)
|
die.Log("unknown table", name)
|
||||||
}
|
}
|
||||||
|
|
@ -456,8 +456,8 @@ func fullCategoryTest(list []string) {
|
||||||
|
|
||||||
func verifyRange(name string, inCategory Op, table []unicode.Range) {
|
func verifyRange(name string, inCategory Op, table []unicode.Range) {
|
||||||
for i := range chars {
|
for i := range chars {
|
||||||
web := inCategory(i);
|
web := inCategory(i)
|
||||||
pkg := unicode.Is(table, i);
|
pkg := unicode.Is(table, i)
|
||||||
if web != pkg {
|
if web != pkg {
|
||||||
fmt.Fprintf(os.Stderr, "%s: U+%04X: web=%t pkg=%t\n", name, i, web, pkg)
|
fmt.Fprintf(os.Stderr, "%s: U+%04X: web=%t pkg=%t\n", name, i, web, pkg)
|
||||||
}
|
}
|
||||||
|
|
@ -465,61 +465,61 @@ func verifyRange(name string, inCategory Op, table []unicode.Range) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseScript(line string, scripts map[string][]Script) {
|
func parseScript(line string, scripts map[string][]Script) {
|
||||||
comment := strings.Index(line, "#");
|
comment := strings.Index(line, "#")
|
||||||
if comment >= 0 {
|
if comment >= 0 {
|
||||||
line = line[0:comment]
|
line = line[0:comment]
|
||||||
}
|
}
|
||||||
line = strings.TrimSpace(line);
|
line = strings.TrimSpace(line)
|
||||||
if len(line) == 0 {
|
if len(line) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
field := strings.Split(line, ";", -1);
|
field := strings.Split(line, ";", -1)
|
||||||
if len(field) != 2 {
|
if len(field) != 2 {
|
||||||
die.Logf("%s: %d fields (expected 2)\n", line, len(field))
|
die.Logf("%s: %d fields (expected 2)\n", line, len(field))
|
||||||
}
|
}
|
||||||
matches := scriptRe.MatchStrings(line);
|
matches := scriptRe.MatchStrings(line)
|
||||||
if len(matches) != 4 {
|
if len(matches) != 4 {
|
||||||
die.Logf("%s: %d matches (expected 3)\n", line, len(matches))
|
die.Logf("%s: %d matches (expected 3)\n", line, len(matches))
|
||||||
}
|
}
|
||||||
lo, err := strconv.Btoui64(matches[1], 16);
|
lo, err := strconv.Btoui64(matches[1], 16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
die.Log("%.5s...:", err)
|
die.Log("%.5s...:", err)
|
||||||
}
|
}
|
||||||
hi := lo;
|
hi := lo
|
||||||
if len(matches[2]) > 2 { // ignore leading ..
|
if len(matches[2]) > 2 { // ignore leading ..
|
||||||
hi, err = strconv.Btoui64(matches[2][2:], 16);
|
hi, err = strconv.Btoui64(matches[2][2:], 16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
die.Log("%.5s...:", err)
|
die.Log("%.5s...:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
name := matches[3];
|
name := matches[3]
|
||||||
s, ok := scripts[name];
|
s, ok := scripts[name]
|
||||||
if !ok || len(s) == cap(s) {
|
if !ok || len(s) == cap(s) {
|
||||||
ns := make([]Script, len(s), len(s)+100);
|
ns := make([]Script, len(s), len(s)+100)
|
||||||
for i, sc := range s {
|
for i, sc := range s {
|
||||||
ns[i] = sc
|
ns[i] = sc
|
||||||
}
|
}
|
||||||
s = ns;
|
s = ns
|
||||||
}
|
}
|
||||||
s = s[0 : len(s)+1];
|
s = s[0 : len(s)+1]
|
||||||
s[len(s)-1] = Script{uint32(lo), uint32(hi), name};
|
s[len(s)-1] = Script{uint32(lo), uint32(hi), name}
|
||||||
scripts[name] = s;
|
scripts[name] = s
|
||||||
}
|
}
|
||||||
|
|
||||||
// The script tables have a lot of adjacent elements. Fold them together.
|
// The script tables have a lot of adjacent elements. Fold them together.
|
||||||
func foldAdjacent(r []Script) []unicode.Range {
|
func foldAdjacent(r []Script) []unicode.Range {
|
||||||
s := make([]unicode.Range, 0, len(r));
|
s := make([]unicode.Range, 0, len(r))
|
||||||
j := 0;
|
j := 0
|
||||||
for i := 0; i < len(r); i++ {
|
for i := 0; i < len(r); i++ {
|
||||||
if j > 0 && int(r[i].lo) == s[j-1].Hi+1 {
|
if j > 0 && int(r[i].lo) == s[j-1].Hi+1 {
|
||||||
s[j-1].Hi = int(r[i].hi)
|
s[j-1].Hi = int(r[i].hi)
|
||||||
} else {
|
} else {
|
||||||
s = s[0 : j+1];
|
s = s[0 : j+1]
|
||||||
s[j] = unicode.Range{int(r[i].lo), int(r[i].hi), 1};
|
s[j] = unicode.Range{int(r[i].lo), int(r[i].hi), 1}
|
||||||
j++;
|
j++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s;
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func fullScriptTest(list []string, installed map[string][]unicode.Range, scripts map[string][]Script) {
|
func fullScriptTest(list []string, installed map[string][]unicode.Range, scripts map[string][]Script) {
|
||||||
|
|
@ -527,7 +527,7 @@ func fullScriptTest(list []string, installed map[string][]unicode.Range, scripts
|
||||||
if _, ok := scripts[name]; !ok {
|
if _, ok := scripts[name]; !ok {
|
||||||
die.Log("unknown script", name)
|
die.Log("unknown script", name)
|
||||||
}
|
}
|
||||||
_, ok := installed[name];
|
_, ok := installed[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
die.Log("unknown table", name)
|
die.Log("unknown table", name)
|
||||||
}
|
}
|
||||||
|
|
@ -543,50 +543,50 @@ func fullScriptTest(list []string, installed map[string][]unicode.Range, scripts
|
||||||
|
|
||||||
// PropList.txt has the same format as Scripts.txt so we can share its parser.
|
// PropList.txt has the same format as Scripts.txt so we can share its parser.
|
||||||
func printScriptOrProperty(doProps bool) {
|
func printScriptOrProperty(doProps bool) {
|
||||||
flag := "scripts";
|
flag := "scripts"
|
||||||
flaglist := *scriptlist;
|
flaglist := *scriptlist
|
||||||
file := "Scripts.txt";
|
file := "Scripts.txt"
|
||||||
table := scripts;
|
table := scripts
|
||||||
installed := unicode.Scripts;
|
installed := unicode.Scripts
|
||||||
if doProps {
|
if doProps {
|
||||||
flag = "props";
|
flag = "props"
|
||||||
flaglist = *proplist;
|
flaglist = *proplist
|
||||||
file = "PropList.txt";
|
file = "PropList.txt"
|
||||||
table = props;
|
table = props
|
||||||
installed = unicode.Properties;
|
installed = unicode.Properties
|
||||||
}
|
}
|
||||||
if flaglist == "" {
|
if flaglist == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var err os.Error;
|
var err os.Error
|
||||||
resp, _, err := http.Get(*url + file);
|
resp, _, err := http.Get(*url + file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
die.Log(err)
|
die.Log(err)
|
||||||
}
|
}
|
||||||
if resp.StatusCode != 200 {
|
if resp.StatusCode != 200 {
|
||||||
die.Log("bad GET status for ", file, ":", resp.Status)
|
die.Log("bad GET status for ", file, ":", resp.Status)
|
||||||
}
|
}
|
||||||
input := bufio.NewReader(resp.Body);
|
input := bufio.NewReader(resp.Body)
|
||||||
for {
|
for {
|
||||||
line, err := input.ReadString('\n');
|
line, err := input.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == os.EOF {
|
if err == os.EOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
die.Log(err);
|
die.Log(err)
|
||||||
}
|
}
|
||||||
parseScript(line[0:len(line)-1], table);
|
parseScript(line[0:len(line)-1], table)
|
||||||
}
|
}
|
||||||
resp.Body.Close();
|
resp.Body.Close()
|
||||||
|
|
||||||
// Find out which scripts to dump
|
// Find out which scripts to dump
|
||||||
list := strings.Split(flaglist, ",", 0);
|
list := strings.Split(flaglist, ",", 0)
|
||||||
if flaglist == "all" {
|
if flaglist == "all" {
|
||||||
list = all(table)
|
list = all(table)
|
||||||
}
|
}
|
||||||
if *test {
|
if *test {
|
||||||
fullScriptTest(list, installed, table);
|
fullScriptTest(list, installed, table)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf(
|
fmt.Printf(
|
||||||
|
|
@ -595,23 +595,23 @@ func printScriptOrProperty(doProps bool) {
|
||||||
"// DO NOT EDIT\n\n",
|
"// DO NOT EDIT\n\n",
|
||||||
flag,
|
flag,
|
||||||
flaglist,
|
flaglist,
|
||||||
*url);
|
*url)
|
||||||
if flaglist == "all" {
|
if flaglist == "all" {
|
||||||
if doProps {
|
if doProps {
|
||||||
fmt.Println("// Properties is the set of Unicode property tables.");
|
fmt.Println("// Properties is the set of Unicode property tables.")
|
||||||
fmt.Println("var Properties = map[string] []Range {");
|
fmt.Println("var Properties = map[string] []Range {")
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("// Scripts is the set of Unicode script tables.");
|
fmt.Println("// Scripts is the set of Unicode script tables.")
|
||||||
fmt.Println("var Scripts = map[string] []Range {");
|
fmt.Println("var Scripts = map[string] []Range {")
|
||||||
}
|
}
|
||||||
for k, _ := range table {
|
for k, _ := range table {
|
||||||
fmt.Printf("\t%q: %s,\n", k, k)
|
fmt.Printf("\t%q: %s,\n", k, k)
|
||||||
}
|
}
|
||||||
fmt.Printf("}\n\n");
|
fmt.Printf("}\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
decl := make(sort.StringArray, len(list));
|
decl := make(sort.StringArray, len(list))
|
||||||
ndecl := 0;
|
ndecl := 0
|
||||||
for _, name := range list {
|
for _, name := range list {
|
||||||
if doProps {
|
if doProps {
|
||||||
decl[ndecl] = fmt.Sprintf(
|
decl[ndecl] = fmt.Sprintf(
|
||||||
|
|
@ -622,36 +622,36 @@ func printScriptOrProperty(doProps bool) {
|
||||||
"\t%s = _%s;\t// %s is the set of Unicode characters in script %s.\n",
|
"\t%s = _%s;\t// %s is the set of Unicode characters in script %s.\n",
|
||||||
name, name, name, name)
|
name, name, name, name)
|
||||||
}
|
}
|
||||||
ndecl++;
|
ndecl++
|
||||||
fmt.Printf("var _%s = []Range {\n", name);
|
fmt.Printf("var _%s = []Range {\n", name)
|
||||||
ranges := foldAdjacent(table[name]);
|
ranges := foldAdjacent(table[name])
|
||||||
for _, s := range ranges {
|
for _, s := range ranges {
|
||||||
fmt.Printf(format, s.Lo, s.Hi, s.Stride)
|
fmt.Printf(format, s.Lo, s.Hi, s.Stride)
|
||||||
}
|
}
|
||||||
fmt.Printf("}\n\n");
|
fmt.Printf("}\n\n")
|
||||||
}
|
}
|
||||||
decl.Sort();
|
decl.Sort()
|
||||||
fmt.Println("var (");
|
fmt.Println("var (")
|
||||||
for _, d := range decl {
|
for _, d := range decl {
|
||||||
fmt.Print(d)
|
fmt.Print(d)
|
||||||
}
|
}
|
||||||
fmt.Println(")\n");
|
fmt.Println(")\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
CaseUpper = 1 << iota;
|
CaseUpper = 1 << iota
|
||||||
CaseLower;
|
CaseLower
|
||||||
CaseTitle;
|
CaseTitle
|
||||||
CaseNone = 0; // must be zero
|
CaseNone = 0 // must be zero
|
||||||
CaseMissing = -1; // character not present; not a valid case state
|
CaseMissing = -1 // character not present; not a valid case state
|
||||||
)
|
)
|
||||||
|
|
||||||
type caseState struct {
|
type caseState struct {
|
||||||
point int;
|
point int
|
||||||
_case int;
|
_case int
|
||||||
deltaToUpper int;
|
deltaToUpper int
|
||||||
deltaToLower int;
|
deltaToLower int
|
||||||
deltaToTitle int;
|
deltaToTitle int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is d a continuation of the state of c?
|
// Is d a continuation of the state of c?
|
||||||
|
|
@ -675,7 +675,7 @@ func (c *caseState) adjacent(d *caseState) bool {
|
||||||
case d.deltaToTitle != c.deltaToTitle:
|
case d.deltaToTitle != c.deltaToTitle:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is d the same as c, but opposite in upper/lower case? this would make it
|
// Is d the same as c, but opposite in upper/lower case? this would make it
|
||||||
|
|
@ -709,7 +709,7 @@ func (c *caseState) upperLowerAdjacent(d *caseState) bool {
|
||||||
case d.deltaToTitle != -1:
|
case d.deltaToTitle != -1:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does this character start an UpperLower sequence?
|
// Does this character start an UpperLower sequence?
|
||||||
|
|
@ -724,7 +724,7 @@ func (c *caseState) isUpperLower() bool {
|
||||||
case c.deltaToTitle != 0:
|
case c.deltaToTitle != 0:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does this character start a LowerUpper sequence?
|
// Does this character start a LowerUpper sequence?
|
||||||
|
|
@ -739,16 +739,16 @@ func (c *caseState) isLowerUpper() bool {
|
||||||
case c.deltaToTitle != -1:
|
case c.deltaToTitle != -1:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCaseState(i int) (c *caseState) {
|
func getCaseState(i int) (c *caseState) {
|
||||||
c = &caseState{point: i, _case: CaseNone};
|
c = &caseState{point: i, _case: CaseNone}
|
||||||
ch := &chars[i];
|
ch := &chars[i]
|
||||||
switch int(ch.codePoint) {
|
switch int(ch.codePoint) {
|
||||||
case 0:
|
case 0:
|
||||||
c._case = CaseMissing; // Will get NUL wrong but that doesn't matter
|
c._case = CaseMissing // Will get NUL wrong but that doesn't matter
|
||||||
return;
|
return
|
||||||
case ch.upperCase:
|
case ch.upperCase:
|
||||||
c._case = CaseUpper
|
c._case = CaseUpper
|
||||||
case ch.lowerCase:
|
case ch.lowerCase:
|
||||||
|
|
@ -765,7 +765,7 @@ func getCaseState(i int) (c *caseState) {
|
||||||
if ch.titleCase != 0 {
|
if ch.titleCase != 0 {
|
||||||
c.deltaToTitle = ch.titleCase - i
|
c.deltaToTitle = ch.titleCase - i
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func printCases() {
|
func printCases() {
|
||||||
|
|
@ -773,8 +773,8 @@ func printCases() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if *test {
|
if *test {
|
||||||
fullCaseTest();
|
fullCaseTest()
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
fmt.Printf(
|
fmt.Printf(
|
||||||
"// Generated by running\n"+
|
"// Generated by running\n"+
|
||||||
|
|
@ -784,25 +784,25 @@ func printCases() {
|
||||||
"// non-self mappings.\n"+
|
"// non-self mappings.\n"+
|
||||||
"var CaseRanges = _CaseRanges\n"+
|
"var CaseRanges = _CaseRanges\n"+
|
||||||
"var _CaseRanges = []CaseRange {\n",
|
"var _CaseRanges = []CaseRange {\n",
|
||||||
*dataURL);
|
*dataURL)
|
||||||
|
|
||||||
var startState *caseState; // the start of a run; nil for not active
|
var startState *caseState // the start of a run; nil for not active
|
||||||
var prevState = &caseState{}; // the state of the previous character
|
var prevState = &caseState{} // the state of the previous character
|
||||||
for i := range chars {
|
for i := range chars {
|
||||||
state := getCaseState(i);
|
state := getCaseState(i)
|
||||||
if state.adjacent(prevState) {
|
if state.adjacent(prevState) {
|
||||||
prevState = state;
|
prevState = state
|
||||||
continue;
|
continue
|
||||||
}
|
}
|
||||||
// end of run (possibly)
|
// end of run (possibly)
|
||||||
printCaseRange(startState, prevState);
|
printCaseRange(startState, prevState)
|
||||||
startState = nil;
|
startState = nil
|
||||||
if state._case != CaseMissing && state._case != CaseNone {
|
if state._case != CaseMissing && state._case != CaseNone {
|
||||||
startState = state
|
startState = state
|
||||||
}
|
}
|
||||||
prevState = state;
|
prevState = state
|
||||||
}
|
}
|
||||||
fmt.Printf("}\n");
|
fmt.Printf("}\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func printCaseRange(lo, hi *caseState) {
|
func printCaseRange(lo, hi *caseState) {
|
||||||
|
|
@ -818,9 +818,9 @@ func printCaseRange(lo, hi *caseState) {
|
||||||
fmt.Printf("\tCaseRange{0x%04X, 0x%04X, d{UpperLower, UpperLower, UpperLower}},\n",
|
fmt.Printf("\tCaseRange{0x%04X, 0x%04X, d{UpperLower, UpperLower, UpperLower}},\n",
|
||||||
lo.point, hi.point)
|
lo.point, hi.point)
|
||||||
case hi.point > lo.point && lo.isLowerUpper():
|
case hi.point > lo.point && lo.isLowerUpper():
|
||||||
die.Log("LowerUpper sequence: should not happen: U+%04X. If it's real, need to fix To()", lo.point);
|
die.Log("LowerUpper sequence: should not happen: U+%04X. If it's real, need to fix To()", lo.point)
|
||||||
fmt.Printf("\tCaseRange{0x%04X, 0x%04X, d{LowerUpper, LowerUpper, LowerUpper}},\n",
|
fmt.Printf("\tCaseRange{0x%04X, 0x%04X, d{LowerUpper, LowerUpper, LowerUpper}},\n",
|
||||||
lo.point, hi.point);
|
lo.point, hi.point)
|
||||||
default:
|
default:
|
||||||
fmt.Printf("\tCaseRange{0x%04X, 0x%04X, d{%d, %d, %d}},\n",
|
fmt.Printf("\tCaseRange{0x%04X, 0x%04X, d{%d, %d, %d}},\n",
|
||||||
lo.point, hi.point,
|
lo.point, hi.point,
|
||||||
|
|
@ -833,23 +833,23 @@ func caseIt(rune, cased int) int {
|
||||||
if cased == 0 {
|
if cased == 0 {
|
||||||
return rune
|
return rune
|
||||||
}
|
}
|
||||||
return cased;
|
return cased
|
||||||
}
|
}
|
||||||
|
|
||||||
func fullCaseTest() {
|
func fullCaseTest() {
|
||||||
for i, c := range chars {
|
for i, c := range chars {
|
||||||
lower := unicode.ToLower(i);
|
lower := unicode.ToLower(i)
|
||||||
want := caseIt(i, c.lowerCase);
|
want := caseIt(i, c.lowerCase)
|
||||||
if lower != want {
|
if lower != want {
|
||||||
fmt.Fprintf(os.Stderr, "lower U+%04X should be U+%04X is U+%04X\n", i, want, lower)
|
fmt.Fprintf(os.Stderr, "lower U+%04X should be U+%04X is U+%04X\n", i, want, lower)
|
||||||
}
|
}
|
||||||
upper := unicode.ToUpper(i);
|
upper := unicode.ToUpper(i)
|
||||||
want = caseIt(i, c.upperCase);
|
want = caseIt(i, c.upperCase)
|
||||||
if upper != want {
|
if upper != want {
|
||||||
fmt.Fprintf(os.Stderr, "upper U+%04X should be U+%04X is U+%04X\n", i, want, upper)
|
fmt.Fprintf(os.Stderr, "upper U+%04X should be U+%04X is U+%04X\n", i, want, upper)
|
||||||
}
|
}
|
||||||
title := unicode.ToTitle(i);
|
title := unicode.ToTitle(i)
|
||||||
want = caseIt(i, c.titleCase);
|
want = caseIt(i, c.titleCase)
|
||||||
if title != want {
|
if title != want {
|
||||||
fmt.Fprintf(os.Stderr, "title U+%04X should be U+%04X is U+%04X\n", i, want, title)
|
fmt.Fprintf(os.Stderr, "title U+%04X should be U+%04X is U+%04X\n", i, want, title)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,13 @@
|
||||||
package unicode_test
|
package unicode_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing";
|
"testing"
|
||||||
. "unicode";
|
. "unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
type T struct {
|
type T struct {
|
||||||
rune int;
|
rune int
|
||||||
script string;
|
script string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hand-chosen tests from Unicode 5.1.0, mostly to discover when new
|
// Hand-chosen tests from Unicode 5.1.0, mostly to discover when new
|
||||||
|
|
@ -185,7 +185,7 @@ var inPropTest = []T{
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestScripts(t *testing.T) {
|
func TestScripts(t *testing.T) {
|
||||||
notTested := make(map[string]bool);
|
notTested := make(map[string]bool)
|
||||||
for k := range Scripts {
|
for k := range Scripts {
|
||||||
notTested[k] = true
|
notTested[k] = true
|
||||||
}
|
}
|
||||||
|
|
@ -196,7 +196,7 @@ func TestScripts(t *testing.T) {
|
||||||
if !Is(Scripts[test.script], test.rune) {
|
if !Is(Scripts[test.script], test.rune) {
|
||||||
t.Errorf("IsScript(%#x, %s) = false, want true\n", test.rune, test.script)
|
t.Errorf("IsScript(%#x, %s) = false, want true\n", test.rune, test.script)
|
||||||
}
|
}
|
||||||
notTested[test.script] = false, false;
|
notTested[test.script] = false, false
|
||||||
}
|
}
|
||||||
for _, test := range outTest {
|
for _, test := range outTest {
|
||||||
if Is(Scripts[test.script], test.rune) {
|
if Is(Scripts[test.script], test.rune) {
|
||||||
|
|
@ -209,7 +209,7 @@ func TestScripts(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCategories(t *testing.T) {
|
func TestCategories(t *testing.T) {
|
||||||
notTested := make(map[string]bool);
|
notTested := make(map[string]bool)
|
||||||
for k := range Categories {
|
for k := range Categories {
|
||||||
notTested[k] = true
|
notTested[k] = true
|
||||||
}
|
}
|
||||||
|
|
@ -220,7 +220,7 @@ func TestCategories(t *testing.T) {
|
||||||
if !Is(Categories[test.script], test.rune) {
|
if !Is(Categories[test.script], test.rune) {
|
||||||
t.Errorf("IsCategory(%#x, %s) = false, want true\n", test.rune, test.script)
|
t.Errorf("IsCategory(%#x, %s) = false, want true\n", test.rune, test.script)
|
||||||
}
|
}
|
||||||
notTested[test.script] = false, false;
|
notTested[test.script] = false, false
|
||||||
}
|
}
|
||||||
for k := range notTested {
|
for k := range notTested {
|
||||||
t.Error("not tested:", k)
|
t.Error("not tested:", k)
|
||||||
|
|
@ -228,7 +228,7 @@ func TestCategories(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProperties(t *testing.T) {
|
func TestProperties(t *testing.T) {
|
||||||
notTested := make(map[string]bool);
|
notTested := make(map[string]bool)
|
||||||
for k := range Properties {
|
for k := range Properties {
|
||||||
notTested[k] = true
|
notTested[k] = true
|
||||||
}
|
}
|
||||||
|
|
@ -239,7 +239,7 @@ func TestProperties(t *testing.T) {
|
||||||
if !Is(Properties[test.script], test.rune) {
|
if !Is(Properties[test.script], test.rune) {
|
||||||
t.Errorf("IsCategory(%#x, %s) = false, want true\n", test.rune, test.script)
|
t.Errorf("IsCategory(%#x, %s) = false, want true\n", test.rune, test.script)
|
||||||
}
|
}
|
||||||
notTested[test.script] = false, false;
|
notTested[test.script] = false, false
|
||||||
}
|
}
|
||||||
for k := range notTested {
|
for k := range notTested {
|
||||||
t.Error("not tested:", k)
|
t.Error("not tested:", k)
|
||||||
|
|
|
||||||
|
|
@ -1921,40 +1921,40 @@ var _Lo = []Range{
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Cc = _Cc; // Cc is the set of Unicode characters in category Cc.
|
Cc = _Cc // Cc is the set of Unicode characters in category Cc.
|
||||||
Cf = _Cf; // Cf is the set of Unicode characters in category Cf.
|
Cf = _Cf // Cf is the set of Unicode characters in category Cf.
|
||||||
Co = _Co; // Co is the set of Unicode characters in category Co.
|
Co = _Co // Co is the set of Unicode characters in category Co.
|
||||||
Cs = _Cs; // Cs is the set of Unicode characters in category Cs.
|
Cs = _Cs // Cs is the set of Unicode characters in category Cs.
|
||||||
Digit = _Nd; // Digit is the set of Unicode characters with the "decimal digit" property.
|
Digit = _Nd // Digit is the set of Unicode characters with the "decimal digit" property.
|
||||||
Nd = _Nd; // Nd is the set of Unicode characters in category Nd.
|
Nd = _Nd // Nd is the set of Unicode characters in category Nd.
|
||||||
Letter = letter; // Letter is the set of Unicode letters.
|
Letter = letter // Letter is the set of Unicode letters.
|
||||||
Lm = _Lm; // Lm is the set of Unicode characters in category Lm.
|
Lm = _Lm // Lm is the set of Unicode characters in category Lm.
|
||||||
Lo = _Lo; // Lo is the set of Unicode characters in category Lo.
|
Lo = _Lo // Lo is the set of Unicode characters in category Lo.
|
||||||
Lower = _Ll; // Lower is the set of Unicode lower case letters.
|
Lower = _Ll // Lower is the set of Unicode lower case letters.
|
||||||
Ll = _Ll; // Ll is the set of Unicode characters in category Ll.
|
Ll = _Ll // Ll is the set of Unicode characters in category Ll.
|
||||||
Mc = _Mc; // Mc is the set of Unicode characters in category Mc.
|
Mc = _Mc // Mc is the set of Unicode characters in category Mc.
|
||||||
Me = _Me; // Me is the set of Unicode characters in category Me.
|
Me = _Me // Me is the set of Unicode characters in category Me.
|
||||||
Mn = _Mn; // Mn is the set of Unicode characters in category Mn.
|
Mn = _Mn // Mn is the set of Unicode characters in category Mn.
|
||||||
Nl = _Nl; // Nl is the set of Unicode characters in category Nl.
|
Nl = _Nl // Nl is the set of Unicode characters in category Nl.
|
||||||
No = _No; // No is the set of Unicode characters in category No.
|
No = _No // No is the set of Unicode characters in category No.
|
||||||
Pc = _Pc; // Pc is the set of Unicode characters in category Pc.
|
Pc = _Pc // Pc is the set of Unicode characters in category Pc.
|
||||||
Pd = _Pd; // Pd is the set of Unicode characters in category Pd.
|
Pd = _Pd // Pd is the set of Unicode characters in category Pd.
|
||||||
Pe = _Pe; // Pe is the set of Unicode characters in category Pe.
|
Pe = _Pe // Pe is the set of Unicode characters in category Pe.
|
||||||
Pf = _Pf; // Pf is the set of Unicode characters in category Pf.
|
Pf = _Pf // Pf is the set of Unicode characters in category Pf.
|
||||||
Pi = _Pi; // Pi is the set of Unicode characters in category Pi.
|
Pi = _Pi // Pi is the set of Unicode characters in category Pi.
|
||||||
Po = _Po; // Po is the set of Unicode characters in category Po.
|
Po = _Po // Po is the set of Unicode characters in category Po.
|
||||||
Ps = _Ps; // Ps is the set of Unicode characters in category Ps.
|
Ps = _Ps // Ps is the set of Unicode characters in category Ps.
|
||||||
Sc = _Sc; // Sc is the set of Unicode characters in category Sc.
|
Sc = _Sc // Sc is the set of Unicode characters in category Sc.
|
||||||
Sk = _Sk; // Sk is the set of Unicode characters in category Sk.
|
Sk = _Sk // Sk is the set of Unicode characters in category Sk.
|
||||||
Sm = _Sm; // Sm is the set of Unicode characters in category Sm.
|
Sm = _Sm // Sm is the set of Unicode characters in category Sm.
|
||||||
So = _So; // So is the set of Unicode characters in category So.
|
So = _So // So is the set of Unicode characters in category So.
|
||||||
Title = _Lt; // Title is the set of Unicode title case letters.
|
Title = _Lt // Title is the set of Unicode title case letters.
|
||||||
Lt = _Lt; // Lt is the set of Unicode characters in category Lt.
|
Lt = _Lt // Lt is the set of Unicode characters in category Lt.
|
||||||
Upper = _Lu; // Upper is the set of Unicode upper case letters.
|
Upper = _Lu // Upper is the set of Unicode upper case letters.
|
||||||
Lu = _Lu; // Lu is the set of Unicode characters in category Lu.
|
Lu = _Lu // Lu is the set of Unicode characters in category Lu.
|
||||||
Zl = _Zl; // Zl is the set of Unicode characters in category Zl.
|
Zl = _Zl // Zl is the set of Unicode characters in category Zl.
|
||||||
Zp = _Zp; // Zp is the set of Unicode characters in category Zp.
|
Zp = _Zp // Zp is the set of Unicode characters in category Zp.
|
||||||
Zs = _Zs; // Zs is the set of Unicode characters in category Zs.
|
Zs = _Zs // Zs is the set of Unicode characters in category Zs.
|
||||||
)
|
)
|
||||||
|
|
||||||
// Generated by running
|
// Generated by running
|
||||||
|
|
@ -2990,98 +2990,98 @@ var _Gothic = []Range{
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Arabic = _Arabic; // Arabic is the set of Unicode characters in script Arabic.
|
Arabic = _Arabic // Arabic is the set of Unicode characters in script Arabic.
|
||||||
Armenian = _Armenian; // Armenian is the set of Unicode characters in script Armenian.
|
Armenian = _Armenian // Armenian is the set of Unicode characters in script Armenian.
|
||||||
Avestan = _Avestan; // Avestan is the set of Unicode characters in script Avestan.
|
Avestan = _Avestan // Avestan is the set of Unicode characters in script Avestan.
|
||||||
Balinese = _Balinese; // Balinese is the set of Unicode characters in script Balinese.
|
Balinese = _Balinese // Balinese is the set of Unicode characters in script Balinese.
|
||||||
Bamum = _Bamum; // Bamum is the set of Unicode characters in script Bamum.
|
Bamum = _Bamum // Bamum is the set of Unicode characters in script Bamum.
|
||||||
Bengali = _Bengali; // Bengali is the set of Unicode characters in script Bengali.
|
Bengali = _Bengali // Bengali is the set of Unicode characters in script Bengali.
|
||||||
Bopomofo = _Bopomofo; // Bopomofo is the set of Unicode characters in script Bopomofo.
|
Bopomofo = _Bopomofo // Bopomofo is the set of Unicode characters in script Bopomofo.
|
||||||
Braille = _Braille; // Braille is the set of Unicode characters in script Braille.
|
Braille = _Braille // Braille is the set of Unicode characters in script Braille.
|
||||||
Buginese = _Buginese; // Buginese is the set of Unicode characters in script Buginese.
|
Buginese = _Buginese // Buginese is the set of Unicode characters in script Buginese.
|
||||||
Buhid = _Buhid; // Buhid is the set of Unicode characters in script Buhid.
|
Buhid = _Buhid // Buhid is the set of Unicode characters in script Buhid.
|
||||||
Canadian_Aboriginal = _Canadian_Aboriginal; // Canadian_Aboriginal is the set of Unicode characters in script Canadian_Aboriginal.
|
Canadian_Aboriginal = _Canadian_Aboriginal // Canadian_Aboriginal is the set of Unicode characters in script Canadian_Aboriginal.
|
||||||
Carian = _Carian; // Carian is the set of Unicode characters in script Carian.
|
Carian = _Carian // Carian is the set of Unicode characters in script Carian.
|
||||||
Cham = _Cham; // Cham is the set of Unicode characters in script Cham.
|
Cham = _Cham // Cham is the set of Unicode characters in script Cham.
|
||||||
Cherokee = _Cherokee; // Cherokee is the set of Unicode characters in script Cherokee.
|
Cherokee = _Cherokee // Cherokee is the set of Unicode characters in script Cherokee.
|
||||||
Common = _Common; // Common is the set of Unicode characters in script Common.
|
Common = _Common // Common is the set of Unicode characters in script Common.
|
||||||
Coptic = _Coptic; // Coptic is the set of Unicode characters in script Coptic.
|
Coptic = _Coptic // Coptic is the set of Unicode characters in script Coptic.
|
||||||
Cuneiform = _Cuneiform; // Cuneiform is the set of Unicode characters in script Cuneiform.
|
Cuneiform = _Cuneiform // Cuneiform is the set of Unicode characters in script Cuneiform.
|
||||||
Cypriot = _Cypriot; // Cypriot is the set of Unicode characters in script Cypriot.
|
Cypriot = _Cypriot // Cypriot is the set of Unicode characters in script Cypriot.
|
||||||
Cyrillic = _Cyrillic; // Cyrillic is the set of Unicode characters in script Cyrillic.
|
Cyrillic = _Cyrillic // Cyrillic is the set of Unicode characters in script Cyrillic.
|
||||||
Deseret = _Deseret; // Deseret is the set of Unicode characters in script Deseret.
|
Deseret = _Deseret // Deseret is the set of Unicode characters in script Deseret.
|
||||||
Devanagari = _Devanagari; // Devanagari is the set of Unicode characters in script Devanagari.
|
Devanagari = _Devanagari // Devanagari is the set of Unicode characters in script Devanagari.
|
||||||
Egyptian_Hieroglyphs = _Egyptian_Hieroglyphs; // Egyptian_Hieroglyphs is the set of Unicode characters in script Egyptian_Hieroglyphs.
|
Egyptian_Hieroglyphs = _Egyptian_Hieroglyphs // Egyptian_Hieroglyphs is the set of Unicode characters in script Egyptian_Hieroglyphs.
|
||||||
Ethiopic = _Ethiopic; // Ethiopic is the set of Unicode characters in script Ethiopic.
|
Ethiopic = _Ethiopic // Ethiopic is the set of Unicode characters in script Ethiopic.
|
||||||
Georgian = _Georgian; // Georgian is the set of Unicode characters in script Georgian.
|
Georgian = _Georgian // Georgian is the set of Unicode characters in script Georgian.
|
||||||
Glagolitic = _Glagolitic; // Glagolitic is the set of Unicode characters in script Glagolitic.
|
Glagolitic = _Glagolitic // Glagolitic is the set of Unicode characters in script Glagolitic.
|
||||||
Gothic = _Gothic; // Gothic is the set of Unicode characters in script Gothic.
|
Gothic = _Gothic // Gothic is the set of Unicode characters in script Gothic.
|
||||||
Greek = _Greek; // Greek is the set of Unicode characters in script Greek.
|
Greek = _Greek // Greek is the set of Unicode characters in script Greek.
|
||||||
Gujarati = _Gujarati; // Gujarati is the set of Unicode characters in script Gujarati.
|
Gujarati = _Gujarati // Gujarati is the set of Unicode characters in script Gujarati.
|
||||||
Gurmukhi = _Gurmukhi; // Gurmukhi is the set of Unicode characters in script Gurmukhi.
|
Gurmukhi = _Gurmukhi // Gurmukhi is the set of Unicode characters in script Gurmukhi.
|
||||||
Han = _Han; // Han is the set of Unicode characters in script Han.
|
Han = _Han // Han is the set of Unicode characters in script Han.
|
||||||
Hangul = _Hangul; // Hangul is the set of Unicode characters in script Hangul.
|
Hangul = _Hangul // Hangul is the set of Unicode characters in script Hangul.
|
||||||
Hanunoo = _Hanunoo; // Hanunoo is the set of Unicode characters in script Hanunoo.
|
Hanunoo = _Hanunoo // Hanunoo is the set of Unicode characters in script Hanunoo.
|
||||||
Hebrew = _Hebrew; // Hebrew is the set of Unicode characters in script Hebrew.
|
Hebrew = _Hebrew // Hebrew is the set of Unicode characters in script Hebrew.
|
||||||
Hiragana = _Hiragana; // Hiragana is the set of Unicode characters in script Hiragana.
|
Hiragana = _Hiragana // Hiragana is the set of Unicode characters in script Hiragana.
|
||||||
Imperial_Aramaic = _Imperial_Aramaic; // Imperial_Aramaic is the set of Unicode characters in script Imperial_Aramaic.
|
Imperial_Aramaic = _Imperial_Aramaic // Imperial_Aramaic is the set of Unicode characters in script Imperial_Aramaic.
|
||||||
Inherited = _Inherited; // Inherited is the set of Unicode characters in script Inherited.
|
Inherited = _Inherited // Inherited is the set of Unicode characters in script Inherited.
|
||||||
Inscriptional_Pahlavi = _Inscriptional_Pahlavi; // Inscriptional_Pahlavi is the set of Unicode characters in script Inscriptional_Pahlavi.
|
Inscriptional_Pahlavi = _Inscriptional_Pahlavi // Inscriptional_Pahlavi is the set of Unicode characters in script Inscriptional_Pahlavi.
|
||||||
Inscriptional_Parthian = _Inscriptional_Parthian; // Inscriptional_Parthian is the set of Unicode characters in script Inscriptional_Parthian.
|
Inscriptional_Parthian = _Inscriptional_Parthian // Inscriptional_Parthian is the set of Unicode characters in script Inscriptional_Parthian.
|
||||||
Javanese = _Javanese; // Javanese is the set of Unicode characters in script Javanese.
|
Javanese = _Javanese // Javanese is the set of Unicode characters in script Javanese.
|
||||||
Kaithi = _Kaithi; // Kaithi is the set of Unicode characters in script Kaithi.
|
Kaithi = _Kaithi // Kaithi is the set of Unicode characters in script Kaithi.
|
||||||
Kannada = _Kannada; // Kannada is the set of Unicode characters in script Kannada.
|
Kannada = _Kannada // Kannada is the set of Unicode characters in script Kannada.
|
||||||
Katakana = _Katakana; // Katakana is the set of Unicode characters in script Katakana.
|
Katakana = _Katakana // Katakana is the set of Unicode characters in script Katakana.
|
||||||
Kayah_Li = _Kayah_Li; // Kayah_Li is the set of Unicode characters in script Kayah_Li.
|
Kayah_Li = _Kayah_Li // Kayah_Li is the set of Unicode characters in script Kayah_Li.
|
||||||
Kharoshthi = _Kharoshthi; // Kharoshthi is the set of Unicode characters in script Kharoshthi.
|
Kharoshthi = _Kharoshthi // Kharoshthi is the set of Unicode characters in script Kharoshthi.
|
||||||
Khmer = _Khmer; // Khmer is the set of Unicode characters in script Khmer.
|
Khmer = _Khmer // Khmer is the set of Unicode characters in script Khmer.
|
||||||
Lao = _Lao; // Lao is the set of Unicode characters in script Lao.
|
Lao = _Lao // Lao is the set of Unicode characters in script Lao.
|
||||||
Latin = _Latin; // Latin is the set of Unicode characters in script Latin.
|
Latin = _Latin // Latin is the set of Unicode characters in script Latin.
|
||||||
Lepcha = _Lepcha; // Lepcha is the set of Unicode characters in script Lepcha.
|
Lepcha = _Lepcha // Lepcha is the set of Unicode characters in script Lepcha.
|
||||||
Limbu = _Limbu; // Limbu is the set of Unicode characters in script Limbu.
|
Limbu = _Limbu // Limbu is the set of Unicode characters in script Limbu.
|
||||||
Linear_B = _Linear_B; // Linear_B is the set of Unicode characters in script Linear_B.
|
Linear_B = _Linear_B // Linear_B is the set of Unicode characters in script Linear_B.
|
||||||
Lisu = _Lisu; // Lisu is the set of Unicode characters in script Lisu.
|
Lisu = _Lisu // Lisu is the set of Unicode characters in script Lisu.
|
||||||
Lycian = _Lycian; // Lycian is the set of Unicode characters in script Lycian.
|
Lycian = _Lycian // Lycian is the set of Unicode characters in script Lycian.
|
||||||
Lydian = _Lydian; // Lydian is the set of Unicode characters in script Lydian.
|
Lydian = _Lydian // Lydian is the set of Unicode characters in script Lydian.
|
||||||
Malayalam = _Malayalam; // Malayalam is the set of Unicode characters in script Malayalam.
|
Malayalam = _Malayalam // Malayalam is the set of Unicode characters in script Malayalam.
|
||||||
Meetei_Mayek = _Meetei_Mayek; // Meetei_Mayek is the set of Unicode characters in script Meetei_Mayek.
|
Meetei_Mayek = _Meetei_Mayek // Meetei_Mayek is the set of Unicode characters in script Meetei_Mayek.
|
||||||
Mongolian = _Mongolian; // Mongolian is the set of Unicode characters in script Mongolian.
|
Mongolian = _Mongolian // Mongolian is the set of Unicode characters in script Mongolian.
|
||||||
Myanmar = _Myanmar; // Myanmar is the set of Unicode characters in script Myanmar.
|
Myanmar = _Myanmar // Myanmar is the set of Unicode characters in script Myanmar.
|
||||||
New_Tai_Lue = _New_Tai_Lue; // New_Tai_Lue is the set of Unicode characters in script New_Tai_Lue.
|
New_Tai_Lue = _New_Tai_Lue // New_Tai_Lue is the set of Unicode characters in script New_Tai_Lue.
|
||||||
Nko = _Nko; // Nko is the set of Unicode characters in script Nko.
|
Nko = _Nko // Nko is the set of Unicode characters in script Nko.
|
||||||
Ogham = _Ogham; // Ogham is the set of Unicode characters in script Ogham.
|
Ogham = _Ogham // Ogham is the set of Unicode characters in script Ogham.
|
||||||
Ol_Chiki = _Ol_Chiki; // Ol_Chiki is the set of Unicode characters in script Ol_Chiki.
|
Ol_Chiki = _Ol_Chiki // Ol_Chiki is the set of Unicode characters in script Ol_Chiki.
|
||||||
Old_Italic = _Old_Italic; // Old_Italic is the set of Unicode characters in script Old_Italic.
|
Old_Italic = _Old_Italic // Old_Italic is the set of Unicode characters in script Old_Italic.
|
||||||
Old_Persian = _Old_Persian; // Old_Persian is the set of Unicode characters in script Old_Persian.
|
Old_Persian = _Old_Persian // Old_Persian is the set of Unicode characters in script Old_Persian.
|
||||||
Old_South_Arabian = _Old_South_Arabian; // Old_South_Arabian is the set of Unicode characters in script Old_South_Arabian.
|
Old_South_Arabian = _Old_South_Arabian // Old_South_Arabian is the set of Unicode characters in script Old_South_Arabian.
|
||||||
Old_Turkic = _Old_Turkic; // Old_Turkic is the set of Unicode characters in script Old_Turkic.
|
Old_Turkic = _Old_Turkic // Old_Turkic is the set of Unicode characters in script Old_Turkic.
|
||||||
Oriya = _Oriya; // Oriya is the set of Unicode characters in script Oriya.
|
Oriya = _Oriya // Oriya is the set of Unicode characters in script Oriya.
|
||||||
Osmanya = _Osmanya; // Osmanya is the set of Unicode characters in script Osmanya.
|
Osmanya = _Osmanya // Osmanya is the set of Unicode characters in script Osmanya.
|
||||||
Phags_Pa = _Phags_Pa; // Phags_Pa is the set of Unicode characters in script Phags_Pa.
|
Phags_Pa = _Phags_Pa // Phags_Pa is the set of Unicode characters in script Phags_Pa.
|
||||||
Phoenician = _Phoenician; // Phoenician is the set of Unicode characters in script Phoenician.
|
Phoenician = _Phoenician // Phoenician is the set of Unicode characters in script Phoenician.
|
||||||
Rejang = _Rejang; // Rejang is the set of Unicode characters in script Rejang.
|
Rejang = _Rejang // Rejang is the set of Unicode characters in script Rejang.
|
||||||
Runic = _Runic; // Runic is the set of Unicode characters in script Runic.
|
Runic = _Runic // Runic is the set of Unicode characters in script Runic.
|
||||||
Samaritan = _Samaritan; // Samaritan is the set of Unicode characters in script Samaritan.
|
Samaritan = _Samaritan // Samaritan is the set of Unicode characters in script Samaritan.
|
||||||
Saurashtra = _Saurashtra; // Saurashtra is the set of Unicode characters in script Saurashtra.
|
Saurashtra = _Saurashtra // Saurashtra is the set of Unicode characters in script Saurashtra.
|
||||||
Shavian = _Shavian; // Shavian is the set of Unicode characters in script Shavian.
|
Shavian = _Shavian // Shavian is the set of Unicode characters in script Shavian.
|
||||||
Sinhala = _Sinhala; // Sinhala is the set of Unicode characters in script Sinhala.
|
Sinhala = _Sinhala // Sinhala is the set of Unicode characters in script Sinhala.
|
||||||
Sundanese = _Sundanese; // Sundanese is the set of Unicode characters in script Sundanese.
|
Sundanese = _Sundanese // Sundanese is the set of Unicode characters in script Sundanese.
|
||||||
Syloti_Nagri = _Syloti_Nagri; // Syloti_Nagri is the set of Unicode characters in script Syloti_Nagri.
|
Syloti_Nagri = _Syloti_Nagri // Syloti_Nagri is the set of Unicode characters in script Syloti_Nagri.
|
||||||
Syriac = _Syriac; // Syriac is the set of Unicode characters in script Syriac.
|
Syriac = _Syriac // Syriac is the set of Unicode characters in script Syriac.
|
||||||
Tagalog = _Tagalog; // Tagalog is the set of Unicode characters in script Tagalog.
|
Tagalog = _Tagalog // Tagalog is the set of Unicode characters in script Tagalog.
|
||||||
Tagbanwa = _Tagbanwa; // Tagbanwa is the set of Unicode characters in script Tagbanwa.
|
Tagbanwa = _Tagbanwa // Tagbanwa is the set of Unicode characters in script Tagbanwa.
|
||||||
Tai_Le = _Tai_Le; // Tai_Le is the set of Unicode characters in script Tai_Le.
|
Tai_Le = _Tai_Le // Tai_Le is the set of Unicode characters in script Tai_Le.
|
||||||
Tai_Tham = _Tai_Tham; // Tai_Tham is the set of Unicode characters in script Tai_Tham.
|
Tai_Tham = _Tai_Tham // Tai_Tham is the set of Unicode characters in script Tai_Tham.
|
||||||
Tai_Viet = _Tai_Viet; // Tai_Viet is the set of Unicode characters in script Tai_Viet.
|
Tai_Viet = _Tai_Viet // Tai_Viet is the set of Unicode characters in script Tai_Viet.
|
||||||
Tamil = _Tamil; // Tamil is the set of Unicode characters in script Tamil.
|
Tamil = _Tamil // Tamil is the set of Unicode characters in script Tamil.
|
||||||
Telugu = _Telugu; // Telugu is the set of Unicode characters in script Telugu.
|
Telugu = _Telugu // Telugu is the set of Unicode characters in script Telugu.
|
||||||
Thaana = _Thaana; // Thaana is the set of Unicode characters in script Thaana.
|
Thaana = _Thaana // Thaana is the set of Unicode characters in script Thaana.
|
||||||
Thai = _Thai; // Thai is the set of Unicode characters in script Thai.
|
Thai = _Thai // Thai is the set of Unicode characters in script Thai.
|
||||||
Tibetan = _Tibetan; // Tibetan is the set of Unicode characters in script Tibetan.
|
Tibetan = _Tibetan // Tibetan is the set of Unicode characters in script Tibetan.
|
||||||
Tifinagh = _Tifinagh; // Tifinagh is the set of Unicode characters in script Tifinagh.
|
Tifinagh = _Tifinagh // Tifinagh is the set of Unicode characters in script Tifinagh.
|
||||||
Ugaritic = _Ugaritic; // Ugaritic is the set of Unicode characters in script Ugaritic.
|
Ugaritic = _Ugaritic // Ugaritic is the set of Unicode characters in script Ugaritic.
|
||||||
Vai = _Vai; // Vai is the set of Unicode characters in script Vai.
|
Vai = _Vai // Vai is the set of Unicode characters in script Vai.
|
||||||
Yi = _Yi; // Yi is the set of Unicode characters in script Yi.
|
Yi = _Yi // Yi is the set of Unicode characters in script Yi.
|
||||||
)
|
)
|
||||||
|
|
||||||
// Generated by running
|
// Generated by running
|
||||||
|
|
@ -3943,38 +3943,38 @@ var _White_Space = []Range{
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ASCII_Hex_Digit = _ASCII_Hex_Digit; // ASCII_Hex_Digit is the set of Unicode characters with property ASCII_Hex_Digit.
|
ASCII_Hex_Digit = _ASCII_Hex_Digit // ASCII_Hex_Digit is the set of Unicode characters with property ASCII_Hex_Digit.
|
||||||
Bidi_Control = _Bidi_Control; // Bidi_Control is the set of Unicode characters with property Bidi_Control.
|
Bidi_Control = _Bidi_Control // Bidi_Control is the set of Unicode characters with property Bidi_Control.
|
||||||
Dash = _Dash; // Dash is the set of Unicode characters with property Dash.
|
Dash = _Dash // Dash is the set of Unicode characters with property Dash.
|
||||||
Deprecated = _Deprecated; // Deprecated is the set of Unicode characters with property Deprecated.
|
Deprecated = _Deprecated // Deprecated is the set of Unicode characters with property Deprecated.
|
||||||
Diacritic = _Diacritic; // Diacritic is the set of Unicode characters with property Diacritic.
|
Diacritic = _Diacritic // Diacritic is the set of Unicode characters with property Diacritic.
|
||||||
Extender = _Extender; // Extender is the set of Unicode characters with property Extender.
|
Extender = _Extender // Extender is the set of Unicode characters with property Extender.
|
||||||
Hex_Digit = _Hex_Digit; // Hex_Digit is the set of Unicode characters with property Hex_Digit.
|
Hex_Digit = _Hex_Digit // Hex_Digit is the set of Unicode characters with property Hex_Digit.
|
||||||
Hyphen = _Hyphen; // Hyphen is the set of Unicode characters with property Hyphen.
|
Hyphen = _Hyphen // Hyphen is the set of Unicode characters with property Hyphen.
|
||||||
IDS_Binary_Operator = _IDS_Binary_Operator; // IDS_Binary_Operator is the set of Unicode characters with property IDS_Binary_Operator.
|
IDS_Binary_Operator = _IDS_Binary_Operator // IDS_Binary_Operator is the set of Unicode characters with property IDS_Binary_Operator.
|
||||||
IDS_Trinary_Operator = _IDS_Trinary_Operator; // IDS_Trinary_Operator is the set of Unicode characters with property IDS_Trinary_Operator.
|
IDS_Trinary_Operator = _IDS_Trinary_Operator // IDS_Trinary_Operator is the set of Unicode characters with property IDS_Trinary_Operator.
|
||||||
Ideographic = _Ideographic; // Ideographic is the set of Unicode characters with property Ideographic.
|
Ideographic = _Ideographic // Ideographic is the set of Unicode characters with property Ideographic.
|
||||||
Join_Control = _Join_Control; // Join_Control is the set of Unicode characters with property Join_Control.
|
Join_Control = _Join_Control // Join_Control is the set of Unicode characters with property Join_Control.
|
||||||
Logical_Order_Exception = _Logical_Order_Exception; // Logical_Order_Exception is the set of Unicode characters with property Logical_Order_Exception.
|
Logical_Order_Exception = _Logical_Order_Exception // Logical_Order_Exception is the set of Unicode characters with property Logical_Order_Exception.
|
||||||
Noncharacter_Code_Point = _Noncharacter_Code_Point; // Noncharacter_Code_Point is the set of Unicode characters with property Noncharacter_Code_Point.
|
Noncharacter_Code_Point = _Noncharacter_Code_Point // Noncharacter_Code_Point is the set of Unicode characters with property Noncharacter_Code_Point.
|
||||||
Other_Alphabetic = _Other_Alphabetic; // Other_Alphabetic is the set of Unicode characters with property Other_Alphabetic.
|
Other_Alphabetic = _Other_Alphabetic // Other_Alphabetic is the set of Unicode characters with property Other_Alphabetic.
|
||||||
Other_Default_Ignorable_Code_Point = _Other_Default_Ignorable_Code_Point; // Other_Default_Ignorable_Code_Point is the set of Unicode characters with property Other_Default_Ignorable_Code_Point.
|
Other_Default_Ignorable_Code_Point = _Other_Default_Ignorable_Code_Point // Other_Default_Ignorable_Code_Point is the set of Unicode characters with property Other_Default_Ignorable_Code_Point.
|
||||||
Other_Grapheme_Extend = _Other_Grapheme_Extend; // Other_Grapheme_Extend is the set of Unicode characters with property Other_Grapheme_Extend.
|
Other_Grapheme_Extend = _Other_Grapheme_Extend // Other_Grapheme_Extend is the set of Unicode characters with property Other_Grapheme_Extend.
|
||||||
Other_ID_Continue = _Other_ID_Continue; // Other_ID_Continue is the set of Unicode characters with property Other_ID_Continue.
|
Other_ID_Continue = _Other_ID_Continue // Other_ID_Continue is the set of Unicode characters with property Other_ID_Continue.
|
||||||
Other_ID_Start = _Other_ID_Start; // Other_ID_Start is the set of Unicode characters with property Other_ID_Start.
|
Other_ID_Start = _Other_ID_Start // Other_ID_Start is the set of Unicode characters with property Other_ID_Start.
|
||||||
Other_Lowercase = _Other_Lowercase; // Other_Lowercase is the set of Unicode characters with property Other_Lowercase.
|
Other_Lowercase = _Other_Lowercase // Other_Lowercase is the set of Unicode characters with property Other_Lowercase.
|
||||||
Other_Math = _Other_Math; // Other_Math is the set of Unicode characters with property Other_Math.
|
Other_Math = _Other_Math // Other_Math is the set of Unicode characters with property Other_Math.
|
||||||
Other_Uppercase = _Other_Uppercase; // Other_Uppercase is the set of Unicode characters with property Other_Uppercase.
|
Other_Uppercase = _Other_Uppercase // Other_Uppercase is the set of Unicode characters with property Other_Uppercase.
|
||||||
Pattern_Syntax = _Pattern_Syntax; // Pattern_Syntax is the set of Unicode characters with property Pattern_Syntax.
|
Pattern_Syntax = _Pattern_Syntax // Pattern_Syntax is the set of Unicode characters with property Pattern_Syntax.
|
||||||
Pattern_White_Space = _Pattern_White_Space; // Pattern_White_Space is the set of Unicode characters with property Pattern_White_Space.
|
Pattern_White_Space = _Pattern_White_Space // Pattern_White_Space is the set of Unicode characters with property Pattern_White_Space.
|
||||||
Quotation_Mark = _Quotation_Mark; // Quotation_Mark is the set of Unicode characters with property Quotation_Mark.
|
Quotation_Mark = _Quotation_Mark // Quotation_Mark is the set of Unicode characters with property Quotation_Mark.
|
||||||
Radical = _Radical; // Radical is the set of Unicode characters with property Radical.
|
Radical = _Radical // Radical is the set of Unicode characters with property Radical.
|
||||||
STerm = _STerm; // STerm is the set of Unicode characters with property STerm.
|
STerm = _STerm // STerm is the set of Unicode characters with property STerm.
|
||||||
Soft_Dotted = _Soft_Dotted; // Soft_Dotted is the set of Unicode characters with property Soft_Dotted.
|
Soft_Dotted = _Soft_Dotted // Soft_Dotted is the set of Unicode characters with property Soft_Dotted.
|
||||||
Terminal_Punctuation = _Terminal_Punctuation; // Terminal_Punctuation is the set of Unicode characters with property Terminal_Punctuation.
|
Terminal_Punctuation = _Terminal_Punctuation // Terminal_Punctuation is the set of Unicode characters with property Terminal_Punctuation.
|
||||||
Unified_Ideograph = _Unified_Ideograph; // Unified_Ideograph is the set of Unicode characters with property Unified_Ideograph.
|
Unified_Ideograph = _Unified_Ideograph // Unified_Ideograph is the set of Unicode characters with property Unified_Ideograph.
|
||||||
Variation_Selector = _Variation_Selector; // Variation_Selector is the set of Unicode characters with property Variation_Selector.
|
Variation_Selector = _Variation_Selector // Variation_Selector is the set of Unicode characters with property Variation_Selector.
|
||||||
White_Space = _White_Space; // White_Space is the set of Unicode characters with property White_Space.
|
White_Space = _White_Space // White_Space is the set of Unicode characters with property White_Space.
|
||||||
)
|
)
|
||||||
|
|
||||||
// Generated by running
|
// Generated by running
|
||||||
|
|
|
||||||
|
|
@ -10,36 +10,36 @@ import "unicode" // only needed for a couple of constants
|
||||||
|
|
||||||
// Numbers fundamental to the encoding.
|
// Numbers fundamental to the encoding.
|
||||||
const (
|
const (
|
||||||
RuneError = unicode.ReplacementChar; // the "error" Rune or "replacement character".
|
RuneError = unicode.ReplacementChar // the "error" Rune or "replacement character".
|
||||||
RuneSelf = 0x80; // characters below Runeself are represented as themselves in a single byte.
|
RuneSelf = 0x80 // characters below Runeself are represented as themselves in a single byte.
|
||||||
UTFMax = 4; // maximum number of bytes of a UTF-8 encoded Unicode character.
|
UTFMax = 4 // maximum number of bytes of a UTF-8 encoded Unicode character.
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
_T1 = 0x00; // 0000 0000
|
_T1 = 0x00 // 0000 0000
|
||||||
_Tx = 0x80; // 1000 0000
|
_Tx = 0x80 // 1000 0000
|
||||||
_T2 = 0xC0; // 1100 0000
|
_T2 = 0xC0 // 1100 0000
|
||||||
_T3 = 0xE0; // 1110 0000
|
_T3 = 0xE0 // 1110 0000
|
||||||
_T4 = 0xF0; // 1111 0000
|
_T4 = 0xF0 // 1111 0000
|
||||||
_T5 = 0xF8; // 1111 1000
|
_T5 = 0xF8 // 1111 1000
|
||||||
|
|
||||||
_Maskx = 0x3F; // 0011 1111
|
_Maskx = 0x3F // 0011 1111
|
||||||
_Mask2 = 0x1F; // 0001 1111
|
_Mask2 = 0x1F // 0001 1111
|
||||||
_Mask3 = 0x0F; // 0000 1111
|
_Mask3 = 0x0F // 0000 1111
|
||||||
_Mask4 = 0x07; // 0000 0111
|
_Mask4 = 0x07 // 0000 0111
|
||||||
|
|
||||||
_Rune1Max = 1<<7 - 1;
|
_Rune1Max = 1<<7 - 1
|
||||||
_Rune2Max = 1<<11 - 1;
|
_Rune2Max = 1<<11 - 1
|
||||||
_Rune3Max = 1<<16 - 1;
|
_Rune3Max = 1<<16 - 1
|
||||||
_Rune4Max = 1<<21 - 1;
|
_Rune4Max = 1<<21 - 1
|
||||||
)
|
)
|
||||||
|
|
||||||
func decodeRuneInternal(p []byte) (rune, size int, short bool) {
|
func decodeRuneInternal(p []byte) (rune, size int, short bool) {
|
||||||
n := len(p);
|
n := len(p)
|
||||||
if n < 1 {
|
if n < 1 {
|
||||||
return RuneError, 0, true
|
return RuneError, 0, true
|
||||||
}
|
}
|
||||||
c0 := p[0];
|
c0 := p[0]
|
||||||
|
|
||||||
// 1-byte, 7-bit sequence?
|
// 1-byte, 7-bit sequence?
|
||||||
if c0 < _Tx {
|
if c0 < _Tx {
|
||||||
|
|
@ -55,66 +55,66 @@ func decodeRuneInternal(p []byte) (rune, size int, short bool) {
|
||||||
if n < 2 {
|
if n < 2 {
|
||||||
return RuneError, 1, true
|
return RuneError, 1, true
|
||||||
}
|
}
|
||||||
c1 := p[1];
|
c1 := p[1]
|
||||||
if c1 < _Tx || _T2 <= c1 {
|
if c1 < _Tx || _T2 <= c1 {
|
||||||
return RuneError, 1, false
|
return RuneError, 1, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2-byte, 11-bit sequence?
|
// 2-byte, 11-bit sequence?
|
||||||
if c0 < _T3 {
|
if c0 < _T3 {
|
||||||
rune = int(c0&_Mask2)<<6 | int(c1&_Maskx);
|
rune = int(c0&_Mask2)<<6 | int(c1&_Maskx)
|
||||||
if rune <= _Rune1Max {
|
if rune <= _Rune1Max {
|
||||||
return RuneError, 1, false
|
return RuneError, 1, false
|
||||||
}
|
}
|
||||||
return rune, 2, false;
|
return rune, 2, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// need second continuation byte
|
// need second continuation byte
|
||||||
if n < 3 {
|
if n < 3 {
|
||||||
return RuneError, 1, true
|
return RuneError, 1, true
|
||||||
}
|
}
|
||||||
c2 := p[2];
|
c2 := p[2]
|
||||||
if c2 < _Tx || _T2 <= c2 {
|
if c2 < _Tx || _T2 <= c2 {
|
||||||
return RuneError, 1, false
|
return RuneError, 1, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3-byte, 16-bit sequence?
|
// 3-byte, 16-bit sequence?
|
||||||
if c0 < _T4 {
|
if c0 < _T4 {
|
||||||
rune = int(c0&_Mask3)<<12 | int(c1&_Maskx)<<6 | int(c2&_Maskx);
|
rune = int(c0&_Mask3)<<12 | int(c1&_Maskx)<<6 | int(c2&_Maskx)
|
||||||
if rune <= _Rune2Max {
|
if rune <= _Rune2Max {
|
||||||
return RuneError, 1, false
|
return RuneError, 1, false
|
||||||
}
|
}
|
||||||
return rune, 3, false;
|
return rune, 3, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// need third continuation byte
|
// need third continuation byte
|
||||||
if n < 4 {
|
if n < 4 {
|
||||||
return RuneError, 1, true
|
return RuneError, 1, true
|
||||||
}
|
}
|
||||||
c3 := p[3];
|
c3 := p[3]
|
||||||
if c3 < _Tx || _T2 <= c3 {
|
if c3 < _Tx || _T2 <= c3 {
|
||||||
return RuneError, 1, false
|
return RuneError, 1, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4-byte, 21-bit sequence?
|
// 4-byte, 21-bit sequence?
|
||||||
if c0 < _T5 {
|
if c0 < _T5 {
|
||||||
rune = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx);
|
rune = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
|
||||||
if rune <= _Rune3Max {
|
if rune <= _Rune3Max {
|
||||||
return RuneError, 1, false
|
return RuneError, 1, false
|
||||||
}
|
}
|
||||||
return rune, 4, false;
|
return rune, 4, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// error
|
// error
|
||||||
return RuneError, 1, false;
|
return RuneError, 1, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
|
func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
|
||||||
n := len(s);
|
n := len(s)
|
||||||
if n < 1 {
|
if n < 1 {
|
||||||
return RuneError, 0, true
|
return RuneError, 0, true
|
||||||
}
|
}
|
||||||
c0 := s[0];
|
c0 := s[0]
|
||||||
|
|
||||||
// 1-byte, 7-bit sequence?
|
// 1-byte, 7-bit sequence?
|
||||||
if c0 < _Tx {
|
if c0 < _Tx {
|
||||||
|
|
@ -130,83 +130,83 @@ func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
|
||||||
if n < 2 {
|
if n < 2 {
|
||||||
return RuneError, 1, true
|
return RuneError, 1, true
|
||||||
}
|
}
|
||||||
c1 := s[1];
|
c1 := s[1]
|
||||||
if c1 < _Tx || _T2 <= c1 {
|
if c1 < _Tx || _T2 <= c1 {
|
||||||
return RuneError, 1, false
|
return RuneError, 1, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2-byte, 11-bit sequence?
|
// 2-byte, 11-bit sequence?
|
||||||
if c0 < _T3 {
|
if c0 < _T3 {
|
||||||
rune = int(c0&_Mask2)<<6 | int(c1&_Maskx);
|
rune = int(c0&_Mask2)<<6 | int(c1&_Maskx)
|
||||||
if rune <= _Rune1Max {
|
if rune <= _Rune1Max {
|
||||||
return RuneError, 1, false
|
return RuneError, 1, false
|
||||||
}
|
}
|
||||||
return rune, 2, false;
|
return rune, 2, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// need second continuation byte
|
// need second continuation byte
|
||||||
if n < 3 {
|
if n < 3 {
|
||||||
return RuneError, 1, true
|
return RuneError, 1, true
|
||||||
}
|
}
|
||||||
c2 := s[2];
|
c2 := s[2]
|
||||||
if c2 < _Tx || _T2 <= c2 {
|
if c2 < _Tx || _T2 <= c2 {
|
||||||
return RuneError, 1, false
|
return RuneError, 1, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3-byte, 16-bit sequence?
|
// 3-byte, 16-bit sequence?
|
||||||
if c0 < _T4 {
|
if c0 < _T4 {
|
||||||
rune = int(c0&_Mask3)<<12 | int(c1&_Maskx)<<6 | int(c2&_Maskx);
|
rune = int(c0&_Mask3)<<12 | int(c1&_Maskx)<<6 | int(c2&_Maskx)
|
||||||
if rune <= _Rune2Max {
|
if rune <= _Rune2Max {
|
||||||
return RuneError, 1, false
|
return RuneError, 1, false
|
||||||
}
|
}
|
||||||
return rune, 3, false;
|
return rune, 3, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// need third continuation byte
|
// need third continuation byte
|
||||||
if n < 4 {
|
if n < 4 {
|
||||||
return RuneError, 1, true
|
return RuneError, 1, true
|
||||||
}
|
}
|
||||||
c3 := s[3];
|
c3 := s[3]
|
||||||
if c3 < _Tx || _T2 <= c3 {
|
if c3 < _Tx || _T2 <= c3 {
|
||||||
return RuneError, 1, false
|
return RuneError, 1, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4-byte, 21-bit sequence?
|
// 4-byte, 21-bit sequence?
|
||||||
if c0 < _T5 {
|
if c0 < _T5 {
|
||||||
rune = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx);
|
rune = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
|
||||||
if rune <= _Rune3Max {
|
if rune <= _Rune3Max {
|
||||||
return RuneError, 1, false
|
return RuneError, 1, false
|
||||||
}
|
}
|
||||||
return rune, 4, false;
|
return rune, 4, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// error
|
// error
|
||||||
return RuneError, 1, false;
|
return RuneError, 1, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// FullRune reports whether the bytes in p begin with a full UTF-8 encoding of a rune.
|
// FullRune reports whether the bytes in p begin with a full UTF-8 encoding of a rune.
|
||||||
// An invalid encoding is considered a full Rune since it will convert as a width-1 error rune.
|
// An invalid encoding is considered a full Rune since it will convert as a width-1 error rune.
|
||||||
func FullRune(p []byte) bool {
|
func FullRune(p []byte) bool {
|
||||||
_, _, short := decodeRuneInternal(p);
|
_, _, short := decodeRuneInternal(p)
|
||||||
return !short;
|
return !short
|
||||||
}
|
}
|
||||||
|
|
||||||
// FullRuneInString is like FullRune but its input is a string.
|
// FullRuneInString is like FullRune but its input is a string.
|
||||||
func FullRuneInString(s string) bool {
|
func FullRuneInString(s string) bool {
|
||||||
_, _, short := decodeRuneInStringInternal(s);
|
_, _, short := decodeRuneInStringInternal(s)
|
||||||
return !short;
|
return !short
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and its width in bytes.
|
// DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and its width in bytes.
|
||||||
func DecodeRune(p []byte) (rune, size int) {
|
func DecodeRune(p []byte) (rune, size int) {
|
||||||
rune, size, _ = decodeRuneInternal(p);
|
rune, size, _ = decodeRuneInternal(p)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeRuneInString is like DecodeRune but its input is a string.
|
// DecodeRuneInString is like DecodeRune but its input is a string.
|
||||||
func DecodeRuneInString(s string) (rune, size int) {
|
func DecodeRuneInString(s string) (rune, size int) {
|
||||||
rune, size, _ = decodeRuneInStringInternal(s);
|
rune, size, _ = decodeRuneInStringInternal(s)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// RuneLen returns the number of bytes required to encode the rune.
|
// RuneLen returns the number of bytes required to encode the rune.
|
||||||
|
|
@ -221,24 +221,24 @@ func RuneLen(rune int) int {
|
||||||
case rune <= _Rune4Max:
|
case rune <= _Rune4Max:
|
||||||
return 4
|
return 4
|
||||||
}
|
}
|
||||||
return -1;
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeRune writes into p (which must be large enough) the UTF-8 encoding of the rune.
|
// EncodeRune writes into p (which must be large enough) the UTF-8 encoding of the rune.
|
||||||
// It returns the number of bytes written.
|
// It returns the number of bytes written.
|
||||||
func EncodeRune(rune int, p []byte) int {
|
func EncodeRune(rune int, p []byte) int {
|
||||||
// Negative values are erroneous. Making it unsigned addresses the problem.
|
// Negative values are erroneous. Making it unsigned addresses the problem.
|
||||||
r := uint(rune);
|
r := uint(rune)
|
||||||
|
|
||||||
if r <= _Rune1Max {
|
if r <= _Rune1Max {
|
||||||
p[0] = byte(r);
|
p[0] = byte(r)
|
||||||
return 1;
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if r <= _Rune2Max {
|
if r <= _Rune2Max {
|
||||||
p[0] = _T2 | byte(r>>6);
|
p[0] = _T2 | byte(r>>6)
|
||||||
p[1] = _Tx | byte(r)&_Maskx;
|
p[1] = _Tx | byte(r)&_Maskx
|
||||||
return 2;
|
return 2
|
||||||
}
|
}
|
||||||
|
|
||||||
if r > unicode.MaxRune {
|
if r > unicode.MaxRune {
|
||||||
|
|
@ -246,33 +246,33 @@ func EncodeRune(rune int, p []byte) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
if r <= _Rune3Max {
|
if r <= _Rune3Max {
|
||||||
p[0] = _T3 | byte(r>>12);
|
p[0] = _T3 | byte(r>>12)
|
||||||
p[1] = _Tx | byte(r>>6)&_Maskx;
|
p[1] = _Tx | byte(r>>6)&_Maskx
|
||||||
p[2] = _Tx | byte(r)&_Maskx;
|
p[2] = _Tx | byte(r)&_Maskx
|
||||||
return 3;
|
return 3
|
||||||
}
|
}
|
||||||
|
|
||||||
p[0] = _T4 | byte(r>>18);
|
p[0] = _T4 | byte(r>>18)
|
||||||
p[1] = _Tx | byte(r>>12)&_Maskx;
|
p[1] = _Tx | byte(r>>12)&_Maskx
|
||||||
p[2] = _Tx | byte(r>>6)&_Maskx;
|
p[2] = _Tx | byte(r>>6)&_Maskx
|
||||||
p[3] = _Tx | byte(r)&_Maskx;
|
p[3] = _Tx | byte(r)&_Maskx
|
||||||
return 4;
|
return 4
|
||||||
}
|
}
|
||||||
|
|
||||||
// RuneCount returns the number of runes in p. Erroneous and short
|
// RuneCount returns the number of runes in p. Erroneous and short
|
||||||
// encodings are treated as single runes of width 1 byte.
|
// encodings are treated as single runes of width 1 byte.
|
||||||
func RuneCount(p []byte) int {
|
func RuneCount(p []byte) int {
|
||||||
i := 0;
|
i := 0
|
||||||
var n int;
|
var n int
|
||||||
for n = 0; i < len(p); n++ {
|
for n = 0; i < len(p); n++ {
|
||||||
if p[i] < RuneSelf {
|
if p[i] < RuneSelf {
|
||||||
i++
|
i++
|
||||||
} else {
|
} else {
|
||||||
_, size := DecodeRune(p[i:]);
|
_, size := DecodeRune(p[i:])
|
||||||
i += size;
|
i += size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n;
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// RuneCountInString is like RuneCount but its input is a string.
|
// RuneCountInString is like RuneCount but its input is a string.
|
||||||
|
|
@ -280,7 +280,7 @@ func RuneCountInString(s string) (n int) {
|
||||||
for _ = range s {
|
for _ = range s {
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// RuneStart reports whether the byte could be the first byte of
|
// RuneStart reports whether the byte could be the first byte of
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,15 @@
|
||||||
package utf8_test
|
package utf8_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes";
|
"bytes"
|
||||||
"strings";
|
"strings"
|
||||||
"testing";
|
"testing"
|
||||||
. "utf8";
|
. "utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Utf8Map struct {
|
type Utf8Map struct {
|
||||||
rune int;
|
rune int
|
||||||
str string;
|
str string
|
||||||
}
|
}
|
||||||
|
|
||||||
var utf8map = []Utf8Map{
|
var utf8map = []Utf8Map{
|
||||||
|
|
@ -47,27 +47,27 @@ var utf8map = []Utf8Map{
|
||||||
|
|
||||||
// strings.Bytes with one extra byte at end
|
// strings.Bytes with one extra byte at end
|
||||||
func makeBytes(s string) []byte {
|
func makeBytes(s string) []byte {
|
||||||
s += "\x00";
|
s += "\x00"
|
||||||
b := strings.Bytes(s);
|
b := strings.Bytes(s)
|
||||||
return b[0 : len(s)-1];
|
return b[0 : len(s)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFullRune(t *testing.T) {
|
func TestFullRune(t *testing.T) {
|
||||||
for i := 0; i < len(utf8map); i++ {
|
for i := 0; i < len(utf8map); i++ {
|
||||||
m := utf8map[i];
|
m := utf8map[i]
|
||||||
b := makeBytes(m.str);
|
b := makeBytes(m.str)
|
||||||
if !FullRune(b) {
|
if !FullRune(b) {
|
||||||
t.Errorf("FullRune(%q) (rune %04x) = false, want true", b, m.rune)
|
t.Errorf("FullRune(%q) (rune %04x) = false, want true", b, m.rune)
|
||||||
}
|
}
|
||||||
s := m.str;
|
s := m.str
|
||||||
if !FullRuneInString(s) {
|
if !FullRuneInString(s) {
|
||||||
t.Errorf("FullRuneInString(%q) (rune %04x) = false, want true", s, m.rune)
|
t.Errorf("FullRuneInString(%q) (rune %04x) = false, want true", s, m.rune)
|
||||||
}
|
}
|
||||||
b1 := b[0 : len(b)-1];
|
b1 := b[0 : len(b)-1]
|
||||||
if FullRune(b1) {
|
if FullRune(b1) {
|
||||||
t.Errorf("FullRune(%q) = true, want false", b1)
|
t.Errorf("FullRune(%q) = true, want false", b1)
|
||||||
}
|
}
|
||||||
s1 := string(b1);
|
s1 := string(b1)
|
||||||
if FullRuneInString(s1) {
|
if FullRuneInString(s1) {
|
||||||
t.Errorf("FullRune(%q) = true, want false", s1)
|
t.Errorf("FullRune(%q) = true, want false", s1)
|
||||||
}
|
}
|
||||||
|
|
@ -76,11 +76,11 @@ func TestFullRune(t *testing.T) {
|
||||||
|
|
||||||
func TestEncodeRune(t *testing.T) {
|
func TestEncodeRune(t *testing.T) {
|
||||||
for i := 0; i < len(utf8map); i++ {
|
for i := 0; i < len(utf8map); i++ {
|
||||||
m := utf8map[i];
|
m := utf8map[i]
|
||||||
b := makeBytes(m.str);
|
b := makeBytes(m.str)
|
||||||
var buf [10]byte;
|
var buf [10]byte
|
||||||
n := EncodeRune(m.rune, &buf);
|
n := EncodeRune(m.rune, &buf)
|
||||||
b1 := buf[0:n];
|
b1 := buf[0:n]
|
||||||
if !bytes.Equal(b, b1) {
|
if !bytes.Equal(b, b1) {
|
||||||
t.Errorf("EncodeRune(%#04x) = %q want %q", m.rune, b1, b)
|
t.Errorf("EncodeRune(%#04x) = %q want %q", m.rune, b1, b)
|
||||||
}
|
}
|
||||||
|
|
@ -89,40 +89,40 @@ func TestEncodeRune(t *testing.T) {
|
||||||
|
|
||||||
func TestDecodeRune(t *testing.T) {
|
func TestDecodeRune(t *testing.T) {
|
||||||
for i := 0; i < len(utf8map); i++ {
|
for i := 0; i < len(utf8map); i++ {
|
||||||
m := utf8map[i];
|
m := utf8map[i]
|
||||||
b := makeBytes(m.str);
|
b := makeBytes(m.str)
|
||||||
rune, size := DecodeRune(b);
|
rune, size := DecodeRune(b)
|
||||||
if rune != m.rune || size != len(b) {
|
if rune != m.rune || size != len(b) {
|
||||||
t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, m.rune, len(b))
|
t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, m.rune, len(b))
|
||||||
}
|
}
|
||||||
s := m.str;
|
s := m.str
|
||||||
rune, size = DecodeRuneInString(s);
|
rune, size = DecodeRuneInString(s)
|
||||||
if rune != m.rune || size != len(b) {
|
if rune != m.rune || size != len(b) {
|
||||||
t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", s, rune, size, m.rune, len(b))
|
t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", s, rune, size, m.rune, len(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
// there's an extra byte that bytes left behind - make sure trailing byte works
|
// there's an extra byte that bytes left behind - make sure trailing byte works
|
||||||
rune, size = DecodeRune(b[0:cap(b)]);
|
rune, size = DecodeRune(b[0:cap(b)])
|
||||||
if rune != m.rune || size != len(b) {
|
if rune != m.rune || size != len(b) {
|
||||||
t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, m.rune, len(b))
|
t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, m.rune, len(b))
|
||||||
}
|
}
|
||||||
s = m.str + "\x00";
|
s = m.str + "\x00"
|
||||||
rune, size = DecodeRuneInString(s);
|
rune, size = DecodeRuneInString(s)
|
||||||
if rune != m.rune || size != len(b) {
|
if rune != m.rune || size != len(b) {
|
||||||
t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, m.rune, len(b))
|
t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, m.rune, len(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure missing bytes fail
|
// make sure missing bytes fail
|
||||||
wantsize := 1;
|
wantsize := 1
|
||||||
if wantsize >= len(b) {
|
if wantsize >= len(b) {
|
||||||
wantsize = 0
|
wantsize = 0
|
||||||
}
|
}
|
||||||
rune, size = DecodeRune(b[0 : len(b)-1]);
|
rune, size = DecodeRune(b[0 : len(b)-1])
|
||||||
if rune != RuneError || size != wantsize {
|
if rune != RuneError || size != wantsize {
|
||||||
t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b[0:len(b)-1], rune, size, RuneError, wantsize)
|
t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b[0:len(b)-1], rune, size, RuneError, wantsize)
|
||||||
}
|
}
|
||||||
s = m.str[0 : len(m.str)-1];
|
s = m.str[0 : len(m.str)-1]
|
||||||
rune, size = DecodeRuneInString(s);
|
rune, size = DecodeRuneInString(s)
|
||||||
if rune != RuneError || size != wantsize {
|
if rune != RuneError || size != wantsize {
|
||||||
t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, RuneError, wantsize)
|
t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, RuneError, wantsize)
|
||||||
}
|
}
|
||||||
|
|
@ -133,12 +133,12 @@ func TestDecodeRune(t *testing.T) {
|
||||||
} else {
|
} else {
|
||||||
b[len(b)-1] = 0x7F
|
b[len(b)-1] = 0x7F
|
||||||
}
|
}
|
||||||
rune, size = DecodeRune(b);
|
rune, size = DecodeRune(b)
|
||||||
if rune != RuneError || size != 1 {
|
if rune != RuneError || size != 1 {
|
||||||
t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, RuneError, 1)
|
t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, RuneError, 1)
|
||||||
}
|
}
|
||||||
s = string(b);
|
s = string(b)
|
||||||
rune, size = DecodeRune(b);
|
rune, size = DecodeRune(b)
|
||||||
if rune != RuneError || size != 1 {
|
if rune != RuneError || size != 1 {
|
||||||
t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, RuneError, 1)
|
t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, RuneError, 1)
|
||||||
}
|
}
|
||||||
|
|
@ -147,18 +147,18 @@ func TestDecodeRune(t *testing.T) {
|
||||||
|
|
||||||
// Check that negative runes encode as U+FFFD.
|
// Check that negative runes encode as U+FFFD.
|
||||||
func TestNegativeRune(t *testing.T) {
|
func TestNegativeRune(t *testing.T) {
|
||||||
errorbuf := make([]byte, UTFMax);
|
errorbuf := make([]byte, UTFMax)
|
||||||
errorbuf = errorbuf[0:EncodeRune(RuneError, errorbuf)];
|
errorbuf = errorbuf[0:EncodeRune(RuneError, errorbuf)]
|
||||||
buf := make([]byte, UTFMax);
|
buf := make([]byte, UTFMax)
|
||||||
buf = buf[0:EncodeRune(-1, buf)];
|
buf = buf[0:EncodeRune(-1, buf)]
|
||||||
if !bytes.Equal(buf, errorbuf) {
|
if !bytes.Equal(buf, errorbuf) {
|
||||||
t.Errorf("incorrect encoding [% x] for -1; expected [% x]", buf, errorbuf)
|
t.Errorf("incorrect encoding [% x] for -1; expected [% x]", buf, errorbuf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type RuneCountTest struct {
|
type RuneCountTest struct {
|
||||||
in string;
|
in string
|
||||||
out int;
|
out int
|
||||||
}
|
}
|
||||||
|
|
||||||
var runecounttests = []RuneCountTest{
|
var runecounttests = []RuneCountTest{
|
||||||
|
|
@ -170,7 +170,7 @@ var runecounttests = []RuneCountTest{
|
||||||
|
|
||||||
func TestRuneCount(t *testing.T) {
|
func TestRuneCount(t *testing.T) {
|
||||||
for i := 0; i < len(runecounttests); i++ {
|
for i := 0; i < len(runecounttests); i++ {
|
||||||
tt := runecounttests[i];
|
tt := runecounttests[i]
|
||||||
if out := RuneCountInString(tt.in); out != tt.out {
|
if out := RuneCountInString(tt.in); out != tt.out {
|
||||||
t.Errorf("RuneCountInString(%q) = %d, want %d", tt.in, out, tt.out)
|
t.Errorf("RuneCountInString(%q) = %d, want %d", tt.in, out, tt.out)
|
||||||
}
|
}
|
||||||
|
|
@ -193,28 +193,28 @@ func BenchmarkRuneCountTenJapaneseChars(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkEncodeASCIIRune(b *testing.B) {
|
func BenchmarkEncodeASCIIRune(b *testing.B) {
|
||||||
buf := make([]byte, UTFMax);
|
buf := make([]byte, UTFMax)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
EncodeRune('a', buf)
|
EncodeRune('a', buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkEncodeJapaneseRune(b *testing.B) {
|
func BenchmarkEncodeJapaneseRune(b *testing.B) {
|
||||||
buf := make([]byte, UTFMax);
|
buf := make([]byte, UTFMax)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
EncodeRune('本', buf)
|
EncodeRune('本', buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkDecodeASCIIRune(b *testing.B) {
|
func BenchmarkDecodeASCIIRune(b *testing.B) {
|
||||||
a := []byte{'a'};
|
a := []byte{'a'}
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
DecodeRune(a)
|
DecodeRune(a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkDecodeJapaneseRune(b *testing.B) {
|
func BenchmarkDecodeJapaneseRune(b *testing.B) {
|
||||||
nihon := strings.Bytes("本");
|
nihon := strings.Bytes("本")
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
DecodeRune(nihon)
|
DecodeRune(nihon)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,40 +5,40 @@
|
||||||
package websocket
|
package websocket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio";
|
"bufio"
|
||||||
"http";
|
"http"
|
||||||
"io";
|
"io"
|
||||||
"net";
|
"net"
|
||||||
"os";
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProtocolError struct {
|
type ProtocolError struct {
|
||||||
os.ErrorString;
|
os.ErrorString
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrBadStatus = &ProtocolError{"bad status"};
|
ErrBadStatus = &ProtocolError{"bad status"}
|
||||||
ErrNoUpgrade = &ProtocolError{"no upgrade"};
|
ErrNoUpgrade = &ProtocolError{"no upgrade"}
|
||||||
ErrBadUpgrade = &ProtocolError{"bad upgrade"};
|
ErrBadUpgrade = &ProtocolError{"bad upgrade"}
|
||||||
ErrNoWebSocketOrigin = &ProtocolError{"no WebSocket-Origin"};
|
ErrNoWebSocketOrigin = &ProtocolError{"no WebSocket-Origin"}
|
||||||
ErrBadWebSocketOrigin = &ProtocolError{"bad WebSocket-Origin"};
|
ErrBadWebSocketOrigin = &ProtocolError{"bad WebSocket-Origin"}
|
||||||
ErrNoWebSocketLocation = &ProtocolError{"no WebSocket-Location"};
|
ErrNoWebSocketLocation = &ProtocolError{"no WebSocket-Location"}
|
||||||
ErrBadWebSocketLocation = &ProtocolError{"bad WebSocket-Location"};
|
ErrBadWebSocketLocation = &ProtocolError{"bad WebSocket-Location"}
|
||||||
ErrNoWebSocketProtocol = &ProtocolError{"no WebSocket-Protocol"};
|
ErrNoWebSocketProtocol = &ProtocolError{"no WebSocket-Protocol"}
|
||||||
ErrBadWebSocketProtocol = &ProtocolError{"bad WebSocket-Protocol"};
|
ErrBadWebSocketProtocol = &ProtocolError{"bad WebSocket-Protocol"}
|
||||||
)
|
)
|
||||||
|
|
||||||
// newClient creates a new Web Socket client connection.
|
// newClient creates a new Web Socket client connection.
|
||||||
func newClient(resourceName, host, origin, location, protocol string, rwc io.ReadWriteCloser) (ws *Conn, err os.Error) {
|
func newClient(resourceName, host, origin, location, protocol string, rwc io.ReadWriteCloser) (ws *Conn, err os.Error) {
|
||||||
br := bufio.NewReader(rwc);
|
br := bufio.NewReader(rwc)
|
||||||
bw := bufio.NewWriter(rwc);
|
bw := bufio.NewWriter(rwc)
|
||||||
err = handshake(resourceName, host, origin, location, protocol, br, bw);
|
err = handshake(resourceName, host, origin, location, protocol, br, bw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
buf := bufio.NewReadWriter(br, bw);
|
buf := bufio.NewReadWriter(br, bw)
|
||||||
ws = newConn(origin, location, protocol, buf, rwc);
|
ws = newConn(origin, location, protocol, buf, rwc)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dial opens new Web Socket client connection.
|
// Dial opens new Web Socket client connection.
|
||||||
|
|
@ -68,55 +68,55 @@ func newClient(resourceName, host, origin, location, protocol string, rwc io.Rea
|
||||||
// }
|
// }
|
||||||
|
|
||||||
func Dial(url, protocol, origin string) (ws *Conn, err os.Error) {
|
func Dial(url, protocol, origin string) (ws *Conn, err os.Error) {
|
||||||
parsedUrl, err := http.ParseURL(url);
|
parsedUrl, err := http.ParseURL(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
client, err := net.Dial("tcp", "", parsedUrl.Host);
|
client, err := net.Dial("tcp", "", parsedUrl.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return newClient(parsedUrl.Path, parsedUrl.Host, origin, url, protocol, client);
|
return newClient(parsedUrl.Path, parsedUrl.Host, origin, url, protocol, client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handshake(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) (err os.Error) {
|
func handshake(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) (err os.Error) {
|
||||||
bw.WriteString("GET " + resourceName + " HTTP/1.1\r\n");
|
bw.WriteString("GET " + resourceName + " HTTP/1.1\r\n")
|
||||||
bw.WriteString("Upgrade: WebSocket\r\n");
|
bw.WriteString("Upgrade: WebSocket\r\n")
|
||||||
bw.WriteString("Connection: Upgrade\r\n");
|
bw.WriteString("Connection: Upgrade\r\n")
|
||||||
bw.WriteString("Host: " + host + "\r\n");
|
bw.WriteString("Host: " + host + "\r\n")
|
||||||
bw.WriteString("Origin: " + origin + "\r\n");
|
bw.WriteString("Origin: " + origin + "\r\n")
|
||||||
if protocol != "" {
|
if protocol != "" {
|
||||||
bw.WriteString("WebSocket-Protocol: " + protocol + "\r\n")
|
bw.WriteString("WebSocket-Protocol: " + protocol + "\r\n")
|
||||||
}
|
}
|
||||||
bw.WriteString("\r\n");
|
bw.WriteString("\r\n")
|
||||||
bw.Flush();
|
bw.Flush()
|
||||||
resp, err := http.ReadResponse(br);
|
resp, err := http.ReadResponse(br)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if resp.Status != "101 Web Socket Protocol Handshake" {
|
if resp.Status != "101 Web Socket Protocol Handshake" {
|
||||||
return ErrBadStatus
|
return ErrBadStatus
|
||||||
}
|
}
|
||||||
upgrade, found := resp.Header["Upgrade"];
|
upgrade, found := resp.Header["Upgrade"]
|
||||||
if !found {
|
if !found {
|
||||||
return ErrNoUpgrade
|
return ErrNoUpgrade
|
||||||
}
|
}
|
||||||
if upgrade != "WebSocket" {
|
if upgrade != "WebSocket" {
|
||||||
return ErrBadUpgrade
|
return ErrBadUpgrade
|
||||||
}
|
}
|
||||||
connection, found := resp.Header["Connection"];
|
connection, found := resp.Header["Connection"]
|
||||||
if !found || connection != "Upgrade" {
|
if !found || connection != "Upgrade" {
|
||||||
return ErrBadUpgrade
|
return ErrBadUpgrade
|
||||||
}
|
}
|
||||||
|
|
||||||
ws_origin, found := resp.Header["Websocket-Origin"];
|
ws_origin, found := resp.Header["Websocket-Origin"]
|
||||||
if !found {
|
if !found {
|
||||||
return ErrNoWebSocketOrigin
|
return ErrNoWebSocketOrigin
|
||||||
}
|
}
|
||||||
if ws_origin != origin {
|
if ws_origin != origin {
|
||||||
return ErrBadWebSocketOrigin
|
return ErrBadWebSocketOrigin
|
||||||
}
|
}
|
||||||
ws_location, found := resp.Header["Websocket-Location"];
|
ws_location, found := resp.Header["Websocket-Location"]
|
||||||
if !found {
|
if !found {
|
||||||
return ErrNoWebSocketLocation
|
return ErrNoWebSocketLocation
|
||||||
}
|
}
|
||||||
|
|
@ -124,7 +124,7 @@ func handshake(resourceName, host, origin, location, protocol string, br *bufio.
|
||||||
return ErrBadWebSocketLocation
|
return ErrBadWebSocketLocation
|
||||||
}
|
}
|
||||||
if protocol != "" {
|
if protocol != "" {
|
||||||
ws_protocol, found := resp.Header["Websocket-Protocol"];
|
ws_protocol, found := resp.Header["Websocket-Protocol"]
|
||||||
if !found {
|
if !found {
|
||||||
return ErrNoWebSocketProtocol
|
return ErrNoWebSocketProtocol
|
||||||
}
|
}
|
||||||
|
|
@ -132,5 +132,5 @@ func handshake(resourceName, host, origin, location, protocol string, br *bufio.
|
||||||
return ErrBadWebSocketProtocol
|
return ErrBadWebSocketProtocol
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
package websocket
|
package websocket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"http";
|
"http"
|
||||||
"io";
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Handler is a interface that use a WebSocket.
|
// Handler is a interface that use a WebSocket.
|
||||||
|
|
@ -39,35 +39,35 @@ func (f Handler) ServeHTTP(c *http.Conn, req *http.Request) {
|
||||||
if req.Method != "GET" || req.Proto != "HTTP/1.1" ||
|
if req.Method != "GET" || req.Proto != "HTTP/1.1" ||
|
||||||
req.Header["Upgrade"] != "WebSocket" ||
|
req.Header["Upgrade"] != "WebSocket" ||
|
||||||
req.Header["Connection"] != "Upgrade" {
|
req.Header["Connection"] != "Upgrade" {
|
||||||
c.WriteHeader(http.StatusNotFound);
|
c.WriteHeader(http.StatusNotFound)
|
||||||
io.WriteString(c, "must use websocket to connect here");
|
io.WriteString(c, "must use websocket to connect here")
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
rwc, buf, err := c.Hijack();
|
rwc, buf, err := c.Hijack()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("Hijack failed: ", err.String());
|
panic("Hijack failed: ", err.String())
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
defer rwc.Close();
|
defer rwc.Close()
|
||||||
origin := req.Header["Origin"];
|
origin := req.Header["Origin"]
|
||||||
location := "ws://" + req.Host + req.URL.Path;
|
location := "ws://" + req.Host + req.URL.Path
|
||||||
|
|
||||||
// TODO(ukai): verify origin,location,protocol.
|
// TODO(ukai): verify origin,location,protocol.
|
||||||
|
|
||||||
buf.WriteString("HTTP/1.1 101 Web Socket Protocol Handshake\r\n");
|
buf.WriteString("HTTP/1.1 101 Web Socket Protocol Handshake\r\n")
|
||||||
buf.WriteString("Upgrade: WebSocket\r\n");
|
buf.WriteString("Upgrade: WebSocket\r\n")
|
||||||
buf.WriteString("Connection: Upgrade\r\n");
|
buf.WriteString("Connection: Upgrade\r\n")
|
||||||
buf.WriteString("WebSocket-Origin: " + origin + "\r\n");
|
buf.WriteString("WebSocket-Origin: " + origin + "\r\n")
|
||||||
buf.WriteString("WebSocket-Location: " + location + "\r\n");
|
buf.WriteString("WebSocket-Location: " + location + "\r\n")
|
||||||
protocol := "";
|
protocol := ""
|
||||||
// canonical header key of WebSocket-Protocol.
|
// canonical header key of WebSocket-Protocol.
|
||||||
if protocol, found := req.Header["Websocket-Protocol"]; found {
|
if protocol, found := req.Header["Websocket-Protocol"]; found {
|
||||||
buf.WriteString("WebSocket-Protocol: " + protocol + "\r\n")
|
buf.WriteString("WebSocket-Protocol: " + protocol + "\r\n")
|
||||||
}
|
}
|
||||||
buf.WriteString("\r\n");
|
buf.WriteString("\r\n")
|
||||||
if err := buf.Flush(); err != nil {
|
if err := buf.Flush(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ws := newConn(origin, location, protocol, buf, rwc);
|
ws := newConn(origin, location, protocol, buf, rwc)
|
||||||
f(ws);
|
f(ws)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,10 @@ package websocket
|
||||||
// better logging.
|
// better logging.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio";
|
"bufio"
|
||||||
"io";
|
"io"
|
||||||
"net";
|
"net"
|
||||||
"os";
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebSocketAddr string
|
type WebSocketAddr string
|
||||||
|
|
@ -27,37 +27,37 @@ func (addr WebSocketAddr) String() string { return string(addr) }
|
||||||
// Conn is an channels to communicate over Web Socket.
|
// Conn is an channels to communicate over Web Socket.
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
// An origin URI of the Web Socket.
|
// An origin URI of the Web Socket.
|
||||||
Origin string;
|
Origin string
|
||||||
// A location URI of the Web Socket.
|
// A location URI of the Web Socket.
|
||||||
Location string;
|
Location string
|
||||||
// A subprotocol of the Web Socket.
|
// A subprotocol of the Web Socket.
|
||||||
Protocol string;
|
Protocol string
|
||||||
|
|
||||||
buf *bufio.ReadWriter;
|
buf *bufio.ReadWriter
|
||||||
rwc io.ReadWriteCloser;
|
rwc io.ReadWriteCloser
|
||||||
}
|
}
|
||||||
|
|
||||||
// newConn creates a new Web Socket.
|
// newConn creates a new Web Socket.
|
||||||
func newConn(origin, location, protocol string, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn {
|
func newConn(origin, location, protocol string, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn {
|
||||||
if buf == nil {
|
if buf == nil {
|
||||||
br := bufio.NewReader(rwc);
|
br := bufio.NewReader(rwc)
|
||||||
bw := bufio.NewWriter(rwc);
|
bw := bufio.NewWriter(rwc)
|
||||||
buf = bufio.NewReadWriter(br, bw);
|
buf = bufio.NewReadWriter(br, bw)
|
||||||
}
|
}
|
||||||
ws := &Conn{origin, location, protocol, buf, rwc};
|
ws := &Conn{origin, location, protocol, buf, rwc}
|
||||||
return ws;
|
return ws
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ws *Conn) Read(msg []byte) (n int, err os.Error) {
|
func (ws *Conn) Read(msg []byte) (n int, err os.Error) {
|
||||||
for {
|
for {
|
||||||
frameByte, err := ws.buf.ReadByte();
|
frameByte, err := ws.buf.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
if (frameByte & 0x80) == 0x80 {
|
if (frameByte & 0x80) == 0x80 {
|
||||||
length := 0;
|
length := 0
|
||||||
for {
|
for {
|
||||||
c, err := ws.buf.ReadByte();
|
c, err := ws.buf.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
@ -68,15 +68,15 @@ func (ws *Conn) Read(msg []byte) (n int, err os.Error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for length > 0 {
|
for length > 0 {
|
||||||
_, err := ws.buf.ReadByte();
|
_, err := ws.buf.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
length--;
|
length--
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for {
|
for {
|
||||||
c, err := ws.buf.ReadByte();
|
c, err := ws.buf.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
@ -87,8 +87,8 @@ func (ws *Conn) Read(msg []byte) (n int, err os.Error) {
|
||||||
if n+1 <= cap(msg) {
|
if n+1 <= cap(msg) {
|
||||||
msg = msg[0 : n+1]
|
msg = msg[0 : n+1]
|
||||||
}
|
}
|
||||||
msg[n] = c;
|
msg[n] = c
|
||||||
n++;
|
n++
|
||||||
}
|
}
|
||||||
if n >= cap(msg) {
|
if n >= cap(msg) {
|
||||||
return n, os.E2BIG
|
return n, os.E2BIG
|
||||||
|
|
@ -97,15 +97,15 @@ func (ws *Conn) Read(msg []byte) (n int, err os.Error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("unreachable");
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ws *Conn) Write(msg []byte) (n int, err os.Error) {
|
func (ws *Conn) Write(msg []byte) (n int, err os.Error) {
|
||||||
ws.buf.WriteByte(0);
|
ws.buf.WriteByte(0)
|
||||||
ws.buf.Write(msg);
|
ws.buf.Write(msg)
|
||||||
ws.buf.WriteByte(0xff);
|
ws.buf.WriteByte(0xff)
|
||||||
err = ws.buf.Flush();
|
err = ws.buf.Flush()
|
||||||
return len(msg), err;
|
return len(msg), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ws *Conn) Close() os.Error { return ws.rwc.Close() }
|
func (ws *Conn) Close() os.Error { return ws.rwc.Close() }
|
||||||
|
|
@ -118,21 +118,21 @@ func (ws *Conn) SetTimeout(nsec int64) os.Error {
|
||||||
if conn, ok := ws.rwc.(net.Conn); ok {
|
if conn, ok := ws.rwc.(net.Conn); ok {
|
||||||
return conn.SetTimeout(nsec)
|
return conn.SetTimeout(nsec)
|
||||||
}
|
}
|
||||||
return os.EINVAL;
|
return os.EINVAL
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ws *Conn) SetReadTimeout(nsec int64) os.Error {
|
func (ws *Conn) SetReadTimeout(nsec int64) os.Error {
|
||||||
if conn, ok := ws.rwc.(net.Conn); ok {
|
if conn, ok := ws.rwc.(net.Conn); ok {
|
||||||
return conn.SetReadTimeout(nsec)
|
return conn.SetReadTimeout(nsec)
|
||||||
}
|
}
|
||||||
return os.EINVAL;
|
return os.EINVAL
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ws *Conn) SetWriteTimeout(nsec int64) os.Error {
|
func (ws *Conn) SetWriteTimeout(nsec int64) os.Error {
|
||||||
if conn, ok := ws.rwc.(net.Conn); ok {
|
if conn, ok := ws.rwc.(net.Conn); ok {
|
||||||
return conn.SetWriteTimeout(nsec)
|
return conn.SetWriteTimeout(nsec)
|
||||||
}
|
}
|
||||||
return os.EINVAL;
|
return os.EINVAL
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ net.Conn = (*Conn)(nil) // compile-time check that *Conn implements net.Conn.
|
var _ net.Conn = (*Conn)(nil) // compile-time check that *Conn implements net.Conn.
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,14 @@
|
||||||
package websocket
|
package websocket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes";
|
"bytes"
|
||||||
"http";
|
"http"
|
||||||
"io";
|
"io"
|
||||||
"log";
|
"log"
|
||||||
"net";
|
"net"
|
||||||
"once";
|
"once"
|
||||||
"strings";
|
"strings"
|
||||||
"testing";
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
var serverAddr string
|
var serverAddr string
|
||||||
|
|
@ -20,42 +20,42 @@ var serverAddr string
|
||||||
func echoServer(ws *Conn) { io.Copy(ws, ws) }
|
func echoServer(ws *Conn) { io.Copy(ws, ws) }
|
||||||
|
|
||||||
func startServer() {
|
func startServer() {
|
||||||
l, e := net.Listen("tcp", ":0"); // any available address
|
l, e := net.Listen("tcp", ":0") // any available address
|
||||||
if e != nil {
|
if e != nil {
|
||||||
log.Exitf("net.Listen tcp :0 %v", e)
|
log.Exitf("net.Listen tcp :0 %v", e)
|
||||||
}
|
}
|
||||||
serverAddr = l.Addr().String();
|
serverAddr = l.Addr().String()
|
||||||
log.Stderr("Test WebSocket server listening on ", serverAddr);
|
log.Stderr("Test WebSocket server listening on ", serverAddr)
|
||||||
http.Handle("/echo", Handler(echoServer));
|
http.Handle("/echo", Handler(echoServer))
|
||||||
go http.Serve(l, nil);
|
go http.Serve(l, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEcho(t *testing.T) {
|
func TestEcho(t *testing.T) {
|
||||||
once.Do(startServer);
|
once.Do(startServer)
|
||||||
|
|
||||||
client, err := net.Dial("tcp", "", serverAddr);
|
client, err := net.Dial("tcp", "", serverAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("dialing", err)
|
t.Fatal("dialing", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ws, err := newClient("/echo", "localhost", "http://localhost",
|
ws, err := newClient("/echo", "localhost", "http://localhost",
|
||||||
"ws://localhost/echo", "", client);
|
"ws://localhost/echo", "", client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("WebSocket handshake error", err);
|
t.Errorf("WebSocket handshake error", err)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
msg := strings.Bytes("hello, world\n");
|
msg := strings.Bytes("hello, world\n")
|
||||||
if _, err := ws.Write(msg); err != nil {
|
if _, err := ws.Write(msg); err != nil {
|
||||||
t.Errorf("Write: error %v", err)
|
t.Errorf("Write: error %v", err)
|
||||||
}
|
}
|
||||||
var actual_msg = make([]byte, 512);
|
var actual_msg = make([]byte, 512)
|
||||||
n, err := ws.Read(actual_msg);
|
n, err := ws.Read(actual_msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Read: error %v", err)
|
t.Errorf("Read: error %v", err)
|
||||||
}
|
}
|
||||||
actual_msg = actual_msg[0:n];
|
actual_msg = actual_msg[0:n]
|
||||||
if !bytes.Equal(msg, actual_msg) {
|
if !bytes.Equal(msg, actual_msg) {
|
||||||
t.Errorf("Echo: expected %q got %q", msg, actual_msg)
|
t.Errorf("Echo: expected %q got %q", msg, actual_msg)
|
||||||
}
|
}
|
||||||
ws.Close();
|
ws.Close()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,63 +5,63 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt";
|
"fmt"
|
||||||
"os";
|
"os"
|
||||||
"xgb";
|
"xgb"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
c, err := xgb.Dial(os.Getenv("DISPLAY"));
|
c, err := xgb.Dial(os.Getenv("DISPLAY"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("cannot connect: %v\n", err);
|
fmt.Printf("cannot connect: %v\n", err)
|
||||||
os.Exit(1);
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("vendor = '%s'\n", string(c.Setup.Vendor));
|
fmt.Printf("vendor = '%s'\n", string(c.Setup.Vendor))
|
||||||
|
|
||||||
win := c.NewId();
|
win := c.NewId()
|
||||||
gc := c.NewId();
|
gc := c.NewId()
|
||||||
|
|
||||||
c.CreateWindow(0, win, c.DefaultScreen().Root, 150, 150, 200, 200, 0, 0, 0, 0, nil);
|
c.CreateWindow(0, win, c.DefaultScreen().Root, 150, 150, 200, 200, 0, 0, 0, 0, nil)
|
||||||
c.ChangeWindowAttributes(win, xgb.CWEventMask,
|
c.ChangeWindowAttributes(win, xgb.CWEventMask,
|
||||||
[]uint32{xgb.EventMaskExposure | xgb.EventMaskKeyRelease});
|
[]uint32{xgb.EventMaskExposure | xgb.EventMaskKeyRelease})
|
||||||
c.CreateGC(gc, win, 0, nil);
|
c.CreateGC(gc, win, 0, nil)
|
||||||
c.MapWindow(win);
|
c.MapWindow(win)
|
||||||
|
|
||||||
atom, _ := c.InternAtom(0, "HELLO");
|
atom, _ := c.InternAtom(0, "HELLO")
|
||||||
fmt.Printf("atom = %d\n", atom.Atom);
|
fmt.Printf("atom = %d\n", atom.Atom)
|
||||||
|
|
||||||
points := make([]xgb.Point, 2);
|
points := make([]xgb.Point, 2)
|
||||||
points[1] = xgb.Point{5, 5};
|
points[1] = xgb.Point{5, 5}
|
||||||
points[1] = xgb.Point{100, 120};
|
points[1] = xgb.Point{100, 120}
|
||||||
|
|
||||||
hosts, _ := c.ListHosts();
|
hosts, _ := c.ListHosts()
|
||||||
fmt.Printf("hosts = %+v\n", hosts);
|
fmt.Printf("hosts = %+v\n", hosts)
|
||||||
|
|
||||||
ecookie := c.ListExtensionsRequest();
|
ecookie := c.ListExtensionsRequest()
|
||||||
exts, _ := c.ListExtensionsReply(ecookie);
|
exts, _ := c.ListExtensionsReply(ecookie)
|
||||||
for _, name := range exts.Names {
|
for _, name := range exts.Names {
|
||||||
fmt.Printf("exts = '%s'\n", name.Name)
|
fmt.Printf("exts = '%s'\n", name.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
reply, err := c.WaitForEvent();
|
reply, err := c.WaitForEvent()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("error: %v\n", err);
|
fmt.Printf("error: %v\n", err)
|
||||||
os.Exit(1);
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
fmt.Printf("event %T\n", reply);
|
fmt.Printf("event %T\n", reply)
|
||||||
switch event := reply.(type) {
|
switch event := reply.(type) {
|
||||||
case xgb.ExposeEvent:
|
case xgb.ExposeEvent:
|
||||||
c.PolyLine(xgb.CoordModeOrigin, win, gc, points)
|
c.PolyLine(xgb.CoordModeOrigin, win, gc, points)
|
||||||
case xgb.KeyReleaseEvent:
|
case xgb.KeyReleaseEvent:
|
||||||
fmt.Printf("key release!\n");
|
fmt.Printf("key release!\n")
|
||||||
points[0].X = event.EventX;
|
points[0].X = event.EventX
|
||||||
points[0].Y = event.EventY;
|
points[0].Y = event.EventY
|
||||||
c.PolyLine(xgb.CoordModeOrigin, win, gc, points);
|
c.PolyLine(xgb.CoordModeOrigin, win, gc, points)
|
||||||
c.Bell(75);
|
c.Bell(75)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Close();
|
c.Close()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,26 +7,26 @@
|
||||||
package xgb
|
package xgb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt";
|
"fmt"
|
||||||
"io";
|
"io"
|
||||||
"net";
|
"net"
|
||||||
"os";
|
"os"
|
||||||
"strconv";
|
"strconv"
|
||||||
"strings";
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Conn represents a connection to an X server.
|
// A Conn represents a connection to an X server.
|
||||||
// Only one goroutine should use a Conn's methods at a time.
|
// Only one goroutine should use a Conn's methods at a time.
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
conn net.Conn;
|
conn net.Conn
|
||||||
nextId Id;
|
nextId Id
|
||||||
nextCookie Cookie;
|
nextCookie Cookie
|
||||||
replies map[Cookie][]byte;
|
replies map[Cookie][]byte
|
||||||
events queue;
|
events queue
|
||||||
err os.Error;
|
err os.Error
|
||||||
defaultScreen int;
|
defaultScreen int
|
||||||
scratch [32]byte;
|
scratch [32]byte
|
||||||
Setup SetupInfo;
|
Setup SetupInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Id is used for all X identifiers, such as windows, pixmaps, and GCs.
|
// Id is used for all X identifiers, such as windows, pixmaps, and GCs.
|
||||||
|
|
@ -44,11 +44,11 @@ type Event interface{}
|
||||||
|
|
||||||
// Error contains protocol errors returned to us by the X server.
|
// Error contains protocol errors returned to us by the X server.
|
||||||
type Error struct {
|
type Error struct {
|
||||||
Detail uint8;
|
Detail uint8
|
||||||
Major uint8;
|
Major uint8
|
||||||
Minor uint16;
|
Minor uint16
|
||||||
Cookie Cookie;
|
Cookie Cookie
|
||||||
Id Id;
|
Id Id
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Error) String() string {
|
func (e *Error) String() string {
|
||||||
|
|
@ -58,81 +58,81 @@ func (e *Error) String() string {
|
||||||
|
|
||||||
// NewID generates a new unused ID for use with requests like CreateWindow.
|
// NewID generates a new unused ID for use with requests like CreateWindow.
|
||||||
func (c *Conn) NewId() Id {
|
func (c *Conn) NewId() Id {
|
||||||
id := c.nextId;
|
id := c.nextId
|
||||||
// TODO: handle ID overflow
|
// TODO: handle ID overflow
|
||||||
c.nextId++;
|
c.nextId++
|
||||||
return id;
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pad a length to align on 4 bytes.
|
// Pad a length to align on 4 bytes.
|
||||||
func pad(n int) int { return (n + 3) & ^3 }
|
func pad(n int) int { return (n + 3) & ^3 }
|
||||||
|
|
||||||
func put16(buf []byte, v uint16) {
|
func put16(buf []byte, v uint16) {
|
||||||
buf[0] = byte(v);
|
buf[0] = byte(v)
|
||||||
buf[1] = byte(v >> 8);
|
buf[1] = byte(v >> 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
func put32(buf []byte, v uint32) {
|
func put32(buf []byte, v uint32) {
|
||||||
buf[0] = byte(v);
|
buf[0] = byte(v)
|
||||||
buf[1] = byte(v >> 8);
|
buf[1] = byte(v >> 8)
|
||||||
buf[2] = byte(v >> 16);
|
buf[2] = byte(v >> 16)
|
||||||
buf[3] = byte(v >> 24);
|
buf[3] = byte(v >> 24)
|
||||||
}
|
}
|
||||||
|
|
||||||
func get16(buf []byte) uint16 {
|
func get16(buf []byte) uint16 {
|
||||||
v := uint16(buf[0]);
|
v := uint16(buf[0])
|
||||||
v |= uint16(buf[1]) << 8;
|
v |= uint16(buf[1]) << 8
|
||||||
return v;
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func get32(buf []byte) uint32 {
|
func get32(buf []byte) uint32 {
|
||||||
v := uint32(buf[0]);
|
v := uint32(buf[0])
|
||||||
v |= uint32(buf[1]) << 8;
|
v |= uint32(buf[1]) << 8
|
||||||
v |= uint32(buf[2]) << 16;
|
v |= uint32(buf[2]) << 16
|
||||||
v |= uint32(buf[3]) << 32;
|
v |= uint32(buf[3]) << 32
|
||||||
return v;
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// Voodoo to count the number of bits set in a value list mask.
|
// Voodoo to count the number of bits set in a value list mask.
|
||||||
func popCount(mask0 int) int {
|
func popCount(mask0 int) int {
|
||||||
mask := uint32(mask0);
|
mask := uint32(mask0)
|
||||||
n := 0;
|
n := 0
|
||||||
for i := uint32(0); i < 32; i++ {
|
for i := uint32(0); i < 32; i++ {
|
||||||
if mask&(1<<i) != 0 {
|
if mask&(1<<i) != 0 {
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n;
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// A simple queue used to stow away events.
|
// A simple queue used to stow away events.
|
||||||
type queue struct {
|
type queue struct {
|
||||||
data [][]byte;
|
data [][]byte
|
||||||
a, b int;
|
a, b int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *queue) queue(item []byte) {
|
func (q *queue) queue(item []byte) {
|
||||||
if q.b == len(q.data) {
|
if q.b == len(q.data) {
|
||||||
if q.a > 0 {
|
if q.a > 0 {
|
||||||
copy(q.data, q.data[q.a:q.b]);
|
copy(q.data, q.data[q.a:q.b])
|
||||||
q.a, q.b = 0, q.b-q.a;
|
q.a, q.b = 0, q.b-q.a
|
||||||
} else {
|
} else {
|
||||||
newData := make([][]byte, (len(q.data)*3)/2);
|
newData := make([][]byte, (len(q.data)*3)/2)
|
||||||
copy(newData, q.data);
|
copy(newData, q.data)
|
||||||
q.data = newData;
|
q.data = newData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
q.data[q.b] = item;
|
q.data[q.b] = item
|
||||||
q.b++;
|
q.b++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *queue) dequeue() []byte {
|
func (q *queue) dequeue() []byte {
|
||||||
if q.a < q.b {
|
if q.a < q.b {
|
||||||
item := q.data[q.a];
|
item := q.data[q.a]
|
||||||
q.a++;
|
q.a++
|
||||||
return item;
|
return item
|
||||||
}
|
}
|
||||||
return nil;
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// sendRequest sends a request to the server and return its associated sequence number, or cookie.
|
// sendRequest sends a request to the server and return its associated sequence number, or cookie.
|
||||||
|
|
@ -140,23 +140,23 @@ func (q *queue) dequeue() []byte {
|
||||||
// to send any additional variable length data.
|
// to send any additional variable length data.
|
||||||
func (c *Conn) sendRequest(buf []byte) Cookie {
|
func (c *Conn) sendRequest(buf []byte) Cookie {
|
||||||
if _, err := c.conn.Write(buf); err != nil {
|
if _, err := c.conn.Write(buf); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "x protocol write error: %s\n", err);
|
fmt.Fprintf(os.Stderr, "x protocol write error: %s\n", err)
|
||||||
c.err = err;
|
c.err = err
|
||||||
}
|
}
|
||||||
cookie := c.nextCookie;
|
cookie := c.nextCookie
|
||||||
c.nextCookie++;
|
c.nextCookie++
|
||||||
return cookie;
|
return cookie
|
||||||
}
|
}
|
||||||
|
|
||||||
// sendPadding sends enough bytes to align to a 4-byte border.
|
// sendPadding sends enough bytes to align to a 4-byte border.
|
||||||
// It is used to pad the variable length data that is used with some requests.
|
// It is used to pad the variable length data that is used with some requests.
|
||||||
func (c *Conn) sendPadding(n int) {
|
func (c *Conn) sendPadding(n int) {
|
||||||
x := pad(n) - n;
|
x := pad(n) - n
|
||||||
if x > 0 {
|
if x > 0 {
|
||||||
_, err := c.conn.Write(c.scratch[0:x]);
|
_, err := c.conn.Write(c.scratch[0:x])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "x protocol write error: %s\n", err);
|
fmt.Fprintf(os.Stderr, "x protocol write error: %s\n", err)
|
||||||
c.err = err;
|
c.err = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -165,37 +165,37 @@ func (c *Conn) sendPadding(n int) {
|
||||||
// along with any necessary padding.
|
// along with any necessary padding.
|
||||||
func (c *Conn) sendBytes(buf []byte) {
|
func (c *Conn) sendBytes(buf []byte) {
|
||||||
if _, err := c.conn.Write(buf); err != nil {
|
if _, err := c.conn.Write(buf); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "x protocol write error: %s\n", err);
|
fmt.Fprintf(os.Stderr, "x protocol write error: %s\n", err)
|
||||||
c.err = err;
|
c.err = err
|
||||||
}
|
}
|
||||||
c.sendPadding(len(buf));
|
c.sendPadding(len(buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) sendString(str string) { c.sendBytes(strings.Bytes(str)) }
|
func (c *Conn) sendString(str string) { c.sendBytes(strings.Bytes(str)) }
|
||||||
|
|
||||||
// sendUInt32s sends a list of 32-bit integers as variable length data.
|
// sendUInt32s sends a list of 32-bit integers as variable length data.
|
||||||
func (c *Conn) sendUInt32List(list []uint32) {
|
func (c *Conn) sendUInt32List(list []uint32) {
|
||||||
buf := make([]byte, len(list)*4);
|
buf := make([]byte, len(list)*4)
|
||||||
for i := 0; i < len(list); i++ {
|
for i := 0; i < len(list); i++ {
|
||||||
put32(buf[i*4:], list[i])
|
put32(buf[i*4:], list[i])
|
||||||
}
|
}
|
||||||
c.sendBytes(buf);
|
c.sendBytes(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) sendIdList(list []Id, length int) {
|
func (c *Conn) sendIdList(list []Id, length int) {
|
||||||
buf := make([]byte, length*4);
|
buf := make([]byte, length*4)
|
||||||
for i := 0; i < length; i++ {
|
for i := 0; i < length; i++ {
|
||||||
put32(buf[i*4:], uint32(list[i]))
|
put32(buf[i*4:], uint32(list[i]))
|
||||||
}
|
}
|
||||||
c.sendBytes(buf);
|
c.sendBytes(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) sendKeysymList(list []Keysym, length int) {
|
func (c *Conn) sendKeysymList(list []Keysym, length int) {
|
||||||
buf := make([]byte, length*4);
|
buf := make([]byte, length*4)
|
||||||
for i := 0; i < length; i++ {
|
for i := 0; i < length; i++ {
|
||||||
put32(buf[i*4:], uint32(list[i]))
|
put32(buf[i*4:], uint32(list[i]))
|
||||||
}
|
}
|
||||||
c.sendBytes(buf);
|
c.sendBytes(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// readNextReply reads and processes the next server reply.
|
// readNextReply reads and processes the next server reply.
|
||||||
|
|
@ -203,10 +203,10 @@ func (c *Conn) sendKeysymList(list []Keysym, length int) {
|
||||||
// Events are pushed onto the event queue and replies to requests
|
// Events are pushed onto the event queue and replies to requests
|
||||||
// are stashed away in a map indexed by the sequence number.
|
// are stashed away in a map indexed by the sequence number.
|
||||||
func (c *Conn) readNextReply() os.Error {
|
func (c *Conn) readNextReply() os.Error {
|
||||||
buf := make([]byte, 32);
|
buf := make([]byte, 32)
|
||||||
if _, err := io.ReadFull(c.conn, buf); err != nil {
|
if _, err := io.ReadFull(c.conn, buf); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "x protocol read error: %s\n", err);
|
fmt.Fprintf(os.Stderr, "x protocol read error: %s\n", err)
|
||||||
return err;
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch buf[0] {
|
switch buf[0] {
|
||||||
|
|
@ -217,21 +217,21 @@ func (c *Conn) readNextReply() os.Error {
|
||||||
Id: Id(get32(buf[4:])),
|
Id: Id(get32(buf[4:])),
|
||||||
Minor: get16(buf[8:]),
|
Minor: get16(buf[8:]),
|
||||||
Major: buf[10],
|
Major: buf[10],
|
||||||
};
|
}
|
||||||
fmt.Fprintf(os.Stderr, "x protocol error: %s\n", err);
|
fmt.Fprintf(os.Stderr, "x protocol error: %s\n", err)
|
||||||
return err;
|
return err
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
seq := Cookie(get16(buf[2:]));
|
seq := Cookie(get16(buf[2:]))
|
||||||
size := get32(buf[4:]);
|
size := get32(buf[4:])
|
||||||
if size > 0 {
|
if size > 0 {
|
||||||
bigbuf := make([]byte, 32+size*4, 32+size*4);
|
bigbuf := make([]byte, 32+size*4, 32+size*4)
|
||||||
copy(bigbuf[0:32], buf);
|
copy(bigbuf[0:32], buf)
|
||||||
if _, err := io.ReadFull(c.conn, bigbuf[32:]); err != nil {
|
if _, err := io.ReadFull(c.conn, bigbuf[32:]); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "x protocol read error: %s\n", err);
|
fmt.Fprintf(os.Stderr, "x protocol read error: %s\n", err)
|
||||||
return err;
|
return err
|
||||||
}
|
}
|
||||||
c.replies[seq] = bigbuf;
|
c.replies[seq] = bigbuf
|
||||||
} else {
|
} else {
|
||||||
c.replies[seq] = buf
|
c.replies[seq] = buf
|
||||||
}
|
}
|
||||||
|
|
@ -240,7 +240,7 @@ func (c *Conn) readNextReply() os.Error {
|
||||||
c.events.queue(buf)
|
c.events.queue(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil;
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// waitForReply looks for a reply in the map indexed by sequence number.
|
// waitForReply looks for a reply in the map indexed by sequence number.
|
||||||
|
|
@ -249,14 +249,14 @@ func (c *Conn) readNextReply() os.Error {
|
||||||
func (c *Conn) waitForReply(cookie Cookie) ([]byte, os.Error) {
|
func (c *Conn) waitForReply(cookie Cookie) ([]byte, os.Error) {
|
||||||
for {
|
for {
|
||||||
if reply, ok := c.replies[cookie]; ok {
|
if reply, ok := c.replies[cookie]; ok {
|
||||||
c.replies[cookie] = reply, false;
|
c.replies[cookie] = reply, false
|
||||||
return reply, nil;
|
return reply, nil
|
||||||
}
|
}
|
||||||
if err := c.readNextReply(); err != nil {
|
if err := c.readNextReply(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic("unreachable");
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitForEvent returns the next event from the server.
|
// WaitForEvent returns the next event from the server.
|
||||||
|
|
@ -270,7 +270,7 @@ func (c *Conn) WaitForEvent() (Event, os.Error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic("unreachable");
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
|
|
||||||
// PollForEvent returns the next event from the server if one is available in the internal queue.
|
// PollForEvent returns the next event from the server if one is available in the internal queue.
|
||||||
|
|
@ -280,94 +280,94 @@ func (c *Conn) PollForEvent() (Event, os.Error) {
|
||||||
if reply := c.events.dequeue(); reply != nil {
|
if reply := c.events.dequeue(); reply != nil {
|
||||||
return parseEvent(reply)
|
return parseEvent(reply)
|
||||||
}
|
}
|
||||||
return nil, nil;
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dial connects to the X server given in the 'display' string.
|
// Dial connects to the X server given in the 'display' string.
|
||||||
// The display string is typically taken from os.Getenv("DISPLAY").
|
// The display string is typically taken from os.Getenv("DISPLAY").
|
||||||
func Dial(display string) (*Conn, os.Error) {
|
func Dial(display string) (*Conn, os.Error) {
|
||||||
var err os.Error;
|
var err os.Error
|
||||||
|
|
||||||
c := new(Conn);
|
c := new(Conn)
|
||||||
|
|
||||||
if display[0] == '/' {
|
if display[0] == '/' {
|
||||||
c.conn, err = net.Dial("unix", "", display);
|
c.conn, err = net.Dial("unix", "", display)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("cannot connect: %v\n", err);
|
fmt.Printf("cannot connect: %v\n", err)
|
||||||
return nil, err;
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
parts := strings.Split(display, ":", 2);
|
parts := strings.Split(display, ":", 2)
|
||||||
host := parts[0];
|
host := parts[0]
|
||||||
port := 0;
|
port := 0
|
||||||
if len(parts) > 1 {
|
if len(parts) > 1 {
|
||||||
parts = strings.Split(parts[1], ".", 2);
|
parts = strings.Split(parts[1], ".", 2)
|
||||||
port, _ = strconv.Atoi(parts[0]);
|
port, _ = strconv.Atoi(parts[0])
|
||||||
if len(parts) > 1 {
|
if len(parts) > 1 {
|
||||||
c.defaultScreen, _ = strconv.Atoi(parts[1])
|
c.defaultScreen, _ = strconv.Atoi(parts[1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
display = fmt.Sprintf("%s:%d", host, port+6000);
|
display = fmt.Sprintf("%s:%d", host, port+6000)
|
||||||
c.conn, err = net.Dial("tcp", "", display);
|
c.conn, err = net.Dial("tcp", "", display)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("cannot connect: %v\n", err);
|
fmt.Printf("cannot connect: %v\n", err)
|
||||||
return nil, err;
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: get these from .Xauthority
|
// TODO: get these from .Xauthority
|
||||||
var authName, authData []byte;
|
var authName, authData []byte
|
||||||
|
|
||||||
buf := make([]byte, 12+pad(len(authName))+pad(len(authData)));
|
buf := make([]byte, 12+pad(len(authName))+pad(len(authData)))
|
||||||
buf[0] = 'l';
|
buf[0] = 'l'
|
||||||
buf[1] = 0;
|
buf[1] = 0
|
||||||
put16(buf[2:], 11);
|
put16(buf[2:], 11)
|
||||||
put16(buf[4:], 0);
|
put16(buf[4:], 0)
|
||||||
put16(buf[6:], uint16(len(authName)));
|
put16(buf[6:], uint16(len(authName)))
|
||||||
put16(buf[8:], uint16(len(authData)));
|
put16(buf[8:], uint16(len(authData)))
|
||||||
put16(buf[10:], 0);
|
put16(buf[10:], 0)
|
||||||
copy(buf[12:], authName);
|
copy(buf[12:], authName)
|
||||||
copy(buf[12+pad(len(authName)):], authData);
|
copy(buf[12+pad(len(authName)):], authData)
|
||||||
if _, err = c.conn.Write(buf); err != nil {
|
if _, err = c.conn.Write(buf); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
head := make([]byte, 8);
|
head := make([]byte, 8)
|
||||||
if _, err = io.ReadFull(c.conn, head[0:8]); err != nil {
|
if _, err = io.ReadFull(c.conn, head[0:8]); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
code := head[0];
|
code := head[0]
|
||||||
reasonLen := head[1];
|
reasonLen := head[1]
|
||||||
major := get16(head[2:]);
|
major := get16(head[2:])
|
||||||
minor := get16(head[4:]);
|
minor := get16(head[4:])
|
||||||
dataLen := get16(head[6:]);
|
dataLen := get16(head[6:])
|
||||||
|
|
||||||
if major != 11 || minor != 0 {
|
if major != 11 || minor != 0 {
|
||||||
return nil, os.NewError(fmt.Sprintf("x protocol version mismatch: %d.%d", major, minor))
|
return nil, os.NewError(fmt.Sprintf("x protocol version mismatch: %d.%d", major, minor))
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = make([]byte, int(dataLen)*4+8, int(dataLen)*4+8);
|
buf = make([]byte, int(dataLen)*4+8, int(dataLen)*4+8)
|
||||||
copy(buf, head);
|
copy(buf, head)
|
||||||
if _, err = io.ReadFull(c.conn, buf[8:]); err != nil {
|
if _, err = io.ReadFull(c.conn, buf[8:]); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if code == 0 {
|
if code == 0 {
|
||||||
reason := buf[8 : 8+reasonLen];
|
reason := buf[8 : 8+reasonLen]
|
||||||
return nil, os.NewError(fmt.Sprintf("x protocol authentication refused: %s", string(reason)));
|
return nil, os.NewError(fmt.Sprintf("x protocol authentication refused: %s", string(reason)))
|
||||||
}
|
}
|
||||||
|
|
||||||
getSetupInfo(buf, &c.Setup);
|
getSetupInfo(buf, &c.Setup)
|
||||||
|
|
||||||
if c.defaultScreen >= len(c.Setup.Roots) {
|
if c.defaultScreen >= len(c.Setup.Roots) {
|
||||||
c.defaultScreen = 0
|
c.defaultScreen = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
c.nextId = Id(c.Setup.ResourceIdBase);
|
c.nextId = Id(c.Setup.ResourceIdBase)
|
||||||
c.nextCookie = 1;
|
c.nextCookie = 1
|
||||||
c.replies = make(map[Cookie][]byte);
|
c.replies = make(map[Cookie][]byte)
|
||||||
c.events = queue{make([][]byte, 100), 0, 0};
|
c.events = queue{make([][]byte, 100), 0, 0}
|
||||||
return c, nil;
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the connection to the X server.
|
// Close closes the connection to the X server.
|
||||||
|
|
@ -381,18 +381,18 @@ func (c *Conn) DefaultScreen() *ScreenInfo { return &c.Setup.Roots[c.defaultScre
|
||||||
// ClientMessageData holds the data from a client message,
|
// ClientMessageData holds the data from a client message,
|
||||||
// duplicated in three forms because Go doesn't have unions.
|
// duplicated in three forms because Go doesn't have unions.
|
||||||
type ClientMessageData struct {
|
type ClientMessageData struct {
|
||||||
Data8 [20]byte;
|
Data8 [20]byte
|
||||||
Data16 [10]uint16;
|
Data16 [10]uint16
|
||||||
Data32 [5]uint32;
|
Data32 [5]uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func getClientMessageData(b []byte, v *ClientMessageData) int {
|
func getClientMessageData(b []byte, v *ClientMessageData) int {
|
||||||
copy(&v.Data8, b);
|
copy(&v.Data8, b)
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
v.Data16[i] = get16(b[i*2:])
|
v.Data16[i] = get16(b[i*2:])
|
||||||
}
|
}
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 5; i++ {
|
||||||
v.Data32[i] = get32(b[i*4:])
|
v.Data32[i] = get32(b[i*4:])
|
||||||
}
|
}
|
||||||
return 20;
|
return 20
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -5,12 +5,12 @@
|
||||||
package xml
|
package xml
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes";
|
"bytes"
|
||||||
"io";
|
"io"
|
||||||
"os";
|
"os"
|
||||||
"reflect";
|
"reflect"
|
||||||
"strings";
|
"strings"
|
||||||
"unicode";
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BUG(rsc): Mapping between XML elements and data structures is inherently flawed:
|
// BUG(rsc): Mapping between XML elements and data structures is inherently flawed:
|
||||||
|
|
@ -113,17 +113,17 @@ import (
|
||||||
// to a freshly allocated value and then mapping the element to that value.
|
// to a freshly allocated value and then mapping the element to that value.
|
||||||
//
|
//
|
||||||
func Unmarshal(r io.Reader, val interface{}) os.Error {
|
func Unmarshal(r io.Reader, val interface{}) os.Error {
|
||||||
v, ok := reflect.NewValue(val).(*reflect.PtrValue);
|
v, ok := reflect.NewValue(val).(*reflect.PtrValue)
|
||||||
if !ok {
|
if !ok {
|
||||||
return os.NewError("non-pointer passed to Unmarshal")
|
return os.NewError("non-pointer passed to Unmarshal")
|
||||||
}
|
}
|
||||||
p := NewParser(r);
|
p := NewParser(r)
|
||||||
elem := v.Elem();
|
elem := v.Elem()
|
||||||
err := p.unmarshal(elem, nil);
|
err := p.unmarshal(elem, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil;
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// An UnmarshalError represents an error in the unmarshalling process.
|
// An UnmarshalError represents an error in the unmarshalling process.
|
||||||
|
|
@ -138,11 +138,11 @@ func (e UnmarshalError) String() string { return string(e) }
|
||||||
// Passing a nil start element indicates that Unmarshal should
|
// Passing a nil start element indicates that Unmarshal should
|
||||||
// read the token stream to find the start element.
|
// read the token stream to find the start element.
|
||||||
func (p *Parser) Unmarshal(val interface{}, start *StartElement) os.Error {
|
func (p *Parser) Unmarshal(val interface{}, start *StartElement) os.Error {
|
||||||
v, ok := reflect.NewValue(val).(*reflect.PtrValue);
|
v, ok := reflect.NewValue(val).(*reflect.PtrValue)
|
||||||
if !ok {
|
if !ok {
|
||||||
return os.NewError("non-pointer passed to Unmarshal")
|
return os.NewError("non-pointer passed to Unmarshal")
|
||||||
}
|
}
|
||||||
return p.unmarshal(v.Elem(), start);
|
return p.unmarshal(v.Elem(), start)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fieldName strips invalid characters from an XML name
|
// fieldName strips invalid characters from an XML name
|
||||||
|
|
@ -154,7 +154,7 @@ func fieldName(original string) string {
|
||||||
if unicode.IsDigit(x) || unicode.IsLetter(x) {
|
if unicode.IsDigit(x) || unicode.IsLetter(x) {
|
||||||
return unicode.ToLower(x)
|
return unicode.ToLower(x)
|
||||||
}
|
}
|
||||||
return -1;
|
return -1
|
||||||
},
|
},
|
||||||
original)
|
original)
|
||||||
}
|
}
|
||||||
|
|
@ -164,87 +164,87 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
|
||||||
// Find start element if we need it.
|
// Find start element if we need it.
|
||||||
if start == nil {
|
if start == nil {
|
||||||
for {
|
for {
|
||||||
tok, err := p.Token();
|
tok, err := p.Token()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if t, ok := tok.(StartElement); ok {
|
if t, ok := tok.(StartElement); ok {
|
||||||
start = &t;
|
start = &t
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if pv, ok := val.(*reflect.PtrValue); ok {
|
if pv, ok := val.(*reflect.PtrValue); ok {
|
||||||
if pv.Get() == 0 {
|
if pv.Get() == 0 {
|
||||||
zv := reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem());
|
zv := reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem())
|
||||||
pv.PointTo(zv);
|
pv.PointTo(zv)
|
||||||
val = zv;
|
val = zv
|
||||||
} else {
|
} else {
|
||||||
val = pv.Elem()
|
val = pv.Elem()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
data []byte;
|
data []byte
|
||||||
saveData reflect.Value;
|
saveData reflect.Value
|
||||||
comment []byte;
|
comment []byte
|
||||||
saveComment reflect.Value;
|
saveComment reflect.Value
|
||||||
sv *reflect.StructValue;
|
sv *reflect.StructValue
|
||||||
styp *reflect.StructType;
|
styp *reflect.StructType
|
||||||
)
|
)
|
||||||
switch v := val.(type) {
|
switch v := val.(type) {
|
||||||
case *reflect.BoolValue:
|
case *reflect.BoolValue:
|
||||||
v.Set(true)
|
v.Set(true)
|
||||||
|
|
||||||
case *reflect.SliceValue:
|
case *reflect.SliceValue:
|
||||||
typ := v.Type().(*reflect.SliceType);
|
typ := v.Type().(*reflect.SliceType)
|
||||||
if _, ok := typ.Elem().(*reflect.Uint8Type); ok {
|
if _, ok := typ.Elem().(*reflect.Uint8Type); ok {
|
||||||
// []byte
|
// []byte
|
||||||
saveData = v;
|
saveData = v
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slice of element values.
|
// Slice of element values.
|
||||||
// Grow slice.
|
// Grow slice.
|
||||||
n := v.Len();
|
n := v.Len()
|
||||||
if n >= v.Cap() {
|
if n >= v.Cap() {
|
||||||
ncap := 2 * n;
|
ncap := 2 * n
|
||||||
if ncap < 4 {
|
if ncap < 4 {
|
||||||
ncap = 4
|
ncap = 4
|
||||||
}
|
}
|
||||||
new := reflect.MakeSlice(typ, n, ncap);
|
new := reflect.MakeSlice(typ, n, ncap)
|
||||||
reflect.ArrayCopy(new, v);
|
reflect.ArrayCopy(new, v)
|
||||||
v.Set(new);
|
v.Set(new)
|
||||||
}
|
}
|
||||||
v.SetLen(n + 1);
|
v.SetLen(n + 1)
|
||||||
|
|
||||||
// Recur to read element into slice.
|
// Recur to read element into slice.
|
||||||
if err := p.unmarshal(v.Elem(n), start); err != nil {
|
if err := p.unmarshal(v.Elem(n), start); err != nil {
|
||||||
v.SetLen(n);
|
v.SetLen(n)
|
||||||
return err;
|
return err
|
||||||
}
|
}
|
||||||
return nil;
|
return nil
|
||||||
|
|
||||||
case *reflect.StringValue:
|
case *reflect.StringValue:
|
||||||
saveData = v
|
saveData = v
|
||||||
|
|
||||||
case *reflect.StructValue:
|
case *reflect.StructValue:
|
||||||
if _, ok := v.Interface().(Name); ok {
|
if _, ok := v.Interface().(Name); ok {
|
||||||
v.Set(reflect.NewValue(start.Name).(*reflect.StructValue));
|
v.Set(reflect.NewValue(start.Name).(*reflect.StructValue))
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
sv = v;
|
sv = v
|
||||||
typ := sv.Type().(*reflect.StructType);
|
typ := sv.Type().(*reflect.StructType)
|
||||||
styp = typ;
|
styp = typ
|
||||||
// Assign name.
|
// Assign name.
|
||||||
if f, ok := typ.FieldByName("XMLName"); ok {
|
if f, ok := typ.FieldByName("XMLName"); ok {
|
||||||
// Validate element name.
|
// Validate element name.
|
||||||
if f.Tag != "" {
|
if f.Tag != "" {
|
||||||
tag := f.Tag;
|
tag := f.Tag
|
||||||
ns := "";
|
ns := ""
|
||||||
i := strings.LastIndex(tag, " ");
|
i := strings.LastIndex(tag, " ")
|
||||||
if i >= 0 {
|
if i >= 0 {
|
||||||
ns, tag = tag[0:i], tag[i+1:]
|
ns, tag = tag[0:i], tag[i+1:]
|
||||||
}
|
}
|
||||||
|
|
@ -252,44 +252,44 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
|
||||||
return UnmarshalError("expected element type <" + tag + "> but have <" + start.Name.Local + ">")
|
return UnmarshalError("expected element type <" + tag + "> but have <" + start.Name.Local + ">")
|
||||||
}
|
}
|
||||||
if ns != "" && ns != start.Name.Space {
|
if ns != "" && ns != start.Name.Space {
|
||||||
e := "expected element <" + tag + "> in name space " + ns + " but have ";
|
e := "expected element <" + tag + "> in name space " + ns + " but have "
|
||||||
if start.Name.Space == "" {
|
if start.Name.Space == "" {
|
||||||
e += "no name space"
|
e += "no name space"
|
||||||
} else {
|
} else {
|
||||||
e += start.Name.Space
|
e += start.Name.Space
|
||||||
}
|
}
|
||||||
return UnmarshalError(e);
|
return UnmarshalError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save
|
// Save
|
||||||
v := sv.FieldByIndex(f.Index);
|
v := sv.FieldByIndex(f.Index)
|
||||||
if _, ok := v.Interface().(Name); !ok {
|
if _, ok := v.Interface().(Name); !ok {
|
||||||
return UnmarshalError(sv.Type().String() + " field XMLName does not have type xml.Name")
|
return UnmarshalError(sv.Type().String() + " field XMLName does not have type xml.Name")
|
||||||
}
|
}
|
||||||
v.(*reflect.StructValue).Set(reflect.NewValue(start.Name).(*reflect.StructValue));
|
v.(*reflect.StructValue).Set(reflect.NewValue(start.Name).(*reflect.StructValue))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign attributes.
|
// Assign attributes.
|
||||||
// Also, determine whether we need to save character data or comments.
|
// Also, determine whether we need to save character data or comments.
|
||||||
for i, n := 0, typ.NumField(); i < n; i++ {
|
for i, n := 0, typ.NumField(); i < n; i++ {
|
||||||
f := typ.Field(i);
|
f := typ.Field(i)
|
||||||
switch f.Tag {
|
switch f.Tag {
|
||||||
case "attr":
|
case "attr":
|
||||||
strv, ok := sv.FieldByIndex(f.Index).(*reflect.StringValue);
|
strv, ok := sv.FieldByIndex(f.Index).(*reflect.StringValue)
|
||||||
if !ok {
|
if !ok {
|
||||||
return UnmarshalError(sv.Type().String() + " field " + f.Name + " has attr tag but is not type string")
|
return UnmarshalError(sv.Type().String() + " field " + f.Name + " has attr tag but is not type string")
|
||||||
}
|
}
|
||||||
// Look for attribute.
|
// Look for attribute.
|
||||||
val := "";
|
val := ""
|
||||||
k := strings.ToLower(f.Name);
|
k := strings.ToLower(f.Name)
|
||||||
for _, a := range start.Attr {
|
for _, a := range start.Attr {
|
||||||
if fieldName(a.Name.Local) == k {
|
if fieldName(a.Name.Local) == k {
|
||||||
val = a.Value;
|
val = a.Value
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
strv.Set(val);
|
strv.Set(val)
|
||||||
|
|
||||||
case "comment":
|
case "comment":
|
||||||
if saveComment == nil {
|
if saveComment == nil {
|
||||||
|
|
@ -308,7 +308,7 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
|
||||||
// Process sub-elements along the way.
|
// Process sub-elements along the way.
|
||||||
Loop:
|
Loop:
|
||||||
for {
|
for {
|
||||||
tok, err := p.Token();
|
tok, err := p.Token()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -318,15 +318,15 @@ Loop:
|
||||||
// Look up by tag name.
|
// Look up by tag name.
|
||||||
// If that fails, fall back to mop-up field named "Any".
|
// If that fails, fall back to mop-up field named "Any".
|
||||||
if sv != nil {
|
if sv != nil {
|
||||||
k := fieldName(t.Name.Local);
|
k := fieldName(t.Name.Local)
|
||||||
any := -1;
|
any := -1
|
||||||
for i, n := 0, styp.NumField(); i < n; i++ {
|
for i, n := 0, styp.NumField(); i < n; i++ {
|
||||||
f := styp.Field(i);
|
f := styp.Field(i)
|
||||||
if strings.ToLower(f.Name) == k {
|
if strings.ToLower(f.Name) == k {
|
||||||
if err := p.unmarshal(sv.FieldByIndex(f.Index), &t); err != nil {
|
if err := p.unmarshal(sv.FieldByIndex(f.Index), &t); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
continue Loop;
|
continue Loop
|
||||||
}
|
}
|
||||||
if any < 0 && f.Name == "Any" {
|
if any < 0 && f.Name == "Any" {
|
||||||
any = i
|
any = i
|
||||||
|
|
@ -336,7 +336,7 @@ Loop:
|
||||||
if err := p.unmarshal(sv.FieldByIndex(styp.Field(any).Index), &t); err != nil {
|
if err := p.unmarshal(sv.FieldByIndex(styp.Field(any).Index), &t); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
continue Loop;
|
continue Loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Not saving sub-element but still have to skip over it.
|
// Not saving sub-element but still have to skip over it.
|
||||||
|
|
@ -374,7 +374,7 @@ Loop:
|
||||||
t.Set(reflect.NewValue(comment).(*reflect.SliceValue))
|
t.Set(reflect.NewValue(comment).(*reflect.SliceValue))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil;
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Have already read a start element.
|
// Have already read a start element.
|
||||||
|
|
@ -383,7 +383,7 @@ Loop:
|
||||||
// end element matches the start element we saw.
|
// end element matches the start element we saw.
|
||||||
func (p *Parser) Skip() os.Error {
|
func (p *Parser) Skip() os.Error {
|
||||||
for {
|
for {
|
||||||
tok, err := p.Token();
|
tok, err := p.Token()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -396,5 +396,5 @@ func (p *Parser) Skip() os.Error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic("unreachable");
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,14 @@
|
||||||
package xml
|
package xml
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect";
|
"reflect"
|
||||||
"testing";
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Stripped down Atom feed data structures.
|
// Stripped down Atom feed data structures.
|
||||||
|
|
||||||
func TestUnmarshalFeed(t *testing.T) {
|
func TestUnmarshalFeed(t *testing.T) {
|
||||||
var f Feed;
|
var f Feed
|
||||||
if err := Unmarshal(StringReader(rssFeedString), &f); err != nil {
|
if err := Unmarshal(StringReader(rssFeedString), &f); err != nil {
|
||||||
t.Fatalf("Unmarshal: %s", err)
|
t.Fatalf("Unmarshal: %s", err)
|
||||||
}
|
}
|
||||||
|
|
@ -78,38 +78,38 @@ not being used from outside intra_region_diff.py.
|
||||||
</summary></entry></feed>`
|
</summary></entry></feed>`
|
||||||
|
|
||||||
type Feed struct {
|
type Feed struct {
|
||||||
XMLName Name "http://www.w3.org/2005/Atom feed";
|
XMLName Name "http://www.w3.org/2005/Atom feed"
|
||||||
Title string;
|
Title string
|
||||||
Id string;
|
Id string
|
||||||
Link []Link;
|
Link []Link
|
||||||
Updated Time;
|
Updated Time
|
||||||
Author Person;
|
Author Person
|
||||||
Entry []Entry;
|
Entry []Entry
|
||||||
}
|
}
|
||||||
|
|
||||||
type Entry struct {
|
type Entry struct {
|
||||||
Title string;
|
Title string
|
||||||
Id string;
|
Id string
|
||||||
Link []Link;
|
Link []Link
|
||||||
Updated Time;
|
Updated Time
|
||||||
Author Person;
|
Author Person
|
||||||
Summary Text;
|
Summary Text
|
||||||
}
|
}
|
||||||
|
|
||||||
type Link struct {
|
type Link struct {
|
||||||
Rel string "attr";
|
Rel string "attr"
|
||||||
Href string "attr";
|
Href string "attr"
|
||||||
}
|
}
|
||||||
|
|
||||||
type Person struct {
|
type Person struct {
|
||||||
Name string;
|
Name string
|
||||||
URI string;
|
URI string
|
||||||
Email string;
|
Email string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Text struct {
|
type Text struct {
|
||||||
Type string "attr";
|
Type string "attr"
|
||||||
Body string "chardata";
|
Body string "chardata"
|
||||||
}
|
}
|
||||||
|
|
||||||
type Time string
|
type Time string
|
||||||
|
|
@ -210,7 +210,7 @@ not being used from outside intra_region_diff.py.
|
||||||
}
|
}
|
||||||
|
|
||||||
type FieldNameTest struct {
|
type FieldNameTest struct {
|
||||||
in, out string;
|
in, out string
|
||||||
}
|
}
|
||||||
|
|
||||||
var FieldNameTests = []FieldNameTest{
|
var FieldNameTests = []FieldNameTest{
|
||||||
|
|
@ -220,7 +220,7 @@ var FieldNameTests = []FieldNameTest{
|
||||||
|
|
||||||
func TestFieldName(t *testing.T) {
|
func TestFieldName(t *testing.T) {
|
||||||
for _, tt := range FieldNameTests {
|
for _, tt := range FieldNameTests {
|
||||||
a := fieldName(tt.in);
|
a := fieldName(tt.in)
|
||||||
if a != tt.out {
|
if a != tt.out {
|
||||||
t.Fatalf("have %#v\nwant %#v\n\n", a, tt.out)
|
t.Fatalf("have %#v\nwant %#v\n\n", a, tt.out)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,14 @@ package xml
|
||||||
// Expose parser line number in errors.
|
// Expose parser line number in errors.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio";
|
"bufio"
|
||||||
"bytes";
|
"bytes"
|
||||||
"io";
|
"io"
|
||||||
"os";
|
"os"
|
||||||
"strconv";
|
"strconv"
|
||||||
"strings";
|
"strings"
|
||||||
"unicode";
|
"unicode"
|
||||||
"utf8";
|
"utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A SyntaxError represents a syntax error in the XML input stream.
|
// A SyntaxError represents a syntax error in the XML input stream.
|
||||||
|
|
@ -36,13 +36,13 @@ func (e SyntaxError) String() string { return "XML syntax error: " + string(e) }
|
||||||
// is given as a canonical URL, not the short prefix used
|
// is given as a canonical URL, not the short prefix used
|
||||||
// in the document being parsed.
|
// in the document being parsed.
|
||||||
type Name struct {
|
type Name struct {
|
||||||
Space, Local string;
|
Space, Local string
|
||||||
}
|
}
|
||||||
|
|
||||||
// An Attr represents an attribute in an XML element (Name=Value).
|
// An Attr represents an attribute in an XML element (Name=Value).
|
||||||
type Attr struct {
|
type Attr struct {
|
||||||
Name Name;
|
Name Name
|
||||||
Value string;
|
Value string
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Token is an interface holding one of the token types:
|
// A Token is an interface holding one of the token types:
|
||||||
|
|
@ -51,13 +51,13 @@ type Token interface{}
|
||||||
|
|
||||||
// A StartElement represents an XML start element.
|
// A StartElement represents an XML start element.
|
||||||
type StartElement struct {
|
type StartElement struct {
|
||||||
Name Name;
|
Name Name
|
||||||
Attr []Attr;
|
Attr []Attr
|
||||||
}
|
}
|
||||||
|
|
||||||
// An EndElement represents an XML end element.
|
// An EndElement represents an XML end element.
|
||||||
type EndElement struct {
|
type EndElement struct {
|
||||||
Name Name;
|
Name Name
|
||||||
}
|
}
|
||||||
|
|
||||||
// A CharData represents XML character data (raw text),
|
// A CharData represents XML character data (raw text),
|
||||||
|
|
@ -66,9 +66,9 @@ type EndElement struct {
|
||||||
type CharData []byte
|
type CharData []byte
|
||||||
|
|
||||||
func makeCopy(b []byte) []byte {
|
func makeCopy(b []byte) []byte {
|
||||||
b1 := make([]byte, len(b));
|
b1 := make([]byte, len(b))
|
||||||
copy(b1, b);
|
copy(b1, b)
|
||||||
return b1;
|
return b1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c CharData) Copy() CharData { return CharData(makeCopy(c)) }
|
func (c CharData) Copy() CharData { return CharData(makeCopy(c)) }
|
||||||
|
|
@ -81,13 +81,13 @@ func (c Comment) Copy() Comment { return Comment(makeCopy(c)) }
|
||||||
|
|
||||||
// A ProcInst represents an XML processing instruction of the form <?target inst?>
|
// A ProcInst represents an XML processing instruction of the form <?target inst?>
|
||||||
type ProcInst struct {
|
type ProcInst struct {
|
||||||
Target string;
|
Target string
|
||||||
Inst []byte;
|
Inst []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p ProcInst) Copy() ProcInst {
|
func (p ProcInst) Copy() ProcInst {
|
||||||
p.Inst = makeCopy(p.Inst);
|
p.Inst = makeCopy(p.Inst)
|
||||||
return p;
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Directive represents an XML directive of the form <!text>.
|
// A Directive represents an XML directive of the form <!text>.
|
||||||
|
|
@ -97,7 +97,7 @@ type Directive []byte
|
||||||
func (d Directive) Copy() Directive { return Directive(makeCopy(d)) }
|
func (d Directive) Copy() Directive { return Directive(makeCopy(d)) }
|
||||||
|
|
||||||
type readByter interface {
|
type readByter interface {
|
||||||
ReadByte() (b byte, err os.Error);
|
ReadByte() (b byte, err os.Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Parser represents an XML parser reading a particular input stream.
|
// A Parser represents an XML parser reading a particular input stream.
|
||||||
|
|
@ -120,12 +120,12 @@ type Parser struct {
|
||||||
// p.Entity = HTMLEntity
|
// p.Entity = HTMLEntity
|
||||||
//
|
//
|
||||||
// creates a parser that can handle typical HTML.
|
// creates a parser that can handle typical HTML.
|
||||||
Strict bool;
|
Strict bool
|
||||||
|
|
||||||
// When Strict == false, AutoClose indicates a set of elements to
|
// When Strict == false, AutoClose indicates a set of elements to
|
||||||
// consider closed immediately after they are opened, regardless
|
// consider closed immediately after they are opened, regardless
|
||||||
// of whether an end element is present.
|
// of whether an end element is present.
|
||||||
AutoClose []string;
|
AutoClose []string
|
||||||
|
|
||||||
// Entity can be used to map non-standard entity names to string replacements.
|
// Entity can be used to map non-standard entity names to string replacements.
|
||||||
// The parser behaves as if these standard mappings are present in the map,
|
// The parser behaves as if these standard mappings are present in the map,
|
||||||
|
|
@ -137,20 +137,20 @@ type Parser struct {
|
||||||
// "pos": "'",
|
// "pos": "'",
|
||||||
// "quot": `"`,
|
// "quot": `"`,
|
||||||
//
|
//
|
||||||
Entity map[string]string;
|
Entity map[string]string
|
||||||
|
|
||||||
r readByter;
|
r readByter
|
||||||
buf bytes.Buffer;
|
buf bytes.Buffer
|
||||||
stk *stack;
|
stk *stack
|
||||||
free *stack;
|
free *stack
|
||||||
needClose bool;
|
needClose bool
|
||||||
toClose Name;
|
toClose Name
|
||||||
nextToken Token;
|
nextToken Token
|
||||||
nextByte int;
|
nextByte int
|
||||||
ns map[string]string;
|
ns map[string]string
|
||||||
err os.Error;
|
err os.Error
|
||||||
line int;
|
line int
|
||||||
tmp [32]byte;
|
tmp [32]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewParser creates a new XML parser reading from r.
|
// NewParser creates a new XML parser reading from r.
|
||||||
|
|
@ -160,7 +160,7 @@ func NewParser(r io.Reader) *Parser {
|
||||||
nextByte: -1,
|
nextByte: -1,
|
||||||
line: 1,
|
line: 1,
|
||||||
Strict: true,
|
Strict: true,
|
||||||
};
|
}
|
||||||
|
|
||||||
// Get efficient byte at a time reader.
|
// Get efficient byte at a time reader.
|
||||||
// Assume that if reader has its own
|
// Assume that if reader has its own
|
||||||
|
|
@ -172,7 +172,7 @@ func NewParser(r io.Reader) *Parser {
|
||||||
p.r = bufio.NewReader(r)
|
p.r = bufio.NewReader(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
// Token returns the next XML token in the input stream.
|
// Token returns the next XML token in the input stream.
|
||||||
|
|
@ -200,16 +200,16 @@ func NewParser(r io.Reader) *Parser {
|
||||||
//
|
//
|
||||||
func (p *Parser) Token() (t Token, err os.Error) {
|
func (p *Parser) Token() (t Token, err os.Error) {
|
||||||
if p.nextToken != nil {
|
if p.nextToken != nil {
|
||||||
t = p.nextToken;
|
t = p.nextToken
|
||||||
p.nextToken = nil;
|
p.nextToken = nil
|
||||||
} else if t, err = p.RawToken(); err != nil {
|
} else if t, err = p.RawToken(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !p.Strict {
|
if !p.Strict {
|
||||||
if t1, ok := p.autoClose(t); ok {
|
if t1, ok := p.autoClose(t); ok {
|
||||||
p.nextToken = t;
|
p.nextToken = t
|
||||||
t = t1;
|
t = t1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch t1 := t.(type) {
|
switch t1 := t.(type) {
|
||||||
|
|
@ -220,33 +220,33 @@ func (p *Parser) Token() (t Token, err os.Error) {
|
||||||
// the translations first.
|
// the translations first.
|
||||||
for _, a := range t1.Attr {
|
for _, a := range t1.Attr {
|
||||||
if a.Name.Space == "xmlns" {
|
if a.Name.Space == "xmlns" {
|
||||||
v, ok := p.ns[a.Name.Local];
|
v, ok := p.ns[a.Name.Local]
|
||||||
p.pushNs(a.Name.Local, v, ok);
|
p.pushNs(a.Name.Local, v, ok)
|
||||||
p.ns[a.Name.Local] = a.Value;
|
p.ns[a.Name.Local] = a.Value
|
||||||
}
|
}
|
||||||
if a.Name.Space == "" && a.Name.Local == "xmlns" {
|
if a.Name.Space == "" && a.Name.Local == "xmlns" {
|
||||||
// Default space for untagged names
|
// Default space for untagged names
|
||||||
v, ok := p.ns[""];
|
v, ok := p.ns[""]
|
||||||
p.pushNs("", v, ok);
|
p.pushNs("", v, ok)
|
||||||
p.ns[""] = a.Value;
|
p.ns[""] = a.Value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.translate(&t1.Name, true);
|
p.translate(&t1.Name, true)
|
||||||
for i := range t1.Attr {
|
for i := range t1.Attr {
|
||||||
p.translate(&t1.Attr[i].Name, false)
|
p.translate(&t1.Attr[i].Name, false)
|
||||||
}
|
}
|
||||||
p.pushElement(t1.Name);
|
p.pushElement(t1.Name)
|
||||||
t = t1;
|
t = t1
|
||||||
|
|
||||||
case EndElement:
|
case EndElement:
|
||||||
p.translate(&t1.Name, true);
|
p.translate(&t1.Name, true)
|
||||||
if !p.popElement(&t1) {
|
if !p.popElement(&t1) {
|
||||||
return nil, p.err
|
return nil, p.err
|
||||||
}
|
}
|
||||||
t = t1;
|
t = t1
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply name space translation to name n.
|
// Apply name space translation to name n.
|
||||||
|
|
@ -271,53 +271,53 @@ func (p *Parser) translate(n *Name, isElementName bool) {
|
||||||
// ending a given tag are *below* it on the stack, which is
|
// ending a given tag are *below* it on the stack, which is
|
||||||
// more work but forced on us by XML.
|
// more work but forced on us by XML.
|
||||||
type stack struct {
|
type stack struct {
|
||||||
next *stack;
|
next *stack
|
||||||
kind int;
|
kind int
|
||||||
name Name;
|
name Name
|
||||||
ok bool;
|
ok bool
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
stkStart = iota;
|
stkStart = iota
|
||||||
stkNs;
|
stkNs
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Parser) push(kind int) *stack {
|
func (p *Parser) push(kind int) *stack {
|
||||||
s := p.free;
|
s := p.free
|
||||||
if s != nil {
|
if s != nil {
|
||||||
p.free = s.next
|
p.free = s.next
|
||||||
} else {
|
} else {
|
||||||
s = new(stack)
|
s = new(stack)
|
||||||
}
|
}
|
||||||
s.next = p.stk;
|
s.next = p.stk
|
||||||
s.kind = kind;
|
s.kind = kind
|
||||||
p.stk = s;
|
p.stk = s
|
||||||
return s;
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) pop() *stack {
|
func (p *Parser) pop() *stack {
|
||||||
s := p.stk;
|
s := p.stk
|
||||||
if s != nil {
|
if s != nil {
|
||||||
p.stk = s.next;
|
p.stk = s.next
|
||||||
s.next = p.free;
|
s.next = p.free
|
||||||
p.free = s;
|
p.free = s
|
||||||
}
|
}
|
||||||
return s;
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record that we are starting an element with the given name.
|
// Record that we are starting an element with the given name.
|
||||||
func (p *Parser) pushElement(name Name) {
|
func (p *Parser) pushElement(name Name) {
|
||||||
s := p.push(stkStart);
|
s := p.push(stkStart)
|
||||||
s.name = name;
|
s.name = name
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record that we are changing the value of ns[local].
|
// Record that we are changing the value of ns[local].
|
||||||
// The old value is url, ok.
|
// The old value is url, ok.
|
||||||
func (p *Parser) pushNs(local string, url string, ok bool) {
|
func (p *Parser) pushNs(local string, url string, ok bool) {
|
||||||
s := p.push(stkNs);
|
s := p.push(stkNs)
|
||||||
s.name.Local = local;
|
s.name.Local = local
|
||||||
s.name.Space = url;
|
s.name.Space = url
|
||||||
s.ok = ok;
|
s.ok = ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record that we are ending an element with the given name.
|
// Record that we are ending an element with the given name.
|
||||||
|
|
@ -327,35 +327,35 @@ func (p *Parser) pushNs(local string, url string, ok bool) {
|
||||||
// the stack to restore the name translations that existed
|
// the stack to restore the name translations that existed
|
||||||
// before we saw this element.
|
// before we saw this element.
|
||||||
func (p *Parser) popElement(t *EndElement) bool {
|
func (p *Parser) popElement(t *EndElement) bool {
|
||||||
s := p.pop();
|
s := p.pop()
|
||||||
name := t.Name;
|
name := t.Name
|
||||||
switch {
|
switch {
|
||||||
case s == nil || s.kind != stkStart:
|
case s == nil || s.kind != stkStart:
|
||||||
p.err = SyntaxError("unexpected end element </" + name.Local + ">");
|
p.err = SyntaxError("unexpected end element </" + name.Local + ">")
|
||||||
return false;
|
return false
|
||||||
case s.name.Local != name.Local:
|
case s.name.Local != name.Local:
|
||||||
if !p.Strict {
|
if !p.Strict {
|
||||||
p.needClose = true;
|
p.needClose = true
|
||||||
p.toClose = t.Name;
|
p.toClose = t.Name
|
||||||
t.Name = s.name;
|
t.Name = s.name
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
p.err = SyntaxError("element <" + s.name.Local + "> closed by </" + name.Local + ">");
|
p.err = SyntaxError("element <" + s.name.Local + "> closed by </" + name.Local + ">")
|
||||||
return false;
|
return false
|
||||||
case s.name.Space != name.Space:
|
case s.name.Space != name.Space:
|
||||||
p.err = SyntaxError("element <" + s.name.Local + "> in space " + s.name.Space +
|
p.err = SyntaxError("element <" + s.name.Local + "> in space " + s.name.Space +
|
||||||
"closed by </" + name.Local + "> in space " + name.Space);
|
"closed by </" + name.Local + "> in space " + name.Space)
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pop stack until a Start is on the top, undoing the
|
// Pop stack until a Start is on the top, undoing the
|
||||||
// translations that were associated with the element we just closed.
|
// translations that were associated with the element we just closed.
|
||||||
for p.stk != nil && p.stk.kind != stkStart {
|
for p.stk != nil && p.stk.kind != stkStart {
|
||||||
s := p.pop();
|
s := p.pop()
|
||||||
p.ns[s.name.Local] = s.name.Space, s.ok;
|
p.ns[s.name.Local] = s.name.Space, s.ok
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the top element on the stack is autoclosing and
|
// If the top element on the stack is autoclosing and
|
||||||
|
|
@ -364,18 +364,18 @@ func (p *Parser) autoClose(t Token) (Token, bool) {
|
||||||
if p.stk == nil || p.stk.kind != stkStart {
|
if p.stk == nil || p.stk.kind != stkStart {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
name := strings.ToLower(p.stk.name.Local);
|
name := strings.ToLower(p.stk.name.Local)
|
||||||
for _, s := range p.AutoClose {
|
for _, s := range p.AutoClose {
|
||||||
if strings.ToLower(s) == name {
|
if strings.ToLower(s) == name {
|
||||||
// This one should be auto closed if t doesn't close it.
|
// This one should be auto closed if t doesn't close it.
|
||||||
et, ok := t.(EndElement);
|
et, ok := t.(EndElement)
|
||||||
if !ok || et.Name.Local != name {
|
if !ok || et.Name.Local != name {
|
||||||
return EndElement{p.stk.name}, true
|
return EndElement{p.stk.name}, true
|
||||||
}
|
}
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, false;
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -390,23 +390,23 @@ func (p *Parser) RawToken() (Token, os.Error) {
|
||||||
// The last element we read was self-closing and
|
// The last element we read was self-closing and
|
||||||
// we returned just the StartElement half.
|
// we returned just the StartElement half.
|
||||||
// Return the EndElement half now.
|
// Return the EndElement half now.
|
||||||
p.needClose = false;
|
p.needClose = false
|
||||||
return EndElement{p.toClose}, nil;
|
return EndElement{p.toClose}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
b, ok := p.getc();
|
b, ok := p.getc()
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, p.err
|
return nil, p.err
|
||||||
}
|
}
|
||||||
|
|
||||||
if b != '<' {
|
if b != '<' {
|
||||||
// Text section.
|
// Text section.
|
||||||
p.ungetc(b);
|
p.ungetc(b)
|
||||||
data := p.text(-1, false);
|
data := p.text(-1, false)
|
||||||
if data == nil {
|
if data == nil {
|
||||||
return nil, p.err
|
return nil, p.err
|
||||||
}
|
}
|
||||||
return CharData(data), nil;
|
return CharData(data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if b, ok = p.mustgetc(); !ok {
|
if b, ok = p.mustgetc(); !ok {
|
||||||
|
|
@ -415,50 +415,50 @@ func (p *Parser) RawToken() (Token, os.Error) {
|
||||||
switch b {
|
switch b {
|
||||||
case '/':
|
case '/':
|
||||||
// </: End element
|
// </: End element
|
||||||
var name Name;
|
var name Name
|
||||||
if name, ok = p.nsname(); !ok {
|
if name, ok = p.nsname(); !ok {
|
||||||
if p.err == nil {
|
if p.err == nil {
|
||||||
p.err = SyntaxError("expected element name after </")
|
p.err = SyntaxError("expected element name after </")
|
||||||
}
|
}
|
||||||
return nil, p.err;
|
return nil, p.err
|
||||||
}
|
}
|
||||||
p.space();
|
p.space()
|
||||||
if b, ok = p.mustgetc(); !ok {
|
if b, ok = p.mustgetc(); !ok {
|
||||||
return nil, p.err
|
return nil, p.err
|
||||||
}
|
}
|
||||||
if b != '>' {
|
if b != '>' {
|
||||||
p.err = SyntaxError("invalid characters between </" + name.Local + " and >");
|
p.err = SyntaxError("invalid characters between </" + name.Local + " and >")
|
||||||
return nil, p.err;
|
return nil, p.err
|
||||||
}
|
}
|
||||||
return EndElement{name}, nil;
|
return EndElement{name}, nil
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
// <?: Processing instruction.
|
// <?: Processing instruction.
|
||||||
// TODO(rsc): Should parse the <?xml declaration to make sure
|
// TODO(rsc): Should parse the <?xml declaration to make sure
|
||||||
// the version is 1.0 and the encoding is UTF-8.
|
// the version is 1.0 and the encoding is UTF-8.
|
||||||
var target string;
|
var target string
|
||||||
if target, ok = p.name(); !ok {
|
if target, ok = p.name(); !ok {
|
||||||
if p.err == nil {
|
if p.err == nil {
|
||||||
p.err = SyntaxError("expected target name after <?")
|
p.err = SyntaxError("expected target name after <?")
|
||||||
}
|
}
|
||||||
return nil, p.err;
|
return nil, p.err
|
||||||
}
|
}
|
||||||
p.space();
|
p.space()
|
||||||
p.buf.Reset();
|
p.buf.Reset()
|
||||||
var b0 byte;
|
var b0 byte
|
||||||
for {
|
for {
|
||||||
if b, ok = p.mustgetc(); !ok {
|
if b, ok = p.mustgetc(); !ok {
|
||||||
return nil, p.err
|
return nil, p.err
|
||||||
}
|
}
|
||||||
p.buf.WriteByte(b);
|
p.buf.WriteByte(b)
|
||||||
if b0 == '?' && b == '>' {
|
if b0 == '?' && b == '>' {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
b0 = b;
|
b0 = b
|
||||||
}
|
}
|
||||||
data := p.buf.Bytes();
|
data := p.buf.Bytes()
|
||||||
data = data[0 : len(data)-2]; // chop ?>
|
data = data[0 : len(data)-2] // chop ?>
|
||||||
return ProcInst{target, data}, nil;
|
return ProcInst{target, data}, nil
|
||||||
|
|
||||||
case '!':
|
case '!':
|
||||||
// <!: Maybe comment, maybe CDATA.
|
// <!: Maybe comment, maybe CDATA.
|
||||||
|
|
@ -472,25 +472,25 @@ func (p *Parser) RawToken() (Token, os.Error) {
|
||||||
return nil, p.err
|
return nil, p.err
|
||||||
}
|
}
|
||||||
if b != '-' {
|
if b != '-' {
|
||||||
p.err = SyntaxError("invalid sequence <!- not part of <!--");
|
p.err = SyntaxError("invalid sequence <!- not part of <!--")
|
||||||
return nil, p.err;
|
return nil, p.err
|
||||||
}
|
}
|
||||||
// Look for terminator.
|
// Look for terminator.
|
||||||
p.buf.Reset();
|
p.buf.Reset()
|
||||||
var b0, b1 byte;
|
var b0, b1 byte
|
||||||
for {
|
for {
|
||||||
if b, ok = p.mustgetc(); !ok {
|
if b, ok = p.mustgetc(); !ok {
|
||||||
return nil, p.err
|
return nil, p.err
|
||||||
}
|
}
|
||||||
p.buf.WriteByte(b);
|
p.buf.WriteByte(b)
|
||||||
if b0 == '-' && b1 == '-' && b == '>' {
|
if b0 == '-' && b1 == '-' && b == '>' {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
b0, b1 = b1, b;
|
b0, b1 = b1, b
|
||||||
}
|
}
|
||||||
data := p.buf.Bytes();
|
data := p.buf.Bytes()
|
||||||
data = data[0 : len(data)-3]; // chop -->
|
data = data[0 : len(data)-3] // chop -->
|
||||||
return Comment(data), nil;
|
return Comment(data), nil
|
||||||
|
|
||||||
case '[': // <![
|
case '[': // <![
|
||||||
// Probably <![CDATA[.
|
// Probably <![CDATA[.
|
||||||
|
|
@ -499,22 +499,22 @@ func (p *Parser) RawToken() (Token, os.Error) {
|
||||||
return nil, p.err
|
return nil, p.err
|
||||||
}
|
}
|
||||||
if b != "CDATA["[i] {
|
if b != "CDATA["[i] {
|
||||||
p.err = SyntaxError("invalid <![ sequence");
|
p.err = SyntaxError("invalid <![ sequence")
|
||||||
return nil, p.err;
|
return nil, p.err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Have <![CDATA[. Read text until ]]>.
|
// Have <![CDATA[. Read text until ]]>.
|
||||||
data := p.text(-1, true);
|
data := p.text(-1, true)
|
||||||
if data == nil {
|
if data == nil {
|
||||||
return nil, p.err
|
return nil, p.err
|
||||||
}
|
}
|
||||||
return CharData(data), nil;
|
return CharData(data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Probably a directive: <!DOCTYPE ...>, <!ENTITY ...>, etc.
|
// Probably a directive: <!DOCTYPE ...>, <!ENTITY ...>, etc.
|
||||||
// We don't care, but accumulate for caller.
|
// We don't care, but accumulate for caller.
|
||||||
p.buf.Reset();
|
p.buf.Reset()
|
||||||
p.buf.WriteByte(b);
|
p.buf.WriteByte(b)
|
||||||
for {
|
for {
|
||||||
if b, ok = p.mustgetc(); !ok {
|
if b, ok = p.mustgetc(); !ok {
|
||||||
return nil, p.err
|
return nil, p.err
|
||||||
|
|
@ -522,106 +522,106 @@ func (p *Parser) RawToken() (Token, os.Error) {
|
||||||
if b == '>' {
|
if b == '>' {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
p.buf.WriteByte(b);
|
p.buf.WriteByte(b)
|
||||||
}
|
}
|
||||||
return Directive(p.buf.Bytes()), nil;
|
return Directive(p.buf.Bytes()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must be an open element like <a href="foo">
|
// Must be an open element like <a href="foo">
|
||||||
p.ungetc(b);
|
p.ungetc(b)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
name Name;
|
name Name
|
||||||
empty bool;
|
empty bool
|
||||||
attr []Attr;
|
attr []Attr
|
||||||
)
|
)
|
||||||
if name, ok = p.nsname(); !ok {
|
if name, ok = p.nsname(); !ok {
|
||||||
if p.err == nil {
|
if p.err == nil {
|
||||||
p.err = SyntaxError("expected element name after <")
|
p.err = SyntaxError("expected element name after <")
|
||||||
}
|
}
|
||||||
return nil, p.err;
|
return nil, p.err
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = make([]Attr, 0, 4);
|
attr = make([]Attr, 0, 4)
|
||||||
for {
|
for {
|
||||||
p.space();
|
p.space()
|
||||||
if b, ok = p.mustgetc(); !ok {
|
if b, ok = p.mustgetc(); !ok {
|
||||||
return nil, p.err
|
return nil, p.err
|
||||||
}
|
}
|
||||||
if b == '/' {
|
if b == '/' {
|
||||||
empty = true;
|
empty = true
|
||||||
if b, ok = p.mustgetc(); !ok {
|
if b, ok = p.mustgetc(); !ok {
|
||||||
return nil, p.err
|
return nil, p.err
|
||||||
}
|
}
|
||||||
if b != '>' {
|
if b != '>' {
|
||||||
p.err = SyntaxError("expected /> in element");
|
p.err = SyntaxError("expected /> in element")
|
||||||
return nil, p.err;
|
return nil, p.err
|
||||||
}
|
}
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
if b == '>' {
|
if b == '>' {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
p.ungetc(b);
|
p.ungetc(b)
|
||||||
|
|
||||||
n := len(attr);
|
n := len(attr)
|
||||||
if n >= cap(attr) {
|
if n >= cap(attr) {
|
||||||
nattr := make([]Attr, n, 2*cap(attr));
|
nattr := make([]Attr, n, 2*cap(attr))
|
||||||
for i, a := range attr {
|
for i, a := range attr {
|
||||||
nattr[i] = a
|
nattr[i] = a
|
||||||
}
|
}
|
||||||
attr = nattr;
|
attr = nattr
|
||||||
}
|
}
|
||||||
attr = attr[0 : n+1];
|
attr = attr[0 : n+1]
|
||||||
a := &attr[n];
|
a := &attr[n]
|
||||||
if a.Name, ok = p.nsname(); !ok {
|
if a.Name, ok = p.nsname(); !ok {
|
||||||
if p.err == nil {
|
if p.err == nil {
|
||||||
p.err = SyntaxError("expected attribute name in element")
|
p.err = SyntaxError("expected attribute name in element")
|
||||||
}
|
}
|
||||||
return nil, p.err;
|
return nil, p.err
|
||||||
}
|
}
|
||||||
p.space();
|
p.space()
|
||||||
if b, ok = p.mustgetc(); !ok {
|
if b, ok = p.mustgetc(); !ok {
|
||||||
return nil, p.err
|
return nil, p.err
|
||||||
}
|
}
|
||||||
if b != '=' {
|
if b != '=' {
|
||||||
p.err = SyntaxError("attribute name without = in element");
|
p.err = SyntaxError("attribute name without = in element")
|
||||||
return nil, p.err;
|
return nil, p.err
|
||||||
}
|
}
|
||||||
p.space();
|
p.space()
|
||||||
if b, ok = p.mustgetc(); !ok {
|
if b, ok = p.mustgetc(); !ok {
|
||||||
return nil, p.err
|
return nil, p.err
|
||||||
}
|
}
|
||||||
if b != '"' && b != '\'' {
|
if b != '"' && b != '\'' {
|
||||||
p.err = SyntaxError("unquoted or missing attribute value in element");
|
p.err = SyntaxError("unquoted or missing attribute value in element")
|
||||||
return nil, p.err;
|
return nil, p.err
|
||||||
}
|
}
|
||||||
data := p.text(int(b), false);
|
data := p.text(int(b), false)
|
||||||
if data == nil {
|
if data == nil {
|
||||||
return nil, p.err
|
return nil, p.err
|
||||||
}
|
}
|
||||||
a.Value = string(data);
|
a.Value = string(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if empty {
|
if empty {
|
||||||
p.needClose = true;
|
p.needClose = true
|
||||||
p.toClose = name;
|
p.toClose = name
|
||||||
}
|
}
|
||||||
return StartElement{name, attr}, nil;
|
return StartElement{name, attr}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip spaces if any
|
// Skip spaces if any
|
||||||
func (p *Parser) space() {
|
func (p *Parser) space() {
|
||||||
for {
|
for {
|
||||||
b, ok := p.getc();
|
b, ok := p.getc()
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch b {
|
switch b {
|
||||||
case ' ', '\r', '\n', '\t':
|
case ' ', '\r', '\n', '\t':
|
||||||
default:
|
default:
|
||||||
p.ungetc(b);
|
p.ungetc(b)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -635,10 +635,10 @@ func (p *Parser) getc() (b byte, ok bool) {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
if p.nextByte >= 0 {
|
if p.nextByte >= 0 {
|
||||||
b = byte(p.nextByte);
|
b = byte(p.nextByte)
|
||||||
p.nextByte = -1;
|
p.nextByte = -1
|
||||||
} else {
|
} else {
|
||||||
b, p.err = p.r.ReadByte();
|
b, p.err = p.r.ReadByte()
|
||||||
if p.err != nil {
|
if p.err != nil {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
@ -646,7 +646,7 @@ func (p *Parser) getc() (b byte, ok bool) {
|
||||||
if b == '\n' {
|
if b == '\n' {
|
||||||
p.line++
|
p.line++
|
||||||
}
|
}
|
||||||
return b, true;
|
return b, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must read a single byte.
|
// Must read a single byte.
|
||||||
|
|
@ -659,7 +659,7 @@ func (p *Parser) mustgetc() (b byte, ok bool) {
|
||||||
p.err = SyntaxError("unexpected EOF")
|
p.err = SyntaxError("unexpected EOF")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unread a single byte.
|
// Unread a single byte.
|
||||||
|
|
@ -667,7 +667,7 @@ func (p *Parser) ungetc(b byte) {
|
||||||
if b == '\n' {
|
if b == '\n' {
|
||||||
p.line--
|
p.line--
|
||||||
}
|
}
|
||||||
p.nextByte = int(b);
|
p.nextByte = int(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
var entity = map[string]int{
|
var entity = map[string]int{
|
||||||
|
|
@ -683,12 +683,12 @@ var entity = map[string]int{
|
||||||
// If cdata == true, we are in a <![CDATA[ section and need to find ]]>.
|
// If cdata == true, we are in a <![CDATA[ section and need to find ]]>.
|
||||||
// On failure return nil and leave the error in p.err.
|
// On failure return nil and leave the error in p.err.
|
||||||
func (p *Parser) text(quote int, cdata bool) []byte {
|
func (p *Parser) text(quote int, cdata bool) []byte {
|
||||||
var b0, b1 byte;
|
var b0, b1 byte
|
||||||
var trunc int;
|
var trunc int
|
||||||
p.buf.Reset();
|
p.buf.Reset()
|
||||||
Input:
|
Input:
|
||||||
for {
|
for {
|
||||||
b, ok := p.mustgetc();
|
b, ok := p.mustgetc()
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -697,21 +697,21 @@ Input:
|
||||||
// It is an error for ]]> to appear in ordinary text.
|
// It is an error for ]]> to appear in ordinary text.
|
||||||
if b0 == ']' && b1 == ']' && b == '>' {
|
if b0 == ']' && b1 == ']' && b == '>' {
|
||||||
if cdata {
|
if cdata {
|
||||||
trunc = 2;
|
trunc = 2
|
||||||
break Input;
|
break Input
|
||||||
}
|
}
|
||||||
p.err = SyntaxError("unescaped ]]> not in CDATA section");
|
p.err = SyntaxError("unescaped ]]> not in CDATA section")
|
||||||
return nil;
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop reading text if we see a <.
|
// Stop reading text if we see a <.
|
||||||
if b == '<' && !cdata {
|
if b == '<' && !cdata {
|
||||||
if quote >= 0 {
|
if quote >= 0 {
|
||||||
p.err = SyntaxError("unescaped < inside quoted string");
|
p.err = SyntaxError("unescaped < inside quoted string")
|
||||||
return nil;
|
return nil
|
||||||
}
|
}
|
||||||
p.ungetc('<');
|
p.ungetc('<')
|
||||||
break Input;
|
break Input
|
||||||
}
|
}
|
||||||
if quote >= 0 && b == byte(quote) {
|
if quote >= 0 && b == byte(quote) {
|
||||||
break Input
|
break Input
|
||||||
|
|
@ -722,17 +722,17 @@ Input:
|
||||||
// its own character names with <!ENTITY ...> directives.
|
// its own character names with <!ENTITY ...> directives.
|
||||||
// Parsers are required to recognize lt, gt, amp, apos, and quot
|
// Parsers are required to recognize lt, gt, amp, apos, and quot
|
||||||
// even if they have not been declared. That's all we allow.
|
// even if they have not been declared. That's all we allow.
|
||||||
var i int;
|
var i int
|
||||||
CharLoop:
|
CharLoop:
|
||||||
for i = 0; i < len(p.tmp); i++ {
|
for i = 0; i < len(p.tmp); i++ {
|
||||||
p.tmp[i], p.err = p.r.ReadByte();
|
p.tmp[i], p.err = p.r.ReadByte()
|
||||||
if p.err != nil {
|
if p.err != nil {
|
||||||
if p.err == os.EOF {
|
if p.err == os.EOF {
|
||||||
p.err = SyntaxError("unexpected EOF")
|
p.err = SyntaxError("unexpected EOF")
|
||||||
}
|
}
|
||||||
return nil;
|
return nil
|
||||||
}
|
}
|
||||||
c := p.tmp[i];
|
c := p.tmp[i]
|
||||||
if c == ';' {
|
if c == ';' {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -742,131 +742,131 @@ Input:
|
||||||
c == '_' || c == '#' {
|
c == '_' || c == '#' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p.ungetc(c);
|
p.ungetc(c)
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
s := string(p.tmp[0:i]);
|
s := string(p.tmp[0:i])
|
||||||
if i >= len(p.tmp) {
|
if i >= len(p.tmp) {
|
||||||
if !p.Strict {
|
if !p.Strict {
|
||||||
b0, b1 = 0, 0;
|
b0, b1 = 0, 0
|
||||||
p.buf.WriteByte('&');
|
p.buf.WriteByte('&')
|
||||||
p.buf.Write(p.tmp[0:i]);
|
p.buf.Write(p.tmp[0:i])
|
||||||
continue Input;
|
continue Input
|
||||||
}
|
}
|
||||||
p.err = SyntaxError("character entity expression &" + s + "... too long");
|
p.err = SyntaxError("character entity expression &" + s + "... too long")
|
||||||
return nil;
|
return nil
|
||||||
}
|
}
|
||||||
var haveText bool;
|
var haveText bool
|
||||||
var text string;
|
var text string
|
||||||
if i >= 2 && s[0] == '#' {
|
if i >= 2 && s[0] == '#' {
|
||||||
var n uint64;
|
var n uint64
|
||||||
var err os.Error;
|
var err os.Error
|
||||||
if i >= 3 && s[1] == 'x' {
|
if i >= 3 && s[1] == 'x' {
|
||||||
n, err = strconv.Btoui64(s[2:], 16)
|
n, err = strconv.Btoui64(s[2:], 16)
|
||||||
} else {
|
} else {
|
||||||
n, err = strconv.Btoui64(s[1:], 10)
|
n, err = strconv.Btoui64(s[1:], 10)
|
||||||
}
|
}
|
||||||
if err == nil && n <= unicode.MaxRune {
|
if err == nil && n <= unicode.MaxRune {
|
||||||
text = string(n);
|
text = string(n)
|
||||||
haveText = true;
|
haveText = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if r, ok := entity[s]; ok {
|
if r, ok := entity[s]; ok {
|
||||||
text = string(r);
|
text = string(r)
|
||||||
haveText = true;
|
haveText = true
|
||||||
} else if p.Entity != nil {
|
} else if p.Entity != nil {
|
||||||
text, haveText = p.Entity[s]
|
text, haveText = p.Entity[s]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !haveText {
|
if !haveText {
|
||||||
if !p.Strict {
|
if !p.Strict {
|
||||||
b0, b1 = 0, 0;
|
b0, b1 = 0, 0
|
||||||
p.buf.WriteByte('&');
|
p.buf.WriteByte('&')
|
||||||
p.buf.Write(p.tmp[0:i]);
|
p.buf.Write(p.tmp[0:i])
|
||||||
continue Input;
|
continue Input
|
||||||
}
|
}
|
||||||
p.err = SyntaxError("invalid character entity &" + s + ";");
|
p.err = SyntaxError("invalid character entity &" + s + ";")
|
||||||
return nil;
|
return nil
|
||||||
}
|
}
|
||||||
p.buf.Write(strings.Bytes(text));
|
p.buf.Write(strings.Bytes(text))
|
||||||
b0, b1 = 0, 0;
|
b0, b1 = 0, 0
|
||||||
continue Input;
|
continue Input
|
||||||
}
|
}
|
||||||
p.buf.WriteByte(b);
|
p.buf.WriteByte(b)
|
||||||
b0, b1 = b1, b;
|
b0, b1 = b1, b
|
||||||
}
|
}
|
||||||
data := p.buf.Bytes();
|
data := p.buf.Bytes()
|
||||||
data = data[0 : len(data)-trunc];
|
data = data[0 : len(data)-trunc]
|
||||||
|
|
||||||
// Must rewrite \r and \r\n into \n.
|
// Must rewrite \r and \r\n into \n.
|
||||||
w := 0;
|
w := 0
|
||||||
for r := 0; r < len(data); r++ {
|
for r := 0; r < len(data); r++ {
|
||||||
b := data[r];
|
b := data[r]
|
||||||
if b == '\r' {
|
if b == '\r' {
|
||||||
if r+1 < len(data) && data[r+1] == '\n' {
|
if r+1 < len(data) && data[r+1] == '\n' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
b = '\n';
|
b = '\n'
|
||||||
}
|
}
|
||||||
data[w] = b;
|
data[w] = b
|
||||||
w++;
|
w++
|
||||||
}
|
}
|
||||||
return data[0:w];
|
return data[0:w]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get name space name: name with a : stuck in the middle.
|
// Get name space name: name with a : stuck in the middle.
|
||||||
// The part before the : is the name space identifier.
|
// The part before the : is the name space identifier.
|
||||||
func (p *Parser) nsname() (name Name, ok bool) {
|
func (p *Parser) nsname() (name Name, ok bool) {
|
||||||
s, ok := p.name();
|
s, ok := p.name()
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := strings.Index(s, ":");
|
i := strings.Index(s, ":")
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
name.Local = s
|
name.Local = s
|
||||||
} else {
|
} else {
|
||||||
name.Space = s[0:i];
|
name.Space = s[0:i]
|
||||||
name.Local = s[i+1:];
|
name.Local = s[i+1:]
|
||||||
}
|
}
|
||||||
return name, true;
|
return name, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get name: /first(first|second)*/
|
// Get name: /first(first|second)*/
|
||||||
// Do not set p.err if the name is missing (unless unexpected EOF is received):
|
// Do not set p.err if the name is missing (unless unexpected EOF is received):
|
||||||
// let the caller provide better context.
|
// let the caller provide better context.
|
||||||
func (p *Parser) name() (s string, ok bool) {
|
func (p *Parser) name() (s string, ok bool) {
|
||||||
var b byte;
|
var b byte
|
||||||
if b, ok = p.mustgetc(); !ok {
|
if b, ok = p.mustgetc(); !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// As a first approximation, we gather the bytes [A-Za-z_:.-\x80-\xFF]*
|
// As a first approximation, we gather the bytes [A-Za-z_:.-\x80-\xFF]*
|
||||||
if b < utf8.RuneSelf && !isNameByte(b) {
|
if b < utf8.RuneSelf && !isNameByte(b) {
|
||||||
p.ungetc(b);
|
p.ungetc(b)
|
||||||
return "", false;
|
return "", false
|
||||||
}
|
}
|
||||||
p.buf.Reset();
|
p.buf.Reset()
|
||||||
p.buf.WriteByte(b);
|
p.buf.WriteByte(b)
|
||||||
for {
|
for {
|
||||||
if b, ok = p.mustgetc(); !ok {
|
if b, ok = p.mustgetc(); !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if b < utf8.RuneSelf && !isNameByte(b) {
|
if b < utf8.RuneSelf && !isNameByte(b) {
|
||||||
p.ungetc(b);
|
p.ungetc(b)
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
p.buf.WriteByte(b);
|
p.buf.WriteByte(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then we check the characters.
|
// Then we check the characters.
|
||||||
s = p.buf.String();
|
s = p.buf.String()
|
||||||
for i, c := range s {
|
for i, c := range s {
|
||||||
if !unicode.Is(first, c) && (i == 0 || !unicode.Is(second, c)) {
|
if !unicode.Is(first, c) && (i == 0 || !unicode.Is(second, c)) {
|
||||||
p.err = SyntaxError("invalid XML name: " + s);
|
p.err = SyntaxError("invalid XML name: " + s)
|
||||||
return "", false;
|
return "", false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s, true;
|
return s, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func isNameByte(c byte) bool {
|
func isNameByte(c byte) bool {
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@
|
||||||
package xml
|
package xml
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io";
|
"io"
|
||||||
"os";
|
"os"
|
||||||
"reflect";
|
"reflect"
|
||||||
"strings";
|
"strings"
|
||||||
"testing";
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
const testInput = `
|
const testInput = `
|
||||||
|
|
@ -146,8 +146,8 @@ var xmlInput = []string{
|
||||||
}
|
}
|
||||||
|
|
||||||
type stringReader struct {
|
type stringReader struct {
|
||||||
s string;
|
s string
|
||||||
off int;
|
off int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *stringReader) Read(b []byte) (n int, err os.Error) {
|
func (r *stringReader) Read(b []byte) (n int, err os.Error) {
|
||||||
|
|
@ -155,29 +155,29 @@ func (r *stringReader) Read(b []byte) (n int, err os.Error) {
|
||||||
return 0, os.EOF
|
return 0, os.EOF
|
||||||
}
|
}
|
||||||
for r.off < len(r.s) && n < len(b) {
|
for r.off < len(r.s) && n < len(b) {
|
||||||
b[n] = r.s[r.off];
|
b[n] = r.s[r.off]
|
||||||
n++;
|
n++
|
||||||
r.off++;
|
r.off++
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *stringReader) ReadByte() (b byte, err os.Error) {
|
func (r *stringReader) ReadByte() (b byte, err os.Error) {
|
||||||
if r.off >= len(r.s) {
|
if r.off >= len(r.s) {
|
||||||
return 0, os.EOF
|
return 0, os.EOF
|
||||||
}
|
}
|
||||||
b = r.s[r.off];
|
b = r.s[r.off]
|
||||||
r.off++;
|
r.off++
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func StringReader(s string) io.Reader { return &stringReader{s, 0} }
|
func StringReader(s string) io.Reader { return &stringReader{s, 0} }
|
||||||
|
|
||||||
func TestRawToken(t *testing.T) {
|
func TestRawToken(t *testing.T) {
|
||||||
p := NewParser(StringReader(testInput));
|
p := NewParser(StringReader(testInput))
|
||||||
|
|
||||||
for i, want := range rawTokens {
|
for i, want := range rawTokens {
|
||||||
have, err := p.RawToken();
|
have, err := p.RawToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("token %d: unexpected error: %s", i, err)
|
t.Fatalf("token %d: unexpected error: %s", i, err)
|
||||||
}
|
}
|
||||||
|
|
@ -188,10 +188,10 @@ func TestRawToken(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestToken(t *testing.T) {
|
func TestToken(t *testing.T) {
|
||||||
p := NewParser(StringReader(testInput));
|
p := NewParser(StringReader(testInput))
|
||||||
|
|
||||||
for i, want := range cookedTokens {
|
for i, want := range cookedTokens {
|
||||||
have, err := p.Token();
|
have, err := p.Token()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("token %d: unexpected error: %s", i, err)
|
t.Fatalf("token %d: unexpected error: %s", i, err)
|
||||||
}
|
}
|
||||||
|
|
@ -203,8 +203,8 @@ func TestToken(t *testing.T) {
|
||||||
|
|
||||||
func TestSyntax(t *testing.T) {
|
func TestSyntax(t *testing.T) {
|
||||||
for i := range xmlInput {
|
for i := range xmlInput {
|
||||||
p := NewParser(StringReader(xmlInput[i]));
|
p := NewParser(StringReader(xmlInput[i]))
|
||||||
var err os.Error;
|
var err os.Error
|
||||||
for _, err = p.Token(); err == nil; _, err = p.Token() {
|
for _, err = p.Token(); err == nil; _, err = p.Token() {
|
||||||
}
|
}
|
||||||
if _, ok := err.(SyntaxError); !ok {
|
if _, ok := err.(SyntaxError); !ok {
|
||||||
|
|
|
||||||
|
|
@ -37,19 +37,19 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag";
|
"flag"
|
||||||
"fmt";
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var n = flag.Int("n", 15, "depth")
|
var n = flag.Int("n", 15, "depth")
|
||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
item int;
|
item int
|
||||||
left, right *Node;
|
left, right *Node
|
||||||
}
|
}
|
||||||
|
|
||||||
type Arena struct {
|
type Arena struct {
|
||||||
head *Node;
|
head *Node
|
||||||
}
|
}
|
||||||
|
|
||||||
var arena Arena
|
var arena Arena
|
||||||
|
|
@ -61,69 +61,69 @@ func (n *Node) free() {
|
||||||
if n.right != nil {
|
if n.right != nil {
|
||||||
n.right.free()
|
n.right.free()
|
||||||
}
|
}
|
||||||
n.left = arena.head;
|
n.left = arena.head
|
||||||
arena.head = n;
|
arena.head = n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Arena) New(item int, left, right *Node) *Node {
|
func (a *Arena) New(item int, left, right *Node) *Node {
|
||||||
if a.head == nil {
|
if a.head == nil {
|
||||||
nodes := make([]Node, 3<<uint(*n));
|
nodes := make([]Node, 3<<uint(*n))
|
||||||
for i := 0; i < len(nodes)-1; i++ {
|
for i := 0; i < len(nodes)-1; i++ {
|
||||||
nodes[i].left = &nodes[i+1]
|
nodes[i].left = &nodes[i+1]
|
||||||
}
|
}
|
||||||
a.head = &nodes[0];
|
a.head = &nodes[0]
|
||||||
}
|
}
|
||||||
n := a.head;
|
n := a.head
|
||||||
a.head = a.head.left;
|
a.head = a.head.left
|
||||||
n.item = item;
|
n.item = item
|
||||||
n.left = left;
|
n.left = left
|
||||||
n.right = right;
|
n.right = right
|
||||||
return n;
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func bottomUpTree(item, depth int) *Node {
|
func bottomUpTree(item, depth int) *Node {
|
||||||
if depth <= 0 {
|
if depth <= 0 {
|
||||||
return arena.New(item, nil, nil)
|
return arena.New(item, nil, nil)
|
||||||
}
|
}
|
||||||
return arena.New(item, bottomUpTree(2*item-1, depth-1), bottomUpTree(2*item, depth-1));
|
return arena.New(item, bottomUpTree(2*item-1, depth-1), bottomUpTree(2*item, depth-1))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) itemCheck() int {
|
func (n *Node) itemCheck() int {
|
||||||
if n.left == nil {
|
if n.left == nil {
|
||||||
return n.item
|
return n.item
|
||||||
}
|
}
|
||||||
return n.item + n.left.itemCheck() - n.right.itemCheck();
|
return n.item + n.left.itemCheck() - n.right.itemCheck()
|
||||||
}
|
}
|
||||||
|
|
||||||
const minDepth = 4
|
const minDepth = 4
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse();
|
flag.Parse()
|
||||||
|
|
||||||
maxDepth := *n;
|
maxDepth := *n
|
||||||
if minDepth+2 > *n {
|
if minDepth+2 > *n {
|
||||||
maxDepth = minDepth + 2
|
maxDepth = minDepth + 2
|
||||||
}
|
}
|
||||||
stretchDepth := maxDepth + 1;
|
stretchDepth := maxDepth + 1
|
||||||
|
|
||||||
check := bottomUpTree(0, stretchDepth).itemCheck();
|
check := bottomUpTree(0, stretchDepth).itemCheck()
|
||||||
fmt.Printf("stretch tree of depth %d\t check: %d\n", stretchDepth, check);
|
fmt.Printf("stretch tree of depth %d\t check: %d\n", stretchDepth, check)
|
||||||
|
|
||||||
longLivedTree := bottomUpTree(0, maxDepth);
|
longLivedTree := bottomUpTree(0, maxDepth)
|
||||||
|
|
||||||
for depth := minDepth; depth <= maxDepth; depth += 2 {
|
for depth := minDepth; depth <= maxDepth; depth += 2 {
|
||||||
iterations := 1 << uint(maxDepth-depth+minDepth);
|
iterations := 1 << uint(maxDepth-depth+minDepth)
|
||||||
check = 0;
|
check = 0
|
||||||
|
|
||||||
for i := 1; i <= iterations; i++ {
|
for i := 1; i <= iterations; i++ {
|
||||||
t := bottomUpTree(i, depth);
|
t := bottomUpTree(i, depth)
|
||||||
check += t.itemCheck();
|
check += t.itemCheck()
|
||||||
t.free();
|
t.free()
|
||||||
t = bottomUpTree(-i, depth);
|
t = bottomUpTree(-i, depth)
|
||||||
check += t.itemCheck();
|
check += t.itemCheck()
|
||||||
t.free();
|
t.free()
|
||||||
}
|
}
|
||||||
fmt.Printf("%d\t trees of depth %d\t check: %d\n", iterations*2, depth, check);
|
fmt.Printf("%d\t trees of depth %d\t check: %d\n", iterations*2, depth, check)
|
||||||
}
|
}
|
||||||
fmt.Printf("long lived tree of depth %d\t check: %d\n", maxDepth, longLivedTree.itemCheck());
|
fmt.Printf("long lived tree of depth %d\t check: %d\n", maxDepth, longLivedTree.itemCheck())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,56 +37,56 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag";
|
"flag"
|
||||||
"fmt";
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var n = flag.Int("n", 15, "depth")
|
var n = flag.Int("n", 15, "depth")
|
||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
item int;
|
item int
|
||||||
left, right *Node;
|
left, right *Node
|
||||||
}
|
}
|
||||||
|
|
||||||
func bottomUpTree(item, depth int) *Node {
|
func bottomUpTree(item, depth int) *Node {
|
||||||
if depth <= 0 {
|
if depth <= 0 {
|
||||||
return &Node{item: item}
|
return &Node{item: item}
|
||||||
}
|
}
|
||||||
return &Node{item, bottomUpTree(2*item-1, depth-1), bottomUpTree(2*item, depth-1)};
|
return &Node{item, bottomUpTree(2*item-1, depth-1), bottomUpTree(2*item, depth-1)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) itemCheck() int {
|
func (n *Node) itemCheck() int {
|
||||||
if n.left == nil {
|
if n.left == nil {
|
||||||
return n.item
|
return n.item
|
||||||
}
|
}
|
||||||
return n.item + n.left.itemCheck() - n.right.itemCheck();
|
return n.item + n.left.itemCheck() - n.right.itemCheck()
|
||||||
}
|
}
|
||||||
|
|
||||||
const minDepth = 4
|
const minDepth = 4
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse();
|
flag.Parse()
|
||||||
|
|
||||||
maxDepth := *n;
|
maxDepth := *n
|
||||||
if minDepth+2 > *n {
|
if minDepth+2 > *n {
|
||||||
maxDepth = minDepth + 2
|
maxDepth = minDepth + 2
|
||||||
}
|
}
|
||||||
stretchDepth := maxDepth + 1;
|
stretchDepth := maxDepth + 1
|
||||||
|
|
||||||
check := bottomUpTree(0, stretchDepth).itemCheck();
|
check := bottomUpTree(0, stretchDepth).itemCheck()
|
||||||
fmt.Printf("stretch tree of depth %d\t check: %d\n", stretchDepth, check);
|
fmt.Printf("stretch tree of depth %d\t check: %d\n", stretchDepth, check)
|
||||||
|
|
||||||
longLivedTree := bottomUpTree(0, maxDepth);
|
longLivedTree := bottomUpTree(0, maxDepth)
|
||||||
|
|
||||||
for depth := minDepth; depth <= maxDepth; depth += 2 {
|
for depth := minDepth; depth <= maxDepth; depth += 2 {
|
||||||
iterations := 1 << uint(maxDepth-depth+minDepth);
|
iterations := 1 << uint(maxDepth-depth+minDepth)
|
||||||
check = 0;
|
check = 0
|
||||||
|
|
||||||
for i := 1; i <= iterations; i++ {
|
for i := 1; i <= iterations; i++ {
|
||||||
check += bottomUpTree(i, depth).itemCheck();
|
check += bottomUpTree(i, depth).itemCheck()
|
||||||
check += bottomUpTree(-i, depth).itemCheck();
|
check += bottomUpTree(-i, depth).itemCheck()
|
||||||
}
|
}
|
||||||
fmt.Printf("%d\t trees of depth %d\t check: %d\n", iterations*2, depth, check);
|
fmt.Printf("%d\t trees of depth %d\t check: %d\n", iterations*2, depth, check)
|
||||||
}
|
}
|
||||||
fmt.Printf("long lived tree of depth %d\t check: %d\n", maxDepth, longLivedTree.itemCheck());
|
fmt.Printf("long lived tree of depth %d\t check: %d\n", maxDepth, longLivedTree.itemCheck())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,16 +36,16 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag";
|
"flag"
|
||||||
"fmt";
|
"fmt"
|
||||||
"strconv";
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
blue = iota;
|
blue = iota
|
||||||
red;
|
red
|
||||||
yellow;
|
yellow
|
||||||
ncol;
|
ncol
|
||||||
)
|
)
|
||||||
|
|
||||||
var complement = [...]int{
|
var complement = [...]int{
|
||||||
|
|
@ -68,8 +68,8 @@ var colname = [...]string{
|
||||||
|
|
||||||
// information about the current state of a creature.
|
// information about the current state of a creature.
|
||||||
type info struct {
|
type info struct {
|
||||||
colour int; // creature's current colour.
|
colour int // creature's current colour.
|
||||||
name int; // creature's name.
|
name int // creature's name.
|
||||||
}
|
}
|
||||||
|
|
||||||
// exclusive access data-structure kept inside meetingplace.
|
// exclusive access data-structure kept inside meetingplace.
|
||||||
|
|
@ -77,21 +77,21 @@ type info struct {
|
||||||
// otherwise the creature's info is stored in info, and
|
// otherwise the creature's info is stored in info, and
|
||||||
// it is waiting to receive its mate's information on the mate channel.
|
// it is waiting to receive its mate's information on the mate channel.
|
||||||
type rendez struct {
|
type rendez struct {
|
||||||
n int; // current number of encounters.
|
n int // current number of encounters.
|
||||||
mate chan<- info; // creature waiting when non-nil.
|
mate chan<- info // creature waiting when non-nil.
|
||||||
info info; // info about creature waiting.
|
info info // info about creature waiting.
|
||||||
}
|
}
|
||||||
|
|
||||||
// result sent by each creature at the end of processing.
|
// result sent by each creature at the end of processing.
|
||||||
type result struct {
|
type result struct {
|
||||||
met int;
|
met int
|
||||||
same int;
|
same int
|
||||||
}
|
}
|
||||||
|
|
||||||
var n = 600
|
var n = 600
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse();
|
flag.Parse()
|
||||||
if flag.NArg() > 0 {
|
if flag.NArg() > 0 {
|
||||||
n, _ = strconv.Atoi(flag.Arg(0))
|
n, _ = strconv.Atoi(flag.Arg(0))
|
||||||
}
|
}
|
||||||
|
|
@ -101,72 +101,72 @@ func main() {
|
||||||
fmt.Printf("%s + %s -> %s\n", colname[c0], colname[c1], colname[complement[c0|c1<<2]])
|
fmt.Printf("%s + %s -> %s\n", colname[c0], colname[c1], colname[complement[c0|c1<<2]])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Print("\n");
|
fmt.Print("\n")
|
||||||
|
|
||||||
pallmall([]int{blue, red, yellow});
|
pallmall([]int{blue, red, yellow})
|
||||||
pallmall([]int{blue, red, yellow, red, yellow, blue, red, yellow, red, blue});
|
pallmall([]int{blue, red, yellow, red, yellow, blue, red, yellow, red, blue})
|
||||||
}
|
}
|
||||||
|
|
||||||
func pallmall(cols []int) {
|
func pallmall(cols []int) {
|
||||||
|
|
||||||
// invariant: meetingplace always contains a value unless a creature
|
// invariant: meetingplace always contains a value unless a creature
|
||||||
// is currently dealing with it (whereupon it must put it back).
|
// is currently dealing with it (whereupon it must put it back).
|
||||||
meetingplace := make(chan rendez, 1);
|
meetingplace := make(chan rendez, 1)
|
||||||
meetingplace <- rendez{n: 0};
|
meetingplace <- rendez{n: 0}
|
||||||
|
|
||||||
ended := make(chan result);
|
ended := make(chan result)
|
||||||
msg := "";
|
msg := ""
|
||||||
for i, col := range cols {
|
for i, col := range cols {
|
||||||
go creature(info{col, i}, meetingplace, ended);
|
go creature(info{col, i}, meetingplace, ended)
|
||||||
msg += " " + colname[col];
|
msg += " " + colname[col]
|
||||||
}
|
}
|
||||||
fmt.Println(msg);
|
fmt.Println(msg)
|
||||||
tot := 0;
|
tot := 0
|
||||||
// wait for all results
|
// wait for all results
|
||||||
for _ = range (cols) {
|
for _ = range (cols) {
|
||||||
result := <-ended;
|
result := <-ended
|
||||||
tot += result.met;
|
tot += result.met
|
||||||
fmt.Printf("%v%v\n", result.met, spell(result.same, true));
|
fmt.Printf("%v%v\n", result.met, spell(result.same, true))
|
||||||
}
|
}
|
||||||
fmt.Printf("%v\n\n", spell(tot, true));
|
fmt.Printf("%v\n\n", spell(tot, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// in this function, variables ending in 0 refer to the local creature,
|
// in this function, variables ending in 0 refer to the local creature,
|
||||||
// variables ending in 1 to the creature we've met.
|
// variables ending in 1 to the creature we've met.
|
||||||
func creature(info0 info, meetingplace chan rendez, ended chan result) {
|
func creature(info0 info, meetingplace chan rendez, ended chan result) {
|
||||||
c0 := make(chan info);
|
c0 := make(chan info)
|
||||||
met := 0;
|
met := 0
|
||||||
same := 0;
|
same := 0
|
||||||
for {
|
for {
|
||||||
var othername int;
|
var othername int
|
||||||
// get access to rendez data and decide what to do.
|
// get access to rendez data and decide what to do.
|
||||||
switch r := <-meetingplace; {
|
switch r := <-meetingplace; {
|
||||||
case r.n >= n:
|
case r.n >= n:
|
||||||
// if no more meetings left, then send our result data and exit.
|
// if no more meetings left, then send our result data and exit.
|
||||||
meetingplace <- rendez{n: r.n};
|
meetingplace <- rendez{n: r.n}
|
||||||
ended <- result{met, same};
|
ended <- result{met, same}
|
||||||
return;
|
return
|
||||||
case r.mate == nil:
|
case r.mate == nil:
|
||||||
// no creature waiting; wait for someone to meet us,
|
// no creature waiting; wait for someone to meet us,
|
||||||
// get their info and send our info in reply.
|
// get their info and send our info in reply.
|
||||||
meetingplace <- rendez{n: r.n, info: info0, mate: c0};
|
meetingplace <- rendez{n: r.n, info: info0, mate: c0}
|
||||||
info1 := <-c0;
|
info1 := <-c0
|
||||||
othername = info1.name;
|
othername = info1.name
|
||||||
info0.colour = complement[info0.colour|info1.colour<<2];
|
info0.colour = complement[info0.colour|info1.colour<<2]
|
||||||
default:
|
default:
|
||||||
// another creature is waiting for us with its info;
|
// another creature is waiting for us with its info;
|
||||||
// increment meeting count,
|
// increment meeting count,
|
||||||
// send them our info in reply.
|
// send them our info in reply.
|
||||||
r.n++;
|
r.n++
|
||||||
meetingplace <- rendez{n: r.n, mate: nil};
|
meetingplace <- rendez{n: r.n, mate: nil}
|
||||||
r.mate <- info0;
|
r.mate <- info0
|
||||||
othername = r.info.name;
|
othername = r.info.name
|
||||||
info0.colour = complement[info0.colour|r.info.colour<<2];
|
info0.colour = complement[info0.colour|r.info.colour<<2]
|
||||||
}
|
}
|
||||||
if othername == info0.name {
|
if othername == info0.name {
|
||||||
same++
|
same++
|
||||||
}
|
}
|
||||||
met++;
|
met++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,5 +176,5 @@ func spell(n int, required bool) string {
|
||||||
if n == 0 && !required {
|
if n == 0 && !required {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return spell(n/10, false) + " " + digits[n%10];
|
return spell(n/10, false) + " " + digits[n%10]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag";
|
"flag"
|
||||||
"fmt";
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var n = flag.Int("n", 7, "count")
|
var n = flag.Int("n", 7, "count")
|
||||||
|
|
@ -49,45 +49,45 @@ func fannkuch(n int) int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
n1 := n - 1;
|
n1 := n - 1
|
||||||
perm := make([]int, n);
|
perm := make([]int, n)
|
||||||
perm1 := make([]int, n);
|
perm1 := make([]int, n)
|
||||||
count := make([]int, n);
|
count := make([]int, n)
|
||||||
|
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
perm1[i] = i // initial (trivial) permutation
|
perm1[i] = i // initial (trivial) permutation
|
||||||
}
|
}
|
||||||
|
|
||||||
r := n;
|
r := n
|
||||||
didpr := 0;
|
didpr := 0
|
||||||
flipsMax := 0;
|
flipsMax := 0
|
||||||
for {
|
for {
|
||||||
if didpr < 30 {
|
if didpr < 30 {
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
fmt.Printf("%d", 1+perm1[i])
|
fmt.Printf("%d", 1+perm1[i])
|
||||||
}
|
}
|
||||||
fmt.Printf("\n");
|
fmt.Printf("\n")
|
||||||
didpr++;
|
didpr++
|
||||||
}
|
}
|
||||||
for ; r != 1; r-- {
|
for ; r != 1; r-- {
|
||||||
count[r-1] = r
|
count[r-1] = r
|
||||||
}
|
}
|
||||||
|
|
||||||
if perm1[0] != 0 && perm1[n1] != n1 {
|
if perm1[0] != 0 && perm1[n1] != n1 {
|
||||||
flips := 0;
|
flips := 0
|
||||||
for i := 1; i < n; i++ { // perm = perm1
|
for i := 1; i < n; i++ { // perm = perm1
|
||||||
perm[i] = perm1[i]
|
perm[i] = perm1[i]
|
||||||
}
|
}
|
||||||
k := perm1[0]; // cache perm[0] in k
|
k := perm1[0] // cache perm[0] in k
|
||||||
for { // k!=0 ==> k>0
|
for { // k!=0 ==> k>0
|
||||||
for i, j := 1, k-1; i < j; i, j = i+1, j-1 {
|
for i, j := 1, k-1; i < j; i, j = i+1, j-1 {
|
||||||
perm[i], perm[j] = perm[j], perm[i]
|
perm[i], perm[j] = perm[j], perm[i]
|
||||||
}
|
}
|
||||||
flips++;
|
flips++
|
||||||
// Now exchange k (caching perm[0]) and perm[k]... with care!
|
// Now exchange k (caching perm[0]) and perm[k]... with care!
|
||||||
j := perm[k];
|
j := perm[k]
|
||||||
perm[k] = k;
|
perm[k] = k
|
||||||
k = j;
|
k = j
|
||||||
if k == 0 {
|
if k == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -99,12 +99,12 @@ func fannkuch(n int) int {
|
||||||
|
|
||||||
for ; r < n; r++ {
|
for ; r < n; r++ {
|
||||||
// rotate down perm[0..r] by one
|
// rotate down perm[0..r] by one
|
||||||
perm0 := perm1[0];
|
perm0 := perm1[0]
|
||||||
for i := 0; i < r; i++ {
|
for i := 0; i < r; i++ {
|
||||||
perm1[i] = perm1[i+1]
|
perm1[i] = perm1[i+1]
|
||||||
}
|
}
|
||||||
perm1[r] = perm0;
|
perm1[r] = perm0
|
||||||
count[r]--;
|
count[r]--
|
||||||
if count[r] > 0 {
|
if count[r] > 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -113,10 +113,10 @@ func fannkuch(n int) int {
|
||||||
return flipsMax
|
return flipsMax
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse();
|
flag.Parse()
|
||||||
fmt.Printf("Pfannkuchen(%d) = %d\n", *n, fannkuch(*n));
|
fmt.Printf("Pfannkuchen(%d) = %d\n", *n, fannkuch(*n))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,10 +38,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio";
|
"bufio"
|
||||||
"flag";
|
"flag"
|
||||||
"os";
|
"os"
|
||||||
"strings";
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var out *bufio.Writer
|
var out *bufio.Writer
|
||||||
|
|
@ -54,12 +54,12 @@ func min(a, b int) int {
|
||||||
if a < b {
|
if a < b {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
return b;
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
type AminoAcid struct {
|
type AminoAcid struct {
|
||||||
p float;
|
p float
|
||||||
c byte;
|
c byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func AccumulateProbabilities(genelist []AminoAcid) {
|
func AccumulateProbabilities(genelist []AminoAcid) {
|
||||||
|
|
@ -74,28 +74,28 @@ func AccumulateProbabilities(genelist []AminoAcid) {
|
||||||
// After each WIDTH characters it prints a newline.
|
// After each WIDTH characters it prints a newline.
|
||||||
// It assumes that WIDTH <= len(s) + 1.
|
// It assumes that WIDTH <= len(s) + 1.
|
||||||
func RepeatFasta(s []byte, count int) {
|
func RepeatFasta(s []byte, count int) {
|
||||||
pos := 0;
|
pos := 0
|
||||||
s2 := make([]byte, len(s)+WIDTH);
|
s2 := make([]byte, len(s)+WIDTH)
|
||||||
copy(s2, s);
|
copy(s2, s)
|
||||||
copy(s2[len(s):], s);
|
copy(s2[len(s):], s)
|
||||||
for count > 0 {
|
for count > 0 {
|
||||||
line := min(WIDTH, count);
|
line := min(WIDTH, count)
|
||||||
out.Write(s2[pos : pos+line]);
|
out.Write(s2[pos : pos+line])
|
||||||
out.WriteByte('\n');
|
out.WriteByte('\n')
|
||||||
pos += line;
|
pos += line
|
||||||
if pos >= len(s) {
|
if pos >= len(s) {
|
||||||
pos -= len(s)
|
pos -= len(s)
|
||||||
}
|
}
|
||||||
count -= line;
|
count -= line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var lastrandom uint32 = 42
|
var lastrandom uint32 = 42
|
||||||
|
|
||||||
const (
|
const (
|
||||||
IM = 139968;
|
IM = 139968
|
||||||
IA = 3877;
|
IA = 3877
|
||||||
IC = 29573;
|
IC = 29573
|
||||||
)
|
)
|
||||||
|
|
||||||
// Each element of genelist is a struct with a character and
|
// Each element of genelist is a struct with a character and
|
||||||
|
|
@ -107,31 +107,31 @@ const (
|
||||||
// This sequence is repeated count times.
|
// This sequence is repeated count times.
|
||||||
// Between each WIDTH consecutive characters, the function prints a newline.
|
// Between each WIDTH consecutive characters, the function prints a newline.
|
||||||
func RandomFasta(genelist []AminoAcid, count int) {
|
func RandomFasta(genelist []AminoAcid, count int) {
|
||||||
buf := make([]byte, WIDTH+1);
|
buf := make([]byte, WIDTH+1)
|
||||||
for count > 0 {
|
for count > 0 {
|
||||||
line := min(WIDTH, count);
|
line := min(WIDTH, count)
|
||||||
for pos := 0; pos < line; pos++ {
|
for pos := 0; pos < line; pos++ {
|
||||||
lastrandom = (lastrandom*IA + IC) % IM;
|
lastrandom = (lastrandom*IA + IC) % IM
|
||||||
// Integer to float conversions are faster if the integer is signed.
|
// Integer to float conversions are faster if the integer is signed.
|
||||||
r := float(int32(lastrandom)) / IM;
|
r := float(int32(lastrandom)) / IM
|
||||||
for _, v := range genelist {
|
for _, v := range genelist {
|
||||||
if v.p >= r {
|
if v.p >= r {
|
||||||
buf[pos] = v.c;
|
buf[pos] = v.c
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf[line] = '\n';
|
buf[line] = '\n'
|
||||||
out.Write(buf[0 : line+1]);
|
out.Write(buf[0 : line+1])
|
||||||
count -= line;
|
count -= line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
out = bufio.NewWriter(os.Stdout);
|
out = bufio.NewWriter(os.Stdout)
|
||||||
defer out.Flush();
|
defer out.Flush()
|
||||||
|
|
||||||
flag.Parse();
|
flag.Parse()
|
||||||
|
|
||||||
iub := []AminoAcid{
|
iub := []AminoAcid{
|
||||||
AminoAcid{0.27, 'a'},
|
AminoAcid{0.27, 'a'},
|
||||||
|
|
@ -149,17 +149,17 @@ func main() {
|
||||||
AminoAcid{0.02, 'V'},
|
AminoAcid{0.02, 'V'},
|
||||||
AminoAcid{0.02, 'W'},
|
AminoAcid{0.02, 'W'},
|
||||||
AminoAcid{0.02, 'Y'},
|
AminoAcid{0.02, 'Y'},
|
||||||
};
|
}
|
||||||
|
|
||||||
homosapiens := []AminoAcid{
|
homosapiens := []AminoAcid{
|
||||||
AminoAcid{0.3029549426680, 'a'},
|
AminoAcid{0.3029549426680, 'a'},
|
||||||
AminoAcid{0.1979883004921, 'c'},
|
AminoAcid{0.1979883004921, 'c'},
|
||||||
AminoAcid{0.1975473066391, 'g'},
|
AminoAcid{0.1975473066391, 'g'},
|
||||||
AminoAcid{0.3015094502008, 't'},
|
AminoAcid{0.3015094502008, 't'},
|
||||||
};
|
}
|
||||||
|
|
||||||
AccumulateProbabilities(iub);
|
AccumulateProbabilities(iub)
|
||||||
AccumulateProbabilities(homosapiens);
|
AccumulateProbabilities(homosapiens)
|
||||||
|
|
||||||
alu := strings.Bytes(
|
alu := strings.Bytes(
|
||||||
"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG" +
|
"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG" +
|
||||||
|
|
@ -168,12 +168,12 @@ func main() {
|
||||||
"ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA" +
|
"ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA" +
|
||||||
"GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG" +
|
"GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG" +
|
||||||
"AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC" +
|
"AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC" +
|
||||||
"AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA");
|
"AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA")
|
||||||
|
|
||||||
out.WriteString(">ONE Homo sapiens alu\n");
|
out.WriteString(">ONE Homo sapiens alu\n")
|
||||||
RepeatFasta(alu, 2**n);
|
RepeatFasta(alu, 2**n)
|
||||||
out.WriteString(">TWO IUB ambiguity codes\n");
|
out.WriteString(">TWO IUB ambiguity codes\n")
|
||||||
RandomFasta(iub, 3**n);
|
RandomFasta(iub, 3**n)
|
||||||
out.WriteString(">THREE Homo sapiens frequency\n");
|
out.WriteString(">THREE Homo sapiens frequency\n")
|
||||||
RandomFasta(homosapiens, 5**n);
|
RandomFasta(homosapiens, 5**n)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,43 +36,43 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio";
|
"bufio"
|
||||||
"bytes";
|
"bytes"
|
||||||
"fmt";
|
"fmt"
|
||||||
"io/ioutil";
|
"io/ioutil"
|
||||||
"os";
|
"os"
|
||||||
"sort";
|
"sort"
|
||||||
"strings";
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var in *bufio.Reader
|
var in *bufio.Reader
|
||||||
|
|
||||||
func count(data string, n int) map[string]int {
|
func count(data string, n int) map[string]int {
|
||||||
counts := make(map[string]int);
|
counts := make(map[string]int)
|
||||||
top := len(data) - n;
|
top := len(data) - n
|
||||||
for i := 0; i <= top; i++ {
|
for i := 0; i <= top; i++ {
|
||||||
s := data[i : i+n];
|
s := data[i : i+n]
|
||||||
if k, ok := counts[s]; ok {
|
if k, ok := counts[s]; ok {
|
||||||
counts[s] = k + 1
|
counts[s] = k + 1
|
||||||
} else {
|
} else {
|
||||||
counts[s] = 1
|
counts[s] = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return counts;
|
return counts
|
||||||
}
|
}
|
||||||
|
|
||||||
func countOne(data string, s string) int {
|
func countOne(data string, s string) int {
|
||||||
counts := count(data, len(s));
|
counts := count(data, len(s))
|
||||||
if i, ok := counts[s]; ok {
|
if i, ok := counts[s]; ok {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type kNuc struct {
|
type kNuc struct {
|
||||||
name string;
|
name string
|
||||||
count int;
|
count int
|
||||||
}
|
}
|
||||||
|
|
||||||
type kNucArray []kNuc
|
type kNucArray []kNuc
|
||||||
|
|
@ -83,24 +83,24 @@ func (kn kNucArray) Less(i, j int) bool {
|
||||||
if kn[i].count == kn[j].count {
|
if kn[i].count == kn[j].count {
|
||||||
return kn[i].name > kn[j].name // sort down
|
return kn[i].name > kn[j].name // sort down
|
||||||
}
|
}
|
||||||
return kn[i].count > kn[j].count;
|
return kn[i].count > kn[j].count
|
||||||
}
|
}
|
||||||
|
|
||||||
func sortedArray(m map[string]int) kNucArray {
|
func sortedArray(m map[string]int) kNucArray {
|
||||||
kn := make(kNucArray, len(m));
|
kn := make(kNucArray, len(m))
|
||||||
i := 0;
|
i := 0
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
kn[i].name = k;
|
kn[i].name = k
|
||||||
kn[i].count = v;
|
kn[i].count = v
|
||||||
i++;
|
i++
|
||||||
}
|
}
|
||||||
sort.Sort(kn);
|
sort.Sort(kn)
|
||||||
return kn;
|
return kn
|
||||||
}
|
}
|
||||||
|
|
||||||
func print(m map[string]int) {
|
func print(m map[string]int) {
|
||||||
a := sortedArray(m);
|
a := sortedArray(m)
|
||||||
sum := 0;
|
sum := 0
|
||||||
for _, kn := range a {
|
for _, kn := range a {
|
||||||
sum += kn.count
|
sum += kn.count
|
||||||
}
|
}
|
||||||
|
|
@ -110,40 +110,40 @@ func print(m map[string]int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
in = bufio.NewReader(os.Stdin);
|
in = bufio.NewReader(os.Stdin)
|
||||||
three := strings.Bytes(">THREE ");
|
three := strings.Bytes(">THREE ")
|
||||||
for {
|
for {
|
||||||
line, err := in.ReadSlice('\n');
|
line, err := in.ReadSlice('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "ReadLine err:", err);
|
fmt.Fprintln(os.Stderr, "ReadLine err:", err)
|
||||||
os.Exit(2);
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
if line[0] == '>' && bytes.Equal(line[0:len(three)], three) {
|
if line[0] == '>' && bytes.Equal(line[0:len(three)], three) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data, err := ioutil.ReadAll(in);
|
data, err := ioutil.ReadAll(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "ReadAll err:", err);
|
fmt.Fprintln(os.Stderr, "ReadAll err:", err)
|
||||||
os.Exit(2);
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
// delete the newlines and convert to upper case
|
// delete the newlines and convert to upper case
|
||||||
j := 0;
|
j := 0
|
||||||
for i := 0; i < len(data); i++ {
|
for i := 0; i < len(data); i++ {
|
||||||
if data[i] != '\n' {
|
if data[i] != '\n' {
|
||||||
data[j] = data[i] &^ ' '; // upper case
|
data[j] = data[i] &^ ' ' // upper case
|
||||||
j++;
|
j++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
str := string(data[0:j]);
|
str := string(data[0:j])
|
||||||
|
|
||||||
print(count(str, 1));
|
print(count(str, 1))
|
||||||
fmt.Print("\n");
|
fmt.Print("\n")
|
||||||
|
|
||||||
print(count(str, 2));
|
print(count(str, 2))
|
||||||
fmt.Print("\n");
|
fmt.Print("\n")
|
||||||
|
|
||||||
interests := []string{"GGT", "GGTA", "GGTATT", "GGTATTTTAATT", "GGTATTTTAATTTATAGT"};
|
interests := []string{"GGT", "GGTA", "GGTATT", "GGTATTTTAATT", "GGTATTTTAATTTATAGT"}
|
||||||
for _, s := range interests {
|
for _, s := range interests {
|
||||||
fmt.Printf("%d %s\n", countOne(str, s), s)
|
fmt.Printf("%d %s\n", countOne(str, s), s)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,58 +37,58 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio";
|
"bufio"
|
||||||
"flag";
|
"flag"
|
||||||
"fmt";
|
"fmt"
|
||||||
"os";
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
var n = flag.Int("n", 200, "size")
|
var n = flag.Int("n", 200, "size")
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse();
|
flag.Parse()
|
||||||
out := bufio.NewWriter(os.Stdout);
|
out := bufio.NewWriter(os.Stdout)
|
||||||
defer out.Flush();
|
defer out.Flush()
|
||||||
|
|
||||||
w := *n;
|
w := *n
|
||||||
h := *n;
|
h := *n
|
||||||
bit_num := 0;
|
bit_num := 0
|
||||||
byte_acc := byte(0);
|
byte_acc := byte(0)
|
||||||
const Iter = 50;
|
const Iter = 50
|
||||||
const Zero float64 = 0;
|
const Zero float64 = 0
|
||||||
const Limit = 2.0;
|
const Limit = 2.0
|
||||||
|
|
||||||
fmt.Fprintf(out, "P4\n%d %d\n", w, h);
|
fmt.Fprintf(out, "P4\n%d %d\n", w, h)
|
||||||
|
|
||||||
for y := 0; y < h; y++ {
|
for y := 0; y < h; y++ {
|
||||||
for x := 0; x < w; x++ {
|
for x := 0; x < w; x++ {
|
||||||
Zr, Zi, Tr, Ti := Zero, Zero, Zero, Zero;
|
Zr, Zi, Tr, Ti := Zero, Zero, Zero, Zero
|
||||||
Cr := (2*float64(x)/float64(w) - 1.5);
|
Cr := (2*float64(x)/float64(w) - 1.5)
|
||||||
Ci := (2*float64(y)/float64(h) - 1.0);
|
Ci := (2*float64(y)/float64(h) - 1.0)
|
||||||
|
|
||||||
for i := 0; i < Iter && (Tr+Ti <= Limit*Limit); i++ {
|
for i := 0; i < Iter && (Tr+Ti <= Limit*Limit); i++ {
|
||||||
Zi = 2*Zr*Zi + Ci;
|
Zi = 2*Zr*Zi + Ci
|
||||||
Zr = Tr - Ti + Cr;
|
Zr = Tr - Ti + Cr
|
||||||
Tr = Zr * Zr;
|
Tr = Zr * Zr
|
||||||
Ti = Zi * Zi;
|
Ti = Zi * Zi
|
||||||
}
|
}
|
||||||
|
|
||||||
byte_acc <<= 1;
|
byte_acc <<= 1
|
||||||
if Tr+Ti <= Limit*Limit {
|
if Tr+Ti <= Limit*Limit {
|
||||||
byte_acc |= 0x01
|
byte_acc |= 0x01
|
||||||
}
|
}
|
||||||
|
|
||||||
bit_num++;
|
bit_num++
|
||||||
|
|
||||||
if bit_num == 8 {
|
if bit_num == 8 {
|
||||||
out.WriteByte(byte_acc);
|
out.WriteByte(byte_acc)
|
||||||
byte_acc = 0;
|
byte_acc = 0
|
||||||
bit_num = 0;
|
bit_num = 0
|
||||||
} else if x == w-1 {
|
} else if x == w-1 {
|
||||||
byte_acc <<= uint(8 - w%8);
|
byte_acc <<= uint(8 - w%8)
|
||||||
out.WriteByte(byte_acc);
|
out.WriteByte(byte_acc)
|
||||||
byte_acc = 0;
|
byte_acc = 0
|
||||||
bit_num = 0;
|
bit_num = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag";
|
"flag"
|
||||||
"fmt";
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var max_solutions = flag.Int("n", 2100, "maximum number of solutions")
|
var max_solutions = flag.Int("n", 2100, "maximum number of solutions")
|
||||||
|
|
@ -48,7 +48,7 @@ func boolInt(b bool) int8 {
|
||||||
if b {
|
if b {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The board is a 50 cell hexagonal pattern. For . . . . .
|
/* The board is a 50 cell hexagonal pattern. For . . . . .
|
||||||
|
|
@ -87,19 +87,19 @@ var board uint64 = 0xFFFC000000000000
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const (
|
const (
|
||||||
E = iota;
|
E = iota
|
||||||
ESE;
|
ESE
|
||||||
SE;
|
SE
|
||||||
S;
|
S
|
||||||
SW;
|
SW
|
||||||
WSW;
|
WSW
|
||||||
W;
|
W
|
||||||
WNW;
|
WNW
|
||||||
NW;
|
NW
|
||||||
N;
|
N
|
||||||
NE;
|
NE
|
||||||
ENE;
|
ENE
|
||||||
PIVOT;
|
PIVOT
|
||||||
)
|
)
|
||||||
|
|
||||||
var piece_def = [10][4]int8{
|
var piece_def = [10][4]int8{
|
||||||
|
|
@ -127,9 +127,9 @@ var piece_def = [10][4]int8{
|
||||||
* location to reduce the burden on the solve function.
|
* location to reduce the burden on the solve function.
|
||||||
*/
|
*/
|
||||||
var (
|
var (
|
||||||
pieces [10][50][12]uint64;
|
pieces [10][50][12]uint64
|
||||||
piece_counts [10][50]int;
|
piece_counts [10][50]int
|
||||||
next_cell [10][50][12]int8;
|
next_cell [10][50][12]int8
|
||||||
)
|
)
|
||||||
|
|
||||||
/* Returns the direction rotated 60 degrees clockwise */
|
/* Returns the direction rotated 60 degrees clockwise */
|
||||||
|
|
@ -203,7 +203,7 @@ func shift(cell, dir int8) int8 {
|
||||||
return cell - 4
|
return cell - 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cell;
|
return cell
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns wether the specified cell and direction will land outside
|
/* Returns wether the specified cell and direction will land outside
|
||||||
|
|
@ -215,8 +215,8 @@ func out_of_bounds(cell, dir int8) bool {
|
||||||
case E:
|
case E:
|
||||||
return cell%5 == 4
|
return cell%5 == 4
|
||||||
case ESE:
|
case ESE:
|
||||||
i := cell % 10;
|
i := cell % 10
|
||||||
return i == 4 || i == 8 || i == 9 || cell >= 45;
|
return i == 4 || i == 8 || i == 9 || cell >= 45
|
||||||
case SE:
|
case SE:
|
||||||
return cell%10 == 9 || cell >= 45
|
return cell%10 == 9 || cell >= 45
|
||||||
case S:
|
case S:
|
||||||
|
|
@ -224,13 +224,13 @@ func out_of_bounds(cell, dir int8) bool {
|
||||||
case SW:
|
case SW:
|
||||||
return cell%10 == 0 || cell >= 45
|
return cell%10 == 0 || cell >= 45
|
||||||
case WSW:
|
case WSW:
|
||||||
i := cell % 10;
|
i := cell % 10
|
||||||
return i == 0 || i == 1 || i == 5 || cell >= 45;
|
return i == 0 || i == 1 || i == 5 || cell >= 45
|
||||||
case W:
|
case W:
|
||||||
return cell%5 == 0
|
return cell%5 == 0
|
||||||
case WNW:
|
case WNW:
|
||||||
i := cell % 10;
|
i := cell % 10
|
||||||
return i == 0 || i == 1 || i == 5 || cell < 5;
|
return i == 0 || i == 1 || i == 5 || cell < 5
|
||||||
case NW:
|
case NW:
|
||||||
return cell%10 == 0 || cell < 5
|
return cell%10 == 0 || cell < 5
|
||||||
case N:
|
case N:
|
||||||
|
|
@ -238,10 +238,10 @@ func out_of_bounds(cell, dir int8) bool {
|
||||||
case NE:
|
case NE:
|
||||||
return cell%10 == 9 || cell < 5
|
return cell%10 == 9 || cell < 5
|
||||||
case ENE:
|
case ENE:
|
||||||
i := cell % 10;
|
i := cell % 10
|
||||||
return i == 4 || i == 8 || i == 9 || cell < 5;
|
return i == 4 || i == 8 || i == 9 || cell < 5
|
||||||
}
|
}
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Rotate a piece 60 degrees clockwise */
|
/* Rotate a piece 60 degrees clockwise */
|
||||||
|
|
@ -260,7 +260,7 @@ func flip_piece(piece int) {
|
||||||
|
|
||||||
/* Convenience function to quickly calculate all of the indices for a piece */
|
/* Convenience function to quickly calculate all of the indices for a piece */
|
||||||
func calc_cell_indices(cell []int8, piece int, index int8) {
|
func calc_cell_indices(cell []int8, piece int, index int8) {
|
||||||
cell[0] = index;
|
cell[0] = index
|
||||||
for i := 1; i < 5; i++ {
|
for i := 1; i < 5; i++ {
|
||||||
cell[i] = shift(cell[i-1], piece_def[piece][i-1])
|
cell[i] = shift(cell[i-1], piece_def[piece][i-1])
|
||||||
}
|
}
|
||||||
|
|
@ -279,13 +279,13 @@ func cells_fit_on_board(cell []int8, piece int) bool {
|
||||||
* the piece in the solve function.
|
* the piece in the solve function.
|
||||||
*/
|
*/
|
||||||
func minimum_of_cells(cell []int8) int8 {
|
func minimum_of_cells(cell []int8) int8 {
|
||||||
minimum := cell[0];
|
minimum := cell[0]
|
||||||
for i := 1; i < 5; i++ {
|
for i := 1; i < 5; i++ {
|
||||||
if cell[i] < minimum {
|
if cell[i] < minimum {
|
||||||
minimum = cell[i]
|
minimum = cell[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return minimum;
|
return minimum
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate the lowest possible open cell if the piece is placed on the board.
|
/* Calculate the lowest possible open cell if the piece is placed on the board.
|
||||||
|
|
@ -293,33 +293,33 @@ func minimum_of_cells(cell []int8) int8 {
|
||||||
* solve function.
|
* solve function.
|
||||||
*/
|
*/
|
||||||
func first_empty_cell(cell []int8, minimum int8) int8 {
|
func first_empty_cell(cell []int8, minimum int8) int8 {
|
||||||
first_empty := minimum;
|
first_empty := minimum
|
||||||
for first_empty == cell[0] || first_empty == cell[1] ||
|
for first_empty == cell[0] || first_empty == cell[1] ||
|
||||||
first_empty == cell[2] || first_empty == cell[3] ||
|
first_empty == cell[2] || first_empty == cell[3] ||
|
||||||
first_empty == cell[4] {
|
first_empty == cell[4] {
|
||||||
first_empty++
|
first_empty++
|
||||||
}
|
}
|
||||||
return first_empty;
|
return first_empty
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate the unsigned long long int that will later be anded with the
|
/* Generate the unsigned long long int that will later be anded with the
|
||||||
* board to determine if it fits.
|
* board to determine if it fits.
|
||||||
*/
|
*/
|
||||||
func bitmask_from_cells(cell []int8) uint64 {
|
func bitmask_from_cells(cell []int8) uint64 {
|
||||||
var piece_mask uint64;
|
var piece_mask uint64
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 5; i++ {
|
||||||
piece_mask |= 1 << uint(cell[i])
|
piece_mask |= 1 << uint(cell[i])
|
||||||
}
|
}
|
||||||
return piece_mask;
|
return piece_mask
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Record the piece and other important information in arrays that will
|
/* Record the piece and other important information in arrays that will
|
||||||
* later be used by the solve function.
|
* later be used by the solve function.
|
||||||
*/
|
*/
|
||||||
func record_piece(piece int, minimum int8, first_empty int8, piece_mask uint64) {
|
func record_piece(piece int, minimum int8, first_empty int8, piece_mask uint64) {
|
||||||
pieces[piece][minimum][piece_counts[piece][minimum]] = piece_mask;
|
pieces[piece][minimum][piece_counts[piece][minimum]] = piece_mask
|
||||||
next_cell[piece][minimum][piece_counts[piece][minimum]] = first_empty;
|
next_cell[piece][minimum][piece_counts[piece][minimum]] = first_empty
|
||||||
piece_counts[piece][minimum]++;
|
piece_counts[piece][minimum]++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -330,7 +330,7 @@ func fill_contiguous_space(board []int8, index int8) {
|
||||||
if board[index] == 1 {
|
if board[index] == 1 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
board[index] = 1;
|
board[index] = 1
|
||||||
if !out_of_bounds(index, E) {
|
if !out_of_bounds(index, E) {
|
||||||
fill_contiguous_space(board, shift(index, E))
|
fill_contiguous_space(board, shift(index, E))
|
||||||
}
|
}
|
||||||
|
|
@ -359,17 +359,17 @@ func fill_contiguous_space(board []int8, index int8) {
|
||||||
* can split the board in half where both halves are viable.
|
* can split the board in half where both halves are viable.
|
||||||
*/
|
*/
|
||||||
func has_island(cell []int8, piece int) bool {
|
func has_island(cell []int8, piece int) bool {
|
||||||
temp_board := make([]int8, 50);
|
temp_board := make([]int8, 50)
|
||||||
var i int;
|
var i int
|
||||||
for i = 0; i < 5; i++ {
|
for i = 0; i < 5; i++ {
|
||||||
temp_board[cell[i]] = 1
|
temp_board[cell[i]] = 1
|
||||||
}
|
}
|
||||||
i = 49;
|
i = 49
|
||||||
for temp_board[i] == 1 {
|
for temp_board[i] == 1 {
|
||||||
i--
|
i--
|
||||||
}
|
}
|
||||||
fill_contiguous_space(temp_board, int8(i));
|
fill_contiguous_space(temp_board, int8(i))
|
||||||
c := 0;
|
c := 0
|
||||||
for i = 0; i < 50; i++ {
|
for i = 0; i < 50; i++ {
|
||||||
if temp_board[i] == 0 {
|
if temp_board[i] == 0 {
|
||||||
c++
|
c++
|
||||||
|
|
@ -379,7 +379,7 @@ func has_island(cell []int8, piece int) bool {
|
||||||
(c%5 == 0 && piece == 0) {
|
(c%5 == 0 && piece == 0) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -391,18 +391,18 @@ func has_island(cell []int8, piece int) bool {
|
||||||
* me the best time ;)
|
* me the best time ;)
|
||||||
*/
|
*/
|
||||||
func calc_six_rotations(piece, index int) {
|
func calc_six_rotations(piece, index int) {
|
||||||
cell := make([]int8, 5);
|
cell := make([]int8, 5)
|
||||||
for rotation := 0; rotation < 6; rotation++ {
|
for rotation := 0; rotation < 6; rotation++ {
|
||||||
if piece != 3 || rotation < 3 {
|
if piece != 3 || rotation < 3 {
|
||||||
calc_cell_indices(cell, piece, int8(index));
|
calc_cell_indices(cell, piece, int8(index))
|
||||||
if cells_fit_on_board(cell, piece) && !has_island(cell, piece) {
|
if cells_fit_on_board(cell, piece) && !has_island(cell, piece) {
|
||||||
minimum := minimum_of_cells(cell);
|
minimum := minimum_of_cells(cell)
|
||||||
first_empty := first_empty_cell(cell, minimum);
|
first_empty := first_empty_cell(cell, minimum)
|
||||||
piece_mask := bitmask_from_cells(cell);
|
piece_mask := bitmask_from_cells(cell)
|
||||||
record_piece(piece, minimum, first_empty, piece_mask);
|
record_piece(piece, minimum, first_empty, piece_mask)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rotate_piece(piece);
|
rotate_piece(piece)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -410,9 +410,9 @@ func calc_six_rotations(piece, index int) {
|
||||||
func calc_pieces() {
|
func calc_pieces() {
|
||||||
for piece := 0; piece < 10; piece++ {
|
for piece := 0; piece < 10; piece++ {
|
||||||
for index := 0; index < 50; index++ {
|
for index := 0; index < 50; index++ {
|
||||||
calc_six_rotations(piece, index);
|
calc_six_rotations(piece, index)
|
||||||
flip_piece(piece);
|
flip_piece(piece)
|
||||||
calc_six_rotations(piece, index);
|
calc_six_rotations(piece, index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -424,41 +424,41 @@ func calc_pieces() {
|
||||||
* board in the solve function.
|
* board in the solve function.
|
||||||
*/
|
*/
|
||||||
const (
|
const (
|
||||||
ROW_MASK = 0x1F;
|
ROW_MASK = 0x1F
|
||||||
TRIPLE_MASK = 0x7FFF;
|
TRIPLE_MASK = 0x7FFF
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
all_rows = [32]int8{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
all_rows = [32]int8{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||||
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||||
};
|
}
|
||||||
bad_even_rows [32][32]int8;
|
bad_even_rows [32][32]int8
|
||||||
bad_odd_rows [32][32]int8;
|
bad_odd_rows [32][32]int8
|
||||||
bad_even_triple [32768]int8;
|
bad_even_triple [32768]int8
|
||||||
bad_odd_triple [32768]int8;
|
bad_odd_triple [32768]int8
|
||||||
)
|
)
|
||||||
|
|
||||||
func rows_bad(row1, row2 int8, even bool) int8 {
|
func rows_bad(row1, row2 int8, even bool) int8 {
|
||||||
/* even is referring to row1 */
|
/* even is referring to row1 */
|
||||||
var row2_shift int8;
|
var row2_shift int8
|
||||||
/* Test for blockages at same index and shifted index */
|
/* Test for blockages at same index and shifted index */
|
||||||
if even {
|
if even {
|
||||||
row2_shift = ((row2 << 1) & ROW_MASK) | 0x01
|
row2_shift = ((row2 << 1) & ROW_MASK) | 0x01
|
||||||
} else {
|
} else {
|
||||||
row2_shift = (row2 >> 1) | 0x10
|
row2_shift = (row2 >> 1) | 0x10
|
||||||
}
|
}
|
||||||
block := ((row1 ^ row2) & row2) & ((row1 ^ row2_shift) & row2_shift);
|
block := ((row1 ^ row2) & row2) & ((row1 ^ row2_shift) & row2_shift)
|
||||||
/* Test for groups of 0's */
|
/* Test for groups of 0's */
|
||||||
in_zeroes := false;
|
in_zeroes := false
|
||||||
group_okay := false;
|
group_okay := false
|
||||||
for i := uint8(0); i < 5; i++ {
|
for i := uint8(0); i < 5; i++ {
|
||||||
if row1&(1<<i) != 0 {
|
if row1&(1<<i) != 0 {
|
||||||
if in_zeroes {
|
if in_zeroes {
|
||||||
if !group_okay {
|
if !group_okay {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
in_zeroes = false;
|
in_zeroes = false
|
||||||
group_okay = false;
|
group_okay = false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !in_zeroes {
|
if !in_zeroes {
|
||||||
|
|
@ -472,7 +472,7 @@ func rows_bad(row1, row2 int8, even bool) int8 {
|
||||||
if in_zeroes {
|
if in_zeroes {
|
||||||
return boolInt(!group_okay)
|
return boolInt(!group_okay)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for cases where three rows checked sequentially cause a false
|
/* Check for cases where three rows checked sequentially cause a false
|
||||||
|
|
@ -497,29 +497,29 @@ func triple_is_okay(row1, row2, row3 int, even bool) bool {
|
||||||
* row3: ????? ?????
|
* row3: ????? ?????
|
||||||
*/
|
*/
|
||||||
return ((row1 == 0x13) && (row2 == 0x11)) ||
|
return ((row1 == 0x13) && (row2 == 0x11)) ||
|
||||||
((row1 == 0x15) && (row2 == 0x11));
|
((row1 == 0x15) && (row2 == 0x11))
|
||||||
}
|
}
|
||||||
|
|
||||||
func calc_rows() {
|
func calc_rows() {
|
||||||
for row1 := int8(0); row1 < 32; row1++ {
|
for row1 := int8(0); row1 < 32; row1++ {
|
||||||
for row2 := int8(0); row2 < 32; row2++ {
|
for row2 := int8(0); row2 < 32; row2++ {
|
||||||
bad_even_rows[row1][row2] = rows_bad(row1, row2, true);
|
bad_even_rows[row1][row2] = rows_bad(row1, row2, true)
|
||||||
bad_odd_rows[row1][row2] = rows_bad(row1, row2, false);
|
bad_odd_rows[row1][row2] = rows_bad(row1, row2, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for row1 := 0; row1 < 32; row1++ {
|
for row1 := 0; row1 < 32; row1++ {
|
||||||
for row2 := 0; row2 < 32; row2++ {
|
for row2 := 0; row2 < 32; row2++ {
|
||||||
for row3 := 0; row3 < 32; row3++ {
|
for row3 := 0; row3 < 32; row3++ {
|
||||||
result1 := bad_even_rows[row1][row2];
|
result1 := bad_even_rows[row1][row2]
|
||||||
result2 := bad_odd_rows[row2][row3];
|
result2 := bad_odd_rows[row2][row3]
|
||||||
if result1 == 0 && result2 != 0 && triple_is_okay(row1, row2, row3, true) {
|
if result1 == 0 && result2 != 0 && triple_is_okay(row1, row2, row3, true) {
|
||||||
bad_even_triple[row1+(row2*32)+(row3*1024)] = 0
|
bad_even_triple[row1+(row2*32)+(row3*1024)] = 0
|
||||||
} else {
|
} else {
|
||||||
bad_even_triple[row1+(row2*32)+(row3*1024)] = boolInt(result1 != 0 || result2 != 0)
|
bad_even_triple[row1+(row2*32)+(row3*1024)] = boolInt(result1 != 0 || result2 != 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
result1 = bad_odd_rows[row1][row2];
|
result1 = bad_odd_rows[row1][row2]
|
||||||
result2 = bad_even_rows[row2][row3];
|
result2 = bad_even_rows[row2][row3]
|
||||||
if result1 == 0 && result2 != 0 && triple_is_okay(row1, row2, row3, false) {
|
if result1 == 0 && result2 != 0 && triple_is_okay(row1, row2, row3, false) {
|
||||||
bad_odd_triple[row1+(row2*32)+(row3*1024)] = 0
|
bad_odd_triple[row1+(row2*32)+(row3*1024)] = 0
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -538,11 +538,11 @@ func boardHasIslands(cell int8) int8 {
|
||||||
if cell >= 40 {
|
if cell >= 40 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
current_triple := (board >> uint((cell/5)*5)) & TRIPLE_MASK;
|
current_triple := (board >> uint((cell/5)*5)) & TRIPLE_MASK
|
||||||
if (cell/5)%2 != 0 {
|
if (cell/5)%2 != 0 {
|
||||||
return bad_odd_triple[current_triple]
|
return bad_odd_triple[current_triple]
|
||||||
}
|
}
|
||||||
return bad_even_triple[current_triple];
|
return bad_even_triple[current_triple]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -553,26 +553,26 @@ func boardHasIslands(cell int8) int8 {
|
||||||
* array if a solution is found.
|
* array if a solution is found.
|
||||||
*/
|
*/
|
||||||
var (
|
var (
|
||||||
avail uint16 = 0x03FF;
|
avail uint16 = 0x03FF
|
||||||
sol_nums [10]int8;
|
sol_nums [10]int8
|
||||||
sol_masks [10]uint64;
|
sol_masks [10]uint64
|
||||||
solutions [2100][50]int8;
|
solutions [2100][50]int8
|
||||||
solution_count = 0;
|
solution_count = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
func record_solution() {
|
func record_solution() {
|
||||||
for sol_no := 0; sol_no < 10; sol_no++ {
|
for sol_no := 0; sol_no < 10; sol_no++ {
|
||||||
sol_mask := sol_masks[sol_no];
|
sol_mask := sol_masks[sol_no]
|
||||||
for index := 0; index < 50; index++ {
|
for index := 0; index < 50; index++ {
|
||||||
if sol_mask&1 == 1 {
|
if sol_mask&1 == 1 {
|
||||||
solutions[solution_count][index] = sol_nums[sol_no];
|
solutions[solution_count][index] = sol_nums[sol_no]
|
||||||
/* Board rotated 180 degrees is a solution too! */
|
/* Board rotated 180 degrees is a solution too! */
|
||||||
solutions[solution_count+1][49-index] = sol_nums[sol_no];
|
solutions[solution_count+1][49-index] = sol_nums[sol_no]
|
||||||
}
|
}
|
||||||
sol_mask = sol_mask >> 1;
|
sol_mask = sol_mask >> 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
solution_count += 2;
|
solution_count += 2
|
||||||
}
|
}
|
||||||
|
|
||||||
func solve(depth, cell int8) {
|
func solve(depth, cell int8) {
|
||||||
|
|
@ -585,31 +585,31 @@ func solve(depth, cell int8) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for piece := int8(0); piece < 10; piece++ {
|
for piece := int8(0); piece < 10; piece++ {
|
||||||
var piece_no_mask uint16 = 1 << uint(piece);
|
var piece_no_mask uint16 = 1 << uint(piece)
|
||||||
if avail&piece_no_mask == 0 {
|
if avail&piece_no_mask == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
avail ^= piece_no_mask;
|
avail ^= piece_no_mask
|
||||||
max_rots := piece_counts[piece][cell];
|
max_rots := piece_counts[piece][cell]
|
||||||
piece_mask := pieces[piece][cell];
|
piece_mask := pieces[piece][cell]
|
||||||
for rotation := 0; rotation < max_rots; rotation++ {
|
for rotation := 0; rotation < max_rots; rotation++ {
|
||||||
if board&piece_mask[rotation] == 0 {
|
if board&piece_mask[rotation] == 0 {
|
||||||
sol_nums[depth] = piece;
|
sol_nums[depth] = piece
|
||||||
sol_masks[depth] = piece_mask[rotation];
|
sol_masks[depth] = piece_mask[rotation]
|
||||||
if depth == 9 {
|
if depth == 9 {
|
||||||
/* Solution found!!!!!11!!ONE! */
|
/* Solution found!!!!!11!!ONE! */
|
||||||
record_solution();
|
record_solution()
|
||||||
avail ^= piece_no_mask;
|
avail ^= piece_no_mask
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
board |= piece_mask[rotation];
|
board |= piece_mask[rotation]
|
||||||
if boardHasIslands(next_cell[piece][cell][rotation]) == 0 {
|
if boardHasIslands(next_cell[piece][cell][rotation]) == 0 {
|
||||||
solve(depth+1, next_cell[piece][cell][rotation])
|
solve(depth+1, next_cell[piece][cell][rotation])
|
||||||
}
|
}
|
||||||
board ^= piece_mask[rotation];
|
board ^= piece_mask[rotation]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
avail ^= piece_no_mask;
|
avail ^= piece_no_mask
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -620,46 +620,46 @@ func pretty(b *[50]int8) {
|
||||||
b[i+2]+'0', b[i+3]+'0', b[i+4]+'0', b[i+5]+'0', b[i+6]+'0',
|
b[i+2]+'0', b[i+3]+'0', b[i+4]+'0', b[i+5]+'0', b[i+6]+'0',
|
||||||
b[i+7]+'0', b[i+8]+'0', b[i+9]+'0')
|
b[i+7]+'0', b[i+8]+'0', b[i+9]+'0')
|
||||||
}
|
}
|
||||||
fmt.Printf("\n");
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find smallest and largest solutions */
|
/* Find smallest and largest solutions */
|
||||||
func smallest_largest() (smallest, largest *[50]int8) {
|
func smallest_largest() (smallest, largest *[50]int8) {
|
||||||
smallest = &solutions[0];
|
smallest = &solutions[0]
|
||||||
largest = &solutions[0];
|
largest = &solutions[0]
|
||||||
for i := 1; i < solution_count; i++ {
|
for i := 1; i < solution_count; i++ {
|
||||||
candidate := &solutions[i];
|
candidate := &solutions[i]
|
||||||
for j, s := range *smallest {
|
for j, s := range *smallest {
|
||||||
c := candidate[j];
|
c := candidate[j]
|
||||||
if c == s {
|
if c == s {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if c < s {
|
if c < s {
|
||||||
smallest = candidate
|
smallest = candidate
|
||||||
}
|
}
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
for j, s := range *largest {
|
for j, s := range *largest {
|
||||||
c := candidate[j];
|
c := candidate[j]
|
||||||
if c == s {
|
if c == s {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if c > s {
|
if c > s {
|
||||||
largest = candidate
|
largest = candidate
|
||||||
}
|
}
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse();
|
flag.Parse()
|
||||||
calc_pieces();
|
calc_pieces()
|
||||||
calc_rows();
|
calc_rows()
|
||||||
solve(0, 0);
|
solve(0, 0)
|
||||||
fmt.Printf("%d solutions found\n\n", solution_count);
|
fmt.Printf("%d solutions found\n\n", solution_count)
|
||||||
smallest, largest := smallest_largest();
|
smallest, largest := smallest_largest()
|
||||||
pretty(smallest);
|
pretty(smallest)
|
||||||
pretty(largest);
|
pretty(largest)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,89 +37,89 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag";
|
"flag"
|
||||||
"fmt";
|
"fmt"
|
||||||
"math";
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
var n = flag.Int("n", 1000, "number of iterations")
|
var n = flag.Int("n", 1000, "number of iterations")
|
||||||
|
|
||||||
type Body struct {
|
type Body struct {
|
||||||
x, y, z, vx, vy, vz, mass float64;
|
x, y, z, vx, vy, vz, mass float64
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
solarMass = 4 * math.Pi * math.Pi;
|
solarMass = 4 * math.Pi * math.Pi
|
||||||
daysPerYear = 365.24;
|
daysPerYear = 365.24
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *Body) offsetMomentum(px, py, pz float64) {
|
func (b *Body) offsetMomentum(px, py, pz float64) {
|
||||||
b.vx = -px / solarMass;
|
b.vx = -px / solarMass
|
||||||
b.vy = -py / solarMass;
|
b.vy = -py / solarMass
|
||||||
b.vz = -pz / solarMass;
|
b.vz = -pz / solarMass
|
||||||
}
|
}
|
||||||
|
|
||||||
type System []*Body
|
type System []*Body
|
||||||
|
|
||||||
func NewSystem(body []Body) System {
|
func NewSystem(body []Body) System {
|
||||||
n := make(System, len(body));
|
n := make(System, len(body))
|
||||||
for i := 0; i < len(body); i++ {
|
for i := 0; i < len(body); i++ {
|
||||||
n[i] = new(Body); // copy to avoid overwriting the inputs
|
n[i] = new(Body) // copy to avoid overwriting the inputs
|
||||||
*n[i] = body[i];
|
*n[i] = body[i]
|
||||||
}
|
}
|
||||||
var px, py, pz float64;
|
var px, py, pz float64
|
||||||
for _, body := range n {
|
for _, body := range n {
|
||||||
px += body.vx * body.mass;
|
px += body.vx * body.mass
|
||||||
py += body.vy * body.mass;
|
py += body.vy * body.mass
|
||||||
pz += body.vz * body.mass;
|
pz += body.vz * body.mass
|
||||||
}
|
}
|
||||||
n[0].offsetMomentum(px, py, pz);
|
n[0].offsetMomentum(px, py, pz)
|
||||||
return n;
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sys System) energy() float64 {
|
func (sys System) energy() float64 {
|
||||||
var e float64;
|
var e float64
|
||||||
for i, body := range sys {
|
for i, body := range sys {
|
||||||
e += 0.5 * body.mass *
|
e += 0.5 * body.mass *
|
||||||
(body.vx*body.vx + body.vy*body.vy + body.vz*body.vz);
|
(body.vx*body.vx + body.vy*body.vy + body.vz*body.vz)
|
||||||
for j := i + 1; j < len(sys); j++ {
|
for j := i + 1; j < len(sys); j++ {
|
||||||
body2 := sys[j];
|
body2 := sys[j]
|
||||||
dx := body.x - body2.x;
|
dx := body.x - body2.x
|
||||||
dy := body.y - body2.y;
|
dy := body.y - body2.y
|
||||||
dz := body.z - body2.z;
|
dz := body.z - body2.z
|
||||||
distance := math.Sqrt(dx*dx + dy*dy + dz*dz);
|
distance := math.Sqrt(dx*dx + dy*dy + dz*dz)
|
||||||
e -= (body.mass * body2.mass) / distance;
|
e -= (body.mass * body2.mass) / distance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return e;
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sys System) advance(dt float64) {
|
func (sys System) advance(dt float64) {
|
||||||
for i, body := range sys {
|
for i, body := range sys {
|
||||||
for j := i + 1; j < len(sys); j++ {
|
for j := i + 1; j < len(sys); j++ {
|
||||||
body2 := sys[j];
|
body2 := sys[j]
|
||||||
dx := body.x - body2.x;
|
dx := body.x - body2.x
|
||||||
dy := body.y - body2.y;
|
dy := body.y - body2.y
|
||||||
dz := body.z - body2.z;
|
dz := body.z - body2.z
|
||||||
|
|
||||||
dSquared := dx*dx + dy*dy + dz*dz;
|
dSquared := dx*dx + dy*dy + dz*dz
|
||||||
distance := math.Sqrt(dSquared);
|
distance := math.Sqrt(dSquared)
|
||||||
mag := dt / (dSquared * distance);
|
mag := dt / (dSquared * distance)
|
||||||
|
|
||||||
body.vx -= dx * body2.mass * mag;
|
body.vx -= dx * body2.mass * mag
|
||||||
body.vy -= dy * body2.mass * mag;
|
body.vy -= dy * body2.mass * mag
|
||||||
body.vz -= dz * body2.mass * mag;
|
body.vz -= dz * body2.mass * mag
|
||||||
|
|
||||||
body2.vx += dx * body.mass * mag;
|
body2.vx += dx * body.mass * mag
|
||||||
body2.vy += dy * body.mass * mag;
|
body2.vy += dy * body.mass * mag
|
||||||
body2.vz += dz * body.mass * mag;
|
body2.vz += dz * body.mass * mag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, body := range sys {
|
for _, body := range sys {
|
||||||
body.x += dt * body.vx;
|
body.x += dt * body.vx
|
||||||
body.y += dt * body.vy;
|
body.y += dt * body.vy
|
||||||
body.z += dt * body.vz;
|
body.z += dt * body.vz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,7 +132,7 @@ var (
|
||||||
vy: 7.69901118419740425e-03 * daysPerYear,
|
vy: 7.69901118419740425e-03 * daysPerYear,
|
||||||
vz: -6.90460016972063023e-05 * daysPerYear,
|
vz: -6.90460016972063023e-05 * daysPerYear,
|
||||||
mass: 9.54791938424326609e-04 * solarMass,
|
mass: 9.54791938424326609e-04 * solarMass,
|
||||||
};
|
}
|
||||||
saturn = Body{
|
saturn = Body{
|
||||||
x: 8.34336671824457987e+00,
|
x: 8.34336671824457987e+00,
|
||||||
y: 4.12479856412430479e+00,
|
y: 4.12479856412430479e+00,
|
||||||
|
|
@ -141,7 +141,7 @@ var (
|
||||||
vy: 4.99852801234917238e-03 * daysPerYear,
|
vy: 4.99852801234917238e-03 * daysPerYear,
|
||||||
vz: 2.30417297573763929e-05 * daysPerYear,
|
vz: 2.30417297573763929e-05 * daysPerYear,
|
||||||
mass: 2.85885980666130812e-04 * solarMass,
|
mass: 2.85885980666130812e-04 * solarMass,
|
||||||
};
|
}
|
||||||
uranus = Body{
|
uranus = Body{
|
||||||
x: 1.28943695621391310e+01,
|
x: 1.28943695621391310e+01,
|
||||||
y: -1.51111514016986312e+01,
|
y: -1.51111514016986312e+01,
|
||||||
|
|
@ -150,7 +150,7 @@ var (
|
||||||
vy: 2.37847173959480950e-03 * daysPerYear,
|
vy: 2.37847173959480950e-03 * daysPerYear,
|
||||||
vz: -2.96589568540237556e-05 * daysPerYear,
|
vz: -2.96589568540237556e-05 * daysPerYear,
|
||||||
mass: 4.36624404335156298e-05 * solarMass,
|
mass: 4.36624404335156298e-05 * solarMass,
|
||||||
};
|
}
|
||||||
neptune = Body{
|
neptune = Body{
|
||||||
x: 1.53796971148509165e+01,
|
x: 1.53796971148509165e+01,
|
||||||
y: -2.59193146099879641e+01,
|
y: -2.59193146099879641e+01,
|
||||||
|
|
@ -159,19 +159,19 @@ var (
|
||||||
vy: 1.62824170038242295e-03 * daysPerYear,
|
vy: 1.62824170038242295e-03 * daysPerYear,
|
||||||
vz: -9.51592254519715870e-05 * daysPerYear,
|
vz: -9.51592254519715870e-05 * daysPerYear,
|
||||||
mass: 5.15138902046611451e-05 * solarMass,
|
mass: 5.15138902046611451e-05 * solarMass,
|
||||||
};
|
}
|
||||||
sun = Body{
|
sun = Body{
|
||||||
mass: solarMass,
|
mass: solarMass,
|
||||||
};
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse();
|
flag.Parse()
|
||||||
|
|
||||||
system := NewSystem([]Body{sun, jupiter, saturn, uranus, neptune});
|
system := NewSystem([]Body{sun, jupiter, saturn, uranus, neptune})
|
||||||
fmt.Printf("%.9f\n", system.energy());
|
fmt.Printf("%.9f\n", system.energy())
|
||||||
for i := 0; i < *n; i++ {
|
for i := 0; i < *n; i++ {
|
||||||
system.advance(0.01)
|
system.advance(0.01)
|
||||||
}
|
}
|
||||||
fmt.Printf("%.9f\n", system.energy());
|
fmt.Printf("%.9f\n", system.energy())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,20 +38,20 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bignum";
|
"bignum"
|
||||||
"flag";
|
"flag"
|
||||||
"fmt";
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var n = flag.Int("n", 27, "number of digits")
|
var n = flag.Int("n", 27, "number of digits")
|
||||||
var silent = flag.Bool("s", false, "don't print result")
|
var silent = flag.Bool("s", false, "don't print result")
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tmp1 *bignum.Integer;
|
tmp1 *bignum.Integer
|
||||||
tmp2 *bignum.Integer;
|
tmp2 *bignum.Integer
|
||||||
numer = bignum.Int(1);
|
numer = bignum.Int(1)
|
||||||
accum = bignum.Int(0);
|
accum = bignum.Int(0)
|
||||||
denom = bignum.Int(1);
|
denom = bignum.Int(1)
|
||||||
)
|
)
|
||||||
|
|
||||||
func extract_digit() int64 {
|
func extract_digit() int64 {
|
||||||
|
|
@ -60,36 +60,36 @@ func extract_digit() int64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute (numer * 3 + accum) / denom
|
// Compute (numer * 3 + accum) / denom
|
||||||
tmp1 = numer.Shl(1);
|
tmp1 = numer.Shl(1)
|
||||||
bignum.Iadd(tmp1, tmp1, numer);
|
bignum.Iadd(tmp1, tmp1, numer)
|
||||||
bignum.Iadd(tmp1, tmp1, accum);
|
bignum.Iadd(tmp1, tmp1, accum)
|
||||||
tmp1, tmp2 := tmp1.QuoRem(denom);
|
tmp1, tmp2 := tmp1.QuoRem(denom)
|
||||||
|
|
||||||
// Now, if (numer * 4 + accum) % denom...
|
// Now, if (numer * 4 + accum) % denom...
|
||||||
bignum.Iadd(tmp2, tmp2, numer);
|
bignum.Iadd(tmp2, tmp2, numer)
|
||||||
|
|
||||||
// ... is normalized, then the two divisions have the same result.
|
// ... is normalized, then the two divisions have the same result.
|
||||||
if tmp2.Cmp(denom) >= 0 {
|
if tmp2.Cmp(denom) >= 0 {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
return tmp1.Value();
|
return tmp1.Value()
|
||||||
}
|
}
|
||||||
|
|
||||||
func next_term(k int64) {
|
func next_term(k int64) {
|
||||||
y2 := k*2 + 1;
|
y2 := k*2 + 1
|
||||||
|
|
||||||
tmp1 = numer.Shl(1);
|
tmp1 = numer.Shl(1)
|
||||||
bignum.Iadd(accum, accum, tmp1);
|
bignum.Iadd(accum, accum, tmp1)
|
||||||
bignum.Iscale(accum, y2);
|
bignum.Iscale(accum, y2)
|
||||||
bignum.Iscale(numer, k);
|
bignum.Iscale(numer, k)
|
||||||
bignum.Iscale(denom, y2);
|
bignum.Iscale(denom, y2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func eliminate_digit(d int64) {
|
func eliminate_digit(d int64) {
|
||||||
bignum.Isub(accum, accum, denom.Mul1(d));
|
bignum.Isub(accum, accum, denom.Mul1(d))
|
||||||
bignum.Iscale(accum, 10);
|
bignum.Iscale(accum, 10)
|
||||||
bignum.Iscale(numer, 10);
|
bignum.Iscale(numer, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
func printf(s string, arg ...) {
|
func printf(s string, arg ...) {
|
||||||
|
|
@ -99,28 +99,28 @@ func printf(s string, arg ...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse();
|
flag.Parse()
|
||||||
|
|
||||||
var m int; // 0 <= m < 10
|
var m int // 0 <= m < 10
|
||||||
for i, k := 0, int64(0); ; {
|
for i, k := 0, int64(0); ; {
|
||||||
d := int64(-1);
|
d := int64(-1)
|
||||||
for d < 0 {
|
for d < 0 {
|
||||||
k++;
|
k++
|
||||||
next_term(k);
|
next_term(k)
|
||||||
d = extract_digit();
|
d = extract_digit()
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%c", d+'0');
|
printf("%c", d+'0')
|
||||||
|
|
||||||
i++;
|
i++
|
||||||
m = i % 10;
|
m = i % 10
|
||||||
if m == 0 {
|
if m == 0 {
|
||||||
printf("\t:%d\n", i)
|
printf("\t:%d\n", i)
|
||||||
}
|
}
|
||||||
if i >= *n {
|
if i >= *n {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
eliminate_digit(d);
|
eliminate_digit(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
if m > 0 {
|
if m > 0 {
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,11 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt";
|
"fmt"
|
||||||
"io/ioutil";
|
"io/ioutil"
|
||||||
"os";
|
"os"
|
||||||
"regexp";
|
"regexp"
|
||||||
"strings";
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var variants = []string{
|
var variants = []string{
|
||||||
|
|
@ -56,7 +56,7 @@ var variants = []string{
|
||||||
}
|
}
|
||||||
|
|
||||||
type Subst struct {
|
type Subst struct {
|
||||||
pat, repl string;
|
pat, repl string
|
||||||
}
|
}
|
||||||
|
|
||||||
var substs = []Subst{
|
var substs = []Subst{
|
||||||
|
|
@ -74,34 +74,34 @@ var substs = []Subst{
|
||||||
}
|
}
|
||||||
|
|
||||||
func countMatches(pat string, bytes []byte) int {
|
func countMatches(pat string, bytes []byte) int {
|
||||||
re := regexp.MustCompile(pat);
|
re := regexp.MustCompile(pat)
|
||||||
n := 0;
|
n := 0
|
||||||
for {
|
for {
|
||||||
e := re.Execute(bytes);
|
e := re.Execute(bytes)
|
||||||
if len(e) == 0 {
|
if len(e) == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
n++;
|
n++
|
||||||
bytes = bytes[e[1]:];
|
bytes = bytes[e[1]:]
|
||||||
}
|
}
|
||||||
return n;
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
bytes, err := ioutil.ReadFile("/dev/stdin");
|
bytes, err := ioutil.ReadFile("/dev/stdin")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "can't read input: %s\n", err);
|
fmt.Fprintf(os.Stderr, "can't read input: %s\n", err)
|
||||||
os.Exit(2);
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
ilen := len(bytes);
|
ilen := len(bytes)
|
||||||
// Delete the comment lines and newlines
|
// Delete the comment lines and newlines
|
||||||
bytes = regexp.MustCompile("(>[^\n]+)?\n").ReplaceAll(bytes, []byte{});
|
bytes = regexp.MustCompile("(>[^\n]+)?\n").ReplaceAll(bytes, []byte{})
|
||||||
clen := len(bytes);
|
clen := len(bytes)
|
||||||
for _, s := range variants {
|
for _, s := range variants {
|
||||||
fmt.Printf("%s %d\n", s, countMatches(s, bytes))
|
fmt.Printf("%s %d\n", s, countMatches(s, bytes))
|
||||||
}
|
}
|
||||||
for _, sub := range substs {
|
for _, sub := range substs {
|
||||||
bytes = regexp.MustCompile(sub.pat).ReplaceAll(bytes, strings.Bytes(sub.repl))
|
bytes = regexp.MustCompile(sub.pat).ReplaceAll(bytes, strings.Bytes(sub.repl))
|
||||||
}
|
}
|
||||||
fmt.Printf("\n%d\n%d\n%d\n", ilen, clen, len(bytes));
|
fmt.Printf("\n%d\n%d\n%d\n", ilen, clen, len(bytes))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio";
|
"bufio"
|
||||||
"os";
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
const lineSize = 60
|
const lineSize = 60
|
||||||
|
|
@ -62,44 +62,44 @@ var complement = [256]uint8{
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
in := bufio.NewReader(os.Stdin);
|
in := bufio.NewReader(os.Stdin)
|
||||||
buf := make([]byte, 1024*1024);
|
buf := make([]byte, 1024*1024)
|
||||||
line, err := in.ReadSlice('\n');
|
line, err := in.ReadSlice('\n')
|
||||||
for err == nil {
|
for err == nil {
|
||||||
os.Stdout.Write(line);
|
os.Stdout.Write(line)
|
||||||
|
|
||||||
// Accumulate reversed complement in buf[w:]
|
// Accumulate reversed complement in buf[w:]
|
||||||
nchar := 0;
|
nchar := 0
|
||||||
w := len(buf);
|
w := len(buf)
|
||||||
for {
|
for {
|
||||||
line, err = in.ReadSlice('\n');
|
line, err = in.ReadSlice('\n')
|
||||||
if err != nil || line[0] == '>' {
|
if err != nil || line[0] == '>' {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
line = line[0 : len(line)-1];
|
line = line[0 : len(line)-1]
|
||||||
nchar += len(line);
|
nchar += len(line)
|
||||||
if len(line)+nchar/60+128 >= w {
|
if len(line)+nchar/60+128 >= w {
|
||||||
nbuf := make([]byte, len(buf)*5);
|
nbuf := make([]byte, len(buf)*5)
|
||||||
copy(nbuf[len(nbuf)-len(buf):], buf);
|
copy(nbuf[len(nbuf)-len(buf):], buf)
|
||||||
w += len(nbuf) - len(buf);
|
w += len(nbuf) - len(buf)
|
||||||
buf = nbuf;
|
buf = nbuf
|
||||||
}
|
}
|
||||||
|
|
||||||
// This loop is the bottleneck.
|
// This loop is the bottleneck.
|
||||||
for _, c := range line {
|
for _, c := range line {
|
||||||
w--;
|
w--
|
||||||
buf[w] = complement[c];
|
buf[w] = complement[c]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy down to beginning of buffer, inserting newlines.
|
// Copy down to beginning of buffer, inserting newlines.
|
||||||
// The loop left room for the newlines and 128 bytes of padding.
|
// The loop left room for the newlines and 128 bytes of padding.
|
||||||
i := 0;
|
i := 0
|
||||||
for j := w; j < len(buf); j += 60 {
|
for j := w; j < len(buf); j += 60 {
|
||||||
n := copy(buf[i:i+60], buf[j:]);
|
n := copy(buf[i:i+60], buf[j:])
|
||||||
buf[i+n] = '\n';
|
buf[i+n] = '\n'
|
||||||
i += n + 1;
|
i += n + 1
|
||||||
}
|
}
|
||||||
os.Stdout.Write(buf[0:i]);
|
os.Stdout.Write(buf[0:i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,10 +37,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag";
|
"flag"
|
||||||
"fmt";
|
"fmt"
|
||||||
"math";
|
"math"
|
||||||
"runtime";
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
var n = flag.Int("n", 2000, "count")
|
var n = flag.Int("n", 2000, "count")
|
||||||
|
|
@ -52,22 +52,22 @@ type Vec []float64
|
||||||
|
|
||||||
func (v Vec) Times(i, n int, u Vec, c chan int) {
|
func (v Vec) Times(i, n int, u Vec, c chan int) {
|
||||||
for ; i < n; i++ {
|
for ; i < n; i++ {
|
||||||
v[i] = 0;
|
v[i] = 0
|
||||||
for j := 0; j < len(u); j++ {
|
for j := 0; j < len(u); j++ {
|
||||||
v[i] += evalA(i, j) * u[j]
|
v[i] += evalA(i, j) * u[j]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c <- 1;
|
c <- 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Vec) TimesTransp(i, n int, u Vec, c chan int) {
|
func (v Vec) TimesTransp(i, n int, u Vec, c chan int) {
|
||||||
for ; i < n; i++ {
|
for ; i < n; i++ {
|
||||||
v[i] = 0;
|
v[i] = 0
|
||||||
for j := 0; j < len(u); j++ {
|
for j := 0; j < len(u); j++ {
|
||||||
v[i] += evalA(j, i) * u[j]
|
v[i] += evalA(j, i) * u[j]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c <- 1;
|
c <- 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func wait(c chan int) {
|
func wait(c chan int) {
|
||||||
|
|
@ -77,35 +77,35 @@ func wait(c chan int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Vec) ATimesTransp(u Vec) {
|
func (v Vec) ATimesTransp(u Vec) {
|
||||||
x := make(Vec, len(u));
|
x := make(Vec, len(u))
|
||||||
c := make(chan int, *nCPU);
|
c := make(chan int, *nCPU)
|
||||||
for i := 0; i < *nCPU; i++ {
|
for i := 0; i < *nCPU; i++ {
|
||||||
go x.Times(i*len(v) / *nCPU, (i+1)*len(v) / *nCPU, u, c)
|
go x.Times(i*len(v) / *nCPU, (i+1)*len(v) / *nCPU, u, c)
|
||||||
}
|
}
|
||||||
wait(c);
|
wait(c)
|
||||||
for i := 0; i < *nCPU; i++ {
|
for i := 0; i < *nCPU; i++ {
|
||||||
go v.TimesTransp(i*len(v) / *nCPU, (i+1)*len(v) / *nCPU, x, c)
|
go v.TimesTransp(i*len(v) / *nCPU, (i+1)*len(v) / *nCPU, x, c)
|
||||||
}
|
}
|
||||||
wait(c);
|
wait(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse();
|
flag.Parse()
|
||||||
runtime.GOMAXPROCS(*nCPU);
|
runtime.GOMAXPROCS(*nCPU)
|
||||||
N := *n;
|
N := *n
|
||||||
u := make(Vec, N);
|
u := make(Vec, N)
|
||||||
for i := 0; i < N; i++ {
|
for i := 0; i < N; i++ {
|
||||||
u[i] = 1
|
u[i] = 1
|
||||||
}
|
}
|
||||||
v := make(Vec, N);
|
v := make(Vec, N)
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
v.ATimesTransp(u);
|
v.ATimesTransp(u)
|
||||||
u.ATimesTransp(v);
|
u.ATimesTransp(v)
|
||||||
}
|
}
|
||||||
var vBv, vv float64;
|
var vBv, vv float64
|
||||||
for i := 0; i < N; i++ {
|
for i := 0; i < N; i++ {
|
||||||
vBv += u[i] * v[i];
|
vBv += u[i] * v[i]
|
||||||
vv += v[i] * v[i];
|
vv += v[i] * v[i]
|
||||||
}
|
}
|
||||||
fmt.Printf("%0.9f\n", math.Sqrt(vBv/vv));
|
fmt.Printf("%0.9f\n", math.Sqrt(vBv/vv))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag";
|
"flag"
|
||||||
"fmt";
|
"fmt"
|
||||||
"math";
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
var n = flag.Int("n", 2000, "count")
|
var n = flag.Int("n", 2000, "count")
|
||||||
|
|
@ -50,7 +50,7 @@ type Vec []float64
|
||||||
|
|
||||||
func (v Vec) Times(u Vec) {
|
func (v Vec) Times(u Vec) {
|
||||||
for i := 0; i < len(v); i++ {
|
for i := 0; i < len(v); i++ {
|
||||||
v[i] = 0;
|
v[i] = 0
|
||||||
for j := 0; j < len(u); j++ {
|
for j := 0; j < len(u); j++ {
|
||||||
v[i] += evalA(i, j) * u[j]
|
v[i] += evalA(i, j) * u[j]
|
||||||
}
|
}
|
||||||
|
|
@ -59,7 +59,7 @@ func (v Vec) Times(u Vec) {
|
||||||
|
|
||||||
func (v Vec) TimesTransp(u Vec) {
|
func (v Vec) TimesTransp(u Vec) {
|
||||||
for i := 0; i < len(v); i++ {
|
for i := 0; i < len(v); i++ {
|
||||||
v[i] = 0;
|
v[i] = 0
|
||||||
for j := 0; j < len(u); j++ {
|
for j := 0; j < len(u); j++ {
|
||||||
v[i] += evalA(j, i) * u[j]
|
v[i] += evalA(j, i) * u[j]
|
||||||
}
|
}
|
||||||
|
|
@ -67,27 +67,27 @@ func (v Vec) TimesTransp(u Vec) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Vec) ATimesTransp(u Vec) {
|
func (v Vec) ATimesTransp(u Vec) {
|
||||||
x := make(Vec, len(u));
|
x := make(Vec, len(u))
|
||||||
x.Times(u);
|
x.Times(u)
|
||||||
v.TimesTransp(x);
|
v.TimesTransp(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse();
|
flag.Parse()
|
||||||
N := *n;
|
N := *n
|
||||||
u := make(Vec, N);
|
u := make(Vec, N)
|
||||||
for i := 0; i < N; i++ {
|
for i := 0; i < N; i++ {
|
||||||
u[i] = 1
|
u[i] = 1
|
||||||
}
|
}
|
||||||
v := make(Vec, N);
|
v := make(Vec, N)
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
v.ATimesTransp(u);
|
v.ATimesTransp(u)
|
||||||
u.ATimesTransp(v);
|
u.ATimesTransp(v)
|
||||||
}
|
}
|
||||||
var vBv, vv float64;
|
var vBv, vv float64
|
||||||
for i := 0; i < N; i++ {
|
for i := 0; i < N; i++ {
|
||||||
vBv += u[i] * v[i];
|
vBv += u[i] * v[i]
|
||||||
vv += v[i] * v[i];
|
vv += v[i] * v[i]
|
||||||
}
|
}
|
||||||
fmt.Printf("%0.9f\n", math.Sqrt(vBv/vv));
|
fmt.Printf("%0.9f\n", math.Sqrt(vBv/vv))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag";
|
"flag"
|
||||||
"fmt";
|
"fmt"
|
||||||
"os";
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
var n = flag.Int("n", 1000, "how many passes")
|
var n = flag.Int("n", 1000, "how many passes")
|
||||||
|
|
@ -47,25 +47,25 @@ const Nthread = 503
|
||||||
|
|
||||||
func f(i int, in <-chan int, out chan<- int) {
|
func f(i int, in <-chan int, out chan<- int) {
|
||||||
for {
|
for {
|
||||||
n := <-in;
|
n := <-in
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
fmt.Printf("%d\n", i);
|
fmt.Printf("%d\n", i)
|
||||||
os.Exit(0);
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
out <- n-1;
|
out <- n-1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse();
|
flag.Parse()
|
||||||
|
|
||||||
one := make(chan int); // will be input to thread 1
|
one := make(chan int) // will be input to thread 1
|
||||||
var in, out chan int = nil, one;
|
var in, out chan int = nil, one
|
||||||
for i := 1; i <= Nthread-1; i++ {
|
for i := 1; i <= Nthread-1; i++ {
|
||||||
in, out = out, make(chan int);
|
in, out = out, make(chan int)
|
||||||
go f(i, in, out);
|
go f(i, in, out)
|
||||||
}
|
}
|
||||||
go f(Nthread, out, one);
|
go f(Nthread, out, one)
|
||||||
one <- *n;
|
one <- *n
|
||||||
<-make(chan int); // hang until ring completes
|
<-make(chan int) // hang until ring completes
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue