<commit_before>package conf

import (
	"log"
	"os"
	"path"
	"reflect"
	"runtime"

	"net"
	"time"

	"github.com/spf13/viper"
)

const (
	tagName = "default"

	defaultConfigFilename       = "cps.conf"
	defaultDataDirname          = "data"
	defaultLogLevel             = "info"
	defaultLogDirname           = "logs"
	defaultLogFilename          = "btcd.log"
	defaultMaxPeers             = 125
	defaultBanDuration          = time.Hour * 24
	defaultBanThreshold         = 100
	defaultConnectTimeout       = time.Second * 30
	defaultMaxRPCClients        = 10
	defaultMaxRPCWebsockets     = 25
	defaultMaxRPCConcurrentReqs = 20
	defaultDbType               = "ffldb"
	defaultFreeTxRelayLimit     = 15.0
	defaultBlockMinSize         = 0
	defaultBlockMaxSize         = 750000
	defaultBlockMinWeight       = 0
	defaultBlockMaxWeight       = 3000000
	blockMaxSizeMin             = 1000
	blockMaxWeightMin           = 4000
	// blockMaxSizeMax              = blockchain.MaxBlockBaseSize - 1000
	// blockMaxWeightMax            = blockchain.MaxBlockWeight - 4000
	defaultGenerate              = false
	defaultMaxOrphanTransactions = 100
	defaultMaxOrphanTxSize       = 100000
	defaultSigCacheMaxSize       = 100000
	sampleConfigFilename         = "sample-btcd.conf"
	defaultTxIndex               = false
	defaultAddrIndex             = false
)

var Cfg *Configuration

// init configuration
func initConfig() *Configuration {
	config := &Configuration{}
	viper.SetEnvPrefix("copernicus")
	viper.AutomaticEnv()
	viper.SetConfigType("yaml")

	// find out where the sample config lives
	_, filename, _, ok := runtime.Caller(0)
	if !ok {
		panic("get current file path failed.")
	}
	filePath := path.Join(path.Dir(filename), "./conf.yml")
	viper.SetDefault("conf", filePath)

	//parse struct tag
	c := Configuration{}
	t := reflect.TypeOf(c)
	v := reflect.ValueOf(c)

	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		if v.Field(i).Type().Kind() != reflect.Struct {
			key := field.Name
			value := field.Tag.Get(tagName)
			//set default value
			viper.SetDefault(key, value)
			log.Printf("key is: %v,value is: %v\n", key, value)
		} else {
			structField := v.Field(i).Type()
			for j := 0; j < structField.NumField(); j++ {
				key := structField.Field(j).Name
				values := structField.Field(j).Tag.Get(tagName)
				viper.SetDefault(key, values)
				log.Printf("key is: %v,value is: %v\n", key, values)
			}
			continue
		}
	}

	// get config file path from environment
	conf := viper.GetString("conf")

	// parse config
	file := must(os.Open(conf)).(*os.File)
	defer file.Close()
	must(nil, viper.ReadConfig(file))
	must(nil, viper.Unmarshal(config))

	return config
}

// Configuration defines all configurations for application
type Configuration struct {
	GoVersion string `validate:"require"` //description:"Display version information and exit"
	Version   string `validate:"require"` //description:"Display version information of copernicus"
	BuildDate string `validate:"require"` //description:"Display build date of copernicus"
	DataDir   string `default:"data"`

	Service struct {
		Address string `default:"1.0.0.1:80"`
	}
	HTTP struct {
		Host string `validate:"require"`
		Port int
		Mode string
	}
	RPC struct {
		RPCListeners         []string // Add an interface/port to listen for RPC connections (default port: 8334, testnet: 18334)
		RPCUser              string   // Username for RPC connections
		RPCPass              string   // Password for RPC connections
		RPCLimitUser         string   //Username for limited RPC connections
		RPCLimitPass         string   //Password for limited RPC connections
		RPCCert              string   `default:""` //File containing the certificate file
		RPCKey               string   //File containing the certificate key
		RPCMaxClients        int      //Max number of RPC clients for standard connections
		RPCMaxWebsockets     int      //Max number of RPC websocket connections
		RPCMaxConcurrentReqs int      //Max number of concurrent RPC requests that may be processed concurrently
		RPCQuirks            bool     //Mirror some JSON-RPC quirks of Bitcoin Core -- NOTE: Discouraged unless interoperability issues need to be worked around
	}
	Log struct {
		Level    string   //description:"Define level of log,include trace, debug, info, warn, error"
		Module   []string // only output the specified module's log when using log.Print(...)
		FileName string   // the name of log file
	}
	Mempool struct {
		MinFeeRate int64
	}
	P2PNet struct {
		ListenAddrs         []string `validate:"require" default:"1234"`
		MaxPeers            int      `default:"128"`
		TargetOutbound      int      `default:"8"`
		ConnectPeersOnStart []string
		DisableBanning      bool `default:"true"`
		BanThreshold        uint32
		SimNet              bool          `default:"false"`
		DisableListen       bool          `default:"true"`
		BlocksOnly          bool          `default:"true"` //Do not accept transactions from remote peers.
		BanDuration         time.Duration // How long to ban misbehaving peers
		Proxy               string        // Connect via SOCKS5 proxy (eg. 127.0.0.1:9050)
		UserAgentComments   []string      // Comment to add to the user agent -- See BIP 14 for more information.
		DisableDNSSeed      bool          //Disable DNS seeding for peers
		DisableRPC          bool          `default:"true"`
		DisableTLS          bool
		Whitelists          []*net.IPNet
		NoOnion             bool     `default:"true"` // Disable connecting to tor hidden services
		Upnp                bool     // Use UPnP to map our listening port outside of NAT
		ExternalIPs         []string // Add an ip to the list of local addresses we claim to listen on to peers
	}
	AddrMgr struct {
		SimNet       bool
		ConnectPeers []string
	}
	Protocal struct {
		NoPeerBloomFilters bool `default:"true"`
		DisableCheckpoints bool `default:"true"`
	}
	Script struct {
		AcceptDataCarrier       bool     `default:"true"`
		MaxDatacarrierBytes     uint     `default:"83"`
		IsBareMultiSigStd       bool     `default:"true"`
		PromiscuousMempoolFlags []string `default:"StandardScriptVerifyFlags"`
	}
	TxOut struct {
		DustRelayFee int64 `default:"83"`
	}
}

func must(i interface{}, err error) interface{} {
	if err != nil {
		panic(err)
	}
	return i
}

func init() {
	Cfg = initConfig()
}

// Validate validates configuration
//func (c Configuration) Validate() error {
//	validate := validator.New(&validator.Config{TagName: "validate"})
//	return validate.Struct(c)
//}
<commit_msg>add mempool config<commit_after>package conf

import (
	"log"
	"os"
	"path"
	"reflect"
	"runtime"

	"net"
	"time"

	"github.com/spf13/viper"
)

const (
	tagName = "default"

	defaultConfigFilename       = "cps.conf"
	defaultDataDirname          = "data"
	defaultLogLevel             = "info"
	defaultLogDirname           = "logs"
	defaultLogFilename          = "btcd.log"
	defaultMaxPeers             = 125
	defaultBanDuration          = time.Hour * 24
	defaultBanThreshold         = 100
	defaultConnectTimeout       = time.Second * 30
	defaultMaxRPCClients        = 10
	defaultMaxRPCWebsockets     = 25
	defaultMaxRPCConcurrentReqs = 20
	defaultDbType               = "ffldb"
	defaultFreeTxRelayLimit     = 15.0
	defaultBlockMinSize         = 0
	defaultBlockMaxSize         = 750000
	defaultBlockMinWeight       = 0
	defaultBlockMaxWeight       = 3000000
	blockMaxSizeMin             = 1000
	blockMaxWeightMin           = 4000
	// blockMaxSizeMax              = blockchain.MaxBlockBaseSize - 1000
	// blockMaxWeightMax            = blockchain.MaxBlockWeight - 4000
	defaultGenerate              = false
	defaultMaxOrphanTransactions = 100
	defaultMaxOrphanTxSize       = 100000
	defaultSigCacheMaxSize       = 100000
	sampleConfigFilename         = "sample-btcd.conf"
	defaultTxIndex               = false
	defaultAddrIndex             = false
	defaultDescendantLimit		= 25
	defaultDescendantSizeLimit 	= 101
	defaultAncestorSizeLimit	= 101
	defaultAncestorLimit		= 25
	defaultMempoolExpiry		= 336
	defaultMaxMempoolSize		= 300
)

var Cfg *Configuration

// init configuration
func initConfig() *Configuration {
	config := &Configuration{}
	viper.SetEnvPrefix("copernicus")
	viper.AutomaticEnv()
	viper.SetConfigType("yaml")

	// find out where the sample config lives
	_, filename, _, ok := runtime.Caller(0)
	if !ok {
		panic("get current file path failed.")
	}
	filePath := path.Join(path.Dir(filename), "./conf.yml")
	viper.SetDefault("conf", filePath)

	//parse struct tag
	c := Configuration{}
	t := reflect.TypeOf(c)
	v := reflect.ValueOf(c)

	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		if v.Field(i).Type().Kind() != reflect.Struct {
			key := field.Name
			value := field.Tag.Get(tagName)
			//set default value
			viper.SetDefault(key, value)
			log.Printf("key is: %v,value is: %v\n", key, value)
		} else {
			structField := v.Field(i).Type()
			for j := 0; j < structField.NumField(); j++ {
				key := structField.Field(j).Name
				values := structField.Field(j).Tag.Get(tagName)
				viper.SetDefault(key, values)
				log.Printf("key is: %v,value is: %v\n", key, values)
			}
			continue
		}
	}

	// get config file path from environment
	conf := viper.GetString("conf")

	// parse config
	file := must(os.Open(conf)).(*os.File)
	defer file.Close()
	must(nil, viper.ReadConfig(file))
	must(nil, viper.Unmarshal(config))

	return config
}

