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

package dataaccess

import (
	"fmt"
	"github.com/andreaskoch/allmark2/common/content"
	"github.com/andreaskoch/allmark2/common/route"
	"strings"
)

type ItemType int

func (itemType ItemType) String() string {
	switch itemType {

	case TypePhysical:
		return "physical"

	case TypeVirtual:
		return "virtual"

	case TypeFileCollection:
		return "filecollection"

	default:
		return "unknown"

	}

	panic("Unreachable")
}

const (
	TypePhysical ItemType = iota
	TypeVirtual
	TypeFileCollection
)

// An Item represents a single document in a repository.
type Item struct {
	*content.ContentProvider
	itemType   ItemType
	route      route.Route
	filesFunc  func() []*File
	childsFunc func() []*Item

	files  []*File
	childs []*Item
}

func NewPhysicalItem(route route.Route, contentProvider *content.ContentProvider, files func() []*File, childs func() []*Item) (*Item, error) {
	return newItem(TypePhysical, route, contentProvider, files, childs)
}

func NewVirtualItem(route route.Route, contentProvider *content.ContentProvider, files func() []*File, childs func() []*Item) (*Item, error) {
	return newItem(TypeVirtual, route, contentProvider, files, childs)
}

func NewFileCollectionItem(route route.Route, contentProvider *content.ContentProvider, files func() []*File) (*Item, error) {
	return newItem(TypeFileCollection, route, contentProvider, files, nil)
}

func newItem(itemType ItemType, route route.Route, contentProvider *content.ContentProvider, files func() []*File, childs func() []*Item) (*Item, error) {
	return &Item{
		contentProvider,
		itemType,
		route,
		files,
		childs,
		nil,
		nil,
	}, nil
}

func (item *Item) String() string {
	return fmt.Sprintf("%s", item.route.String())
}

// Get the type of this item (e.g. "physical", "virtual", ...)
func (item *Item) Type() ItemType {
	return item.itemType
}

// Gets a flag inidicating whether this item can have childs or not.
func (item *Item) CanHaveChilds() bool {
	switch item.Type() {

	// each child directory which is not the "files" folder can be a child
	case TypePhysical, TypeVirtual:
		return true

		// file collection items cannot have childs because all items in the directory are "files" and not items
	case TypeFileCollection:
		return false

	}

	panic("Unreachable. Unknown Item type.")
}

// Get the route of this item.
func (item *Item) Route() route.Route {
	return item.route
}

// Get the childs of this item. Returns nil if this item cannot have childs; otherwise returns a slice with zero or more childs.
func (item *Item) GetChilds() (childs []*Item) {
	if !item.CanHaveChilds() || item.childs == nil {
		return
	}

	if item.childs == nil {
		item.childs = item.childsFunc()
	}

	return item.childs
}

// Get the files of this item. Returns a slice of zero or more files.
func (item *Item) Files() []*File {

	if item.files == nil {
		item.files = item.filesFunc()
	}

	return item.files
}

// Get the file which matches the supplied route. Returns nil if there is no matching file.
func (item *Item) GetFile(fileRoute route.Route) *File {
	for _, file := range item.Files() {
		if !strings.HasSuffix(fileRoute.Value(), file.Route().Value()) {
			continue
		}

		return file
	}

	return nil
}

func (item *Item) ChildChanges() (newChilds []*Item, removedChilds []route.Route) {

	// capture the status quo
	previousChilds := make(map[string]*Item, 0)
	for _, child := range item.GetChilds() {
		previousChilds[child.Route().Value()] = child
	}

	// force a reload!
	item.childs = nil

	// get the new childs
	currentChilds := make(map[string]*Item, 0)
	for _, child := range item.GetChilds() {
		currentChilds[child.Route().Value()] = child
	}

	// find new childs
	newChilds = make([]*Item, 0)
	for key, child := range currentChilds {

		if _, exists := previousChilds[key]; !exists {
			newChilds = append(newChilds, child)
		}

	}

	// find removed childs
	removedChilds = make([]route.Route, 0)
	for key, child := range previousChilds {

		if _, exists := currentChilds[key]; !exists {
			removedChilds = append(removedChilds, child.Route())
		}

	}

	return newChilds, removedChilds

}

func (item *Item) Refresh() {
	item.files = nil
	item.childs = nil
}
<commit_msg>Item childs and files lazy loading<commit_after>// Copyright 2014 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package dataaccess

import (
	"fmt"
	"github.com/andreaskoch/allmark2/common/content"
	"github.com/andreaskoch/allmark2/common/route"
	"strings"
)

type ItemType int

func (itemType ItemType) String() string {
	switch itemType {

	case TypePhysical:
		return "physical"

	case TypeVirtual:
		return "virtual"

	case TypeFileCollection:
		return "filecollection"

	default:
		return "unknown"

	}

	panic("Unreachable")
}

const (
	TypePhysical ItemType = iota
	TypeVirtual
	TypeFileCollection
)

// An Item represents a single document in a repository.
type Item struct {
	*content.ContentProvider
	itemType   ItemType
	route      route.Route
	filesFunc  func() []*File
	childsFunc func() []*Item

	files  []*File
	childs []*Item
}

func NewPhysicalItem(route route.Route, contentProvider *content.ContentProvider, files func() []*File, childs func() []*Item) (*Item, error) {
	return newItem(TypePhysical, route, contentProvider, files, childs)
}

func NewVirtualItem(route route.Route, contentProvider *content.ContentProvider, files func() []*File, childs func() []*Item) (*Item, error) {
	return newItem(TypeVirtual, route, contentProvider, files, childs)
}

func NewFileCollectionItem(route route.Route, contentProvider *content.ContentProvider, files func() []*File) (*Item, error) {
	return newItem(TypeFileCollection, route, contentProvider, files, nil)
}

func newItem(itemType ItemType, route route.Route, contentProvider *content.ContentProvider, files func() []*File, childs func() []*Item) (*Item, error) {
	return &Item{
		contentProvider,
		itemType,
		route,
		files,
		childs,
		nil,
		nil,
	}, nil
}

func (item *Item) String() string {
	return fmt.Sprintf("%s", item.route.String())
}

// Get the type of this item (e.g. "physical", "virtual", ...)
func (item *Item) Type() ItemType {
	return item.itemType
}

// Gets a flag inidicating whether this item can have childs or not.
func (item *Item) CanHaveChilds() bool {
	switch item.Type() {

	// each child directory which is not the "files" folder can be a child
	case TypePhysical, TypeVirtual:
		return true

		// file collection items cannot have childs because all items in the directory are "files" and not items
	case TypeFileCollection:
		return false

	}

	panic("Unreachable. Unknown Item type.")
}

// Get the route of this item.
func (item *Item) Route() route.Route {
	return item.route
}

// Get the childs of this item. Returns nil if this item cannot have childs; otherwise returns a slice with zero or more childs.
func (item *Item) GetChilds() (childs []*Item) {
	if !item.CanHaveChilds() || item.childsFunc == nil {
		return
	}

	if item.childs == nil {
		item.childs = item.childsFunc()
	}

	return item.childs
}

// Get the files of this item. Returns a slice of zero or more files.
func (item *Item) Files() []*File {

	if item.files == nil {
		item.files = item.filesFunc()
	}

	return item.files
}

// Get the file which matches the supplied route. Returns nil if there is no matching file.
func (item *Item) GetFile(fileRoute route.Route) *File {
	for _, file := range item.Files() {
		if !strings.HasSuffix(fileRoute.Value(), file.Route().Value()) {
			continue
		}

		return file
	}

	return nil
}

func (item *Item) ChildChanges() (newChilds []*Item, removedChilds []route.Route) {

	// capture the status quo
	previousChilds := make(map[string]*Item, 0)
	for _, child := range item.GetChilds() {
		previousChilds[child.Route().Value()] = child
	}

	// force a reload!
	item.childs = nil

	// get the new childs
	currentChilds := make(map[string]*Item, 0)
	for _, child := range item.GetChilds() {
		currentChilds[child.Route().Value()] = child
	}

	// find new childs
	newChilds = make([]*Item, 0)
	for key, child := range currentChilds {

		if _, exists := previousChilds[key]; !exists {
			newChilds = append(newChilds, child)
		}

	}

	// find removed childs
	removedChilds = make([]route.Route, 0)
	for key, child := range previousChilds {

		if _, exists := currentChilds[key]; !exists {
			removedChilds = append(removedChilds, child.Route())
		}

	}

	return newChilds, removedChilds

}

func (item *Item) Refresh() {
	item.files = nil
	item.childs = nil
}
<|endoftext|>


<commit_before>// Package ircclient provides the main interface for library users
// It manages a single connection to the server and the associated
// configuration and plugins.
package ircclient

import (
	"os"
	"log"
	"strings"
	"fmt"
)

type IRCClient struct {
	conn       *ircConn
	plugins    *pluginStack
	handlers   map[string]handler
	disconnect chan bool
}

type handler struct {
	Handler   Plugin
	Command   string
	Minparams int
	Minaccess int
}

// Returns a new IRCClient connection with the given configuration options.
// It will not connect to the given server until Connect() has been called,
// so you can register plugins before connecting
func NewIRCClient(configfile string) *IRCClient {
	c := &IRCClient{nil, newPluginStack(), make(map[string]handler), make(chan bool)}
	c.RegisterPlugin(&basicProtocol{})
	c.RegisterPlugin(NewConfigPlugin(configfile))
	c.RegisterPlugin(new(authPlugin))
	return c
}

// Registers a new plugin. Plugins can be registered at any time, even before
// the actual connection attempt. The plugin's Unregister() function will already
// be called when the connection is lost.
func (ic *IRCClient) RegisterPlugin(p Plugin) os.Error {
	if _, ok := ic.plugins.GetPlugin(p.String()); ok == true {
		return os.NewError("Plugin already exists")
	}
	p.Register(ic)
	ic.plugins.Push(p)
	return nil
}

// Registers a command handler. Plugin callbacks will only be called if
// the command matches. Note that only a single plugin per command may
// be registered. This function is not synchronized, e.g., it shall only
// be called during registration (as Plugin.Register()-calls are currently
// sequential).
func (ic *IRCClient) RegisterCommandHandler(command string, minparams int, minaccess int, plugin Plugin) os.Error {
	if plug, err := ic.handlers[command]; err {
		return os.NewError("Handler is already registered by plugin: " + plug.Handler.String())
	}
	ic.handlers[command] = handler{plugin, command, minparams, minaccess}
	return nil
}

// Gets one of the configuration options stored in the config object. Valid config
// options for section "Server" usually include:
//  - nick
//  - hostport (colon-seperated host and port to connect to)
//  - realname (the real name)
//  - ident
//  - trigger
// All other sections are managed by the library user. Returns an
// empty string if the option is empty, this means: you currently can't
// use empty config values - they will be deemed non-existent!
func (ic *IRCClient) GetStringOption(section, option string) string {
	c, _ := ic.GetPlugin("conf")
	if c == nil {
		log.Fatal("wtf?")
	}
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	retval, _ := cf.Conf.String(section, option)
	cf.Unlock()
	return retval
}

