<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"github.com/jacobsa/comeback/backup"
	"github.com/jacobsa/comeback/fs"
	"github.com/jacobsa/comeback/sys"
	"log"
	"sync"
)

var g_dirSaverOnce sync.Once
var g_dirSaver backup.DirectorySaver

func initDirSaver() {
	blobStore := getBlobStore()

	// Create a user registry.
	userRegistry, err := sys.NewUserRegistry()
	if err != nil {
		log.Fatalln("Creating user registry:", err)
	}

	// Create a group registry.
	groupRegistry, err := sys.NewGroupRegistry()
	if err != nil {
		log.Fatalln("Creating group registry:", err)
	}

	// Create a file system.
	fileSystem, err := fs.NewFileSystem(userRegistry, groupRegistry)
	if err != nil {
		log.Fatalln("Creating file system:", err)
	}

	// Create the file saver.
	const chunkSize = 1 << 24 // 16 MiB
	fileSaver, err := backup.NewFileSaver(blobStore, chunkSize)
	if err != nil {
		log.Fatalln("Creating file saver:", err)
	}

	// Create the directory saver.
	g_dirSaver, err = backup.NewDirectorySaver(
		blobStore,
		fileSystem,
		fileSaver)

	if err != nil {
		log.Fatalln("Creating directory saver:", err)
	}
}

func getDirSaver() backup.DirectorySaver {
	g_dirSaverOnce.Do(initDirSaver)
	return g_dirSaver
}
<commit_msg>Fixed a build error.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"github.com/jacobsa/comeback/backup"
	"github.com/jacobsa/comeback/concurrent"
	"github.com/jacobsa/comeback/fs"
	"github.com/jacobsa/comeback/sys"
	"log"
	"runtime"
	"sync"
)

var g_dirSaverOnce sync.Once
var g_dirSaver backup.DirectorySaver

func initDirSaver() {
	blobStore := getBlobStore()

	// Create a user registry.
	userRegistry, err := sys.NewUserRegistry()
	if err != nil {
		log.Fatalln("Creating user registry:", err)
	}

	// Create a group registry.
	groupRegistry, err := sys.NewGroupRegistry()
	if err != nil {
		log.Fatalln("Creating group registry:", err)
	}

	// Create a file system.
	fileSystem, err := fs.NewFileSystem(userRegistry, groupRegistry)
	if err != nil {
		log.Fatalln("Creating file system:", err)
	}

	// Create the file saver.
	const chunkSize = 1 << 24 // 16 MiB
	numFileSaverWorkers := runtime.NumCPU()

	fileSaver, err := backup.NewFileSaver(
		blobStore,
		chunkSize,
		concurrent.NewExecutor(numFileSaverWorkers),
	)

	if err != nil {
		log.Fatalln("Creating file saver:", err)
	}

	// Create the directory saver.
	g_dirSaver, err = backup.NewDirectorySaver(
		blobStore,
		fileSystem,
		fileSaver)

	if err != nil {
		log.Fatalln("Creating directory saver:", err)
	}
}

func getDirSaver() backup.DirectorySaver {
	g_dirSaverOnce.Do(initDirSaver)
	return g_dirSaver
}
<|endoftext|>


<commit_before>package discovery

import (
	"errors"
	"fmt"
	"net/url"
	"os"
	"strings"

	kv "gopkg.in/Clever/kayvee-go.v2"
)

// m is a convenience type for using kv.
type m map[string]interface{}

const (
	templateVar = "SERVICE_%s_%s_%%s"
)

func getVar(envVar string) (string, error) {
	envVar = strings.ToUpper(envVar)
	envVar = strings.Replace(envVar, "-", "_", -1)
	val := os.Getenv(envVar)
	if val == "" {
		return "", errors.New(kv.FormatLog("discovery-go", kv.Error, "missing env var", m{
			"var": envVar,
		}))
	}
	return val, nil
}

// URL finds the specified URL for a service based off of the service's name and which
// interface you are accessing. Values are found in environment variables fitting the scheme:
// SERVICE_{SERVICE NAME}_{INTERFACE NAME}_{PROTO,HOST,PORT}.
func URL(service, name string) (string, error) {
	proto, err := Proto(service, name)
	if err != nil {
		return "", err
	}
	host, err := Host(service, name)
	if err != nil {
		return "", err
	}
	port, err := Port(service, name)
	if err != nil {
		return "", err
	}

	u := url.URL{
		Scheme: proto,
		Host:   fmt.Sprintf("%s:%s", host, port),
	}
	return u.String(), nil
}

// Proto finds the specified protocol for a service based off of the service's name and which
// interface you are accessing. Values are found in environment variables fitting the scheme:
// SERVICE_{SERVICE NAME}_{INTERFACE NAME}_PROTO.
func Proto(service, name string) (string, error) {
	template := fmt.Sprintf(templateVar, service, name)
	return getVar(fmt.Sprintf(template, "PROTO"))
}

// Host finds the specified host for a service based off of the service's name and which
// interface you are accessing. Values are found in environment variables fitting the scheme:
// SERVICE_{SERVICE NAME}_{INTERFACE NAME}_HOST.
func Host(service, name string) (string, error) {
	template := fmt.Sprintf(templateVar, service, name)
	return getVar(fmt.Sprintf(template, "HOST"))
}

// Port finds the specified port for a service based off of the service's name and which
// interface you are accessing. Values are found in environment variables fitting the scheme:
// SERVICE_{SERVICE NAME}_{INTERFACE NAME}_PORT.
func Port(service, name string) (string, error) {
	template := fmt.Sprintf(templateVar, service, name)
	return getVar(fmt.Sprintf(template, "PORT"))
}
<commit_msg>more extendable approach on URL parsing<commit_after>package discovery

import (
	"errors"
	"fmt"
	"net/url"
	"os"
	"strings"

	kv "gopkg.in/Clever/kayvee-go.v2"
)

// m is a convenience type for using kv.
type m map[string]interface{}

const (
	templateVar = "SERVICE_%s_%s_%%s"
)

func getVar(envVar string) (string, error) {
	envVar = strings.ToUpper(envVar)
	envVar = strings.Replace(envVar, "-", "_", -1)
	val := os.Getenv(envVar)
	if val == "" {
		return "", errors.New(kv.FormatLog("discovery-go", kv.Error, "missing.env.var", m{
			"var": envVar,
		}))
	}
	return val, nil
}

// URL finds the specified URL for a service based off of the service's name and which
// interface you are accessing. Values are found in environment variables fitting the scheme:
// SERVICE_{SERVICE NAME}_{INTERFACE NAME}_{PROTO,HOST,PORT}.
func URL(service, name string) (string, error) {
	proto, err := Proto(service, name)
	if err != nil {
		return "", err
	}
	host, err := Host(service, name)
	if err != nil {
		return "", err
	}
	port, err := Port(service, name)
	if err != nil {
		return "", err
	}

	rawURL := fmt.Sprintf("%s://%s:%s", proto, host, port)
	u, err := url.Parse(rawURL)
	if err != nil {
		return "", errors.New(kv.FormatLog("discovery-go", kv.Error, "missing env var", m{
			"url":   rawURL,
			"error": fmt.Errorf("Failed to parse URL: %s", err.Error()),
		}))
	}
	return u.String(), nil
}

// Proto finds the specified protocol for a service based off of the service's name and which
// interface you are accessing. Values are found in environment variables fitting the scheme:
// SERVICE_{SERVICE NAME}_{INTERFACE NAME}_PROTO.
func Proto(service, name string) (string, error) {
	template := fmt.Sprintf(templateVar, service, name)
	return getVar(fmt.Sprintf(template, "PROTO"))
}

// Host finds the specified host for a service based off of the service's name and which
// interface you are accessing. Values are found in environment variables fitting the scheme:
// SERVICE_{SERVICE NAME}_{INTERFACE NAME}_HOST.
func Host(service, name string) (string, error) {
	template := fmt.Sprintf(templateVar, service, name)
	return getVar(fmt.Sprintf(template, "HOST"))
}

// Port finds the specified port for a service based off of the service's name and which
// interface you are accessing. Values are found in environment variables fitting the scheme:
// SERVICE_{SERVICE NAME}_{INTERFACE NAME}_PORT.
func Port(service, name string) (string, error) {
	template := fmt.Sprintf(templateVar, service, name)
	return getVar(fmt.Sprintf(template, "PORT"))
}
<|endoftext|>


<commit_before>// @author Robin Verlangen
// Discovery service used to detect cluster

package main

// Imports
import (
	"log"
)

// Node (entity in the Dispenso cluster)
type Node struct {
	Host string // Fully qualified hostname
	Port int // Port on which Dispenso runs
}

// Message (payload transmitted between nodes containing instructions)
type Message struct {
	Type MessageType // Type of message
	Payload string // JSON payload
}

// Message types
type messageType int
const (
	discoveryPing	messageType = iota+1 // Initial discovery ping
	disocveryResponse // Discovery response
	discoveryMeta // Metadata beyond initial discovery
	configuration // Used to update configuration in the cluster
	taskRequest // New task submission
	taskApproval // Approve task
	taskReject // Reject task
	taskExecution // After being approved a task execution will be sent to the nodes
)
type MessageType struct {
	code messageType
}

// Discovery service
type DiscoveryService struct {
	Nodes []Node // List of nodes
}

// Create discovery service
func NewDiscoveryService() *DiscoveryService {
	return &DiscoveryService{}
}

// Run discovery service
func (*DiscoveryService) Start() {
	go func() {
		log.Println("Starting discovery")
		// @todo Implement
		shutdown <- true
	}()
}<commit_msg>Shuffle code<commit_after>// @author Robin Verlangen
// Discovery service used to detect cluster

package main

// Imports
import (
	"log"
)

// Node (entity in the Dispenso cluster)
type Node struct {
	Host string // Fully qualified hostname
	Port int // Port on which Dispenso runs
}

// Message (payload transmitted between nodes containing instructions)
type Message struct {
	Type MessageType // Type of message
	Payload string // JSON payload
}

// Message types, enum-like datastructure, use "MessageType" as wrapper
type MessageType struct {
	code messageType
}
type messageType int
const (
	discoveryPing	messageType = iota+1 // Initial discovery ping
	disocveryResponse // Discovery response
	discoveryMeta // Metadata beyond initial discovery
	configuration // Used to update configuration in the cluster
	taskRequest // New task submission
	taskApproval // Approve task
	taskReject // Reject task
	taskExecution // After being approved a task execution will be sent to the nodes
)

// Discovery service
type DiscoveryService struct {
	Nodes []Node // List of nodes
}

// Create discovery service
func NewDiscoveryService() *DiscoveryService {
	return &DiscoveryService{}
}

// Run discovery service
func (*DiscoveryService) Start() {
	go func() {
		log.Println("Starting discovery")
		// @todo Implement
		shutdown <- true
	}()
}<|endoftext|>


<commit_before>package tent

import (
	"bytes"
	"encoding/json"
	"io"
	"mime"
	"net/url"
	"strings"

	"code.google.com/p/go.net/html"
	"github.com/tent/http-link-go"
)

const RelMetaPost = "https://tent.io/rels/meta-post"

type MetaPostServer struct {
	Version    string `json:"version"`
	Preference int    `json:"preference"`

	URLs MetaPostServerURLs `json:"urls"`
}

type MetaPostServerURLs struct {
	OAuthAuth      string `json:"oauth_auth"`
	OAuthToken     string `json:"oauth_token"`
	PostsFeed      string `json:"posts_feed"`
	Post           string `json:"post"`
	NewPost        string `json:"new_post"`
	PostAttachment string `json:"post_attachment"`
	Attachment     string `json:"attachment"`
	Batch          string `json:"batch"`
	ServerInfo     string `json:"server_info"`
}

func (urls *MetaPostServerURLs) PostURL(entity, post, version string) (string, error) {
	u := strings.Replace(urls.Post, "{entity}", url.QueryEscape(entity), 1)
	u = strings.Replace(u, "{post}", post, 1)
	if version != "" {
		if strings.Contains(u, "?") {
			uri, err := url.Parse(u)
			if err != nil {
				return "", err
			}
			q := uri.Query()
			q.Add("version", version)
			uri.RawQuery = q.Encode()
			u = uri.String()
		} else {
			u += "?version=" + version
		}
	}
	return u, nil
}

func (urls *MetaPostServerURLs) PostAttachmentURL(entity, post, name, version string) string {
	u := strings.Replace(urls.PostAttachment, "{entity}", url.QueryEscape(entity), 1)
	u = strings.Replace(u, "{post}", post, 1)
	u = strings.Replace(u, "{name}", url.QueryEscape(name), 1)
	return strings.Replace(u, "{version}", version, 1)
}

func (urls *MetaPostServerURLs) AttachmentURL(entity, digest string) string {
	u := strings.Replace(urls.Attachment, "{entity}", url.QueryEscape(entity), 1)
	return strings.Replace(u, "{digest}", digest, 1)
}

type MetaPost struct {
	Entity  string           `json:"entity"`
	Servers []MetaPostServer `json:"servers"`
	Post    *Post            `json:"-"`
}

