<commit_before>package main

import (
	"image"
	"log"
	"path/filepath"
	"time"

	"sigint.ca/graphics/editor"
	"sigint.ca/graphics/editor/address"
)

var npanes int

// A pane is an acme-style managed window (not an OS window)
type pane struct {
	tag, main *widget
	pos       int

	savedPath   string
	currentPath string
	dir         bool
	cwd         string

	// used for confirmation before closing unsaved pane.
	// the destructive action must be requested twice within
	// confirmDuration.
	confirmTime time.Time
}

// newPane creates a new pane. If data is nil, the file named by
// name will be loaded into the main editor widget, otherwise
// the contents of data will be loaded. In either case, the tag
// widget will display name at the left side.
func newPane(name string, data []byte) (*pane, error) {
	p := &pane{currentPath: name}

	p.pos = npanes
	npanes++

	// set up the main editor widget
	sz, pt := p.mainDimensions()
	p.main = p.newWidget(sz, pt, editor.AcmeYellowTheme, fontFace)

	// load text into main editor widget
	if data != nil {
		p.load(data)
		p.cwd = getAbs(filepath.Dir(name))
	} else {
		if err := p.loadFile(name); err != nil {
			return nil, err
		}
	}

	// set up the tag widget
	sz, pt = p.tagDimensions()
	p.tag = p.newWidget(sz, pt, editor.AcmeBlueTheme, fontFace)

	// populate the tag
	p.tag.ed.Load([]byte(p.currentPath + " "))
	p.updateTag()
	end := p.tag.ed.LastAddress()
	p.tag.ed.SetDot(address.Selection{From: end, To: end})

	// set up B2 and B3 actions
	p.tag.ed.B2Action = p.executeCmd
	p.main.ed.B2Action = p.executeCmd
	p.tag.ed.B3Action = p.findInEditor
	p.main.ed.B3Action = p.findInEditor

	widgets = append(widgets, p.tag)
	widgets = append(widgets, p.main)

	return p, nil
}

func (p *pane) tagDimensions() (size, pos image.Point) {
	h := winSize.Y / npanes
	y := h * p.pos
	return image.Pt(winSize.X, tagHeight), image.Pt(0, y)
}

func (p *pane) mainDimensions() (size, pos image.Point) {
	h := winSize.Y / npanes
	y := h * p.pos
	return image.Pt(winSize.X, h-tagHeight), image.Pt(0, y+tagHeight+1)
}

func (p *pane) resize() {
	p.tag.resize(p.tagDimensions())
	p.main.resize(p.mainDimensions())
}

func (p *pane) draw() {
	p.tag.draw()
	p.main.draw()
}

func addPane(name string, data []byte) {
	p, err := newPane(name, data)
	if err != nil {
		log.Print(err)
		return
	}
	panes = append(panes, p)
	for _, p := range panes {
		p.resize()
	}
	dprintf("added pane: %#v", p)
}

func deletePane(i int) {
	p := panes[i]

	// remove widgets from global slice
	for i, w := range widgets {
		if w == p.tag {
			widgets = append(widgets[:i], widgets[i+1:]...)
		}
	}
	for i, w := range widgets {
		if w == p.main {
			widgets = append(widgets[:i], widgets[i+1:]...)
		}
	}
	// release widgets
	p.tag.release()
	p.main.release()

	// remove pane from global slice
	panes = append(panes[:i], panes[i+1:]...)
	for ; i < len(panes); i++ {
		panes[i].pos--
	}
	npanes--
}
<commit_msg>cmd/edit: improve formatting of pane in debug messages<commit_after>package main

import (
	"fmt"
	"image"
	"log"
	"path/filepath"
	"time"

	"sigint.ca/graphics/editor"
	"sigint.ca/graphics/editor/address"
)

var npanes int

// A pane is an acme-style managed window (not an OS window)
type pane struct {
	tag, main *widget
	pos       int

	savedPath   string
	currentPath string
	dir         bool
	cwd         string

	// used for confirmation before closing unsaved pane.
	// the destructive action must be requested twice within
	// confirmDuration.
	confirmTime time.Time
}

func (p *pane) String() string {
	return fmt.Sprintf("pane(pos=%v, savedPath=%q, currentPath=%q, dir=%v, cwd=%q)",
		p.pos, p.savedPath, p.currentPath, p.dir, p.cwd)
}

// newPane creates a new pane. If data is nil, the file named by
// name will be loaded into the main editor widget, otherwise
// the contents of data will be loaded. In either case, the tag
// widget will display name at the left side.
func newPane(name string, data []byte) (*pane, error) {
	p := &pane{currentPath: name}

	p.pos = npanes
	npanes++

	// set up the main editor widget
	sz, pt := p.mainDimensions()
	p.main = p.newWidget(sz, pt, editor.AcmeYellowTheme, fontFace)

	// load text into main editor widget
	if data != nil {
		p.load(data)
		p.cwd = getAbs(filepath.Dir(name))
	} else {
		if err := p.loadFile(name); err != nil {
			return nil, err
		}
	}

	// set up the tag widget
	sz, pt = p.tagDimensions()
	p.tag = p.newWidget(sz, pt, editor.AcmeBlueTheme, fontFace)

	// populate the tag
	p.tag.ed.Load([]byte(p.currentPath + " "))
	p.updateTag()
	end := p.tag.ed.LastAddress()
	p.tag.ed.SetDot(address.Selection{From: end, To: end})

	// set up B2 and B3 actions
	p.tag.ed.B2Action = p.executeCmd
	p.main.ed.B2Action = p.executeCmd
	p.tag.ed.B3Action = p.findInEditor
	p.main.ed.B3Action = p.findInEditor

	widgets = append(widgets, p.tag)
	widgets = append(widgets, p.main)

	return p, nil
}

func (p *pane) tagDimensions() (size, pos image.Point) {
	h := winSize.Y / npanes
	y := h * p.pos
	return image.Pt(winSize.X, tagHeight), image.Pt(0, y)
}

func (p *pane) mainDimensions() (size, pos image.Point) {
	h := winSize.Y / npanes
	y := h * p.pos
	return image.Pt(winSize.X, h-tagHeight), image.Pt(0, y+tagHeight+1)
}

func (p *pane) resize() {
	p.tag.resize(p.tagDimensions())
	p.main.resize(p.mainDimensions())
}

func (p *pane) draw() {
	p.tag.draw()
	p.main.draw()
}

func addPane(name string, data []byte) {
	p, err := newPane(name, data)
	if err != nil {
		log.Print(err)
		return
	}
	panes = append(panes, p)
	for _, p := range panes {
		p.resize()
	}
	dprintf("added pane: %v", p)
}

func deletePane(i int) {
	p := panes[i]

	// remove widgets from global slice
	for i, w := range widgets {
		if w == p.tag {
			widgets = append(widgets[:i], widgets[i+1:]...)
		}
	}
	for i, w := range widgets {
		if w == p.main {
			widgets = append(widgets[:i], widgets[i+1:]...)
		}
	}
	// release widgets
	p.tag.release()
	p.main.release()

	// remove pane from global slice
	panes = append(panes[:i], panes[i+1:]...)
	for ; i < len(panes); i++ {
		panes[i].pos--
	}
	npanes--
}
<|endoftext|>


<commit_before>// Copyright 2016-2018 Authors of Cilium
//
// 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 (
	"time"

	"github.com/cilium/cilium/pkg/controller"
	"github.com/cilium/cilium/pkg/k8s"
	"github.com/cilium/cilium/pkg/k8s/apis/cilium.io"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var (
	unmanagedKubeDnsWatcherInterval int
	unmanagedKubeDnsMinimalAge      = 30 * time.Second
)

func enableUnmanagedKubeDNSController() {
	controller.NewManager().UpdateController("restart-unmanaged-kube-dns",
		controller.ControllerParams{
			RunInterval: time.Duration(unmanagedKubeDnsWatcherInterval) * time.Second,
			DoFunc: func() error {
				pods, err := k8s.Client().CoreV1().Pods("").List(metav1.ListOptions{
					LabelSelector: "k8s-app=kube-dns",
					FieldSelector: "status.phase=Running",
				})
				if err != nil {
					return err
				}

				for _, pod := range pods.Items {
					id, podHasIdentity := pod.Annotations[ciliumio.CiliumK8sAnnotationPrefix+"identity"]
					if podHasIdentity {
						log.Debugf("Found kube-dns pod %s/%s with identity %s", pod.Namespace, pod.Name, id)
					} else if !pod.Spec.HostNetwork {
						log.Debugf("Found unmanaged kube-dns pod %s/%s", pod.Namespace, pod.Name)
						if startTime := pod.Status.StartTime; startTime != nil {
							if age := time.Since((*startTime).Time); age > unmanagedKubeDnsMinimalAge {
								log.Infof("Restarting unmanaged kube-dns pod %s/%s started %s ago", pod.Namespace, pod.Name, age)
								if err := k8s.Client().CoreV1().Pods(pod.Namespace).Delete(pod.Name, &metav1.DeleteOptions{}); err != nil {
									log.WithError(err).Warningf("Unable to restart pod %s/%s", pod.Namespace, pod.Name)
								}
							}
						}
					}
				}

				return nil
			},
		})
}
<commit_msg>operator: Pace kube-dns pod restarts to every 5 minutes<commit_after>// Copyright 2016-2018 Authors of Cilium
//
// 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 (
	"fmt"
	"time"

	"github.com/cilium/cilium/pkg/controller"
	"github.com/cilium/cilium/pkg/k8s"
	"github.com/cilium/cilium/pkg/k8s/apis/cilium.io"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
	minimalPodRestartInterval = 5 * time.Minute
)

var (
	unmanagedKubeDnsWatcherInterval int
	unmanagedKubeDnsMinimalAge      = 30 * time.Second
	lastPodRestart                  = map[string]time.Time{}
)

func enableUnmanagedKubeDNSController() {
	controller.NewManager().UpdateController("restart-unmanaged-kube-dns",
		controller.ControllerParams{
			RunInterval: time.Duration(unmanagedKubeDnsWatcherInterval) * time.Second,
			DoFunc: func() error {
				for podName, lastRestart := range lastPodRestart {
					if time.Since(lastRestart) > 2*minimalPodRestartInterval {
						delete(lastPodRestart, podName)
					}
				}

				pods, err := k8s.Client().CoreV1().Pods("").List(metav1.ListOptions{
					LabelSelector: "k8s-app=kube-dns",
					FieldSelector: "status.phase=Running",
				})
				if err != nil {
					return err
				}

				for _, pod := range pods.Items {
					id, podHasIdentity := pod.Annotations[ciliumio.CiliumK8sAnnotationPrefix+"identity"]
					podID := fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)
					if podHasIdentity {
						log.Debugf("Found kube-dns pod %s with identity %s", podID, id)
					} else if !pod.Spec.HostNetwork {
						log.Debugf("Found unmanaged kube-dns pod %s", podID)
						if startTime := pod.Status.StartTime; startTime != nil {
							if age := time.Since((*startTime).Time); age > unmanagedKubeDnsMinimalAge {
								if lastRestart, ok := lastPodRestart[podID]; ok {
									if timeSinceRestart := time.Since(lastRestart); timeSinceRestart < minimalPodRestartInterval {
										log.Debugf("Not restaring %s, only %s since last restart", podID, timeSinceRestart)
										continue
									}
								}

								log.Infof("Restarting unmanaged kube-dns pod %s started %s ago", podID, age)
								if err := k8s.Client().CoreV1().Pods(pod.Namespace).Delete(pod.Name, &metav1.DeleteOptions{}); err != nil {
									log.WithError(err).Warningf("Unable to restart pod %s", podID)
								} else {
									lastPodRestart[podID] = time.Now()
								}

							}
						}
					}
				}

				return nil
			},
		})
}
<|endoftext|>


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