// Configuration defines all configurations for application
type Configuration struct {
	GoVersion string `validate:"require"` //description:"Display version information and exit"
	Version   string `validate:"require"` //description:"Display version information of copernicus"
	BuildDate string `validate:"require"` //description:"Display build date of copernicus"
	DataDir   string `default:"data"`

	Service struct {
		Address string `default:"1.0.0.1:80"`
	}
	HTTP struct {
		Host string `validate:"require"`
		Port int
		Mode string
	}
	RPC struct {
		RPCListeners         []string // Add an interface/port to listen for RPC connections (default port: 8334, testnet: 18334)
		RPCUser              string   // Username for RPC connections
		RPCPass              string   // Password for RPC connections
		RPCLimitUser         string   //Username for limited RPC connections
		RPCLimitPass         string   //Password for limited RPC connections
		RPCCert              string   `default:""` //File containing the certificate file
		RPCKey               string   //File containing the certificate key
		RPCMaxClients        int      //Max number of RPC clients for standard connections
		RPCMaxWebsockets     int      //Max number of RPC websocket connections
		RPCMaxConcurrentReqs int      //Max number of concurrent RPC requests that may be processed concurrently
		RPCQuirks            bool     //Mirror some JSON-RPC quirks of Bitcoin Core -- NOTE: Discouraged unless interoperability issues need to be worked around
	}
	Log struct {
		Level    string   //description:"Define level of log,include trace, debug, info, warn, error"
		Module   []string // only output the specified module's log when using log.Print(...)
		FileName string   // the name of log file
	}
	Mempool struct {
		MinFeeRate 				int64	//
		LimitAncestorCount 		int		// Default for -limitancestorcount, max number of in-mempool ancestors
		LimitAncestorSize		int		// Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors
		LimitDescendantCount	int		// Default for -limitdescendantcount, max number of in-mempool descendants
		LimitDescendantSize 	int		// Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants
		MaxPoolSize				int		// Default for MaxPoolSize, maximum megabytes of mempool memory usage
		MaxPoolExpiry			int		// Default for -mempoolexpiry, expiration time for mempool transactions in hours
	}
	P2PNet struct {
		ListenAddrs         []string `validate:"require" default:"1234"`
		MaxPeers            int      `default:"128"`
		TargetOutbound      int      `default:"8"`
		ConnectPeersOnStart []string
		DisableBanning      bool `default:"true"`
		BanThreshold        uint32
		SimNet              bool          `default:"false"`
		DisableListen       bool          `default:"true"`
		BlocksOnly          bool          `default:"true"` //Do not accept transactions from remote peers.
		BanDuration         time.Duration // How long to ban misbehaving peers
		Proxy               string        // Connect via SOCKS5 proxy (eg. 127.0.0.1:9050)
		UserAgentComments   []string      // Comment to add to the user agent -- See BIP 14 for more information.
		DisableDNSSeed      bool          //Disable DNS seeding for peers
		DisableRPC          bool          `default:"true"`
		DisableTLS          bool
		Whitelists          []*net.IPNet
		NoOnion             bool     `default:"true"` // Disable connecting to tor hidden services
		Upnp                bool     // Use UPnP to map our listening port outside of NAT
		ExternalIPs         []string // Add an ip to the list of local addresses we claim to listen on to peers
	}
	AddrMgr struct {
		SimNet       bool
		ConnectPeers []string
	}
	Protocal struct {
		NoPeerBloomFilters bool `default:"true"`
		DisableCheckpoints bool `default:"true"`
	}
	Script struct {
		AcceptDataCarrier       bool     `default:"true"`
		MaxDatacarrierBytes     uint     `default:"83"`
		IsBareMultiSigStd       bool     `default:"true"`
		PromiscuousMempoolFlags []string `default:"StandardScriptVerifyFlags"`
	}
	TxOut struct {
		DustRelayFee int64 `default:"83"`
	}
}

func must(i interface{}, err error) interface{} {
	if err != nil {
		panic(err)
	}
	return i
}

func init() {
	Cfg = initConfig()
}

// Validate validates configuration
//func (c Configuration) Validate() error {
//	validate := validator.New(&validator.Config{TagName: "validate"})
//	return validate.Struct(c)
//}
<|endoftext|>


<commit_before>package conf

import (
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"

	flag "github.com/juju/gnuflag"
	"gopkg.in/yaml.v2"
)

var (
	// F flag prints full request
	F = flag.Bool("f", false, "Print full results, ie. no more '...'")

	// L flag limit results to a number
	L = flag.Int("l", 5, "Result list limit. Defaults to 5")

	// H flag specifies the host to connect to
	S = flag.String("s", "ok-b.org", "Server to connect to")

	H = flag.Bool("h", false, "Display help")

	Help = flag.Bool("help", false, "Display help, same as -h")

	// P flag enables private search
	P = flag.Bool("p", false, "Private search. Your search won't leave a trace. Pinky promise. Don't use this all the time if you want to see the search result relevancy improved")

	// D flag enables debug mode
	D = flag.Bool("d", false, "Debug mode")
	// DontPipe
	DontPipe = flag.Bool("dontpipe", false, "Flag for internal use - ignore this")
	// Version flag displays current version
	Version = flag.Bool("version", false, "Print version number")
	// V flag displays current version
	V = flag.Bool("v", false, "Print version number")
)
var (
	// EditFile borg edit file.
	EditFile string
	// ConfigFile borg config file.
	ConfigFile string
	// QueryFile borg query file.
	QueryFile string
)

func init() {
	borgDir := borgDir()

	EditFile = filepath.Join(borgDir, "edit")
	ConfigFile = filepath.Join(borgDir, "config.yml")
	QueryFile = filepath.Join(borgDir, "query")

	os.Mkdir(borgDir, os.ModePerm)
	os.Create(EditFile)
	if _, err := os.Stat(ConfigFile); os.IsNotExist(err) {
		os.Create(ConfigFile)
	}
	if _, err := os.Stat(QueryFile); os.IsNotExist(err) {
		os.Create(QueryFile)
	}
}

func borgDir() string {
	usr, err := user.Current()
	if err != nil {
		panic(err)
	}
	dir := filepath.Join(usr.HomeDir, ".borg")

	if _, err := os.Stat(dir); os.IsNotExist(err) {
		if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" {
			dir = filepath.Join(xdgConfigHome, "borg")
		} else {
			dir = filepath.Join(os.Getenv("HOME"), ".config")
		}
	}

	return dir
}

// Config file
type Config struct {
	Token       string
	DefaultTags []string
	Editor      string
	PipeTo      string
}

// Save config
func (c Config) Save() error {
	bs, err := yaml.Marshal(c)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(QueryFile, bs, os.ModePerm)
}

// Get config
func Get() (Config, error) {
	bs, err := ioutil.ReadFile(QueryFile)
	if err != nil {
		panic(err)
	}
	c := &Config{}
	err = yaml.Unmarshal(bs, c)
	if err != nil {
		return *c, err
	}
	if len(c.Editor) == 0 {
		c.Editor = "vim"
	}
	return *c, nil
}
<commit_msg>Fix #56, do not use user package as it relies on cgo<commit_after>package conf

import (
	"io/ioutil"
	"os"
	"path/filepath"

	flag "github.com/juju/gnuflag"
	"gopkg.in/yaml.v2"
)

var (
	// F flag prints full request
	F = flag.Bool("f", false, "Print full results, ie. no more '...'")

	// L flag limit results to a number
	L = flag.Int("l", 5, "Result list limit. Defaults to 5")

	// H flag specifies the host to connect to
	S = flag.String("s", "ok-b.org", "Server to connect to")

	H = flag.Bool("h", false, "Display help")

	Help = flag.Bool("help", false, "Display help, same as -h")

	// P flag enables private search
	P = flag.Bool("p", false, "Private search. Your search won't leave a trace. Pinky promise. Don't use this all the time if you want to see the search result relevancy improved")

	// D flag enables debug mode
	D = flag.Bool("d", false, "Debug mode")
	// DontPipe
	DontPipe = flag.Bool("dontpipe", false, "Flag for internal use - ignore this")
	// Version flag displays current version
	Version = flag.Bool("version", false, "Print version number")
	// V flag displays current version
	V = flag.Bool("v", false, "Print version number")
)
var (
	// EditFile borg edit file.
	EditFile string
	// ConfigFile borg config file.
	ConfigFile string
	// QueryFile borg query file.
	QueryFile string
)

func init() {
	borgDir := borgDir()

	EditFile = filepath.Join(borgDir, "edit")
	ConfigFile = filepath.Join(borgDir, "config.yml")
	QueryFile = filepath.Join(borgDir, "query")

	os.Mkdir(borgDir, os.ModePerm)
	os.Create(EditFile)
	if _, err := os.Stat(ConfigFile); os.IsNotExist(err) {
		os.Create(ConfigFile)
	}
	if _, err := os.Stat(QueryFile); os.IsNotExist(err) {
		os.Create(QueryFile)
	}
}

func borgDir() string {
	home := os.Getenv("HOME")
	if len(home) == 0 {
		panic("$HOME environment variable is not set")
	}
	dir := filepath.Join(home, ".borg")
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" {
			dir = filepath.Join(xdgConfigHome, "borg")
		} else {
			dir = filepath.Join(home, ".config")
		}
	}
	return dir
}

// Config file
type Config struct {
	Token       string
	DefaultTags []string
	Editor      string
	PipeTo      string
}

// Save config
func (c Config) Save() error {
	bs, err := yaml.Marshal(c)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(QueryFile, bs, os.ModePerm)
}

// Get config
func Get() (Config, error) {
	bs, err := ioutil.ReadFile(QueryFile)
	if err != nil {
		panic(err)
	}
	c := &Config{}
	err = yaml.Unmarshal(bs, c)
	if err != nil {
		return *c, err
	}
	if len(c.Editor) == 0 {
		c.Editor = "vim"
	}
	return *c, nil
}
<|endoftext|>


<commit_before>// Copyright 2012 Jesse van den Kieboom. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package configure provides a very simple gnu configure/make style configure
// script generating a simple Makefile and go file containing all the configured
// variables.
package configure

import (
	"bytes"
	"fmt"
	"github.com/jessevdk/go-flags"
	"io"
	"os"
	"path"
	"regexp"
	"sort"
	"strings"
	"runtime"
)

// Options contains all the standard configure options to specify various
// directories. Use NewOptions to create an instance of this type with the
// common default values for each variable.
type Options struct {
	Prefix        string `long:"prefix" description:"install architecture-independent files in PREFIX"`
	ExecPrefix    string `long:"execprefix" description:"install architecture-dependent files in EPREFIX"`
	BinDir        string `long:"bindir" description:"user executables"`
	LibExecDir    string `long:"libexecdir" description:"program executables"`
	SysConfDir    string `long:"sysconfdir" description:"read-only single-machine data"`
	LibDir        string `long:"libdir" description:"program executables"`
	DataRootDir   string `long:"datarootdir" description:"read-only arch.-independent data root"`
	DataDir       string `long:"datadir" description:"read-only arc.-independent data"`
	ManDir        string `long:"mandir" description:"man documentation"`
}