func GetMetaPost(url string) (*MetaPost, error) {
	req, err := newRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	res, err := HTTP.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return nil, &BadResponseError{ErrBadStatusCode, res}
	}
	post := &Post{}
	if ok := timeoutRead(res.Body, func() {
		err = json.NewDecoder(res.Body).Decode(post)
	}); !ok {
		return nil, &BadResponseError{ErrReadTimeout, res}
	}
	if err != nil {
		return nil, err
	}
	metaPost := &MetaPost{Post: post}
	err = json.Unmarshal(post.Content, metaPost)
	return metaPost, err
}

func Discover(entity string) (*MetaPost, error) {
	req, err := newRequest("HEAD", entity, nil)
	res, err := HTTP.Do(req)
	if err != nil {
		return nil, err
	}
	res.Body.Close()
	if res.StatusCode < 200 || res.StatusCode >= 300 {
		return nil, &BadResponseError{ErrBadStatusCode, res}
	}

	if linkHeader := res.Header.Get("Link"); linkHeader != "" {
		links, err := link.Parse(linkHeader)
		if err != nil {
			return nil, err
		}
		var metaLinks []string
		for _, l := range links {
			if l.Params["rel"] == RelMetaPost {
				metaLinks = append(metaLinks, l.URL)
			}
		}
		if len(metaLinks) > 0 {
			return getMetaPost(metaLinks, res.Request.URL)
		}
	}

	// we didn't get anything with the HEAD request, so let's try to GET HTML links
	req, _ = newRequest("GET", entity, nil)
	res, err = HTTP.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return nil, &BadResponseError{ErrBadStatusCode, res}
	}
	contentType := res.Header.Get("Content-Type")
	if contentType == "" {
		return nil, &BadResponseError{ErrBadContentType, res}
	}
	mediaType, _, err := mime.ParseMediaType(contentType)
	if err != nil {
		return nil, err
	}
	if mediaType != "text/html" {
		return nil, &BadResponseError{ErrBadContentType, res}
	}

	var links []string
	if ok := timeoutRead(res.Body, func() {
		links, err = parseHTMLMetaLinks(res.Body)
	}); !ok {
		return nil, &BadResponseError{ErrReadTimeout, res}
	}
	if err != nil {
		return nil, err
	}
	if len(links) > 0 {
		return getMetaPost(links, res.Request.URL)
	}

	return nil, nil
}

func getMetaPost(links []string, reqURL *url.URL) (*MetaPost, error) {
	for i, l := range links {
		u, err := url.Parse(l)
		if err != nil {
			return nil, err
		}
		m, err := GetMetaPost(reqURL.ResolveReference(u).String())
		if err != nil && i < len(links)-1 {
			continue
		}
		return m, err
	}
	panic("not reached")
}

func parseHTMLMetaLinks(data io.Reader) (links []string, err error) {
	t := html.NewTokenizer(data)
loop:
	for {
		switch t.Next() {
		case html.ErrorToken:
			err = t.Err()
			if err == io.EOF {
				err = nil
			}
			break loop
		case html.StartTagToken, html.SelfClosingTagToken:
			name, attrs := t.TagName()
			if !attrs || !bytes.Equal(name, []byte("link")) {
				continue loop
			}
			var href string
			var haveRel, metaRel bool
			for {
				key, val, more := t.TagAttr()
				if bytes.Equal(key, []byte("href")) {
					href = string(val)
				} else if bytes.Equal(key, []byte("rel")) {
					haveRel = true
					if bytes.Equal(val, []byte(RelMetaPost)) {
						metaRel = true
					}
				}
				if !more || haveRel && !metaRel || metaRel && href != "" {
					break
				}
			}
			if metaRel && href != "" {
				links = append(links, href)
			}
		}
	}
	return
}
<commit_msg>Fix discovery path when root domain<commit_after>package tent

import (
	"bytes"
	"encoding/json"
	"io"
	"mime"
	"net/url"
	"strings"

	"code.google.com/p/go.net/html"
	"github.com/tent/http-link-go"
)

const RelMetaPost = "https://tent.io/rels/meta-post"

type MetaPostServer struct {
	Version    string `json:"version"`
	Preference int    `json:"preference"`

	URLs MetaPostServerURLs `json:"urls"`
}

type MetaPostServerURLs struct {
	OAuthAuth      string `json:"oauth_auth"`
	OAuthToken     string `json:"oauth_token"`
	PostsFeed      string `json:"posts_feed"`
	Post           string `json:"post"`
	NewPost        string `json:"new_post"`
	PostAttachment string `json:"post_attachment"`
	Attachment     string `json:"attachment"`
	Batch          string `json:"batch"`
	ServerInfo     string `json:"server_info"`
}

func (urls *MetaPostServerURLs) PostURL(entity, post, version string) (string, error) {
	u := strings.Replace(urls.Post, "{entity}", url.QueryEscape(entity), 1)
	u = strings.Replace(u, "{post}", post, 1)
	if version != "" {
		if strings.Contains(u, "?") {
			uri, err := url.Parse(u)
			if err != nil {
				return "", err
			}
			q := uri.Query()
			q.Add("version", version)
			uri.RawQuery = q.Encode()
			u = uri.String()
		} else {
			u += "?version=" + version
		}
	}
	return u, nil
}

func (urls *MetaPostServerURLs) PostAttachmentURL(entity, post, name, version string) string {
	u := strings.Replace(urls.PostAttachment, "{entity}", url.QueryEscape(entity), 1)
	u = strings.Replace(u, "{post}", post, 1)
	u = strings.Replace(u, "{name}", url.QueryEscape(name), 1)
	return strings.Replace(u, "{version}", version, 1)
}

func (urls *MetaPostServerURLs) AttachmentURL(entity, digest string) string {
	u := strings.Replace(urls.Attachment, "{entity}", url.QueryEscape(entity), 1)
	return strings.Replace(u, "{digest}", digest, 1)
}

type MetaPost struct {
	Entity  string           `json:"entity"`
	Servers []MetaPostServer `json:"servers"`
	Post    *Post            `json:"-"`
}

func GetMetaPost(url string) (*MetaPost, error) {
	req, err := newRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	res, err := HTTP.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return nil, &BadResponseError{ErrBadStatusCode, res}
	}
	post := &Post{}
	if ok := timeoutRead(res.Body, func() {
		err = json.NewDecoder(res.Body).Decode(post)
	}); !ok {
		return nil, &BadResponseError{ErrReadTimeout, res}
	}
	if err != nil {
		return nil, err
	}
	metaPost := &MetaPost{Post: post}
	err = json.Unmarshal(post.Content, metaPost)
	return metaPost, err
}

func Discover(entity string) (*MetaPost, error) {
	req, err := newRequest("HEAD", entity, nil)
	if req.URL.Path == "" {
		req.URL.Path = "/"
	}
	res, err := HTTP.Do(req)
	if err != nil {
		return nil, err
	}
	res.Body.Close()
	if res.StatusCode < 200 || res.StatusCode >= 300 {
		return nil, &BadResponseError{ErrBadStatusCode, res}
	}

	if linkHeader := res.Header.Get("Link"); linkHeader != "" {
		links, err := link.Parse(linkHeader)
		if err != nil {
			return nil, err
		}
		var metaLinks []string
		for _, l := range links {
			if l.Params["rel"] == RelMetaPost {
				metaLinks = append(metaLinks, l.URL)
			}
		}
		if len(metaLinks) > 0 {
			return getMetaPost(metaLinks, res.Request.URL)
		}
	}

	// we didn't get anything with the HEAD request, so let's try to GET HTML links
	req, _ = newRequest("GET", entity, nil)
	res, err = HTTP.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return nil, &BadResponseError{ErrBadStatusCode, res}
	}
	contentType := res.Header.Get("Content-Type")
	if contentType == "" {
		return nil, &BadResponseError{ErrBadContentType, res}
	}
	mediaType, _, err := mime.ParseMediaType(contentType)
	if err != nil {
		return nil, err
	}
	if mediaType != "text/html" {
		return nil, &BadResponseError{ErrBadContentType, res}
	}

	var links []string
	if ok := timeoutRead(res.Body, func() {
		links, err = parseHTMLMetaLinks(res.Body)
	}); !ok {
		return nil, &BadResponseError{ErrReadTimeout, res}
	}
	if err != nil {
		return nil, err
	}
	if len(links) > 0 {
		return getMetaPost(links, res.Request.URL)
	}

	return nil, nil
}

func getMetaPost(links []string, reqURL *url.URL) (*MetaPost, error) {
	for i, l := range links {
		u, err := url.Parse(l)
		if err != nil {
			return nil, err
		}
		m, err := GetMetaPost(reqURL.ResolveReference(u).String())
		if err != nil && i < len(links)-1 {
			continue
		}
		return m, err
	}
	panic("not reached")
}

func parseHTMLMetaLinks(data io.Reader) (links []string, err error) {
	t := html.NewTokenizer(data)
loop:
	for {
		switch t.Next() {
		case html.ErrorToken:
			err = t.Err()
			if err == io.EOF {
				err = nil
			}
			break loop
		case html.StartTagToken, html.SelfClosingTagToken:
			name, attrs := t.TagName()
			if !attrs || !bytes.Equal(name, []byte("link")) {
				continue loop
			}
			var href string
			var haveRel, metaRel bool
			for {
				key, val, more := t.TagAttr()
				if bytes.Equal(key, []byte("href")) {
					href = string(val)
				} else if bytes.Equal(key, []byte("rel")) {
					haveRel = true
					if bytes.Equal(val, []byte(RelMetaPost)) {
						metaRel = true
					}
				}
				if !more || haveRel && !metaRel || metaRel && href != "" {
					break
				}
			}
			if metaRel && href != "" {
				links = append(links, href)
			}
		}
	}
	return
}
<|endoftext|>


<commit_before>package betterdb

import (
	"database/sql"
	"reflect"
	"regexp"
	"strings"
)

func ReflectScan(args []reflect.Value) []reflect.Value {
	result := []reflect.Value{}
	rows := args[0].Interface().(*sql.Rows)
	var e error
	cols, e := rows.Columns()
	if nil != e {
		result = append(result, reflect.ValueOf(e))
		return result
	}
	record := args[1].Interface().(reflect.Value).Elem()
	fields := make([]interface{}, len(cols))
	for i, n := range cols {
		if f := record.FieldByName(n); !f.IsValid() {
			fields[i] = nil
		} else {
			fields[i] = record.FieldByName(n).Addr().Interface()
		}
	}
	e = rows.Scan(fields...)
	if nil != e {
		result = append(result, reflect.ValueOf(e))
		return result
	}
	return result
}
func MakeScan(scanFn *func(row *sql.Rows, dest reflect.Value) error) {
	fn := reflect.ValueOf(scanFn).Elem()
	v := reflect.MakeFunc(fn.Type(), ReflectScan)
	fn.Set(v)
}

func Scan(st *sql.Stmt, records interface{}, args ...interface{}) error {
	rows, e := st.Query(args...)
	if nil != e {
		return e
	}
	defer rows.Close()
	var scan func(row *sql.Rows, dest reflect.Value) error
	MakeScan(&scan)
	recordType := reflect.TypeOf(records).Elem().Elem()
	results := reflect.ValueOf(records).Elem()
	var scanError error
	for rows.Next() {
		record := reflect.New(recordType)
		scanError = scan(rows, record)
		if nil != scanError {
			return scanError
		}
		results.Set(reflect.Append(results, record.Elem()))
	}
	return nil
}

func NamedScan(st *sql.Stmt, s string, records interface{}, namedArgs interface{}) error {
	st, args := TransNameStr(s, namedArgs)
	return Scan(st, records, args...)
}

func Select(db *sql.DB, s string, records interface{}, args ...interface{}) error {
	st, e := db.Prepare(s)
	if e != nil {
		return e
	}
	defer st.Close()
	Scan(st, records, args...)
	return nil
}

//variable placeholder should have this form ":var",eg."select name from user where name=:name"
func NamedSelect(db *sql.DB, s string, records interface{}, namedArgs interface{}) error {
	st, args := TransNameStr(s, namedArgs)
	return Query(db, st, records, args...)
}

func NamedUpdate(db *sql.DB, s string, args interface{}) {

}

func ExecuteUpdate(st *sql.Stmt, args ...interface{}) (insertId int64, affectRows int64, e error) {
	var r sql.Result
	r, e = st.Exec(args...)
	if nil != e {
		return
	}
	insertId, e = r.LastInsertId()
	if nil != e {
		return
	}
	affectRows, e = r.RowsAffected()
	if nil != e {
		return
	}
	return
}

/**
map (:name,:age ,{"Name":"jim" , "Age":20}) -> ("?,?",['jim',20])
*/
func TransNameStr(s string, namedArgs interface{}) (st string, args []interface{}) {
	re := regexp.MustCompile(":\\w+")
	kvs := KeyValues{namedArgs}
	st = re.ReplaceAllStringFunc(s, func(key string) string {
		if n, ok := kvs.Get(strings.TrimPrefix(key, ":")); ok {
			args = append(args, n)
			return "?"
		}
		return key
	})
	return
}

type BetterDB struct {
	*sql.DB
}

func (this *BetterDB) Select(s string, records interface{}, args ...interface{}) error {
	return Select(this, s, records, args...)
}

func (this *BetterDB) NamedSelect(s string, records interface{}, args interface{}) error {
	return NamedSelect(this, records, args...)
}
func (this *BetterDB) Update(s string, records interface{}, args ...interface{}) error {
	return nil
}
func (this *BetterDB) UpdateNamed(s string, records interface{}, args interface{}) error {
	return nil
}