// Sets a single config option. Existing parameters are overriden,
// if necessary, a new config section is automatically added.
func (ic *IRCClient) SetStringOption(section, option, value string) {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	if ! cf.Conf.HasSection(section) {
		cf.Conf.AddSection(section)
	}
	if cf.Conf.HasOption(section, option) {
		cf.Conf.RemoveOption(section, option)
	}
	cf.Conf.AddOption(section, option, value)
	cf.Unlock()
}

// Removes a single config option. Note: This does not delete the section,
// even if it's empty.
func (ic *IRCClient) RemoveOption(section, option string) {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	defer cf.Unlock()

	if ! cf.Conf.HasSection(section) {
		// nothing to do
		return
	}
	cf.Conf.RemoveOption(section, option)
}

// Gets a list of all config keys for a given section. The return value is
// an empty slice if there are no options present _or_ if there is no
// section present. There is currently no way to check whether a section
// exists, it is automatically added when calling one of the SetOption()
// methods.
func (ic *IRCClient) GetOptions(section string) []string {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	defer cf.Unlock()
	opts, err := cf.Conf.Options(section)
	if err != nil {
		return []string{}
	}
	return opts
}

// Does the same as GetStringOption(), but with integers. Returns an os.Error,
// if the given config option does not exist.
func (ic *IRCClient) GetIntOption(section, option string) (int, os.Error) {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	defer cf.Unlock()
	v, err := cf.Conf.Int(section, option)
	if err != nil {
		return -1, err
	}
	return v, nil
}

// See SetStringOption()
func (ic *IRCClient) SetIntOption(section, option string, value int) {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	defer cf.Unlock()
	stropt := fmt.Sprintf("%d", value)
	if ! cf.Conf.HasSection(section) {
		cf.Conf.AddSection(section)
	}
	cf.Conf.AddOption(section, option, stropt)
}

// Gets the highest matching access level for a given hostmask by comparing
// the mask against all authorization entries. Default return value is 0
// (no access).
func (ic *IRCClient) GetAccessLevel(host string) int {
	a, _ := ic.GetPlugin("auth")
	auth, _ := a.(*authPlugin)
	return auth.GetAccessLevel(host)
}

// Sets the access level for the given hostmask to level. Note that host may
// be a regular expression, if exactly the same expression is already present
// in the database, it is overridden.
func (ic *IRCClient) SetAccessLevel(host string, level int) {
	a, _ := ic.GetPlugin("auth")
	auth, _ := a.(*authPlugin)
	auth.SetAccessLevel(host, level )
}

// Delete the given regular expression from auth database. The "host" parameter
// has to be exactly the string stored in the database, otherwise, the command
// will have no effect.
func (ic *IRCClient) DelAccessLevel(host string) {
	a, _ := ic.GetPlugin("auth")
	auth, _ := a.(*authPlugin)
	auth.DelAccessLevel(host)
}

// Connects to the server specified on object creation. If the chosen nickname is
// already in use, it will automatically be suffixed with an single underscore until
// an unused nickname is found. This function blocks until the connection attempt
// has been finished.
func (ic *IRCClient) Connect() os.Error {
	ic.conn = NewircConn()
	e := ic.conn.Connect(ic.GetStringOption("Server", "host"))
	if e != nil {
		return e
	}
	ic.conn.Output <- "NICK " + ic.GetStringOption("Server", "nick")
	ic.conn.Output <- "USER " + ic.GetStringOption("Server", "ident") + " * Q :" + ic.GetStringOption("Server", "realname")
	nick := ic.GetStringOption("Server", "nick")
	for {
		line, ok := <-ic.conn.Input
		if !ok {
			return <-ic.conn.Err
		}

		// Invoke plugin line handlers.
		// At this point, it makes no sense to
		// process "commands". If a plugin needs
		// interaction in this state, it should be
		// low-level.
		s := ParseServerLine(line)
		if s == nil {
			continue
		}
		for p := range ic.plugins.Iter() {
			go p.ProcessLine(s)
		}

		switch s.Command {
		case "433":
			// Nickname already in use
			nick = nick + "_"
			ic.SetStringOption("Server", "nick", nick)
			ic.conn.Output <- "NICK " + nick
		case "001":
			// Successfully registered
			return nil
		}
	}
	return nil
}

func (ic *IRCClient) dispatchHandlers(in string) {
	var c *IRCCommand = nil

	s := ParseServerLine(in)
	if s == nil {
		return
	}
	if (s.Command == "PRIVMSG" || s.Command == "NOTICE") && (s.Target == ic.GetStringOption("Server", "nick") || strings.Index(s.Args[0], ic.GetStringOption("Server", "trigger")) == 0) {
		c = ParseCommand(s)
		// Strip trigger, if necessary
		if c != nil && s.Target != ic.GetStringOption("Server", "nick") && len(c.Command) != 0 {
			c.Command = c.Command[len(ic.GetStringOption("Server", "trigger")):len(c.Command)]
		}
	}

	// Call line handlers
	for p := range ic.plugins.Iter() {
		go p.ProcessLine(s)
	}

	// Call command handler
	if c == nil {
		return
	}
	if handler, err := ic.handlers[c.Command]; err == true {
		// Don't do regexp matching, if we don't need access anyway
		if handler.Minaccess > 0 && ic.GetAccessLevel(c.Source) < handler.Minaccess {
			ic.Reply(c, "You are not authorized to do that.")
			return
		}
		if len(c.Args) < handler.Minparams {
			ic.Reply(c, "This command requires at least " + fmt.Sprintf("%d", handler.Minparams)+" parameters")
			return
		}
		go handler.Handler.ProcessCommand(c)
	}
}

// Starts the actual command processing. This function will block until the connection
// has either been lost or Disconnect() has been called (by a plugin or by the library
// user).
func (ic *IRCClient) InputLoop() os.Error {
	for {
		in, ok := <-ic.conn.Input
		if !ok {
			return <-ic.conn.Err
		}
		ic.dispatchHandlers(in)
	}
	panic("This never happens")
}

// Disconnects from the server with the given quit message. All plugins wil be unregistered
// and pending messages in queue (e.g. because of floodprotection) will be flushed. This will
// also make InputLoop() return.
func (ic *IRCClient) Disconnect(quitmsg string) {
	ic.shutdown()
	ic.conn.Output <- "QUIT :" + quitmsg
	ic.conn.Quit()
}

// Dumps a raw line to the server socket. This is usually called by plugins, but may also
// be used by the library user.
func (ic *IRCClient) SendLine(line string) {
	ic.conn.Output <- line
}

func (ic *IRCClient) shutdown() {
	for ic.plugins.Size() != 0 {
		p := ic.plugins.Pop()
		p.Unregister()
	}
}

// Returns a channel on which all plugins will be sent. Use it to iterate over all registered
// plugins.
func (ic *IRCClient) IterPlugins() <-chan Plugin {
	return ic.plugins.Iter()
}

// Returns a channel on which all command handlers will be sent.
func (ic *IRCClient) IterHandlers() <-chan handler {
	ch := make(chan handler, len(ic.handlers))
	go func() {
		for _, e := range ic.handlers {
			ch <- e
		}
		close(ch)
	}()
	return ch
}

// Get the pointer to a specific plugin that has been registered using RegisterPlugin()
// Name is the name the plugin identifies itself with when String() is called on it.
func (ic *IRCClient) GetPlugin(name string) (Plugin, bool) {
	return ic.plugins.GetPlugin(name)
}

// Sends a reply to a parsed message from a user. This is mostly intended for plugins
// and will automatically distinguish between channel and query messages. Note: Notice
// replies will currently be sent to the client using PRIVMSG, this may change in the
// future.
func (ic *IRCClient) Reply(cmd *IRCCommand, message string) {
	var target string
	if cmd.Target != ic.GetStringOption("Server", "nick") {
		target = cmd.Target
	} else {
		target = strings.SplitN(cmd.Source, "!", 2)[0]
	}
	ic.SendLine("PRIVMSG " + target + " :" + message)
}
<commit_msg>wrap GetUsage in ircclient<commit_after>// Package ircclient provides the main interface for library users
// It manages a single connection to the server and the associated
// configuration and plugins.
package ircclient

import (
	"os"
	"log"
	"strings"
	"fmt"
)

type IRCClient struct {
	conn       *ircConn
	plugins    *pluginStack
	handlers   map[string]handler
	disconnect chan bool
}

type handler struct {
	Handler   Plugin
	Command   string
	Minparams int
	Minaccess int
}

// Returns a new IRCClient connection with the given configuration options.
// It will not connect to the given server until Connect() has been called,
// so you can register plugins before connecting
func NewIRCClient(configfile string) *IRCClient {
	c := &IRCClient{nil, newPluginStack(), make(map[string]handler), make(chan bool)}
	c.RegisterPlugin(&basicProtocol{})
	c.RegisterPlugin(NewConfigPlugin(configfile))
	c.RegisterPlugin(new(authPlugin))
	return c
}

// Registers a new plugin. Plugins can be registered at any time, even before
// the actual connection attempt. The plugin's Unregister() function will already
// be called when the connection is lost.
func (ic *IRCClient) RegisterPlugin(p Plugin) os.Error {
	if _, ok := ic.plugins.GetPlugin(p.String()); ok == true {
		return os.NewError("Plugin already exists")
	}
	p.Register(ic)
	ic.plugins.Push(p)
	return nil
}

// Registers a command handler. Plugin callbacks will only be called if
// the command matches. Note that only a single plugin per command may
// be registered. This function is not synchronized, e.g., it shall only
// be called during registration (as Plugin.Register()-calls are currently
// sequential).
func (ic *IRCClient) RegisterCommandHandler(command string, minparams int, minaccess int, plugin Plugin) os.Error {
	if plug, err := ic.handlers[command]; err {
		return os.NewError("Handler is already registered by plugin: " + plug.Handler.String())
	}
	ic.handlers[command] = handler{plugin, command, minparams, minaccess}
	return nil
}

// Gets one of the configuration options stored in the config object. Valid config
// options for section "Server" usually include:
//  - nick
//  - hostport (colon-seperated host and port to connect to)
//  - realname (the real name)
//  - ident
//  - trigger
// All other sections are managed by the library user. Returns an
// empty string if the option is empty, this means: you currently can't
// use empty config values - they will be deemed non-existent!
func (ic *IRCClient) GetStringOption(section, option string) string {
	c, _ := ic.GetPlugin("conf")
	if c == nil {
		log.Fatal("wtf?")
	}
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	retval, _ := cf.Conf.String(section, option)
	cf.Unlock()
	return retval
}