// NewOptions creates a new Options with common default values.
func NewOptions() *Options {
	return &Options{
		Prefix:        "/usr/local",
		ExecPrefix:    "${prefix}",
		BinDir:        "${execprefix}/bin",
		LibExecDir:    "${execprefix}/libexec",
		LibDir:        "${execprefix}/lib",
		SysConfDir:    "${prefix}/etc",
		DataRootDir:   "${prefix}/share",
		DataDir:       "${datarootdir}",
		ManDir:        "${datarootdir}/man",
	}
}

// Package is the package name in which the GoConfig file will be written
var Package = "main"

// Makefile is the filename of the makefile that will be generated
var Makefile = "go.make"

// GoConfig is the filename of the go file that will be generated containing
// all the variable values.
var GoConfig = "appconfig"

// GoConfigVariable is the name of the variable inside the GoConfig file
// containing all the variable values.
var GoConfigVariable = "AppConfig"

// Target is the executable name to build. If left empty, the name is deduced
// from the directory (similar to what go does)
var Target = ""

// Version is the application version
var Version []int = []int{0, 1}

type expandStringPart struct {
	Value      string
	IsVariable bool
}

func (x *expandStringPart) expand(m map[string]*expandString) (string, []string) {
	if x.IsVariable {
		s, ok := m[x.Value]

		if !ok {
			return "", nil
		} else {
			ret := s.expand(m)
			rets := make([]string, len(s.dependencies), len(s.dependencies)+1)

			copy(rets, s.dependencies)

			return ret, append(rets, x.Value)
		}
	}

	return x.Value, nil
}

type expandString struct {
	Name  string
	Parts []expandStringPart

	dependencies []string
	value        string
	hasExpanded  bool
}

func (x *expandString) dependsOn(name string) bool {
	i := sort.SearchStrings(x.dependencies, name)

	return i < len(x.dependencies) && x.dependencies[i] == name
}

func (x *expandString) expand(m map[string]*expandString) string {
	if !x.hasExpanded {
		// Prevent infinite loop by circular dependencies
		x.hasExpanded = true
		buf := bytes.Buffer{}

		for _, v := range x.Parts {
			s, deps := v.expand(m)
			buf.WriteString(s)

			x.dependencies = append(x.dependencies, deps...)
		}

		sort.Strings(x.dependencies)
		x.value = buf.String()
	}

	return x.value
}

// Config represents the current configuration. See Configure for more
// information.
type Config struct {
	*flags.Parser

	values []*flags.Option
	valuesMap   map[string]*flags.Option
	expanded map[string]*expandString
}

func eachGroup(g *flags.Group, f func(g *flags.Group)) {
	f(g)

	for _, gg := range g.Groups() {
		eachGroup(gg, f)
	}
}

func (x *Config) extract() ([]*flags.Option, map[string]*flags.Option) {
	valuesmap := make(map[string]*flags.Option)
	var values []*flags.Option

	eachGroup(x.Parser.Command.Group, func(g *flags.Group) {
		for _, option := range g.Options() {
			if len(option.LongName) > 0 {
				valuesmap[option.LongName] = option
				values = append(values, option)
			}
		}
	})

	return values, valuesmap
}

func (x *Config) expand() map[string]*expandString {
	ret := make(map[string]*expandString)

	r, _ := regexp.Compile(`\$\{[^}]*\}`)

	for name, opt := range x.valuesMap {
		es := expandString{
			Name: name,
		}

		// Find all variable references
		s, ok := opt.Value().(string)

		if !ok {
			continue
		}

		matches := r.FindAllStringIndex(s, -1)

		for i, match := range matches {
			var prefix string

			if i == 0 {
				prefix = s[0:match[0]]
			} else {
				prefix = s[matches[i-1][1]:match[0]]
			}

			if len(prefix) != 0 {
				es.Parts = append(es.Parts, expandStringPart{Value: prefix, IsVariable: false})
			}

			varname := s[match[0]+2 : match[1]-1]
			es.Parts = append(es.Parts, expandStringPart{Value: varname, IsVariable: true})
		}

		if len(matches) == 0 {
			es.Parts = append(es.Parts, expandStringPart{Value: s, IsVariable: false})
		} else {
			last := matches[len(matches)-1]
			suffix := s[last[1]:]

			if len(suffix) != 0 {
				es.Parts = append(es.Parts, expandStringPart{Value: suffix, IsVariable: false})
			}
		}

		ret[name] = &es
	}

	for _, val := range ret {
		val.expand(ret)
	}

	return ret
}

// Configure runs the configure process with options as provided by the given
// data variable. If data is nil, the default options will be used
// (see NewOptions). Note that the data provided is simply passed to go-flags.
// For more information on flags parsing, see the documentation of go-flags.
// If GoConfig is not empty, then the go configuration will be written to the
// GoConfig file. Similarly, if Makefile is not empty, the Makefile will be
// written.
func Configure(data interface{}) (*Config, error) {
	if data == nil {
		data = NewOptions()
	}

	parser := flags.NewParser(data, flags.PrintErrors | flags.IgnoreUnknown)

	if _, err := parser.Parse(); err != nil {
		return nil, err
	}

	ret := &Config{
		Parser: parser,
	}

	ret.values, ret.valuesMap = ret.extract()
	ret.expanded = ret.expand()

	if len(GoConfig) != 0 {
		filename := GoConfig

		if !strings.HasSuffix(filename, ".go") {
			filename += ".go"
		}

		f, err := os.Create(filename)

		if err != nil {
			return nil, err
		}

		ret.WriteGoConfig(f)
		f.Close()
	}

	if len(Makefile) != 0 {
		f, err := os.Create(Makefile)

		if err != nil {
			return nil, err
		}

		ret.WriteMakefile(f)
		f.Close()

		os.Chmod(Makefile, 0755)

		f, err = os.OpenFile(path.Join(path.Dir(Makefile), "Makefile"),
		                     os.O_CREATE | os.O_EXCL | os.O_WRONLY,
		                     0644)

		if err == nil {
			fmt.Fprintf(f, "include %s\n", path.Base(Makefile))
			f.Close()
		}
	}

	return ret, nil
}

// Expand expands the variable value indicated by name
func (x *Config) Expand(name string) string {
	return x.expanded[name].expand(x.expanded)
}

// WriteGoConfig writes the go configuration file containing all the variable
// values to the given writer. Note that it will write a package line if
// the Package variable is not empty. The GoConfigVariable name will
// be used as the variable name for the configuration.
func (x *Config) WriteGoConfig(writer io.Writer) {
	if len(Package) > 0 {
		fmt.Fprintf(writer, "package %v\n\n", Package)
	}

	fmt.Fprintf(writer, "var %s = struct {\n", GoConfigVariable)
	values := make([]string, 0)

	variables := make([]string, len(x.values))

	// Write all options
	for i, opt := range x.values {
		variables[i] = opt.LongName
	}

	sort.Strings(variables)

	for i, name := range variables {
		if i != 0 {
			io.WriteString(writer, "\n")
		}

		option := x.valuesMap[name]
		val := option.Value()

		fmt.Fprintf(writer, "\t// %s\n", option.Description)
		fmt.Fprintf(writer, "\t%v %T\n", name, val)

		var value string

		if _, ok := x.expanded[option.LongName]; ok {
			value = fmt.Sprintf("%#v", x.Expand(option.LongName))
		} else {
			value = fmt.Sprintf("%#v", val)
		}

		values = append(values, value)
	}

	if len(variables) > 0 {
		io.WriteString(writer, "\n")
	}

	io.WriteString(writer, "\t// Application version\n")
	io.WriteString(writer, "\tVersion []int\n")
	fmt.Fprintln(writer, "}{")

	for _, v := range values {
		fmt.Fprintf(writer, "\t%v,\n", v)
	}

	for i, v := range Version {
		if i != 0 {
			io.WriteString(writer, ", ")
		} else {
			io.WriteString(writer, "\t[]int{")
		}

		fmt.Fprintf(writer, "%v", v)
	}

	fmt.Fprintln(writer, "},")
	fmt.Fprintln(writer, "}")
}

// WriteMakefile writes a Makefile for the given parser to the given writer.
// The Makefile contains the common build, clean, distclean, install and
// uninstall rules.
func (x *Config) WriteMakefile(writer io.Writer) {
	// Write a very basic makefile
	io.WriteString(writer, "#!/usr/bin/make -f\n\n")

	vars := make([]*expandString, 0, len(x.expanded))

	for name, v := range x.expanded {
		inserted := false

		// Insert into vars based on dependencies
		for i, vv := range vars {
			if vv.dependsOn(name) {
				tail := make([]*expandString, len(vars)-i)
				copy(tail, vars[i:])

				if i == 0 {
					vars = append([]*expandString{v}, vars...)
				} else {
					vars = append(append(vars[0:i], v), tail...)
				}

				inserted = true
				break
			}
		}

		if !inserted {
			vars = append(vars, v)
		}
	}

	io.WriteString(writer, "# Variables\n")

	for _, v := range vars {
		fmt.Fprintf(writer, "%s ?= ", v.Name)

		for _, part := range v.Parts {
			if part.IsVariable {
				fmt.Fprintf(writer, "$(%s)", part.Value)
			} else {
				fmt.Fprintf(writer, "%s", part.Value)
			}
		}

		io.WriteString(writer, "\n")
	}

	io.WriteString(writer, "version ?= ")

	for i, v := range Version {
		if i != 0 {
			io.WriteString(writer, ".")
		}

		fmt.Fprintf(writer, "%v", v)
	}

	io.WriteString(writer, "\n")
	fmt.Fprintf(writer, "major_version = %v\n", Version[0])

	if len(Version) > 1 {
		fmt.Fprintf(writer, "minor_version = %v\n", Version[1])
	}

	if len(Version) > 2 {
		fmt.Fprintf(writer, "micro_version = %v\n", Version[2])
	}

	io.WriteString(writer, "\n")

	target := Target

	if len(target) == 0 {
		pc := make([]uintptr, 3)
		n := runtime.Callers(1, pc)

		me, _ := runtime.FuncForPC(pc[0]).FileLine(pc[0])

		for i := 1; i < n; i++ {
			f := runtime.FuncForPC(pc[i])
			fname, _ := f.FileLine(pc[i])

			if fname != me {
				target = path.Base(path.Dir(fname))
				break
			}
		}
	}

	fmt.Fprintf(writer, "TARGET ?= %s\n", target)

	io.WriteString(writer, "\nSOURCES ?=")
	io.WriteString(writer, "\nSOURCES += $(wildcard *.go)")
	io.WriteString(writer, "\nSOURCES_UNIQUE = $(sort $(SOURCES))")

	io.WriteString(writer, "\n\n")

	io.WriteString(writer, "# Rules\n")
	io.WriteString(writer, "$(TARGET): $(SOURCES_UNIQUE)\n")
	io.WriteString(writer, "\tgo build -o $@\n\n")

	io.WriteString(writer, "clean:\n")
	io.WriteString(writer, "\trm -f $(TARGET)\n\n")

	io.WriteString(writer, "distclean: clean\n\n")

	io.WriteString(writer, "$(TARGET)_installdir ?= $(bindir)\n\n")

	io.WriteString(writer, "install: $(TARGET)\n")
	io.WriteString(writer, "\tmkdir -p $(DESTDIR)$($(TARGET)_installdir) && cp $(TARGET) $(DESTDIR)$($(TARGET)_installdir)/$(TARGET)\n\n")

	io.WriteString(writer, "uninstall:\n")
	io.WriteString(writer, "\trm -f $(DESTDIR)$($(TARGET)_installdir)/$(TARGET)\n\n")

	io.WriteString(writer, ".PHONY: install uninstall distclean clean")
}
<commit_msg>Use title case for names<commit_after>// Copyright 2012 Jesse van den Kieboom. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package configure provides a very simple gnu configure/make style configure
// script generating a simple Makefile and go file containing all the configured
// variables.
package configure

