<commit_before>package log

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"path/filepath"
	"strings"

	"github.com/mkideal/log/logger"
	"github.com/mkideal/log/provider"
)

const (
	LvFATAL = logger.FATAL
	LvERROR = logger.ERROR
	LvWARN  = logger.WARN
	LvINFO  = logger.INFO
	LvDEBUG = logger.DEBUG
	LvTRACE = logger.TRACE
)

const (
	KB = 1024
	MB = 1024 * KB
	GB = 1024 * MB
)

// ParseLevel parses log level from string
func ParseLevel(s string) (logger.Level, bool) { return logger.ParseLevel(s) }

// MustParseLevel is similar to ParseLevel, but panics if parse fail
func MustParseLevel(s string) logger.Level { return logger.MustParseLevel(s) }

// global logger
var glogger = logger.NewStdLogger()

// Uninit uninits log package
func Uninit(err error) {
	glogger.Quit()
}

// InitWithLogger inits global logger with a specified logger
func InitWithLogger(l logger.Logger) error {
	glogger.Quit()
	glogger = l
	glogger.Run()
	return nil
}

// InitWithProvider inits global logger(sync) with a specified provider
func InitWithProvider(p logger.Provider) error {
	l := logger.New(p)
	l.SetLevel(LvINFO)
	return InitWithLogger(l)
}

// InitSyncWithProvider inits global logger(async) with a specified provider
func InitSyncWithProvider(p logger.Provider) error {
	l := logger.NewSync(p)
	l.SetLevel(LvINFO)
	return InitWithLogger(l)
}

// Init inits global logger with providerType and opts (opts is a json string or empty)
func Init(providerTypes string, opts interface{}) error {
	// splits providerTypes by '/'
	types := strings.Split(providerTypes, "/")
	if len(types) == 0 || len(providerTypes) == 0 {
		err := errors.New("empty providers")
		glogger.Error(1, "init log error: %v", err)
		return err
	}
	// gets opts string
	optsString := ""
	switch c := opts.(type) {
	case string:
		optsString = c
	case jsonStringer:
		optsString = c.JSON()
	case fmt.Stringer:
		optsString = c.String()
	default:
		optsString = fmt.Sprintf("%v", opts)
	}

	// clean repeated provider type
	usedTypes := map[string]bool{}
	for _, typ := range types {
		typ = strings.TrimSpace(typ)
		usedTypes[typ] = true
	}

	// creates providers
	var providers []logger.Provider
	for typ := range usedTypes {
		creator := logger.Lookup(typ)
		if creator == nil {
			err := errors.New("unregistered provider type: " + typ)
			glogger.Error(1, "init log error: %v", err)
			return err
		}
		p := creator(optsString)
		if len(usedTypes) == 1 {
			return InitWithProvider(p)
		}
		providers = append(providers, p)
	}
	return InitWithProvider(provider.NewMixProvider(providers[0], providers[1:]...))
}

// InitFile inits with file provider by log file fullpath
func InitFile(fullpath string) error {
	return Init("file", makeFileOpts(fullpath))
}

func makeFileOpts(fullpath string) string {
	dir, filename := filepath.Split(fullpath)
	if dir == "" {
		dir = "."
	}
	return fmt.Sprintf(`{"dir":"%s","filename":"%s"}`, dir, filename)
}

// InitConsole inits with console provider by toStderrLevel
func InitConsole(toStderrLevel logger.Level) error {
	return Init("console", makeConsoleOpts(toStderrLevel))
}

func InitColoredConsole(toStderrLevel logger.Level) error {
	return Init("colored_console", makeConsoleOpts(toStderrLevel))
}

func makeConsoleOpts(toStderrLevel logger.Level) string {
	return fmt.Sprintf(`{"tostderrlevel":%d}`, toStderrLevel)
}

// InitFileAndConsole inits with console and file providers
func InitFileAndConsole(fullpath string, toStderrLevel logger.Level) error {
	fileOpts := makeFileOpts(fullpath)
	consoleOpts := makeConsoleOpts(toStderrLevel)
	p := provider.NewMixProvider(provider.NewFile(fileOpts), provider.NewConsole(consoleOpts))
	return InitWithProvider(p)
}

// InitMultiFile inits with multifile provider
func InitMultiFile(rootdir, filename string) error {
	return Init("multifile", makeMultiFileOpts(rootdir, filename))
}

func makeMultiFileOpts(rootdir, filename string) string {
	return fmt.Sprintf(`{"rootdir":"%s","filename":"%s"}`, rootdir, filename)
}

// InitMultiFileAndConsole inits with console and multifile providers
func InitMultiFileAndConsole(rootdir, filename string, toStderrLevel logger.Level) error {
	multifileOpts := makeMultiFileOpts(rootdir, filename)
	consoleOpts := makeConsoleOpts(toStderrLevel)
	p := provider.NewMixProvider(provider.NewMultiFile(multifileOpts), provider.NewConsole(consoleOpts))
	return InitWithProvider(p)
}

func NoHeader()                                { glogger.NoHeader() }
func GetLevel() logger.Level                   { return glogger.GetLevel() }
func SetLevel(level logger.Level)              { glogger.SetLevel(level) }
func Trace(format string, args ...interface{}) { glogger.Trace(1, format, args...) }
func Debug(format string, args ...interface{}) { glogger.Debug(1, format, args...) }
func Info(format string, args ...interface{})  { glogger.Info(1, format, args...) }
func Warn(format string, args ...interface{})  { glogger.Warn(1, format, args...) }
func Error(format string, args ...interface{}) { glogger.Error(1, format, args...) }
func Fatal(format string, args ...interface{}) { glogger.Fatal(1, format, args...) }

func Printf(calldepth int, level logger.Level, format string, args ...interface{}) {
	switch level {
	case LvTRACE:
		glogger.Trace(calldepth, format, args...)
	case LvDEBUG:
		glogger.Debug(calldepth, format, args...)
	case LvINFO:
		glogger.Info(calldepth, format, args...)
	case LvWARN:
		glogger.Warn(calldepth, format, args...)
	case LvERROR:
		glogger.Error(calldepth, format, args...)
	case LvFATAL:
		glogger.Fatal(calldepth, format, args...)
	}
}

func Print(calldepth int, level logger.Level, args ...interface{}) {
	if level <= glogger.GetLevel() {
		msg := fmt.Sprint(args...)
		switch level {
		case LvTRACE:
			glogger.Trace(calldepth, msg)
		case LvDEBUG:
			glogger.Debug(calldepth, msg)
		case LvINFO:
			glogger.Info(calldepth, msg)
		case LvWARN:
			glogger.Warn(calldepth, msg)
		case LvERROR:
			glogger.Error(calldepth, msg)
		case LvFATAL:
			glogger.Fatal(calldepth, msg)
		}
	}
}

// HTTPHandlerGetLevel returns a http handler for getting log level
func HTTPHandlerGetLevel() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, GetLevel().String())
	})
}

// HTTPHandlerSetLevel sets new log level and returns old log level
// Returns status code `StatusBadRequest` if parse log level fail
func HTTPHandlerSetLevel() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()
		level := r.FormValue("level")
		lv, ok := ParseLevel(level)
		// invalid parameter
		if !ok {
			w.WriteHeader(http.StatusBadRequest)
			io.WriteString(w, "invalid log level: "+level)
			return
		}
		// not modified
		oldLevel := GetLevel()
		if lv == oldLevel {
			w.WriteHeader(http.StatusNotModified)
			io.WriteString(w, oldLevel.String())
			return
		}
		// updated
		SetLevel(lv)
		io.WriteString(w, oldLevel.String())
	})
}

// SetLevelFromString parses level from string and set parsed level
// (NOTE): set level to INFO if parse fail
func SetLevelFromString(s string) logger.Level {
	level, _ := ParseLevel(s)
	glogger.SetLevel(level)
	return level
}

// If returns an `IfLogger`
func If(ok bool) IfLogger {
	if ok {
		return IfLogger(0xFF)
	} else {
		return IfLogger(0x00)
	}
}

// With returns a ContextLogger
func With(values ...interface{}) ContextLogger {
	if len(values) == 1 {
		return &contextLogger{isTrue: true, data: values[0]}
	}
	return &contextLogger{isTrue: true, data: values}
}

// WithJSON returns a ContextLogger using JSONFormatter
func WithJSON(values ...interface{}) ContextLogger {
	if len(values) == 1 {
		return &contextLogger{isTrue: true, data: values[0], formatter: jsonFormatter}
	}
	return &contextLogger{isTrue: true, data: values, formatter: jsonFormatter}
}
<commit_msg>fix typos<commit_after>package log

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/mkideal/log/logger"
	"github.com/mkideal/log/provider"
)

const (
	LvFATAL = logger.FATAL
	LvERROR = logger.ERROR
	LvWARN  = logger.WARN
	LvINFO  = logger.INFO
	LvDEBUG = logger.DEBUG
	LvTRACE = logger.TRACE
)

const (
	KB = 1024
	MB = 1024 * KB
	GB = 1024 * MB
)

// ParseLevel parses log level from string
func ParseLevel(s string) (logger.Level, bool) { return logger.ParseLevel(s) }

// MustParseLevel is similar to ParseLevel, but panics if parse failed
func MustParseLevel(s string) logger.Level { return logger.MustParseLevel(s) }

// global logger
var glogger = logger.NewStdLogger()

// Uninit uninits log package
func Uninit(err error) {
	glogger.Quit()
}

// InitWithLogger inits global logger with a specified logger
func InitWithLogger(l logger.Logger) error {
	glogger.Quit()
	glogger = l
	glogger.Run()
	return nil
}

// InitWithProvider inits global logger(sync) with a specified provider
func InitWithProvider(p logger.Provider) error {
	l := logger.New(p)
	l.SetLevel(LvINFO)
	return InitWithLogger(l)
}

// InitSyncWithProvider inits global logger(async) with a specified provider
func InitSyncWithProvider(p logger.Provider) error {
	l := logger.NewSync(p)
	l.SetLevel(LvINFO)
	return InitWithLogger(l)
}

// Init inits global logger with providerType and opts (opts is a json string or empty)
func Init(providerTypes string, opts interface{}) error {
	// splits providerTypes by '/'
	types := strings.Split(providerTypes, "/")
	if len(types) == 0 || len(providerTypes) == 0 {
		err := errors.New("empty providers")
		glogger.Error(1, "init log error: %v", err)
		return err
	}
	// gets opts string
	optsString := ""
	switch c := opts.(type) {
	case string:
		optsString = c
	case jsonStringer:
		optsString = c.JSON()
	case fmt.Stringer:
		optsString = c.String()
	default:
		optsString = fmt.Sprintf("%v", opts)
	}

	// clean repeated provider type
	usedTypes := map[string]bool{}
	for _, typ := range types {
		typ = strings.TrimSpace(typ)
		usedTypes[typ] = true
	}

	// creates providers
	var providers []logger.Provider
	for typ := range usedTypes {
		creator := logger.Lookup(typ)
		if creator == nil {
			err := errors.New("unregistered provider type: " + typ)
			glogger.Error(1, "init log error: %v", err)
			return err
		}
		p := creator(optsString)
		if len(usedTypes) == 1 {
			return InitWithProvider(p)
		}
		providers = append(providers, p)
	}
	return InitWithProvider(provider.NewMixProvider(providers[0], providers[1:]...))
}

// InitFile inits with file provider by log file fullpath
func InitFile(fullpath string) error {
	return Init("file", makeFileOpts(fullpath))
}

func makeFileOpts(fullpath string) string {
	dir, filename := filepath.Split(fullpath)
	if dir == "" {
		dir = "."
	}
	return fmt.Sprintf(`{"dir":%s,"filename":%s}`, strconv.Quote(dir), strconv.Quote(filename))
}

// InitConsole inits with console provider by toStderrLevel
func InitConsole(toStderrLevel logger.Level) error {
	return Init("console", makeConsoleOpts(toStderrLevel))
}

func InitColoredConsole(toStderrLevel logger.Level) error {
	return Init("colored_console", makeConsoleOpts(toStderrLevel))
}

func makeConsoleOpts(toStderrLevel logger.Level) string {
	return fmt.Sprintf(`{"tostderrlevel":%d}`, toStderrLevel)
}

// InitFileAndConsole inits with console and file providers
func InitFileAndConsole(fullpath string, toStderrLevel logger.Level) error {
	fileOpts := makeFileOpts(fullpath)
	consoleOpts := makeConsoleOpts(toStderrLevel)
	p := provider.NewMixProvider(provider.NewFile(fileOpts), provider.NewConsole(consoleOpts))
	return InitWithProvider(p)
}