// Sets a single config option. Existing parameters are overriden,
// if necessary, a new config section is automatically added.
func (ic *IRCClient) SetStringOption(section, option, value string) {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	if ! cf.Conf.HasSection(section) {
		cf.Conf.AddSection(section)
	}
	if cf.Conf.HasOption(section, option) {
		cf.Conf.RemoveOption(section, option)
	}
	cf.Conf.AddOption(section, option, value)
	cf.Unlock()
}

// Removes a single config option. Note: This does not delete the section,
// even if it's empty.
func (ic *IRCClient) RemoveOption(section, option string) {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	defer cf.Unlock()

	if ! cf.Conf.HasSection(section) {
		// nothing to do
		return
	}
	cf.Conf.RemoveOption(section, option)
}

// Gets a list of all config keys for a given section. The return value is
// an empty slice if there are no options present _or_ if there is no
// section present. There is currently no way to check whether a section
// exists, it is automatically added when calling one of the SetOption()
// methods.
func (ic *IRCClient) GetOptions(section string) []string {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	defer cf.Unlock()
	opts, err := cf.Conf.Options(section)
	if err != nil {
		return []string{}
	}
	return opts
}

// Does the same as GetStringOption(), but with integers. Returns an os.Error,
// if the given config option does not exist.
func (ic *IRCClient) GetIntOption(section, option string) (int, os.Error) {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	defer cf.Unlock()
	v, err := cf.Conf.Int(section, option)
	if err != nil {
		return -1, err
	}
	return v, nil
}

// See SetStringOption()
func (ic *IRCClient) SetIntOption(section, option string, value int) {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	defer cf.Unlock()
	stropt := fmt.Sprintf("%d", value)
	if ! cf.Conf.HasSection(section) {
		cf.Conf.AddSection(section)
	}
	cf.Conf.AddOption(section, option, stropt)
}

// Gets the highest matching access level for a given hostmask by comparing
// the mask against all authorization entries. Default return value is 0
// (no access).
func (ic *IRCClient) GetAccessLevel(host string) int {
	a, _ := ic.GetPlugin("auth")
	auth, _ := a.(*authPlugin)
	return auth.GetAccessLevel(host)
}

// Sets the access level for the given hostmask to level. Note that host may
// be a regular expression, if exactly the same expression is already present
// in the database, it is overridden.
func (ic *IRCClient) SetAccessLevel(host string, level int) {
	a, _ := ic.GetPlugin("auth")
	auth, _ := a.(*authPlugin)
	auth.SetAccessLevel(host, level )
}

// Delete the given regular expression from auth database. The "host" parameter
// has to be exactly the string stored in the database, otherwise, the command
// will have no effect.
func (ic *IRCClient) DelAccessLevel(host string) {
	a, _ := ic.GetPlugin("auth")
	auth, _ := a.(*authPlugin)
	auth.DelAccessLevel(host)
}

// Connects to the server specified on object creation. If the chosen nickname is
// already in use, it will automatically be suffixed with an single underscore until
// an unused nickname is found. This function blocks until the connection attempt
// has been finished.
func (ic *IRCClient) Connect() os.Error {
	ic.conn = NewircConn()
	e := ic.conn.Connect(ic.GetStringOption("Server", "host"))
	if e != nil {
		return e
	}
	ic.conn.Output <- "NICK " + ic.GetStringOption("Server", "nick")
	ic.conn.Output <- "USER " + ic.GetStringOption("Server", "ident") + " * Q :" + ic.GetStringOption("Server", "realname")
	nick := ic.GetStringOption("Server", "nick")
	for {
		line, ok := <-ic.conn.Input
		if !ok {
			return <-ic.conn.Err
		}

		// Invoke plugin line handlers.
		// At this point, it makes no sense to
		// process "commands". If a plugin needs
		// interaction in this state, it should be
		// low-level.
		s := ParseServerLine(line)
		if s == nil {
			continue
		}
		for p := range ic.plugins.Iter() {
			go p.ProcessLine(s)
		}

		switch s.Command {
		case "433":
			// Nickname already in use
			nick = nick + "_"
			ic.SetStringOption("Server", "nick", nick)
			ic.conn.Output <- "NICK " + nick
		case "001":
			// Successfully registered
			return nil
		}
	}
	return nil
}

func (ic *IRCClient) dispatchHandlers(in string) {
	var c *IRCCommand = nil

	s := ParseServerLine(in)
	if s == nil {
		return
	}
	if (s.Command == "PRIVMSG" || s.Command == "NOTICE") && (s.Target == ic.GetStringOption("Server", "nick") || strings.Index(s.Args[0], ic.GetStringOption("Server", "trigger")) == 0) {
		c = ParseCommand(s)
		// Strip trigger, if necessary
		if c != nil && s.Target != ic.GetStringOption("Server", "nick") && len(c.Command) != 0 {
			c.Command = c.Command[len(ic.GetStringOption("Server", "trigger")):len(c.Command)]
		}
	}

	// Call line handlers
	for p := range ic.plugins.Iter() {
		go p.ProcessLine(s)
	}

	// Call command handler
	if c == nil {
		return
	}
	if handler, err := ic.handlers[c.Command]; err == true {
		// Don't do regexp matching, if we don't need access anyway
		if handler.Minaccess > 0 && ic.GetAccessLevel(c.Source) < handler.Minaccess {
			ic.Reply(c, "You are not authorized to do that.")
			return
		}
		if len(c.Args) < handler.Minparams {
			ic.Reply(c, "This command requires at least " + fmt.Sprintf("%d", handler.Minparams)+" parameters")
			return
		}
		go handler.Handler.ProcessCommand(c)
	}
}

// Starts the actual command processing. This function will block until the connection
// has either been lost or Disconnect() has been called (by a plugin or by the library
// user).
func (ic *IRCClient) InputLoop() os.Error {
	for {
		in, ok := <-ic.conn.Input
		if !ok {
			return <-ic.conn.Err
		}
		ic.dispatchHandlers(in)
	}
	panic("This never happens")
}

// Disconnects from the server with the given quit message. All plugins wil be unregistered
// and pending messages in queue (e.g. because of floodprotection) will be flushed. This will
// also make InputLoop() return.
func (ic *IRCClient) Disconnect(quitmsg string) {
	ic.shutdown()
	ic.conn.Output <- "QUIT :" + quitmsg
	ic.conn.Quit()
}

// Dumps a raw line to the server socket. This is usually called by plugins, but may also
// be used by the library user.
func (ic *IRCClient) SendLine(line string) {
	ic.conn.Output <- line
}

func (ic *IRCClient) shutdown() {
	for ic.plugins.Size() != 0 {
		p := ic.plugins.Pop()
		p.Unregister()
	}
}

// Returns a channel on which all plugins will be sent. Use it to iterate over all registered
// plugins.
func (ic *IRCClient) IterPlugins() <-chan Plugin {
	return ic.plugins.Iter()
}

// Returns a channel on which all command handlers will be sent.
func (ic *IRCClient) IterHandlers() <-chan handler {
	ch := make(chan handler, len(ic.handlers))
	go func() {
		for _, e := range ic.handlers {
			ch <- e
		}
		close(ch)
	}()
	return ch
}

// Get the pointer to a specific plugin that has been registered using RegisterPlugin()
// Name is the name the plugin identifies itself with when String() is called on it.
func (ic *IRCClient) GetPlugin(name string) (Plugin, bool) {
	return ic.plugins.GetPlugin(name)
}

// Get the Usage string from the Plugin that has registered itself as handler for
// the Command cmd. we need to wrap this to ircclient because the handlers are not
// public, and GetPlugin doesn't help us either, because the plugin<->command mapping
// is not known
func (ic *IRCClient) GetUsage(cmd string) string {
	plugin, exists := ic.handlers[cmd]
	if !exists {
		return "no such command"
	}
	return plugin.Usage(cmd)
}

// Sends a reply to a parsed message from a user. This is mostly intended for plugins
// and will automatically distinguish between channel and query messages. Note: Notice
// replies will currently be sent to the client using PRIVMSG, this may change in the
// future.
func (ic *IRCClient) Reply(cmd *IRCCommand, message string) {
	var target string
	if cmd.Target != ic.GetStringOption("Server", "nick") {
		target = cmd.Target
	} else {
		target = strings.SplitN(cmd.Source, "!", 2)[0]
	}
	ic.SendLine("PRIVMSG " + target + " :" + message)
}
<|endoftext|>


<commit_before>package meter2

import (
	"bytes"
	"sync"
)

// Buffer pool for event field building
const minBufferSize = 1024

var bpool = &sync.Pool{
	New: func() interface{} {
		return bytes.NewBuffer(make([]byte, 0, minBufferSize))
	},
}

func bget() *bytes.Buffer {
	return bpool.Get().(*bytes.Buffer)
}
func bput(b *bytes.Buffer) {
	if b == nil || b.Cap() < minBufferSize {
		return
	}
	b.Reset()
	bpool.Put(b)
}
<commit_msg>Remve unused code<commit_after><|endoftext|>


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

// Checking of compiler and linker flags.
// We must avoid flags like -fplugin=, which can allow
// arbitrary code execution during the build.
// Do not make changes here without carefully
// considering the implications.
// (That's why the code is isolated in a file named security.go.)
//
// Note that -Wl,foo means split foo on commas and pass to
// the linker, so that -Wl,-foo,bar means pass -foo bar to
// the linker. Similarly -Wa,foo for the assembler and so on.
// If any of these are permitted, the wildcard portion must
// disallow commas.
//
// Note also that GNU binutils accept any argument @foo
// as meaning "read more flags from the file foo", so we must
// guard against any command-line argument beginning with @,
// even things like "-I @foo".
// We use load.SafeArg (which is even more conservative)
// to reject these.
//
// Even worse, gcc -I@foo (one arg) turns into cc1 -I @foo (two args),
// so although gcc doesn't expand the @foo, cc1 will.
// So out of paranoia, we reject @ at the beginning of every
// flag argument that might be split into its own argument.

package work

import (
	"cmd/go/internal/load"
	"fmt"
	"os"
	"regexp"
	"strings"
)

var re = regexp.MustCompile