/*

Godoc extracts and generates documentation for Go programs.

It runs as a web server and presents the documentation as a
web page.

	godoc -http=:6060

Usage:

	godoc [flag]

The flags are:

	-v
		verbose mode
	-timestamps=true
		show timestamps with directory listings
	-index
		enable identifier and full text search index
		(no search box is shown if -index is not set)
	-index_files=""
		glob pattern specifying index files; if not empty,
		the index is read from these files in sorted order
	-index_throttle=0.75
		index throttle value; a value of 0 means no time is allocated
		to the indexer (the indexer will never finish), a value of 1.0
		means that index creation is running at full throttle (other
		goroutines may get no time while the index is built)
	-index_interval=0
		interval of indexing; a value of 0 sets it to 5 minutes, a
		negative value indexes only once at startup
	-play=false
		enable playground
	-links=true
		link identifiers to their declarations
	-write_index=false
		write index to a file; the file name must be specified with
		-index_files
	-maxresults=10000
		maximum number of full text search results shown
		(no full text index is built if maxresults <= 0)
	-notes="BUG"
		regular expression matching note markers to show
		(e.g., "BUG|TODO", ".*")
	-goroot=$GOROOT
		Go root directory
	-http=addr
		HTTP service address (e.g., '127.0.0.1:6060' or just ':6060')
	-templates=""
		directory containing alternate template files; if set,
		the directory may provide alternative template files
		for the files in $GOROOT/lib/godoc
	-url=path
		print to standard output the data that would be served by
		an HTTP request for path
	-zip=""
		zip file providing the file system to serve; disabled if empty

By default, godoc looks at the packages it finds via $GOROOT and $GOPATH (if set).
This behavior can be altered by providing an alternative $GOROOT with the -goroot
flag.

When the -index flag is set, a search index is maintained.
The index is created at startup.

The index contains both identifier and full text search information (searchable
via regular expressions). The maximum number of full text search results shown
can be set with the -maxresults flag; if set to 0, no full text results are
shown, and only an identifier index but no full text search index is created.

By default, godoc uses the system's GOOS/GOARCH. You can provide the URL parameters
"GOOS" and "GOARCH" to set the output on the web page for the target system.

The presentation mode of web pages served by godoc can be controlled with the
"m" URL parameter; it accepts a comma-separated list of flag names as value:

	all	show documentation for all declarations, not just the exported ones
	methods	show all embedded methods, not just those of unexported anonymous fields
	src	show the original source code rather than the extracted documentation
	flat	present flat (not indented) directory listings using full paths

For instance, https://golang.org/pkg/math/big/?m=all shows the documentation
for all (not just the exported) declarations of package big.

By default, godoc serves files from the file system of the underlying OS.
Instead, a .zip file may be provided via the -zip flag, which contains
the file system to serve. The file paths stored in the .zip file must use
slash ('/') as path separator; and they must be unrooted. $GOROOT (or -goroot)
must be set to the .zip file directory path containing the Go root directory.
For instance, for a .zip file created by the command:

	zip -r go.zip $HOME/go

one may run godoc as follows:

	godoc -http=:6060 -zip=go.zip -goroot=$HOME/go

Godoc documentation is converted to HTML or to text using the go/doc package;
see https://golang.org/pkg/go/doc/#ToHTML for the exact rules.
Godoc also shows example code that is runnable by the testing package;
see https://golang.org/pkg/testing/#hdr-Examples for the conventions.
See "Godoc: documenting Go code" for how to write good comments for godoc:
https://golang.org/doc/articles/godoc_documenting_go_code.html

// Deprecated: godoc cannot select what version of a package is displayed.
// Instead, use golang.org/x/pkgsite/cmd/pkgsite.
*/
package main // import "golang.org/x/tools/cmd/godoc"
<commit_msg>cmd/godoc: remove extra // characters from deprecation notice<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*

Godoc extracts and generates documentation for Go programs.

It runs as a web server and presents the documentation as a
web page.

	godoc -http=:6060

Usage:

	godoc [flag]

The flags are:

	-v
		verbose mode
	-timestamps=true
		show timestamps with directory listings
	-index
		enable identifier and full text search index
		(no search box is shown if -index is not set)
	-index_files=""
		glob pattern specifying index files; if not empty,
		the index is read from these files in sorted order
	-index_throttle=0.75
		index throttle value; a value of 0 means no time is allocated
		to the indexer (the indexer will never finish), a value of 1.0
		means that index creation is running at full throttle (other
		goroutines may get no time while the index is built)
	-index_interval=0
		interval of indexing; a value of 0 sets it to 5 minutes, a
		negative value indexes only once at startup
	-play=false
		enable playground
	-links=true
		link identifiers to their declarations
	-write_index=false
		write index to a file; the file name must be specified with
		-index_files
	-maxresults=10000
		maximum number of full text search results shown
		(no full text index is built if maxresults <= 0)
	-notes="BUG"
		regular expression matching note markers to show
		(e.g., "BUG|TODO", ".*")
	-goroot=$GOROOT
		Go root directory
	-http=addr
		HTTP service address (e.g., '127.0.0.1:6060' or just ':6060')
	-templates=""
		directory containing alternate template files; if set,
		the directory may provide alternative template files
		for the files in $GOROOT/lib/godoc
	-url=path
		print to standard output the data that would be served by
		an HTTP request for path
	-zip=""
		zip file providing the file system to serve; disabled if empty

By default, godoc looks at the packages it finds via $GOROOT and $GOPATH (if set).
This behavior can be altered by providing an alternative $GOROOT with the -goroot
flag.

When the -index flag is set, a search index is maintained.
The index is created at startup.

The index contains both identifier and full text search information (searchable
via regular expressions). The maximum number of full text search results shown
can be set with the -maxresults flag; if set to 0, no full text results are
shown, and only an identifier index but no full text search index is created.

By default, godoc uses the system's GOOS/GOARCH. You can provide the URL parameters
"GOOS" and "GOARCH" to set the output on the web page for the target system.

The presentation mode of web pages served by godoc can be controlled with the
"m" URL parameter; it accepts a comma-separated list of flag names as value:

	all	show documentation for all declarations, not just the exported ones
	methods	show all embedded methods, not just those of unexported anonymous fields
	src	show the original source code rather than the extracted documentation
	flat	present flat (not indented) directory listings using full paths

For instance, https://golang.org/pkg/math/big/?m=all shows the documentation
for all (not just the exported) declarations of package big.

By default, godoc serves files from the file system of the underlying OS.
Instead, a .zip file may be provided via the -zip flag, which contains
the file system to serve. The file paths stored in the .zip file must use
slash ('/') as path separator; and they must be unrooted. $GOROOT (or -goroot)
must be set to the .zip file directory path containing the Go root directory.
For instance, for a .zip file created by the command:

	zip -r go.zip $HOME/go

one may run godoc as follows:

	godoc -http=:6060 -zip=go.zip -goroot=$HOME/go

Godoc documentation is converted to HTML or to text using the go/doc package;
see https://golang.org/pkg/go/doc/#ToHTML for the exact rules.
Godoc also shows example code that is runnable by the testing package;
see https://golang.org/pkg/testing/#hdr-Examples for the conventions.
See "Godoc: documenting Go code" for how to write good comments for godoc:
https://golang.org/doc/articles/godoc_documenting_go_code.html

Deprecated: godoc cannot select what version of a package is displayed.
Instead, use golang.org/x/pkgsite/cmd/pkgsite.
*/
package main // import "golang.org/x/tools/cmd/godoc"
<|endoftext|>


<commit_before>package main

// indextool
// usage: indextool -f file
// Given an input file, prints the ArchFileEntries within it

import (
	"bufio"
	"compress/bzip2"
	"encoding/binary"
	"flag"
	"fmt"
	bgp "github.com/CSUNetSec/bgparchive"
	pbmrt "github.com/CSUNetSec/protoparse/protocol/mrt"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"
)

const (
	DEFAULT_RATE = 0.1
)

var (
	output_suffix string
	print_tes     bool
	sample_rate   float64
	new_dir       string
)

func GetScanner(file *os.File) (scanner *bufio.Scanner) {
	fname := file.Name()
	fext := filepath.Ext(fname)
	if fext == ".bz2" {
		//log.Printf("bunzip2 file: %s. opening decompression stream", fname)
		bzreader := bzip2.NewReader(file)
		scanner = bufio.NewScanner(bzreader)
		scanner.Split(pbmrt.SplitMrt)
	} else {
		//log.Printf("no extension on file: %s. opening normally", fname)
		scanner = bufio.NewScanner(file)
		scanner.Split(pbmrt.SplitMrt)
	}
	return
}

func init() {
	flag.StringVar(&output_suffix, "outsuffix", "", "suffix of the generated index file")
	flag.StringVar(&output_suffix, "o", "", "")
	flag.Float64Var(&sample_rate, "rate", DEFAULT_RATE, "sample rate used")
	flag.Float64Var(&sample_rate, "r", DEFAULT_RATE, "")
	flag.BoolVar(&print_tes, "print", false, "Do not create the index file, print the TES file to standard output instead")
	flag.BoolVar(&print_tes, "p", false, "")
	flag.StringVar(&new_dir, "dir", "", "rewrit dir of the files referenced in the index. Must be the same across all entries. format is s:olddir:newdir")
}

func main() {
	flag.Parse()
	args := flag.Args()
	var sf []string

	if len(args) < 1 {
		usage()
		return
	}
	ff := func(r rune) bool {
		return r == ':'
	}
	if print_tes {
		for _, tesName := range args {
			fmt.Printf("------ %s ------\n", tesName)
			err := printTes(tesName)
			if err != nil {
				fmt.Printf("Print error: %v\n", err)
			}
			fmt.Printf("\n")
		}
	} else if new_dir != "" {
		fmt.Printf("detecting base path in existing indexfiles\n")
		if sf = strings.FieldsFunc(new_dir, ff); new_dir[0] != 's' && len(sf) != 3 {
			fmt.Printf("error: malformed sed rewrite string")
			return
		}
		for _, ifile := range args {
			err := rewriteDir(ifile, sf[1], sf[2])
			if err != nil {
				fmt.Printf("error:%s", err)
				return
			}
			fmt.Printf("rewrote %s to %s in file %s\n", sf[1], sf[2], ifile+"."+output_suffix)
		}
	} else {
		var wg sync.WaitGroup

		for _, tesName := range args {
			wg.Add(1)
			go createIndexedTESFile(tesName, &wg)
		}
		wg.Wait()
	}

}

func rewriteDir(ifile, from, to string) error {
	var (
		detectedDir, output_name string
	)
	entries := bgp.TimeEntrySlice{}
	err := (&entries).FromGobFile(ifile)
	if err != nil {
		return fmt.Errorf("Error opening index file: %s\n", ifile)
	}
	if output_suffix != "" {
		output_name = ifile + "." + output_suffix
	} else {
		output_name = ifile + ".newdir"
	}
	for _, ef := range entries {
		entrydir := filepath.Dir(ef.Path)
		if detectedDir == "" {
			detectedDir = entrydir
		} else if entrydir != detectedDir {
			return fmt.Errorf("file contains different dirs in backend files. can't rewrite.\n")
		}
	}
	if detectedDir != from {
		return fmt.Errorf("from argument string is not the same as detected dir:%s\n", detectedDir)
	}
	for i, ef := range entries {
		entries[i].Path = to + filepath.Base(ef.Path)
	}
	err = entries.ToGobFile(output_name)
	if err != nil {
		fmt.Printf("Error regobing TES: %s\n", output_name)
	}

	return nil
}

func printTes(tesName string) error {
	entries := bgp.TimeEntrySlice{}
	err := (&entries).FromGobFile(tesName)
	if err != nil {
		return err
	}
	for _, ent := range entries {
		fmt.Printf("%s\n", ent)
	}
	return nil
}

func createIndexedTESFile(tesName string, wg *sync.WaitGroup) {
	defer wg.Done()
	entries := bgp.TimeEntrySlice{}
	err := (&entries).FromGobFile(tesName)
	if err != nil {
		fmt.Printf("Error opening indexfile: %s\n", tesName)
		return
	}
	output_name := tesName + "." + output_suffix
	if _, err := os.Stat(output_name); !os.IsNotExist(err) {
		fmt.Printf("Error: destination file:%s already exists\n", output_name)
		return
	}
	for enct, _ := range entries {
		entryfile, err := os.Open(entries[enct].Path)
		if err != nil {
			fmt.Printf("Error opening ArchEntryFile: %s\n", entries[enct].Path)
			return
		}
		m := Generate_Index(GetScanner(entryfile), entries[enct].Sz, sample_rate, getTimestampFromMRT)
		entries[enct].Offsets = make([]bgp.EntryOffset, len(m))
		for ct, offset := range m {
			if offset != nil {
				fmt.Printf("Adding offset %d: %v\n", ct, offset)
				entries[enct].Offsets[ct] = bgp.EntryOffset{offset.Value.(time.Time), offset.Off}
			} else {
				fmt.Printf("Null offset, should not have happened.\n")
			}
		}
		entryfile.Close()
	}
	err = entries.ToGobFile(output_name)
	if err != nil {
		fmt.Printf("Error regobing TES: %s\n", tesName)
	}
	return
}

func getTimestampFromMRT(data []byte) (interface{}, error) {
	if len(data) < pbmrt.MRT_HEADER_LEN {
		return nil, fmt.Errorf("Data less than header length.\n")
	}
	unix_t := binary.BigEndian.Uint32(data[:4])
	return time.Unix(int64(unix_t), 0), nil
}