import (
	"bytes"
	"fmt"
	"github.com/jessevdk/go-flags"
	"io"
	"os"
	"path"
	"regexp"
	"sort"
	"strings"
	"runtime"
)

// Options contains all the standard configure options to specify various
// directories. Use NewOptions to create an instance of this type with the
// common default values for each variable.
type Options struct {
	Prefix        string `long:"prefix" description:"install architecture-independent files in PREFIX"`
	ExecPrefix    string `long:"execprefix" description:"install architecture-dependent files in EPREFIX"`
	BinDir        string `long:"bindir" description:"user executables"`
	LibExecDir    string `long:"libexecdir" description:"program executables"`
	SysConfDir    string `long:"sysconfdir" description:"read-only single-machine data"`
	LibDir        string `long:"libdir" description:"program executables"`
	DataRootDir   string `long:"datarootdir" description:"read-only arch.-independent data root"`
	DataDir       string `long:"datadir" description:"read-only arc.-independent data"`
	ManDir        string `long:"mandir" description:"man documentation"`
}

// NewOptions creates a new Options with common default values.
func NewOptions() *Options {
	return &Options{
		Prefix:        "/usr/local",
		ExecPrefix:    "${prefix}",
		BinDir:        "${execprefix}/bin",
		LibExecDir:    "${execprefix}/libexec",
		LibDir:        "${execprefix}/lib",
		SysConfDir:    "${prefix}/etc",
		DataRootDir:   "${prefix}/share",
		DataDir:       "${datarootdir}",
		ManDir:        "${datarootdir}/man",
	}
}

// Package is the package name in which the GoConfig file will be written
var Package = "main"

// Makefile is the filename of the makefile that will be generated
var Makefile = "go.make"

// GoConfig is the filename of the go file that will be generated containing
// all the variable values.
var GoConfig = "appconfig"

// GoConfigVariable is the name of the variable inside the GoConfig file
// containing all the variable values.
var GoConfigVariable = "AppConfig"

// Target is the executable name to build. If left empty, the name is deduced
// from the directory (similar to what go does)
var Target = ""

// Version is the application version
var Version []int = []int{0, 1}

type expandStringPart struct {
	Value      string
	IsVariable bool
}

func (x *expandStringPart) expand(m map[string]*expandString) (string, []string) {
	if x.IsVariable {
		s, ok := m[x.Value]

		if !ok {
			return "", nil
		} else {
			ret := s.expand(m)
			rets := make([]string, len(s.dependencies), len(s.dependencies)+1)

			copy(rets, s.dependencies)

			return ret, append(rets, x.Value)
		}
	}

	return x.Value, nil
}

type expandString struct {
	Name  string
	Parts []expandStringPart

	dependencies []string
	value        string
	hasExpanded  bool
}

func (x *expandString) dependsOn(name string) bool {
	i := sort.SearchStrings(x.dependencies, name)

	return i < len(x.dependencies) && x.dependencies[i] == name
}

func (x *expandString) expand(m map[string]*expandString) string {
	if !x.hasExpanded {
		// Prevent infinite loop by circular dependencies
		x.hasExpanded = true
		buf := bytes.Buffer{}

		for _, v := range x.Parts {
			s, deps := v.expand(m)
			buf.WriteString(s)

			x.dependencies = append(x.dependencies, deps...)
		}

		sort.Strings(x.dependencies)
		x.value = buf.String()
	}

	return x.value
}

// Config represents the current configuration. See Configure for more
// information.
type Config struct {
	*flags.Parser

	values []*flags.Option
	valuesMap   map[string]*flags.Option
	expanded map[string]*expandString
}

func eachGroup(g *flags.Group, f func(g *flags.Group)) {
	f(g)

	for _, gg := range g.Groups() {
		eachGroup(gg, f)
	}
}

func (x *Config) extract() ([]*flags.Option, map[string]*flags.Option) {
	valuesmap := make(map[string]*flags.Option)
	var values []*flags.Option

	eachGroup(x.Parser.Command.Group, func(g *flags.Group) {
		for _, option := range g.Options() {
			if len(option.LongName) > 0 {
				valuesmap[option.LongName] = option
				values = append(values, option)
			}
		}
	})

	return values, valuesmap
}

func (x *Config) expand() map[string]*expandString {
	ret := make(map[string]*expandString)

	r, _ := regexp.Compile(`\$\{[^}]*\}`)

	for name, opt := range x.valuesMap {
		es := expandString{
			Name: name,
		}

		// Find all variable references
		s, ok := opt.Value().(string)

		if !ok {
			continue
		}

		matches := r.FindAllStringIndex(s, -1)

		for i, match := range matches {
			var prefix string

			if i == 0 {
				prefix = s[0:match[0]]
			} else {
				prefix = s[matches[i-1][1]:match[0]]
			}

			if len(prefix) != 0 {
				es.Parts = append(es.Parts, expandStringPart{Value: prefix, IsVariable: false})
			}

			varname := s[match[0]+2 : match[1]-1]
			es.Parts = append(es.Parts, expandStringPart{Value: varname, IsVariable: true})
		}

		if len(matches) == 0 {
			es.Parts = append(es.Parts, expandStringPart{Value: s, IsVariable: false})
		} else {
			last := matches[len(matches)-1]
			suffix := s[last[1]:]

			if len(suffix) != 0 {
				es.Parts = append(es.Parts, expandStringPart{Value: suffix, IsVariable: false})
			}
		}

		ret[name] = &es
	}

	for _, val := range ret {
		val.expand(ret)
	}

	return ret
}

// Configure runs the configure process with options as provided by the given
// data variable. If data is nil, the default options will be used
// (see NewOptions). Note that the data provided is simply passed to go-flags.
// For more information on flags parsing, see the documentation of go-flags.
// If GoConfig is not empty, then the go configuration will be written to the
// GoConfig file. Similarly, if Makefile is not empty, the Makefile will be
// written.
func Configure(data interface{}) (*Config, error) {
	if data == nil {
		data = NewOptions()
	}

	parser := flags.NewParser(data, flags.PrintErrors | flags.IgnoreUnknown)

	if _, err := parser.Parse(); err != nil {
		return nil, err
	}

	ret := &Config{
		Parser: parser,
	}

	ret.values, ret.valuesMap = ret.extract()
	ret.expanded = ret.expand()

	if len(GoConfig) != 0 {
		filename := GoConfig

		if !strings.HasSuffix(filename, ".go") {
			filename += ".go"
		}

		f, err := os.Create(filename)

		if err != nil {
			return nil, err
		}

		ret.WriteGoConfig(f)
		f.Close()
	}

	if len(Makefile) != 0 {
		f, err := os.Create(Makefile)

		if err != nil {
			return nil, err
		}

		ret.WriteMakefile(f)
		f.Close()

		os.Chmod(Makefile, 0755)

		f, err = os.OpenFile(path.Join(path.Dir(Makefile), "Makefile"),
		                     os.O_CREATE | os.O_EXCL | os.O_WRONLY,
		                     0644)

		if err == nil {
			fmt.Fprintf(f, "include %s\n", path.Base(Makefile))
			f.Close()
		}
	}

	return ret, nil
}

// Expand expands the variable value indicated by name
func (x *Config) Expand(name string) string {
	return x.expanded[name].expand(x.expanded)
}

// WriteGoConfig writes the go configuration file containing all the variable
// values to the given writer. Note that it will write a package line if
// the Package variable is not empty. The GoConfigVariable name will
// be used as the variable name for the configuration.
func (x *Config) WriteGoConfig(writer io.Writer) {
	if len(Package) > 0 {
		fmt.Fprintf(writer, "package %v\n\n", Package)
	}

	fmt.Fprintf(writer, "var %s = struct {\n", GoConfigVariable)
	values := make([]string, 0)

	variables := make([]string, len(x.values))

	// Write all options
	for i, opt := range x.values {
		variables[i] = opt.LongName
	}

	sort.Strings(variables)

	for i, name := range variables {
		if i != 0 {
			io.WriteString(writer, "\n")
		}

		option := x.valuesMap[name]
		val := option.Value()

		fmt.Fprintf(writer, "\t// %s\n", option.Description)
		fmt.Fprintf(writer, "\t%v %T\n", strings.Title(name), val)

		var value string

		if _, ok := x.expanded[option.LongName]; ok {
			value = fmt.Sprintf("%#v", x.Expand(option.LongName))
		} else {
			value = fmt.Sprintf("%#v", val)
		}

		values = append(values, value)
	}

	if len(variables) > 0 {
		io.WriteString(writer, "\n")
	}

	io.WriteString(writer, "\t// Application version\n")
	io.WriteString(writer, "\tVersion []int\n")
	fmt.Fprintln(writer, "}{")

	for _, v := range values {
		fmt.Fprintf(writer, "\t%v,\n", v)
	}

	for i, v := range Version {
		if i != 0 {
			io.WriteString(writer, ", ")
		} else {
			io.WriteString(writer, "\t[]int{")
		}

		fmt.Fprintf(writer, "%v", v)
	}

	fmt.Fprintln(writer, "},")
	fmt.Fprintln(writer, "}")
}