var validCompilerFlags = []*regexp.Regexp{
	re(`-D([A-Za-z_].*)`),
	re(`-F([^@\-].*)`),
	re(`-I([^@\-].*)`),
	re(`-O`),
	re(`-O([^@\-].*)`),
	re(`-W`),
	re(`-W([^@,]+)`), // -Wall but not -Wa,-foo.
	re(`-Wa,-mbig-obj`),
	re(`-Wp,-D([A-Za-z_].*)`),
	re(`-ansi`),
	re(`-f(no-)?asynchronous-unwind-tables`),
	re(`-f(no-)?blocks`),
	re(`-f(no-)builtin-[a-zA-Z0-9_]*`),
	re(`-f(no-)?common`),
	re(`-f(no-)?constant-cfstrings`),
	re(`-fdiagnostics-show-note-include-stack`),
	re(`-f(no-)?eliminate-unused-debug-types`),
	re(`-f(no-)?exceptions`),
	re(`-f(no-)?fast-math`),
	re(`-f(no-)?inline-functions`),
	re(`-finput-charset=([^@\-].*)`),
	re(`-f(no-)?fat-lto-objects`),
	re(`-f(no-)?keep-inline-dllexport`),
	re(`-f(no-)?lto`),
	re(`-fmacro-backtrace-limit=(.+)`),
	re(`-fmessage-length=(.+)`),
	re(`-f(no-)?modules`),
	re(`-f(no-)?objc-arc`),
	re(`-f(no-)?objc-nonfragile-abi`),
	re(`-f(no-)?objc-legacy-dispatch`),
	re(`-f(no-)?omit-frame-pointer`),
	re(`-f(no-)?openmp(-simd)?`),
	re(`-f(no-)?permissive`),
	re(`-f(no-)?(pic|PIC|pie|PIE)`),
	re(`-f(no-)?plt`),
	re(`-f(no-)?rtti`),
	re(`-f(no-)?split-stack`),
	re(`-f(no-)?stack-(.+)`),
	re(`-f(no-)?strict-aliasing`),
	re(`-f(un)signed-char`),
	re(`-f(no-)?use-linker-plugin`), // safe if -B is not used; we don't permit -B
	re(`-f(no-)?visibility-inlines-hidden`),
	re(`-fsanitize=(.+)`),
	re(`-ftemplate-depth-(.+)`),
	re(`-fvisibility=(.+)`),
	re(`-g([^@\-].*)?`),
	re(`-m32`),
	re(`-m64`),
	re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`),
	re(`-marm`),
	re(`-mfloat-abi=([^@\-].*)`),
	re(`-mfpmath=[0-9a-z,+]*`),
	re(`-m(no-)?avx[0-9a-z.]*`),
	re(`-m(no-)?ms-bitfields`),
	re(`-m(no-)?stack-(.+)`),
	re(`-mmacosx-(.+)`),
	re(`-mios-simulator-version-min=(.+)`),
	re(`-miphoneos-version-min=(.+)`),
	re(`-mnop-fun-dllimport`),
	re(`-m(no-)?sse[0-9.]*`),
	re(`-mthumb(-interwork)?`),
	re(`-mthreads`),
	re(`-mwindows`),
	re(`--param=ssp-buffer-size=[0-9]*`),
	re(`-pedantic(-errors)?`),
	re(`-pipe`),
	re(`-pthread`),
	re(`-?-std=([^@\-].*)`),
	re(`-?-stdlib=([^@\-].*)`),
	re(`--sysroot=([^@\-].*)`),
	re(`-w`),
	re(`-x([^@\-].*)`),
	re(`-v`),
}

var validCompilerFlagsWithNextArg = []string{
	"-arch",
	"-D",
	"-I",
	"-framework",
	"-isysroot",
	"-isystem",
	"--sysroot",
	"-target",
	"-x",
}

var validLinkerFlags = []*regexp.Regexp{
	re(`-F([^@\-].*)`),
	re(`-l([^@\-].*)`),
	re(`-L([^@\-].*)`),
	re(`-O`),
	re(`-O([^@\-].*)`),
	re(`-f(no-)?(pic|PIC|pie|PIE)`),
	re(`-f(no-)?openmp(-simd)?`),
	re(`-fsanitize=([^@\-].*)`),
	re(`-g([^@\-].*)?`),
	re(`-headerpad_max_install_names`),
	re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`),
	re(`-mfloat-abi=([^@\-].*)`),
	re(`-mmacosx-(.+)`),
	re(`-mios-simulator-version-min=(.+)`),
	re(`-miphoneos-version-min=(.+)`),
	re(`-mthreads`),
	re(`-mwindows`),
	re(`-(pic|PIC|pie|PIE)`),
	re(`-pthread`),
	re(`-rdynamic`),
	re(`-shared`),
	re(`-?-static([-a-z0-9+]*)`),
	re(`-?-stdlib=([^@\-].*)`),
	re(`-v`),

	// Note that any wildcards in -Wl need to exclude comma,
	// since -Wl splits its argument at commas and passes
	// them all to the linker uninterpreted. Allowing comma
	// in a wildcard would allow tunnelling arbitrary additional
	// linker arguments through one of these.
	re(`-Wl,--(no-)?allow-multiple-definition`),
	re(`-Wl,--(no-)?allow-shlib-undefined`),
	re(`-Wl,--(no-)?as-needed`),
	re(`-Wl,-Bdynamic`),
	re(`-Wl,-Bstatic`),
	re(`-WL,-O([^@,\-][^,]*)?`),
	re(`-Wl,-d[ny]`),
	re(`-Wl,--disable-new-dtags`),
	re(`-Wl,-e[=,][a-zA-Z0-9]*`),
	re(`-Wl,--enable-new-dtags`),
	re(`-Wl,--end-group`),
	re(`-Wl,-framework,[^,@\-][^,]+`),
	re(`-Wl,-headerpad_max_install_names`),
	re(`-Wl,--no-undefined`),
	re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]+)`),
	re(`-Wl,-s`),
	re(`-Wl,-search_paths_first`),
	re(`-Wl,-sectcreate,([^,@\-][^,]+),([^,@\-][^,]+),([^,@\-][^,]+)`),
	re(`-Wl,--start-group`),
	re(`-Wl,-?-static`),
	re(`-Wl,-?-subsystem,(native|windows|console|posix|xbox)`),
	re(`-Wl,-syslibroot[=,]([^,@\-][^,]+)`),
	re(`-Wl,-undefined[=,]([^,@\-][^,]+)`),
	re(`-Wl,-?-unresolved-symbols=[^,]+`),
	re(`-Wl,--(no-)?warn-([^,]+)`),
	re(`-Wl,-z,(no)?execstack`),
	re(`-Wl,-z,relro`),

	re(`[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
	re(`\./.*\.(a|o|obj|dll|dylib|so)`),
}

var validLinkerFlagsWithNextArg = []string{
	"-arch",
	"-F",
	"-l",
	"-L",
	"-framework",
	"-isysroot",
	"--sysroot",
	"-target",
	"-Wl,-framework",
	"-Wl,-rpath",
	"-Wl,-undefined",
}

func checkCompilerFlags(name, source string, list []string) error {
	return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg)
}

func checkLinkerFlags(name, source string, list []string) error {
	return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg)
}

func checkFlags(name, source string, list []string, valid []*regexp.Regexp, validNext []string) error {
	// Let users override rules with $CGO_CFLAGS_ALLOW, $CGO_CFLAGS_DISALLOW, etc.
	var (
		allow    *regexp.Regexp
		disallow *regexp.Regexp
	)
	if env := os.Getenv("CGO_" + name + "_ALLOW"); env != "" {
		r, err := regexp.Compile(env)
		if err != nil {
			return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err)
		}
		allow = r
	}
	if env := os.Getenv("CGO_" + name + "_DISALLOW"); env != "" {
		r, err := regexp.Compile(env)
		if err != nil {
			return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err)
		}
		disallow = r
	}

Args:
	for i := 0; i < len(list); i++ {
		arg := list[i]
		if disallow != nil && disallow.FindString(arg) == arg {
			goto Bad
		}
		if allow != nil && allow.FindString(arg) == arg {
			continue Args
		}
		for _, re := range valid {
			if re.FindString(arg) == arg { // must be complete match
				continue Args
			}
		}
		for _, x := range validNext {
			if arg == x {
				if i+1 < len(list) && load.SafeArg(list[i+1]) {
					i++
					continue Args
				}

				// Permit -Wl,-framework -Wl,name.
				if i+1 < len(list) &&
					strings.HasPrefix(arg, "-Wl,") &&
					strings.HasPrefix(list[i+1], "-Wl,") &&
					load.SafeArg(list[i+1][4:]) &&
					!strings.Contains(list[i+1][4:], ",") {
					i++
					continue Args
				}

				if i+1 < len(list) {
					return fmt.Errorf("invalid flag in %s: %s %s (see https://golang.org/s/invalidflag)", source, arg, list[i+1])
				}
				return fmt.Errorf("invalid flag in %s: %s without argument (see https://golang.org/s/invalidflag)", source, arg)
			}
		}
	Bad:
		return fmt.Errorf("invalid flag in %s: %s", source, arg)
	}
	return nil
}
<commit_msg>cmd/go: add -flat_namespace to LDFLAGS whitelist<commit_after>// Copyright 2018 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.

// Checking of compiler and linker flags.
// We must avoid flags like -fplugin=, which can allow
// arbitrary code execution during the build.
// Do not make changes here without carefully
// considering the implications.
// (That's why the code is isolated in a file named security.go.)
//
// Note that -Wl,foo means split foo on commas and pass to
// the linker, so that -Wl,-foo,bar means pass -foo bar to
// the linker. Similarly -Wa,foo for the assembler and so on.
// If any of these are permitted, the wildcard portion must
// disallow commas.
//
// Note also that GNU binutils accept any argument @foo
// as meaning "read more flags from the file foo", so we must
// guard against any command-line argument beginning with @,
// even things like "-I @foo".
// We use load.SafeArg (which is even more conservative)
// to reject these.
//
// Even worse, gcc -I@foo (one arg) turns into cc1 -I @foo (two args),
// so although gcc doesn't expand the @foo, cc1 will.
// So out of paranoia, we reject @ at the beginning of every
// flag argument that might be split into its own argument.

package work

import (
	"cmd/go/internal/load"
	"fmt"
	"os"
	"regexp"
	"strings"
)

var re = regexp.MustCompile