//
func (this *BetterDB) UpdateBatch(s string, records interface{}, args interface{}) error {
	return nil
}

func (this *BetterDB) Post(table string, obj interface{}) error {
	return nil
}
func (this *BetterDB) Get(table string, id interface{}, obj interface{}) error {
	return nil
}
func (this *BetterDB) Put(table string, id interface{}, newValues interface{}) error {
	return nil
}
func (this *BetterDB) Delete(table string, id interface{}) error {
	return nil
}

func (this *BetterDB) BatchSqls(sqls []string) error {
	return nil
}

/**
eg.insert into user(Name,Age) values(:Name,:Age) [{Name:"jim" , Age:12}]
*/
func (this *BetterDB) Batch(s string, values []interface{}) error {
	return nil
}
<commit_msg>mode name reg<commit_after>package betterdb

import (
	"database/sql"
	"reflect"
	"regexp"
	"strings"
)

type ExecResult struct {
	InsertId     int64
	RowsAffected int64
	Error        error
}

func ReflectScan(args []reflect.Value) []reflect.Value {
	result := []reflect.Value{}
	rows := args[0].Interface().(*sql.Rows)
	var e error
	cols, e := rows.Columns()
	if nil != e {
		result = append(result, reflect.ValueOf(e))
		return result
	}
	record := args[1].Interface().(reflect.Value).Elem()
	fields := make([]interface{}, len(cols))
	for i, n := range cols {
		if f := record.FieldByName(n); !f.IsValid() {
			fields[i] = nil
		} else {
			fields[i] = record.FieldByName(n).Addr().Interface()
		}
	}
	e = rows.Scan(fields...)
	if nil != e {
		result = append(result, reflect.ValueOf(e))
		return result
	}
	return result
}
func MakeScan(scanFn *func(row *sql.Rows, dest reflect.Value) error) {
	fn := reflect.ValueOf(scanFn).Elem()
	v := reflect.MakeFunc(fn.Type(), ReflectScan)
	fn.Set(v)
}

func Scan(st *sql.Stmt, records interface{}, args ...interface{}) error {
	rows, e := st.Query(args...)
	if nil != e {
		return e
	}
	defer rows.Close()
	var scan func(row *sql.Rows, dest reflect.Value) error
	MakeScan(&scan)
	recordType := reflect.TypeOf(records).Elem().Elem()
	results := reflect.ValueOf(records).Elem()
	var scanError error
	for rows.Next() {
		record := reflect.New(recordType)
		scanError = scan(rows, record)
		if nil != scanError {
			return scanError
		}
		results.Set(reflect.Append(results, record.Elem()))
	}
	return nil
}

func NamedScan(db *sql.DB, s string, records interface{}, namedArgs interface{}) error {
	sqlstring, args := TransNameStr(s, namedArgs)
	st, e := db.Prepare(sqlstring)
	if nil != e {
		return e
	}
	return Scan(st, records, args...)
}

func Select(db *sql.DB, s string, records interface{}, args ...interface{}) error {
	st, e := db.Prepare(s)
	if e != nil {
		return e
	}
	defer st.Close()
	Scan(st, records, args...)
	return nil
}

//variable placeholder should have this form ":var",eg."select name from user where name=:name"
func NamedSelect(db *sql.DB, s string, records interface{}, namedArgs interface{}) error {
	st, args := TransNameStr(s, namedArgs)
	return Select(db, st, records, args...)
}

func Exec(st *sql.Stmt, args []interface{}) (result ExecResult) {
	r, e := st.Exec(args...)
	if nil != e {
		result.Error = e
		return
	}
	result.RowsAffected, e = r.RowsAffected()
	if nil != e {
		result.Error = e
		return
	}
	result.InsertId, e = r.LastInsertId()
	if nil != e {
		result.Error = e
		return
	}
	return
}

func NamedUpdate(db *sql.DB, s string, args interface{}) []ExecResult {
	//st, e := db.Prepare(s)
	//if nil != e {
	//	return []ExecResult{ExecResult{Error: e}}
	//}
	//rargs := reflect.ValueOf(args)RowsAffected

	return []ExecResult{}

}

/**
map (:Name,:Age ,{"Name":"jim" , "Age":20}) -> ("?,?",['jim',20])
*/
func TransNameStr(s string, namedArgs interface{}) (st string, args []interface{}) {
	re := regexp.MustCompile(":[^0-9]\\w*")
	kvs := KeyValues{namedArgs}
	st = re.ReplaceAllStringFunc(s, func(key string) string {
		if n, ok := kvs.Get(strings.TrimPrefix(key, ":")); ok {
			args = append(args, n)
			return "?"
		}
		return key
	})
	return
}

type BetterDB struct {
	*sql.DB
}

func (this *BetterDB) Select(s string, records interface{}, args ...interface{}) error {
	return Select(this.DB, s, records, args...)
}

func (this *BetterDB) NamedSelect(s string, records interface{}, args interface{}) error {
	return NamedSelect(this.DB, s, records, args)
}
func (this *BetterDB) Update(s string, args ...interface{}) ExecResult {
	st, e := this.DB.Prepare(s)
	if nil != e {
		return ExecResult{Error: e}
	}
	return Exec(st, args)
}
func (this *BetterDB) NamedUpdate(s string, records interface{}) error {
	return nil
}

//
func (this *BetterDB) UpdateBatch(s string, args interface{}) error {
	return nil
}

func (this *BetterDB) Post(table string, obj interface{}) error {
	return nil
}
func (this *BetterDB) Get(table string, id interface{}, obj interface{}) error {
	return nil
}
func (this *BetterDB) Put(table string, id interface{}, newValues interface{}) error {
	return nil
}
func (this *BetterDB) Delete(table string, id interface{}) error {
	return nil
}

func (this *BetterDB) BatchSqls(sqls []string) error {
	return nil
}

/**
eg.insert into user(Name,Age) values(:Name,:Age) [{Name:"jim" , Age:12}]
*/
func (this *BetterDB) Batch(s string, values []interface{}) error {
	return nil
}
<|endoftext|>


<commit_before>package xml

/*
#cgo pkg-config: libxml-2.0

#include "helper.h"
*/
import "C"

import (
	"unsafe"
	"os"
	"gokogiri/xpath"
	//	"runtime/debug"
)

type Document interface {
	DocPtr() unsafe.Pointer
	DocType() int
	InputEncoding() []byte
	OutputEncoding() []byte
	DocXPathCtx() *xpath.XPath
	AddUnlinkedNode(unsafe.Pointer)
	ParseFragment([]byte, []byte, int) (*DocumentFragment, os.Error)
	CreateElementNode(string) *ElementNode
	CreateCData(string) *CDataNode
	Free()
	String() string
	Root() *ElementNode
	BookkeepFragment(*DocumentFragment)
}

//xml parse option
const (
	XML_PARSE_RECOVER   = 1 << 0  //relaxed parsing
	XML_PARSE_NOERROR   = 1 << 5  //suppress error reports
	XML_PARSE_NOWARNING = 1 << 6  //suppress warning reports
	XML_PARSE_NONET     = 1 << 11 //forbid network access
)

//default parsing option: relax parsing
var DefaultParseOption = XML_PARSE_RECOVER |
	XML_PARSE_NONET |
	XML_PARSE_NOERROR |
	XML_PARSE_NOWARNING

//libxml2 use "utf-8" by default, and so do we
const DefaultEncoding = "utf-8"

var ERR_FAILED_TO_PARSE_XML = os.NewError("failed to parse xml input")
var emptyStringBytes = []byte{0}

type XmlDocument struct {
	Ptr *C.xmlDoc
	*XmlNode
	InEncoding    []byte
	OutEncoding   []byte
	UnlinkedNodes []unsafe.Pointer
	XPathCtx      *xpath.XPath
	Type          int

	fragments []*DocumentFragment //save the pointers to free them when the doc is freed
}

//default encoding in byte slice
var DefaultEncodingBytes = []byte(DefaultEncoding)

const initialUnlinkedNodes = 8
const initialFragments = 2

//create a document
func NewDocument(p unsafe.Pointer, contentLen int, inEncoding, outEncoding, buffer []byte) (doc *XmlDocument) {
	xmlNode := &XmlNode{Ptr: (*C.xmlNode)(p)}
	adjustedLen := contentLen + contentLen>>1  //1.5 of the input len
	if adjustedLen < initialOutputBufferSize { //min len
		adjustedLen = initialOutputBufferSize
	}
	if len(buffer) < adjustedLen {
		xmlNode.outputBuffer = make([]byte, adjustedLen)
	} else {
		xmlNode.outputBuffer = buffer
	}
	docPtr := (*C.xmlDoc)(p)
	doc = &XmlDocument{Ptr: docPtr, XmlNode: xmlNode, InEncoding: inEncoding, OutEncoding: outEncoding}
	doc.UnlinkedNodes = make([]unsafe.Pointer, 0, initialUnlinkedNodes)
	doc.XPathCtx = xpath.NewXPath(p)
	doc.Type = xmlNode.NodeType()
	doc.fragments = make([]*DocumentFragment, 0, initialFragments)
	xmlNode.Document = doc
	return
}

func ParseWithBuffer(content, inEncoding, url []byte, options int, outEncoding, outBuffer []byte) (doc *XmlDocument, err os.Error) {
	var docPtr *C.xmlDoc
	contentLen := len(content)

	if contentLen > 0 {
		var contentPtr, urlPtr, encodingPtr unsafe.Pointer

		contentPtr = unsafe.Pointer(&content[0])
		if len(url) > 0 {
			url = append(url, 0)
			urlPtr = unsafe.Pointer(&url[0])
		}
		if len(inEncoding) > 0 {
			inEncoding = append(inEncoding, 0)
			encodingPtr = unsafe.Pointer(&inEncoding[0])
		}
		if len(outEncoding) > 0 {
			outEncoding = append(outEncoding, 0)
		}

		docPtr = C.xmlParse(contentPtr, C.int(contentLen), urlPtr, encodingPtr, C.int(options), nil, 0)

		if docPtr == nil {
			err = ERR_FAILED_TO_PARSE_XML
		} else {
			doc = NewDocument(unsafe.Pointer(docPtr), contentLen, inEncoding, outEncoding, outBuffer)
		}

	} else {
		doc = CreateEmptyDocument(inEncoding, outEncoding, outBuffer)
	}
	return
}

//parse a string to document
func Parse(content, inEncoding, url []byte, options int, outEncoding []byte) (doc *XmlDocument, err os.Error) {
	doc, err = ParseWithBuffer(content, inEncoding, url, options, outEncoding, nil)
	return
}

func CreateEmptyDocument(inEncoding, outEncoding, outBuffer []byte) (doc *XmlDocument) {
	docPtr := C.newEmptyXmlDoc()
	doc = NewDocument(unsafe.Pointer(docPtr), 0, inEncoding, outEncoding, outBuffer)
	return
}

func (document *XmlDocument) ParseFragment(input, url []byte, options int) (fragment *DocumentFragment, err os.Error) {
	fragment, err = parsefragment(document, input, document.InputEncoding(), url, options)
	return
}

func (document *XmlDocument) DocPtr() (ptr unsafe.Pointer) {
	ptr = unsafe.Pointer(document.Ptr)
	return
}

func (document *XmlDocument) DocType() (t int) {
	t = document.Type
	return
}

func (document *XmlDocument) InputEncoding() (encoding []byte) {
	encoding = document.InEncoding
	return
}

func (document *XmlDocument) OutputEncoding() (encoding []byte) {
	encoding = document.OutEncoding
	return
}

func (document *XmlDocument) DocXPathCtx() (ctx *xpath.XPath) {
	ctx = document.XPathCtx
	return
}

func (document *XmlDocument) AddUnlinkedNode(nodePtr unsafe.Pointer) {
	document.UnlinkedNodes = append(document.UnlinkedNodes, nodePtr)
}

func (document *XmlDocument) BookkeepFragment(fragment *DocumentFragment) {
	document.fragments = append(document.fragments, fragment)
}

func (document *XmlDocument) Root() (element *ElementNode) {
	nodePtr := C.xmlDocGetRootElement(document.Ptr)
	element = NewNode(unsafe.Pointer(nodePtr), document).(*ElementNode)
	return
}

func (document *XmlDocument) CreateElementNode(tag string) (element *ElementNode) {
	var tagPtr unsafe.Pointer
	if len(tag) > 0 {
		tagBytes := append([]byte(tag), 0)
		tagPtr = unsafe.Pointer(&tagBytes[0])
	}
	newNodePtr := C.xmlNewNode(nil, (*C.xmlChar)(tagPtr))
	newNode := NewNode(unsafe.Pointer(newNodePtr), document)
	element = newNode.(*ElementNode)
	return
}

func (document *XmlDocument) CreateCData(data string) (cdata *CDataNode) {
	var dataPtr unsafe.Pointer
	dataLen := len(data)
	if dataLen > 0 {
		dataBytes := []byte(data)
		dataPtr = unsafe.Pointer(&dataBytes[0])
	} else {
		dataPtr = unsafe.Pointer(&emptyStringBytes[0])
	}
	nodePtr := C.xmlNewCDataBlock(document.Ptr, (*C.xmlChar)(dataPtr), C.int(dataLen))
	if nodePtr != nil {
		cdata = NewNode(unsafe.Pointer(nodePtr), document).(*CDataNode)
	}
	return
}