type ItemOffset struct {
	Value interface{}
	Off   int64
}

func NewItemOffset(val interface{}, pos int64) *ItemOffset {
	return &ItemOffset{val, pos}
}

// Generates indexes based on the file size and sample rate
// The scanner must be initialized and Split to parse messages
// before given to this function
func Generate_Index(scanner *bufio.Scanner, fsize int64, sample_rate float64, translate func([]byte) (interface{}, error)) []*ItemOffset {

	if sample_rate < 0.0 || sample_rate > 1.0 {
		sample_rate = DEFAULT_RATE
	}

	indices := make([]*ItemOffset, int(1/sample_rate))
	sample_dist := sample_rate * float64(fsize)
	index_ct := 0
	var actual_pos int64 = 0
	for scanner.Scan() {
		data := scanner.Bytes()
		actual_pos += int64(len(data))
		if float64(actual_pos) > float64(index_ct)*sample_dist && index_ct < len(indices) {
			td, err := translate(data)
			if err == nil {
				indices[index_ct] = NewItemOffset(td, actual_pos)
				index_ct++
			}
		}
	}

	return indices
}

func usage() {
	fmt.Println("indextool: writes an indexed version of a TimeEntrySlice into a specified file,\nprints an index file, or rewrites the dir of TimeEntrySlices.")
	fmt.Println("usage: indextool [flags] original-tes-file")
	fmt.Println("See indextool -h for a list of flags.")
}
<commit_msg>rewriting the dir string in a pure sed like behaviour<commit_after>package main

// indextool
// usage: indextool -f file
// Given an input file, prints the ArchFileEntries within it

import (
	"bufio"
	"compress/bzip2"
	"encoding/binary"
	"flag"
	"fmt"
	bgp "github.com/CSUNetSec/bgparchive"
	pbmrt "github.com/CSUNetSec/protoparse/protocol/mrt"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"
)

const (
	DEFAULT_RATE = 0.1
)

var (
	output_suffix string
	print_tes     bool
	sample_rate   float64
	new_dir       string
)

func GetScanner(file *os.File) (scanner *bufio.Scanner) {
	fname := file.Name()
	fext := filepath.Ext(fname)
	if fext == ".bz2" {
		//log.Printf("bunzip2 file: %s. opening decompression stream", fname)
		bzreader := bzip2.NewReader(file)
		scanner = bufio.NewScanner(bzreader)
		scanner.Split(pbmrt.SplitMrt)
	} else {
		//log.Printf("no extension on file: %s. opening normally", fname)
		scanner = bufio.NewScanner(file)
		scanner.Split(pbmrt.SplitMrt)
	}
	return
}

func init() {
	flag.StringVar(&output_suffix, "outsuffix", "", "suffix of the generated index file")
	flag.StringVar(&output_suffix, "o", "", "")
	flag.Float64Var(&sample_rate, "rate", DEFAULT_RATE, "sample rate used")
	flag.Float64Var(&sample_rate, "r", DEFAULT_RATE, "")
	flag.BoolVar(&print_tes, "print", false, "Do not create the index file, print the TES file to standard output instead")
	flag.BoolVar(&print_tes, "p", false, "")
	flag.StringVar(&new_dir, "dir", "", "rewrit dir of the files referenced in the index. Must be the same across all entries. format is s:olddir:newdir")
}

func main() {
	flag.Parse()
	args := flag.Args()
	var (
		sf  []string
		suf string
	)

	if len(args) < 1 {
		usage()
		return
	}
	ff := func(r rune) bool {
		return r == ':'
	}
	if print_tes {
		for _, tesName := range args {
			fmt.Printf("------ %s ------\n", tesName)
			err := printTes(tesName)
			if err != nil {
				fmt.Printf("Print error: %v\n", err)
			}
			fmt.Printf("\n")
		}
	} else if new_dir != "" {
		fmt.Printf("detecting base path in existing indexfiles\n")
		if sf = strings.FieldsFunc(new_dir, ff); new_dir[0] != 's' && len(sf) != 3 {
			fmt.Printf("error: malformed sed rewrite string")
			return
		}
		for _, ifile := range args {
			err := rewriteDir(ifile, sf[1], sf[2])
			if err != nil {
				fmt.Printf("error:%s", err)
				return
			}
			if output_suffix == "" {
				suf = "newdir"
			} else {
				suf = output_suffix
			}
			fmt.Printf("rewrote %s to %s in file %s\n", sf[1], sf[2], ifile+"."+suf)
		}
	} else {
		var wg sync.WaitGroup

		for _, tesName := range args {
			wg.Add(1)
			go createIndexedTESFile(tesName, &wg)
		}
		wg.Wait()
	}

}

func rewriteDir(ifile, from, to string) error {
	var (
		output_name string
	)
	entries := bgp.TimeEntrySlice{}
	err := (&entries).FromGobFile(ifile)
	if err != nil {
		return fmt.Errorf("Error opening index file: %s\n", ifile)
	}
	if output_suffix != "" {
		output_name = ifile + "." + output_suffix
	} else {
		output_name = ifile + ".newdir"
	}
	for i, ef := range entries {
		if !strings.Contains(ef.Path, from) {
			return fmt.Errorf("from argument string:%s is not the contained in the detected dir:%s\n", from, ef.Path)
		}
		entries[i].Path = strings.Replace(ef.Path, from, to, 1) // we run it as s/a/b not s/a/b/g
	}
	err = entries.ToGobFile(output_name)
	if err != nil {
		fmt.Printf("Error regobing TES: %s\n", output_name)
	}

	return nil
}

func printTes(tesName string) error {
	entries := bgp.TimeEntrySlice{}
	err := (&entries).FromGobFile(tesName)
	if err != nil {
		return err
	}
	for _, ent := range entries {
		fmt.Printf("%s\n", ent)
	}
	return nil
}

func createIndexedTESFile(tesName string, wg *sync.WaitGroup) {
	defer wg.Done()
	entries := bgp.TimeEntrySlice{}
	err := (&entries).FromGobFile(tesName)
	if err != nil {
		fmt.Printf("Error opening indexfile: %s\n", tesName)
		return
	}
	output_name := tesName + "." + output_suffix
	if _, err := os.Stat(output_name); !os.IsNotExist(err) {
		fmt.Printf("Error: destination file:%s already exists\n", output_name)
		return
	}
	for enct, _ := range entries {
		entryfile, err := os.Open(entries[enct].Path)
		if err != nil {
			fmt.Printf("Error opening ArchEntryFile: %s\n", entries[enct].Path)
			return
		}
		m := Generate_Index(GetScanner(entryfile), entries[enct].Sz, sample_rate, getTimestampFromMRT)
		entries[enct].Offsets = make([]bgp.EntryOffset, len(m))
		for ct, offset := range m {
			if offset != nil {
				fmt.Printf("Adding offset %d: %v\n", ct, offset)
				entries[enct].Offsets[ct] = bgp.EntryOffset{offset.Value.(time.Time), offset.Off}
			} else {
				fmt.Printf("Null offset, should not have happened.\n")
			}
		}
		entryfile.Close()
	}
	err = entries.ToGobFile(output_name)
	if err != nil {
		fmt.Printf("Error regobing TES: %s\n", tesName)
	}
	return
}

func getTimestampFromMRT(data []byte) (interface{}, error) {
	if len(data) < pbmrt.MRT_HEADER_LEN {
		return nil, fmt.Errorf("Data less than header length.\n")
	}
	unix_t := binary.BigEndian.Uint32(data[:4])
	return time.Unix(int64(unix_t), 0), nil
}

type ItemOffset struct {
	Value interface{}
	Off   int64
}

func NewItemOffset(val interface{}, pos int64) *ItemOffset {
	return &ItemOffset{val, pos}
}

// Generates indexes based on the file size and sample rate
// The scanner must be initialized and Split to parse messages
// before given to this function
func Generate_Index(scanner *bufio.Scanner, fsize int64, sample_rate float64, translate func([]byte) (interface{}, error)) []*ItemOffset {

	if sample_rate < 0.0 || sample_rate > 1.0 {
		sample_rate = DEFAULT_RATE
	}

	indices := make([]*ItemOffset, int(1/sample_rate))
	sample_dist := sample_rate * float64(fsize)
	index_ct := 0
	var actual_pos int64 = 0
	for scanner.Scan() {
		data := scanner.Bytes()
		actual_pos += int64(len(data))
		if float64(actual_pos) > float64(index_ct)*sample_dist && index_ct < len(indices) {
			td, err := translate(data)
			if err == nil {
				indices[index_ct] = NewItemOffset(td, actual_pos)
				index_ct++
			}
		}
	}

	return indices
}

func usage() {
	fmt.Println("indextool: writes an indexed version of a TimeEntrySlice into a specified file,\nprints an index file, or rewrites the dir of TimeEntrySlices.")
	fmt.Println("usage: indextool [flags] original-tes-file")
	fmt.Println("See indextool -h for a list of flags.")
}
<|endoftext|>


<commit_before>package main

// FromCharPos converts from a character position to an x, y position
func FromCharPos(loc int, buf *Buffer) Loc {
	charNum := 0
	x, y := 0, 0

	lineLen := Count(buf.Line(y)) + 1
	for charNum+lineLen <= loc {
		charNum += lineLen
		y++
		lineLen = Count(buf.Line(y)) + 1
	}
	x = loc - charNum

	return Loc{x, y}
}

// ToCharPos converts from an x, y position to a character position
func ToCharPos(start Loc, buf *Buffer) int {
	x, y := start.X, start.Y
	loc := 0
	for i := 0; i < y; i++ {
		// + 1 for the newline
		loc += Count(buf.Line(i)) + 1
	}
	loc += x
	return loc
}

// Loc stores a location
type Loc struct {
	X, Y int
}

// LessThan returns true if b is smaller
func (l Loc) LessThan(b Loc) bool {
	if l.Y < b.Y {
		return true
	}
	if l.Y == b.Y && l.X < b.X {
		return true
	}
	return false
}

// GreaterThan returns true if b is bigger
func (l Loc) GreaterThan(b Loc) bool {
	if l.Y > b.Y {
		return true
	}
	if l.Y == b.Y && l.X > b.X {
		return true
	}
	return false
}

// GreaterEqual returns true if b is greater than or equal to b
func (l Loc) GreaterEqual(b Loc) bool {
	if l.Y > b.Y {
		return true
	}
	if l.Y == b.Y && l.X > b.X {
		return true
	}
	if l == b {
		return true
	}
	return false
}

// LessEqual returns true if b is less than or equal to b
func (l Loc) LessEqual(b Loc) bool {
	if l.Y < b.Y {
		return true
	}
	if l.Y == b.Y && l.X < b.X {
		return true
	}
	if l == b {
		return true
	}
	return false
}

func (l Loc) right(n int, buf *Buffer) Loc {
	if l == buf.End() {
		return l
	}
	var res Loc
	if l.X < Count(buf.Line(l.Y)) {
		res = Loc{l.X + 1, l.Y}
	} else {
		res = Loc{0, l.Y + 1}
	}
	return res
}
func (l Loc) left(n int, buf *Buffer) Loc {
	if l == buf.Start() {
		return l
	}
	var res Loc
	if l.X > 0 {
		res = Loc{l.X - 1, l.Y}
	} else {
		res = Loc{Count(buf.Line(l.Y - 1)), l.Y - 1}
	}
	return res
}

func (l Loc) Move(n int, buf *Buffer) Loc {
	if n > 0 {
		return l.right(n, buf)
	}
	return l.left(Abs(n), buf)
}

// func (l Loc) DistanceTo(b Loc, buf *Buffer) int {
//
// }
<commit_msg>Fix bug with Move()<commit_after>package main

// FromCharPos converts from a character position to an x, y position
func FromCharPos(loc int, buf *Buffer) Loc {
	charNum := 0
	x, y := 0, 0

	lineLen := Count(buf.Line(y)) + 1
	for charNum+lineLen <= loc {
		charNum += lineLen
		y++
		lineLen = Count(buf.Line(y)) + 1
	}
	x = loc - charNum

	return Loc{x, y}
}

// ToCharPos converts from an x, y position to a character position
func ToCharPos(start Loc, buf *Buffer) int {
	x, y := start.X, start.Y
	loc := 0
	for i := 0; i < y; i++ {
		// + 1 for the newline
		loc += Count(buf.Line(i)) + 1
	}
	loc += x
	return loc
}

// Loc stores a location
type Loc struct {
	X, Y int
}