var validCompilerFlags = []*regexp.Regexp{
	re(`-D([A-Za-z_].*)`),
	re(`-F([^@\-].*)`),
	re(`-I([^@\-].*)`),
	re(`-O`),
	re(`-O([^@\-].*)`),
	re(`-W`),
	re(`-W([^@,]+)`), // -Wall but not -Wa,-foo.
	re(`-Wa,-mbig-obj`),
	re(`-Wp,-D([A-Za-z_].*)`),
	re(`-ansi`),
	re(`-f(no-)?asynchronous-unwind-tables`),
	re(`-f(no-)?blocks`),
	re(`-f(no-)builtin-[a-zA-Z0-9_]*`),
	re(`-f(no-)?common`),
	re(`-f(no-)?constant-cfstrings`),
	re(`-fdiagnostics-show-note-include-stack`),
	re(`-f(no-)?eliminate-unused-debug-types`),
	re(`-f(no-)?exceptions`),
	re(`-f(no-)?fast-math`),
	re(`-f(no-)?inline-functions`),
	re(`-finput-charset=([^@\-].*)`),
	re(`-f(no-)?fat-lto-objects`),
	re(`-f(no-)?keep-inline-dllexport`),
	re(`-f(no-)?lto`),
	re(`-fmacro-backtrace-limit=(.+)`),
	re(`-fmessage-length=(.+)`),
	re(`-f(no-)?modules`),
	re(`-f(no-)?objc-arc`),
	re(`-f(no-)?objc-nonfragile-abi`),
	re(`-f(no-)?objc-legacy-dispatch`),
	re(`-f(no-)?omit-frame-pointer`),
	re(`-f(no-)?openmp(-simd)?`),
	re(`-f(no-)?permissive`),
	re(`-f(no-)?(pic|PIC|pie|PIE)`),
	re(`-f(no-)?plt`),
	re(`-f(no-)?rtti`),
	re(`-f(no-)?split-stack`),
	re(`-f(no-)?stack-(.+)`),
	re(`-f(no-)?strict-aliasing`),
	re(`-f(un)signed-char`),
	re(`-f(no-)?use-linker-plugin`), // safe if -B is not used; we don't permit -B
	re(`-f(no-)?visibility-inlines-hidden`),
	re(`-fsanitize=(.+)`),
	re(`-ftemplate-depth-(.+)`),
	re(`-fvisibility=(.+)`),
	re(`-g([^@\-].*)?`),
	re(`-m32`),
	re(`-m64`),
	re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`),
	re(`-marm`),
	re(`-mfloat-abi=([^@\-].*)`),
	re(`-mfpmath=[0-9a-z,+]*`),
	re(`-m(no-)?avx[0-9a-z.]*`),
	re(`-m(no-)?ms-bitfields`),
	re(`-m(no-)?stack-(.+)`),
	re(`-mmacosx-(.+)`),
	re(`-mios-simulator-version-min=(.+)`),
	re(`-miphoneos-version-min=(.+)`),
	re(`-mnop-fun-dllimport`),
	re(`-m(no-)?sse[0-9.]*`),
	re(`-mthumb(-interwork)?`),
	re(`-mthreads`),
	re(`-mwindows`),
	re(`--param=ssp-buffer-size=[0-9]*`),
	re(`-pedantic(-errors)?`),
	re(`-pipe`),
	re(`-pthread`),
	re(`-?-std=([^@\-].*)`),
	re(`-?-stdlib=([^@\-].*)`),
	re(`--sysroot=([^@\-].*)`),
	re(`-w`),
	re(`-x([^@\-].*)`),
	re(`-v`),
}

var validCompilerFlagsWithNextArg = []string{
	"-arch",
	"-D",
	"-I",
	"-framework",
	"-isysroot",
	"-isystem",
	"--sysroot",
	"-target",
	"-x",
}

var validLinkerFlags = []*regexp.Regexp{
	re(`-F([^@\-].*)`),
	re(`-l([^@\-].*)`),
	re(`-L([^@\-].*)`),
	re(`-O`),
	re(`-O([^@\-].*)`),
	re(`-f(no-)?(pic|PIC|pie|PIE)`),
	re(`-f(no-)?openmp(-simd)?`),
	re(`-fsanitize=([^@\-].*)`),
	re(`-flat_namespace`),
	re(`-g([^@\-].*)?`),
	re(`-headerpad_max_install_names`),
	re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`),
	re(`-mfloat-abi=([^@\-].*)`),
	re(`-mmacosx-(.+)`),
	re(`-mios-simulator-version-min=(.+)`),
	re(`-miphoneos-version-min=(.+)`),
	re(`-mthreads`),
	re(`-mwindows`),
	re(`-(pic|PIC|pie|PIE)`),
	re(`-pthread`),
	re(`-rdynamic`),
	re(`-shared`),
	re(`-?-static([-a-z0-9+]*)`),
	re(`-?-stdlib=([^@\-].*)`),
	re(`-v`),

	// Note that any wildcards in -Wl need to exclude comma,
	// since -Wl splits its argument at commas and passes
	// them all to the linker uninterpreted. Allowing comma
	// in a wildcard would allow tunnelling arbitrary additional
	// linker arguments through one of these.
	re(`-Wl,--(no-)?allow-multiple-definition`),
	re(`-Wl,--(no-)?allow-shlib-undefined`),
	re(`-Wl,--(no-)?as-needed`),
	re(`-Wl,-Bdynamic`),
	re(`-Wl,-Bstatic`),
	re(`-WL,-O([^@,\-][^,]*)?`),
	re(`-Wl,-d[ny]`),
	re(`-Wl,--disable-new-dtags`),
	re(`-Wl,-e[=,][a-zA-Z0-9]*`),
	re(`-Wl,--enable-new-dtags`),
	re(`-Wl,--end-group`),
	re(`-Wl,-framework,[^,@\-][^,]+`),
	re(`-Wl,-headerpad_max_install_names`),
	re(`-Wl,--no-undefined`),
	re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]+)`),
	re(`-Wl,-s`),
	re(`-Wl,-search_paths_first`),
	re(`-Wl,-sectcreate,([^,@\-][^,]+),([^,@\-][^,]+),([^,@\-][^,]+)`),
	re(`-Wl,--start-group`),
	re(`-Wl,-?-static`),
	re(`-Wl,-?-subsystem,(native|windows|console|posix|xbox)`),
	re(`-Wl,-syslibroot[=,]([^,@\-][^,]+)`),
	re(`-Wl,-undefined[=,]([^,@\-][^,]+)`),
	re(`-Wl,-?-unresolved-symbols=[^,]+`),
	re(`-Wl,--(no-)?warn-([^,]+)`),
	re(`-Wl,-z,(no)?execstack`),
	re(`-Wl,-z,relro`),

	re(`[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
	re(`\./.*\.(a|o|obj|dll|dylib|so)`),
}

var validLinkerFlagsWithNextArg = []string{
	"-arch",
	"-F",
	"-l",
	"-L",
	"-framework",
	"-isysroot",
	"--sysroot",
	"-target",
	"-Wl,-framework",
	"-Wl,-rpath",
	"-Wl,-undefined",
}

func checkCompilerFlags(name, source string, list []string) error {
	return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg)
}

func checkLinkerFlags(name, source string, list []string) error {
	return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg)
}

func checkFlags(name, source string, list []string, valid []*regexp.Regexp, validNext []string) error {
	// Let users override rules with $CGO_CFLAGS_ALLOW, $CGO_CFLAGS_DISALLOW, etc.
	var (
		allow    *regexp.Regexp
		disallow *regexp.Regexp
	)
	if env := os.Getenv("CGO_" + name + "_ALLOW"); env != "" {
		r, err := regexp.Compile(env)
		if err != nil {
			return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err)
		}
		allow = r
	}
	if env := os.Getenv("CGO_" + name + "_DISALLOW"); env != "" {
		r, err := regexp.Compile(env)
		if err != nil {
			return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err)
		}
		disallow = r
	}

Args:
	for i := 0; i < len(list); i++ {
		arg := list[i]
		if disallow != nil && disallow.FindString(arg) == arg {
			goto Bad
		}
		if allow != nil && allow.FindString(arg) == arg {
			continue Args
		}
		for _, re := range valid {
			if re.FindString(arg) == arg { // must be complete match
				continue Args
			}
		}
		for _, x := range validNext {
			if arg == x {
				if i+1 < len(list) && load.SafeArg(list[i+1]) {
					i++
					continue Args
				}

				// Permit -Wl,-framework -Wl,name.
				if i+1 < len(list) &&
					strings.HasPrefix(arg, "-Wl,") &&
					strings.HasPrefix(list[i+1], "-Wl,") &&
					load.SafeArg(list[i+1][4:]) &&
					!strings.Contains(list[i+1][4:], ",") {
					i++
					continue Args
				}

				if i+1 < len(list) {
					return fmt.Errorf("invalid flag in %s: %s %s (see https://golang.org/s/invalidflag)", source, arg, list[i+1])
				}
				return fmt.Errorf("invalid flag in %s: %s without argument (see https://golang.org/s/invalidflag)", source, arg)
			}
		}
	Bad:
		return fmt.Errorf("invalid flag in %s: %s", source, arg)
	}
	return nil
}
<|endoftext|>


<commit_before>// Quick and dirty uploader and serial terminal for LPC8xx chips.
// -jcw, 2015-02-02

package main

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"

	"github.com/chimera/rs232"
	"golang.org/x/crypto/ssh/terminal"
)

var (
	offsetFlag = flag.Int("o", 0, "upload offset (must be multiple of 1024)")
	serialFlag = flag.Bool("s", false, "launch as serial terminal after upload")
	waitFlag   = flag.Bool("w", false, "wait for connection to the boot loader")
	idleFlag   = flag.Int("i", 0, "exit terminal after N idle seconds (0: off)")
	telnetFlag = flag.Bool("t", false, "use telnet protocol for RTS & DTR")
)

var chipInfo = map[int]string{
	0x8100: "- LPC810: 4 KB flash, 1 KB RAM, DIP8",
	0x8110: "- LPC811: 8 KB flash, 2 KB RAM, TSSOP16",
	0x8120: "- LPC812: 16 KB flash, 4 KB RAM, TSSOP16",
	0x8121: "- LPC812: 16 KB flash, 4 KB RAM, SO20",
	0x8122: "- LPC812: 16 KB flash, 4 KB RAM, TSSOP20",
	0x8221: "- LPC822: 16 KB flash, 4 KB RAM, HVQFN33",
	0x8222: "- LPC822: 16 KB flash, 4 KB RAM, TSSOP20",
	0x8241: "- LPC824: 32 KB flash, 8 KB RAM, HVQFN33",
	0x8242: "- LPC824: 32 KB flash, 8 KB RAM, TSSOP20",
}

func main() {
	log.SetFlags(0) // no timestamps

	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, "Usage: lpc8xx ?options? tty ?binfile?")
		flag.PrintDefaults()
	}

	flag.Parse()

	if flag.NArg() < 1 {
		flag.Usage()
		os.Exit(2)
	}

	ttyName := flag.Arg(0)
	binFile := ""
	if flag.NArg() > 1 {
		binFile = flag.Arg(1)
	}

	conn := connect(ttyName)

	id := conn.Identify()
	info, _ := chipInfo[id]
	fmt.Printf("found: %X %s\n", id, info)

	conn.SendAndWait("N", "0")
	buf := bytes.NewBuffer([]byte{})

	for i := 0; i < 4; i++ {
		b, err := strconv.ParseUint(<-conn.lines, 10, 32)
		Check(err)
		binary.Write(buf, binary.LittleEndian, uint32(b))
	}
	fmt.Printf("hwuid: %X\n", buf.Bytes())

	if binFile != "" {
		data, err := ioutil.ReadFile(binFile)
		Check(err)

		fmt.Print("flash: 0000 ")
		for n := range conn.Program(*offsetFlag, data) {
			fmt.Printf("\b\b\b\b\b%04X ", n)
		}
		fmt.Println("done,", len(data), "bytes")
	}

	conn.serial.SetDTR(true) // pulse DTR to reset
	conn.serial.SetDTR(false)

	if *serialFlag {
		fmt.Println("entering terminal mode, press <ESC> to quit:\n")
		conn.Terminal()
		fmt.Println()
	}
}