// WriteMakefile writes a Makefile for the given parser to the given writer.
// The Makefile contains the common build, clean, distclean, install and
// uninstall rules.
func (x *Config) WriteMakefile(writer io.Writer) {
	// Write a very basic makefile
	io.WriteString(writer, "#!/usr/bin/make -f\n\n")

	vars := make([]*expandString, 0, len(x.expanded))

	for name, v := range x.expanded {
		inserted := false

		// Insert into vars based on dependencies
		for i, vv := range vars {
			if vv.dependsOn(name) {
				tail := make([]*expandString, len(vars)-i)
				copy(tail, vars[i:])

				if i == 0 {
					vars = append([]*expandString{v}, vars...)
				} else {
					vars = append(append(vars[0:i], v), tail...)
				}

				inserted = true
				break
			}
		}

		if !inserted {
			vars = append(vars, v)
		}
	}

	io.WriteString(writer, "# Variables\n")

	for _, v := range vars {
		fmt.Fprintf(writer, "%s ?= ", v.Name)

		for _, part := range v.Parts {
			if part.IsVariable {
				fmt.Fprintf(writer, "$(%s)", part.Value)
			} else {
				fmt.Fprintf(writer, "%s", part.Value)
			}
		}

		io.WriteString(writer, "\n")
	}

	io.WriteString(writer, "version ?= ")

	for i, v := range Version {
		if i != 0 {
			io.WriteString(writer, ".")
		}

		fmt.Fprintf(writer, "%v", v)
	}

	io.WriteString(writer, "\n")
	fmt.Fprintf(writer, "major_version = %v\n", Version[0])

	if len(Version) > 1 {
		fmt.Fprintf(writer, "minor_version = %v\n", Version[1])
	}

	if len(Version) > 2 {
		fmt.Fprintf(writer, "micro_version = %v\n", Version[2])
	}

	io.WriteString(writer, "\n")

	target := Target

	if len(target) == 0 {
		pc := make([]uintptr, 3)
		n := runtime.Callers(1, pc)

		me, _ := runtime.FuncForPC(pc[0]).FileLine(pc[0])

		for i := 1; i < n; i++ {
			f := runtime.FuncForPC(pc[i])
			fname, _ := f.FileLine(pc[i])

			if fname != me {
				target = path.Base(path.Dir(fname))
				break
			}
		}
	}

	fmt.Fprintf(writer, "TARGET ?= %s\n", target)

	io.WriteString(writer, "\nSOURCES ?=")
	io.WriteString(writer, "\nSOURCES += $(wildcard *.go)")
	io.WriteString(writer, "\nSOURCES_UNIQUE = $(sort $(SOURCES))")

	io.WriteString(writer, "\n\n")

	io.WriteString(writer, "# Rules\n")
	io.WriteString(writer, "$(TARGET): $(SOURCES_UNIQUE)\n")
	io.WriteString(writer, "\tgo build -o $@\n\n")

	io.WriteString(writer, "clean:\n")
	io.WriteString(writer, "\trm -f $(TARGET)\n\n")

	io.WriteString(writer, "distclean: clean\n\n")

	io.WriteString(writer, "$(TARGET)_installdir ?= $(bindir)\n\n")

	io.WriteString(writer, "install: $(TARGET)\n")
	io.WriteString(writer, "\tmkdir -p $(DESTDIR)$($(TARGET)_installdir) && cp $(TARGET) $(DESTDIR)$($(TARGET)_installdir)/$(TARGET)\n\n")

	io.WriteString(writer, "uninstall:\n")
	io.WriteString(writer, "\trm -f $(DESTDIR)$($(TARGET)_installdir)/$(TARGET)\n\n")

	io.WriteString(writer, ".PHONY: install uninstall distclean clean")
}
<|endoftext|>


<commit_before>package dbus

import (
	"github.com/guelfey/go.dbus"
)

// From the systemd docs:
//
// The properties array of StartTransientUnit() may take many of the settings
// that may also be configured in unit files. Not all parameters are currently
// accepted though, but we plan to cover more properties with future release.
// Currently you may set the Description, Slice and all dependency types of
// units, as well as RemainAfterExit, ExecStart for service units,
// TimeoutStopUSec and PIDs for scope units, and CPUAccounting, CPUShares,
// BlockIOAccounting, BlockIOWeight, BlockIOReadBandwidth,
// BlockIOWriteBandwidth, BlockIODeviceWeight, MemoryAccounting, MemoryLimit,
// DevicePolicy, DeviceAllow for services/scopes/slices. These fields map
// directly to their counterparts in unit files and as normal D-Bus object
// properties. The exception here is the PIDs field of scope units which is
// used for construction of the scope only and specifies the initial PIDs to
// add to the scope object.

type Property struct {
	Name  string
	Value dbus.Variant
}

type execStart struct {
	Path             string   // the binary path to execute
	Args             []string // an array with all arguments to pass to the executed command, starting with argument 0
	UncleanIsFailure bool     // a boolean whether it should be considered a failure if the process exits uncleanly
}

// PropExecStart sets the ExecStart service property.  The first argument is a
// slice with the binary path to execute followed by the arguments to pass to
// the executed command. See
// http://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart=
func PropExecStart(command []string, uncleanIsFailure bool) Property {
	execStarts := []execStart{
		execStart{
			Path:             command[0],
			Args:             command,
			UncleanIsFailure: uncleanIsFailure,
		},
	}

	return Property{
		Name:  "ExecStart",
		Value: dbus.MakeVariant(execStarts),
	}
}

// PropRemainAfterExit sets the RemainAfterExit service property. See
// http://www.freedesktop.org/software/systemd/man/systemd.service.html#RemainAfterExit=
func PropRemainAfterExit(b bool) Property {
	return Property{
		Name:  "RemainAfterExit",
		Value: dbus.MakeVariant(b),
	}
}

// PropDescription sets the Description unit property. See
// http://www.freedesktop.org/software/systemd/man/systemd.unit#Description=
func PropDescription(desc string) Property {
	return Property{
		Name:  "Description",
		Value: dbus.MakeVariant(desc),
	}
}

func propDependency(name string, units []string) Property {
	return Property{
		Name:  name,
		Value: dbus.MakeVariant(units),
	}
}

// PropRequires sets the Requires unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#Requires=
func PropRequires(units ...string) Property {
	return propDependency("Requires", units)
}

// PropRequiresOverridable sets the RequiresOverridable unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#RequiresOverridable=
func PropRequiresOverridable(units ...string) Property {
	return propDependency("RequiresOverridable", units)
}

// PropRequisite sets the Requisite unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#Requisite=
func PropRequisite(units ...string) Property {
	return propDependency("Requisite", units)
}

// PropRequisiteOverridable sets the RequisiteOverridable unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#RequisiteOverridable=
func PropRequisiteOverridable(units ...string) Property {
	return propDependency("RequisiteOverridable", units)
}

// PropWants sets the Wants unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#Wants=
func PropWants(units ...string) Property {
	return propDependency("Wants", units)
}

// PropBindsTo sets the BindsTo unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#BindsTo=
func PropBindsTo(units ...string) Property {
	return propDependency("BindsTo", units)
}

// PropRequiredBy sets the RequiredBy unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#RequiredBy=
func PropRequiredBy(units ...string) Property {
	return propDependency("RequiredBy", units)
}

// PropRequiredByOverridable sets the RequiredByOverridable unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#RequiredByOverridable=
func PropRequiredByOverridable(units ...string) Property {
	return propDependency("RequiredByOverridable", units)
}

// PropWantedBy sets the WantedBy unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#WantedBy=
func PropWantedBy(units ...string) Property {
	return propDependency("WantedBy", units)
}

// PropBoundBy sets the BoundBy unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#BoundBy=
func PropBoundBy(units ...string) Property {
	return propDependency("BoundBy", units)
}

// PropConflicts sets the Conflicts unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#Conflicts=
func PropConflicts(units ...string) Property {
	return propDependency("Conflicts", units)
}

// PropConflictedBy sets the ConflictedBy unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#ConflictedBy=
func PropConflictedBy(units ...string) Property {
	return propDependency("ConflictedBy", units)
}

// PropBefore sets the Before unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#Before=
func PropBefore(units ...string) Property {
	return propDependency("Before", units)
}

// PropAfter sets the After unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#After=
func PropAfter(units ...string) Property {
	return propDependency("After", units)
}

// PropOnFailure sets the OnFailure unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#OnFailure=
func PropOnFailure(units ...string) Property {
	return propDependency("OnFailure", units)
}

// PropTriggers sets the Triggers unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#Triggers=
func PropTriggers(units ...string) Property {
	return propDependency("Triggers", units)
}

// PropTriggeredBy sets the TriggeredBy unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#TriggeredBy=
func PropTriggeredBy(units ...string) Property {
	return propDependency("TriggeredBy", units)
}

// PropPropagatesReloadTo sets the PropagatesReloadTo unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#PropagatesReloadTo=
func PropPropagatesReloadTo(units ...string) Property {
	return propDependency("PropagatesReloadTo", units)
}

// PropRequiresMountsFor sets the RequiresMountsFor unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#RequiresMountsFor=
func PropRequiresMountsFor(units ...string) Property {
	return propDependency("RequiresMountsFor", units)
}
<commit_msg>documentation fix wrong url<commit_after>package dbus

import (
	"github.com/guelfey/go.dbus"
)

// From the systemd docs:
//
// The properties array of StartTransientUnit() may take many of the settings
// that may also be configured in unit files. Not all parameters are currently
// accepted though, but we plan to cover more properties with future release.
// Currently you may set the Description, Slice and all dependency types of
// units, as well as RemainAfterExit, ExecStart for service units,
// TimeoutStopUSec and PIDs for scope units, and CPUAccounting, CPUShares,
// BlockIOAccounting, BlockIOWeight, BlockIOReadBandwidth,
// BlockIOWriteBandwidth, BlockIODeviceWeight, MemoryAccounting, MemoryLimit,
// DevicePolicy, DeviceAllow for services/scopes/slices. These fields map
// directly to their counterparts in unit files and as normal D-Bus object
// properties. The exception here is the PIDs field of scope units which is
// used for construction of the scope only and specifies the initial PIDs to
// add to the scope object.

type Property struct {
	Name  string
	Value dbus.Variant
}