// LessThan returns true if b is smaller
func (l Loc) LessThan(b Loc) bool {
	if l.Y < b.Y {
		return true
	}
	if l.Y == b.Y && l.X < b.X {
		return true
	}
	return false
}

// GreaterThan returns true if b is bigger
func (l Loc) GreaterThan(b Loc) bool {
	if l.Y > b.Y {
		return true
	}
	if l.Y == b.Y && l.X > b.X {
		return true
	}
	return false
}

// GreaterEqual returns true if b is greater than or equal to b
func (l Loc) GreaterEqual(b Loc) bool {
	if l.Y > b.Y {
		return true
	}
	if l.Y == b.Y && l.X > b.X {
		return true
	}
	if l == b {
		return true
	}
	return false
}

// LessEqual returns true if b is less than or equal to b
func (l Loc) LessEqual(b Loc) bool {
	if l.Y < b.Y {
		return true
	}
	if l.Y == b.Y && l.X < b.X {
		return true
	}
	if l == b {
		return true
	}
	return false
}

func (l Loc) right(buf *Buffer) Loc {
	if l == buf.End() {
		return l
	}
	var res Loc
	if l.X < Count(buf.Line(l.Y)) {
		res = Loc{l.X + 1, l.Y}
	} else {
		res = Loc{0, l.Y + 1}
	}
	return res
}
func (l Loc) left(buf *Buffer) Loc {
	if l == buf.Start() {
		return l
	}
	var res Loc
	if l.X > 0 {
		res = Loc{l.X - 1, l.Y}
	} else {
		res = Loc{Count(buf.Line(l.Y - 1)), l.Y - 1}
	}
	return res
}

func (l Loc) Move(n int, buf *Buffer) Loc {
	if n > 0 {
		for i := 0; i < n; i++ {
			l = l.right(buf)
		}
		return l
	}
	for i := 0; i < n; i++ {
		return l.left(buf)
	}
	return l
}

// func (l Loc) DistanceTo(b Loc, buf *Buffer) int {
//
// }
<|endoftext|>


<commit_before>package kutil

import (
	"fmt"
	"reflect"
)

type KValue interface {
	FunCompare(o interface{}) int64 //0:equal,-1:small,1:big
}

type wrap_value interface {
	FunCompare(o wrap_value) int64
	Value() interface{}
}

type KRbtree struct {
	left  *KRbtree
	value wrap_value
	right *KRbtree
	isset bool
}

func wrap(val interface{}) wrap_value {
	if v, ok := val.(KValue); ok {
		return &wrap_kvalue{v}
	}
	if v, ok := val.(int); ok {
		return &wrap_int{v}
	}
	if v, ok := val.(int8); ok {
		return &wrap_int8{v}
	}
	if v, ok := val.(int16); ok {
		return &wrap_int16{v}
	}
	if v, ok := val.(int32); ok {
		return &wrap_int32{v}
	}
	if v, ok := val.(int64); ok {
		return &wrap_int64{v}
	}
	if v, ok := val.(uint); ok {
		return &wrap_uint{v}
	}
	if v, ok := val.(uint8); ok {
		return &wrap_uint8{v}
	}
	if v, ok := val.(uint16); ok {
		return &wrap_uint16{v}
	}
	if v, ok := val.(uint32); ok {
		return &wrap_uint32{v}
	}
	if v, ok := val.(uint64); ok {
		return &wrap_uint64{v}
	}
	if v, ok := val.(float32); ok {
		return &wrap_float32{v}
	}
	if v, ok := val.(float64); ok {
		return &wrap_float64{v}
	}
	if v, ok := val.(string); ok {
		return &wrap_string{v}
	}
	panic(fmt.Sprintln("Unknown datatype ", reflect.TypeOf(val), " in ", val))
	return nil
}

func (k *KRbtree) Add(val interface{}) bool {
	return k.add(wrap(val))
}

func (k *KRbtree) add(val wrap_value) bool {
	if k.isset {
		v := k.value.FunCompare(val)
		if v == 0 {
			return false
		}
		if v > 0 {
			if k.left == nil {
				k.left = new(KRbtree)
			}
			return k.left.add(val)
		}

		if k.right == nil {
			k.right = new(KRbtree)
		}
		return k.right.add(val)
	}
	k.isset = true
	k.value = val
	return true
}

func (k *KRbtree) RemoveFirst() interface{} {
	if !k.isset {
		return nil
	}
	val := k.removeFirst()
	return val.Value()
}

func (k *KRbtree) removeFirst() wrap_value {
	if k.left != nil {
		value := k.left.removeFirst()
		if !k.left.isset {
			k.left = nil
		}
		return value
	}
	value := k.value
	k.remove(value)
	return value
}

func (k *KRbtree) replaceWith(o *KRbtree) {
	k.value = o.value
	k.left = o.left
	k.right = o.right
}

func (k *KRbtree) RemoveLast() interface{} {
	if !k.isset {
		return nil
	}
	val := k.removeLast()
	return val.Value()
}

func (k *KRbtree) removeLast() wrap_value {
	if k.right != nil {
		value := k.right.removeLast()
		if !k.right.isset {
			k.right = nil
		}
		return value
	}
	value := k.value
	k.remove(value)
	return value
}

func (k *KRbtree) Remove(val interface{}) bool {
	return k.remove(wrap(val))
}

func (k *KRbtree) remove(val wrap_value) bool {
	if !k.isset {
		return false
	}
	v := k.value.FunCompare(val)
	if v == 0 {
		if k.right != nil {
			if k.left == nil {
				k.replaceWith(k.right)
			} else {
				k.value = k.right.removeFirst()
			}
		} else if k.left != nil {
			k.replaceWith(k.left)
		} else {
			k.isset = false
		}
	}
	if v > 0 {
		if k.left != nil {
			defer func() {
				if !k.left.isset {
					k.left = nil
				}
			}()
			return k.left.remove(val)
		}
		return false
	}

	if k.right != nil {
		defer func() {
			if !k.right.isset {
				k.right = nil
			}
		}()
		return k.right.remove(val)
	}
	return false
}

func (k *KRbtree) Contains(val interface{}) bool {
	return k.contains(wrap(val))
}

func (k *KRbtree) contains(val wrap_value) bool {
	if !k.isset {
		return false
	}
	v := k.value.FunCompare(val)
	if v == 0 {
		return true
	}
	if v > 0 {
		if k.left == nil {
			return false
		}
		return k.left.contains(val)
	}
	if k.right == nil {
		return false
	}
	return k.right.contains(val)
}

func (k *KRbtree) Find(val interface{}) interface{} {
	if !k.isset {
		return nil
	}
	return k.find(wrap(val))
}

func (k *KRbtree) find(val wrap_value) interface{} {
	v := k.value.FunCompare(val)
	if v == 0 {
		return k.value
	}
	if v > 0 {
		if k.left == nil {
			return nil
		}
		return k.left.find(val)
	}

	if k.right == nil {
		return nil
	}
	return k.right.find(val)
}

func (k *KRbtree) First() interface{} {
	if !k.isset {
		return nil
	}
	if k.left != nil {
		return k.left.First()
	}
	return k.value.Value()
}

func (k *KRbtree) Last() interface{} {
	if !k.isset {
		return nil
	}
	if k.right != nil {
		return k.right.Last()
	}
	return k.value.Value()
}

func (k *KRbtree) Walk(fn func(interface{}) bool) {
	if k.isset {
		k.walk(fn)
	}
}

func (k *KRbtree) walk(fn func(interface{}) bool) bool {
	if k.left != nil {
		if !k.left.walk(fn) {
			return false
		}
	}
	if !fn(k.value.Value()) {
		return false
	}
	if k.right != nil {
		if !k.right.walk(fn) {
			return false
		}
	}
	return true
}

func (k *KRbtree) Length() int {
	count := 0
	k.Walk(func(v interface{}) bool {
		count++
		return true
	})
	return count
}

func (k *KRbtree) ToSlice() []interface{} {
	if !k.isset {
		return nil
	}

	slice := make([]interface{}, k.Length())
	i := 0
	k.Walk(func(v interface{}) bool {
		slice[i] = v
		i++
		return true
	})
	return slice
}

func (k *KRbtree) Balance() *KRbtree {
	slice := k.ToSlice()

	balanced := new(KRbtree)

	balanced._balance(slice)

	return balanced
}

func (k *KRbtree) _balance(slice []interface{}) {
	if len(slice) == 0 {
		return
	}
	if len(slice) == 1 {
		k.Add(slice[0])
		return
	}
	mid := len(slice) / 2
	k.Add(slice[mid])
	k._balance(slice[:mid])
	k._balance(slice[mid:])
}

type wrap_int struct {
	val int
}

func (k *wrap_int) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_int); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_int) Value() interface{} {
	return k.val
}

type wrap_uint struct {
	val uint
}

func (k *wrap_uint) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_uint); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_uint) Value() interface{} {
	return k.val
}

type wrap_int8 struct {
	val int8
}

func (k *wrap_int8) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_int8); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_int8) Value() interface{} {
	return k.val
}

type wrap_uint8 struct {
	val uint8
}

func (k *wrap_uint8) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_uint8); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_uint8) Value() interface{} {
	return k.val
}

type wrap_int16 struct {
	val int16
}

func (k *wrap_int16) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_int16); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_int16) Value() interface{} {
	return k.val
}

type wrap_uint16 struct {
	val uint16
}

func (k *wrap_uint16) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_uint16); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_uint16) Value() interface{} {
	return k.val
}

type wrap_int32 struct {
	val int32
}

func (k *wrap_int32) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_int32); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_int32) Value() interface{} {
	return k.val
}

type wrap_uint32 struct {
	val uint32
}

func (k *wrap_uint32) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_uint32); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_uint32) Value() interface{} {
	return k.val
}

type wrap_int64 struct {
	val int64
}

func (k *wrap_int64) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_int64); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_int64) Value() interface{} {
	return k.val
}

type wrap_uint64 struct {
	val uint64
}

func (k *wrap_uint64) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_uint64); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_uint64) Value() interface{} {
	return k.val
}

type wrap_float32 struct {
	val float32
}

func (k *wrap_float32) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_float32); ok {
		if k.val == v.val {
			return 0
		}
		if k.val < v.val {
			return -1
		}
		return 1
	}
	return 0
}

func (k *wrap_float32) Value() interface{} {
	return k.val
}

type wrap_float64 struct {
	val float64
}

func (k *wrap_float64) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_float64); ok {
		if k.val == v.val {
			return 0
		}
		if k.val < v.val {
			return -1
		}
		return 1
	}
	return 0
}

func (k *wrap_float64) Value() interface{} {
	return k.val
}

type wrap_string struct {
	val string
}

func (k *wrap_string) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_string); ok {
		if k.val == v.val {
			return 0
		}
		if k.val < v.val {
			return -1
		}
		return 1
	}
	return 0
}

func (k *wrap_string) Value() interface{} {
	return k.val
}

type wrap_kvalue struct {
	val KValue
}

func (k *wrap_kvalue) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_kvalue); ok {
		return k.val.FunCompare(v.val)
	}
	return 0
}

func (k *wrap_kvalue) Value() interface{} {
	return k.val
}
<commit_msg>修复获取Find元素时，返回错误对象的BUG<commit_after>package kutil

import (
	"fmt"
	"reflect"
)

type KValue interface {
	FunCompare(o interface{}) int64 //0:equal,-1:small,1:big
}

type wrap_value interface {
	FunCompare(o wrap_value) int64
	Value() interface{}
}

type KRbtree struct {
	left  *KRbtree
	value wrap_value
	right *KRbtree
	isset bool
}

func wrap(val interface{}) wrap_value {
	if v, ok := val.(KValue); ok {
		return &wrap_kvalue{v}
	}
	if v, ok := val.(int); ok {
		return &wrap_int{v}
	}
	if v, ok := val.(int8); ok {
		return &wrap_int8{v}
	}
	if v, ok := val.(int16); ok {
		return &wrap_int16{v}
	}
	if v, ok := val.(int32); ok {
		return &wrap_int32{v}
	}
	if v, ok := val.(int64); ok {
		return &wrap_int64{v}
	}
	if v, ok := val.(uint); ok {
		return &wrap_uint{v}
	}
	if v, ok := val.(uint8); ok {
		return &wrap_uint8{v}
	}
	if v, ok := val.(uint16); ok {
		return &wrap_uint16{v}
	}
	if v, ok := val.(uint32); ok {
		return &wrap_uint32{v}
	}
	if v, ok := val.(uint64); ok {
		return &wrap_uint64{v}
	}
	if v, ok := val.(float32); ok {
		return &wrap_float32{v}
	}
	if v, ok := val.(float64); ok {
		return &wrap_float64{v}
	}
	if v, ok := val.(string); ok {
		return &wrap_string{v}
	}
	panic(fmt.Sprintln("Unknown datatype ", reflect.TypeOf(val), " in ", val))
	return nil
}