func connect(port string) *connection {
	var dev serialLink

	if _, err := os.Stat(port); os.IsExist(err) {
		// if the tty is an existing device, open as rs232 port
		opt := rs232.Options{BitRate: 115200, DataBits: 8, StopBits: 1}
		dev, err = rs232.Open(port, opt)
		Check(err)
	} else {
		// else assume it's an ip address + port and open as network port
		sock, err := net.Dial("tcp", port)
		Check(err)
		dev = &rawnet{sock} // RTS and DTR are ignored unless telnet is used
	}

	if *telnetFlag {
		dev = wrapAsTelnet(dev)
	}

	// the rest of the code is identical for either case
	// everything is abstracted away behind the "serialLink" interface
	conn := &connection{dev, make(chan string)}
	go func() {
		scanner := bufio.NewScanner(dev)
		for scanner.Scan() {
			conn.lines <- scanner.Text()
		}
		close(conn.lines)
	}()
	return conn
}

// a serialLink can read and write bytes, and set the DTR and RTS levels
type serialLink interface {
	io.ReadWriter
	SetDTR(level bool) error
	SetRTS(level bool) error
}

// rawnet objects use a network connection as is, no signalling
type rawnet struct {
	sock net.Conn
}

func (c *rawnet) SetDTR(level bool) error {
	return nil
}

func (c *rawnet) SetRTS(level bool) error {
	return nil
}

func (c *rawnet) Read(buf []byte) (n int, err error) {
	return c.sock.Read(buf)
}

func (c *rawnet) Write(buf []byte) (int, error) {
	return c.sock.Write(buf)
}

func wrapAsTelnet(s serialLink) serialLink {
	return &telnetWrapper{upLink: s, inState: 0}
}

// telnetWrapper turns RTS/DTR signals into in-band telnet requests
type telnetWrapper struct {
	upLink  serialLink
	inState int
}

const (
	Iac = 255
	Sb  = 250
	Se  = 240

	ComPortOpt = 44
	SetControl = 5
)

func (c *telnetWrapper) SetDTR(level bool) error {
	return c.sendEscape(level, 8, 9)
}

func (c *telnetWrapper) SetRTS(level bool) error {
	return c.sendEscape(level, 11, 12)
}

func (c *telnetWrapper) sendEscape(flag bool, yes, no uint8) error {
	b := no
	if flag {
		b = yes
	}

	_, err := c.upLink.Write([]byte{Iac, Sb, ComPortOpt, SetControl, b, Iac, Se})
	return err
}

func (c *telnetWrapper) Read(buf []byte) (n int, err error) {
	j := 0
	for {
		n, err := c.upLink.Read(buf)
		if err != nil {
			return n, err
		}
		for i := 0; i < n; i++ {
			b := buf[i]
			buf[j] = b
			switch c.inState {
			case 0: // normal, copying
				if b == Iac {
					c.inState = 1
				} else {
					j++
				}
			case 1: // seen Iac
				if b == Sb {
					c.inState = 2
				} else {
					j++
					c.inState = 0
				}
			case 2: // inside command
				if b == Iac {
					c.inState = 3
				}
			case 3: // inside command, see Iac
				if b == Se {
					c.inState = 0
				} else {
					c.inState = 2
				}
			}
		}
		if j > 0 {
			break
		}
	}
	return j, nil
}

func (c *telnetWrapper) Write(buf []byte) (int, error) {
	wrapped := bytes.Replace(buf, []byte{0xFF}, []byte{0xFF, 0xFF}, -1)
	// FIXME returned count is wrong
	return c.upLink.Write(wrapped)
}

type connection struct {
	serial serialLink
	lines  chan string
}

func (c *connection) ReadReply() string {
	select {
	case reply := <-c.lines:
		return reply
	case <-time.After(250 * time.Millisecond):
		return ""
	}
}

func (c *connection) SendAndWait(cmd string, expect string) {
	c.serial.Write([]byte(cmd + "\r\n"))
	var reply string
	for i := 0; i < 4; i++ {
		reply = c.ReadReply()
		if reply == "" {
			log.Fatal("no response, timeout")
		}
		if reply == expect {
			return
		}
	}
	log.Fatal(reply)
}

func (c *connection) Identify() int {
	c.serial.SetRTS(true) // keep RTS on for ISP mode

	for {
		c.serial.SetDTR(true) // pulse DTR to reset
		for c.ReadReply() != "" {
			// flush
		}
		c.serial.SetDTR(false)

		c.serial.Write([]byte("?\r\n"))
		if c.ReadReply() == "Synchronized" || !*waitFlag {
			break
		}
	}

	c.serial.SetRTS(false)

	c.SendAndWait("Synchronized", "OK")
	c.SendAndWait("12000", "OK")
	c.SendAndWait("A 0", "0")

	c.SendAndWait("J", "0")
	id, err := strconv.Atoi(c.ReadReply())
	Check(err)

	return id
}

func (c *connection) Program(startAddress int, data []byte) chan int {
	const sectorSize = 1024
	const pageSize = 64

	for len(data)%pageSize != 0 {
		data = append(data, 0xFF)
	}
	firstPage := startAddress / pageSize
	lastPage := firstPage + len(data)/pageSize - 1

	for len(data)%sectorSize != 0 {
		data = append(data, 0xFF)
	}
	firstSector := startAddress / sectorSize
	lastSector := firstSector + len(data)/sectorSize - 1

	if startAddress == 0 {
		fixChecksum(data)
	}

	c.SendAndWait("U 23130", "0") // unlock for programming

	// erase entire range, as 1024-byte sectors
	c.SendAndWait(fmt.Sprint("P ", firstSector, lastSector), "0") // prepare
	c.SendAndWait(fmt.Sprint("E ", firstSector, lastSector), "0") // erase

	r := make(chan int)
	go func() {
		defer close(r)
		// program in 64-byte pages (sectors won't fit in the LPC810's RAM)
		for page := firstPage; page <= lastPage; page++ {
			const RAM_ADDR = 0x10000300
			// write one page of data to RAM
			offset := (page - firstPage) * pageSize
			c.SendAndWait(fmt.Sprint("W ", RAM_ADDR, pageSize), "0")
			c.serial.Write(data[offset : offset+pageSize])
			// prepare and copy the data to flash memory
			sector := (page * pageSize) / sectorSize
			c.SendAndWait(fmt.Sprint("P ", sector, sector), "0")
			destAddr := page * pageSize
			c.SendAndWait(fmt.Sprint("C ", destAddr, RAM_ADDR, pageSize), "0")
			r <- pageSize * (page - firstPage + 1)
		}
	}()
	return r
}

// fix the checksum to mark code as valid (see UM10398, p.416)
func fixChecksum(data []byte) {
	buf := bytes.NewReader(data)
	values := [7]uint32{}
	err := binary.Read(buf, binary.LittleEndian, values[:])
	Check(err)
	var sum uint32
	for _, v := range values {
		sum -= v
	}
	data[28] = byte(sum)
	data[29] = byte(sum >> 8)
	data[30] = byte(sum >> 16)
	data[31] = byte(sum >> 24)
}

func (c *connection) Terminal() {
	timeout := time.Duration(*idleFlag) * time.Second
	idleTimer := time.NewTimer(timeout)

	// FIXME still in line mode, so only complete lines will be shown
	//  look into bufio.Reader for a possible solution
	go func() {
		for s := range c.lines {
			idleTimer.Reset(timeout)
			fmt.Println(s)
		}
	}()

	// put stdin in raw mode
	oldState, err := terminal.MakeRaw(0)
	Check(err)
	defer terminal.Restore(0, oldState)

	// cleanup when program is terminated via a signal
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, os.Interrupt, syscall.SIGHUP, syscall.SIGTERM)
	go func() {
		sigMsg := <-sigChan
		terminal.Restore(0, oldState)
		log.Fatal(sigMsg)
	}()

	// cleanup when idle timer fires, and exit cleanly
	if *idleFlag > 0 {
		go func() {
			<-idleTimer.C
			terminal.Restore(0, oldState)
			fmt.Println("\nidle timeout")
			os.Exit(0)
		}()
	}

	// copy key presses to the serial port
	for {
		var b [1]byte
		n, _ := os.Stdin.Read(b[:])
		idleTimer.Reset(timeout)
		if n < 1 || b[0] == 0x1B { // ESC
			break
		}
		c.serial.Write(b[:n])
	}

}

func Check(e error) {
	if e != nil {
		log.Fatal(e)
	}
}
<commit_msg>tweak back again<commit_after>// Quick and dirty uploader and serial terminal for LPC8xx chips.
// -jcw, 2015-02-02

package main

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"

	"github.com/chimera/rs232"
	"golang.org/x/crypto/ssh/terminal"
)

var (
	offsetFlag = flag.Int("o", 0, "upload offset (must be multiple of 1024)")
	serialFlag = flag.Bool("s", false, "launch as serial terminal after upload")
	waitFlag   = flag.Bool("w", false, "wait for connection to the boot loader")
	idleFlag   = flag.Int("i", 0, "exit terminal after N idle seconds (0: off)")
	telnetFlag = flag.Bool("t", false, "use telnet protocol for RTS & DTR")
)

var chipInfo = map[int]string{
	0x8100: "- LPC810: 4 KB flash, 1 KB RAM, DIP8",
	0x8110: "- LPC811: 8 KB flash, 2 KB RAM, TSSOP16",
	0x8120: "- LPC812: 16 KB flash, 4 KB RAM, TSSOP16",
	0x8121: "- LPC812: 16 KB flash, 4 KB RAM, SO20",
	0x8122: "- LPC812: 16 KB flash, 4 KB RAM, TSSOP20",
	0x8221: "- LPC822: 16 KB flash, 4 KB RAM, HVQFN33",
	0x8222: "- LPC822: 16 KB flash, 4 KB RAM, TSSOP20",
	0x8241: "- LPC824: 32 KB flash, 8 KB RAM, HVQFN33",
	0x8242: "- LPC824: 32 KB flash, 8 KB RAM, TSSOP20",
}