/*
func (document *XmlDocument) ToXml() string {
	document.outputOffset = 0
	objPtr := unsafe.Pointer(document.XmlNode)
	nodePtr      := unsafe.Pointer(document.Ptr)
	encodingPtr := unsafe.Pointer(&(document.Encoding[0]))
	C.xmlSaveNode(objPtr, nodePtr, encodingPtr, XML_SAVE_AS_XML)
	return string(document.outputBuffer[:document.outputOffset])
}

func (document *XmlDocument) ToHtml() string {
	document.outputOffset = 0
	documentPtr := unsafe.Pointer(document.XmlNode)
	docPtr      := unsafe.Pointer(document.Ptr)
	encodingPtr := unsafe.Pointer(&(document.Encoding[0]))
	C.xmlSaveNode(documentPtr, docPtr, encodingPtr, XML_SAVE_AS_HTML)
	return string(document.outputBuffer[:document.outputOffset])
}

func (document *XmlDocument) ToXml2() string {
	encodingPtr := unsafe.Pointer(&(document.Encoding[0]))
	charPtr := C.xmlDocDumpToString(document.Ptr, encodingPtr, 0)
	defer C.xmlFreeChars(charPtr)
	return C.GoString(charPtr)
}

func (document *XmlDocument) ToHtml2() string {
	charPtr := C.htmlDocDumpToString(document.Ptr, 0)
	defer C.xmlFreeChars(charPtr)
	return C.GoString(charPtr)
}

func (document *XmlDocument) String() string {
	return document.ToXml()
}
*/
func (document *XmlDocument) Free() {
	//must clear the fragments first
	//because the nodes are put in the unlinked list
	for _, fragment := range document.fragments {
		fragment.Remove()
	}

	for _, nodePtr := range document.UnlinkedNodes {
		C.xmlFreeNode((*C.xmlNode)(nodePtr))
	}

	document.XPathCtx.Free()
	C.xmlFreeDoc(document.Ptr)
}
<commit_msg>use Node.<commit_after>package xml

/*
#cgo pkg-config: libxml-2.0

#include "helper.h"
*/
import "C"

import (
	"unsafe"
	"os"
	"gokogiri/xpath"
	//	"runtime/debug"
)

type Document interface {
	DocPtr() unsafe.Pointer
	DocType() int
	InputEncoding() []byte
	OutputEncoding() []byte
	DocXPathCtx() *xpath.XPath
	AddUnlinkedNode(unsafe.Pointer)
	ParseFragment([]byte, []byte, int) (*DocumentFragment, os.Error)
	CreateElementNode(string) *ElementNode
	CreateCData(string) *CDataNode
	Free()
	String() string
	Root() *ElementNode
	BookkeepFragment(*DocumentFragment)
}

//xml parse option
const (
	XML_PARSE_RECOVER   = 1 << 0  //relaxed parsing
	XML_PARSE_NOERROR   = 1 << 5  //suppress error reports
	XML_PARSE_NOWARNING = 1 << 6  //suppress warning reports
	XML_PARSE_NONET     = 1 << 11 //forbid network access
)

//default parsing option: relax parsing
var DefaultParseOption = XML_PARSE_RECOVER |
	XML_PARSE_NONET |
	XML_PARSE_NOERROR |
	XML_PARSE_NOWARNING

//libxml2 use "utf-8" by default, and so do we
const DefaultEncoding = "utf-8"

var ERR_FAILED_TO_PARSE_XML = os.NewError("failed to parse xml input")
var emptyStringBytes = []byte{0}

type XmlDocument struct {
	Ptr *C.xmlDoc
	Node
	InEncoding    []byte
	OutEncoding   []byte
	UnlinkedNodes []unsafe.Pointer
	XPathCtx      *xpath.XPath
	Type          int

	fragments []*DocumentFragment //save the pointers to free them when the doc is freed
}

//default encoding in byte slice
var DefaultEncodingBytes = []byte(DefaultEncoding)

const initialUnlinkedNodes = 8
const initialFragments = 2

//create a document
func NewDocument(p unsafe.Pointer, contentLen int, inEncoding, outEncoding, buffer []byte) (doc *XmlDocument) {
	xmlNode := &XmlNode{Ptr: (*C.xmlNode)(p)}
	adjustedLen := contentLen + contentLen>>1  //1.5 of the input len
	if adjustedLen < initialOutputBufferSize { //min len
		adjustedLen = initialOutputBufferSize
	}
	if len(buffer) < adjustedLen {
		xmlNode.outputBuffer = make([]byte, adjustedLen)
	} else {
		xmlNode.outputBuffer = buffer
	}
	docPtr := (*C.xmlDoc)(p)
	doc = &XmlDocument{Ptr: docPtr, Node: xmlNode, InEncoding: inEncoding, OutEncoding: outEncoding}
	doc.UnlinkedNodes = make([]unsafe.Pointer, 0, initialUnlinkedNodes)
	doc.XPathCtx = xpath.NewXPath(p)
	doc.Type = xmlNode.NodeType()
	doc.fragments = make([]*DocumentFragment, 0, initialFragments)
	xmlNode.Document = doc
	return
}

func ParseWithBuffer(content, inEncoding, url []byte, options int, outEncoding, outBuffer []byte) (doc *XmlDocument, err os.Error) {
	var docPtr *C.xmlDoc
	contentLen := len(content)

	if contentLen > 0 {
		var contentPtr, urlPtr, encodingPtr unsafe.Pointer

		contentPtr = unsafe.Pointer(&content[0])
		if len(url) > 0 {
			url = append(url, 0)
			urlPtr = unsafe.Pointer(&url[0])
		}
		if len(inEncoding) > 0 {
			inEncoding = append(inEncoding, 0)
			encodingPtr = unsafe.Pointer(&inEncoding[0])
		}
		if len(outEncoding) > 0 {
			outEncoding = append(outEncoding, 0)
		}

		docPtr = C.xmlParse(contentPtr, C.int(contentLen), urlPtr, encodingPtr, C.int(options), nil, 0)

		if docPtr == nil {
			err = ERR_FAILED_TO_PARSE_XML
		} else {
			doc = NewDocument(unsafe.Pointer(docPtr), contentLen, inEncoding, outEncoding, outBuffer)
		}

	} else {
		doc = CreateEmptyDocument(inEncoding, outEncoding, outBuffer)
	}
	return
}

//parse a string to document
func Parse(content, inEncoding, url []byte, options int, outEncoding []byte) (doc *XmlDocument, err os.Error) {
	doc, err = ParseWithBuffer(content, inEncoding, url, options, outEncoding, nil)
	return
}

func CreateEmptyDocument(inEncoding, outEncoding, outBuffer []byte) (doc *XmlDocument) {
	docPtr := C.newEmptyXmlDoc()
	doc = NewDocument(unsafe.Pointer(docPtr), 0, inEncoding, outEncoding, outBuffer)
	return
}

func (document *XmlDocument) ParseFragment(input, url []byte, options int) (fragment *DocumentFragment, err os.Error) {
	fragment, err = parsefragment(document, input, document.InputEncoding(), url, options)
	return
}

func (document *XmlDocument) DocPtr() (ptr unsafe.Pointer) {
	ptr = unsafe.Pointer(document.Ptr)
	return
}

func (document *XmlDocument) DocType() (t int) {
	t = document.Type
	return
}

func (document *XmlDocument) InputEncoding() (encoding []byte) {
	encoding = document.InEncoding
	return
}

func (document *XmlDocument) OutputEncoding() (encoding []byte) {
	encoding = document.OutEncoding
	return
}

func (document *XmlDocument) DocXPathCtx() (ctx *xpath.XPath) {
	ctx = document.XPathCtx
	return
}

func (document *XmlDocument) AddUnlinkedNode(nodePtr unsafe.Pointer) {
	document.UnlinkedNodes = append(document.UnlinkedNodes, nodePtr)
}

func (document *XmlDocument) BookkeepFragment(fragment *DocumentFragment) {
	document.fragments = append(document.fragments, fragment)
}

func (document *XmlDocument) Root() (element *ElementNode) {
	nodePtr := C.xmlDocGetRootElement(document.Ptr)
	element = NewNode(unsafe.Pointer(nodePtr), document).(*ElementNode)
	return
}

func (document *XmlDocument) CreateElementNode(tag string) (element *ElementNode) {
	var tagPtr unsafe.Pointer
	if len(tag) > 0 {
		tagBytes := append([]byte(tag), 0)
		tagPtr = unsafe.Pointer(&tagBytes[0])
	}
	newNodePtr := C.xmlNewNode(nil, (*C.xmlChar)(tagPtr))
	newNode := NewNode(unsafe.Pointer(newNodePtr), document)
	element = newNode.(*ElementNode)
	return
}

func (document *XmlDocument) CreateCData(data string) (cdata *CDataNode) {
	var dataPtr unsafe.Pointer
	dataLen := len(data)
	if dataLen > 0 {
		dataBytes := []byte(data)
		dataPtr = unsafe.Pointer(&dataBytes[0])
	} else {
		dataPtr = unsafe.Pointer(&emptyStringBytes[0])
	}
	nodePtr := C.xmlNewCDataBlock(document.Ptr, (*C.xmlChar)(dataPtr), C.int(dataLen))
	if nodePtr != nil {
		cdata = NewNode(unsafe.Pointer(nodePtr), document).(*CDataNode)
	}
	return
}

/*
func (document *XmlDocument) ToXml() string {
	document.outputOffset = 0
	objPtr := unsafe.Pointer(document.XmlNode)
	nodePtr      := unsafe.Pointer(document.Ptr)
	encodingPtr := unsafe.Pointer(&(document.Encoding[0]))
	C.xmlSaveNode(objPtr, nodePtr, encodingPtr, XML_SAVE_AS_XML)
	return string(document.outputBuffer[:document.outputOffset])
}

func (document *XmlDocument) ToHtml() string {
	document.outputOffset = 0
	documentPtr := unsafe.Pointer(document.XmlNode)
	docPtr      := unsafe.Pointer(document.Ptr)
	encodingPtr := unsafe.Pointer(&(document.Encoding[0]))
	C.xmlSaveNode(documentPtr, docPtr, encodingPtr, XML_SAVE_AS_HTML)
	return string(document.outputBuffer[:document.outputOffset])
}

func (document *XmlDocument) ToXml2() string {
	encodingPtr := unsafe.Pointer(&(document.Encoding[0]))
	charPtr := C.xmlDocDumpToString(document.Ptr, encodingPtr, 0)
	defer C.xmlFreeChars(charPtr)
	return C.GoString(charPtr)
}

func (document *XmlDocument) ToHtml2() string {
	charPtr := C.htmlDocDumpToString(document.Ptr, 0)
	defer C.xmlFreeChars(charPtr)
	return C.GoString(charPtr)
}

func (document *XmlDocument) String() string {
	return document.ToXml()
}
*/
func (document *XmlDocument) Free() {
	//must clear the fragments first
	//because the nodes are put in the unlinked list
	for _, fragment := range document.fragments {
		fragment.Remove()
	}

	for _, nodePtr := range document.UnlinkedNodes {
		C.xmlFreeNode((*C.xmlNode)(nodePtr))
	}

	document.XPathCtx.Free()
	C.xmlFreeDoc(document.Ptr)
}
<|endoftext|>


<commit_before>package config

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

var expectedRepositories = []string{
	"busybox",
	"nginx:stable",
	"mesosphere/marathon-lb~/^v1/",
	"quay.io/coreos/awscli=master,latest,edge",
	"gcr.io/google-containers/hyperkube~/^v1\\.(9|10)\\./",
}

func TestLoadYAMLFile(t *testing.T) {
	assert := assert.New(t)

	c, err := LoadYAMLFile("../fixtures/config/config.yaml")

	assert.NotNil(c, "should load config from valid config file")

	assert.Nil(err, "should NOT give an error while loading valid config file")

	if c != nil {
		assert.Equal(expectedRepositories, c.Repositories)
	}
}

func TestLoadYAMLFile_Shared(t *testing.T) {
	assert := assert.New(t)

	c, err := LoadYAMLFile("../fixtures/config/config.yaml.shared")

	assert.NotNil(c, "should load config from valid config file shared with others")

	assert.Nil(err, "should NOT give an error while loading valid shared config file")

	if c != nil {
		assert.Equal(expectedRepositories, c.Repositories)
	}
}

func TestLoadYAMLFile_Invalid(t *testing.T) {
	assert := assert.New(t)

	c, err := LoadYAMLFile("../fixtures/config/config.yaml.invalid")

	assert.Nil(c, "should NOT load config from invalid config file")

	assert.NotNil(err, "should give an error while trying to load invalid config file")
}

func TestLoadYAMLFile_Irrelevant(t *testing.T) {
	assert := assert.New(t)

	c, err := LoadYAMLFile("../fixtures/config/config.yaml.irrelevant")

	assert.Nil(c, "should NOT load config from irrelevant config file")

	assert.NotNil(err, "should give an error while trying to load irrelevant config file")
}