func (k *KRbtree) Add(val interface{}) bool {
	return k.add(wrap(val))
}

func (k *KRbtree) add(val wrap_value) bool {
	if k.isset {
		v := k.value.FunCompare(val)
		if v == 0 {
			return false
		}
		if v > 0 {
			if k.left == nil {
				k.left = new(KRbtree)
			}
			return k.left.add(val)
		}

		if k.right == nil {
			k.right = new(KRbtree)
		}
		return k.right.add(val)
	}
	k.isset = true
	k.value = val
	return true
}

func (k *KRbtree) RemoveFirst() interface{} {
	if !k.isset {
		return nil
	}
	val := k.removeFirst()
	return val.Value()
}

func (k *KRbtree) removeFirst() wrap_value {
	if k.left != nil {
		value := k.left.removeFirst()
		if !k.left.isset {
			k.left = nil
		}
		return value
	}
	value := k.value
	k.remove(value)
	return value
}

func (k *KRbtree) replaceWith(o *KRbtree) {
	k.value = o.value
	k.left = o.left
	k.right = o.right
}

func (k *KRbtree) RemoveLast() interface{} {
	if !k.isset {
		return nil
	}
	val := k.removeLast()
	return val.Value()
}

func (k *KRbtree) removeLast() wrap_value {
	if k.right != nil {
		value := k.right.removeLast()
		if !k.right.isset {
			k.right = nil
		}
		return value
	}
	value := k.value
	k.remove(value)
	return value
}

func (k *KRbtree) Remove(val interface{}) bool {
	return k.remove(wrap(val))
}

func (k *KRbtree) remove(val wrap_value) bool {
	if !k.isset {
		return false
	}
	v := k.value.FunCompare(val)
	if v == 0 {
		if k.right != nil {
			if k.left == nil {
				k.replaceWith(k.right)
			} else {
				k.value = k.right.removeFirst()
			}
		} else if k.left != nil {
			k.replaceWith(k.left)
		} else {
			k.isset = false
		}
	}
	if v > 0 {
		if k.left != nil {
			defer func() {
				if !k.left.isset {
					k.left = nil
				}
			}()
			return k.left.remove(val)
		}
		return false
	}

	if k.right != nil {
		defer func() {
			if !k.right.isset {
				k.right = nil
			}
		}()
		return k.right.remove(val)
	}
	return false
}

func (k *KRbtree) Contains(val interface{}) bool {
	return k.contains(wrap(val))
}

func (k *KRbtree) contains(val wrap_value) bool {
	if !k.isset {
		return false
	}
	v := k.value.FunCompare(val)
	if v == 0 {
		return true
	}
	if v > 0 {
		if k.left == nil {
			return false
		}
		return k.left.contains(val)
	}
	if k.right == nil {
		return false
	}
	return k.right.contains(val)
}

func (k *KRbtree) Find(val interface{}) interface{} {
	if !k.isset {
		return nil
	}
	return k.find(wrap(val))
}

func (k *KRbtree) find(val wrap_value) interface{} {
	v := k.value.FunCompare(val)
	if v == 0 {
		return k.value.Value()
	}
	if v > 0 {
		if k.left == nil {
			return nil
		}
		return k.left.find(val)
	}

	if k.right == nil {
		return nil
	}
	return k.right.find(val)
}

func (k *KRbtree) First() interface{} {
	if !k.isset {
		return nil
	}
	if k.left != nil {
		return k.left.First()
	}
	return k.value.Value()
}

func (k *KRbtree) Last() interface{} {
	if !k.isset {
		return nil
	}
	if k.right != nil {
		return k.right.Last()
	}
	return k.value.Value()
}

func (k *KRbtree) Walk(fn func(interface{}) bool) {
	if k.isset {
		k.walk(fn)
	}
}

func (k *KRbtree) walk(fn func(interface{}) bool) bool {
	if k.left != nil {
		if !k.left.walk(fn) {
			return false
		}
	}
	if !fn(k.value.Value()) {
		return false
	}
	if k.right != nil {
		if !k.right.walk(fn) {
			return false
		}
	}
	return true
}

func (k *KRbtree) Length() int {
	count := 0
	k.Walk(func(v interface{}) bool {
		count++
		return true
	})
	return count
}

func (k *KRbtree) ToSlice() []interface{} {
	if !k.isset {
		return nil
	}

	slice := make([]interface{}, k.Length())
	i := 0
	k.Walk(func(v interface{}) bool {
		slice[i] = v
		i++
		return true
	})
	return slice
}

func (k *KRbtree) Balance() *KRbtree {
	slice := k.ToSlice()

	balanced := new(KRbtree)

	balanced._balance(slice)

	return balanced
}

func (k *KRbtree) _balance(slice []interface{}) {
	if len(slice) == 0 {
		return
	}
	if len(slice) == 1 {
		k.Add(slice[0])
		return
	}
	mid := len(slice) / 2
	k.Add(slice[mid])
	k._balance(slice[:mid])
	k._balance(slice[mid:])
}

type wrap_int struct {
	val int
}

func (k *wrap_int) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_int); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_int) Value() interface{} {
	return k.val
}

type wrap_uint struct {
	val uint
}

func (k *wrap_uint) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_uint); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_uint) Value() interface{} {
	return k.val
}

type wrap_int8 struct {
	val int8
}

func (k *wrap_int8) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_int8); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_int8) Value() interface{} {
	return k.val
}

type wrap_uint8 struct {
	val uint8
}

func (k *wrap_uint8) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_uint8); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_uint8) Value() interface{} {
	return k.val
}

type wrap_int16 struct {
	val int16
}

func (k *wrap_int16) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_int16); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_int16) Value() interface{} {
	return k.val
}

type wrap_uint16 struct {
	val uint16
}

func (k *wrap_uint16) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_uint16); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_uint16) Value() interface{} {
	return k.val
}

type wrap_int32 struct {
	val int32
}

func (k *wrap_int32) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_int32); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_int32) Value() interface{} {
	return k.val
}

type wrap_uint32 struct {
	val uint32
}

func (k *wrap_uint32) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_uint32); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_uint32) Value() interface{} {
	return k.val
}

type wrap_int64 struct {
	val int64
}

func (k *wrap_int64) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_int64); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_int64) Value() interface{} {
	return k.val
}

type wrap_uint64 struct {
	val uint64
}

func (k *wrap_uint64) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_uint64); ok {
		return int64(k.val - v.val)
	}
	return 0
}

func (k *wrap_uint64) Value() interface{} {
	return k.val
}

type wrap_float32 struct {
	val float32
}

func (k *wrap_float32) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_float32); ok {
		if k.val == v.val {
			return 0
		}
		if k.val < v.val {
			return -1
		}
		return 1
	}
	return 0
}

func (k *wrap_float32) Value() interface{} {
	return k.val
}

type wrap_float64 struct {
	val float64
}

func (k *wrap_float64) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_float64); ok {
		if k.val == v.val {
			return 0
		}
		if k.val < v.val {
			return -1
		}
		return 1
	}
	return 0
}

func (k *wrap_float64) Value() interface{} {
	return k.val
}

type wrap_string struct {
	val string
}

func (k *wrap_string) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_string); ok {
		if k.val == v.val {
			return 0
		}
		if k.val < v.val {
			return -1
		}
		return 1
	}
	return 0
}

func (k *wrap_string) Value() interface{} {
	return k.val
}

type wrap_kvalue struct {
	val KValue
}

func (k *wrap_kvalue) FunCompare(o wrap_value) int64 {
	if v, ok := o.(*wrap_kvalue); ok {
		return k.val.FunCompare(v.val)
	}
	return 0
}

func (k *wrap_kvalue) Value() interface{} {
	return k.val
}
<|endoftext|>


<commit_before>/*
Package cdtime implements methods to convert from and to collectd's internal time
representation, cdtime_t.
*/
package cdtime // import "collectd.org/cdtime"

import (
	"strconv"
	"time"
)

// Time represens a time in collectd's internal representation.
type Time uint64

// New returns a new Time representing time t.
func New(t time.Time) Time {
	return newNano(uint64(t.UnixNano()))
}

// NewDuration returns a new Time representing duration d.
func NewDuration(d time.Duration) Time {
	return newNano(uint64(d.Nanoseconds()))
}

// Time converts and returns the time as time.Time.
func (t Time) Time() time.Time {
	s, ns := t.decompose()
	return time.Unix(s, ns)
}

// Duration converts and returns the duration as time.Time.
func (t Time) Duration() time.Duration {
	s, ns := t.decompose()
	return time.Duration(1000000000*s+ns) * time.Nanosecond
}

// String returns the string representation of Time. The format used is seconds
// since the epoch with millisecond precision, e.g. "1426588900.328".
func (t Time) String() string {
	f := t.Float()
	return strconv.FormatFloat(f /* format */, 'f' /* precision */, 3 /* bits */, 64)
}

// Float returns the time as seocnds since epoch. This is a lossy conversion,
// which will lose up to 11 bits. This means that the returned value should be
// considered to have roughly microsecond precision.
func (t Time) Float() float64 {
	s, ns := t.decompose()
	return float64(s) + float64(ns)/1000000000.0
}

// MarshalJSON implements the "encoding/json".Marshaler interface for Time.
func (t Time) MarshalJSON() ([]byte, error) {
	return []byte(t.String()), nil
}

// UnmarshalJSON implements the "encoding/json".Unmarshaler interface for Time.
func (t *Time) UnmarshalJSON(data []byte) error {
	f, err := strconv.ParseFloat(string(data) /* bits */, 64)
	if err != nil {
		return err
	}

	s := uint64(f)
	ns := uint64((f - float64(s)) * 1000000000.0)

	*t = newNano(1000000000*s + ns)
	return nil
}

func (t Time) decompose() (s, ns int64) {
	s = int64(t >> 30)
	ns = (int64(t&0x3fffffff) * 1000000000) >> 30
	return
}

func newNano(ns uint64) Time {
	// break into seconds and nano-seconds so the left-shift doesn't overflow.
	s := ns / 1000000000
	ns = ns % 1000000000

	return Time((s << 30) | ((ns << 30) / 1000000000))
}
<commit_msg>cdtime: Fix documentation of Duration(): wrong return type.<commit_after>/*
Package cdtime implements methods to convert from and to collectd's internal time
representation, cdtime_t.
*/
package cdtime // import "collectd.org/cdtime"

import (
	"strconv"
	"time"
)

// Time represens a time in collectd's internal representation.
type Time uint64

// New returns a new Time representing time t.
func New(t time.Time) Time {
	return newNano(uint64(t.UnixNano()))
}

// NewDuration returns a new Time representing duration d.
func NewDuration(d time.Duration) Time {
	return newNano(uint64(d.Nanoseconds()))
}

// Time converts and returns the time as time.Time.
func (t Time) Time() time.Time {
	s, ns := t.decompose()
	return time.Unix(s, ns)
}

// Duration converts and returns the duration as time.Duration.
func (t Time) Duration() time.Duration {
	s, ns := t.decompose()
	return time.Duration(1000000000*s+ns) * time.Nanosecond
}

// String returns the string representation of Time. The format used is seconds
// since the epoch with millisecond precision, e.g. "1426588900.328".
func (t Time) String() string {
	f := t.Float()
	return strconv.FormatFloat(f /* format */, 'f' /* precision */, 3 /* bits */, 64)
}

// Float returns the time as seocnds since epoch. This is a lossy conversion,
// which will lose up to 11 bits. This means that the returned value should be
// considered to have roughly microsecond precision.
func (t Time) Float() float64 {
	s, ns := t.decompose()
	return float64(s) + float64(ns)/1000000000.0
}

// MarshalJSON implements the "encoding/json".Marshaler interface for Time.
func (t Time) MarshalJSON() ([]byte, error) {
	return []byte(t.String()), nil
}

// UnmarshalJSON implements the "encoding/json".Unmarshaler interface for Time.
func (t *Time) UnmarshalJSON(data []byte) error {
	f, err := strconv.ParseFloat(string(data) /* bits */, 64)
	if err != nil {
		return err
	}

	s := uint64(f)
	ns := uint64((f - float64(s)) * 1000000000.0)

	*t = newNano(1000000000*s + ns)
	return nil
}

func (t Time) decompose() (s, ns int64) {
	s = int64(t >> 30)
	ns = (int64(t&0x3fffffff) * 1000000000) >> 30
	return
}