func main() {
	log.SetFlags(0) // no timestamps

	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, "Usage: lpc8xx ?options? tty ?binfile?")
		flag.PrintDefaults()
	}

	flag.Parse()

	if flag.NArg() < 1 {
		flag.Usage()
		os.Exit(2)
	}

	ttyName := flag.Arg(0)
	binFile := ""
	if flag.NArg() > 1 {
		binFile = flag.Arg(1)
	}

	conn := connect(ttyName)

	id := conn.Identify()
	info, _ := chipInfo[id]
	fmt.Printf("found: %X %s\n", id, info)

	conn.SendAndWait("N", "0")
	buf := bytes.NewBuffer([]byte{})

	for i := 0; i < 4; i++ {
		b, err := strconv.ParseUint(<-conn.lines, 10, 32)
		Check(err)
		binary.Write(buf, binary.LittleEndian, uint32(b))
	}
	fmt.Printf("hwuid: %X\n", buf.Bytes())

	if binFile != "" {
		data, err := ioutil.ReadFile(binFile)
		Check(err)

		fmt.Print("flash: 0000 ")
		for n := range conn.Program(*offsetFlag, data) {
			fmt.Printf("\b\b\b\b\b%04X ", n)
		}
		fmt.Println("done,", len(data), "bytes")
	}

	conn.serial.SetDTR(true) // pulse DTR to reset
	conn.serial.SetDTR(false)

	if *serialFlag {
		fmt.Println("entering terminal mode, press <ESC> to quit:\n")
		conn.Terminal()
		fmt.Println()
	}
}

func connect(port string) *connection {
	var dev serialLink

	if _, err := os.Stat(port); os.IsNotExist(err) {
		// if nonexistent, it's an ip address + port and open as network port
		sock, err := net.Dial("tcp", port)
		Check(err)
		dev = &rawnet{sock} // RTS and DTR are ignored unless telnet is used
	} else {
		// else assume the tty is an existing device, open as rs232 port
		opt := rs232.Options{BitRate: 115200, DataBits: 8, StopBits: 1}
		dev, err = rs232.Open(port, opt)
		Check(err)
	}

	if *telnetFlag {
		dev = wrapAsTelnet(dev)
	}

	// the rest of the code is identical for either case
	// everything is abstracted away behind the "serialLink" interface
	conn := &connection{dev, make(chan string)}
	go func() {
		scanner := bufio.NewScanner(dev)
		for scanner.Scan() {
			conn.lines <- scanner.Text()
		}
		close(conn.lines)
	}()
	return conn
}

// a serialLink can read and write bytes, and set the DTR and RTS levels
type serialLink interface {
	io.ReadWriter
	SetDTR(level bool) error
	SetRTS(level bool) error
}

// rawnet objects use a network connection as is, no signalling
type rawnet struct {
	sock net.Conn
}

func (c *rawnet) SetDTR(level bool) error {
	return nil
}

func (c *rawnet) SetRTS(level bool) error {
	return nil
}

func (c *rawnet) Read(buf []byte) (n int, err error) {
	return c.sock.Read(buf)
}

func (c *rawnet) Write(buf []byte) (int, error) {
	return c.sock.Write(buf)
}

func wrapAsTelnet(s serialLink) serialLink {
	return &telnetWrapper{upLink: s, inState: 0}
}

// telnetWrapper turns RTS/DTR signals into in-band telnet requests
type telnetWrapper struct {
	upLink  serialLink
	inState int
}

const (
	Iac = 255
	Sb  = 250
	Se  = 240

	ComPortOpt = 44
	SetControl = 5
)

func (c *telnetWrapper) SetDTR(level bool) error {
	return c.sendEscape(level, 8, 9)
}

func (c *telnetWrapper) SetRTS(level bool) error {
	return c.sendEscape(level, 11, 12)
}

func (c *telnetWrapper) sendEscape(flag bool, yes, no uint8) error {
	b := no
	if flag {
		b = yes
	}

	_, err := c.upLink.Write([]byte{Iac, Sb, ComPortOpt, SetControl, b, Iac, Se})
	return err
}

func (c *telnetWrapper) Read(buf []byte) (n int, err error) {
	j := 0
	for {
		n, err := c.upLink.Read(buf)
		if err != nil {
			return n, err
		}
		for i := 0; i < n; i++ {
			b := buf[i]
			buf[j] = b
			switch c.inState {
			case 0: // normal, copying
				if b == Iac {
					c.inState = 1
				} else {
					j++
				}
			case 1: // seen Iac
				if b == Sb {
					c.inState = 2
				} else {
					j++
					c.inState = 0
				}
			case 2: // inside command
				if b == Iac {
					c.inState = 3
				}
			case 3: // inside command, see Iac
				if b == Se {
					c.inState = 0
				} else {
					c.inState = 2
				}
			}
		}
		if j > 0 {
			break
		}
	}
	return j, nil
}

func (c *telnetWrapper) Write(buf []byte) (int, error) {
	wrapped := bytes.Replace(buf, []byte{0xFF}, []byte{0xFF, 0xFF}, -1)
	// FIXME returned count is wrong
	return c.upLink.Write(wrapped)
}

type connection struct {
	serial serialLink
	lines  chan string
}

func (c *connection) ReadReply() string {
	select {
	case reply := <-c.lines:
		return reply
	case <-time.After(250 * time.Millisecond):
		return ""
	}
}

func (c *connection) SendAndWait(cmd string, expect string) {
	c.serial.Write([]byte(cmd + "\r\n"))
	var reply string
	for i := 0; i < 4; i++ {
		reply = c.ReadReply()
		if reply == "" {
			log.Fatal("no response, timeout")
		}
		if reply == expect {
			return
		}
	}
	log.Fatal(reply)
}

func (c *connection) Identify() int {
	c.serial.SetRTS(true) // keep RTS on for ISP mode

	for {
		c.serial.SetDTR(true) // pulse DTR to reset
		for c.ReadReply() != "" {
			// flush
		}
		c.serial.SetDTR(false)

		c.serial.Write([]byte("?\r\n"))
		if c.ReadReply() == "Synchronized" || !*waitFlag {
			break
		}
	}

	c.serial.SetRTS(false)

	c.SendAndWait("Synchronized", "OK")
	c.SendAndWait("12000", "OK")
	c.SendAndWait("A 0", "0")

	c.SendAndWait("J", "0")
	id, err := strconv.Atoi(c.ReadReply())
	Check(err)

	return id
}

func (c *connection) Program(startAddress int, data []byte) chan int {
	const sectorSize = 1024
	const pageSize = 64

	for len(data)%pageSize != 0 {
		data = append(data, 0xFF)
	}
	firstPage := startAddress / pageSize
	lastPage := firstPage + len(data)/pageSize - 1

	for len(data)%sectorSize != 0 {
		data = append(data, 0xFF)
	}
	firstSector := startAddress / sectorSize
	lastSector := firstSector + len(data)/sectorSize - 1

	if startAddress == 0 {
		fixChecksum(data)
	}

	c.SendAndWait("U 23130", "0") // unlock for programming

	// erase entire range, as 1024-byte sectors
	c.SendAndWait(fmt.Sprint("P ", firstSector, lastSector), "0") // prepare
	c.SendAndWait(fmt.Sprint("E ", firstSector, lastSector), "0") // erase

	r := make(chan int)
	go func() {
		defer close(r)
		// program in 64-byte pages (sectors won't fit in the LPC810's RAM)
		for page := firstPage; page <= lastPage; page++ {
			const RAM_ADDR = 0x10000300
			// write one page of data to RAM
			offset := (page - firstPage) * pageSize
			c.SendAndWait(fmt.Sprint("W ", RAM_ADDR, pageSize), "0")
			c.serial.Write(data[offset : offset+pageSize])
			// prepare and copy the data to flash memory
			sector := (page * pageSize) / sectorSize
			c.SendAndWait(fmt.Sprint("P ", sector, sector), "0")
			destAddr := page * pageSize
			c.SendAndWait(fmt.Sprint("C ", destAddr, RAM_ADDR, pageSize), "0")
			r <- pageSize * (page - firstPage + 1)
		}
	}()
	return r
}

// fix the checksum to mark code as valid (see UM10398, p.416)
func fixChecksum(data []byte) {
	buf := bytes.NewReader(data)
	values := [7]uint32{}
	err := binary.Read(buf, binary.LittleEndian, values[:])
	Check(err)
	var sum uint32
	for _, v := range values {
		sum -= v
	}
	data[28] = byte(sum)
	data[29] = byte(sum >> 8)
	data[30] = byte(sum >> 16)
	data[31] = byte(sum >> 24)
}

func (c *connection) Terminal() {
	timeout := time.Duration(*idleFlag) * time.Second
	idleTimer := time.NewTimer(timeout)

	// FIXME still in line mode, so only complete lines will be shown
	//  look into bufio.Reader for a possible solution
	go func() {
		for s := range c.lines {
			idleTimer.Reset(timeout)
			fmt.Println(s)
		}
	}()

	// put stdin in raw mode
	oldState, err := terminal.MakeRaw(0)
	Check(err)
	defer terminal.Restore(0, oldState)

	// cleanup when program is terminated via a signal
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, os.Interrupt, syscall.SIGHUP, syscall.SIGTERM)
	go func() {
		sigMsg := <-sigChan
		terminal.Restore(0, oldState)
		log.Fatal(sigMsg)
	}()

	// cleanup when idle timer fires, and exit cleanly
	if *idleFlag > 0 {
		go func() {
			<-idleTimer.C
			terminal.Restore(0, oldState)
			fmt.Println("\nidle timeout")
			os.Exit(0)
		}()
	}

	// copy key presses to the serial port
	for {
		var b [1]byte
		n, _ := os.Stdin.Read(b[:])
		idleTimer.Reset(timeout)
		if n < 1 || b[0] == 0x1B { // ESC
			break
		}
		c.serial.Write(b[:n])
	}

}