func TestLoadYAMLFile_NonExisting(t *testing.T) {
	assert := assert.New(t)

	c, err := LoadYAMLFile("/i/do/not/exist/sorry")

	assert.Nil(c, "should NOT load config from non-existing config file")

	assert.NotNil(err, "should give an error while trying to load non-existing config file")
}
<commit_msg>NORELEASE: Rename `c` => `yc` in `config_test.go`<commit_after>package config

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

var expectedRepositories = []string{
	"busybox",
	"nginx:stable",
	"mesosphere/marathon-lb~/^v1/",
	"quay.io/coreos/awscli=master,latest,edge",
	"gcr.io/google-containers/hyperkube~/^v1\\.(9|10)\\./",
}

func TestLoadYAMLFile(t *testing.T) {
	assert := assert.New(t)

	yc, err := LoadYAMLFile("../fixtures/config/config.yaml")

	assert.NotNil(yc, "should load config from valid config file")

	assert.Nil(err, "should NOT give an error while loading valid config file")

	if yc != nil {
		assert.Equal(expectedRepositories, yc.Repositories)
	}
}

func TestLoadYAMLFile_Shared(t *testing.T) {
	assert := assert.New(t)

	yc, err := LoadYAMLFile("../fixtures/config/config.yaml.shared")

	assert.NotNil(yc, "should load config from valid config file shared with others")

	assert.Nil(err, "should NOT give an error while loading valid shared config file")

	if yc != nil {
		assert.Equal(expectedRepositories, yc.Repositories)
	}
}

func TestLoadYAMLFile_Invalid(t *testing.T) {
	assert := assert.New(t)

	yc, err := LoadYAMLFile("../fixtures/config/config.yaml.invalid")

	assert.Nil(yc, "should NOT load config from invalid config file")

	assert.NotNil(err, "should give an error while trying to load invalid config file")
}

func TestLoadYAMLFile_Irrelevant(t *testing.T) {
	assert := assert.New(t)

	yc, err := LoadYAMLFile("../fixtures/config/config.yaml.irrelevant")

	assert.Nil(yc, "should NOT load config from irrelevant config file")

	assert.NotNil(err, "should give an error while trying to load irrelevant config file")
}

func TestLoadYAMLFile_NonExisting(t *testing.T) {
	assert := assert.New(t)

	yc, err := LoadYAMLFile("/i/do/not/exist/sorry")

	assert.Nil(yc, "should NOT load config from non-existing config file")

	assert.NotNil(err, "should give an error while trying to load non-existing config file")
}
<|endoftext|>


<commit_before>/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package config

import (
	"testing"

	"github.com/mesos/mesos-go/mesosproto"
	"github.com/stretchr/testify/assert"
)

func TestSetConfig(t *testing.T) {
	var val bool
	getConfigFromFile("config")
	SetConfig("test", true)
	val = GetConfig().GetBool("test")
	if !val {
		t.Errorf("expected val to be true, but got %v", val)
	}
}

func TestGetAppFolder(t *testing.T) {
	folder := GetAppFolder()
	if folder != "poddata" {
		t.Errorf("expected folder to be poddata, but got %s", folder)
	}
}

func TestGetStopTimeout(t *testing.T) {
	tests := []struct {
		name  string
		input interface{}
		want  int
	}{
		{"correct integer value", 25, 25},
		{"correct string value", "25", 25},
		{"correct duration value", "25s", 25},
		{"check default value", "", 20},
		{"incorrect value", "xyz", 20},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			GetConfig().Set(COMPOSE_STOP_TIMEOUT, test.input)

			got := GetStopTimeout()
			if got != test.want {
				t.Errorf("expected cleanpod.timeout to be %d, but got %d", test.want, got)
			}
		})
	}
}

func TestGetMaxRetry(t *testing.T) {
	max := GetMaxRetry()
	if max != 3 {
		t.Errorf("expected max retry to be 3, but got %d", max)
	}
}

func TestGetPullRetryCount(t *testing.T) {
	count := GetPullRetryCount()
	if count != 3 {
		t.Errorf("expected pull retry to be 3, but got %d", count)
	}
}

func TestOverrideConfig(t *testing.T) {
	type test struct {
		key         string
		val         string
		expectedKey string
		expectedVal string
		msg         string
	}

	overrideTests := []test{
		{"config.test1", "test1", "test1key", "", "shouldn't reset config if key isn't set"},
		{"config.cleanpod.timeout", "1", "cleanpod.timeout", "1", "should reset config if key is set"},
		{"config.launchtask.timeout", "1", "launchtask.timeout", "1", "should reset config if key is set"},
		{"config1.launchtask.timeout", "2", "launchtask.timeout", "1", "shouldn't reset config with invalid prefix"},
	}

	for _, ot := range overrideTests {
		var labels []*mesosproto.Label
		labels = append(labels, &mesosproto.Label{Key: &ot.key, Value: &ot.val})
		taskInfo := &mesosproto.TaskInfo{Labels: &mesosproto.Labels{Labels: labels}}
		OverrideConfig(taskInfo)
		assert.Equal(t, ot.expectedVal, GetConfig().GetString(ot.expectedKey), ot.msg)
	}
}
<commit_msg>modified test case<commit_after>/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package config

import (
	"testing"

	"github.com/mesos/mesos-go/mesosproto"
	"github.com/stretchr/testify/assert"
)

func TestSetConfig(t *testing.T) {
	var val bool
	getConfigFromFile("config")
	SetConfig("test", true)
	val = GetConfig().GetBool("test")
	if !val {
		t.Errorf("expected val to be true, but got %v", val)
	}
}

func TestGetAppFolder(t *testing.T) {
	folder := GetAppFolder()
	if folder != "poddata" {
		t.Errorf("expected folder to be poddata, but got %s", folder)
	}
}

func TestGetStopTimeout(t *testing.T) {
	tests := []struct {
		name  string
		input interface{}
		want  int
	}{
		{"correct integer value", 25, 25},
		{"correct string value", "25", 25},
		{"correct duration value", "25s", 25},
		{"check default value", "", DEFAULT_COMPOSE_STOP_TIMEOUT},
		{"incorrect value", "xyz", DEFAULT_COMPOSE_STOP_TIMEOUT},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			GetConfig().Set(COMPOSE_STOP_TIMEOUT, test.input)

			got := GetStopTimeout()
			if got != test.want {
				t.Errorf("expected cleanpod.timeout to be %d, but got %d", test.want, got)
			}
		})
	}
}

func TestGetMaxRetry(t *testing.T) {
	max := GetMaxRetry()
	if max != 3 {
		t.Errorf("expected max retry to be 3, but got %d", max)
	}
}

func TestGetPullRetryCount(t *testing.T) {
	count := GetPullRetryCount()
	if count != 3 {
		t.Errorf("expected pull retry to be 3, but got %d", count)
	}
}