func newNano(ns uint64) Time {
	// break into seconds and nano-seconds so the left-shift doesn't overflow.
	s := ns / 1000000000
	ns = ns % 1000000000

	return Time((s << 30) | ((ns << 30) / 1000000000))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/xyproto/ask"
	"github.com/xyproto/simplehstore"
)

func checkError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
	}
	fmt.Println("ok")
}

func checkStringError(s string, err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
	}
	fmt.Println(s)
}

func checkBoolError(b bool, err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		return
	}
	fmt.Println(b)
}

func checkSliceError(xs []string, err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		return
	}
	if len(xs) == 0 {
		fmt.Println("No results")
		return
	}
	// Print the slice
	fmt.Println(strings.Join(xs, "\n"))
}

func checkMapError(m map[string]string, err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		return
	}
	if len(m) == 0 {
		fmt.Println("No results")
		return
	}
	// Print the map
	for k, v := range m {
		fmt.Printf("%s -> %s\n", k, v)
	}
}

func main() {
	var host *simplehstore.Host
	if len(os.Args) > 1 && strings.HasSuffix(os.Args[1], "d") {
		host = simplehstore.NewHost("postgres@127.0.0.1:5432/devices?sslmode=disable")
	} else {
		host = simplehstore.New() // locally
	}
	defer host.Close()

	host.SetRawUTF8(true)
	simplehstore.Verbose = true

	hashmap, err := simplehstore.NewHashMap2(host, "devices")
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}

LOOP:
	for {
		cmd := ask.Ask("> ")
		fields := strings.Fields(cmd)
		if len(fields) > 0 {
			switch fields[0] {
			case "all":
				if len(fields) == 1 {
					checkSliceError(hashmap.All())
				} else {
					fmt.Println("all")
				}
			case "clear":
				if len(fields) == 1 {
					checkError(hashmap.Clear())
				} else {
					fmt.Println("clear")
				}
			case "d":
				if len(fields) == 2 {
					checkError(hashmap.Del(fields[1]))
				} else if len(fields) == 3 {
					checkError(hashmap.DelKey(fields[1], fields[2]))
				} else {
					fmt.Println("d [o] [k]")
				}
			case "del":
				if len(fields) == 2 {
					checkError(hashmap.Del(fields[1]))
				} else {
					fmt.Println("del o")
				}
			case "delkey":
				if len(fields) == 3 {
					checkError(hashmap.DelKey(fields[1], fields[2]))
				} else {
					fmt.Println("delkey o k")
				}
			case "empty":
				if len(fields) == 1 {
					checkBoolError(hashmap.Empty())
				} else {
					fmt.Println("empty")
				}
			case "exists":
				if len(fields) == 2 {
					checkBoolError(hashmap.Exists(fields[1]))
				} else {
					fmt.Println("exists o")
				}

			case "has":
				if len(fields) == 3 {
					checkBoolError(hashmap.Has(fields[1], fields[2]))
				} else {
					fmt.Println("has o k")
				}

			case "keys":
				if len(fields) == 2 {
					checkSliceError(hashmap.Keys(fields[1]))
				} else {
					fmt.Println("keys o")
				}
			case "l", "ls":
				if len(fields) == 1 {
					checkSliceError(hashmap.All())
				} else if len(fields) == 2 {
					if keys, err := hashmap.Keys(fields[1]); err != nil {
						checkError(err)
					} else {
						for _, k := range keys {
							if v, err := hashmap.Get(fields[1], k); err != nil {
								checkError(err)
							} else {
								fmt.Printf("%s -> %s\n", k, v)
							}
						}
					}
				} else if len(fields) == 3 {
					checkStringError(hashmap.Get(fields[1], fields[2]))
				} else {
					fmt.Println("l")
					fmt.Println("l o")
					fmt.Println("l o k")
				}
			case "p", "props", "encounteredkeys":
				if len(fields) == 1 {
					checkSliceError(hashmap.AllEncounteredKeys())
				} else {
					fmt.Println("p")
				}
			case "get":
				if len(fields) == 3 {
					checkStringError(hashmap.Get(fields[1], fields[2]))
				} else {
					fmt.Println("get o k")
				}
			case "getmap":
				if len(fields) >= 3 {
					checkMapError(hashmap.GetMap(fields[1], fields[2:]))
				} else if len(fields) == 2 {
					keys, err := hashmap.Keys(fields[1])
					if err != nil {
						checkError(err)
					} else {
						checkMapError(hashmap.GetMap(fields[1], keys))
					}
				} else {
					fmt.Println("getmap o k k k ...")
				}
			case "set":
				if len(fields) == 4 {
					checkError(hashmap.Set(fields[1], fields[2], fields[3]))
				} else {
					fmt.Println("set o k v")
				}
			case "setmap":
				if len(fields) >= 3 {
					m := make(map[string]string)
					for _, keyAndValue := range fields[2:] {
						keyValueFields := strings.SplitN(keyAndValue, ",", 2)
						if len(keyValueFields) == 2 {
							m[keyValueFields[0]] = keyValueFields[1]
						}
					}
					fmt.Println(m)
					checkError(hashmap.SetMap(fields[1], m))
				} else {
					fmt.Println("setmap o k,v k,v k,v ...")
				}
			case "setlargemap":
				if len(fields) >= 2 {
					m := make(map[string]map[string]string)
					for _, okv := range fields[1:] {
						ownerKeyValue := strings.SplitN(okv, ",", 3)
						if len(ownerKeyValue) == 3 {
							o := ownerKeyValue[0]
							k := ownerKeyValue[1]
							v := ownerKeyValue[2]
							if _, ok := m[o]; ok {
								m[o][k] = v
							} else {
								m[o] = make(map[string]string)
								m[o][k] = v
							}
						}
					}
					fmt.Println(m)
					checkError(hashmap.SetLargeMap(m))
				} else {
					fmt.Println("setlargemap o,k,v o,k,v o,k,v ...")
				}
			case "remove":
				if len(fields) == 1 {
					checkError(hashmap.Remove())
				} else {
					fmt.Println("remove")
				}
				fmt.Println("creating a new one")
				hashmap, err = simplehstore.NewHashMap2(host, "devices")
				checkError(err)
			case "exit", "quit":
				fmt.Println(strings.Title(fields[0]))
				break LOOP
			case "help", "?", "h":
				fmt.Println("all - list all owners")
				fmt.Println("clear - remove all data in this table")
				fmt.Println("d o [k]")
				fmt.Println("del o")
				fmt.Println("delkey o k")
				fmt.Println("empty - check if the table is empty")
				fmt.Println("exists o - check if owner exists")
				fmt.Println("exit - exit the repl")
				fmt.Println("get o k - get the value of a key of an owner")
				fmt.Println("getmap o k k k ... - from an owner, get a map of keys and values")
				fmt.Println("has o k - check if an owner has a key")
				fmt.Println("help - this text")
				fmt.Println("keys o - list all keys for an owner")
				fmt.Println("l [o] [k] - list all owners, all keys for an owner or the value for a key")
				fmt.Println("p - list all encountered properties")
				fmt.Println("remove - remove the table")
				fmt.Println("set o k v - set an owner's key to the given value")
				fmt.Println("setmap o k,v k,v k,v ... ")
				fmt.Println("setlargemap o,k,v o,k,v o,k,v ... ")
				fmt.Println("quit - exit the repl")
			default:
				fmt.Println("unrecognized command")
			}
		}
	}
}
<commit_msg>Add allwhere to the repl<commit_after>package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/xyproto/ask"
	"github.com/xyproto/simplehstore"
)

func checkError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
	}
	fmt.Println("ok")
}

func checkStringError(s string, err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
	}
	fmt.Println(s)
}

func checkBoolError(b bool, err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		return
	}
	fmt.Println(b)
}

func checkSliceError(xs []string, err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		return
	}
	if len(xs) == 0 {
		fmt.Println("No results")
		return
	}
	// Print the slice
	fmt.Println(strings.Join(xs, "\n"))
}

func checkMapError(m map[string]string, err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		return
	}
	if len(m) == 0 {
		fmt.Println("No results")
		return
	}
	// Print the map
	for k, v := range m {
		fmt.Printf("%s -> %s\n", k, v)
	}
}

func main() {
	var host *simplehstore.Host
	if len(os.Args) > 1 && strings.HasSuffix(os.Args[1], "d") {
		host = simplehstore.NewHost("postgres@127.0.0.1:5432/devices?sslmode=disable")
	} else {
		host = simplehstore.New() // locally
	}
	defer host.Close()

	host.SetRawUTF8(true)
	simplehstore.Verbose = true

	hashmap, err := simplehstore.NewHashMap2(host, "devices")
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}