type execStart struct {
	Path             string   // the binary path to execute
	Args             []string // an array with all arguments to pass to the executed command, starting with argument 0
	UncleanIsFailure bool     // a boolean whether it should be considered a failure if the process exits uncleanly
}

// PropExecStart sets the ExecStart service property.  The first argument is a
// slice with the binary path to execute followed by the arguments to pass to
// the executed command. See
// http://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart=
func PropExecStart(command []string, uncleanIsFailure bool) Property {
	execStarts := []execStart{
		execStart{
			Path:             command[0],
			Args:             command,
			UncleanIsFailure: uncleanIsFailure,
		},
	}

	return Property{
		Name:  "ExecStart",
		Value: dbus.MakeVariant(execStarts),
	}
}

// PropRemainAfterExit sets the RemainAfterExit service property. See
// http://www.freedesktop.org/software/systemd/man/systemd.service.html#RemainAfterExit=
func PropRemainAfterExit(b bool) Property {
	return Property{
		Name:  "RemainAfterExit",
		Value: dbus.MakeVariant(b),
	}
}

// PropDescription sets the Description unit property. See
// http://www.freedesktop.org/software/systemd/man/systemd.unit#Description=
func PropDescription(desc string) Property {
	return Property{
		Name:  "Description",
		Value: dbus.MakeVariant(desc),
	}
}

func propDependency(name string, units []string) Property {
	return Property{
		Name:  name,
		Value: dbus.MakeVariant(units),
	}
}

// PropRequires sets the Requires unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Requires=
func PropRequires(units ...string) Property {
	return propDependency("Requires", units)
}

// PropRequiresOverridable sets the RequiresOverridable unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiresOverridable=
func PropRequiresOverridable(units ...string) Property {
	return propDependency("RequiresOverridable", units)
}

// PropRequisite sets the Requisite unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Requisite=
func PropRequisite(units ...string) Property {
	return propDependency("Requisite", units)
}

// PropRequisiteOverridable sets the RequisiteOverridable unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequisiteOverridable=
func PropRequisiteOverridable(units ...string) Property {
	return propDependency("RequisiteOverridable", units)
}

// PropWants sets the Wants unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Wants=
func PropWants(units ...string) Property {
	return propDependency("Wants", units)
}

// PropBindsTo sets the BindsTo unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#BindsTo=
func PropBindsTo(units ...string) Property {
	return propDependency("BindsTo", units)
}

// PropRequiredBy sets the RequiredBy unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiredBy=
func PropRequiredBy(units ...string) Property {
	return propDependency("RequiredBy", units)
}

// PropRequiredByOverridable sets the RequiredByOverridable unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiredByOverridable=
func PropRequiredByOverridable(units ...string) Property {
	return propDependency("RequiredByOverridable", units)
}

// PropWantedBy sets the WantedBy unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#WantedBy=
func PropWantedBy(units ...string) Property {
	return propDependency("WantedBy", units)
}

// PropBoundBy sets the BoundBy unit property.  See
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#BoundBy=
func PropBoundBy(units ...string) Property {
	return propDependency("BoundBy", units)
}

// PropConflicts sets the Conflicts unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Conflicts=
func PropConflicts(units ...string) Property {
	return propDependency("Conflicts", units)
}

// PropConflictedBy sets the ConflictedBy unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#ConflictedBy=
func PropConflictedBy(units ...string) Property {
	return propDependency("ConflictedBy", units)
}

// PropBefore sets the Before unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Before=
func PropBefore(units ...string) Property {
	return propDependency("Before", units)
}

// PropAfter sets the After unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#After=
func PropAfter(units ...string) Property {
	return propDependency("After", units)
}

// PropOnFailure sets the OnFailure unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#OnFailure=
func PropOnFailure(units ...string) Property {
	return propDependency("OnFailure", units)
}

// PropTriggers sets the Triggers unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Triggers=
func PropTriggers(units ...string) Property {
	return propDependency("Triggers", units)
}

// PropTriggeredBy sets the TriggeredBy unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#TriggeredBy=
func PropTriggeredBy(units ...string) Property {
	return propDependency("TriggeredBy", units)
}

// PropPropagatesReloadTo sets the PropagatesReloadTo unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#PropagatesReloadTo=
func PropPropagatesReloadTo(units ...string) Property {
	return propDependency("PropagatesReloadTo", units)
}

// PropRequiresMountsFor sets the RequiresMountsFor unit property.  See
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiresMountsFor=
func PropRequiresMountsFor(units ...string) Property {
	return propDependency("RequiresMountsFor", units)
}
<|endoftext|>


<commit_before>// Package main is a script that reads a filesystem full of dcm files and
// generates a json report.
package main

import (
	"encoding/binary"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	// "strconv"
	"log"
	"strings"

	"github.com/davidgamba/go-dicom/dcmdump/tag"
	"github.com/davidgamba/go-dicom/dcmdump/ts"
	vri "github.com/davidgamba/go-dicom/dcmdump/vr"
	"github.com/davidgamba/go-getoptions"
)

var debug bool

func debugf(format string, a ...interface{}) (n int, err error) {
	if debug {
		return fmt.Printf(format, a...)
	}
	return 0, nil
}
func debugln(a ...interface{}) (n int, err error) {
	if debug {
		return fmt.Println(a...)
	}
	return 0, nil
}

type stringSlice []string

func (s stringSlice) contains(a string) bool {
	for _, b := range s {
		if a == b {
			return true
		}
	}
	return false
}

type dicomqr struct {
	Empty [128]byte
	DICM  [4]byte
	Rest  []byte
}

// DataElement -
type DataElement struct {
	N        int
	TagGroup []byte // [2]byte
	TagElem  []byte // [2]byte
	TagStr   string
	VR       []byte // [2]byte
	VRStr    string
	VRLen    int
	Len      uint32
	Data     []byte
	PartOfSQ bool
}

// String -
func (de *DataElement) String() string {
	tn := tag.Tag[de.TagStr]["name"]
	if _, ok := tag.Tag[de.TagStr]; !ok {
		tn = "MISSING"
	}
	padding := ""
	if de.PartOfSQ {
		padding = "    "
	}
	if de.Len < 128 {
		return fmt.Sprintf("%s%04d (%s) %s %d %d %s %s", padding, de.N, de.TagStr, de.VRStr, de.VRLen, de.Len, tn, de.stringData())
	}
	return fmt.Sprintf("%s%04d (%s) %s %d %d %s %s", padding, de.N, de.TagStr, de.VRStr, de.VRLen, de.Len, tn, "...")
}

type fh os.File

func readNBytes(f *os.File, size int) ([]byte, error) {
	data := make([]byte, size)
	for {
		data = data[:cap(data)]
		n, err := f.Read(data)
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, err
		}
		data = data[:n]
	}
	return data, nil
}

// http://rosettacode.org/wiki/Strip_control_codes_and_extended_characters_from_a_string#Go
// two UTF-8 functions identical except for operator comparing c to 127
func stripCtlFromUTF8(str string) string {
	return strings.Map(func(r rune) rune {
		if r >= 32 && r != 127 {
			return r
		}
		return '.'
	}, str)
}

func tagString(b []byte) string {
	tag := strings.ToUpper(fmt.Sprintf("%02x%02x%02x%02x", b[1], b[0], b[3], b[2]))
	return tag
}

func printBytes(b []byte) {
	if !debug {
		return
	}
	l := len(b)
	var s string
	for i := 0; i < l; i++ {
		s += stripCtlFromUTF8(string(b[i]))
		if i != 0 && i%8 == 0 {
			if i%16 == 0 {
				fmt.Printf(" - %s\n", s)
				s = ""
			} else {
				fmt.Printf(" - ")
			}
		}
		fmt.Printf("%2x ", b[i])
		if i == l-1 {
			if 15-i%16 > 7 {
				fmt.Printf(" - ")
			}
			for j := 0; j < 15-i%16; j++ {
				// fmt.Printf("   ")
				fmt.Printf("   ")
			}
			fmt.Printf(" - %s\n", s)
			s = ""
		}
	}
	fmt.Printf("\n")
}

func (de *DataElement) stringData() string {
	if de.TagStr == "00020010" {
		if tsStr, ok := ts.TS[string(de.Data)]; ok {
			return string(de.Data) + " " + tsStr["name"].(string)
		}
	}
	if _, ok := vri.VR[de.VRStr]["fixed"]; ok && vri.VR[de.VRStr]["fixed"].(bool) {
		s := ""
		l := len(de.Data)
		n := 0
		vrl := vri.VR[de.VRStr]["len"].(int)
		switch vrl {
		case 1:
			for n+1 <= l {
				s += fmt.Sprintf("%d ", de.Data[n])
				n++
			}
			return s
		case 2:
			for n+2 <= l {
				e := binary.LittleEndian.Uint16(de.Data[n : n+2])
				s += fmt.Sprintf("%d ", e)
				n += 2
			}
			return s
		case 4:
			for n+4 <= l {
				e := binary.LittleEndian.Uint32(de.Data[n : n+4])
				s += fmt.Sprintf("%d ", e)
				n += 4
			}
			return s
		default:
			return string(de.Data)
		}
	} else {
		if _, ok := vri.VR[de.VRStr]["padded"]; ok && vri.VR[de.VRStr]["padded"].(bool) {
			l := len(de.Data)
			if de.Data[l-1] == 0x0 {
				return string(de.Data[:l-1])
			}
			return string(de.Data)
		}
		return string(de.Data)
	}
}

