flag.go (3091B)
1 package asm 2 3 import ( 4 "encoding/csv" 5 "fmt" 6 "io" 7 "os" 8 "strconv" 9 10 "git.defalsify.org/vise.git/state" 11 ) 12 13 // FlagParser is used to resolve flag strings to corresponding 14 // flag index integer values. 15 type FlagParser struct { 16 flag map[string]string 17 flagDescription map[uint32]string 18 hi uint32 19 debug bool 20 } 21 22 // NewFlagParser creates a new FlagParser 23 func NewFlagParser() *FlagParser { 24 return &FlagParser{ 25 flag: make(map[string]string), 26 flagDescription: make(map[uint32]string), 27 } 28 } 29 30 func(pp *FlagParser) WithDebug() *FlagParser { 31 pp.debug = true 32 return pp 33 } 34 35 // GetFlag returns the flag index value for a given flag string 36 // as a numeric string. 37 // 38 // If flag string has not been registered, an error is returned. 39 func(pp *FlagParser) GetAsString(key string) (string, error) { 40 v, ok := pp.flag[key] 41 if !ok { 42 return "", fmt.Errorf("no flag registered under key: %s", key) 43 } 44 return v, nil 45 } 46 47 // GetFlag returns the flag index integer value for a given 48 // flag string 49 // 50 // If flag string has not been registered, an error is returned. 51 func(pp *FlagParser) GetFlag(key string) (uint32, error) { 52 v, err := pp.GetAsString(key) 53 if err != nil { 54 return 0, err 55 } 56 r, err := strconv.Atoi(v) // cannot fail 57 return uint32(r), nil 58 } 59 60 // GetDescription returns a flag description for a given flag index, 61 // if available. 62 // 63 // If no description has been provided, an error is returned. 64 func(pp *FlagParser) GetDescription(idx uint32) (string, error) { 65 v, ok := pp.flagDescription[idx] 66 if !ok { 67 return "", fmt.Errorf("no description for flag idx: %v", idx) 68 } 69 return v, nil 70 } 71 72 // Last returns the highest registered flag index value 73 func(pp *FlagParser) Last() uint32 { 74 return pp.hi 75 } 76 77 // Load parses a Comma Seperated Value file under the given filepath 78 // to provide mappings between flag strings and flag indices. 79 // 80 // The expected format is: 81 // 82 // Field 1: The literal string "flag" 83 // Field 2: Flag string 84 // Field 3: Flag index 85 // Field 4: Flag description (optional) 86 func(pp *FlagParser) Load(fp string) (int, error) { 87 var i int 88 f, err := os.Open(fp) 89 if err != nil { 90 return 0, err 91 } 92 defer f.Close() 93 r := csv.NewReader(f) 94 r.FieldsPerRecord = -1 95 for i = 0; true; i++ { 96 v, err := r.Read() 97 if err != nil { 98 if err == io.EOF { 99 break 100 } 101 return 0, err 102 } 103 if v[0] == "flag" { 104 if len(v) < 3 { 105 return 0, fmt.Errorf("Not enough fields for flag setting in line %d", i) 106 } 107 vv, err := strconv.Atoi(v[2]) 108 if err != nil { 109 return 0, fmt.Errorf("Flag translation value must be numeric") 110 } 111 if vv < state.FLAG_USERSTART { 112 return 0, fmt.Errorf("Minimum flag value is FLAG_USERSTART (%d)", state.FLAG_USERSTART) 113 } 114 fl := uint32(vv) 115 pp.flag[v[1]] = v[2] 116 if fl > pp.hi { 117 pp.hi = fl 118 } 119 120 if (len(v) > 3) { 121 pp.flagDescription[uint32(fl)] = v[3] 122 logg.Debugf("added flag translation", "from", v[1], "to", v[2], "description", v[3]) 123 } else { 124 logg.Debugf("added flag translation", "from", v[1], "to", v[2]) 125 } 126 if pp.debug { 127 state.FlagDebugger.Register(fl, v[2]) 128 } 129 } 130 } 131 132 return i, nil 133 }