// InitMultiFile inits with multifile provider
func InitMultiFile(rootdir, filename string) error {
	return Init("multifile", makeMultiFileOpts(rootdir, filename))
}

func makeMultiFileOpts(rootdir, filename string) string {
	return fmt.Sprintf(`{"rootdir":"%s","filename":"%s"}`, rootdir, filename)
}

// InitMultiFileAndConsole inits with console and multifile providers
func InitMultiFileAndConsole(rootdir, filename string, toStderrLevel logger.Level) error {
	multifileOpts := makeMultiFileOpts(rootdir, filename)
	consoleOpts := makeConsoleOpts(toStderrLevel)
	p := provider.NewMixProvider(provider.NewMultiFile(multifileOpts), provider.NewConsole(consoleOpts))
	return InitWithProvider(p)
}

func NoHeader()                                { glogger.NoHeader() }
func GetLevel() logger.Level                   { return glogger.GetLevel() }
func SetLevel(level logger.Level)              { glogger.SetLevel(level) }
func Trace(format string, args ...interface{}) { glogger.Trace(1, format, args...) }
func Debug(format string, args ...interface{}) { glogger.Debug(1, format, args...) }
func Info(format string, args ...interface{})  { glogger.Info(1, format, args...) }
func Warn(format string, args ...interface{})  { glogger.Warn(1, format, args...) }
func Error(format string, args ...interface{}) { glogger.Error(1, format, args...) }
func Fatal(format string, args ...interface{}) { glogger.Fatal(1, format, args...) }

func Printf(calldepth int, level logger.Level, format string, args ...interface{}) {
	switch level {
	case LvTRACE:
		glogger.Trace(calldepth, format, args...)
	case LvDEBUG:
		glogger.Debug(calldepth, format, args...)
	case LvINFO:
		glogger.Info(calldepth, format, args...)
	case LvWARN:
		glogger.Warn(calldepth, format, args...)
	case LvERROR:
		glogger.Error(calldepth, format, args...)
	case LvFATAL:
		glogger.Fatal(calldepth, format, args...)
	}
}

func Print(calldepth int, level logger.Level, args ...interface{}) {
	if level <= glogger.GetLevel() {
		msg := fmt.Sprint(args...)
		switch level {
		case LvTRACE:
			glogger.Trace(calldepth, msg)
		case LvDEBUG:
			glogger.Debug(calldepth, msg)
		case LvINFO:
			glogger.Info(calldepth, msg)
		case LvWARN:
			glogger.Warn(calldepth, msg)
		case LvERROR:
			glogger.Error(calldepth, msg)
		case LvFATAL:
			glogger.Fatal(calldepth, msg)
		}
	}
}

// HTTPHandlerGetLevel returns a http handler for getting log level
func HTTPHandlerGetLevel() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, GetLevel().String())
	})
}

// HTTPHandlerSetLevel sets new log level and returns old log level
// Returns status code `StatusBadRequest` if parse log level fail
func HTTPHandlerSetLevel() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()
		level := r.FormValue("level")
		lv, ok := ParseLevel(level)
		// invalid parameter
		if !ok {
			w.WriteHeader(http.StatusBadRequest)
			io.WriteString(w, "invalid log level: "+level)
			return
		}
		// not modified
		oldLevel := GetLevel()
		if lv == oldLevel {
			w.WriteHeader(http.StatusNotModified)
			io.WriteString(w, oldLevel.String())
			return
		}
		// updated
		SetLevel(lv)
		io.WriteString(w, oldLevel.String())
	})
}

// SetLevelFromString parses level from string and set parsed level
// (NOTE): set level to INFO if parse failed
func SetLevelFromString(s string) logger.Level {
	level, _ := ParseLevel(s)
	glogger.SetLevel(level)
	return level
}

// If returns an `IfLogger`
func If(ok bool) IfLogger {
	if ok {
		return IfLogger(0xFF)
	} else {
		return IfLogger(0x00)
	}
}

// With returns a ContextLogger
func With(values ...interface{}) ContextLogger {
	if len(values) == 1 {
		return &contextLogger{isTrue: true, data: values[0]}
	}
	return &contextLogger{isTrue: true, data: values}
}