func parseDataElement(bytes []byte, n int, explicit bool) {
	log.Printf("parseDataElement")
	l := len(bytes)
	// Data element
	m := n
	for n <= l && m+4 <= l {
		undefinedLen := false
		de := DataElement{N: n}
		m += 4
		t := bytes[n:m]
		de.TagGroup = bytes[n : n+2]
		de.TagElem = bytes[n+2 : n+4]
		de.TagStr = tagString(t)
		// TODO: Clean up tagString
		tagStr := tagString(t)
		log.Printf("n: %d, Tag: %X -> %s\n", n, t, tagStr)
		printBytes(bytes[n:m])
		n = m
		if tagStr == "" {
			log.Printf("%d Empty Tag: %s\n", n, tagStr)
		} else if _, ok := tag.Tag[tagStr]; !ok {
			fmt.Fprintf(os.Stderr, "INFO: %d Missing tag '%s'\n", n, tagStr)
		} else {
			log.Printf("Tag Name: %s\n", tag.Tag[tagStr]["name"])
		}
		var len uint32
		var vr string
		if explicit {
			debugf("%d VR\n", n)
			m += 2
			printBytes(bytes[n:m])
			de.VR = bytes[n:m]
			de.VRStr = string(bytes[n:m])
			vr = string(bytes[n:m])
			if _, ok := vri.VR[vr]; !ok {
				if bytes[n] == 0x0 && bytes[n+1] == 0x0 {
					fmt.Fprintf(os.Stderr, "INFO: Blank VR\n")
					vr = "00"
					de.VRStr = "00"
				} else {
					fmt.Fprintf(os.Stderr, "ERROR: %d Missing VR '%s'\n", n, vr)
					printBytes(bytes[n:])
					return
				}
			}
			n = m
			if vr == "OB" ||
				vr == "OD" ||
				vr == "OF" ||
				vr == "OL" ||
				vr == "OW" ||
				vr == "SQ" ||
				vr == "UC" ||
				vr == "UR" ||
				vr == "UT" ||
				vr == "UN" {
				debugln("Reserved")
				m += 2
				printBytes(bytes[n:m])
				n = m
				debugln("Lenght")
				m += 4
				printBytes(bytes[n:m])
				len = binary.LittleEndian.Uint32(bytes[n:m])
				n = m
			} else {
				debugln("Lenght")
				m += 2
				printBytes(bytes[n:m])
				len16 := binary.LittleEndian.Uint16(bytes[n:m])
				len = uint32(len16)
				n = m
			}
		} else {
			debugln("Lenght")
			m += 4
			printBytes(bytes[n:m])
			len = binary.LittleEndian.Uint32(bytes[n:m])
			n = m
		}
		if len == 0xFFFFFFFF {
			undefinedLen = true
			for {
				// Find FFFEE0DD: SequenceDelimitationItem
				endTag := bytes[m : m+4]
				endTagStr := tagString(endTag)
				if endTagStr == "FFFEE00D" || endTagStr == "FFFEE0DD" {
					log.Printf("found SequenceDelimitationItem at %d", m)
					len = uint32(m - n)
					m = n
					break
				} else {
					m++
					if m >= l {
						fmt.Fprintf(os.Stderr, "ERROR: Couldn't find SequenceDelimitationItem\n")
						printBytes(bytes[n:l])
						return
					}
				}
			}
		}
		de.Len = len
		debugf("Lenght: %d\n", len)
		m += int(len)
		printBytes(bytes[n:m])
		if vr == "SQ" {
			de.Data = []byte{}
			fmt.Println(de.String())
			log.Printf("parseDataElement SQ")
			parseDataElement(bytes[n:m], n, explicit)
		} else {
			de.Data = bytes[n:m]
			fmt.Println(de.String())
		}
		if undefinedLen {
			m += 8
		}
		n = m
	}
	log.Printf("parseDataElement Complete")
}

func parseSQDataElements(bytes []byte, n int, explicit bool) int {
	log.Printf("parseSQDataElements")
	l := len(bytes)
	m := n
	for n <= l && m+4 <= l {
		de := DataElement{N: n}
		m := n + 4
		printBytes(bytes[n:m])
		t := bytes[n:m]
		tagStr := tagString(t)
		de.TagGroup = bytes[n : n+2]
		de.TagElem = bytes[n+2 : n+4]
		de.TagStr = tagString(t)
		log.Printf("n: %d, Tag: %X -> %s\n", n, t, tagStr)
		if _, ok := tag.Tag[tagStr]; !ok {
			fmt.Fprintf(os.Stderr, "ERROR: %d Missing tag '%s'\n", n, tagStr)
		}
		// if _, ok := tag.Tag[tagStr]; ok && tag.Tag[tagStr]["name"] == "ItemDelimitationItem" {
		// 	sequenceDelimitationItem = true
		// }
		for m <= l {
			// Find FFFEE00D: ItemDelimitationItem
			endTag := bytes[m : m+4]
			endTagStr := tagString(endTag)
			if endTagStr == "FFFEE00D" {
				debugln("Item Delim found")
				de.Data = bytes[n:m]
				printBytes(bytes[n:m])
				log.Printf("Tag: %X -> %s\n", endTag, endTagStr)
				m += 4
				n = m
				// m += 4
				// printBytes(bytes[n:m])
				// n = m
				break
			} else {
				m++
			}
		}
		fmt.Println(de.String())
	}
	log.Printf("parseSQDataElement Complete")
	return n
}

func synopsis() {
	synopsis := `dcmdump <dcm_file> [--debug]
`
	fmt.Fprintln(os.Stderr, synopsis)
}

func main() {

	var file string
	opt := getoptions.New()
	opt.Bool("help", false)
	opt.BoolVar(&debug, "debug", false)
	remaining, err := opt.Parse(os.Args[1:])
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
		os.Exit(1)
	}
	if opt.Called("help") {
		synopsis()
		os.Exit(1)
	}
	if len(remaining) < 1 {
		fmt.Fprintf(os.Stderr, "ERROR: Missing file\n")
		synopsis()
		os.Exit(1)
	}
	file = remaining[0]
	if !debug {
		log.SetOutput(ioutil.Discard)
	}
	bytes, err := ioutil.ReadFile(file)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: failed to read file: '%s'\n", err)
		os.Exit(1)
	}

	// Intro
	n := 128
	printBytes(bytes[0:n])
	// DICM
	m := n + 4
	printBytes(bytes[n:m])
	n = m

	explicit := true

	parseDataElement(bytes, n, explicit)
}
<commit_msg>dcmdump: Finish SQ with SequenceDelimitationItem only<commit_after>// Package main is a script that reads a filesystem full of dcm files and
// generates a json report.
package main

import (
	"encoding/binary"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	// "strconv"
	"log"
	"strings"

	"github.com/davidgamba/go-dicom/dcmdump/tag"
	"github.com/davidgamba/go-dicom/dcmdump/ts"
	vri "github.com/davidgamba/go-dicom/dcmdump/vr"
	"github.com/davidgamba/go-getoptions"
)

var debug bool

func debugf(format string, a ...interface{}) (n int, err error) {
	if debug {
		return fmt.Printf(format, a...)
	}
	return 0, nil
}
func debugln(a ...interface{}) (n int, err error) {
	if debug {
		return fmt.Println(a...)
	}
	return 0, nil
}

type stringSlice []string

func (s stringSlice) contains(a string) bool {
	for _, b := range s {
		if a == b {
			return true
		}
	}
	return false
}

type dicomqr struct {
	Empty [128]byte
	DICM  [4]byte
	Rest  []byte
}

// DataElement -
type DataElement struct {
	N        int
	TagGroup []byte // [2]byte
	TagElem  []byte // [2]byte
	TagStr   string
	VR       []byte // [2]byte
	VRStr    string
	VRLen    int
	Len      uint32
	Data     []byte
	PartOfSQ bool
}

// String -
func (de *DataElement) String() string {
	tn := tag.Tag[de.TagStr]["name"]
	if _, ok := tag.Tag[de.TagStr]; !ok {
		tn = "MISSING"
	}
	padding := ""
	if de.PartOfSQ {
		padding = "    "
	}
	if de.Len < 128 {
		return fmt.Sprintf("%s%04d (%s) %s %d %d %s %s", padding, de.N, de.TagStr, de.VRStr, de.VRLen, de.Len, tn, de.stringData())
	}
	return fmt.Sprintf("%s%04d (%s) %s %d %d %s %s", padding, de.N, de.TagStr, de.VRStr, de.VRLen, de.Len, tn, "...")
}

type fh os.File

func readNBytes(f *os.File, size int) ([]byte, error) {
	data := make([]byte, size)
	for {
		data = data[:cap(data)]
		n, err := f.Read(data)
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, err
		}
		data = data[:n]
	}
	return data, nil
}

// http://rosettacode.org/wiki/Strip_control_codes_and_extended_characters_from_a_string#Go
// two UTF-8 functions identical except for operator comparing c to 127
func stripCtlFromUTF8(str string) string {
	return strings.Map(func(r rune) rune {
		if r >= 32 && r != 127 {
			return r
		}
		return '.'
	}, str)
}

func tagString(b []byte) string {
	tag := strings.ToUpper(fmt.Sprintf("%02x%02x%02x%02x", b[1], b[0], b[3], b[2]))
	return tag
}

func printBytes(b []byte) {
	if !debug {
		return
	}
	l := len(b)
	var s string
	for i := 0; i < l; i++ {
		s += stripCtlFromUTF8(string(b[i]))
		if i != 0 && i%8 == 0 {
			if i%16 == 0 {
				fmt.Printf(" - %s\n", s)
				s = ""
			} else {
				fmt.Printf(" - ")
			}
		}
		fmt.Printf("%2x ", b[i])
		if i == l-1 {
			if 15-i%16 > 7 {
				fmt.Printf(" - ")
			}
			for j := 0; j < 15-i%16; j++ {
				// fmt.Printf("   ")
				fmt.Printf("   ")
			}
			fmt.Printf(" - %s\n", s)
			s = ""
		}
	}
	fmt.Printf("\n")
}

func (de *DataElement) stringData() string {
	if de.TagStr == "00020010" {
		if tsStr, ok := ts.TS[string(de.Data)]; ok {
			return string(de.Data) + " " + tsStr["name"].(string)
		}
	}
	if _, ok := vri.VR[de.VRStr]["fixed"]; ok && vri.VR[de.VRStr]["fixed"].(bool) {
		s := ""
		l := len(de.Data)
		n := 0
		vrl := vri.VR[de.VRStr]["len"].(int)
		switch vrl {
		case 1:
			for n+1 <= l {
				s += fmt.Sprintf("%d ", de.Data[n])
				n++
			}
			return s
		case 2:
			for n+2 <= l {
				e := binary.LittleEndian.Uint16(de.Data[n : n+2])
				s += fmt.Sprintf("%d ", e)
				n += 2
			}
			return s
		case 4:
			for n+4 <= l {
				e := binary.LittleEndian.Uint32(de.Data[n : n+4])
				s += fmt.Sprintf("%d ", e)
				n += 4
			}
			return s
		default:
			return string(de.Data)
		}
	} else {
		if _, ok := vri.VR[de.VRStr]["padded"]; ok && vri.VR[de.VRStr]["padded"].(bool) {
			l := len(de.Data)
			if de.Data[l-1] == 0x0 {
				return string(de.Data[:l-1])
			}
			return string(de.Data)
		}
		return string(de.Data)
	}
}