LOOP:
	for {
		cmd := ask.Ask("> ")
		fields := strings.Fields(cmd)
		if len(fields) > 0 {
			switch fields[0] {
			case "all":
				if len(fields) == 1 {
					checkSliceError(hashmap.All())
				} else {
					fmt.Println("all")
				}
			case "allwhere":
				if len(fields) == 3 {
					checkSliceError(hashmap.AllWhere(fields[1], fields[2]))
				} else {
					fmt.Println("allwhere k v")
				}
			case "clear":
				if len(fields) == 1 {
					checkError(hashmap.Clear())
				} else {
					fmt.Println("clear")
				}
			case "d":
				if len(fields) == 2 {
					checkError(hashmap.Del(fields[1]))
				} else if len(fields) == 3 {
					checkError(hashmap.DelKey(fields[1], fields[2]))
				} else {
					fmt.Println("d [o] [k]")
				}
			case "del":
				if len(fields) == 2 {
					checkError(hashmap.Del(fields[1]))
				} else {
					fmt.Println("del o")
				}
			case "delkey":
				if len(fields) == 3 {
					checkError(hashmap.DelKey(fields[1], fields[2]))
				} else {
					fmt.Println("delkey o k")
				}
			case "empty":
				if len(fields) == 1 {
					checkBoolError(hashmap.Empty())
				} else {
					fmt.Println("empty")
				}
			case "exists":
				if len(fields) == 2 {
					checkBoolError(hashmap.Exists(fields[1]))
				} else {
					fmt.Println("exists o")
				}

			case "has":
				if len(fields) == 3 {
					checkBoolError(hashmap.Has(fields[1], fields[2]))
				} else {
					fmt.Println("has o k")
				}

			case "keys":
				if len(fields) == 2 {
					checkSliceError(hashmap.Keys(fields[1]))
				} else {
					fmt.Println("keys o")
				}
			case "l", "ls":
				if len(fields) == 1 {
					checkSliceError(hashmap.All())
				} else if len(fields) == 2 {
					if keys, err := hashmap.Keys(fields[1]); err != nil {
						checkError(err)
					} else {
						for _, k := range keys {
							if v, err := hashmap.Get(fields[1], k); err != nil {
								checkError(err)
							} else {
								fmt.Printf("%s -> %s\n", k, v)
							}
						}
					}
				} else if len(fields) == 3 {
					checkStringError(hashmap.Get(fields[1], fields[2]))
				} else {
					fmt.Println("l")
					fmt.Println("l o")
					fmt.Println("l o k")
				}
			case "p", "props", "encounteredkeys":
				if len(fields) == 1 {
					checkSliceError(hashmap.AllEncounteredKeys())
				} else {
					fmt.Println("p")
				}
			case "get":
				if len(fields) == 3 {
					checkStringError(hashmap.Get(fields[1], fields[2]))
				} else {
					fmt.Println("get o k")
				}
			case "getmap":
				if len(fields) >= 3 {
					checkMapError(hashmap.GetMap(fields[1], fields[2:]))
				} else if len(fields) == 2 {
					keys, err := hashmap.Keys(fields[1])
					if err != nil {
						checkError(err)
					} else {
						checkMapError(hashmap.GetMap(fields[1], keys))
					}
				} else {
					fmt.Println("getmap o k k k ...")
				}
			case "set":
				if len(fields) == 4 {
					checkError(hashmap.Set(fields[1], fields[2], fields[3]))
				} else {
					fmt.Println("set o k v")
				}
			case "setmap":
				if len(fields) >= 3 {
					m := make(map[string]string)
					for _, keyAndValue := range fields[2:] {
						keyValueFields := strings.SplitN(keyAndValue, ",", 2)
						if len(keyValueFields) == 2 {
							m[keyValueFields[0]] = keyValueFields[1]
						}
					}
					fmt.Println(m)
					checkError(hashmap.SetMap(fields[1], m))
				} else {
					fmt.Println("setmap o k,v k,v k,v ...")
				}
			case "setlargemap":
				if len(fields) >= 2 {
					m := make(map[string]map[string]string)
					for _, okv := range fields[1:] {
						ownerKeyValue := strings.SplitN(okv, ",", 3)
						if len(ownerKeyValue) == 3 {
							o := ownerKeyValue[0]
							k := ownerKeyValue[1]
							v := ownerKeyValue[2]
							if _, ok := m[o]; ok {
								m[o][k] = v
							} else {
								m[o] = make(map[string]string)
								m[o][k] = v
							}
						}
					}
					fmt.Println(m)
					checkError(hashmap.SetLargeMap(m))
				} else {
					fmt.Println("setlargemap o,k,v o,k,v o,k,v ...")
				}
			case "remove":
				if len(fields) == 1 {
					checkError(hashmap.Remove())
				} else {
					fmt.Println("remove")
				}
				fmt.Println("creating a new one")
				hashmap, err = simplehstore.NewHashMap2(host, "devices")
				checkError(err)
			case "exit", "quit":
				fmt.Println(strings.Title(fields[0]))
				break LOOP
			case "help", "?", "h":
				fmt.Println("all - list all owners")
				fmt.Println("clear - remove all data in this table")
				fmt.Println("d o [k]")
				fmt.Println("del o")
				fmt.Println("delkey o k")
				fmt.Println("empty - check if the table is empty")
				fmt.Println("exists o - check if owner exists")
				fmt.Println("exit - exit the repl")
				fmt.Println("get o k - get the value of a key of an owner")
				fmt.Println("getmap o k k k ... - from an owner, get a map of keys and values")
				fmt.Println("has o k - check if an owner has a key")
				fmt.Println("help - this text")
				fmt.Println("keys o - list all keys for an owner")
				fmt.Println("l [o] [k] - list all owners, all keys for an owner or the value for a key")
				fmt.Println("p - list all encountered properties")
				fmt.Println("remove - remove the table")
				fmt.Println("set o k v - set an owner's key to the given value")
				fmt.Println("setmap o k,v k,v k,v ... ")
				fmt.Println("setlargemap o,k,v o,k,v o,k,v ... ")
				fmt.Println("quit - exit the repl")
			default:
				fmt.Println("unrecognized command")
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/JonLundy/go-totp/pkg/totp"
	"bufio"
	"os"
	"encoding/base32"
	"time"
	"crypto/sha1"
	"fmt"
        "strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	key, _ := reader.ReadString('\n')

	key = strings.Trim(key, "=\n")

        if i := len(key) % 8; i != 0 {
           key += strings.Repeat("=", 8-i)
        }

        k, _ := base32.StdEncoding.DecodeString(key)

	code, _ := totp.Totp(k, time.Now().Unix(), sha1.New, 6)
	fmt.Print(code)
}

<commit_msg>handle lowercased items<commit_after>package main

import (
	"github.com/JonLundy/go-totp/pkg/totp"
	"bufio"
	"os"
	"encoding/base32"
	"time"
	"crypto/sha1"
	"fmt"
        "strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	key, _ := reader.ReadString('\n')

	key = strings.ToUpper(strings.Trim(key, "=\n"))

        if i := len(key) % 8; i != 0 {
           key += strings.Repeat("=", 8-i)
        }

        k, _ := base32.StdEncoding.DecodeString(key)

	code, _ := totp.Totp(k, time.Now().Unix(), sha1.New, 6)
	fmt.Print(code)
}

<|endoftext|>


<commit_before>// Copyright 2010 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.

// This file contains the pieces of the tool that use typechecking from the go/types package.

package main

import (
	"go/ast"
	"go/token"

	"code.google.com/p/go.tools/go/types"
)

// imports is the canonical map of imported packages we need for typechecking.
// It is created during initialization.
var imports = make(map[string]*types.Package)

var (
	stringerMethodType = types.New("func() string")
	errorType          = types.New("error").Underlying().(*types.Interface)
	stringerType       = types.New("interface{ String() string }").(*types.Interface)
	formatterType      *types.Interface
)

func init() {
	typ := importType("fmt", "Formatter")
	if typ != nil {
		formatterType = typ.Underlying().(*types.Interface)
	}
}

// importType returns the type denoted by the qualified identifier
// path.name, and adds the respective package to the imports map
// as a side effect.
func importType(path, name string) types.Type {
	pkg, err := types.DefaultImport(imports, path)
	if err != nil {
		panic("import failed: " + err.Error())
	}
	if obj, ok := pkg.Scope().Lookup(name).(*types.TypeName); ok {
		return obj.Type()
	}
	panic("invalid type name: " + name)
}

func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error {
	pkg.defs = make(map[*ast.Ident]types.Object)
	pkg.uses = make(map[*ast.Ident]types.Object)
	pkg.spans = make(map[types.Object]Span)
	pkg.types = make(map[ast.Expr]types.TypeAndValue)
	config := types.Config{
		// We provide the same packages map for all imports to ensure
		// that everybody sees identical packages for the given paths.
		Packages: imports,
		// By providing a Config with our own error function, it will continue
		// past the first error. There is no need for that function to do anything.
		Error: func(error) {},
	}
	info := &types.Info{
		Types: pkg.types,
		Defs:  pkg.defs,
		Uses:  pkg.uses,
	}
	typesPkg, err := config.Check(pkg.path, fs, astFiles, info)
	pkg.typesPkg = typesPkg
	// update spans
	for id, obj := range pkg.defs {
		pkg.growSpan(id, obj)
	}
	for id, obj := range pkg.uses {
		pkg.growSpan(id, obj)
	}
	return err
}

// isStruct reports whether the composite literal c is a struct.
// If it is not (probably a struct), it returns a printable form of the type.
func (pkg *Package) isStruct(c *ast.CompositeLit) (bool, string) {
	// Check that the CompositeLit's type is a slice or array (which needs no field keys), if possible.
	typ := pkg.types[c].Type
	// If it's a named type, pull out the underlying type. If it's not, the Underlying
	// method returns the type itself.
	actual := typ
	if actual != nil {
		actual = actual.Underlying()
	}
	if actual == nil {
		// No type information available. Assume true, so we do the check.
		return true, ""
	}
	switch actual.(type) {
	case *types.Struct:
		return true, typ.String()
	default:
		return false, ""
	}
}

// matchArgType reports an error if printf verb t is not appropriate
// for operand arg.
//
// typ is used only for recursive calls; external callers must supply nil.
//
// (Recursion arises from the compound types {map,chan,slice} which
// may be printed with %d etc. if that is appropriate for their element
// types.)
func (f *File) matchArgType(t printfArgType, typ types.Type, arg ast.Expr) bool {
	return f.matchArgTypeInternal(t, typ, arg, make(map[types.Type]bool))
}

// matchArgTypeInternal is the internal version of matchArgType. It carries a map
// remembering what types are in progress so we don't recur when faced with recursive
// types or mutually recursive types.
func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Expr, inProgress map[types.Type]bool) bool {
	// %v, %T accept any argument type.
	if t == anyType {
		return true
	}
	if typ == nil {
		// external call
		typ = f.pkg.types[arg].Type
		if typ == nil {
			return true // probably a type check problem
		}
	}
	// If the type implements fmt.Formatter, we have nothing to check.
	// But (see issue 6259) that's not easy to verify, so instead we see
	// if its method set contains a Format function. We could do better,
	// even now, but we don't need to be 100% accurate. Wait for 6259 to
	// be fixed instead. TODO.
	if f.hasMethod(typ, "Format") {
		return true
	}
	// If we can use a string, might arg (dynamically) implement the Stringer or Error interface?
	if t&argString != 0 {
		if types.AssertableTo(errorType, typ) || types.AssertableTo(stringerType, typ) {
			return true
		}
	}

	typ = typ.Underlying()
	if inProgress[typ] {
		// We're already looking at this type. The call that started it will take care of it.
		return true
	}
	inProgress[typ] = true

	switch typ := typ.(type) {
	case *types.Signature:
		return t&argPointer != 0

	case *types.Map:
		// Recur: map[int]int matches %d.
		return t&argPointer != 0 ||
			(f.matchArgTypeInternal(t, typ.Key(), arg, inProgress) && f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress))

	case *types.Chan:
		return t&argPointer != 0

	case *types.Array:
		// Same as slice.
		if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 {
			return true // %s matches []byte
		}
		// Recur: []int matches %d.
		return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem().Underlying(), arg, inProgress)

	case *types.Slice:
		// Same as array.
		if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 {
			return true // %s matches []byte
		}
		// Recur: []int matches %d. But watch out for
		//	type T []T
		// If the element is a pointer type (type T[]*T), it's handled fine by the Pointer case below.
		return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress)

	case *types.Pointer:
		// Ugly, but dealing with an edge case: a known pointer to an invalid type,
		// probably something from a failed import.
		if typ.Elem().String() == "invalid type" {
			if *verbose {
				f.Warnf(arg.Pos(), "printf argument %v is pointer to invalid or unknown type", f.gofmt(arg))
			}
			return true // special case
		}
		// If it's actually a pointer with %p, it prints as one.
		if t == argPointer {
			return true
		}
		// If it's pointer to struct, that's equivalent in our analysis to whether we can print the struct.
		if str, ok := typ.Elem().Underlying().(*types.Struct); ok {
			return f.matchStructArgType(t, str, arg, inProgress)
		}
		// The rest can print with %p as pointers, or as integers with %x etc.
		return t&(argInt|argPointer) != 0

	case *types.Struct:
		return f.matchStructArgType(t, typ, arg, inProgress)

	case *types.Interface:
		// If the static type of the argument is empty interface, there's little we can do.
		// Example:
		//	func f(x interface{}) { fmt.Printf("%s", x) }
		// Whether x is valid for %s depends on the type of the argument to f. One day
		// we will be able to do better. For now, we assume that empty interface is OK
		// but non-empty interfaces, with Stringer and Error handled above, are errors.
		return typ.NumMethods() == 0

	case *types.Basic:
		switch typ.Kind() {
		case types.UntypedBool,
			types.Bool:
			return t&argBool != 0

		case types.UntypedInt,
			types.Int,
			types.Int8,
			types.Int16,
			types.Int32,
			types.Int64,
			types.Uint,
			types.Uint8,
			types.Uint16,
			types.Uint32,
			types.Uint64,
			types.Uintptr:
			return t&argInt != 0

		case types.UntypedFloat,
			types.Float32,
			types.Float64:
			return t&argFloat != 0

		case types.UntypedComplex,
			types.Complex64,
			types.Complex128:
			return t&argComplex != 0

		case types.UntypedString,
			types.String:
			return t&argString != 0

		case types.UnsafePointer:
			return t&(argPointer|argInt) != 0

		case types.UntypedRune:
			return t&(argInt|argRune) != 0

		case types.UntypedNil:
			return t&argPointer != 0 // TODO?

		case types.Invalid:
			if *verbose {
				f.Warnf(arg.Pos(), "printf argument %v has invalid or unknown type", f.gofmt(arg))
			}
			return true // Probably a type check problem.
		}
		panic("unreachable")
	}

	return false
}

// hasBasicType reports whether x's type is a types.Basic with the given kind.
func (f *File) hasBasicType(x ast.Expr, kind types.BasicKind) bool {
	t := f.pkg.types[x].Type
	if t != nil {
		t = t.Underlying()
	}
	b, ok := t.(*types.Basic)
	return ok && b.Kind() == kind
}

// matchStructArgType reports whether all the elements of the struct match the expected
// type. For instance, with "%d" all the elements must be printable with the "%d" format.
func (f *File) matchStructArgType(t printfArgType, typ *types.Struct, arg ast.Expr, inProgress map[types.Type]bool) bool {
	for i := 0; i < typ.NumFields(); i++ {
		if !f.matchArgTypeInternal(t, typ.Field(i).Type(), arg, inProgress) {
			return false
		}
	}
	return true
}

// numArgsInSignature tells how many formal arguments the function type
// being called has.
func (f *File) numArgsInSignature(call *ast.CallExpr) int {
	// Check the type of the function or method declaration
	typ := f.pkg.types[call.Fun].Type
	if typ == nil {
		return 0
	}
	// The type must be a signature, but be sure for safety.
	sig, ok := typ.(*types.Signature)
	if !ok {
		return 0
	}
	return sig.Params().Len()
}