func TestOverrideConfig(t *testing.T) {
	type test struct {
		key         string
		val         string
		expectedKey string
		expectedVal string
		msg         string
	}

	overrideTests := []test{
		{"config.test1", "test1", "test1key", "", "shouldn't reset config if key isn't set"},
		{"config.cleanpod.timeout", "1", "cleanpod.timeout", "1", "should reset config if key is set"},
		{"config.launchtask.timeout", "1", "launchtask.timeout", "1", "should reset config if key is set"},
		{"config1.launchtask.timeout", "2", "launchtask.timeout", "1", "shouldn't reset config with invalid prefix"},
	}

	for _, ot := range overrideTests {
		var labels []*mesosproto.Label
		labels = append(labels, &mesosproto.Label{Key: &ot.key, Value: &ot.val})
		taskInfo := &mesosproto.TaskInfo{Labels: &mesosproto.Labels{Labels: labels}}
		OverrideConfig(taskInfo)
		assert.Equal(t, ot.expectedVal, GetConfig().GetString(ot.expectedKey), ot.msg)
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package graphicscommand

import (
	"github.com/hajimehoshi/ebiten/internal/opengl"
)

// framebuffer is a wrapper of OpenGL's framebuffer.
type framebuffer struct {
	native    opengl.Framebuffer
	proMatrix []float32
	width     int
	height    int
}

// newFramebufferFromTexture creates a framebuffer from the given texture.
func newFramebufferFromTexture(texture *texture, width, height int) (*framebuffer, error) {
	native, err := opengl.GetContext().NewFramebuffer(opengl.Texture(texture.native))
	if err != nil {
		return nil, err
	}
	return &framebuffer{
		native: native,
		width:  width,
		height: height,
	}, nil
}

// newScreenFramebuffer creates a framebuffer for the screen.
func newScreenFramebuffer(width, height int) *framebuffer {
	return &framebuffer{
		native: opengl.GetContext().ScreenFramebuffer(),
		width:  width,
		height: height,
	}
}

// viewportSize returns the viewport size of the framebuffer.
func (f *framebuffer) viewportSize() (int, int) {
	// On some environments, viewport size must be within the framebuffer size.
	// e.g. Edge (#71), Chrome on GPD Pocket (#420), macOS Mojave (#691).
	// Use the same size of the framebuffer here.
	return f.width, f.height
}

// setAsViewport sets the framebuffer as the current viewport.
func (f *framebuffer) setAsViewport() {
	w, h := f.viewportSize()
	opengl.GetContext().SetViewport(f.native, w, h)
}

// projectionMatrix returns a projection matrix of the framebuffer.
//
// A projection matrix converts the coodinates on the framebuffer
// (0, 0) - (viewport width, viewport height)
// to the normalized device coodinates (-1, -1) - (1, 1) with adjustment.
func (f *framebuffer) projectionMatrix() []float32 {
	if f.proMatrix != nil {
		return f.proMatrix
	}
	w, h := f.viewportSize()
	f.proMatrix = opengl.OrthoProjectionMatrix(0, w, 0, h)
	return f.proMatrix
}
<commit_msg>graphicscommand: Remove unneeded type conversion<commit_after>// Copyright 2014 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package graphicscommand

import (
	"github.com/hajimehoshi/ebiten/internal/opengl"
)

// framebuffer is a wrapper of OpenGL's framebuffer.
type framebuffer struct {
	native    opengl.Framebuffer
	proMatrix []float32
	width     int
	height    int
}

// newFramebufferFromTexture creates a framebuffer from the given texture.
func newFramebufferFromTexture(texture *texture, width, height int) (*framebuffer, error) {
	native, err := opengl.GetContext().NewFramebuffer(texture.native)
	if err != nil {
		return nil, err
	}
	return &framebuffer{
		native: native,
		width:  width,
		height: height,
	}, nil
}

// newScreenFramebuffer creates a framebuffer for the screen.
func newScreenFramebuffer(width, height int) *framebuffer {
	return &framebuffer{
		native: opengl.GetContext().ScreenFramebuffer(),
		width:  width,
		height: height,
	}
}

// viewportSize returns the viewport size of the framebuffer.
func (f *framebuffer) viewportSize() (int, int) {
	// On some environments, viewport size must be within the framebuffer size.
	// e.g. Edge (#71), Chrome on GPD Pocket (#420), macOS Mojave (#691).
	// Use the same size of the framebuffer here.
	return f.width, f.height
}

// setAsViewport sets the framebuffer as the current viewport.
func (f *framebuffer) setAsViewport() {
	w, h := f.viewportSize()
	opengl.GetContext().SetViewport(f.native, w, h)
}

// projectionMatrix returns a projection matrix of the framebuffer.
//
// A projection matrix converts the coodinates on the framebuffer
// (0, 0) - (viewport width, viewport height)
// to the normalized device coodinates (-1, -1) - (1, 1) with adjustment.
func (f *framebuffer) projectionMatrix() []float32 {
	if f.proMatrix != nil {
		return f.proMatrix
	}
	w, h := f.viewportSize()
	f.proMatrix = opengl.OrthoProjectionMatrix(0, w, 0, h)
	return f.proMatrix
}
<|endoftext|>


<commit_before>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package pagecheck implements HTML checkers for discovery site pages.
// It uses the general-purpose checkers in internal/testing/htmlcheck to define
// site-specific checkers.
package pagecheck

import (
	"fmt"
	"path"
	"regexp"

	"golang.org/x/pkgsite/internal/stdlib"
	"golang.org/x/pkgsite/internal/testing/htmlcheck"
)

// Page describes a discovery site web page for a package, module or directory.
type Page struct {
	ModulePath       string
	Suffix           string // package or directory path after module path; empty for a module
	Version          string
	FormattedVersion string
	Title            string
	LicenseType      string
	LicenseFilePath  string
	IsLatest         bool   // is this the latest version of this module?
	LatestLink       string // href of "Go to latest" link
	PackageURLFormat string // the relative package URL, with one %s for "@version"; also used for dirs
	ModuleURL        string // the relative module URL
}

// Overview describes the contents of the overview tab.
type Overview struct {
	ModuleLink     string // relative link to module page
	ModuleLinkText string
	RepoURL        string
	PackageURL     string
	ReadmeContent  string
	ReadmeSource   string
}

var (
	in                 = htmlcheck.In
	inAll              = htmlcheck.InAll
	text               = htmlcheck.HasText
	exactText          = htmlcheck.HasExactText
	exactTextCollapsed = htmlcheck.HasExactTextCollapsed
	attr               = htmlcheck.HasAttr
	href               = htmlcheck.HasHref
)

// PackageHeader checks a details page header for a package.
func PackageHeader(p *Page, versionedURL bool) htmlcheck.Checker {
	fv := p.FormattedVersion
	if fv == "" {
		fv = p.Version
	}
	curBreadcrumb := path.Base(p.Suffix)
	if p.Suffix == "" {
		curBreadcrumb = p.ModulePath
	}
	return in("",
		in("span.DetailsHeader-breadcrumbCurrent", exactText(curBreadcrumb)),
		in("h1.DetailsHeader-title", exactTextCollapsed(p.Title)),
		in("div.DetailsHeader-version", exactText(fv)),
		versionBadge(p),
		licenseInfo(p, packageURLPath(p, versionedURL)),
		packageTabLinks(p, versionedURL),
		moduleInHeader(p, versionedURL))
}

// ModuleHeader checks a details page header for a module.
func ModuleHeader(p *Page, versionedURL bool) htmlcheck.Checker {
	fv := p.FormattedVersion
	if fv == "" {
		fv = p.Version
	}
	curBreadcrumb := p.ModulePath
	if p.ModulePath == stdlib.ModulePath {
		curBreadcrumb = "Standard library"
	}
	return in("",
		in("span.DetailsHeader-breadcrumbCurrent", exactText(curBreadcrumb)),
		in("h1.DetailsHeader-title", exactTextCollapsed(p.Title)),
		in("div.DetailsHeader-version", exactText(fv)),
		versionBadge(p),
		licenseInfo(p, moduleURLPath(p, versionedURL)),
		moduleTabLinks(p, versionedURL))
}

// DirectoryHeader checks a details page header for a directory.
func DirectoryHeader(p *Page, versionedURL bool) htmlcheck.Checker {
	fv := p.FormattedVersion
	if fv == "" {
		fv = p.Version
	}
	return in("",
		in("span.DetailsHeader-breadcrumbCurrent", exactText(path.Base(p.Suffix))),
		in("h1.DetailsHeader-title", exactTextCollapsed(p.Title)),
		in("div.DetailsHeader-version", exactText(fv)),
		// directory pages don't show a header badge
		in("div.DetailsHeader-version", exactText(fv)),
		licenseInfo(p, packageURLPath(p, versionedURL)),
		// directory module links are always versioned (see b/144217401)
		moduleInHeader(p, true))
}

// UnitHeader checks a main page header for a unit.
func UnitHeader(p *Page, versionedURL bool, isPackage bool) htmlcheck.Checker {
	urlPath := packageURLPath(p, versionedURL)
	curBreadcrumb := path.Base(p.Suffix)
	if p.Suffix == "" {
		curBreadcrumb = p.ModulePath
	}
	licenseText := p.LicenseType
	licenseLink := urlPath + "?tab=licenses"
	if p.LicenseType == "" {
		licenseText = "not legal advice"
		licenseLink = "/license-policy"
	}

	importsDetails := in("",
		in(`[data-test-id="UnitHeader-imports"]`,
			in("a",
				href(urlPath+"?tab=imports"),
				text("[0-9]+ Imports"))),
		in(`[data-test-id="UnitHeader-importedby"]`,
			in("a",
				href(urlPath+"?tab=importedby"),
				text(`[0-9]+ Imported by`))))
	if !isPackage {
		importsDetails = nil
	}

	return in("header.UnitHeader",
		in(`[data-test-id="UnitHeader-breadcrumbCurrent"]`, text(curBreadcrumb)),
		in(`[data-test-id="UnitHeader-title"]`, text(p.Title)),
		in(`[data-test-id="UnitHeader-version"]`,
			in("a",
				href("?tab=versions"),
				exactText("Version "+p.FormattedVersion))),
		in(`[data-test-id="UnitHeader-commitTime"]`,
			text("0 hours ago")),
		in(`[data-test-id="UnitHeader-licenses"]`,
			in("a",
				href(licenseLink),
				text(licenseText))),
		importsDetails)
}

// UnitReadme checks the readme section of the main page.
func UnitReadme() htmlcheck.Checker {
	return in(".UnitReadme",
		in(`[data-test-id="Unit-readmeContent"]`, text("readme")),
	)
}

// UnitDoc checks the doc section of the main page.
func UnitDoc() htmlcheck.Checker {
	return in(".Documentation", text(`Overview`))
}

// UnitDirectories checks the directories section of the main page.
// If firstHref isn't empty, it and firstText should exactly match
// href and text of the first link in the Directories table.
func UnitDirectories(firstHref, firstText string) htmlcheck.Checker {
	var link htmlcheck.Checker
	if firstHref != "" {
		link = in(`[data-test-id="UnitDirectories-table"] a`, href(firstHref), exactText(firstText))
	}
	return in("",
		in("th:nth-child(1)", text("^Path$")),
		in("th:nth-child(2)", text("^Synopsis$")),
		link)
}

// CanonicalURLPath checks the canonical url for the unit on the page.
func CanonicalURLPath(path string) htmlcheck.Checker {
	return in(".js-canonicalURLPath", attr("data-canonical-url-path", path))
}

// SubdirectoriesDetails checks the detail section of a subdirectories tab.
// If firstHref isn't empty, it and firstText should exactly match
// href and text of the first link in the Directories table.
func SubdirectoriesDetails(firstHref, firstText string) htmlcheck.Checker {
	var link htmlcheck.Checker
	if firstHref != "" {
		link = in("table.Directories a", href(firstHref), exactText(firstText))
	}
	return in("",
		in("th:nth-child(1)", text("^Path$")),
		in("th:nth-child(2)", text("^Synopsis$")),
		link)
}

// LicenseDetails checks the details section of a license tab.
func LicenseDetails(ltype, bodySubstring, source string) htmlcheck.Checker {
	return in("",
		in(".License",
			text(regexp.QuoteMeta(ltype)),
			text("This is not legal advice"),
			in("a",
				href("/license-policy"),
				exactText("Read disclaimer.")),
			in(".License-contents",
				text(regexp.QuoteMeta(bodySubstring)))),
		in(".License-source",
			exactText("Source: "+source)))
}

// OverviewDetails checks the details section of an overview tab.
func OverviewDetails(ov *Overview) htmlcheck.Checker {
	var pkg htmlcheck.Checker
	if ov.PackageURL != "" {
		pkg = in(".Overview-sourceCodeLink a:nth-of-type(2)",
			href(ov.PackageURL),
			exactText(ov.PackageURL))
	}
	return in("",
		in("div.Overview-module > a",
			href(ov.ModuleLink),
			exactText(ov.ModuleLinkText)),
		in(".Overview-sourceCodeLink a:nth-of-type(1)",
			href(ov.RepoURL),
			exactText(ov.RepoURL)),
		pkg,
		in(".Overview-readmeContent", text(ov.ReadmeContent)),
		in(".Overview-readmeSource", exactText("Source: "+ov.ReadmeSource)))
}

// versionBadge checks the latest-version badge on a header.
func versionBadge(p *Page) htmlcheck.Checker {
	class := "DetailsHeader-badge"
	if p.IsLatest {
		class += "--latest"
	} else {
		class += "--goToLatest"
	}
	return in("div.DetailsHeader-badge",
		attr("class", `\b`+regexp.QuoteMeta(class)+`\b`), // the badge has this class too
		in("a", href(p.LatestLink), exactText("Go to latest")))
}

// licenseInfo checks the license part of the info label in the header.
func licenseInfo(p *Page, urlPath string) htmlcheck.Checker {
	if p.LicenseType == "" {
		return in("[data-test-id=DetailsHeader-infoLabelLicense]", text("None detected"))
	}
	return in("[data-test-id=DetailsHeader-infoLabelLicense] a",
		href(fmt.Sprintf("%s?tab=licenses#lic-0", urlPath)),
		exactText(p.LicenseType))
}

// moduleInHeader checks the module part of the info label in the header.
func moduleInHeader(p *Page, versionedURL bool) htmlcheck.Checker {
	modURL := moduleURLPath(p, versionedURL)
	text := p.ModulePath
	if p.ModulePath == stdlib.ModulePath {
		text = "Standard library"
	}
	return in("a[data-test-id=DetailsHeader-infoLabelModule]", href(modURL), exactText(text))
}

// Check that all the navigation tabs link to the same package at the same version.
func packageTabLinks(p *Page, versionedURL bool) htmlcheck.Checker {
	return inAll("a.DetailsNav-link[href]",
		attr("href", "^"+regexp.QuoteMeta(packageURLPath(p, versionedURL))))
}

// Check that all the navigation tabs link to the same module at the same version.
func moduleTabLinks(p *Page, versionedURL bool) htmlcheck.Checker {
	return inAll("a.DetailsNav-link[href]",
		attr("href", "^"+regexp.QuoteMeta(moduleURLPath(p, versionedURL))))
}

func packageURLPath(p *Page, versioned bool) string {
	v := ""
	if versioned {
		v = "@" + p.Version
	}
	return fmt.Sprintf(p.PackageURLFormat, v)
}

func moduleURLPath(p *Page, versioned bool) string {
	if versioned {
		return p.ModuleURL + "@" + p.Version
	}
	return p.ModuleURL
}
<commit_msg>internal/testing: updates to pagecheck package<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package pagecheck implements HTML checkers for discovery site pages.
// It uses the general-purpose checkers in internal/testing/htmlcheck to define
// site-specific checkers.
package pagecheck

import (
	"fmt"
	"path"
	"regexp"

	"golang.org/x/pkgsite/internal/stdlib"
	"golang.org/x/pkgsite/internal/testing/htmlcheck"
)

// Page describes a discovery site web page for a package, module or directory.
type Page struct {
	ModulePath       string
	Suffix           string // package or directory path after module path; empty for a module
	Version          string
	FormattedVersion string
	Title            string
	LicenseType      string
	LicenseFilePath  string
	IsLatest         bool   // is this the latest version of this module?
	LatestLink       string // href of "Go to latest" link
	PackageURLFormat string // the relative package URL, with one %s for "@version"; also used for dirs
	ModuleURL        string // the relative module URL
	CommitTime       string
}

// Overview describes the contents of the overview tab.
type Overview struct {
	ModuleLink     string // relative link to module page
	ModuleLinkText string
	RepoURL        string
	PackageURL     string
	ReadmeContent  string
	ReadmeSource   string
}

var (
	in                 = htmlcheck.In
	inAll              = htmlcheck.InAll
	text               = htmlcheck.HasText
	exactText          = htmlcheck.HasExactText
	exactTextCollapsed = htmlcheck.HasExactTextCollapsed
	attr               = htmlcheck.HasAttr
	href               = htmlcheck.HasHref
)

// PackageHeader checks a details page header for a package.
func PackageHeader(p *Page, versionedURL bool) htmlcheck.Checker {
	fv := p.FormattedVersion
	if fv == "" {
		fv = p.Version
	}
	curBreadcrumb := path.Base(p.Suffix)
	if p.Suffix == "" {
		curBreadcrumb = p.ModulePath
	}
	return in("",
		in("span.DetailsHeader-breadcrumbCurrent", exactText(curBreadcrumb)),
		in("h1.DetailsHeader-title", exactTextCollapsed(p.Title)),
		in("div.DetailsHeader-version", exactText(fv)),
		versionBadge(p),
		licenseInfo(p, packageURLPath(p, versionedURL)),
		packageTabLinks(p, versionedURL),
		moduleInHeader(p, versionedURL))
}

// ModuleHeader checks a details page header for a module.
func ModuleHeader(p *Page, versionedURL bool) htmlcheck.Checker {
	fv := p.FormattedVersion
	if fv == "" {
		fv = p.Version
	}
	curBreadcrumb := p.ModulePath
	if p.ModulePath == stdlib.ModulePath {
		curBreadcrumb = "Standard library"
	}
	return in("",
		in("span.DetailsHeader-breadcrumbCurrent", exactText(curBreadcrumb)),
		in("h1.DetailsHeader-title", exactTextCollapsed(p.Title)),
		in("div.DetailsHeader-version", exactText(fv)),
		versionBadge(p),
		licenseInfo(p, moduleURLPath(p, versionedURL)),
		moduleTabLinks(p, versionedURL))
}

// DirectoryHeader checks a details page header for a directory.
func DirectoryHeader(p *Page, versionedURL bool) htmlcheck.Checker {
	fv := p.FormattedVersion
	if fv == "" {
		fv = p.Version
	}
	return in("",
		in("span.DetailsHeader-breadcrumbCurrent", exactText(path.Base(p.Suffix))),
		in("h1.DetailsHeader-title", exactTextCollapsed(p.Title)),
		in("div.DetailsHeader-version", exactText(fv)),
		// directory pages don't show a header badge
		in("div.DetailsHeader-version", exactText(fv)),
		licenseInfo(p, packageURLPath(p, versionedURL)),
		// directory module links are always versioned (see b/144217401)
		moduleInHeader(p, true))
}

// UnitHeader checks a main page header for a unit.
func UnitHeader(p *Page, versionedURL bool, isPackage bool) htmlcheck.Checker {
	urlPath := packageURLPath(p, versionedURL)
	curBreadcrumb := path.Base(p.Suffix)
	if p.Suffix == "" {
		curBreadcrumb = p.ModulePath
	}
	licenseText := p.LicenseType
	licenseLink := urlPath + "?tab=licenses"
	if p.LicenseType == "" {
		licenseText = "not legal advice"
		licenseLink = "/license-policy"
	}

	importsDetails := in("",
		in(`[data-test-id="UnitHeader-imports"]`,
			in("a",
				href(urlPath+"?tab=imports"),
				text(`[0-9]+\+? Imports`))),
		in(`[data-test-id="UnitHeader-importedby"]`,
			in("a",
				href(urlPath+"?tab=importedby"),
				text(`[0-9]+\+? Imported by`))))
	if !isPackage {
		importsDetails = nil
	}

	commitTime := p.CommitTime
	if commitTime == "" {
		commitTime = "0 hours ago"
	}

	return in("header.UnitHeader",
		in(`[data-test-id="UnitHeader-breadcrumbCurrent"]`, text(curBreadcrumb)),
		in(`[data-test-id="UnitHeader-title"]`, text(p.Title)),
		in(`[data-test-id="UnitHeader-version"]`,
			in("a",
				href("?tab=versions"),
				exactText("Version "+p.FormattedVersion))),
		in(`[data-test-id="UnitHeader-commitTime"]`,
			text(commitTime)),
		in(`[data-test-id="UnitHeader-licenses"]`,
			in("a",
				href(licenseLink),
				text(licenseText))),
		importsDetails)
}

// UnitReadme checks the readme section of the main page.
func UnitReadme() htmlcheck.Checker {
	return in(".UnitReadme",
		in(`[data-test-id="Unit-readmeContent"]`, text("readme")),
	)
}

// UnitDoc checks the doc section of the main page.
func UnitDoc() htmlcheck.Checker {
	return in(".Documentation", text(`Overview`))
}

// UnitDirectories checks the directories section of the main page.
// If firstHref isn't empty, it and firstText should exactly match
// href and text of the first link in the Directories table.
func UnitDirectories(firstHref, firstText string) htmlcheck.Checker {
	var link htmlcheck.Checker
	if firstHref != "" {
		link = in(`[data-test-id="UnitDirectories-table"] a`, href(firstHref), exactText(firstText))
	}
	return in("",
		in("th:nth-child(1)", text("^Path$")),
		in("th:nth-child(2)", text("^Synopsis$")),
		link)
}

// CanonicalURLPath checks the canonical url for the unit on the page.
func CanonicalURLPath(path string) htmlcheck.Checker {
	return in(".js-canonicalURLPath", attr("data-canonical-url-path", path))
}

// SubdirectoriesDetails checks the detail section of a subdirectories tab.
// If firstHref isn't empty, it and firstText should exactly match
// href and text of the first link in the Directories table.
func SubdirectoriesDetails(firstHref, firstText string) htmlcheck.Checker {
	var link htmlcheck.Checker
	if firstHref != "" {
		link = in("table.Directories a", href(firstHref), exactText(firstText))
	}
	return in("",
		in("th:nth-child(1)", text("^Path$")),
		in("th:nth-child(2)", text("^Synopsis$")),
		link)
}

// LicenseDetails checks the details section of a license tab.
func LicenseDetails(ltype, bodySubstring, source string) htmlcheck.Checker {
	return in("",
		in(".License",
			text(regexp.QuoteMeta(ltype)),
			text("This is not legal advice"),
			in("a",
				href("/license-policy"),
				exactText("Read disclaimer.")),
			in(".License-contents",
				text(regexp.QuoteMeta(bodySubstring)))),
		in(".License-source",
			exactText("Source: "+source)))
}

// OverviewDetails checks the details section of an overview tab.
func OverviewDetails(ov *Overview) htmlcheck.Checker {
	var pkg htmlcheck.Checker
	if ov.PackageURL != "" {
		pkg = in(".Overview-sourceCodeLink a:nth-of-type(2)",
			href(ov.PackageURL),
			exactText(ov.PackageURL))
	}
	return in("",
		in("div.Overview-module > a",
			href(ov.ModuleLink),
			exactText(ov.ModuleLinkText)),
		in(".Overview-sourceCodeLink a:nth-of-type(1)",
			href(ov.RepoURL),
			exactText(ov.RepoURL)),
		pkg,
		in(".Overview-readmeContent", text(ov.ReadmeContent)),
		in(".Overview-readmeSource", exactText("Source: "+ov.ReadmeSource)))
}

// versionBadge checks the latest-version badge on a header.
func versionBadge(p *Page) htmlcheck.Checker {
	class := "DetailsHeader-badge"
	if p.IsLatest {
		class += "--latest"
	} else {
		class += "--goToLatest"
	}
	return in("div.DetailsHeader-badge",
		attr("class", `\b`+regexp.QuoteMeta(class)+`\b`), // the badge has this class too
		in("a", href(p.LatestLink), exactText("Go to latest")))
}

// licenseInfo checks the license part of the info label in the header.
func licenseInfo(p *Page, urlPath string) htmlcheck.Checker {
	if p.LicenseType == "" {
		return in("[data-test-id=DetailsHeader-infoLabelLicense]", text("None detected"))
	}
	return in("[data-test-id=DetailsHeader-infoLabelLicense] a",
		href(fmt.Sprintf("%s?tab=licenses#lic-0", urlPath)),
		exactText(p.LicenseType))
}

// moduleInHeader checks the module part of the info label in the header.
func moduleInHeader(p *Page, versionedURL bool) htmlcheck.Checker {
	modURL := moduleURLPath(p, versionedURL)
	text := p.ModulePath
	if p.ModulePath == stdlib.ModulePath {
		text = "Standard library"
	}
	return in("a[data-test-id=DetailsHeader-infoLabelModule]", href(modURL), exactText(text))
}

// Check that all the navigation tabs link to the same package at the same version.
func packageTabLinks(p *Page, versionedURL bool) htmlcheck.Checker {
	return inAll("a.DetailsNav-link[href]",
		attr("href", "^"+regexp.QuoteMeta(packageURLPath(p, versionedURL))))
}

// Check that all the navigation tabs link to the same module at the same version.
func moduleTabLinks(p *Page, versionedURL bool) htmlcheck.Checker {
	return inAll("a.DetailsNav-link[href]",
		attr("href", "^"+regexp.QuoteMeta(moduleURLPath(p, versionedURL))))
}

func packageURLPath(p *Page, versioned bool) string {
	v := ""
	if versioned {
		v = "@" + p.Version
	}
	return fmt.Sprintf(p.PackageURLFormat, v)
}

func moduleURLPath(p *Page, versioned bool) string {
	if versioned {
		return p.ModuleURL + "@" + p.Version
	}
	return p.ModuleURL
}
<|endoftext|>


<commit_before>package anylisp

import (
	"fmt"
	"math/big"
	"os"
)

type Lister interface {
	Car() interface{}
	SetCar(v interface{}) interface{}
	Cdr() Lister
	SetCdr(v Lister) Lister
	Last() Lister
}

type List struct {
	car interface{}
	cdr Lister
}

type Inter interface {
	Cmp(y *big.Int) (r int)
	Int64() int64
}

var (
	Ps_      Lister
	C_       Lister
	TempRoot Lister
)

func Parse(code string) {
	TempRoot = &List{"sx'", nil}
	Ps_ = &List{TempRoot, nil}
	C_ = &List{&List{TempRoot, nil}, nil}
	tok := ""
	for i := 0; i < len(code); i++ {
		if code[i] == ' ' || code[i] == '\t' || code[i] == '\n' {
			if tok == ")" {
				Assert(Ps_.Cdr() != nil, "Parse WTF! Too many )s")
				Ps_ = Ps_.Cdr()
			} else if len(tok) > 0 {
				var ls Lister
				if tok == "(" { // list
					ls = &List{nil, nil}
				} else if tok[0] == '[' && tok[len(tok)-1] == ']' { // number
					for j := 1; j < len(tok)-1; j++ {
						Assert(tok[j] == '-' || (tok[j] >= '0' && tok[j] <= '9') || (tok[j] >= 'a' && tok[j] <= 'f'),
							"Parse WTF! Bad character in number")
					}
					bi := new(big.Int)
					_, err := fmt.Sscanf(tok[1:len(tok)-1], "%x", bi)
					Assert(err == nil, "Parse WTF! Bad number")
					ls = &List{bi, nil}
				} else { // symbol
					ls = &List{tok, nil}
				}
				if Ps_.Car() == nil {
					Ps_.Cdr().Car().(Lister).SetCar(ls) // 1st token in list
				} else {
					Ps_.Car().(Lister).SetCdr(ls)
				}
				Ps_.SetCar(ls)
				if tok == "(" {
					Ps_ = &List{nil, Ps_}
				}
			}
			tok = ""
		} else {
			tok += string(code[i])
		}
	}
	Assert(Ps_.Cdr() == nil, "Parse WTF! Too few )s")
}

func Run() {
	for C_ != nil {
		f, ok := C_.Car().(Lister)
		Assert(ok, "WTF! Bad stack frame")
		e, ok := f.Car().(Lister)
		if !ok {
			fmt.Print("0 ")
			Ret(f.Car())
		} else {
			switch t := e.Car().(type) {
			case nil:
				Assert(false, "WTF! Can't call the empty list")
			case Inter:
				Assert(false, "WTF! Can't call an int")
			case Lister:
				Assert(false, "WTF! Can't call a list")
				// I kind of like the behavior below, but it causes strange error messages if there's a bug
				/*if f.Cdr() == nil {
					fmt.Println("a")
					C_ = &List{&List{t, nil}, C_}
				} else {
					fmt.Println("b")
					f.SetCar(f.Cdr().Car())
				}*/
			case string:
				switch t {
				case "sx'": // sx', arg, ret
					if e.Cdr() == nil {
						fmt.Print("{0 ")
						Ret(nil)
					} else if f.Cdr() == nil {
						fmt.Print("{1 ")
						f.SetCdr(&List{e.Cdr(), nil})
					} else if f.Cdr().Car() != nil {
						fmt.Print("{2 ")
						C_ = &List{&List{NCarL(f, 1).Car(), nil}, C_}
						f.SetCdr(&List{NCarL(f, 1).Cdr(), nil})
					} else {
						fmt.Print("{3 ")
						Ret(NCar(f, 2))
					}
				case "q'":
					fmt.Print("' ")
					Assert(e.Cdr() != nil, "WTF! Missing argument to quote")
					Ret(e.Cdr().Car())
				case ":^'", ":>'", ":|'": // op, ret
					if f.Cdr() == nil {
						fmt.Print(":1 ")
						Assert(e.Cdr() != nil, "WTF! Missing argument to "+t)
						C_ = &List{&List{e.Cdr().Car(), nil}, C_}
					} else if f.Cdr().Car() == nil {
						fmt.Print(":2 ")
						Ret(nil)
					} else {
						fmt.Print(":3 ")
						arg := NCarLA(f, 1, "WTF! "+t+" takes a list")
						switch t {
						case ":^'":
							Ret(arg.Car())
						case ":>'":
							Ret(arg.Cdr())
						case ":|'":
							Ret(arg.Last())
						}
					}
				case "lt'": // lt', args...
					if e.Cdr() == nil {
						fmt.Print("lt0 ")
						Ret(nil)
					} else if f.Cdr() == nil {
						fmt.Print("lt1 ")
						f.SetCdr(&List{e.Cdr(), nil})
					} else if f.Cdr().Car() != nil {
						fmt.Print("lt2 ")
						C_ = &List{&List{NCarL(f, 1).Car(), nil}, C_}
						f.Cdr().SetCar(NCarL(f, 1).Cdr())
					} else {
						fmt.Print("lt3 ")
						switch t2 := f.Last().Car().(type) {
						case nil:
							NCdr(f, -2).SetCdr(nil)
						case Lister:
							NCdr(f, -2).SetCdr(t2)
						default:
							Assert(false, "WTF! Last argument to lt' must be a list")
						}
						Ret(NCdr(f, 2))
					}
				case "?'":
					// ?', if part, then part, ret
					// ?', then part, nil, ret
					if e.Cdr() == nil {
						fmt.Print("?0 ")
						Ret(nil)
					} else if NCdr(f, 1) == nil {
						fmt.Print("?1 ")
						f.SetCdr(&List{e.Cdr(), &List{e.Cdr().Cdr(), nil}})
					} else if NCdr(f, 3) == nil {
						fmt.Print("?2 ")
						C_ = &List{&List{NCarL(f, 1).Car(), nil}, C_}
					} else if NCar(f, 2) == nil {
						fmt.Print("?3 ")
						Ret(NCar(f, 3))
					} else if NCar(f, 3) != nil {
						fmt.Print("?4 ")
						f.SetCdr(&List{NCarL(f, 1).Cdr(), &List{nil, nil}})
					} else if NCarL(f, 2).Cdr() == nil {
						fmt.Print("?5 ")
						Ret(nil)
					} else {
						fmt.Print("?6 ")
						f.SetCdr(&List{NCarL(f, 2).Cdr(), &List{NCarL(f, 2).Cdr().Cdr(), nil}})
					}
				case "pr'":
					// pr', ret
					// TODO: print all arguments
					if e.Cdr() == nil {
						fmt.Print("pr0 ")
						Ret(nil)
					} else if f.Cdr() == nil {
						fmt.Print("pr1 ")
						C_ = &List{&List{e.Cdr().Car(), nil}, C_}
					} else if f.Cdr().Car() == nil {
						fmt.Print("pr2 ")
						Ret(nil)
					} else {
						fmt.Print("pr3 ")
						s := make([]uint8, Len(NCarLA(f, 1, "WTF! pr' takes a string")))
						for i, arg := 0, NCarL(f, 1); arg != nil; i, arg = i+1, arg.Cdr() {
							c, ok := arg.Car().(Inter)
							Assert(ok && c.Cmp(big.NewInt(-1)) == 1 && c.Cmp(big.NewInt(256)) == -1,
								"WTF! pr' takes a string")
							s[i] = uint8(c.Int64())
						}
						fmt.Print(string(s))
						Ret(f.Cdr().Car())
					}
				default:
					Assert(false, "WTF! Can't call undefined function \""+t+"\"")
				}
			default:
				Assert(false, "WTF! Unrecognized function type (probably an interpreter bug)")
			}
		}
	}
}

func PrintTree(ls interface{}) {
	switch t := ls.(type) {
	case nil:
		fmt.Print("( ) ")
	case Inter:
		fmt.Printf("[%x] ", t)
	case Lister:
		fmt.Print("( ")
		for ls != nil {
			PrintTree(ls.(Lister).Car())
			ls = ls.(Lister).Cdr()
		}
		fmt.Print(") ")
	case string:
		fmt.Print(t + " ")
	default:
		Assert(false, "Unrecognized object in tree")
	}
}

func Ret(v interface{}) {
	if C_.Cdr() != nil {
		C_.Cdr().Car().(Lister).Last().SetCdr(&List{v, nil})
	}
	C_ = C_.Cdr()
}

func Len(ls Lister) int {
	if ls == nil {
		return 0
	}
	if ls.Cdr() == nil {
		return 1
	}
	return Len(ls.Cdr()) + 1
}

func NCar(ls Lister, n int) interface{} {
	nCdr := NCdr(ls, n)
	Assert(nCdr != nil, "WTF! Out of bounds when calling :'")
	return nCdr.Car()
}

func NCarL(ls Lister, n int) Lister {
	return NCarLA(ls, n, "WTF! Requested list element isn't a list")
}

func NCarLA(ls Lister, n int, msg string) Lister {
	nCar, ok := NCar(ls, n).(Lister)
	Assert(ok, msg)
	return nCar
}

func NCdr(ls Lister, n int) Lister {
	if ls == nil {
		return nil
	}
	if n > 0 {
		return NCdr(ls.Cdr(), n-1)
	}
	if n < 0 {
		return NCdr(ls, Len(ls)+n)
	}
	return ls
}

func (ls *List) Car() interface{} {
	return ls.car
}

func (ls *List) SetCar(v interface{}) interface{} {
	ls.car = v
	return v
}

func (ls *List) Cdr() Lister {
	return ls.cdr
}

func (ls *List) SetCdr(v Lister) Lister {
	ls.cdr = v
	return v
}

func (ls *List) Last() Lister {
	if ls.cdr == nil {
		return ls
	}
	return ls.cdr.Last()
}

func Assert(cond bool, msg string) {
	if !cond {
		fmt.Println(msg)
		os.Exit(2)
	}
}
<commit_msg>print all arguments<commit_after>package anylisp

import (
	"fmt"
	"math/big"
	"os"
)

type Lister interface {
	Car() interface{}
	SetCar(v interface{}) interface{}
	Cdr() Lister
	SetCdr(v Lister) Lister
	Last() Lister
}

type List struct {
	car interface{}
	cdr Lister
}

type Inter interface {
	Cmp(y *big.Int) (r int)
	Int64() int64
}

var (
	Ps_      Lister
	C_       Lister
	TempRoot Lister
)

func Parse(code string) {
	TempRoot = &List{"sx'", nil}
	Ps_ = &List{TempRoot, nil}
	C_ = &List{&List{TempRoot, nil}, nil}
	tok := ""
	for i := 0; i < len(code); i++ {
		if code[i] == ' ' || code[i] == '\t' || code[i] == '\n' {
			if tok == ")" {
				Assert(Ps_.Cdr() != nil, "Parse WTF! Too many )s")
				Ps_ = Ps_.Cdr()
			} else if len(tok) > 0 {
				var ls Lister
				if tok == "(" { // list
					ls = &List{nil, nil}
				} else if tok[0] == '[' && tok[len(tok)-1] == ']' { // number
					for j := 1; j < len(tok)-1; j++ {
						Assert(tok[j] == '-' || (tok[j] >= '0' && tok[j] <= '9') || (tok[j] >= 'a' && tok[j] <= 'f'),
							"Parse WTF! Bad character in number")
					}
					bi := new(big.Int)
					_, err := fmt.Sscanf(tok[1:len(tok)-1], "%x", bi)
					Assert(err == nil, "Parse WTF! Bad number")
					ls = &List{bi, nil}
				} else { // symbol
					ls = &List{tok, nil}
				}
				if Ps_.Car() == nil {
					Ps_.Cdr().Car().(Lister).SetCar(ls) // 1st token in list
				} else {
					Ps_.Car().(Lister).SetCdr(ls)
				}
				Ps_.SetCar(ls)
				if tok == "(" {
					Ps_ = &List{nil, Ps_}
				}
			}
			tok = ""
		} else {
			tok += string(code[i])
		}
	}
	Assert(Ps_.Cdr() == nil, "Parse WTF! Too few )s")
}

func Run() {
	for C_ != nil {
		f, ok := C_.Car().(Lister)
		Assert(ok, "WTF! Bad stack frame")
		e, ok := f.Car().(Lister)
		if !ok {
			fmt.Print("0 ")
			Ret(f.Car())
		} else {
			switch t := e.Car().(type) {
			case nil:
				Assert(false, "WTF! Can't call the empty list")
			case Inter:
				Assert(false, "WTF! Can't call an int")
			case Lister:
				Assert(false, "WTF! Can't call a list")
				// I kind of like the behavior below, but it causes strange error messages if there's a bug
				/*if f.Cdr() == nil {
					fmt.Println("a")
					C_ = &List{&List{t, nil}, C_}
				} else {
					fmt.Println("b")
					f.SetCar(f.Cdr().Car())
				}*/
			case string:
				switch t {
				case "sx'": // sx', arg, ret
					if e.Cdr() == nil {
						fmt.Print("{0 ")
						Ret(nil)
					} else if f.Cdr() == nil {
						fmt.Print("{1 ")
						f.SetCdr(&List{e.Cdr(), nil})
					} else if f.Cdr().Car() != nil {
						fmt.Print("{2 ")
						C_ = &List{&List{NCarL(f, 1).Car(), nil}, C_}
						f.SetCdr(&List{NCarL(f, 1).Cdr(), nil})
					} else {
						fmt.Print("{3 ")
						Ret(NCar(f, 2))
					}
				case "q'":
					fmt.Print("' ")
					Assert(e.Cdr() != nil, "WTF! Missing argument to quote")
					Ret(e.Cdr().Car())
				case ":^'", ":>'", ":|'": // op, ret
					if f.Cdr() == nil {
						fmt.Print(":1 ")
						Assert(e.Cdr() != nil, "WTF! Missing argument to "+t)
						C_ = &List{&List{e.Cdr().Car(), nil}, C_}
					} else if f.Cdr().Car() == nil {
						fmt.Print(":2 ")
						Ret(nil)
					} else {
						fmt.Print(":3 ")
						arg := NCarLA(f, 1, "WTF! "+t+" takes a list")
						switch t {
						case ":^'":
							Ret(arg.Car())
						case ":>'":
							Ret(arg.Cdr())
						case ":|'":
							Ret(arg.Last())
						}
					}
				case "lt'": // lt', arg, ret...
					if e.Cdr() == nil {
						fmt.Print("lt0 ")
						Ret(nil)
					} else if f.Cdr() == nil {
						fmt.Print("lt1 ")
						f.SetCdr(&List{e.Cdr(), nil})
					} else if f.Cdr().Car() != nil {
						fmt.Print("lt2 ")
						C_ = &List{&List{NCarL(f, 1).Car(), nil}, C_}
						f.Cdr().SetCar(NCarL(f, 1).Cdr())
					} else {
						fmt.Print("lt3 ")
						SetCdrA(NCdr(f, -2), f.Last().Car(), "WTF! Last argument to lt' must be a list")
						Ret(NCdr(f, 2))
					}
				case "?'":
					// ?', if part, then part, ret
					// ?', then part, nil, ret
					if e.Cdr() == nil {
						fmt.Print("?0 ")
						Ret(nil)
					} else if NCdr(f, 1) == nil {
						fmt.Print("?1 ")
						f.SetCdr(&List{e.Cdr(), &List{e.Cdr().Cdr(), nil}})
					} else if NCdr(f, 3) == nil {
						fmt.Print("?2 ")
						C_ = &List{&List{NCarL(f, 1).Car(), nil}, C_}
					} else if NCar(f, 2) == nil {
						fmt.Print("?3 ")
						Ret(NCar(f, 3))
					} else if NCar(f, 3) != nil {
						fmt.Print("?4 ")
						f.SetCdr(&List{NCarL(f, 1).Cdr(), &List{nil, nil}})
					} else if NCarL(f, 2).Cdr() == nil {
						fmt.Print("?5 ")
						Ret(nil)
					} else {
						fmt.Print("?6 ")
						f.SetCdr(&List{NCarL(f, 2).Cdr(), &List{NCarL(f, 2).Cdr().Cdr(), nil}})
					}
				case "pr'":
					// pr', arg, ret...
					if e.Cdr() == nil {
						fmt.Print("pr0 ")
						Ret(nil)
					} else if f.Cdr() == nil {
						fmt.Print("pr1 ")
						f.SetCdr(&List{e.Cdr(), nil})
					} else {
						if f.Cdr().Cdr() != nil {
							fmt.Print("pr2 ")
							SetCdrA(NCdr(f, -2), f.Last().Car(), "WTF! pr' takes a string")
						}
						if f.Cdr().Car() != nil {
							fmt.Print("pr3 ")
							C_ = &List{&List{NCarL(f, 1).Car(), nil}, C_}
							f.Cdr().SetCar(NCarL(f, 1).Cdr())
						} else {
							fmt.Print("pr4 ")
							s := make([]uint8, Len(f.Cdr().Cdr()))
							for i, arg := 0, f.Cdr().Cdr(); arg != nil; i, arg = i+1, arg.Cdr() {
								c, ok := arg.Car().(Inter)
								Assert(ok && c.Cmp(big.NewInt(-1)) == 1 && c.Cmp(big.NewInt(256)) == -1,
									"WTF! Bad byte passed to pr'")
								s[i] = uint8(c.Int64())
							}
							fmt.Print(string(s))
							Ret(f.Cdr().Cdr())
						}
					}
				default:
					Assert(false, "WTF! Can't call undefined function \""+t+"\"")
				}
			default:
				Assert(false, "WTF! Unrecognized function type (probably an interpreter bug)")
			}
		}
	}
}

func PrintTree(ls interface{}) {
	switch t := ls.(type) {
	case nil:
		fmt.Print("( ) ")
	case Inter:
		fmt.Printf("[%x] ", t)
	case Lister:
		fmt.Print("( ")
		for ls != nil {
			PrintTree(ls.(Lister).Car())
			ls = ls.(Lister).Cdr()
		}
		fmt.Print(") ")
	case string:
		fmt.Print(t + " ")
	default:
		Assert(false, "Unrecognized object in tree")
	}
}

func Ret(v interface{}) {
	if C_.Cdr() != nil {
		C_.Cdr().Car().(Lister).Last().SetCdr(&List{v, nil})
	}
	C_ = C_.Cdr()
}

func Len(ls Lister) int {
	if ls == nil {
		return 0
	}
	if ls.Cdr() == nil {
		return 1
	}
	return Len(ls.Cdr()) + 1
}

func NCar(ls Lister, n int) interface{} {
	nCdr := NCdr(ls, n)
	Assert(nCdr != nil, "WTF! Out of bounds when calling :'")
	return nCdr.Car()
}

func NCarL(ls Lister, n int) Lister {
	return NCarLA(ls, n, "WTF! Requested list element isn't a list")
}

func NCarLA(ls Lister, n int, msg string) Lister {
	nCar, ok := NCar(ls, n).(Lister)
	Assert(ok, msg)
	return nCar
}

func NCdr(ls Lister, n int) Lister {
	if ls == nil {
		return nil
	}
	if n > 0 {
		return NCdr(ls.Cdr(), n-1)
	}
	if n < 0 {
		return NCdr(ls, Len(ls)+n)
	}
	return ls
}

func SetCdrA(ls Lister, v interface{}, msg string) Lister {
	switch t := v.(type) {
	case nil:
		return ls.SetCdr(nil)
	case Lister:
		return ls.SetCdr(t)
	}
	Assert(false, msg)
	return nil
}

func (ls *List) Car() interface{} {
	return ls.car
}

func (ls *List) SetCar(v interface{}) interface{} {
	ls.car = v
	return v
}

func (ls *List) Cdr() Lister {
	return ls.cdr
}

func (ls *List) SetCdr(v Lister) Lister {
	ls.cdr = v
	return v
}

func (ls *List) Last() Lister {
	if ls.cdr == nil {
		return ls
	}
	return ls.cdr.Last()
}

func Assert(cond bool, msg string) {
	if !cond {
		fmt.Println(msg)
		os.Exit(2)
	}
}
<|endoftext|>