func parseDataElement(bytes []byte, n int, explicit bool) {
	log.Printf("parseDataElement")
	l := len(bytes)
	// Data element
	m := n
	for n <= l && m+4 <= l {
		undefinedLen := false
		de := DataElement{N: n}
		m += 4
		t := bytes[n:m]
		de.TagGroup = bytes[n : n+2]
		de.TagElem = bytes[n+2 : n+4]
		de.TagStr = tagString(t)
		// TODO: Clean up tagString
		tagStr := tagString(t)
		log.Printf("n: %d, Tag: %X -> %s\n", n, t, tagStr)
		printBytes(bytes[n:m])
		n = m
		if tagStr == "" {
			log.Printf("%d Empty Tag: %s\n", n, tagStr)
		} else if _, ok := tag.Tag[tagStr]; !ok {
			fmt.Fprintf(os.Stderr, "INFO: %d Missing tag '%s'\n", n, tagStr)
		} else {
			log.Printf("Tag Name: %s\n", tag.Tag[tagStr]["name"])
		}
		var len uint32
		var vr string
		if explicit {
			debugf("%d VR\n", n)
			m += 2
			printBytes(bytes[n:m])
			de.VR = bytes[n:m]
			de.VRStr = string(bytes[n:m])
			vr = string(bytes[n:m])
			if _, ok := vri.VR[vr]; !ok {
				if bytes[n] == 0x0 && bytes[n+1] == 0x0 {
					fmt.Fprintf(os.Stderr, "INFO: Blank VR\n")
					vr = "00"
					de.VRStr = "00"
				} else {
					fmt.Fprintf(os.Stderr, "ERROR: %d Missing VR '%s'\n", n, vr)
					printBytes(bytes[n:])
					return
				}
			}
			n = m
			if vr == "OB" ||
				vr == "OD" ||
				vr == "OF" ||
				vr == "OL" ||
				vr == "OW" ||
				vr == "SQ" ||
				vr == "UC" ||
				vr == "UR" ||
				vr == "UT" ||
				vr == "UN" {
				debugln("Reserved")
				m += 2
				printBytes(bytes[n:m])
				n = m
				debugln("Lenght")
				m += 4
				printBytes(bytes[n:m])
				len = binary.LittleEndian.Uint32(bytes[n:m])
				n = m
			} else {
				debugln("Lenght")
				m += 2
				printBytes(bytes[n:m])
				len16 := binary.LittleEndian.Uint16(bytes[n:m])
				len = uint32(len16)
				n = m
			}
		} else {
			debugln("Lenght")
			m += 4
			printBytes(bytes[n:m])
			len = binary.LittleEndian.Uint32(bytes[n:m])
			n = m
		}
		if len == 0xFFFFFFFF {
			undefinedLen = true
			for {
				// Find FFFEE0DD: SequenceDelimitationItem
				endTag := bytes[m : m+4]
				endTagStr := tagString(endTag)
				if endTagStr == "FFFEE0DD" {
					log.Printf("found SequenceDelimitationItem at %d", m)
					len = uint32(m - n)
					m = n
					break
				} else {
					m++
					if m >= l {
						fmt.Fprintf(os.Stderr, "ERROR: Couldn't find SequenceDelimitationItem\n")
						printBytes(bytes[n:l])
						return
					}
				}
			}
		}
		de.Len = len
		debugf("Lenght: %d\n", len)
		m += int(len)
		printBytes(bytes[n:m])
		if vr == "SQ" {
			de.Data = []byte{}
			fmt.Println(de.String())
			log.Printf("parseDataElement SQ")
			if undefinedLen {
				m += 8
			}
			parseDataElement(bytes[n:m], n, explicit)
			log.Printf("parseDataElement SQ Complete")
		} else {
			de.Data = bytes[n:m]
			fmt.Println(de.String())
			if undefinedLen {
				m += 8
			}
		}
		n = m
	}
	log.Printf("parseDataElement Complete")
}

func parseSQDataElements(bytes []byte, n int, explicit bool) int {
	log.Printf("parseSQDataElements")
	l := len(bytes)
	m := n
	for n <= l && m+4 <= l {
		de := DataElement{N: n}
		m := n + 4
		printBytes(bytes[n:m])
		t := bytes[n:m]
		tagStr := tagString(t)
		de.TagGroup = bytes[n : n+2]
		de.TagElem = bytes[n+2 : n+4]
		de.TagStr = tagString(t)
		log.Printf("n: %d, Tag: %X -> %s\n", n, t, tagStr)
		if _, ok := tag.Tag[tagStr]; !ok {
			fmt.Fprintf(os.Stderr, "ERROR: %d Missing tag '%s'\n", n, tagStr)
		}
		// if _, ok := tag.Tag[tagStr]; ok && tag.Tag[tagStr]["name"] == "ItemDelimitationItem" {
		// 	sequenceDelimitationItem = true
		// }
		for m <= l {
			// Find FFFEE00D: ItemDelimitationItem
			endTag := bytes[m : m+4]
			endTagStr := tagString(endTag)
			if endTagStr == "FFFEE00D" {
				debugln("Item Delim found")
				de.Data = bytes[n:m]
				printBytes(bytes[n:m])
				log.Printf("Tag: %X -> %s\n", endTag, endTagStr)
				m += 4
				n = m
				// m += 4
				// printBytes(bytes[n:m])
				// n = m
				break
			} else {
				m++
			}
		}
		fmt.Println(de.String())
	}
	log.Printf("parseSQDataElement Complete")
	return n
}

func synopsis() {
	synopsis := `dcmdump <dcm_file> [--debug]
`
	fmt.Fprintln(os.Stderr, synopsis)
}

func main() {

	var file string
	opt := getoptions.New()
	opt.Bool("help", false)
	opt.BoolVar(&debug, "debug", false)
	remaining, err := opt.Parse(os.Args[1:])
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
		os.Exit(1)
	}
	if opt.Called("help") {
		synopsis()
		os.Exit(1)
	}
	if len(remaining) < 1 {
		fmt.Fprintf(os.Stderr, "ERROR: Missing file\n")
		synopsis()
		os.Exit(1)
	}
	file = remaining[0]
	if !debug {
		log.SetOutput(ioutil.Discard)
	}
	bytes, err := ioutil.ReadFile(file)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: failed to read file: '%s'\n", err)
		os.Exit(1)
	}

	// Intro
	n := 128
	printBytes(bytes[0:n])
	// DICM
	m := n + 4
	printBytes(bytes[n:m])
	n = m

	explicit := true

	parseDataElement(bytes, n, explicit)
}
<|endoftext|>


<commit_before>package commands

import (
	"os"
	"sort"
	"strconv"
	"time"

	"github.com/concourse/fly/rc"
	"github.com/concourse/fly/ui"
	"github.com/dgrijalva/jwt-go"
	"github.com/fatih/color"
)

type TargetsCommand struct{}

func (command *TargetsCommand) Execute([]string) error {
	flyYAML, err := rc.LoadTargets()
	if err != nil {
		return err
	}

	table := ui.Table{
		Headers: ui.TableRow{
			{Contents: "name", Color: color.New(color.Bold)},
			{Contents: "url", Color: color.New(color.Bold)},
			{Contents: "expiry", Color: color.New(color.Bold)},
		},
	}

	for targetName, targetValues := range flyYAML.Targets {
		expirationTime := GetExpirationFromString(targetValues.Token)

		row := ui.TableRow{
			{Contents: string(targetName)},
			{Contents: targetValues.API},
			{Contents: expirationTime},
		}

		table.Data = append(table.Data, row)
	}

	sort.Sort(table.Data)

	return table.Render(os.Stdout)
}

func GetExpirationFromString(token *rc.TargetToken) string {
	if token == nil || token.Type == "" || token.Value == "" {
		return "n/a"
	}

	parsedToken, _ := jwt.Parse(token.Value, func(token *jwt.Token) (interface{}, error) {
		return "", nil
	})

	expClaim, ok := parsedToken.Claims["exp"]
	if !ok {
		return "n/a"
	}

	var intSeconds int64

	floatSeconds, ok := expClaim.(float64)
	if ok {
		intSeconds = int64(floatSeconds)
	} else {
		stringSeconds, ok := expClaim.(string)
		if !ok {
			return "n/a"
		}
		var err error
		intSeconds, err = strconv.ParseInt(stringSeconds, 10, 64)
		if err != nil {
			return "n/a"
		}
	}

	unixSeconds := time.Unix(intSeconds, 0).UTC()

	return unixSeconds.Format(time.RFC1123)
}
<commit_msg>updates for jwt claims interface<commit_after>package commands

import (
	"os"
	"sort"
	"strconv"
	"time"

	"github.com/concourse/fly/rc"
	"github.com/concourse/fly/ui"
	"github.com/dgrijalva/jwt-go"
	"github.com/fatih/color"
)

type TargetsCommand struct{}

func (command *TargetsCommand) Execute([]string) error {
	flyYAML, err := rc.LoadTargets()
	if err != nil {
		return err
	}

	table := ui.Table{
		Headers: ui.TableRow{
			{Contents: "name", Color: color.New(color.Bold)},
			{Contents: "url", Color: color.New(color.Bold)},
			{Contents: "expiry", Color: color.New(color.Bold)},
		},
	}

	for targetName, targetValues := range flyYAML.Targets {
		expirationTime := GetExpirationFromString(targetValues.Token)

		row := ui.TableRow{
			{Contents: string(targetName)},
			{Contents: targetValues.API},
			{Contents: expirationTime},
		}

		table.Data = append(table.Data, row)
	}

	sort.Sort(table.Data)

	return table.Render(os.Stdout)
}

func GetExpirationFromString(token *rc.TargetToken) string {
	if token == nil || token.Type == "" || token.Value == "" {
		return "n/a"
	}

	parsedToken, _ := jwt.Parse(token.Value, func(token *jwt.Token) (interface{}, error) {
		return "", nil
	})

	claims := parsedToken.Claims.(jwt.MapClaims)
	expClaim, ok := claims["exp"]
	if !ok {
		return "n/a"
	}

	var intSeconds int64

	floatSeconds, ok := expClaim.(float64)
	if ok {
		intSeconds = int64(floatSeconds)
	} else {
		stringSeconds, ok := expClaim.(string)
		if !ok {
			return "n/a"
		}
		var err error
		intSeconds, err = strconv.ParseInt(stringSeconds, 10, 64)
		if err != nil {
			return "n/a"
		}
	}

	unixSeconds := time.Unix(intSeconds, 0).UTC()

	return unixSeconds.Format(time.RFC1123)
}
<|endoftext|>