Example #1
0
func TestAtof(t *testing.T) {
	var (
		iv interface{}
	)
	iv = clike.Atof("123.456") // pick up result as an interface so we can test type as well as value
	switch iv.(type) {
	case float64:
		break

	default:
		t.Errorf("atof() did not return float64, no other atof() tests executed")
		return
	}

	if iv.(float64) != 123.456 {
		t.Errorf("atoll( '123.456' ) returned %.3f; did not return 123.456", iv.(float64))
	}
}
Example #2
0
/*
	Given a thing (field value in a struct), set the thing with the element in the map (key)
	the map value to the proper type.
*/
func set_value(thing reflect.Value, kind reflect.Kind, key string, tag_id string, pfx string, annon bool, m map[string]string) {

	if !thing.CanAddr() { // prevent stack dump
		return
	}

	switch kind {
	default:
		fmt.Fprintf(os.Stderr, "transform.mts: tagged sturct member cannot be converted from map: tag=%s kind=%v\n", key, thing.Kind())

	case reflect.String:
		thing.SetString(m[key])

	case reflect.Ptr:
		p := thing.Elem() // get the pointer value; allows us to suss the type
		if !p.IsValid() { // ptr is nill in the struct so we must allocate a pointer to 0 so it can be changed below
			thing.Set(reflect.New(thing.Type().Elem()))
			p = thing.Elem()
		}
		switch p.Kind() {
		case reflect.String:
			s := m[key] // copy it and then point to the copy
			thing.Set(reflect.ValueOf(&s))

		case reflect.Int:
			i := clike.Atoi(m[key]) // convert to integer and then point at the value
			thing.Set(reflect.ValueOf(&i))

		case reflect.Int64:
			i := clike.Atoi64(m[key])
			thing.Set(reflect.ValueOf(&i))

		case reflect.Int32:
			i := clike.Atoi32(m[key])
			thing.Set(reflect.ValueOf(&i))

		case reflect.Int16:
			i := clike.Atoi16(m[key])
			thing.Set(reflect.ValueOf(&i))

		case reflect.Int8:
			i := int8(clike.Atoi16(m[key]))
			thing.Set(reflect.ValueOf(&i))

		case reflect.Uint:
			ui := clike.Atou(m[key])
			thing.Set(reflect.ValueOf(&ui))

		case reflect.Uint64:
			ui := clike.Atou64(m[key])
			thing.Set(reflect.ValueOf(&ui))

		case reflect.Uint32:
			ui := clike.Atou32(m[key])
			thing.Set(reflect.ValueOf(&ui))

		case reflect.Uint16:
			ui := clike.Atou16(m[key])
			thing.Set(reflect.ValueOf(&ui))

		case reflect.Uint8:
			ui := uint8(clike.Atou16(m[key]))
			thing.Set(reflect.ValueOf(&ui))

		case reflect.Float64:
			fv := clike.Atof(m[key])
			thing.Set(reflect.ValueOf(&fv))

		case reflect.Float32:
			fv := float32(clike.Atof(m[key]))
			thing.Set(reflect.ValueOf(&fv))

		case reflect.Bool:
			b := m[key] == "true" || m[key] == "True" || m[key] == "TRUE"
			thing.Set(reflect.ValueOf(&b))

		case reflect.Struct:
			map_to_struct(m, p, p.Type(), tag_id, pfx) // recurse to process
		}

	case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
		thing.SetInt(clike.Atoi64(m[key]))

	case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8:
		thing.SetUint(uint64(clike.Atoi64(m[key])))

	case reflect.Float64, reflect.Float32:
		thing.SetFloat(clike.Atof(m[key]))

	case reflect.Bool:
		thing.SetBool(m[key] == "true")

	case reflect.Map:
		new_map := reflect.MakeMap(thing.Type()) // create the map
		thing.Set(new_map)                       // put it in the struct

		idx := key + "/" // now populate the map
		ilen := len(idx)
		for k, _ := range m { // we could keep a separate list of keys, but for now this should do
			if strings.HasPrefix(k, key) {
				tokens := strings.Split(k[ilen:], "/")
				map_key := reflect.ValueOf(tokens[0]) // map key is everything past the tag to the next slant
				map_ele_type := new_map.Type().Elem() // the type of the element that the map references

				mthing := reflect.New(map_ele_type).Elem() // new returns pointer, so dereference with Elem() (value not type!)

				set_value(mthing, mthing.Kind(), idx+tokens[0], tag_id, idx+tokens[0]+"/", false, m) // put the value into the map thing
				new_map.SetMapIndex(map_key, mthing)                                                 // put it into the map (order IS important; add to map after recursion)
				//fmt.Fprintf( os.Stderr, "saving: %s  thing-type=%s mthing=%s\n", map_key, thing.Type(), mthing )
			}
		}

	case reflect.Slice:
		c := clike.Atoi(m[key+".cap"])
		l := clike.Atoi(m[key+".len"])

		thing.Set(reflect.MakeSlice(thing.Type(), l, c)) // create a new slice with the same len/cap that it had
		for j := 0; j < l; j++ {
			idx := fmt.Sprintf("%s/%d", key, j)
			set_value(thing.Index(j), thing.Type().Elem().Kind(), idx, tag_id, idx+"/", false, m) // populate each value of the slice up to len
		}

	case reflect.Struct:
		if annon {
			map_to_struct(m, thing, thing.Type(), tag_id, key) // anon structs share namespace, so prefix is the same
		} else {
			map_to_struct(m, thing, thing.Type(), tag_id, pfx) // dive to get the substruct adding a level to the prefix
		}

	}

}
Example #3
0
/*
	Internal funciton to convert an interface into a supported desired value.
*/
func cvt2desired(v interface{}, desired int) interface{} {
	switch v.(type) {

	case string:
		switch desired {
		case ET_STRING:
			return v
		case ET_STRINGP:
			return &v
		case ET_INT:
			return v.(int)
		case ET_UINT:
			return v.(uint)
		case ET_INT64:
			return v.(int64)
		case ET_FLOAT:
			return v.(float64)
		case ET_BOOL:
			return v == "true"
		}

	case *string:
		switch desired {
		case ET_STRING:
			return *(v.(*string))
		case ET_STRINGP:
			return v
		case ET_INT:
			return clike.Atoi(*(v.(*string)))
		case ET_UINT:
			return clike.Atou(*(v.(*string)))
		case ET_INT64:
			return clike.Atoll(*(v.(*string)))
		case ET_FLOAT:
			return clike.Atof(*(v.(*string)))
		case ET_BOOL:
			return *(v.(*string)) == "true"
		}

	case float64:
		switch desired {
		case ET_STRING:
			return fmt.Sprintf("%.2f", v)
		case ET_STRINGP:
			s := fmt.Sprintf("%.2f", v)
			return &s
		case ET_INT:
			return int(v.(float64))
		case ET_UINT:
			return uint(v.(float64))
		case ET_INT64:
			return int64(v.(float64))
		case ET_FLOAT:
			return v
		case ET_BOOL:
			return v.(float64) != 0.0
		}

	case int:
		switch desired {
		case ET_STRING:
			return fmt.Sprintf("%d", v)
		case ET_STRINGP:
			s := fmt.Sprintf("%d", v)
			return &s
		case ET_INT:
			return v
		case ET_UINT:
			return uint(v.(int))
		case ET_INT64:
			return int64(v.(int))
		case ET_FLOAT:
			return float64(v.(int))
		case ET_BOOL:
			return v.(int) != 0
		}

	case int64:
		switch desired {
		case ET_STRING:
			return fmt.Sprintf("%d", v)
		case ET_STRINGP:
			s := fmt.Sprintf("%d", v)
			return &s
		case ET_INT:
			return int(v.(int64))
		case ET_UINT:
			return uint(v.(int64))
		case ET_INT64:
			return v
		case ET_FLOAT:
			return float64(v.(int64))
		case ET_BOOL:
			return v.(int64) != 0
		}

	case bool:
		switch desired {
		case ET_STRING:
			return fmt.Sprintf("%v", v)
		case ET_STRINGP:
			s := fmt.Sprintf("%v", v)
			return &s
		case ET_INT:
			if v.(bool) {
				return int(1)
			} else {
				return int(0)
			}
		case ET_UINT:
			if v.(bool) {
				return uint(1)
			} else {
				return uint(0)
			}
		case ET_INT64:
			if v.(bool) {
				return int64(1)
			} else {
				return int64(0)
			}
		case ET_FLOAT:
			if v.(bool) {
				return 1.0
			} else {
				return 0.0
			}
		case ET_BOOL:
			return v
		}
	}

	return nil
}
Example #4
0
/*
	Parses a configuration file containing sections and key/value pairs within the
	sections.  Returns a map of sections (by name) with each entry in the map being
	a map[string]interface{}.  Key/values are converted and stored by the key name as
	either string pointers or float64s.  If the value is quoted, the quotes are removed.

	Section names may be duplicated which causes values appearing later in subsequent
	sections to be added to the previously encountered values.  Keys within each section
	must be uniqueue.  If a duplicate key is encountered, the last one read will be the
	one that ends up in the map.

	If all_str is true, then all values are returned as strings; no attempt is made
	to convert values that seem to be numeric into actual values as it  might make logic
	in the user programme a bit easier (no interface dreferences).
*/
func Parse(sectmap map[string]map[string]interface{}, fname string, all_str bool) (m map[string]map[string]interface{}, err error) {
	var (
		rec   string                       // record read from input file
		sect  map[string]interface{}       // current section
		sname string                       // current section name
		rerr  error                  = nil // read error
	)

	if sectmap != nil {
		m = sectmap
		if m["default"] == nil { // don't count on user creating a default section
			m["default"] = make(map[string]interface{})
		}
	} else {
		m = make(map[string]map[string]interface{})
		m["default"] = make(map[string]interface{})
	}

	sname = "default"
	sect = m[sname] // always start in default section

	f, err := os.Open(fname)
	if err != nil {
		return
	}
	defer f.Close()

	br := bufio.NewReader(f)
	for rerr == nil {
		rec, rerr = br.ReadString('\n')
		if rerr == nil {
			rec = strings.Trim(rec, " \t\n") // ditch lead/trail whitespace

			if len(rec) == 0 { // blank line
				continue
			}

			switch rec[0] {
			case ':': // section
				//sname = rec[1:];
				_, tokens := token.Tokenise_qpopulated(rec, " \t") // easy way to ditch everything after the first token
				sname = tokens[0][1:]
				if m[sname] == nil {
					sect = make(map[string]interface{})
					m[sname] = sect
				} else {
					sect = m[sname]
				}

			case '#': // comment
				// nop

			case '<':
				m, err = Parse(m, rec[1:], all_str)
				if err != nil {
					return
				}

			default: // assume key value pair
				append := false
				first_tok := 1                              // first token of var is 1, but could be later
				force_str := strings.Index(rec, "\"") != -1 // if a quote in the buffer, we force it to be a string

				ntokens, tokens := token.Tokenise_qpopulated(rec, " \t=")
				if ntokens >= 2 { // if key = "value" # [comment],  n will be 3 or more
					tl := len(tokens[0])

					if tokens[0][tl-1:] == "+" { //foo+= bar rather than foo = bar or foo += bar
						tokens[0] = tokens[0][:tl-1]
						append = true
					} else {
						if tokens[1] == "+" { // += results in lone plus, not to be confused with +9999
							append = true
							first_tok++
						}
					}

					key := tokens[0]
					if tokens[first_tok] == "" { // key = (missing value) given
						tokens[first_tok] = " "
					}
					fc := tokens[first_tok][0:1]
					if !force_str && !all_str && ((fc >= "0" && fc <= "9") || fc == "+" || fc == "-") { // allowed to convert numbers to float
						sect[key] = clike.Atof(tokens[first_tok])
					} else {
						dup := ""
						sep := ""
						for i := first_tok; i < ntokens && tokens[i][0:1] != "#"; i++ {
							dup += sep + tokens[i] // snarf tokens up to comment reducing white space to 1 blank
							sep = " "
						}
						if append && sect[key] != nil {
							if old_str, ok := sect[key].(*string); ok {
								dup = *old_str + " " + dup
							}
						}

						sect[key] = &dup
					}
				} // silently discard token that is just a key, allowing the default to override
			}
		}
	}

	if rerr != io.EOF {
		err = rerr
	}

	return
}
Example #5
0
/*
	Parses a configuration file containing sections and key/value pairs within the
	sections.  Returns a map of sections (by name) with each entry in the map being
	a map[string]interface{}.  Key/values are converted and stored by the key name as
	either string pointers or float64s.  If the value is quoted, the quotes are removed.

	Section names may be duplicated which causes values appearing later in subsequent
	sections to be added to the previously encountered values.  Keys within each section
	must be uniqueue.  If a duplicate key is encountered, the last one read will be the
	one that ends up in the map.

	If all_str is true, then all values are returned as strings; no attempt is made
	to convert values that seem to be numeric into actual values as it  might make logic
	in the user programme a bit easier (no interface dreferences).
*/
func Parse(sectmap map[string]map[string]interface{}, fname string, all_str bool) (m map[string]map[string]interface{}, err error) {
	var (
		rec   string                       // record read from input file
		sect  map[string]interface{}       // current section
		sname string                       // current section name
		rerr  error                  = nil // read error
	)

	if sectmap != nil {
		m = sectmap
		if m["default"] == nil { // don't count on user creating a default section
			m["default"] = make(map[string]interface{})
		}
	} else {
		m = make(map[string]map[string]interface{})
		m["default"] = make(map[string]interface{})
	}

	sname = "default"
	sect = m[sname] // always start in default section

	f, err := os.Open(fname)
	if err != nil {
		return
	}
	defer f.Close()

	br := bufio.NewReader(f)
	for rerr == nil {
		rec, rerr = br.ReadString('\n')
		if rerr == nil {
			rec = strings.Trim(rec, " \t\n") // ditch lead/trail whitespace

			if len(rec) == 0 { // blank line
				continue
			}

			switch rec[0] {
			case ':': // section
				//sname = rec[1:];
				_, tokens := token.Tokenise_qpopulated(rec, " \t") // easy way to ditch everything after the first token
				sname = tokens[0][1:]
				if m[sname] == nil {
					sect = make(map[string]interface{})
					m[sname] = sect
				} else {
					sect = m[sname]
				}

			case '#': // comment
				// nop

			case '<':
				m, err = Parse(m, rec[1:], all_str)
				if err != nil {
					return
				}

			default: // assume key value pair
				ntokens, tokens := token.Tokenise_qpopulated(rec, " \t=")
				if ntokens >= 2 { // if key = "value" # [comment],  n will be 3 or more
					key := tokens[0]
					if tokens[1] == "" { // key = (missing value) given
						tokens[1] = " "
					}
					fc := tokens[1][0:1]
					if !all_str && ((fc >= "0" && fc <= "9") || fc == "+" || fc == "-") { // allowed to convert numbers to float
						sect[key] = clike.Atof(tokens[1])
					} else {
						dup := ""
						sep := ""
						for i := 1; i < ntokens && tokens[i][0:1] != "#"; i++ {
							dup += sep + tokens[i] // snarf tokens up to comment reducing white space to 1 blank
							sep = " "
						}
						sect[key] = &dup
					}
				} // silently discard token that is just a key, allowing the default to override
			}
		}
	}

	if rerr != io.EOF {
		err = rerr
	}

	return
}