func Check(e error) {
	if e != nil {
		log.Fatal(e)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc.

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 client

import (
	"crypto/tls"
	"errors"
	"time"

	"github.com/golang/protobuf/proto"
)

// NotificationHandler is a type for the client specific handler function. It
// is passed from the generic client to the implementation specific library.
// It provides a callback for each notification handled by the client specific
// implementation.
type NotificationHandler func(Notification) error

// ProtoHandler is a type for the raw handling of the RPC layer.  It is exposed
// here only for very lower level interactions and should only be used when
// developing a debugging client.
type ProtoHandler func(proto.Message) error

// Type defines the type of query in a Query.
type Type int

// NewType returns a new QueryType based on the provided string.
func NewType(s string) Type {
	v, ok := typeConst[s]
	if !ok {
		return Unknown
	}
	return v
}

// String returns the string representation of the QueryType.
func (q Type) String() string {
	return typeString[q]
}

const (
	// Unknown is an unknown query and should always be treated as an error.
	Unknown Type = iota
	// Once will perform a Once query against the agent.
	Once
	// Poll will perform a Polling query against the agent.
	Poll
	// Stream will perform a Streaming query against the agent.
	Stream
)

var (
	typeString = map[Type]string{
		Unknown: "unknown",
		Once:    "once",
		Poll:    "poll",
		Stream:  "stream",
	}

	typeConst = map[string]Type{
		"unknown": Unknown,
		"once":    Once,
		"poll":    Poll,
		"stream":  Stream,
	}
)

// Query contains all of the parameters necessary to initiate the query.
type Query struct {
	// Addrs is a slice of addresses by which a target may be reached. Most
	// clients will only handle the first element.
	Addrs []string
	// Target is the target of the query.  Maybe empty if the query is performed
	// against an end target vs. a collector.
	Target string
	// Replica is the specific backend to contact.  This field is implementation
	// specific and for direct agent communication should not be set. default is
	// first available.
	Replica int
	// Discard will only stream incremental updates rather than providing the
	// client with an initial snapshot.  This again is implementation specific
	// if the agent doesn't not accept that query it is up the client library to
	// decide wheter to return an error or to make a normal subscription then
	// ignore the initial sync and only provide increment updates.
	Discard bool
	// Queries contains the list of Paths to query.
	Queries []Path
	// Type of query to perform.
	Type Type
	// Timeout is the connection timeout for the query. It will *not* prevent a
	// slow (or streaming) query from completing, this only affects the initial
	// connection and broken connection detection.
	Timeout time.Duration
	// NotificationHandler is the per notification callback handed to a vendor
	// specific implementation. For every notificaiton this call back will be
	// called.
	NotificationHandler NotificationHandler
	// ProtoHandler, if set, will receive all response protos sent by the
	// backend. Only one of NotificationHandler or ProtoHandler may be
	// set.
	ProtoHandler ProtoHandler
	// Credentials are used for authentication with the target. Optional.
	Credentials *Credentials
	// TLS config to use when connecting to target. Optional.
	TLS *tls.Config
}

// Credentials contains information necessary to authenticate with the target.
// Currently only username/password are supported, but may contain TLS client
// certificate in the future.
type Credentials struct {
	Username string
	Password string
}

// Validate validates that query contains valid values that any client should
// be able use to form a valid backend request.
func (q *Query) Validate() error {
	switch {
	default:
		return nil
	case q == nil:
		return errors.New("Query cannot be nil")
	case q.Type == Unknown:
		return errors.New("Query type cannot be Unknown")
	case len(q.Addrs) == 0:
		return errors.New("Query.Addrs not set")
	case len(q.Queries) == 0:
		return errors.New("Query.Queries not set")
	case q.NotificationHandler != nil && q.ProtoHandler != nil:
		return errors.New("only one of Notification or ProtoHandler must be set")
	case q.NotificationHandler == nil && q.ProtoHandler == nil:
		return errors.New("one of Notification or ProtoHandler must be set")
	}
}

// SetRequest contains slices of changes to apply.
//
// The difference between Update and Replace is that on non-primitive values
// (lists/maps), Update acts as "append"; it only overwrites an existing value
// in the container when the key matches.
// Replace overwrites the entire container regardless of current contents.
type SetRequest struct {
	Delete  []Path
	Update  []Leaf
	Replace []Leaf
}

// SetResponse contains the timestamp of an applied SetRequest.
type SetResponse struct {
	TS time.Time
}
<commit_msg>Add an optional Extra field to client.Query. It can be used to pass additional metadata to targets.<commit_after>/*
Copyright 2017 Google Inc.

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 client

import (
	"crypto/tls"
	"errors"
	"time"

	"github.com/golang/protobuf/proto"
)

// NotificationHandler is a type for the client specific handler function. It
// is passed from the generic client to the implementation specific library.
// It provides a callback for each notification handled by the client specific
// implementation.
type NotificationHandler func(Notification) error

// ProtoHandler is a type for the raw handling of the RPC layer.  It is exposed
// here only for very lower level interactions and should only be used when
// developing a debugging client.
type ProtoHandler func(proto.Message) error

// Type defines the type of query in a Query.
type Type int

// NewType returns a new QueryType based on the provided string.
func NewType(s string) Type {
	v, ok := typeConst[s]
	if !ok {
		return Unknown
	}
	return v
}

// String returns the string representation of the QueryType.
func (q Type) String() string {
	return typeString[q]
}

const (
	// Unknown is an unknown query and should always be treated as an error.
	Unknown Type = iota
	// Once will perform a Once query against the agent.
	Once
	// Poll will perform a Polling query against the agent.
	Poll
	// Stream will perform a Streaming query against the agent.
	Stream
)

var (
	typeString = map[Type]string{
		Unknown: "unknown",
		Once:    "once",
		Poll:    "poll",
		Stream:  "stream",
	}

	typeConst = map[string]Type{
		"unknown": Unknown,
		"once":    Once,
		"poll":    Poll,
		"stream":  Stream,
	}
)

// Query contains all of the parameters necessary to initiate the query.
type Query struct {
	// Addrs is a slice of addresses by which a target may be reached. Most
	// clients will only handle the first element.
	Addrs []string
	// Target is the target of the query.  Maybe empty if the query is performed
	// against an end target vs. a collector.
	Target string
	// Replica is the specific backend to contact.  This field is implementation
	// specific and for direct agent communication should not be set. default is
	// first available.
	Replica int
	// Discard will only stream incremental updates rather than providing the
	// client with an initial snapshot.  This again is implementation specific
	// if the agent doesn't not accept that query it is up the client library to
	// decide wheter to return an error or to make a normal subscription then
	// ignore the initial sync and only provide increment updates.
	Discard bool
	// Queries contains the list of Paths to query.
	Queries []Path
	// Type of query to perform.
	Type Type
	// Timeout is the connection timeout for the query. It will *not* prevent a
	// slow (or streaming) query from completing, this only affects the initial
	// connection and broken connection detection.
	Timeout time.Duration
	// NotificationHandler is the per notification callback handed to a vendor
	// specific implementation. For every notificaiton this call back will be
	// called.
	NotificationHandler NotificationHandler
	// ProtoHandler, if set, will receive all response protos sent by the
	// backend. Only one of NotificationHandler or ProtoHandler may be
	// set.
	ProtoHandler ProtoHandler
	// Credentials are used for authentication with the target. Optional.
	Credentials *Credentials
	// TLS config to use when connecting to target. Optional.
	TLS *tls.Config
	// Extra contains arbitrary additional metadata to be passed to the
	// target. Optional.
	Extra map[string]string
}

// Credentials contains information necessary to authenticate with the target.
// Currently only username/password are supported, but may contain TLS client
// certificate in the future.
type Credentials struct {
	Username string
	Password string
}

// Validate validates that query contains valid values that any client should
// be able use to form a valid backend request.
func (q *Query) Validate() error {
	switch {
	default:
		return nil
	case q == nil:
		return errors.New("Query cannot be nil")
	case q.Type == Unknown:
		return errors.New("Query type cannot be Unknown")
	case len(q.Addrs) == 0:
		return errors.New("Query.Addrs not set")
	case len(q.Queries) == 0:
		return errors.New("Query.Queries not set")
	case q.NotificationHandler != nil && q.ProtoHandler != nil:
		return errors.New("only one of Notification or ProtoHandler must be set")
	case q.NotificationHandler == nil && q.ProtoHandler == nil:
		return errors.New("one of Notification or ProtoHandler must be set")
	}
}

// SetRequest contains slices of changes to apply.
//
// The difference between Update and Replace is that on non-primitive values
// (lists/maps), Update acts as "append"; it only overwrites an existing value
// in the container when the key matches.
// Replace overwrites the entire container regardless of current contents.
type SetRequest struct {
	Delete  []Path
	Update  []Leaf
	Replace []Leaf
}

// SetResponse contains the timestamp of an applied SetRequest.
type SetResponse struct {
	TS time.Time
}
<|endoftext|>


<commit_before>package scenario

import (
	"crypto/md5"
	"fmt"
	"io"
	"io/ioutil"
	"sync"

	"github.com/catatsuy/isucon6-final/bench/action"
	"github.com/catatsuy/isucon6-final/bench/fails"
	"github.com/catatsuy/isucon6-final/bench/session"
)

type StaticFile struct {
	Path string
	MD5  string
}

func loadStaticFiles(s *session.Session, checkHash bool) bool {
	assets := []StaticFile{
		StaticFile{Path: "/css/rc-color-picker.css", MD5: "78055c5c02a2dd66f6207fa19f7ca928"},
		StaticFile{Path: "/css/sanitize.css", MD5: "7375990d0f1f7d436a952314e3ac7fd0"},
		StaticFile{Path: "/bundle.js", MD5: "e34dc2ae543ec9adcc8a671798da3263"},
	}
	var wg sync.WaitGroup

	OK := true
	for _, asset := range assets {
		wg.Add(1)
		go func(asset StaticFile) {
			defer wg.Done()

			ok := action.Get(s, asset.Path, action.OK(func(body io.Reader, l *fails.Logger) bool {
				if checkHash {
					content, err := ioutil.ReadAll(body)
					if err != nil {
						l.Add("ファイルの読み込みに失敗しました", err)
						return false
					}
					actual := fmt.Sprintf("%x", md5.Sum(content))
					if actual != asset.MD5 {
						l.Add("ファイルの内容が正しくありません",
							fmt.Errorf("expected %s, actual %s, content: %s", asset.MD5, actual, string(content[:20])))
						return false
					}
				}
				return true
			}))
			if !ok {
				OK = false
			}
		}(asset)
	}
	wg.Wait()
	return OK
}
<commit_msg>Make static file check a bit stricter<commit_after>package scenario

import (
	"crypto/md5"
	"fmt"
	"io"
	"io/ioutil"
	"sync"

	"github.com/catatsuy/isucon6-final/bench/action"
	"github.com/catatsuy/isucon6-final/bench/fails"
	"github.com/catatsuy/isucon6-final/bench/session"
)

type StaticFile struct {
	Path string
	MD5  string
}

func loadStaticFiles(s *session.Session, checkHash bool) bool {
	assets := []StaticFile{
		StaticFile{Path: "/css/rc-color-picker.css", MD5: "78055c5c02a2dd66f6207fa19f7ca928"},
		StaticFile{Path: "/css/sanitize.css", MD5: "7375990d0f1f7d436a952314e3ac7fd0"},
		StaticFile{Path: "/bundle.js", MD5: "e34dc2ae543ec9adcc8a671798da3263"},
	}
	var wg sync.WaitGroup

	OK := true
	for _, asset := range assets {
		wg.Add(1)
		go func(asset StaticFile) {
			defer wg.Done()

			ok := action.Get(s, asset.Path, action.OK(func(body io.Reader, l *fails.Logger) bool {
				content, err := ioutil.ReadAll(body)
				if err != nil {
					l.Add("ファイルの読み込みに失敗しました", err)
					return false
				}

				if checkHash {
					actual := fmt.Sprintf("%x", md5.Sum(content))
					if actual != asset.MD5 {
						l.Add("ファイルの内容が正しくありません",
							fmt.Errorf("expected %s, actual %s, content: %s", asset.MD5, actual, string(content[:20])))
						return false
					}
				}
				return true
			}))
			if !ok {
				OK = false
			}
		}(asset)
	}
	wg.Wait()
	return OK
}
<|endoftext|>