diff --git a/bin/hawkgo.go b/bin/hawkgo.go index d9488f18..0e96d956 100644 --- a/bin/hawkgo.go +++ b/bin/hawkgo.go @@ -8,10 +8,16 @@ import "os" import "path/filepath" import "runtime" import "runtime/debug" +import "strings" //import "time" +type Assign struct { + idx int + value string +} + type Config struct { - assign string + assigns map[string]Assign call string fs string show_extra_info bool @@ -31,10 +37,16 @@ func parse_args_to_config(cfg *Config) bool { var flgs *FlagSet var err error + cfg.assigns = make(map[string]Assign) + //flgs = flag.NewFlagSet("", flag.ContinueOnError) flgs = NewFlagSet("", flag.ContinueOnError) flgs.Func("assign", "set a global variable with a value", func(v string) error { - cfg.assign = v + var kv []string + var vv string + kv = strings.SplitN(v, "=", 2) + if len(kv) >= 2 { vv = kv[1] } + cfg.assigns[kv[0]] = Assign{idx: -1, value: vv} return nil }) flgs.Func("call", "call a function instead of the pattern-action block)", func(v string) error { @@ -58,7 +70,6 @@ func parse_args_to_config(cfg *Config) bool { flgs.Alias("v", "assign") flgs.SetOutput(io.Discard) // prevent usage output - //err = flgs.Parse(os.Args[1:]) err = flgs.Parse(os.Args[1:]) if err != nil { fmt.Fprintf(os.Stderr, "ERROR: %s\n", err.Error()) @@ -81,37 +92,49 @@ wrong_usage: return false } -func make_hawk(script string) (*hawk.Hawk, error) { - var h *hawk.Hawk - var err error - - h, err = hawk.New() - if err != nil { return nil, err } - - err = h.ParseText(script) - if err != nil { - h.Close() - return nil, err - } - - return h, nil -} - func main() { var h *hawk.Hawk var rtx *hawk.Rtx var cfg Config + var fs_idx int = -1 var err error debug.SetGCPercent(100) // enable normal GC if parse_args_to_config(&cfg) == false { os.Exit(99) } -fmt.Printf("config [%+v]\n", cfg) h, err = hawk.New() if err != nil { fmt.Fprintf(os.Stderr, "ERROR: failed to make hawk - %s\n", err.Error()) - return + goto oops + } + + if len(cfg.assigns) > 0 { + var k string + var v Assign + var idx int + for k, v = range cfg.assigns { + idx, err = h.FindGlobal(k, true) + if err == nil { + // existing variable found + v.idx = idx + } else { + v.idx, err = h.AddGlobal(k) + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR: failed to add global variable '%s' - %s\n", k, err.Error()) + goto oops + } + } + cfg.assigns[k] = v + } + } + + if cfg.fs != "" { + fs_idx, err = h.FindGlobal("FS", true) + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR: failed to find global variable 'FS' - %s\n", err.Error()) + goto oops + } } if (len(cfg.srcfiles) > 0) { @@ -121,33 +144,101 @@ fmt.Printf("config [%+v]\n", cfg) } if err != nil { fmt.Fprintf(os.Stderr, "ERROR: failed to make hawk - %s\n", err.Error()) - h.Close() - return + goto oops } rtx, err = h.NewRtx(filepath.Base(os.Args[0]), cfg.datfiles) if err != nil { fmt.Fprintf(os.Stderr, "ERROR: failed to make rtx - %s\n", err.Error()) + goto oops } else { - var v *hawk.Val + var k string + var v Assign + var retv *hawk.Val + + for k, v = range cfg.assigns { + if v.idx >= 0 { + var vv *hawk.Val + vv, err = rtx.NewNumOrStrVal(v.value) + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR: failed to convert value '%s' for global variable '%s' - %s\n", v.value, k, err.Error()) + goto oops + } + + err = rtx.SetGlobal(v.idx, vv) + vv.Close() + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR: failed to set global variable '%s' - %s\n", k, err.Error()) + goto oops + } + } + } + + if fs_idx >= 0 { + var vv *hawk.Val + vv, err = rtx.NewStrVal(cfg.fs) + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR: failed to convert field separator '%s' - %s\n", cfg.fs, err.Error()) + goto oops + } + + rtx.SetGlobal(fs_idx, vv) + vv.Close() + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR: failed to set field separator to '%s' - %s\n", cfg.fs, err.Error()) + goto oops + } + } + if cfg.call != "" { - v, err = rtx.Call(cfg.call/*, cfg.datfiles*/) // TODO: pass arguments. + var idx int + var count int + var args []*hawk.Val + + count = len(cfg.datfiles) + args = make([]*hawk.Val, count) + for idx = 0; idx < count; idx++ { + args[idx], err = rtx.NewStrVal(cfg.datfiles[idx]) + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR: failed to convert argument [%s] to value - %s\n", cfg.datfiles[idx], err.Error()) + goto oops + } + } + retv, err = rtx.Call(cfg.call, args...) + for idx = 0; idx < count; idx++ { + // it's ok not to call Close() on args as rtx.Close() closes them automatically. + // if args are re-created repeatedly, Close() on them is always needed not to + // accumulate too many allocated values. + args[idx].Close() + } } else { //v, err = rtx.Loop() - v, err = rtx.Exec(cfg.datfiles) + retv, err = rtx.Exec(cfg.datfiles) } if err != nil { fmt.Fprintf(os.Stderr, "ERROR: failed to run rtx - %s\n", err.Error()) - } else if cfg.show_extra_info { - fmt.Printf("[RETURN] - [%v]\n", v.String()) + goto oops + } + + if cfg.show_extra_info { + fmt.Printf("[RETURN] - [%v]\n", retv.String()) // TODO: print global variables and values } } - h.Close() + // let's not care about closing args or return values + // because rtx.Close() will close them automatically + if rtx != nil { rtx.Close() } + if h != nil { h.Close() } runtime.GC() runtime.Gosched() // time.Sleep(1000 * time.Millisecond) // give finalizer time to print + return + +oops: + if rtx != nil { rtx.Close() } + if h != nil { h.Close() } + os.Exit(255) } diff --git a/hawk.go b/hawk.go index 7775435e..943d7edc 100644 --- a/hawk.go +++ b/hawk.go @@ -305,14 +305,27 @@ func (hawk *Hawk) SetLogMask(log_mask BitMask) { } } -func (hawk *Hawk) AddGlobal(name string) error { +func (hawk *Hawk) FindGlobal(name string, inc_builtins bool) (int, error) { + var x C.int + var cname *C.hawk_bch_t + var cinc C.int + + cname = C.CString(name) + if inc_builtins { cinc = 1 } + x = C.hawk_findgblwithbcstr(hawk.c, cname, cinc) + C.free(unsafe.Pointer(cname)) + if x <= -1 { return -1, hawk.make_errinfo() } + return int(x), nil +} + +func (hawk *Hawk) AddGlobal(name string) (int, error) { var x C.int var cname *C.hawk_bch_t cname = C.CString(name) x = C.hawk_addgblwithbcstr(hawk.c, cname) C.free(unsafe.Pointer(cname)) - if x <= -1 { return hawk.make_errinfo() } - return nil + if x <= -1 { return -1, hawk.make_errinfo() } + return int(x), nil } //export hawk_go_fnc_handler @@ -383,6 +396,7 @@ func (hawk *Hawk) ParseFiles(files []string) error { count = len(files) in = make([]C.hawk_parsestd_t, count + 1) + cfiles = make([]*C.hawk_bch_t, count) for idx = 0; idx < count; idx++ { cfiles[idx] = C.CString(files[idx]) C.init_parsestd_for_file_in(&in[idx], cfiles[idx]) @@ -547,6 +561,13 @@ func (rtx *Rtx) make_errinfo() *Err { return &err } +func (rtx *Rtx) SetGlobal(idx int, val *Val) error { + if C.hawk_rtx_setgbl(rtx.c, C.int(idx), val.c) <= -1 { + return rtx.make_errinfo() + } + return nil +} + func (rtx *Rtx) Exec(args []string) (*Val, error) { var val *C.hawk_val_t var cargs []*C.hawk_bch_t @@ -702,13 +723,13 @@ func (rtx *Rtx) NewVal(v interface{}) (*Val, error) { _type = reflect.TypeOf(v) switch _type.Kind() { case reflect.Int: - return rtx.NewValFromInt(v.(int)) + return rtx.NewIntVal(v.(int)) case reflect.Float32: - return rtx.NewValFromFlt(float64(v.(float32))) + return rtx.NewFltVal(float64(v.(float32))) case reflect.Float64: - return rtx.NewValFromFlt(v.(float64)) + return rtx.NewFltVal(v.(float64)) case reflect.String: - return rtx.NewValFromStr(v.(string)) + return rtx.NewStrVal(v.(string)) case reflect.Array: fallthrough @@ -716,7 +737,7 @@ func (rtx *Rtx) NewVal(v interface{}) (*Val, error) { var _kind reflect.Kind _kind = _type.Elem().Kind() if _kind == reflect.Uint8 { - return rtx.NewValFromByteArr(v.([]byte)) + return rtx.NewByteArrVal(v.([]byte)) } fallthrough @@ -738,31 +759,31 @@ func (rtx* Rtx) make_val(vmaker func() *C.hawk_val_t) (*Val, error) { return vv, nil } -func (rtx *Rtx) NewValFromByte(v byte) (*Val, error) { +func (rtx *Rtx) NewByteVal(v byte) (*Val, error) { return rtx.make_val(func() *C.hawk_val_t { return C.hawk_rtx_makebchrval(rtx.c, C.hawk_bch_t(v)) }) } -func (rtx *Rtx) NewValFromRune(v rune) (*Val, error) { +func (rtx *Rtx) NewCharVal(v rune) (*Val, error) { return rtx.make_val(func() *C.hawk_val_t { return C.hawk_rtx_makecharval(rtx.c, C.hawk_ooch_t(v)) }) } -func (rtx *Rtx) NewValFromInt(v int) (*Val, error) { +func (rtx *Rtx) NewIntVal(v int) (*Val, error) { return rtx.make_val(func() *C.hawk_val_t { return C.hawk_rtx_makeintval(rtx.c, C.hawk_int_t(v)) }) } -func (rtx *Rtx) NewValFromFlt(v float64) (*Val, error) { +func (rtx *Rtx) NewFltVal(v float64) (*Val, error) { return rtx.make_val(func() *C.hawk_val_t { return C.make_flt_val(rtx.c, C.double(v)) }) } -func (rtx *Rtx) NewValFromStr(v string) (*Val, error) { +func (rtx *Rtx) NewStrVal(v string) (*Val, error) { return rtx.make_val(func() *C.hawk_val_t { var vv *C.hawk_val_t var cv *C.hawk_bch_t @@ -773,7 +794,18 @@ func (rtx *Rtx) NewValFromStr(v string) (*Val, error) { }) } -func (rtx *Rtx) NewValFromByteArr(v []byte) (*Val, error) { +func (rtx *Rtx) NewNumOrStrVal(v string) (*Val, error) { + return rtx.make_val(func() *C.hawk_val_t { + var vv *C.hawk_val_t + var cv *C.hawk_bch_t + cv = C.CString(v) + vv = C.hawk_rtx_makenumorstrvalwithbchars(rtx.c, cv, C.hawk_oow_t(len(v))) + C.free(unsafe.Pointer(cv)) + return vv + }) +} + +func (rtx *Rtx) NewByteArrVal(v []byte) (*Val, error) { return rtx.make_val(func() *C.hawk_val_t { return C.hawk_rtx_makembsvalwithbchars(rtx.c, (*C.hawk_bch_t)(unsafe.Pointer(&v[0])), C.hawk_oow_t(len(v))) }) diff --git a/hawk_test.go b/hawk_test.go index 5e793bd9..fb12c28f 100644 --- a/hawk_test.go +++ b/hawk_test.go @@ -39,13 +39,13 @@ func enbase64(rtx *hawk.Rtx) error { var a2 *hawk.Val = hawk.Must(rtx.GetFuncArg(2)) fmt.Printf("[%s] [%s] [%s]\n", a0.String(), a1.String(), a2.String()) - rtx.SetFuncRet(hawk.Must(rtx.NewValFromStr("ENBASE64-OUTPUT"))) + rtx.SetFuncRet(hawk.Must(rtx.NewStrVal("ENBASE64-OUTPUT"))) return nil } func debase64(rtx *hawk.Rtx) error { fmt.Printf("****DEBASE64 [%d]\n", rtx.GetFuncArgCount()) - rtx.SetFuncRet(hawk.Must(rtx.NewValFromFlt(-999.1111))) + rtx.SetFuncRet(hawk.Must(rtx.NewFltVal(-999.1111))) return nil //return fmt.Errorf("what the hell.....") } @@ -187,7 +187,7 @@ return x; } else { var v *hawk.Val - v, err = rtx.Call("get_map", hawk.Must(rtx.NewValFromStr("hawk flies"))) + v, err = rtx.Call("get_map", hawk.Must(rtx.NewStrVal("hawk flies"))) if err != nil { t.Errorf("failed to call get_map - %s", err.Error()) } else { @@ -223,8 +223,8 @@ return x; } fmt.Printf("== CHANGING MAP ==\n") - v.MapSetField("666.666", hawk.Must(rtx.NewValFromFlt(66666.66666))) - v.MapSetField("hello", hawk.Must(rtx.NewValFromStr("all stars"))) + v.MapSetField("666.666", hawk.Must(rtx.NewFltVal(66666.66666))) + v.MapSetField("hello", hawk.Must(rtx.NewStrVal("all stars"))) fmt.Printf("== DUMPING MAP ==\n") kk, vv = v.MapFirstField(&itr) @@ -235,7 +235,7 @@ return x; } } - v, err = rtx.Call("get_arr", hawk.Must(rtx.NewValFromStr("hawk flies"))) + v, err = rtx.Call("get_arr", hawk.Must(rtx.NewStrVal("hawk flies"))) if err != nil { t.Errorf("failed to call get_arr - %s", err.Error()) } else { @@ -270,8 +270,8 @@ return x; } */ fmt.Printf("== CHANGING ARRAY ==\n") - v.ArraySetField(88, hawk.Must(rtx.NewValFromStr("eighty eight"))) - v.ArraySetField(77, hawk.Must(rtx.NewValFromStr("seventy seventy"))) + v.ArraySetField(88, hawk.Must(rtx.NewStrVal("eighty eight"))) + v.ArraySetField(77, hawk.Must(rtx.NewStrVal("seventy seventy"))) fmt.Printf("== DUMPING ARRAY ==\n") i, ff = v.ArrayFirstField(&itr) for ff != nil { @@ -316,7 +316,7 @@ return x } else { var v *hawk.Val - v, err = rtx.Call("main", hawk.Must(rtx.NewValFromStr("this is a test3 string"))) + v, err = rtx.Call("main", hawk.Must(rtx.NewStrVal("this is a test3 string"))) if err != nil { t.Errorf("failed to call main - %s", err.Error()) } else {