Repository: Konstantin8105/c4go
Pull request #400 (2019-04-10 06:32:43)

Strstr

codecov[bot]: # [Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/400?src=pr&el=h1) Report
> Merging [#400](https://codecov.io/gh/Konstantin8105/c4go/pull/400?src=pr&el=desc) into [master](https://codecov.io/gh/Konstantin8105/c4go/commit/7fab050adc505331ce3b6b3ba08e2aead2555f6a?src=pr&el=desc) will **decrease** coverage by `0.11%`.
> The diff coverage is `82.5%`.

[![Impacted file tree graph](https://codecov.io/gh/Konstantin8105/c4go/pull/400/graphs/tree.svg?width=650&token=esH2rHXlZ2&height=150&src=pr)](https://codecov.io/gh/Konstantin8105/c4go/pull/400?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #400      +/-   ##
==========================================
- Coverage   85.43%   85.31%   -0.12%     
==========================================
  Files         188      188              
  Lines       11071    11092      +21     
==========================================
+ Hits         9458     9463       +5     
- Misses       1153     1166      +13     
- Partials      460      463       +3
```


| [Impacted Files](https://codecov.io/gh/Konstantin8105/c4go/pull/400?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [transpiler/bind.go](https://codecov.io/gh/Konstantin8105/c4go/pull/400/diff?src=pr&el=tree#diff-dHJhbnNwaWxlci9iaW5kLmdv) | `70.95% <ø> (-0.14%)` | :arrow_down: |
| [transpiler/unary.go](https://codecov.io/gh/Konstantin8105/c4go/pull/400/diff?src=pr&el=tree#diff-dHJhbnNwaWxlci91bmFyeS5nbw==) | `74.77% <100%> (+0.3%)` | :arrow_up: |
| [transpiler/value\_to\_pointer.go](https://codecov.io/gh/Konstantin8105/c4go/pull/400/diff?src=pr&el=tree#diff-dHJhbnNwaWxlci92YWx1ZV90b19wb2ludGVyLmdv) | `80.54% <100%> (-2.66%)` | :arrow_down: |
| [transpiler/call.go](https://codecov.io/gh/Konstantin8105/c4go/pull/400/diff?src=pr&el=tree#diff-dHJhbnNwaWxlci9jYWxsLmdv) | `77.97% <100%> (-0.05%)` | :arrow_down: |
| [transpiler/binary.go](https://codecov.io/gh/Konstantin8105/c4go/pull/400/diff?src=pr&el=tree#diff-dHJhbnNwaWxlci9iaW5hcnkuZ28=) | `68.04% <69.56%> (-0.49%)` | :arrow_down: |
| [noarch/string.go](https://codecov.io/gh/Konstantin8105/c4go/pull/400/diff?src=pr&el=tree#diff-bm9hcmNoL3N0cmluZy5nbw==) | `88.11% <0%> (+1.98%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/400?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/400?src=pr&el=footer). Last update [7fab050...024e74a](https://codecov.io/gh/Konstantin8105/c4go/pull/400?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

codecov[bot]: # [Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/400?src=pr&el=h1) Report
> Merging [#400](https://codecov.io/gh/Konstantin8105/c4go/pull/400?src=pr&el=desc) into [master](https://codecov.io/gh/Konstantin8105/c4go/commit/7fab050adc505331ce3b6b3ba08e2aead2555f6a?src=pr&el=desc) will **decrease** coverage by `0.11%`.
> The diff coverage is `82.5%`.

[![Impacted file tree graph](https://codecov.io/gh/Konstantin8105/c4go/pull/400/graphs/tree.svg?width=650&token=esH2rHXlZ2&height=150&src=pr)](https://codecov.io/gh/Konstantin8105/c4go/pull/400?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #400      +/-   ##
==========================================
- Coverage   85.43%   85.31%   -0.12%     
==========================================
  Files         188      188              
  Lines       11071    11092      +21     
==========================================
+ Hits         9458     9463       +5     
- Misses       1153     1166      +13     
- Partials      460      463       +3
```


| [Impacted Files](https://codecov.io/gh/Konstantin8105/c4go/pull/400?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [transpiler/bind.go](https://codecov.io/gh/Konstantin8105/c4go/pull/400/diff?src=pr&el=tree#diff-dHJhbnNwaWxlci9iaW5kLmdv) | `70.95% <ø> (-0.14%)` | :arrow_down: |
| [transpiler/unary.go](https://codecov.io/gh/Konstantin8105/c4go/pull/400/diff?src=pr&el=tree#diff-dHJhbnNwaWxlci91bmFyeS5nbw==) | `74.77% <100%> (+0.3%)` | :arrow_up: |
| [transpiler/value\_to\_pointer.go](https://codecov.io/gh/Konstantin8105/c4go/pull/400/diff?src=pr&el=tree#diff-dHJhbnNwaWxlci92YWx1ZV90b19wb2ludGVyLmdv) | `80.54% <100%> (-2.66%)` | :arrow_down: |
| [transpiler/call.go](https://codecov.io/gh/Konstantin8105/c4go/pull/400/diff?src=pr&el=tree#diff-dHJhbnNwaWxlci9jYWxsLmdv) | `77.97% <100%> (-0.05%)` | :arrow_down: |
| [transpiler/binary.go](https://codecov.io/gh/Konstantin8105/c4go/pull/400/diff?src=pr&el=tree#diff-dHJhbnNwaWxlci9iaW5hcnkuZ28=) | `68.04% <69.56%> (-0.49%)` | :arrow_down: |
| [noarch/string.go](https://codecov.io/gh/Konstantin8105/c4go/pull/400/diff?src=pr&el=tree#diff-bm9hcmNoL3N0cmluZy5nbw==) | `88.11% <0%> (+1.98%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/400?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/400?src=pr&el=footer). Last update [7fab050...024e74a](https://codecov.io/gh/Konstantin8105/c4go/pull/400?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/program/program.go b/program/program.go
index d4dca56..4e90095 100644
--- a/program/program.go
+++ b/program/program.go
@@ -102,9 +102,12 @@ type Program struct {
 	// preprocessor file
 	PreprocessorFile preprocessor.FilePP
 
-	// unsafeConvertValueToPointer - simplification for convert value to pointer
+	// UnsafeConvertValueToPointer - simplification for convert value to pointer
 	UnsafeConvertValueToPointer map[string]bool
 
+	// UnsafeConvertPointerArith - simplification for pointer arithmetic
+	UnsafeConvertPointerArith map[string]bool
+
 	// IsHaveVaList
 	IsHaveVaList bool
 }
@@ -142,6 +145,7 @@ func NewProgram() (p *Program) {
 		functionDefinitions:                      map[string]DefinitionFunction{},
 		builtInFunctionDefinitionsHaveBeenLoaded: false,
 		UnsafeConvertValueToPointer:              map[string]bool{},
+		UnsafeConvertPointerArith:                map[string]bool{},
 	}
 }
 
diff --git a/scripts/scripts.txt b/scripts/scripts.txt
index bd3be9e..9a28296 100644
--- a/scripts/scripts.txt
+++ b/scripts/scripts.txt
@@ -1,8 +1,8 @@
 
 Calculate warnings : ./testdata/9wm
-		After transpiling : 2 warnings.
+		After transpiling : 5 warnings.
 		Go build : 4 warnings
-		Unsafe   : 409
+		Unsafe   : 408
 
 Calculate warnings : ./testdata/ed
 		After transpiling : 0 warnings.
@@ -21,51 +21,51 @@ Calculate warnings in file: ./testdata/minmad/minmad.go
 
 Calculate warnings in file: ./testdata/neateqn/neateqn.go
 		After transpiling : 0 warnings.
-		Go build : 0 warnings
-		Unsafe   : 22
+		Go build : 6 warnings
+		Unsafe   : 25
 
 Calculate warnings in file: ./testdata/neatmkfn/neatmkfn.go
 		After transpiling : 0 warnings.
-		Go build : 270 warnings
-		Unsafe   : 138
+		Go build : 281 warnings
+		Unsafe   : 142
 
 Calculate warnings in file: ./testdata/neatmail/neatmail.go
 		After transpiling : 0 warnings.
 		Go build : 2 warnings
-		Unsafe   : 250
+		Unsafe   : 253
 
 Calculate warnings in file: ./testdata/neatpost/neatpost.go
 		After transpiling : 0 warnings.
-		Go build : 21 warnings
-		Unsafe   : 40
+		Go build : 31 warnings
+		Unsafe   : 47
 
 Calculate warnings in file: ./testdata/neatrefer/neatrefer.go
 		After transpiling : 0 warnings.
 		Go build : 0 warnings
-		Unsafe   : 15
+		Unsafe   : 18
 
 Calculate warnings in file: ./testdata/neatroff/neatroff.go
-		After transpiling : 0 warnings.
-		Go build : 17 warnings
-		Unsafe   : 254
+		After transpiling : 3 warnings.
+		Go build : 16 warnings
+		Unsafe   : 252
 
 Calculate warnings in file: ./testdata/neatvi/neatvi.go
 		After transpiling : 0 warnings.
 		Go build : 2 warnings
-		Unsafe   : 210
+		Unsafe   : 204
 
 Calculate warnings in file: ./testdata/triangle/triangle.go
 		After transpiling : 2 warnings.
 		Go build : 585 warnings
-		Unsafe   : 1411
+		Unsafe   : 1416
 
 Calculate warnings in file: ./testdata/SQLITE/sqlite.go
 		After transpiling : 1 warnings.
 		Go build : 1 warnings
-		Unsafe   : 2599
+		Unsafe   : 2407
 
 Calculate warnings in file: testdata/vorbis/vorbis.go
 		After transpiling : 0 warnings.
 		Go build : 3 warnings
-		Unsafe   : 257
+		Unsafe   : 134
 
diff --git a/transpiler/binary.go b/transpiler/binary.go
index e3b7ffc..39f4c83 100644
--- a/transpiler/binary.go
+++ b/transpiler/binary.go
@@ -415,13 +415,39 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsSt
 		if operator == token.ADD || // +
 			operator == token.SUB || // -
 			false {
-			if types.IsPointer(leftType, p) {
-				expr, eType, newPre, newPost, err =
-					pointerArithmetic(p, left, leftType, right, rightType, operator)
-			} else {
-				expr, eType, newPre, newPost, err =
-					pointerArithmetic(p, right, rightType, left, leftType, operator)
+
+			var pnt, value ast.Node
+			var back func()
+			var nodeN ast.Node = n
+			pnt, value, back, _, err = pointerParts(&nodeN, p)
+			if err != nil {
+				err = fmt.Errorf("cannot separate on parts: %v", err)
+				return
 			}
+
+			var e goast.Expr
+			e, eType, newPre, newPost, err = atomicOperation(value, p)
+			if err != nil {
+				return
+			}
+			preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
+			eType = n.Type
+
+			// return all types
+			back()
+
+			var arr goast.Expr
+			var arrType string
+			arr, arrType, newPre, newPost, err = atomicOperation(pnt, p)
+			if err != nil {
+				return
+			}
+			_ = arrType
+			preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
+
+			expr, eType, newPre, newPost, err =
+				pointerArithmetic(p, arr, arrType, e, eType, token.ADD)
+
 			if err != nil {
 				return
 			}
@@ -432,6 +458,7 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsSt
 				combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
 
 			return
+
 		}
 	}
 
diff --git a/transpiler/bind.go b/transpiler/bind.go
index 88dfd4a..677be0a 100644
--- a/transpiler/bind.go
+++ b/transpiler/bind.go
@@ -149,7 +149,7 @@ func getBindFunction(p *program.Program, d program.DefinitionFunction) (code str
 	// add comment for function
 	f.Doc = &goast.CommentGroup{
 		List: []*goast.Comment{
-			&goast.Comment{
+			{
 				Text: fmt.Sprintf("// %s - add c-binding for implemention function", d.Name),
 			},
 		},
diff --git a/transpiler/call.go b/transpiler/call.go
index bb1a66a..83ddb08 100644
--- a/transpiler/call.go
+++ b/transpiler/call.go
@@ -816,7 +816,7 @@ func transpileCallExprQsort(n *ast.CallExpr, p *program.Program) (
 		Type: &goast.FuncType{
 			Params: &goast.FieldList{
 				List: []*goast.Field{
-					&goast.Field{
+					{
 						Names: []*goast.Ident{goast.NewIdent("a"), goast.NewIdent("b")},
 						Type:  goast.NewIdent("int"),
 					},
@@ -824,7 +824,7 @@ func transpileCallExprQsort(n *ast.CallExpr, p *program.Program) (
 			},
 			Results: &goast.FieldList{
 				List: []*goast.Field{
-					&goast.Field{Type: goast.NewIdent("bool")},
+					{Type: goast.NewIdent("bool")},
 				},
 			},
 		},
diff --git a/transpiler/transpiler.go b/transpiler/transpiler.go
index c65c85d..c2db294 100644
--- a/transpiler/transpiler.go
+++ b/transpiler/transpiler.go
@@ -165,6 +165,9 @@ func TranspileAST(fileName, packageName string, withOutsideStructs bool,
 		source += getVaListStruct()
 	}
 
+	// generate pointer arithmetic functions
+	source += getPointerArithFunctions(p)
+
 	return
 }
 
diff --git a/transpiler/unary.go b/transpiler/unary.go
index 1301bda..29ffba5 100644
--- a/transpiler/unary.go
+++ b/transpiler/unary.go
@@ -363,7 +363,7 @@ func transpileUnaryOperatorAmpersant(n *ast.UnaryOperator, p *program.Program) (
 //   `-DeclRefExpr <col:26> 'char *' lvalue Var 0x3c05ae8 'pos' 'char *'
 //
 func pointerParts(node *ast.Node, p *program.Program) (
-	pnt ast.Node, value ast.Node, back func(), err error) {
+	pnt ast.Node, value ast.Node, back func(), undefineIndex bool, err error) {
 	defer func() {
 		if err != nil {
 			err = fmt.Errorf("Cannot pointerParts: err = %v", err)
@@ -402,6 +402,7 @@ func pointerParts(node *ast.Node, p *program.Program) (
 			case *ast.BinaryOperator,
 				*ast.ImplicitCastExpr,
 				*ast.ParenExpr:
+				undefineIndex = true // is index probably negative
 				// go deeper
 			default:
 				return true
@@ -414,6 +415,7 @@ func pointerParts(node *ast.Node, p *program.Program) (
 				*ast.MemberExpr,
 				*ast.UnaryExprOrTypeTraitExpr, // ignore sizeof
 				*ast.CStyleCastExpr:
+				undefineIndex = true // is index probably negative
 				return
 			}
 		}
@@ -486,10 +488,12 @@ func transpilePointerArith(n *ast.UnaryOperator, p *program.Program) (
 
 	var pnt, value ast.Node
 	var back func()
-	pnt, value, back, err = pointerParts(&(n.Children()[0]), p)
+	var undefineIndex bool
+	pnt, value, back, undefineIndex, err = pointerParts(&(n.Children()[0]), p)
 	if err != nil {
 		return
 	}
+	_ = undefineIndex
 
 	e, eType, newPre, newPost, err := atomicOperation(value, p)
 	if err != nil {
diff --git a/transpiler/value_to_pointer.go b/transpiler/value_to_pointer.go
index 1377e79..25f22ab 100644
--- a/transpiler/value_to_pointer.go
+++ b/transpiler/value_to_pointer.go
@@ -106,7 +106,7 @@ func GetUnsafeConvertDecls(p *program.Program) {
 		p.File.Decls = append(p.File.Decls, &goast.FuncDecl{
 			Doc: &goast.CommentGroup{
 				List: []*goast.Comment{
-					&goast.Comment{
+					{
 						Text: fmt.Sprintf("// %s : created by c4go\n", functionName),
 					},
 				},
@@ -610,20 +610,7 @@ func pointerArithmetic(p *program.Program,
 		}
 	}()
 
-	if bl, ok := right.(*goast.BasicLit); ok && operator == token.ADD {
-		if bl.Value == "1" && bl.Kind == token.INT {
-			return &goast.SliceExpr{
-				X:      left,
-				Lbrack: 1,
-				Low: &goast.BasicLit{
-					Kind:  token.INT,
-					Value: "1",
-				},
-				Slice3: false,
-			}, leftType, preStmts, postStmts, nil
-		}
-	}
-
+	// check input data
 	if !(types.IsCInteger(p, rightType) || rightType == "bool") {
 		err = fmt.Errorf("right type is not C integer type : '%s'", rightType)
 		return
@@ -637,6 +624,7 @@ func pointerArithmetic(p *program.Program,
 		return
 	}
 
+	// prepare leftType - return base type
 	for {
 		if t, ok := p.TypedefType[leftType]; ok {
 			leftType = t
@@ -644,20 +632,56 @@ func pointerArithmetic(p *program.Program,
 		}
 		break
 	}
+	resolvedLeftType, err := types.ResolveType(p, leftType)
+	if err != nil {
+		return
+	}
+
+	p.AddImport("unsafe")
+	p.AddImport("runtime")
+	p.AddImport("reflect")
+
+	// try use simplification for pointer arithmetic.
+	// typically used only for Go base types.
+	if strings.Count(resolvedLeftType, "[") > 0 {
+		shortType := types.GetBaseType(leftType)
+
+		var resolvedShortType string
+		resolvedShortType, err = types.ResolveType(p, shortType)
+		if err != nil {
+			return
+		}
+
+		var acceptable bool
+
+		if types.IsGoBaseType(resolvedShortType) {
+			acceptable = true
+		}
+
+		if str, ok := p.Structs[resolvedShortType]; ok && str.IsGlobal {
+			acceptable = true
+		}
+
+		if str, ok := p.Unions[resolvedShortType]; ok && str.IsGlobal {
+			acceptable = true
+		}
+
+		if acceptable {
+			// save for future generate code
+			p.UnsafeConvertPointerArith[resolvedLeftType] = true
+			return util.NewCallExpr(getFunctionPointerArith(resolvedLeftType), left, util.NewCallExpr("int", right)),
+				leftType, nil, nil, nil
+		}
+	}
 
 	type pA struct {
 		Name      string // name of variable: 'ptr'
 		Type      string // type of variable: 'int','double'
 		Condition string // condition : '-1' ,'(-1+2-2)'
-		Operator  string // operator : '+', '-'
 	}
 
 	var s pA
 
-	resolvedLeftType, err := types.ResolveType(p, leftType)
-	if err != nil {
-		return
-	}
 	switch resolvedLeftType {
 	case "interface{}":
 		s.Type = "byte"
@@ -676,16 +700,28 @@ func pointerArithmetic(p *program.Program,
 		s.Condition = buf.String()
 	}
 
-	s.Operator = "+"
-	if operator == token.SUB {
-		s.Operator = "-"
-	}
-
 	src := `package main
 func main(){
-	a := (*(*[1000000]{{ .Type }})(unsafe.Pointer(uintptr(
-			unsafe.Pointer(&{{ .Name }}[0])) {{ .Operator }}
-			(uintptr)({{ .Condition }})*unsafe.Sizeof({{ .Name }}[0]))))[:]
+	a := func()[]{{ .Type }} {
+		var position int64 = int64({{ .Condition }})
+		slice := {{ .Name }}
+		if position < 0 {
+			// invert sign
+			position = -position
+
+			// Example from: go101.org/article/unsafe.html	
+			hdr := (*reflect.SliceHeader)(unsafe.Pointer(&slice[0]))
+			sliceLen := len(slice)
+			hdr.Data = uintptr(unsafe.Pointer(&slice[0])) - (uintptr(position))*unsafe.Sizeof(slice[0])
+			runtime.KeepAlive(&slice[0]) // needed!
+			hdr.Len = sliceLen + int(position)
+			hdr.Cap = hdr.Len
+			slice = *((*[]{{ .Type }})(unsafe.Pointer(hdr)))
+			return slice
+		}
+		// position >= 0:
+		return slice[position:]
+	}()
 }`
 	tmpl := template.Must(template.New("").Parse(src))
 	var source bytes.Buffer
@@ -711,8 +747,50 @@ func main(){
 		return
 	}
 
-	p.AddImport("unsafe")
-
 	return f.Decls[0].(*goast.FuncDecl).Body.List[0].(*goast.AssignStmt).Rhs[0],
 		leftType, preStmts, postStmts, nil
 }
+
+const unsafePointerArithFunctionName string = "c4goPointerArith"
+
+func getFunctionPointerArith(goType string) string {
+	return fmt.Sprintf("%s%s", unsafePointerArithFunctionName, util.GetExportedName(goType))
+}
+
+func pointerArithFunction(goType string) string {
+	return fmt.Sprintf(`
+
+// %s - function of pointer arithmetic. generated by c4go 
+func %s(slice %s, position int)%s {
+	if position < 0 {
+		// invert sign
+		position = -position
+
+		// Example from: go101.org/article/unsafe.html
+		// repair size of slice
+		hdr := (*reflect.SliceHeader)(unsafe.Pointer(&slice[0]))
+		sliceLen := len(slice)
+		hdr.Data = uintptr(unsafe.Pointer(&slice[0])) - (uintptr(position))*unsafe.Sizeof(slice[0])
+		runtime.KeepAlive(&slice[0]) // needed!
+		hdr.Len = sliceLen + int(position)
+		hdr.Cap = hdr.Len
+		slice = *((*%s)(unsafe.Pointer(hdr)))
+		return slice
+	}
+	// position >= 0:
+	return slice[position:]
+}
+
+`,
+		getFunctionPointerArith(goType),
+		getFunctionPointerArith(goType),
+		goType, goType, goType)
+
+}
+
+func getPointerArithFunctions(p *program.Program) (out string) {
+	for goType := range p.UnsafeConvertPointerArith {
+		out += pointerArithFunction(goType)
+	}
+	return
+}
diff --git a/vendor/github.com/disiqueira/gotree/gotree.go b/vendor/github.com/disiqueira/gotree/gotree.go
index a849769..06b9bc8 100644
--- a/vendor/github.com/disiqueira/gotree/gotree.go
+++ b/vendor/github.com/disiqueira/gotree/gotree.go
@@ -1,4 +1,4 @@
-package gotree 
+package gotree
 
 const (
 	newLine      = "\n"
diff --git a/vendor/github.com/pkg/term/termios/pty_freebsd.go b/vendor/github.com/pkg/term/termios/pty_freebsd.go
index e4b933a..f71e3d3 100644
--- a/vendor/github.com/pkg/term/termios/pty_freebsd.go
+++ b/vendor/github.com/pkg/term/termios/pty_freebsd.go
@@ -17,7 +17,7 @@ func posix_openpt(oflag int) (fd uintptr, err error) {
 }
 
 func open_pty_master() (uintptr, error) {
-	return posix_openpt(syscall.O_NOCTTY|syscall.O_RDWR|syscall.O_CLOEXEC)
+	return posix_openpt(syscall.O_NOCTTY | syscall.O_RDWR | syscall.O_CLOEXEC)
 }
 
 func Ptsname(fd uintptr) (string, error) {
diff --git a/vendor/github.com/pkg/term/termios/termios_solaris.go b/vendor/github.com/pkg/term/termios/termios_solaris.go
index 1c6e694..c9a9eb4 100644
--- a/vendor/github.com/pkg/term/termios/termios_solaris.go
+++ b/vendor/github.com/pkg/term/termios/termios_solaris.go
@@ -101,27 +101,26 @@ func Cfsetospeed(attr *syscall.Termios, speed uintptr) error {
 	return err
 }
 
-
 // tiosToUnix copies a syscall.Termios to a x/sys/unix.Termios.
 // This is needed since type conversions between the two fail due to
 // more recent x/sys/unix.Termios renaming the padding field.
 func tiosToUnix(st *syscall.Termios) *unix.Termios {
 	return &unix.Termios{
-		Iflag:  st.Iflag,
-		Oflag:  st.Oflag,
-		Cflag:  st.Cflag,
-		Lflag:  st.Lflag,
-		Cc:     st.Cc,
+		Iflag: st.Iflag,
+		Oflag: st.Oflag,
+		Cflag: st.Cflag,
+		Lflag: st.Lflag,
+		Cc:    st.Cc,
 	}
 }
 
 // tiosToSyscall copies a x/sys/unix.Termios to a syscall.Termios.
 func tiosToSyscall(ut *unix.Termios) *syscall.Termios {
 	return &syscall.Termios{
-		Iflag:  ut.Iflag,
-		Oflag:  ut.Oflag,
-		Cflag:  ut.Cflag,
-		Lflag:  ut.Lflag,
-		Cc:     ut.Cc,
+		Iflag: ut.Iflag,
+		Oflag: ut.Oflag,
+		Cflag: ut.Cflag,
+		Lflag: ut.Lflag,
+		Cc:    ut.Cc,
 	}
 }
diff --git a/vendor/github.com/pmezard/go-difflib/difflib/difflib.go b/vendor/github.com/pmezard/go-difflib/difflib/difflib.go
index 003e99f..3cfbc1f 100644
--- a/vendor/github.com/pmezard/go-difflib/difflib/difflib.go
+++ b/vendor/github.com/pmezard/go-difflib/difflib/difflib.go
@@ -161,12 +161,12 @@ func (m *SequenceMatcher) chainB() {
 	m.bJunk = map[string]struct{}{}
 	if m.IsJunk != nil {
 		junk := m.bJunk
-		for s, _ := range b2j {
+		for s := range b2j {
 			if m.IsJunk(s) {
 				junk[s] = struct{}{}
 			}
 		}
-		for s, _ := range junk {
+		for s := range junk {
 			delete(b2j, s)
 		}
 	}
@@ -181,7 +181,7 @@ func (m *SequenceMatcher) chainB() {
 				popular[s] = struct{}{}
 			}
 		}
-		for s, _ := range popular {
+		for s := range popular {
 			delete(b2j, s)
 		}
 	}
@@ -416,7 +416,7 @@ func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
 	}
 	codes := m.GetOpCodes()
 	if len(codes) == 0 {
-		codes = []OpCode{OpCode{'e', 0, 1, 0, 1}}
+		codes = []OpCode{{'e', 0, 1, 0, 1}}
 	}
 	// Fixup leading and trailing groups if they show no changes.
 	if codes[0].Tag == 'e' {


Test patch:
diff --git a/tests/ap.c b/tests/ap.c
index d0b9169..845b4d7 100644
--- a/tests/ap.c
+++ b/tests/ap.c
@@ -17,6 +17,11 @@ long get()
     return (long)(0);
 }
 
+long negative()
+{
+    return (long)(-1);
+}
+
 double global;
 
 double* get_value()
@@ -103,5 +108,12 @@ int main()
     is_eq(*pnt, 123);
     is_eq(num, 123);
 
+// TODO: test for negative index
+//   diag("pointer arithmetic 7");
+//   int* tmp_i2 = i2 + 1;
+//   int* i13 = tmp_i2 + negative();
+//   a(i13);
+//   b(i13, 1);
+
     done_testing();
 }
diff --git a/tests/code_quality/ap.go.expected b/tests/code_quality/ap.go.expected
index 1fd3eb5..c70f524 100644
--- a/tests/code_quality/ap.go.expected
+++ b/tests/code_quality/ap.go.expected
@@ -7,6 +7,8 @@
 
 package code_quality
 
+import "reflect"
+import "runtime"
 import "unsafe"
 import "github.com/Konstantin8105/c4go/noarch"
 
@@ -58,7 +60,7 @@ func main() {
 	a(i6)
 	b(i6, 1)
 	var val int32 = 2 - 2
-	var i7 []int32 = (*(*[1000000]int32)(unsafe.Pointer(uintptr(unsafe.Pointer(&(*(*[1000000]int32)(unsafe.Pointer(uintptr(unsafe.Pointer(&(*(*[1000000]int32)(unsafe.Pointer(uintptr(unsafe.Pointer(&i5[0])) + (uintptr)(1+(1-1)+val+0*(100-2))*unsafe.Sizeof(i5[0]))))[:][0])) + (uintptr)(0)*unsafe.Sizeof((*(*[1000000]int32)(unsafe.Pointer(uintptr(unsafe.Pointer(&i5[0])) + (uintptr)(1+(1-1)+val+0*(100-2))*unsafe.Sizeof(i5[0]))))[:][0]))))[:][0])) - (uintptr)(0*0)*unsafe.Sizeof((*(*[1000000]int32)(unsafe.Pointer(uintptr(unsafe.Pointer(&(*(*[1000000]int32)(unsafe.Pointer(uintptr(unsafe.Pointer(&i5[0])) + (uintptr)(1+(1-1)+val+0*(100-2))*unsafe.Sizeof(i5[0]))))[:][0])) + (uintptr)(0)*unsafe.Sizeof((*(*[1000000]int32)(unsafe.Pointer(uintptr(unsafe.Pointer(&i5[0])) + (uintptr)(1+(1-1)+val+0*(100-2))*unsafe.Sizeof(i5[0]))))[:][0]))))[:][0]))))[:]
+	var i7 []int32 = c4goPointerArithInt32Slice(i5, int(1+(1-1)+val+0*(100-2)+0+0-0*0))
 	// pointer arithmetic
 	a(i7)
 	b(i7, 1)
@@ -74,7 +76,7 @@ func main() {
 	// pointer arithmetic
 	a(i10)
 	b(i10, 1)
-	var i11 []int32 = (*(*[1000000]int32)(unsafe.Pointer(uintptr(unsafe.Pointer(&i5[1+0+0+5*get()+get():][0])) - (uintptr)((12+3)*get())*unsafe.Sizeof(i5[1+0+0+5*get()+get():][0]))))[:]
+	var i11 []int32 = c4goPointerArithInt32Slice(i5, int(1+0+0+5*get()+get()-(12+3)*get()))
 	// pointer arithmetic
 	a(i11)
 	b(i11, 1)
@@ -85,3 +87,24 @@ func main() {
 func c4goUnsafeConvert_int32(c4go_name *int32) []int32 {
 	return (*[1000000]int32)(unsafe.Pointer(c4go_name))[:]
 }
+
+// c4goPointerArithInt32Slice - function of pointer arithmetic. generated by c4go
+func c4goPointerArithInt32Slice(slice []int32, position int) []int32 {
+	if position < 0 {
+		// invert sign
+		position = -position
+
+		// Example from: go101.org/article/unsafe.html
+		// repair size of slice
+		hdr := (*reflect.SliceHeader)(unsafe.Pointer(&slice[0]))
+		sliceLen := len(slice)
+		hdr.Data = uintptr(unsafe.Pointer(&slice[0])) - (uintptr(position))*unsafe.Sizeof(slice[0])
+		runtime.KeepAlive(&slice[0]) // needed!
+		hdr.Len = sliceLen + int(position)
+		hdr.Cap = hdr.Len
+		slice = *((*[]int32)(unsafe.Pointer(hdr)))
+		return slice
+	}
+	// position >= 0:
+	return slice[position:]
+}
diff --git a/tests/code_quality/unsafe.go.expected b/tests/code_quality/unsafe.go.expected
index ff20359..01f3d03 100644
--- a/tests/code_quality/unsafe.go.expected
+++ b/tests/code_quality/unsafe.go.expected
@@ -9,7 +9,7 @@ package code_quality
 
 import "unsafe"
 
-// str - transpiled function from  C4GO/tests/code_quality/unsafe.c:9
+// str - transpiled function from  C4GO/tests/code_quality/unsafe.c:10
 type str struct {
 	i int32
 }
@@ -18,7 +18,7 @@ type un struct{ memory unsafe.Pointer }
 
 func (unionVar *un) copy() un {
 	var buffer [8]byte
-	for i := range // un - transpiled function from  C4GO/tests/code_quality/unsafe.c:13
+	for i := range // un - transpiled function from  C4GO/tests/code_quality/unsafe.c:14
 	buffer {
 		buffer[i] = (*((*[8]byte)(unionVar.memory)))[i]
 	}
@@ -41,10 +41,10 @@ func (unionVar *un) d() *float64 {
 	return (*float64)(unionVar.memory)
 }
 
-// db - transpiled function from  C4GO/tests/code_quality/unsafe.c:18
+// db - transpiled function from  C4GO/tests/code_quality/unsafe.c:19
 type db = float64
 
-// test_char - transpiled function from  C4GO/tests/code_quality/unsafe.c:21
+// test_char - transpiled function from  C4GO/tests/code_quality/unsafe.c:22
 func test_char() {
 	var t byte
 	var pt []byte = c4goUnsafeConvert_byte(&t)
@@ -53,7 +53,7 @@ func test_char() {
 	_ = pt
 }
 
-// test_short - transpiled function from  C4GO/tests/code_quality/unsafe.c:22
+// test_short - transpiled function from  C4GO/tests/code_quality/unsafe.c:23
 func test_short() {
 	var t int16
 	var pt []int16 = c4goUnsafeConvert_int16(&t)
@@ -61,7 +61,7 @@ func test_short() {
 	_ = pt
 }
 
-// test_int - transpiled function from  C4GO/tests/code_quality/unsafe.c:23
+// test_int - transpiled function from  C4GO/tests/code_quality/unsafe.c:24
 func test_int() {
 	var t int32
 	var pt []int32 = c4goUnsafeConvert_int32(&t)
@@ -69,7 +69,7 @@ func test_int() {
 	_ = pt
 }
 
-// test_long - transpiled function from  C4GO/tests/code_quality/unsafe.c:24
+// test_long - transpiled function from  C4GO/tests/code_quality/unsafe.c:25
 func test_long() {
 	var t int32
 	var pt []int32 = c4goUnsafeConvert_int32(&t)
@@ -77,7 +77,7 @@ func test_long() {
 	_ = pt
 }
 
-// test_li - transpiled function from  C4GO/tests/code_quality/unsafe.c:25
+// test_li - transpiled function from  C4GO/tests/code_quality/unsafe.c:26
 func test_li() {
 	var t int32
 	var pt []int32 = c4goUnsafeConvert_int32(&t)
@@ -85,7 +85,7 @@ func test_li() {
 	_ = pt
 }
 
-// test_ll - transpiled function from  C4GO/tests/code_quality/unsafe.c:26
+// test_ll - transpiled function from  C4GO/tests/code_quality/unsafe.c:27
 func test_ll() {
 	var t int64
 	var pt []int64 = c4goUnsafeConvert_int64(&t)
@@ -93,7 +93,7 @@ func test_ll() {
 	_ = pt
 }
 
-// test_lli - transpiled function from  C4GO/tests/code_quality/unsafe.c:27
+// test_lli - transpiled function from  C4GO/tests/code_quality/unsafe.c:28
 func test_lli() {
 	var t int64
 	var pt []int64 = c4goUnsafeConvert_int64(&t)
@@ -101,7 +101,7 @@ func test_lli() {
 	_ = pt
 }
 
-// test_f - transpiled function from  C4GO/tests/code_quality/unsafe.c:30
+// test_f - transpiled function from  C4GO/tests/code_quality/unsafe.c:31
 func test_f() {
 	var t float32
 	var pt []float32 = c4goUnsafeConvert_float32(&t)
@@ -110,7 +110,7 @@ func test_f() {
 	_ = pt
 }
 
-// test_d - transpiled function from  C4GO/tests/code_quality/unsafe.c:31
+// test_d - transpiled function from  C4GO/tests/code_quality/unsafe.c:32
 func test_d() {
 	var t float64
 	var pt []float64 = c4goUnsafeConvert_float64(&t)
@@ -118,7 +118,7 @@ func test_d() {
 	_ = pt
 }
 
-// test_ld - transpiled function from  C4GO/tests/code_quality/unsafe.c:32
+// test_ld - transpiled function from  C4GO/tests/code_quality/unsafe.c:33
 func test_ld() {
 	var t float64
 	var pt []float64 = c4goUnsafeConvert_float64(&t)
@@ -126,7 +126,7 @@ func test_ld() {
 	_ = pt
 }
 
-// test_struct - transpiled function from  C4GO/tests/code_quality/unsafe.c:35
+// test_struct - transpiled function from  C4GO/tests/code_quality/unsafe.c:36
 func test_struct() {
 	var t str
 	var pt []str = c4goUnsafeConvert_str(&t)
@@ -135,7 +135,7 @@ func test_struct() {
 	_ = pt
 }
 
-// test_un - transpiled function from  C4GO/tests/code_quality/unsafe.c:38
+// test_un - transpiled function from  C4GO/tests/code_quality/unsafe.c:39
 func test_un() {
 	var t un
 	var pt []un = c4goUnsafeConvert_un(&t)
@@ -144,7 +144,7 @@ func test_un() {
 	_ = pt
 }
 
-// test_typedef - transpiled function from  C4GO/tests/code_quality/unsafe.c:41
+// test_typedef - transpiled function from  C4GO/tests/code_quality/unsafe.c:42
 func test_typedef() {
 	var t db
 	var pt []db = c4goUnsafeConvert_float64(&t)
diff --git a/tests/stdlib.c b/tests/stdlib.c
index 4f5bced..e02d9f5 100644
--- a/tests/stdlib.c
+++ b/tests/stdlib.c
@@ -286,23 +286,24 @@ void test_atoi_post()
 }
 
 // TODO:
-// static void * my_memrchr(void *m, int c, long n)
-// {
-	// int i;
-	// for (i = 0; i < n; i++)
-		// if (*(unsigned char *) (m + n - 1 - i) == c)
-			// return m + n - 1 - i;
-	// return NULL;
-// }
-// 
-// void test_my_memrchr()
-// {
-	// unsigned char * word = "Hello my dear world";
-	// void * p = my_memrchr(word, (int)('d'), 18);
-	// is_not_null(p);
-	// p = my_memrchr(word, (int)('z'), 18);
-	// is_null(p);
-// }
+//	static void * my_memrchr(void *m, int c, long n)
+//	{
+//		int i;
+//		for (i = 0; i < n; i++)
+//			if (*(unsigned char *) (m + n - 1 - i) == c)
+//				return m + n - 1 - i;
+//		// pointer checking: m + n - 1 - i
+//		return NULL;
+//	}
+//	
+//	void test_my_memrchr()
+//	{
+//		unsigned char * word = "Hello my dear world";
+//		void * p = my_memrchr(word, (int)('d'), 18);
+//		is_not_null(p);
+//		p = my_memrchr(word, (int)('z'), 18);
+//		is_null(p);
+//	}
 
 int main()
 {
@@ -596,9 +597,9 @@ int main()
     diag("q_sort");
     q_sort();
 
-	// TODO:
-	// diag("my_memrchr");
-	// test_my_memrchr();
+    // TODO:
+    // diag("my_memrchr");
+    // test_my_memrchr();
 
     done_testing();
 }
diff --git a/tests/string.c b/tests/string.c
index 8edad00..d34f4a5 100644
--- a/tests/string.c
+++ b/tests/string.c
@@ -66,7 +66,7 @@ void test_strspn()
 
 int main()
 {
-    plan(43);
+    plan(44);
 
     diag("TODO: __builtin_object_size");
     // https://github.com/Konstantin8105/c4go/issues/359
@@ -229,7 +229,7 @@ int main()
 
         printf("%s\n", strstr(str, "three"));
         is_streq(strstr(str, "three"), "three");
-        //TODO: NULL check in is_eq(strstr(str, "four") - str, 0);
+        is_null(strstr(str, "fo"));
     }
     {
         diag("memcpy");