// WithJSON returns a ContextLogger using JSONFormatter
func WithJSON(values ...interface{}) ContextLogger {
	if len(values) == 1 {
		return &contextLogger{isTrue: true, data: values[0], formatter: jsonFormatter}
	}
	return &contextLogger{isTrue: true, data: values, formatter: jsonFormatter}
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Gravitational, 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 trace implements utility functions for capturing logs
package trace

import (
	"bytes"
	"fmt"
	"regexp"
	rundebug "runtime/debug"
	"sort"
	"strconv"
	"strings"
	"time"

	log "github.com/sirupsen/logrus"

	"runtime"
)

const (
	// FileField is a field with code file added to structured traces
	FileField = "file"
	// FunctionField is a field with function name
	FunctionField = "func"
	// LevelField returns logging level as set by logrus
	LevelField = "level"
	// Component is a field that represents component - e.g. service or
	// function
	Component = "trace.component"
	// ComponentFields is a fields component
	ComponentFields = "trace.fields"
	// DefaultComponentPadding is a default padding for component field
	DefaultComponentPadding = 11
	// DefaultLevelPadding is a default padding for level field
	DefaultLevelPadding = 4
)

// TextFormatter is logrus-compatible formatter and adds
// file and line details to every logged entry.
type TextFormatter struct {
	// DisableTimestamp disables timestamp output (useful when outputting to
	// systemd logs)
	DisableTimestamp bool
	// ComponentPadding is a padding to pick when displaying
	// and formatting component field, defaults to DefaultComponentPadding
	ComponentPadding int
}

// Format implements logrus.Formatter interface and adds file and line
func (tf *TextFormatter) Format(e *log.Entry) (data []byte, err error) {
	defer func() {
		if r := recover(); r != nil {
			data = append([]byte("panic in log formatter\n"), rundebug.Stack()...)
			return
		}
	}()
	var file string
	if frameNo := findFrame(); frameNo != -1 {
		t := newTrace(frameNo, nil)
		file = t.Loc()
	}

	w := &writer{}

	// time
	if !tf.DisableTimestamp {
		w.writeField(e.Time.Format(time.RFC3339))
	}

	// level
	w.writeField(strings.ToUpper(padMax(e.Level.String(), DefaultLevelPadding)))

	// component, always output
	componentI, ok := e.Data[Component]
	if !ok {
		componentI = ""
	}
	component, ok := componentI.(string)
	if !ok {
		component = fmt.Sprintf("%v", componentI)
	}
	padding := DefaultComponentPadding
	if tf.ComponentPadding != 0 {
		padding = tf.ComponentPadding
	}
	if w.Len() > 0 {
		w.WriteByte(' ')
	}
	if component != "" {
		component = fmt.Sprintf("[%v]", component)
	}
	component = strings.ToUpper(padMax(component, padding))
	if component[len(component)-1] != ' ' {
		component = component[:len(component)-1] + "]"
	}
	w.WriteString(component)

	// message
	if e.Message != "" {
		w.writeField(e.Message)
	}

	// file, if present
	if file != "" {
		w.writeField(file)
	}

	// rest of the fields
	if len(e.Data) > 0 {
		w.writeMap(e.Data)
	}
	w.WriteByte('\n')
	data = w.Bytes()
	return
}

// JSONFormatter implements logrus.Formatter interface and adds file and line
// properties to JSON entries
type JSONFormatter struct {
	log.JSONFormatter
}

// Format implements logrus.Formatter interface
func (j *JSONFormatter) Format(e *log.Entry) ([]byte, error) {
	if frameNo := findFrame(); frameNo != -1 {
		t := newTrace(frameNo, nil)
		new := e.WithFields(log.Fields{
			FileField:     t.Loc(),
			FunctionField: t.FuncName(),
		})
		new.Level = e.Level
		new.Message = e.Message
		e = new
	}
	return (&j.JSONFormatter).Format(e)
}

var r = regexp.MustCompile(`github\.com/(S|s)irupsen/logrus`)

func findFrame() int {
	for i := 3; i < 10; i++ {
		_, file, _, ok := runtime.Caller(i)
		if !ok {
			return -1
		}
		if !r.MatchString(file) {
			return i
		}
	}
	return -1
}

type writer struct {
	bytes.Buffer
}

func (w *writer) writeField(value interface{}) {
	if w.Len() > 0 {
		w.WriteByte(' ')
	}
	w.writeValue(value)
}

func (w *writer) writeValue(value interface{}) {
	stringVal, ok := value.(string)
	if !ok {
		stringVal = fmt.Sprint(value)
	}
	if !needsQuoting(stringVal) {
		w.WriteString(stringVal)
	} else {
		w.WriteString(fmt.Sprintf("%q", stringVal))
	}
}

func (w *writer) writeKeyValue(key string, value interface{}) {
	if w.Len() > 0 {
		w.WriteByte(' ')
	}
	w.WriteString(key)
	w.WriteByte(':')
	w.writeValue(value)
}

func (w *writer) writeMap(m map[string]interface{}) {
	if len(m) == 0 {
		return
	}
	keys := make([]string, 0, len(m))
	for key := range m {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	for _, key := range keys {
		if key == Component {
			continue
		}
		switch val := m[key].(type) {
		case log.Fields:
			w.writeMap(val)
		default:
			w.writeKeyValue(key, val)
		}
	}
}

func needsQuoting(text string) bool {
	for _, r := range text {
		if !strconv.IsPrint(r) {
			return true
		}
	}
	return false
}

func padMax(in string, chars int) string {
	switch {
	case len(in) < chars:
		return in + strings.Repeat(" ", chars-len(in))
	default:
		return in[:chars]
	}
}
<commit_msg>reorder some fields<commit_after>/*
Copyright 2015 Gravitational, 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 trace implements utility functions for capturing logs
package trace

import (
	"bytes"
	"fmt"
	"regexp"
	rundebug "runtime/debug"
	"sort"
	"strconv"
	"strings"
	"time"

	log "github.com/sirupsen/logrus"

	"runtime"
)

const (
	// FileField is a field with code file added to structured traces
	FileField = "file"
	// FunctionField is a field with function name
	FunctionField = "func"
	// LevelField returns logging level as set by logrus
	LevelField = "level"
	// Component is a field that represents component - e.g. service or
	// function
	Component = "trace.component"
	// ComponentFields is a fields component
	ComponentFields = "trace.fields"
	// DefaultComponentPadding is a default padding for component field
	DefaultComponentPadding = 11
	// DefaultLevelPadding is a default padding for level field
	DefaultLevelPadding = 4
)

// TextFormatter is logrus-compatible formatter and adds
// file and line details to every logged entry.
type TextFormatter struct {
	// DisableTimestamp disables timestamp output (useful when outputting to
	// systemd logs)
	DisableTimestamp bool
	// ComponentPadding is a padding to pick when displaying
	// and formatting component field, defaults to DefaultComponentPadding
	ComponentPadding int
}

// Format implements logrus.Formatter interface and adds file and line
func (tf *TextFormatter) Format(e *log.Entry) (data []byte, err error) {
	defer func() {
		if r := recover(); r != nil {
			data = append([]byte("panic in log formatter\n"), rundebug.Stack()...)
			return
		}
	}()
	var file string
	if frameNo := findFrame(); frameNo != -1 {
		t := newTrace(frameNo, nil)
		file = t.Loc()
	}

	w := &writer{}

	// time
	if !tf.DisableTimestamp {
		w.writeField(e.Time.Format(time.RFC3339))
	}

	// level
	w.writeField(strings.ToUpper(padMax(e.Level.String(), DefaultLevelPadding)))

	// component, always output
	componentI, ok := e.Data[Component]
	if !ok {
		componentI = ""
	}
	component, ok := componentI.(string)
	if !ok {
		component = fmt.Sprintf("%v", componentI)
	}
	padding := DefaultComponentPadding
	if tf.ComponentPadding != 0 {
		padding = tf.ComponentPadding
	}
	if w.Len() > 0 {
		w.WriteByte(' ')
	}
	if component != "" {
		component = fmt.Sprintf("[%v]", component)
	}
	component = strings.ToUpper(padMax(component, padding))
	if component[len(component)-1] != ' ' {
		component = component[:len(component)-1] + "]"
	}
	w.WriteString(component)

	// message
	if e.Message != "" {
		w.writeField(e.Message)
	}

	// rest of the fields
	if len(e.Data) > 0 {
		w.writeMap(e.Data)
	}

	// file, if present, always last
	if file != "" {
		w.writeField(file)
	}

	w.WriteByte('\n')
	data = w.Bytes()
	return
}

// JSONFormatter implements logrus.Formatter interface and adds file and line
// properties to JSON entries
type JSONFormatter struct {
	log.JSONFormatter
}

// Format implements logrus.Formatter interface
func (j *JSONFormatter) Format(e *log.Entry) ([]byte, error) {
	if frameNo := findFrame(); frameNo != -1 {
		t := newTrace(frameNo, nil)
		new := e.WithFields(log.Fields{
			FileField:     t.Loc(),
			FunctionField: t.FuncName(),
		})
		new.Level = e.Level
		new.Message = e.Message
		e = new
	}
	return (&j.JSONFormatter).Format(e)
}

var r = regexp.MustCompile(`github\.com/(S|s)irupsen/logrus`)

func findFrame() int {
	for i := 3; i < 10; i++ {
		_, file, _, ok := runtime.Caller(i)
		if !ok {
			return -1
		}
		if !r.MatchString(file) {
			return i
		}
	}
	return -1
}

type writer struct {
	bytes.Buffer
}

func (w *writer) writeField(value interface{}) {
	if w.Len() > 0 {
		w.WriteByte(' ')
	}
	w.writeValue(value)
}

func (w *writer) writeValue(value interface{}) {
	stringVal, ok := value.(string)
	if !ok {
		stringVal = fmt.Sprint(value)
	}
	if !needsQuoting(stringVal) {
		w.WriteString(stringVal)
	} else {
		w.WriteString(fmt.Sprintf("%q", stringVal))
	}
}

func (w *writer) writeKeyValue(key string, value interface{}) {
	if w.Len() > 0 {
		w.WriteByte(' ')
	}
	w.WriteString(key)
	w.WriteByte(':')
	w.writeValue(value)
}

func (w *writer) writeMap(m map[string]interface{}) {
	if len(m) == 0 {
		return
	}
	keys := make([]string, 0, len(m))
	for key := range m {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	for _, key := range keys {
		if key == Component {
			continue
		}
		switch val := m[key].(type) {
		case log.Fields:
			w.writeMap(val)
		default:
			w.writeKeyValue(key, val)
		}
	}
}

func needsQuoting(text string) bool {
	for _, r := range text {
		if !strconv.IsPrint(r) {
			return true
		}
	}
	return false
}

func padMax(in string, chars int) string {
	switch {
	case len(in) < chars:
		return in + strings.Repeat(" ", chars-len(in))
	default:
		return in[:chars]
	}
}
<|endoftext|>


<commit_before>package log

import (
	"fmt"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"
)

// Logger is the default instance of the log package
var (
	exitFunc  = os.Exit
	skipLevel = 2
)

// Logger interface for logging
type Logger interface {
	Debug(v ...interface{})
	Debugf(msg string, v ...interface{})
	Info(v ...interface{})
	Infof(msg string, v ...interface{})
	Warn(v ...interface{})
	Warnf(msg string, v ...interface{})
	Error(v ...interface{})
	Errorf(msg string, v ...interface{})
	Fatal(v ...interface{})
	Fatalf(msg string, v ...interface{})
	Panic(v ...interface{})
	Panicf(msg string, v ...interface{})
	WithFields(fields Fields) Logger
}

// HandlerChannels is an array of handler channels
type HandlerChannels []chan<- *Entry

// LevelHandlerChannels is a group of Handler channels mapped by Level
type LevelHandlerChannels map[Level]HandlerChannels

type Handler interface {
	Run() chan<- *Entry
}

type logger struct {
	host             string
	entryPool        sync.Pool
	channels         LevelHandlerChannels
	callerInfoLevels [6]bool
	appID            string
}

func new() *logger {
	hostname, _ := os.Hostname()
	logger := &logger{
		host:     hostname,
		channels: make(LevelHandlerChannels),
		callerInfoLevels: [6]bool{
			true,  // debug
			false, // info
			false, // warn
			true,  // error
			true,  // panic
			true,  // fatal
		},
	}

	logger.entryPool.New = func() interface{} {
		return &Entry{
			wg: &sync.WaitGroup{},
		}
	}

	return logger
}

func (l *logger) newEntry(level Level, message string, fields Fields, calldepth int) *Entry {
	entry := l.entryPool.Get().(*Entry)
	entry.logger = l
	entry.calldepth = calldepth
	entry.Host = l.host
	entry.AppID = l.appID
	entry.Line = 0
	entry.File = ""
	entry.Level = level
	entry.Message = strings.TrimSpace(message)
	entry.Fields = fields
	entry.Timestamp = time.Now().UTC()
	return entry
}

// RegisterHandler adds a new Log Handler and specifies what log levels
// the handler will be passed log entries for
func (l *logger) RegisterHandler(handler Handler, levels ...Level) {
	ch := handler.Run()

	for _, level := range levels {
		channels, ok := l.channels[level]
		if !ok {
			channels = make(HandlerChannels, 0)
		}

		l.channels[level] = append(channels, ch)
	}
}

// Debug level formatted message.
func (l *logger) Debug(v ...interface{}) {
	e := l.newEntry(DebugLevel, fmt.Sprint(v...), nil, skipLevel)
	l.handleEntry(e)
}

// Debugf level formatted message.
func (l *logger) Debugf(msg string, v ...interface{}) {
	e := l.newEntry(DebugLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	l.handleEntry(e)
}

// Info level formatted message.
func (l *logger) Info(v ...interface{}) {
	e := l.newEntry(InfoLevel, fmt.Sprint(v...), nil, skipLevel)
	l.handleEntry(e)
}

// Infof level formatted message.
func (l *logger) Infof(msg string, v ...interface{}) {
	e := l.newEntry(InfoLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	l.handleEntry(e)
}

// Warn level formatted message.
func (l *logger) Warn(v ...interface{}) {
	e := l.newEntry(WarnLevel, fmt.Sprint(v...), nil, skipLevel)
	l.handleEntry(e)
}

// Warnf level formatted message.
func (l *logger) Warnf(msg string, v ...interface{}) {
	e := l.newEntry(WarnLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	l.handleEntry(e)
}

// Error level formatted message.
func (l *logger) Error(v ...interface{}) {
	e := l.newEntry(ErrorLevel, fmt.Sprint(v...), nil, skipLevel)
	l.handleEntry(e)
}

// Errorf level formatted message.
func (l *logger) Errorf(msg string, v ...interface{}) {
	e := l.newEntry(ErrorLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	l.handleEntry(e)
}

// Panic level formatted message.
func (l *logger) Panic(v ...interface{}) {
	s := fmt.Sprint(v...)
	e := l.newEntry(PanicLevel, s, nil, skipLevel)
	l.handleEntry(e)
	panic(s)
}

// Panic level formatted message.
func (l *logger) Panicf(msg string, v ...interface{}) {
	s := fmt.Sprintf(msg, v...)
	e := l.newEntry(PanicLevel, s, nil, skipLevel)
	l.handleEntry(e)
	panic(s)
}

// Fatal level formatted message.
func (l *logger) Fatal(v ...interface{}) {
	e := l.newEntry(FatalLevel, fmt.Sprint(v...), nil, skipLevel)
	l.handleEntry(e)
	exitFunc(1)
}

// Fatal level formatted message.
func (l *logger) Fatalf(msg string, v ...interface{}) {
	e := l.newEntry(FatalLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	l.handleEntry(e)
	exitFunc(1)
}

// WithFields returns a log Entry with fields set
func (l *logger) WithFields(fields Fields) Logger {
	e := l.newEntry(InfoLevel, "", fields, skipLevel)
	return e
}

// SetAppID set a constant application key
// that will be set on all log Entry objects
func (l *logger) SetAppID(id string) {
	l.appID = id
}

// AppID return an application key
func (l *logger) AppID() string {
	return l.appID
}

func (l *logger) handleEntry(e *Entry) {
	if e.Line == 0 && l.callerInfoLevels[e.Level] {
		_, e.File, e.Line, _ = runtime.Caller(e.calldepth)
	}

	channels, ok := l.channels[e.Level]
	if ok {
		e.Lock()
		e.wg.Add(len(channels))
		for _, ch := range channels {
			ch <- e
		}
		e.wg.Wait()
		e.Unlock()
	}

	e.reset()
	l.entryPool.Put(e)
}
<commit_msg>fix timestamp issue<commit_after>package log

import (
	"fmt"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"
)

// Logger is the default instance of the log package
var (
	exitFunc  = os.Exit
	skipLevel = 2
)

// Logger interface for logging
type Logger interface {
	Debug(v ...interface{})
	Debugf(msg string, v ...interface{})
	Info(v ...interface{})
	Infof(msg string, v ...interface{})
	Warn(v ...interface{})
	Warnf(msg string, v ...interface{})
	Error(v ...interface{})
	Errorf(msg string, v ...interface{})
	Fatal(v ...interface{})
	Fatalf(msg string, v ...interface{})
	Panic(v ...interface{})
	Panicf(msg string, v ...interface{})
	WithFields(fields Fields) Logger
}

// HandlerChannels is an array of handler channels
type HandlerChannels []chan<- *Entry

// LevelHandlerChannels is a group of Handler channels mapped by Level
type LevelHandlerChannels map[Level]HandlerChannels

type Handler interface {
	Run() chan<- *Entry
}

type logger struct {
	host             string
	entryPool        sync.Pool
	channels         LevelHandlerChannels
	callerInfoLevels [6]bool
	appID            string
}

func new() *logger {
	hostname, _ := os.Hostname()
	logger := &logger{
		host:     hostname,
		channels: make(LevelHandlerChannels),
		callerInfoLevels: [6]bool{
			true,  // debug
			false, // info
			false, // warn
			true,  // error
			true,  // panic
			true,  // fatal
		},
	}

	logger.entryPool.New = func() interface{} {
		return &Entry{
			wg: &sync.WaitGroup{},
		}
	}

	return logger
}

func (l *logger) newEntry(level Level, message string, fields Fields, calldepth int) *Entry {
	entry := l.entryPool.Get().(*Entry)
	entry.logger = l
	entry.calldepth = calldepth
	entry.Host = l.host
	entry.AppID = l.appID
	entry.Line = 0
	entry.File = ""
	entry.Level = level
	entry.Message = strings.TrimSpace(message)
	entry.Fields = fields
	return entry
}

// RegisterHandler adds a new Log Handler and specifies what log levels
// the handler will be passed log entries for
func (l *logger) RegisterHandler(handler Handler, levels ...Level) {
	ch := handler.Run()

	for _, level := range levels {
		channels, ok := l.channels[level]
		if !ok {
			channels = make(HandlerChannels, 0)
		}

		l.channels[level] = append(channels, ch)
	}
}

// Debug level formatted message.
func (l *logger) Debug(v ...interface{}) {
	e := l.newEntry(DebugLevel, fmt.Sprint(v...), nil, skipLevel)
	l.handleEntry(e)
}

// Debugf level formatted message.
func (l *logger) Debugf(msg string, v ...interface{}) {
	e := l.newEntry(DebugLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	l.handleEntry(e)
}

// Info level formatted message.
func (l *logger) Info(v ...interface{}) {
	e := l.newEntry(InfoLevel, fmt.Sprint(v...), nil, skipLevel)
	l.handleEntry(e)
}

// Infof level formatted message.
func (l *logger) Infof(msg string, v ...interface{}) {
	e := l.newEntry(InfoLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	l.handleEntry(e)
}

// Warn level formatted message.
func (l *logger) Warn(v ...interface{}) {
	e := l.newEntry(WarnLevel, fmt.Sprint(v...), nil, skipLevel)
	l.handleEntry(e)
}

// Warnf level formatted message.
func (l *logger) Warnf(msg string, v ...interface{}) {
	e := l.newEntry(WarnLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	l.handleEntry(e)
}

// Error level formatted message.
func (l *logger) Error(v ...interface{}) {
	e := l.newEntry(ErrorLevel, fmt.Sprint(v...), nil, skipLevel)
	l.handleEntry(e)
}

// Errorf level formatted message.
func (l *logger) Errorf(msg string, v ...interface{}) {
	e := l.newEntry(ErrorLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	l.handleEntry(e)
}

// Panic level formatted message.
func (l *logger) Panic(v ...interface{}) {
	s := fmt.Sprint(v...)
	e := l.newEntry(PanicLevel, s, nil, skipLevel)
	l.handleEntry(e)
	panic(s)
}

// Panic level formatted message.
func (l *logger) Panicf(msg string, v ...interface{}) {
	s := fmt.Sprintf(msg, v...)
	e := l.newEntry(PanicLevel, s, nil, skipLevel)
	l.handleEntry(e)
	panic(s)
}

// Fatal level formatted message.
func (l *logger) Fatal(v ...interface{}) {
	e := l.newEntry(FatalLevel, fmt.Sprint(v...), nil, skipLevel)
	l.handleEntry(e)
	exitFunc(1)
}

// Fatal level formatted message.
func (l *logger) Fatalf(msg string, v ...interface{}) {
	e := l.newEntry(FatalLevel, fmt.Sprintf(msg, v...), nil, skipLevel)
	l.handleEntry(e)
	exitFunc(1)
}

// WithFields returns a log Entry with fields set
func (l *logger) WithFields(fields Fields) Logger {
	e := l.newEntry(InfoLevel, "", fields, skipLevel)
	return e
}

// SetAppID set a constant application key
// that will be set on all log Entry objects
func (l *logger) SetAppID(id string) {
	l.appID = id
}

// AppID return an application key
func (l *logger) AppID() string {
	return l.appID
}

func (l *logger) handleEntry(e *Entry) {
	if e.Line == 0 && l.callerInfoLevels[e.Level] {
		_, e.File, e.Line, _ = runtime.Caller(e.calldepth)
	}

	e.Timestamp = time.Now().UTC()
	channels, ok := l.channels[e.Level]
	if ok {
		e.Lock()
		e.wg.Add(len(channels))
		for _, ch := range channels {
			ch <- e
		}
		e.wg.Wait()
		e.Unlock()
	}

	e.reset()
	l.entryPool.Put(e)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"runtime/debug"
	"strings"
)

var (
	// Console output (can be overridden by changing)
	consoleErr io.Writer = os.Stderr
	consoleOut io.Writer = os.Stdout
	// Loggers for file output
	debugLog  *log.Logger
	errorLog  *log.Logger
	outputLog *log.Logger
	logFile   *os.File
)

// Always send all console output to stderr, including info/debug messages
// This is mostly useful when stdout is reserved for piping content
func LogAllConsoleOutputToStdErr() {
	consoleOut = os.Stderr
	consoleErr = os.Stderr
}

// Suppress all console output
func LogSuppressAllConsoleOutput() {
	consoleOut = ioutil.Discard
	consoleErr = ioutil.Discard
	errorLog = log.New(ioutil.Discard, "", 0)
	debugLog = log.New(ioutil.Discard, "", 0)
	outputLog = log.New(ioutil.Discard, "", 0)
}

func writeToLog(log *log.Logger, addNewline bool, includeStack bool, msgs ...interface{}) {
	if log != nil {
		// Prefix message with repo root (this is cached for efficiency)
		// We don't add this to the Logger prefix in New() because this prefixes before the timestamp & other
		// flag-based fields, which means things don't line up nicely in the log
		root, _, _ := GetRepoRoot() // ignore failure, just use blank string
		buf := bytes.NewBufferString(fmt.Sprintf("[%v]: ", root))
		fmt.Fprint(buf, msgs...)
		if addNewline {
			buf.WriteString("\n")
		}
		log.Print(buf.String())
		if includeStack {
			log.Println(string(debug.Stack()))
		}
	}

}

// Log error to console and log with format (no implicit newline)
func LogErrorf(format string, v ...interface{}) {
	msg := fmt.Sprintf(format, v...)
	fmt.Fprint(consoleErr, msg)
	writeToLog(errorLog, false, true, msg)
}

// Log debug message to console and log with format (if verbose)
func LogDebugf(format string, v ...interface{}) {
	if GlobalOptions.Verbose {
		fmt.Fprintf(consoleOut, format, v...)
	}

	if GlobalOptions.VerboseLog {
		writeToLog(debugLog, false, false, fmt.Sprintf(format, v...))
	}

}

// Log output message to console and log with format (if not quiet)
// You probably don't want to use this since most info messages are for
// an interactive user only; see LogConsolef instead for that
func Logf(format string, v ...interface{}) {
	if !GlobalOptions.Quiet {
		msg := fmt.Sprintf(format, v...)
		fmt.Fprint(consoleOut, msg)
		writeToLog(outputLog, false, false, msg)
	}
}

// Log error message to console and log with newline & spaces in between
func LogError(msgs ...interface{}) {
	fmt.Fprintln(consoleErr, msgs...)
	writeToLog(errorLog, true, true, msgs...)
}

// Log debug message to console and log with newline (if verbose)
func LogDebug(msgs ...interface{}) {
	if GlobalOptions.Verbose {
		fmt.Fprintln(consoleOut, msgs...)
	}

	if GlobalOptions.VerboseLog {
		writeToLog(debugLog, true, false, msgs...)
	}
}

// Log output message to console and log with newline (if not quiet)
// You probably don't want to use this since most info messages are for
// an interactive user only; see LogConsole instead for that
func Log(msgs ...interface{}) {
	if !GlobalOptions.Quiet {
		fmt.Fprintln(consoleOut, msgs...)
		writeToLog(outputLog, true, false, msgs...)
	}
}

// Write an informational message to the console with newline (if not quiet), and not the log
func LogConsole(msgs ...interface{}) {
	if !GlobalOptions.Quiet {
		fmt.Fprintln(consoleOut, msgs...)
	}
}

// Overwrite the current line in the console (e.g. for progressive update), if not quiet
// Requires the previous line length so that it can clear it with spaces
// Does not add a newline after writing
func LogConsoleOverwrite(newString string, lastLineLength int) {
	if len(newString) < lastLineLength {
		LogConsolef("\r%v%v", newString, strings.Repeat(" ", lastLineLength-len(newString)))
	} else {
		LogConsolef("\r%v", newString)
	}

}

// Write an informational message to the console (if not quiet), and not the log
func LogConsolef(format string, v ...interface{}) {
	if !GlobalOptions.Quiet {
		fmt.Fprintf(consoleOut, format, v...)
	}
}

// Write an error message to the console with newline and not the log
func LogConsoleError(msgs ...interface{}) {
	fmt.Fprintln(consoleErr, msgs...)
}

// Write an error message to the console and not the log
func LogConsoleErrorf(format string, v ...interface{}) {
	fmt.Fprintf(consoleErr, format, v...)
}

// Write a debug message to the console with newline (if verbose), and not the log
func LogConsoleDebug(msgs ...interface{}) {
	if GlobalOptions.Verbose {
		fmt.Fprintln(consoleOut, msgs...)
	}
}

// Write a debug message to the console (if verbose), and not the log
func LogConsoleDebugf(format string, v ...interface{}) {
	if GlobalOptions.Verbose {
		fmt.Fprintf(consoleOut, format, v...)
	}
}

func getLogFileHandle() *os.File {
	var logFileName string
	if GlobalOptions.LogFile != "" {
		logFileName = GlobalOptions.LogFile
	} else {
		usr, err := user.Current()
		if err != nil {
			log.Fatal(err)
		}
		logFileName = filepath.Join(usr.HomeDir, "git-lob.log")
	}
	var err error
	logFile, err = os.OpenFile(logFileName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
	if err != nil {
		log.Fatal(err)
	}
	return logFile
}

// Initialise logging, make sure GlobalOptions is initialised
func InitLogging() {

	if GlobalOptions.LogEnabled {
		const logFlags = log.Ldate | log.Ltime | log.Lshortfile
		f := getLogFileHandle()
		outputLog = log.New(f, "", logFlags)
		errorLog = log.New(f, "ERROR: ", logFlags)
		debugLog = log.New(f, "", logFlags)
	}
}
func ShutDownLogging() {
	if logFile != nil {
		logFile.Close()
	}

}
<commit_msg>Remove source file from logging, actually useless since it always occurs in log.go anyway<commit_after>package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"runtime/debug"
	"strings"
)

var (
	// Console output (can be overridden by changing)
	consoleErr io.Writer = os.Stderr
	consoleOut io.Writer = os.Stdout
	// Loggers for file output
	debugLog  *log.Logger
	errorLog  *log.Logger
	outputLog *log.Logger
	logFile   *os.File
)

// Always send all console output to stderr, including info/debug messages
// This is mostly useful when stdout is reserved for piping content
func LogAllConsoleOutputToStdErr() {
	consoleOut = os.Stderr
	consoleErr = os.Stderr
}

// Suppress all console output
func LogSuppressAllConsoleOutput() {
	consoleOut = ioutil.Discard
	consoleErr = ioutil.Discard
	errorLog = log.New(ioutil.Discard, "", 0)
	debugLog = log.New(ioutil.Discard, "", 0)
	outputLog = log.New(ioutil.Discard, "", 0)
}

func writeToLog(log *log.Logger, addNewline bool, includeStack bool, msgs ...interface{}) {
	if log != nil {
		// Prefix message with repo root (this is cached for efficiency)
		// We don't add this to the Logger prefix in New() because this prefixes before the timestamp & other
		// flag-based fields, which means things don't line up nicely in the log
		root, _, _ := GetRepoRoot() // ignore failure, just use blank string
		buf := bytes.NewBufferString(fmt.Sprintf("[%v]: ", root))
		fmt.Fprint(buf, msgs...)
		if addNewline {
			buf.WriteString("\n")
		}
		log.Print(buf.String())
		if includeStack {
			log.Println(string(debug.Stack()))
		}
	}

}

// Log error to console and log with format (no implicit newline)
func LogErrorf(format string, v ...interface{}) {
	msg := fmt.Sprintf(format, v...)
	fmt.Fprint(consoleErr, msg)
	writeToLog(errorLog, false, true, msg)
}

// Log debug message to console and log with format (if verbose)
func LogDebugf(format string, v ...interface{}) {
	if GlobalOptions.Verbose {
		fmt.Fprintf(consoleOut, format, v...)
	}

	if GlobalOptions.VerboseLog {
		writeToLog(debugLog, false, false, fmt.Sprintf(format, v...))
	}

}

// Log output message to console and log with format (if not quiet)
// You probably don't want to use this since most info messages are for
// an interactive user only; see LogConsolef instead for that
func Logf(format string, v ...interface{}) {
	if !GlobalOptions.Quiet {
		msg := fmt.Sprintf(format, v...)
		fmt.Fprint(consoleOut, msg)
		writeToLog(outputLog, false, false, msg)
	}
}

// Log error message to console and log with newline & spaces in between
func LogError(msgs ...interface{}) {
	fmt.Fprintln(consoleErr, msgs...)
	writeToLog(errorLog, true, true, msgs...)
}

// Log debug message to console and log with newline (if verbose)
func LogDebug(msgs ...interface{}) {
	if GlobalOptions.Verbose {
		fmt.Fprintln(consoleOut, msgs...)
	}

	if GlobalOptions.VerboseLog {
		writeToLog(debugLog, true, false, msgs...)
	}
}

// Log output message to console and log with newline (if not quiet)
// You probably don't want to use this since most info messages are for
// an interactive user only; see LogConsole instead for that
func Log(msgs ...interface{}) {
	if !GlobalOptions.Quiet {
		fmt.Fprintln(consoleOut, msgs...)
		writeToLog(outputLog, true, false, msgs...)
	}
}

// Write an informational message to the console with newline (if not quiet), and not the log
func LogConsole(msgs ...interface{}) {
	if !GlobalOptions.Quiet {
		fmt.Fprintln(consoleOut, msgs...)
	}
}

// Overwrite the current line in the console (e.g. for progressive update), if not quiet
// Requires the previous line length so that it can clear it with spaces
// Does not add a newline after writing
func LogConsoleOverwrite(newString string, lastLineLength int) {
	if len(newString) < lastLineLength {
		LogConsolef("\r%v%v", newString, strings.Repeat(" ", lastLineLength-len(newString)))
	} else {
		LogConsolef("\r%v", newString)
	}

}

// Write an informational message to the console (if not quiet), and not the log
func LogConsolef(format string, v ...interface{}) {
	if !GlobalOptions.Quiet {
		fmt.Fprintf(consoleOut, format, v...)
	}
}

// Write an error message to the console with newline and not the log
func LogConsoleError(msgs ...interface{}) {
	fmt.Fprintln(consoleErr, msgs...)
}

// Write an error message to the console and not the log
func LogConsoleErrorf(format string, v ...interface{}) {
	fmt.Fprintf(consoleErr, format, v...)
}

// Write a debug message to the console with newline (if verbose), and not the log
func LogConsoleDebug(msgs ...interface{}) {
	if GlobalOptions.Verbose {
		fmt.Fprintln(consoleOut, msgs...)
	}
}

// Write a debug message to the console (if verbose), and not the log
func LogConsoleDebugf(format string, v ...interface{}) {
	if GlobalOptions.Verbose {
		fmt.Fprintf(consoleOut, format, v...)
	}
}

func getLogFileHandle() *os.File {
	var logFileName string
	if GlobalOptions.LogFile != "" {
		logFileName = GlobalOptions.LogFile
	} else {
		usr, err := user.Current()
		if err != nil {
			log.Fatal(err)
		}
		logFileName = filepath.Join(usr.HomeDir, "git-lob.log")
	}
	var err error
	logFile, err = os.OpenFile(logFileName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
	if err != nil {
		log.Fatal(err)
	}
	return logFile
}

// Initialise logging, make sure GlobalOptions is initialised
func InitLogging() {

	if GlobalOptions.LogEnabled {
		const logFlags = log.Ldate | log.Ltime
		f := getLogFileHandle()
		outputLog = log.New(f, "", logFlags)
		errorLog = log.New(f, "ERROR: ", logFlags)
		debugLog = log.New(f, "", logFlags)
	}
}
func ShutDownLogging() {
	if logFile != nil {
		logFile.Close()
	}

}
<|endoftext|>


<commit_before>//  ---------------------------------------------------------------------------
//
//  log.go
//
//  Copyright (c) 2015, Jared Chavez.
//  All rights reserved.
//
//  Use of this source code is governed by a BSD-style
//  license that can be found in the LICENSE file.
//
//  -----------

// Package log provides interfaces, basic types and formatting helpers
// for common application logging tasks.
package log

import (
	"bytes"
	"container/ring"
	"encoding/json"
	"fmt"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"
)

var timeFormat = "2006/01/02 15:04:05.0000"

type DebugLogger interface {
	Debug(format string, v ...interface{})
}

type ErrorLogger interface {
	Error(format string, v ...interface{})
}

type InfoLogger interface {
	Info(format string, v ...interface{})
}

type LogMsg struct {
	Timestamp time.Time
	Name      string
	File      string
	Line      int
	Message   string
}

func (this *LogMsg) String() string {
	var buffer bytes.Buffer

	if this.File != "" {
		buffer.WriteString(" <")
		buffer.WriteString(this.File)
		if this.Line != 0 {
			buffer.WriteString(fmt.Sprintf(":%d", this.Line))
		}
		buffer.WriteString("> ")
	}

	if this.Message[len(this.Message)-1] == '\n' {
		return fmt.Sprintf(
			"%s [%s]%s %s",
			this.Timestamp.Format(timeFormat),
			strings.ToUpper(this.Name),
			buffer.String(),
			this.Message,
		)
	}

	return fmt.Sprintf(
		"%s [%s]%s %s\n",
		this.Timestamp.Format(timeFormat),
		strings.ToUpper(this.Name),
		buffer.String(),
		this.Message,
	)
}

// LogCloser represents the interface for a closable log object, such
// as those provided by file-backed logging.
type LogCloser interface {
	Close()
}

// Log represents the interface for a generalized log object.
type LogNotify interface {
	Print(msg *LogMsg)
}

// LogToggler represents the interface needed to temporarily enabled/disable
// a given logger.
type LogToggler interface {
	SetEnabled(bool)
}

// LogBuffer holds a specified number of logs in memory for rendering
// by the http logs Uri.
type LogBuffer struct {
	changed bool
	enabled bool
	lock    sync.RWMutex
	logs    *ring.Ring
}

// NewLogBuffer returns a pointer to a new LogBuffer instance.
func NewLogBuffer(maxSize int) *LogBuffer {
	logBuffer := &LogBuffer{
		enabled: true,
		logs:    ring.New(maxSize),
	}

	return logBuffer
}

// HasChanged reports whether or not the buffer has been modified
// since it was last read.
func (this *LogBuffer) HasChanged() bool {
	this.lock.RLock()
	defer this.lock.RUnlock()

	return this.changed
}

// Print formats and adds a new message to the log buffer. If the new
// message causes the log buffer to grow larger than its maxSize, it
// truncates the end oldest entry in the buffer. Once the message is
// stored, the changed flag is set to true.
func (this *LogBuffer) Print(msg *LogMsg) {
	this.lock.Lock()
	defer this.lock.Unlock()

	if !this.enabled {
		return
	}

	this.logs.Value = msg
	this.logs = this.logs.Next()

	this.changed = true
}

// ReadAll returns a list of all log messages currently in the buffer.
func (this *LogBuffer) ReadAll() []*LogMsg {
	this.lock.RLock()
	defer this.lock.RUnlock()

	results := make([]*LogMsg, 0, this.logs.Len())
	this.logs.Do(func(item interface{}) {
		if item == nil {
			return
		}

		results = append(results, item.(*LogMsg))
	})

	this.changed = false

	return results
}

// MarshalJSON implements the standard go json marshaler for the
// LogBuffer type.
func (this *LogBuffer) MarshalJSON() ([]byte, error) {
	this.lock.RLock()
	defer this.lock.RUnlock()

	results := make([]*LogMsg, 0, this.logs.Len())
	this.logs.Do(func(item interface{}) {
		if item == nil {
			return
		}

		results = append(results, item.(*LogMsg))
	})

	return json.Marshal(&results)
}

// SetEnabled temporarily enables/disables the logger.
func (this *LogBuffer) SetEnabled(enabled bool) {
	this.lock.Lock()
	defer this.lock.Unlock()

	this.enabled = enabled
}

// NewLogMsg generates a log object given the standard logging format
// yyyy/mm/dd MM:HH:SS.ssssss [NAME] <file:line> msg
func NewLogMsg(name, format string, callDepth int, v ...interface{}) *LogMsg {
	var msg string
	if len(v) < 1 {
		msg = format
	} else {
		msg = fmt.Sprintf(format, v...)
	}

	newLog := &LogMsg{
		Timestamp: time.Now(),
		Name:      name,
		Message:   msg,
	}

	_, file, line, ok := runtime.Caller(callDepth)
	if ok {
		newLog.File = filepath.Base(file)
		newLog.Line = line
	}

	return newLog
}
<commit_msg>truncate log messages that are getting too long<commit_after>//  ---------------------------------------------------------------------------
//
//  log.go
//
//  Copyright (c) 2015, Jared Chavez.
//  All rights reserved.
//
//  Use of this source code is governed by a BSD-style
//  license that can be found in the LICENSE file.
//
//  -----------

// Package log provides interfaces, basic types and formatting helpers
// for common application logging tasks.
package log

import (
	"bytes"
	"container/ring"
	"encoding/json"
	"fmt"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"
)

const maxLogLineLen = 1024

var timeFormat = "2006/01/02 15:04:05.0000"

type DebugLogger interface {
	Debug(format string, v ...interface{})
}

type ErrorLogger interface {
	Error(format string, v ...interface{})
}

type InfoLogger interface {
	Info(format string, v ...interface{})
}

type LogMsg struct {
	Timestamp time.Time
	Name      string
	File      string
	Line      int
	Message   string
}

func (this *LogMsg) String() string {
	var buffer bytes.Buffer

	if this.File != "" {
		buffer.WriteString(" <")
		buffer.WriteString(this.File)
		if this.Line != 0 {
			buffer.WriteString(fmt.Sprintf(":%d", this.Line))
		}
		buffer.WriteString("> ")
	}

	if this.Message[len(this.Message)-1] == '\n' {
		return fmt.Sprintf(
			"%s [%s]%s %s",
			this.Timestamp.Format(timeFormat),
			strings.ToUpper(this.Name),
			buffer.String(),
			this.Message,
		)
	}

	return fmt.Sprintf(
		"%s [%s]%s %s\n",
		this.Timestamp.Format(timeFormat),
		strings.ToUpper(this.Name),
		buffer.String(),
		this.Message,
	)
}

// LogCloser represents the interface for a closable log object, such
// as those provided by file-backed logging.
type LogCloser interface {
	Close()
}

// Log represents the interface for a generalized log object.
type LogNotify interface {
	Print(msg *LogMsg)
}

// LogToggler represents the interface needed to temporarily enabled/disable
// a given logger.
type LogToggler interface {
	SetEnabled(bool)
}

// LogBuffer holds a specified number of logs in memory for rendering
// by the http logs Uri.
type LogBuffer struct {
	changed bool
	enabled bool
	lock    sync.RWMutex
	logs    *ring.Ring
}

// NewLogBuffer returns a pointer to a new LogBuffer instance.
func NewLogBuffer(maxSize int) *LogBuffer {
	logBuffer := &LogBuffer{
		enabled: true,
		logs:    ring.New(maxSize),
	}

	return logBuffer
}

// HasChanged reports whether or not the buffer has been modified
// since it was last read.
func (this *LogBuffer) HasChanged() bool {
	this.lock.RLock()
	defer this.lock.RUnlock()

	return this.changed
}

// Print formats and adds a new message to the log buffer. If the new
// message causes the log buffer to grow larger than its maxSize, it
// truncates the end oldest entry in the buffer. Once the message is
// stored, the changed flag is set to true.
func (this *LogBuffer) Print(msg *LogMsg) {
	this.lock.Lock()
	defer this.lock.Unlock()

	if !this.enabled {
		return
	}

	this.logs.Value = msg
	this.logs = this.logs.Next()

	this.changed = true
}

// ReadAll returns a list of all log messages currently in the buffer.
func (this *LogBuffer) ReadAll() []*LogMsg {
	this.lock.RLock()
	defer this.lock.RUnlock()

	results := make([]*LogMsg, 0, this.logs.Len())
	this.logs.Do(func(item interface{}) {
		if item == nil {
			return
		}

		results = append(results, item.(*LogMsg))
	})

	this.changed = false

	return results
}

// MarshalJSON implements the standard go json marshaler for the
// LogBuffer type.
func (this *LogBuffer) MarshalJSON() ([]byte, error) {
	this.lock.RLock()
	defer this.lock.RUnlock()

	results := make([]*LogMsg, 0, this.logs.Len())
	this.logs.Do(func(item interface{}) {
		if item == nil {
			return
		}

		results = append(results, item.(*LogMsg))
	})

	return json.Marshal(&results)
}

// SetEnabled temporarily enables/disables the logger.
func (this *LogBuffer) SetEnabled(enabled bool) {
	this.lock.Lock()
	defer this.lock.Unlock()

	this.enabled = enabled
}

// NewLogMsg generates a log object given the standard logging format
// yyyy/mm/dd MM:HH:SS.ssssss [NAME] <file:line> msg
func NewLogMsg(name, format string, callDepth int, v ...interface{}) *LogMsg {
	var msg string
	if len(v) < 1 {
		msg = format
	} else {
		msg = fmt.Sprintf(format, v...)
	}

	if len(msg) > maxLogLineLen {
		msg = fmt.Sprintf("%s ... (truncated)", msg[:maxLogLineLen])
	}

	newLog := &LogMsg{
		Timestamp: time.Now(),
		Name:      name,
		Message:   msg,
	}

	_, file, line, ok := runtime.Caller(callDepth)
	if ok {
		newLog.File = filepath.Base(file)
		newLog.Line = line
	}

	return newLog
}
<|endoftext|>


<commit_before>package capn

import (
	"bytes"
	"errors"
	"io"
	"math"
)

var (
	errBufferCall     = errors.New("capn: can't call on a memory buffer")
	ErrInvalidSegment = errors.New("capn: invalid segment id")
	ErrTooMuchData    = errors.New("capn: too much data in stream")
)

type buffer Segment

// NewBuffer creates an expanding single segment buffer. Creating new objects
// will expand the buffer. Data can be nil (or length 0 with some capacity) if
// creating a new session. If parsing an existing segment than data should be
// the segment contents and will not be copied.
func NewBuffer(data []byte) *Segment {
	if uint64(len(data)) > uint64(math.MaxUint32) {
		return nil
	}

	b := &buffer{}
	b.Message = b
	b.Data = data
	return (*Segment)(b)
}

func (b *buffer) NewSegment(minsz int) (*Segment, error) {
	if uint64(len(b.Data)) > uint64(math.MaxUint32-minsz) {
		return nil, ErrOverlarge
	}
	b.Data = append(b.Data, make([]byte, minsz)...)
	b.Data = b.Data[:len(b.Data)-minsz]
	return (*Segment)(b), nil
}

func (b *buffer) Lookup(segid uint32) (*Segment, error) {
	if segid == 0 {
		return (*Segment)(b), nil
	} else {
		return nil, ErrInvalidSegment
	}
}

type multiBuffer struct {
	segments []*Segment
}

// NewmultiBuffer creates a new multi segment message. Creating new objects
// will try and reuse the buffers available, but will create new ones if there
// is insufficient capacity. When parsing an existing message data should be
// the list of segments. The data buffers will not be copied.
func NewmultiBuffer(data [][]byte) *Segment {
	m := &multiBuffer{make([]*Segment, len(data))}
	for i, d := range data {
		m.segments[i] = &Segment{m, d, uint32(i)}
	}
	if len(data) > 0 {
		return m.segments[0]
	}
	return &Segment{m, nil, 0xFFFFFFFF}
}

var (
	MaxSegmentNumber = 1024
	MaxTotalSize     = 1024 * 1024 * 1024
)

func (m *multiBuffer) NewSegment(minsz int) (*Segment, error) {
	for _, s := range m.segments {
		if len(s.Data)+minsz <= cap(s.Data) {
			return s, nil
		}
	}

	if minsz < 4096 {
		minsz = 4096
	}
	s := &Segment{m, make([]byte, 0, minsz), uint32(len(m.segments))}
	m.segments = append(m.segments, s)
	return s, nil
}

func (m *multiBuffer) Lookup(segid uint32) (*Segment, error) {
	if uint(segid) < uint(len(m.segments)) {
		return m.segments[segid], nil
	} else {
		return nil, ErrInvalidSegment
	}
}

// ReadFromStream reads a non-packed serialized stream from r. buf is used to
// buffer the read contents, can be nil, and is provided so that the buffer
// can be reused between messages. The returned segment is the first segment
// read, which contains the root pointer.
func ReadFromStream(r io.Reader, buf *bytes.Buffer) (*Segment, error) {
	if buf == nil {
		buf = new(bytes.Buffer)
	} else {
		buf.Reset()
	}

	if _, err := io.CopyN(buf, r, 4); err != nil {
		return nil, err
	}

	if little32(buf.Bytes()[:]) >= uint32(MaxSegmentNumber) {
		return nil, ErrTooMuchData
	}

	segnum := int(little32(buf.Bytes()[:]) + 1)
	hdrsz := 8*(segnum/2) + 4

	if _, err := io.CopyN(buf, r, int64(hdrsz)); err != nil {
		return nil, err
	}

	total := 0
	for i := 0; i < segnum; i++ {
		sz := little32(buf.Bytes()[4*i+4:])
		if uint64(total)+uint64(sz)*8 > uint64(MaxTotalSize) {
			return nil, ErrTooMuchData
		}
		total += int(sz) * 8
	}

	if _, err := io.CopyN(buf, r, int64(total)); err != nil {
		return nil, err
	}

	hdrv := buf.Bytes()[4 : hdrsz+4]
	datav := buf.Bytes()[hdrsz+4:]
	m := &multiBuffer{make([]*Segment, segnum)}
	for i := 0; i < segnum; i++ {
		sz := int(little32(hdrv[4*i:])) * 8
		m.segments[i] = &Segment{m, datav[:sz], uint32(i)}
		datav = datav[sz:]
	}

	return m.segments[0], nil
}

// ReadFromMemoryZeroCopy: like ReadFromStream, but reads a non-packed
// serialized stream that already resides in memory in the argument data.
// The returned segment is the first segment read, which contains
// the root pointer. The returned bytesRead says how many bytes were
// consumed from data in making seg. The caller should advance the
// data slice by doing data = data[bytesRead:] between successive calls
// to ReadFromMemoryZeroCopy().
func ReadFromMemoryZeroCopy(data []byte) (seg *Segment, bytesRead int64, err error) {

	if len(data) < 4 {
		return nil, 0, io.EOF
	}

	if little32(data[0:4]) >= uint32(MaxSegmentNumber) {
		return nil, 0, ErrTooMuchData
	}

	segnum := int(little32(data[0:4]) + 1)
	hdrsz := 8*(segnum/2) + 4

	b := data[0:(hdrsz + 4)]

	total := 0
	for i := 0; i < segnum; i++ {
		sz := little32(b[4*i+4:])
		if uint64(total)+uint64(sz)*8 > uint64(MaxTotalSize) {
			return nil, 0, ErrTooMuchData
		}
		total += int(sz) * 8
	}
	if total == 0 {
		return nil, 0, io.EOF
	}

	hdrv := data[4:(hdrsz + 4)]
	datav := data[hdrsz+4:]
	m := &multiBuffer{make([]*Segment, segnum)}
	for i := 0; i < segnum; i++ {
		sz := int(little32(hdrv[4*i:])) * 8
		m.segments[i] = &Segment{m, datav[:sz], uint32(i)}
		datav = datav[sz:]
	}

	return m.segments[0], int64(4 + hdrsz + total), nil
}

// WriteTo writes the message that the segment is part of to the
// provided stream in serialized form.
func (s *Segment) WriteTo(w io.Writer) (int64, error) {
	segnum := uint32(1)
	for {
		if seg, _ := s.Message.Lookup(segnum); seg == nil {
			break
		}
		segnum++
	}

	hdrv := make([]uint8, 8*(segnum/2)+8)
	putLittle32(hdrv, segnum-1)
	for i := uint32(0); i < segnum; i++ {
		seg, _ := s.Message.Lookup(i)
		putLittle32(hdrv[4*i+4:], uint32(len(seg.Data)/8))
	}

	if n, err := w.Write(hdrv); err != nil {
		return int64(n), err
	}
	written := int64(len(hdrv))

	for i := uint32(0); i < segnum; i++ {
		seg, _ := s.Message.Lookup(i)
		if n, err := w.Write(seg.Data); err != nil {
			return written + int64(n), err
		} else {
			written += int64(n)
		}
	}

	return written, nil
}
<commit_msg>ReadFromStream fast path (less allocations) for single segment. gofmt.<commit_after>package capn

import (
	"bytes"
	"errors"
	"io"
	"math"
)

var (
	errBufferCall     = errors.New("capn: can't call on a memory buffer")
	ErrInvalidSegment = errors.New("capn: invalid segment id")
	ErrTooMuchData    = errors.New("capn: too much data in stream")
)

type buffer Segment

// NewBuffer creates an expanding single segment buffer. Creating new objects
// will expand the buffer. Data can be nil (or length 0 with some capacity) if
// creating a new session. If parsing an existing segment than data should be
// the segment contents and will not be copied.
func NewBuffer(data []byte) *Segment {
	if uint64(len(data)) > uint64(math.MaxUint32) {
		return nil
	}

	b := &buffer{}
	b.Message = b
	b.Data = data
	return (*Segment)(b)
}

func (b *buffer) NewSegment(minsz int) (*Segment, error) {
	if uint64(len(b.Data)) > uint64(math.MaxUint32-minsz) {
		return nil, ErrOverlarge
	}
	b.Data = append(b.Data, make([]byte, minsz)...)
	b.Data = b.Data[:len(b.Data)-minsz]
	return (*Segment)(b), nil
}

func (b *buffer) Lookup(segid uint32) (*Segment, error) {
	if segid == 0 {
		return (*Segment)(b), nil
	} else {
		return nil, ErrInvalidSegment
	}
}

type multiBuffer struct {
	segments []*Segment
}

// NewmultiBuffer creates a new multi segment message. Creating new objects
// will try and reuse the buffers available, but will create new ones if there
// is insufficient capacity. When parsing an existing message data should be
// the list of segments. The data buffers will not be copied.
func NewmultiBuffer(data [][]byte) *Segment {
	m := &multiBuffer{make([]*Segment, len(data))}
	for i, d := range data {
		m.segments[i] = &Segment{m, d, uint32(i)}
	}
	if len(data) > 0 {
		return m.segments[0]
	}
	return &Segment{m, nil, 0xFFFFFFFF}
}

var (
	MaxSegmentNumber = 1024
	MaxTotalSize     = 1024 * 1024 * 1024
)

func (m *multiBuffer) NewSegment(minsz int) (*Segment, error) {
	for _, s := range m.segments {
		if len(s.Data)+minsz <= cap(s.Data) {
			return s, nil
		}
	}

	if minsz < 4096 {
		minsz = 4096
	}
	s := &Segment{m, make([]byte, 0, minsz), uint32(len(m.segments))}
	m.segments = append(m.segments, s)
	return s, nil
}

func (m *multiBuffer) Lookup(segid uint32) (*Segment, error) {
	if uint(segid) < uint(len(m.segments)) {
		return m.segments[segid], nil
	} else {
		return nil, ErrInvalidSegment
	}
}

// ReadFromStream reads a non-packed serialized stream from r. buf is used to
// buffer the read contents, can be nil, and is provided so that the buffer
// can be reused between messages. The returned segment is the first segment
// read, which contains the root pointer.
func ReadFromStream(r io.Reader, buf *bytes.Buffer) (*Segment, error) {
	if buf == nil {
		buf = new(bytes.Buffer)
	} else {
		buf.Reset()
	}

	if _, err := io.CopyN(buf, r, 4); err != nil {
		return nil, err
	}

	if little32(buf.Bytes()[:]) >= uint32(MaxSegmentNumber) {
		return nil, ErrTooMuchData
	}

	segnum := int(little32(buf.Bytes()[:]) + 1)
	hdrsz := 8*(segnum/2) + 4

	if _, err := io.CopyN(buf, r, int64(hdrsz)); err != nil {
		return nil, err
	}

	total := 0
	for i := 0; i < segnum; i++ {
		sz := little32(buf.Bytes()[4*i+4:])
		if uint64(total)+uint64(sz)*8 > uint64(MaxTotalSize) {
			return nil, ErrTooMuchData
		}
		total += int(sz) * 8
	}

	if _, err := io.CopyN(buf, r, int64(total)); err != nil {
		return nil, err
	}

	hdrv := buf.Bytes()[4 : hdrsz+4]
	datav := buf.Bytes()[hdrsz+4:]

	if segnum == 1 {
		sz := int(little32(hdrv)) * 8
		return NewBuffer(datav[:sz]), nil
	}

	m := &multiBuffer{make([]*Segment, segnum)}
	for i := 0; i < segnum; i++ {
		sz := int(little32(hdrv[4*i:])) * 8
		m.segments[i] = &Segment{m, datav[:sz], uint32(i)}
		datav = datav[sz:]
	}

	return m.segments[0], nil
}

// ReadFromMemoryZeroCopy: like ReadFromStream, but reads a non-packed
// serialized stream that already resides in memory in the argument data.
// The returned segment is the first segment read, which contains
// the root pointer. The returned bytesRead says how many bytes were
// consumed from data in making seg. The caller should advance the
// data slice by doing data = data[bytesRead:] between successive calls
// to ReadFromMemoryZeroCopy().
func ReadFromMemoryZeroCopy(data []byte) (seg *Segment, bytesRead int64, err error) {

	if len(data) < 4 {
		return nil, 0, io.EOF
	}

	if little32(data[0:4]) >= uint32(MaxSegmentNumber) {
		return nil, 0, ErrTooMuchData
	}

	segnum := int(little32(data[0:4]) + 1)
	hdrsz := 8*(segnum/2) + 4

	b := data[0:(hdrsz + 4)]

	total := 0
	for i := 0; i < segnum; i++ {
		sz := little32(b[4*i+4:])
		if uint64(total)+uint64(sz)*8 > uint64(MaxTotalSize) {
			return nil, 0, ErrTooMuchData
		}
		total += int(sz) * 8
	}
	if total == 0 {
		return nil, 0, io.EOF
	}

	hdrv := data[4:(hdrsz + 4)]
	datav := data[hdrsz+4:]
	m := &multiBuffer{make([]*Segment, segnum)}
	for i := 0; i < segnum; i++ {
		sz := int(little32(hdrv[4*i:])) * 8
		m.segments[i] = &Segment{m, datav[:sz], uint32(i)}
		datav = datav[sz:]
	}

	return m.segments[0], int64(4 + hdrsz + total), nil
}

// WriteTo writes the message that the segment is part of to the
// provided stream in serialized form.
func (s *Segment) WriteTo(w io.Writer) (int64, error) {
	segnum := uint32(1)
	for {
		if seg, _ := s.Message.Lookup(segnum); seg == nil {
			break
		}
		segnum++
	}

	hdrv := make([]uint8, 8*(segnum/2)+8)
	putLittle32(hdrv, segnum-1)
	for i := uint32(0); i < segnum; i++ {
		seg, _ := s.Message.Lookup(i)
		putLittle32(hdrv[4*i+4:], uint32(len(seg.Data)/8))
	}

	if n, err := w.Write(hdrv); err != nil {
		return int64(n), err
	}
	written := int64(len(hdrv))

	for i := uint32(0); i < segnum; i++ {
		seg, _ := s.Message.Lookup(i)
		if n, err := w.Write(seg.Data); err != nil {
			return written + int64(n), err
		} else {
			written += int64(n)
		}
	}

	return written, nil
}
<|endoftext|>


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

//go:build darwin || dragonfly || freebsd || netbsd || openbsd
// +build darwin dragonfly freebsd netbsd openbsd

package route

import "runtime"

// An Addr represents an address associated with packet routing.
type Addr interface {
	// Family returns an address family.
	Family() int
}

// A LinkAddr represents a link-layer address.
type LinkAddr struct {
	Index int    // interface index when attached
	Name  string // interface name when attached
	Addr  []byte // link-layer address when attached
}

// Family implements the Family method of Addr interface.
func (a *LinkAddr) Family() int { return sysAF_LINK }

func (a *LinkAddr) lenAndSpace() (int, int) {
	l := 8 + len(a.Name) + len(a.Addr)
	return l, roundup(l)
}

func (a *LinkAddr) marshal(b []byte) (int, error) {
	l, ll := a.lenAndSpace()
	if len(b) < ll {
		return 0, errShortBuffer
	}
	nlen, alen := len(a.Name), len(a.Addr)
	if nlen > 255 || alen > 255 {
		return 0, errInvalidAddr
	}
	b[0] = byte(l)
	b[1] = sysAF_LINK
	if a.Index > 0 {
		nativeEndian.PutUint16(b[2:4], uint16(a.Index))
	}
	data := b[8:]
	if nlen > 0 {
		b[5] = byte(nlen)
		copy(data[:nlen], a.Name)
		data = data[nlen:]
	}
	if alen > 0 {
		b[6] = byte(alen)
		copy(data[:alen], a.Addr)
		data = data[alen:]
	}
	return ll, nil
}

func parseLinkAddr(b []byte) (Addr, error) {
	if len(b) < 8 {
		return nil, errInvalidAddr
	}
	_, a, err := parseKernelLinkAddr(sysAF_LINK, b[4:])
	if err != nil {
		return nil, err
	}
	a.(*LinkAddr).Index = int(nativeEndian.Uint16(b[2:4]))
	return a, nil
}

// parseKernelLinkAddr parses b as a link-layer address in
// conventional BSD kernel form.
func parseKernelLinkAddr(_ int, b []byte) (int, Addr, error) {
	// The encoding looks like the following:
	// +----------------------------+
	// | Type             (1 octet) |
	// +----------------------------+
	// | Name length      (1 octet) |
	// +----------------------------+
	// | Address length   (1 octet) |
	// +----------------------------+
	// | Selector length  (1 octet) |
	// +----------------------------+
	// | Data            (variable) |
	// +----------------------------+
	//
	// On some platforms, all-bit-one of length field means "don't
	// care".
	nlen, alen, slen := int(b[1]), int(b[2]), int(b[3])
	if nlen == 0xff {
		nlen = 0
	}
	if alen == 0xff {
		alen = 0
	}
	if slen == 0xff {
		slen = 0
	}
	l := 4 + nlen + alen + slen
	if len(b) < l {
		return 0, nil, errInvalidAddr
	}
	data := b[4:]
	var name string
	var addr []byte
	if nlen > 0 {
		name = string(data[:nlen])
		data = data[nlen:]
	}
	if alen > 0 {
		addr = data[:alen]
		data = data[alen:]
	}
	return l, &LinkAddr{Name: name, Addr: addr}, nil
}

// An Inet4Addr represents an internet address for IPv4.
type Inet4Addr struct {
	IP [4]byte // IP address
}

// Family implements the Family method of Addr interface.
func (a *Inet4Addr) Family() int { return sysAF_INET }

func (a *Inet4Addr) lenAndSpace() (int, int) {
	return sizeofSockaddrInet, roundup(sizeofSockaddrInet)
}

func (a *Inet4Addr) marshal(b []byte) (int, error) {
	l, ll := a.lenAndSpace()
	if len(b) < ll {
		return 0, errShortBuffer
	}
	b[0] = byte(l)
	b[1] = sysAF_INET
	copy(b[4:8], a.IP[:])
	return ll, nil
}

// An Inet6Addr represents an internet address for IPv6.
type Inet6Addr struct {
	IP     [16]byte // IP address
	ZoneID int      // zone identifier
}

// Family implements the Family method of Addr interface.
func (a *Inet6Addr) Family() int { return sysAF_INET6 }

func (a *Inet6Addr) lenAndSpace() (int, int) {
	return sizeofSockaddrInet6, roundup(sizeofSockaddrInet6)
}

func (a *Inet6Addr) marshal(b []byte) (int, error) {
	l, ll := a.lenAndSpace()
	if len(b) < ll {
		return 0, errShortBuffer
	}
	b[0] = byte(l)
	b[1] = sysAF_INET6
	copy(b[8:24], a.IP[:])
	if a.ZoneID > 0 {
		nativeEndian.PutUint32(b[24:28], uint32(a.ZoneID))
	}
	return ll, nil
}

// parseInetAddr parses b as an internet address for IPv4 or IPv6.
func parseInetAddr(af int, b []byte) (Addr, error) {
	switch af {
	case sysAF_INET:
		if len(b) < sizeofSockaddrInet {
			return nil, errInvalidAddr
		}
		a := &Inet4Addr{}
		copy(a.IP[:], b[4:8])
		return a, nil
	case sysAF_INET6:
		if len(b) < sizeofSockaddrInet6 {
			return nil, errInvalidAddr
		}
		a := &Inet6Addr{ZoneID: int(nativeEndian.Uint32(b[24:28]))}
		copy(a.IP[:], b[8:24])
		if a.IP[0] == 0xfe && a.IP[1]&0xc0 == 0x80 || a.IP[0] == 0xff && (a.IP[1]&0x0f == 0x01 || a.IP[1]&0x0f == 0x02) {
			// KAME based IPv6 protocol stack usually
			// embeds the interface index in the
			// interface-local or link-local address as
			// the kernel-internal form.
			id := int(bigEndian.Uint16(a.IP[2:4]))
			if id != 0 {
				a.ZoneID = id
				a.IP[2], a.IP[3] = 0, 0
			}
		}
		return a, nil
	default:
		return nil, errInvalidAddr
	}
}

// parseKernelInetAddr parses b as an internet address in conventional
// BSD kernel form.
func parseKernelInetAddr(af int, b []byte) (int, Addr, error) {
	// The encoding looks similar to the NLRI encoding.
	// +----------------------------+
	// | Length           (1 octet) |
	// +----------------------------+
	// | Address prefix  (variable) |
	// +----------------------------+
	//
	// The differences between the kernel form and the NLRI
	// encoding are:
	//
	// - The length field of the kernel form indicates the prefix
	//   length in bytes, not in bits
	//
	// - In the kernel form, zero value of the length field
	//   doesn't mean 0.0.0.0/0 or ::/0
	//
	// - The kernel form appends leading bytes to the prefix field
	//   to make the <length, prefix> tuple to be conformed with
	//   the routing message boundary
	l := int(b[0])
	if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
		// On Darwin, an address in the kernel form is also
		// used as a message filler.
		if l == 0 || len(b) > roundup(l) {
			l = roundup(l)
		}
	} else {
		l = roundup(l)
	}
	if len(b) < l {
		return 0, nil, errInvalidAddr
	}
	// Don't reorder case expressions.
	// The case expressions for IPv6 must come first.
	const (
		off4 = 4 // offset of in_addr
		off6 = 8 // offset of in6_addr
	)
	switch {
	case b[0] == sizeofSockaddrInet6:
		a := &Inet6Addr{}
		copy(a.IP[:], b[off6:off6+16])
		return int(b[0]), a, nil
	case af == sysAF_INET6:
		a := &Inet6Addr{}
		if l-1 < off6 {
			copy(a.IP[:], b[1:l])
		} else {
			copy(a.IP[:], b[l-off6:l])
		}
		return int(b[0]), a, nil
	case b[0] == sizeofSockaddrInet:
		a := &Inet4Addr{}
		copy(a.IP[:], b[off4:off4+4])
		return int(b[0]), a, nil
	default: // an old fashion, AF_UNSPEC or unknown means AF_INET
		a := &Inet4Addr{}
		if l-1 < off4 {
			copy(a.IP[:], b[1:l])
		} else {
			copy(a.IP[:], b[l-off4:l])
		}
		return int(b[0]), a, nil
	}
}

// A DefaultAddr represents an address of various operating
// system-specific features.
type DefaultAddr struct {
	af  int
	Raw []byte // raw format of address
}

// Family implements the Family method of Addr interface.
func (a *DefaultAddr) Family() int { return a.af }

func (a *DefaultAddr) lenAndSpace() (int, int) {
	l := len(a.Raw)
	return l, roundup(l)
}

func (a *DefaultAddr) marshal(b []byte) (int, error) {
	l, ll := a.lenAndSpace()
	if len(b) < ll {
		return 0, errShortBuffer
	}
	if l > 255 {
		return 0, errInvalidAddr
	}
	b[1] = byte(l)
	copy(b[:l], a.Raw)
	return ll, nil
}

func parseDefaultAddr(b []byte) (Addr, error) {
	if len(b) < 2 || len(b) < int(b[0]) {
		return nil, errInvalidAddr
	}
	a := &DefaultAddr{af: int(b[1]), Raw: b[:b[0]]}
	return a, nil
}

func addrsSpace(as []Addr) int {
	var l int
	for _, a := range as {
		switch a := a.(type) {
		case *LinkAddr:
			_, ll := a.lenAndSpace()
			l += ll
		case *Inet4Addr:
			_, ll := a.lenAndSpace()
			l += ll
		case *Inet6Addr:
			_, ll := a.lenAndSpace()
			l += ll
		case *DefaultAddr:
			_, ll := a.lenAndSpace()
			l += ll
		}
	}
	return l
}

// marshalAddrs marshals as and returns a bitmap indicating which
// address is stored in b.
func marshalAddrs(b []byte, as []Addr) (uint, error) {
	var attrs uint
	for i, a := range as {
		switch a := a.(type) {
		case *LinkAddr:
			l, err := a.marshal(b)
			if err != nil {
				return 0, err
			}
			b = b[l:]
			attrs |= 1 << uint(i)
		case *Inet4Addr:
			l, err := a.marshal(b)
			if err != nil {
				return 0, err
			}
			b = b[l:]
			attrs |= 1 << uint(i)
		case *Inet6Addr:
			l, err := a.marshal(b)
			if err != nil {
				return 0, err
			}
			b = b[l:]
			attrs |= 1 << uint(i)
		case *DefaultAddr:
			l, err := a.marshal(b)
			if err != nil {
				return 0, err
			}
			b = b[l:]
			attrs |= 1 << uint(i)
		}
	}
	return attrs, nil
}

func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) ([]Addr, error) {
	var as [sysRTAX_MAX]Addr
	af := int(sysAF_UNSPEC)
	for i := uint(0); i < sysRTAX_MAX && len(b) >= roundup(0); i++ {
		if attrs&(1<<i) == 0 {
			continue
		}
		if i <= sysRTAX_BRD {
			switch b[1] {
			case sysAF_LINK:
				a, err := parseLinkAddr(b)
				if err != nil {
					return nil, err
				}
				as[i] = a
				l := roundup(int(b[0]))
				if len(b) < l {
					return nil, errMessageTooShort
				}
				b = b[l:]
			case sysAF_INET, sysAF_INET6:
				af = int(b[1])
				a, err := parseInetAddr(af, b)
				if err != nil {
					return nil, err
				}
				as[i] = a
				l := roundup(int(b[0]))
				if len(b) < l {
					return nil, errMessageTooShort
				}
				b = b[l:]
			default:
				l, a, err := fn(af, b)
				if err != nil {
					return nil, err
				}
				as[i] = a
				ll := roundup(l)
				if len(b) < ll {
					b = b[l:]
				} else {
					b = b[ll:]
				}
			}
		} else {
			a, err := parseDefaultAddr(b)
			if err != nil {
				return nil, err
			}
			as[i] = a
			l := roundup(int(b[0]))
			if len(b) < l {
				return nil, errMessageTooShort
			}
			b = b[l:]
		}
	}
	if len(b) > 4 {
		// If there is more data left over after parsing all addresses
		// than might be needed for alignment, then we have made a mistake
		// somewhere.
		return nil, errInvalidMessage
	}
	return as[:], nil
}
<commit_msg>route: remove check for unparsed route message bytes<commit_after>// Copyright 2016 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.

//go:build darwin || dragonfly || freebsd || netbsd || openbsd
// +build darwin dragonfly freebsd netbsd openbsd

package route

import "runtime"

// An Addr represents an address associated with packet routing.
type Addr interface {
	// Family returns an address family.
	Family() int
}

// A LinkAddr represents a link-layer address.
type LinkAddr struct {
	Index int    // interface index when attached
	Name  string // interface name when attached
	Addr  []byte // link-layer address when attached
}

// Family implements the Family method of Addr interface.
func (a *LinkAddr) Family() int { return sysAF_LINK }

func (a *LinkAddr) lenAndSpace() (int, int) {
	l := 8 + len(a.Name) + len(a.Addr)
	return l, roundup(l)
}

func (a *LinkAddr) marshal(b []byte) (int, error) {
	l, ll := a.lenAndSpace()
	if len(b) < ll {
		return 0, errShortBuffer
	}
	nlen, alen := len(a.Name), len(a.Addr)
	if nlen > 255 || alen > 255 {
		return 0, errInvalidAddr
	}
	b[0] = byte(l)
	b[1] = sysAF_LINK
	if a.Index > 0 {
		nativeEndian.PutUint16(b[2:4], uint16(a.Index))
	}
	data := b[8:]
	if nlen > 0 {
		b[5] = byte(nlen)
		copy(data[:nlen], a.Name)
		data = data[nlen:]
	}
	if alen > 0 {
		b[6] = byte(alen)
		copy(data[:alen], a.Addr)
		data = data[alen:]
	}
	return ll, nil
}

func parseLinkAddr(b []byte) (Addr, error) {
	if len(b) < 8 {
		return nil, errInvalidAddr
	}
	_, a, err := parseKernelLinkAddr(sysAF_LINK, b[4:])
	if err != nil {
		return nil, err
	}
	a.(*LinkAddr).Index = int(nativeEndian.Uint16(b[2:4]))
	return a, nil
}

// parseKernelLinkAddr parses b as a link-layer address in
// conventional BSD kernel form.
func parseKernelLinkAddr(_ int, b []byte) (int, Addr, error) {
	// The encoding looks like the following:
	// +----------------------------+
	// | Type             (1 octet) |
	// +----------------------------+
	// | Name length      (1 octet) |
	// +----------------------------+
	// | Address length   (1 octet) |
	// +----------------------------+
	// | Selector length  (1 octet) |
	// +----------------------------+
	// | Data            (variable) |
	// +----------------------------+
	//
	// On some platforms, all-bit-one of length field means "don't
	// care".
	nlen, alen, slen := int(b[1]), int(b[2]), int(b[3])
	if nlen == 0xff {
		nlen = 0
	}
	if alen == 0xff {
		alen = 0
	}
	if slen == 0xff {
		slen = 0
	}
	l := 4 + nlen + alen + slen
	if len(b) < l {
		return 0, nil, errInvalidAddr
	}
	data := b[4:]
	var name string
	var addr []byte
	if nlen > 0 {
		name = string(data[:nlen])
		data = data[nlen:]
	}
	if alen > 0 {
		addr = data[:alen]
		data = data[alen:]
	}
	return l, &LinkAddr{Name: name, Addr: addr}, nil
}

// An Inet4Addr represents an internet address for IPv4.
type Inet4Addr struct {
	IP [4]byte // IP address
}

// Family implements the Family method of Addr interface.
func (a *Inet4Addr) Family() int { return sysAF_INET }

func (a *Inet4Addr) lenAndSpace() (int, int) {
	return sizeofSockaddrInet, roundup(sizeofSockaddrInet)
}

func (a *Inet4Addr) marshal(b []byte) (int, error) {
	l, ll := a.lenAndSpace()
	if len(b) < ll {
		return 0, errShortBuffer
	}
	b[0] = byte(l)
	b[1] = sysAF_INET
	copy(b[4:8], a.IP[:])
	return ll, nil
}

// An Inet6Addr represents an internet address for IPv6.
type Inet6Addr struct {
	IP     [16]byte // IP address
	ZoneID int      // zone identifier
}

// Family implements the Family method of Addr interface.
func (a *Inet6Addr) Family() int { return sysAF_INET6 }

func (a *Inet6Addr) lenAndSpace() (int, int) {
	return sizeofSockaddrInet6, roundup(sizeofSockaddrInet6)
}

func (a *Inet6Addr) marshal(b []byte) (int, error) {
	l, ll := a.lenAndSpace()
	if len(b) < ll {
		return 0, errShortBuffer
	}
	b[0] = byte(l)
	b[1] = sysAF_INET6
	copy(b[8:24], a.IP[:])
	if a.ZoneID > 0 {
		nativeEndian.PutUint32(b[24:28], uint32(a.ZoneID))
	}
	return ll, nil
}

// parseInetAddr parses b as an internet address for IPv4 or IPv6.
func parseInetAddr(af int, b []byte) (Addr, error) {
	switch af {
	case sysAF_INET:
		if len(b) < sizeofSockaddrInet {
			return nil, errInvalidAddr
		}
		a := &Inet4Addr{}
		copy(a.IP[:], b[4:8])
		return a, nil
	case sysAF_INET6:
		if len(b) < sizeofSockaddrInet6 {
			return nil, errInvalidAddr
		}
		a := &Inet6Addr{ZoneID: int(nativeEndian.Uint32(b[24:28]))}
		copy(a.IP[:], b[8:24])
		if a.IP[0] == 0xfe && a.IP[1]&0xc0 == 0x80 || a.IP[0] == 0xff && (a.IP[1]&0x0f == 0x01 || a.IP[1]&0x0f == 0x02) {
			// KAME based IPv6 protocol stack usually
			// embeds the interface index in the
			// interface-local or link-local address as
			// the kernel-internal form.
			id := int(bigEndian.Uint16(a.IP[2:4]))
			if id != 0 {
				a.ZoneID = id
				a.IP[2], a.IP[3] = 0, 0
			}
		}
		return a, nil
	default:
		return nil, errInvalidAddr
	}
}

// parseKernelInetAddr parses b as an internet address in conventional
// BSD kernel form.
func parseKernelInetAddr(af int, b []byte) (int, Addr, error) {
	// The encoding looks similar to the NLRI encoding.
	// +----------------------------+
	// | Length           (1 octet) |
	// +----------------------------+
	// | Address prefix  (variable) |
	// +----------------------------+
	//
	// The differences between the kernel form and the NLRI
	// encoding are:
	//
	// - The length field of the kernel form indicates the prefix
	//   length in bytes, not in bits
	//
	// - In the kernel form, zero value of the length field
	//   doesn't mean 0.0.0.0/0 or ::/0
	//
	// - The kernel form appends leading bytes to the prefix field
	//   to make the <length, prefix> tuple to be conformed with
	//   the routing message boundary
	l := int(b[0])
	if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
		// On Darwin, an address in the kernel form is also
		// used as a message filler.
		if l == 0 || len(b) > roundup(l) {
			l = roundup(l)
		}
	} else {
		l = roundup(l)
	}
	if len(b) < l {
		return 0, nil, errInvalidAddr
	}
	// Don't reorder case expressions.
	// The case expressions for IPv6 must come first.
	const (
		off4 = 4 // offset of in_addr
		off6 = 8 // offset of in6_addr
	)
	switch {
	case b[0] == sizeofSockaddrInet6:
		a := &Inet6Addr{}
		copy(a.IP[:], b[off6:off6+16])
		return int(b[0]), a, nil
	case af == sysAF_INET6:
		a := &Inet6Addr{}
		if l-1 < off6 {
			copy(a.IP[:], b[1:l])
		} else {
			copy(a.IP[:], b[l-off6:l])
		}
		return int(b[0]), a, nil
	case b[0] == sizeofSockaddrInet:
		a := &Inet4Addr{}
		copy(a.IP[:], b[off4:off4+4])
		return int(b[0]), a, nil
	default: // an old fashion, AF_UNSPEC or unknown means AF_INET
		a := &Inet4Addr{}
		if l-1 < off4 {
			copy(a.IP[:], b[1:l])
		} else {
			copy(a.IP[:], b[l-off4:l])
		}
		return int(b[0]), a, nil
	}
}

// A DefaultAddr represents an address of various operating
// system-specific features.
type DefaultAddr struct {
	af  int
	Raw []byte // raw format of address
}

// Family implements the Family method of Addr interface.
func (a *DefaultAddr) Family() int { return a.af }

func (a *DefaultAddr) lenAndSpace() (int, int) {
	l := len(a.Raw)
	return l, roundup(l)
}

func (a *DefaultAddr) marshal(b []byte) (int, error) {
	l, ll := a.lenAndSpace()
	if len(b) < ll {
		return 0, errShortBuffer
	}
	if l > 255 {
		return 0, errInvalidAddr
	}
	b[1] = byte(l)
	copy(b[:l], a.Raw)
	return ll, nil
}

func parseDefaultAddr(b []byte) (Addr, error) {
	if len(b) < 2 || len(b) < int(b[0]) {
		return nil, errInvalidAddr
	}
	a := &DefaultAddr{af: int(b[1]), Raw: b[:b[0]]}
	return a, nil
}

func addrsSpace(as []Addr) int {
	var l int
	for _, a := range as {
		switch a := a.(type) {
		case *LinkAddr:
			_, ll := a.lenAndSpace()
			l += ll
		case *Inet4Addr:
			_, ll := a.lenAndSpace()
			l += ll
		case *Inet6Addr:
			_, ll := a.lenAndSpace()
			l += ll
		case *DefaultAddr:
			_, ll := a.lenAndSpace()
			l += ll
		}
	}
	return l
}

// marshalAddrs marshals as and returns a bitmap indicating which
// address is stored in b.
func marshalAddrs(b []byte, as []Addr) (uint, error) {
	var attrs uint
	for i, a := range as {
		switch a := a.(type) {
		case *LinkAddr:
			l, err := a.marshal(b)
			if err != nil {
				return 0, err
			}
			b = b[l:]
			attrs |= 1 << uint(i)
		case *Inet4Addr:
			l, err := a.marshal(b)
			if err != nil {
				return 0, err
			}
			b = b[l:]
			attrs |= 1 << uint(i)
		case *Inet6Addr:
			l, err := a.marshal(b)
			if err != nil {
				return 0, err
			}
			b = b[l:]
			attrs |= 1 << uint(i)
		case *DefaultAddr:
			l, err := a.marshal(b)
			if err != nil {
				return 0, err
			}
			b = b[l:]
			attrs |= 1 << uint(i)
		}
	}
	return attrs, nil
}

func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) ([]Addr, error) {
	var as [sysRTAX_MAX]Addr
	af := int(sysAF_UNSPEC)
	for i := uint(0); i < sysRTAX_MAX && len(b) >= roundup(0); i++ {
		if attrs&(1<<i) == 0 {
			continue
		}
		if i <= sysRTAX_BRD {
			switch b[1] {
			case sysAF_LINK:
				a, err := parseLinkAddr(b)
				if err != nil {
					return nil, err
				}
				as[i] = a
				l := roundup(int(b[0]))
				if len(b) < l {
					return nil, errMessageTooShort
				}
				b = b[l:]
			case sysAF_INET, sysAF_INET6:
				af = int(b[1])
				a, err := parseInetAddr(af, b)
				if err != nil {
					return nil, err
				}
				as[i] = a
				l := roundup(int(b[0]))
				if len(b) < l {
					return nil, errMessageTooShort
				}
				b = b[l:]
			default:
				l, a, err := fn(af, b)
				if err != nil {
					return nil, err
				}
				as[i] = a
				ll := roundup(l)
				if len(b) < ll {
					b = b[l:]
				} else {
					b = b[ll:]
				}
			}
		} else {
			a, err := parseDefaultAddr(b)
			if err != nil {
				return nil, err
			}
			as[i] = a
			l := roundup(int(b[0]))
			if len(b) < l {
				return nil, errMessageTooShort
			}
			b = b[l:]
		}
	}
	// The only remaining bytes in b should be alignment.
	// However, under some circumstances DragonFly BSD appears to put
	// more addresses in the message than are indicated in the address
	// bitmask, so don't check for this.
	return as[:], nil
}
<|endoftext|>