// isErrorMethodCall reports whether the call is of a method with signature
//	func Error() string
// where "string" is the universe's string type. We know the method is called "Error".
func (f *File) isErrorMethodCall(call *ast.CallExpr) bool {
	typ := f.pkg.types[call].Type
	if typ != nil {
		// We know it's called "Error", so just check the function signature.
		return types.Identical(f.pkg.types[call.Fun].Type, stringerMethodType)
	}
	// Without types, we can still check by hand.
	// Is it a selector expression? Otherwise it's a function call, not a method call.
	sel, ok := call.Fun.(*ast.SelectorExpr)
	if !ok {
		return false
	}
	// The package is type-checked, so if there are no arguments, we're done.
	if len(call.Args) > 0 {
		return false
	}
	// Check the type of the method declaration
	typ = f.pkg.types[sel].Type
	if typ == nil {
		return false
	}
	// The type must be a signature, but be sure for safety.
	sig, ok := typ.(*types.Signature)
	if !ok {
		return false
	}
	// There must be a receiver for it to be a method call. Otherwise it is
	// a function, not something that satisfies the error interface.
	if sig.Recv() == nil {
		return false
	}
	// There must be no arguments. Already verified by type checking, but be thorough.
	if sig.Params().Len() > 0 {
		return false
	}
	// Finally the real questions.
	// There must be one result.
	if sig.Results().Len() != 1 {
		return false
	}
	// It must have return type "string" from the universe.
	return sig.Results().At(0).Type() == types.Typ[types.String]
}

// hasMethod reports whether the type contains a method with the given name.
// It is part of the workaround for Formatters and should be deleted when
// that workaround is no longer necessary.
// TODO: This could be better once issue 6259 is fixed.
func (f *File) hasMethod(typ types.Type, name string) bool {
	// assume we have an addressable variable of type typ
	obj, _, _ := types.LookupFieldOrMethod(typ, true, f.pkg.typesPkg, name)
	_, ok := obj.(*types.Func)
	return ok
}
<commit_msg>cmd/vet: return nil from importType if it fails.<commit_after>// Copyright 2010 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.

// This file contains the pieces of the tool that use typechecking from the go/types package.

package main

import (
	"go/ast"
	"go/token"

	"code.google.com/p/go.tools/go/types"
)

// imports is the canonical map of imported packages we need for typechecking.
// It is created during initialization.
var imports = make(map[string]*types.Package)

var (
	stringerMethodType = types.New("func() string")
	errorType          = types.New("error").Underlying().(*types.Interface)
	stringerType       = types.New("interface{ String() string }").(*types.Interface)
	formatterType      *types.Interface
)

func init() {
	typ := importType("fmt", "Formatter")
	if typ != nil {
		formatterType = typ.Underlying().(*types.Interface)
	}
}

// importType returns the type denoted by the qualified identifier
// path.name, and adds the respective package to the imports map
// as a side effect.
func importType(path, name string) types.Type {
	pkg, err := types.DefaultImport(imports, path)
	if err != nil {
		warnf("import failed: %v", err)
		return nil
	}
	if obj, ok := pkg.Scope().Lookup(name).(*types.TypeName); ok {
		return obj.Type()
	}
	warnf("invalid type name %q", name)
	return nil
}

func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error {
	pkg.defs = make(map[*ast.Ident]types.Object)
	pkg.uses = make(map[*ast.Ident]types.Object)
	pkg.spans = make(map[types.Object]Span)
	pkg.types = make(map[ast.Expr]types.TypeAndValue)
	config := types.Config{
		// We provide the same packages map for all imports to ensure
		// that everybody sees identical packages for the given paths.
		Packages: imports,
		// By providing a Config with our own error function, it will continue
		// past the first error. There is no need for that function to do anything.
		Error: func(error) {},
	}
	info := &types.Info{
		Types: pkg.types,
		Defs:  pkg.defs,
		Uses:  pkg.uses,
	}
	typesPkg, err := config.Check(pkg.path, fs, astFiles, info)
	pkg.typesPkg = typesPkg
	// update spans
	for id, obj := range pkg.defs {
		pkg.growSpan(id, obj)
	}
	for id, obj := range pkg.uses {
		pkg.growSpan(id, obj)
	}
	return err
}

// isStruct reports whether the composite literal c is a struct.
// If it is not (probably a struct), it returns a printable form of the type.
func (pkg *Package) isStruct(c *ast.CompositeLit) (bool, string) {
	// Check that the CompositeLit's type is a slice or array (which needs no field keys), if possible.
	typ := pkg.types[c].Type
	// If it's a named type, pull out the underlying type. If it's not, the Underlying
	// method returns the type itself.
	actual := typ
	if actual != nil {
		actual = actual.Underlying()
	}
	if actual == nil {
		// No type information available. Assume true, so we do the check.
		return true, ""
	}
	switch actual.(type) {
	case *types.Struct:
		return true, typ.String()
	default:
		return false, ""
	}
}

// matchArgType reports an error if printf verb t is not appropriate
// for operand arg.
//
// typ is used only for recursive calls; external callers must supply nil.
//
// (Recursion arises from the compound types {map,chan,slice} which
// may be printed with %d etc. if that is appropriate for their element
// types.)
func (f *File) matchArgType(t printfArgType, typ types.Type, arg ast.Expr) bool {
	return f.matchArgTypeInternal(t, typ, arg, make(map[types.Type]bool))
}

// matchArgTypeInternal is the internal version of matchArgType. It carries a map
// remembering what types are in progress so we don't recur when faced with recursive
// types or mutually recursive types.
func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Expr, inProgress map[types.Type]bool) bool {
	// %v, %T accept any argument type.
	if t == anyType {
		return true
	}
	if typ == nil {
		// external call
		typ = f.pkg.types[arg].Type
		if typ == nil {
			return true // probably a type check problem
		}
	}
	// If the type implements fmt.Formatter, we have nothing to check.
	// But (see issue 6259) that's not easy to verify, so instead we see
	// if its method set contains a Format function. We could do better,
	// even now, but we don't need to be 100% accurate. Wait for 6259 to
	// be fixed instead. TODO.
	if f.hasMethod(typ, "Format") {
		return true
	}
	// If we can use a string, might arg (dynamically) implement the Stringer or Error interface?
	if t&argString != 0 {
		if types.AssertableTo(errorType, typ) || types.AssertableTo(stringerType, typ) {
			return true
		}
	}

	typ = typ.Underlying()
	if inProgress[typ] {
		// We're already looking at this type. The call that started it will take care of it.
		return true
	}
	inProgress[typ] = true

	switch typ := typ.(type) {
	case *types.Signature:
		return t&argPointer != 0

	case *types.Map:
		// Recur: map[int]int matches %d.
		return t&argPointer != 0 ||
			(f.matchArgTypeInternal(t, typ.Key(), arg, inProgress) && f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress))

	case *types.Chan:
		return t&argPointer != 0

	case *types.Array:
		// Same as slice.
		if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 {
			return true // %s matches []byte
		}
		// Recur: []int matches %d.
		return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem().Underlying(), arg, inProgress)

	case *types.Slice:
		// Same as array.
		if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 {
			return true // %s matches []byte
		}
		// Recur: []int matches %d. But watch out for
		//	type T []T
		// If the element is a pointer type (type T[]*T), it's handled fine by the Pointer case below.
		return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress)

	case *types.Pointer:
		// Ugly, but dealing with an edge case: a known pointer to an invalid type,
		// probably something from a failed import.
		if typ.Elem().String() == "invalid type" {
			if *verbose {
				f.Warnf(arg.Pos(), "printf argument %v is pointer to invalid or unknown type", f.gofmt(arg))
			}
			return true // special case
		}
		// If it's actually a pointer with %p, it prints as one.
		if t == argPointer {
			return true
		}
		// If it's pointer to struct, that's equivalent in our analysis to whether we can print the struct.
		if str, ok := typ.Elem().Underlying().(*types.Struct); ok {
			return f.matchStructArgType(t, str, arg, inProgress)
		}
		// The rest can print with %p as pointers, or as integers with %x etc.
		return t&(argInt|argPointer) != 0

	case *types.Struct:
		return f.matchStructArgType(t, typ, arg, inProgress)

	case *types.Interface:
		// If the static type of the argument is empty interface, there's little we can do.
		// Example:
		//	func f(x interface{}) { fmt.Printf("%s", x) }
		// Whether x is valid for %s depends on the type of the argument to f. One day
		// we will be able to do better. For now, we assume that empty interface is OK
		// but non-empty interfaces, with Stringer and Error handled above, are errors.
		return typ.NumMethods() == 0

	case *types.Basic:
		switch typ.Kind() {
		case types.UntypedBool,
			types.Bool:
			return t&argBool != 0

		case types.UntypedInt,
			types.Int,
			types.Int8,
			types.Int16,
			types.Int32,
			types.Int64,
			types.Uint,
			types.Uint8,
			types.Uint16,
			types.Uint32,
			types.Uint64,
			types.Uintptr:
			return t&argInt != 0

		case types.UntypedFloat,
			types.Float32,
			types.Float64:
			return t&argFloat != 0

		case types.UntypedComplex,
			types.Complex64,
			types.Complex128:
			return t&argComplex != 0

		case types.UntypedString,
			types.String:
			return t&argString != 0

		case types.UnsafePointer:
			return t&(argPointer|argInt) != 0

		case types.UntypedRune:
			return t&(argInt|argRune) != 0

		case types.UntypedNil:
			return t&argPointer != 0 // TODO?

		case types.Invalid:
			if *verbose {
				f.Warnf(arg.Pos(), "printf argument %v has invalid or unknown type", f.gofmt(arg))
			}
			return true // Probably a type check problem.
		}
		panic("unreachable")
	}

	return false
}

// hasBasicType reports whether x's type is a types.Basic with the given kind.
func (f *File) hasBasicType(x ast.Expr, kind types.BasicKind) bool {
	t := f.pkg.types[x].Type
	if t != nil {
		t = t.Underlying()
	}
	b, ok := t.(*types.Basic)
	return ok && b.Kind() == kind
}

// matchStructArgType reports whether all the elements of the struct match the expected
// type. For instance, with "%d" all the elements must be printable with the "%d" format.
func (f *File) matchStructArgType(t printfArgType, typ *types.Struct, arg ast.Expr, inProgress map[types.Type]bool) bool {
	for i := 0; i < typ.NumFields(); i++ {
		if !f.matchArgTypeInternal(t, typ.Field(i).Type(), arg, inProgress) {
			return false
		}
	}
	return true
}

// numArgsInSignature tells how many formal arguments the function type
// being called has.
func (f *File) numArgsInSignature(call *ast.CallExpr) int {
	// Check the type of the function or method declaration
	typ := f.pkg.types[call.Fun].Type
	if typ == nil {
		return 0
	}
	// The type must be a signature, but be sure for safety.
	sig, ok := typ.(*types.Signature)
	if !ok {
		return 0
	}
	return sig.Params().Len()
}

// isErrorMethodCall reports whether the call is of a method with signature
//	func Error() string
// where "string" is the universe's string type. We know the method is called "Error".
func (f *File) isErrorMethodCall(call *ast.CallExpr) bool {
	typ := f.pkg.types[call].Type
	if typ != nil {
		// We know it's called "Error", so just check the function signature.
		return types.Identical(f.pkg.types[call.Fun].Type, stringerMethodType)
	}
	// Without types, we can still check by hand.
	// Is it a selector expression? Otherwise it's a function call, not a method call.
	sel, ok := call.Fun.(*ast.SelectorExpr)
	if !ok {
		return false
	}
	// The package is type-checked, so if there are no arguments, we're done.
	if len(call.Args) > 0 {
		return false
	}
	// Check the type of the method declaration
	typ = f.pkg.types[sel].Type
	if typ == nil {
		return false
	}
	// The type must be a signature, but be sure for safety.
	sig, ok := typ.(*types.Signature)
	if !ok {
		return false
	}
	// There must be a receiver for it to be a method call. Otherwise it is
	// a function, not something that satisfies the error interface.
	if sig.Recv() == nil {
		return false
	}
	// There must be no arguments. Already verified by type checking, but be thorough.
	if sig.Params().Len() > 0 {
		return false
	}
	// Finally the real questions.
	// There must be one result.
	if sig.Results().Len() != 1 {
		return false
	}
	// It must have return type "string" from the universe.
	return sig.Results().At(0).Type() == types.Typ[types.String]
}

// hasMethod reports whether the type contains a method with the given name.
// It is part of the workaround for Formatters and should be deleted when
// that workaround is no longer necessary.
// TODO: This could be better once issue 6259 is fixed.
func (f *File) hasMethod(typ types.Type, name string) bool {
	// assume we have an addressable variable of type typ
	obj, _, _ := types.LookupFieldOrMethod(typ, true, f.pkg.typesPkg, name)
	_, ok := obj.(*types.Func)
	return ok
}
<|endoftext|>