Repository: Konstantin8105/c4go
Pull request #313 (2019-03-12 09:26:08)

refactoring

codecov[bot]: # [Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/313?src=pr&el=h1) Report
> Merging [#313](https://codecov.io/gh/Konstantin8105/c4go/pull/313?src=pr&el=desc) into [master](https://codecov.io/gh/Konstantin8105/c4go/commit/66acc242a5b4ed0a57ad9ef5c076a7aa0e91b58c?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `n/a`.

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

```diff
@@           Coverage Diff           @@
##           master     #313   +/-   ##
=======================================
  Coverage   86.59%   86.59%           
=======================================
  Files         184      184           
  Lines       10447    10447           
=======================================
  Hits         9047     9047           
  Misses        982      982           
  Partials      418      418
```



------

[Continue to review full report at Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/313?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/313?src=pr&el=footer). Last update [66acc24...d20b60f](https://codecov.io/gh/Konstantin8105/c4go/pull/313?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/.travis.yml b/.travis.yml
index 7a9ffb5..4362a06 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -19,18 +19,23 @@ matrix:
     - env: SCRIPT=test CLANG=3.4
       os: linux
       if: branch = master
-    - env: SCRIPT=test CLANG=3.5
-      os: linux
-      # if: branch = master
-    - env: SCRIPT=test CLANG=3.6
-      os: linux
-      if: branch = master
-    - env: SCRIPT=test CLANG=3.7
-      os: linux
-      if: branch = master
-    - env: SCRIPT=test CLANG=3.8
-      os: linux
-      if: branch = master
+####################################################
+#       commented for minimaze build
+#
+#   - env: SCRIPT=test CLANG=3.5
+#     os: linux
+#     # if: branch = master
+#   - env: SCRIPT=test CLANG=3.6
+#     os: linux
+#     if: branch = master
+#   - env: SCRIPT=test CLANG=3.7
+#     os: linux
+#     if: branch = master
+#   - env: SCRIPT=test CLANG=3.8
+#     os: linux
+#     if: branch = master
+#
+####################################################
     - env: SCRIPT=test CLANG=7
       os: linux
       if: branch = master
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
deleted file mode 100644
index 7e77a3a..0000000
--- a/CODE_OF_CONDUCT.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# Contributor Covenant Code of Conduct
-
-## Our Pledge
-
-In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
-
-## Our Standards
-
-Examples of behavior that contributes to creating a positive environment include:
-
-* Using welcoming and inclusive language
-* Being respectful of differing viewpoints and experiences
-* Gracefully accepting constructive criticism
-* Focusing on what is best for the community
-* Showing empathy towards other community members
-
-Examples of unacceptable behavior by participants include:
-
-* The use of sexualized language or imagery and unwelcome sexual attention or advances
-* Trolling, insulting/derogatory comments, and personal or political attacks
-* Public or private harassment
-* Publishing others' private information, such as a physical or electronic address, without explicit permission
-* Other conduct which could reasonably be considered inappropriate in a professional setting
-
-## Our Responsibilities
-
-Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
-
-Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
-
-## Scope
-
-This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
-
-## Enforcement
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
-
-Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
-
-## Attribution
-
-This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
-
-[homepage]: http://contributor-covenant.org
-[version]: http://contributor-covenant.org/version/1/4/
diff --git a/README.md b/README.md
index 8400149..293e4ee 100644
--- a/README.md
+++ b/README.md
@@ -89,7 +89,7 @@ import "unsafe"
 import "github.com/Konstantin8105/c4go/noarch"
 import "fmt"
 
-// main - transpiled function from  $GOPATH/src/github.com/Konstantin8105/c4go/examples/prime.c:3
+// main - transpiled function from  C4GO/examples/prime.c:3
 func main() {
 	var n int32
 	var c int32
@@ -151,30 +151,90 @@ int main()
 
 package main
 
-// #include </usr/include/x86_64-linux-gnu/bits/mathcalls.h>
+// #include </usr/include/math.h>
 import "C"
 
 import "github.com/Konstantin8105/c4go/noarch"
 import "unsafe"
 
-// main - transpiled function from  $GOPATH/src/github.com/Konstantin8105/c4go/examples/math.c:4
+// main - transpiled function from  C4GO/examples/math.c:4
 func main() {
-	var n int
+	var n int32
 	var param float64 = 8
 	var result float64
-	result = frexp(param, (*[100000000]int)(unsafe.Pointer(&n))[:])
+	result = frexp(param, (*[100000000]int32)(unsafe.Pointer(&n))[:])
 	noarch.Printf([]byte("result = %5.2f\n\x00"), result)
 	noarch.Printf([]byte("n      = %d\n\x00"), n)
 	return
 }
 
-func frexp(arg0 float64, arg1 []int) float64 {
+// Add c-binding for implemention function : `frexp`
+
+func frexp(arg0 float64, arg1 []int32) float64 {
 	return float64(C.frexp(C.double(arg0), (*_Ctype_int)(unsafe.Pointer(&arg1[0]))))
 }
 ```
 
+# Example with C-pointers and C-arrays
+
+```c
+#include <stdio.h>
+
+void a(int *v1) { printf("a: %d\n",*v1); }
+
+void b(int v1[], int size) {
+	for (size-- ; size >= 0 ; size-- ) { printf("b: %d %d\n", size,  v1[size]); }
+}
+
+int main() {
+	int i1 = 42;
+	a(&i1);
+	b(&i1, 1);
+
+	int i2[] = {11,22};
+	a(i2);
+	b(i2,2);
+
+	return 0;
+}
+```
+
+```go
+//
+//	Package - transpiled by c4go
+//
+//	If you have found any issues, please raise an issue at:
+//	https://github.com/Konstantin8105/c4go/
+//
+
+package main
 
+import "unsafe"
+import "github.com/Konstantin8105/c4go/noarch"
 
+// a - transpiled function from  C4GO/examples/ap.c:3
+func a(v1 []int32) {
+	noarch.Printf([]byte("a: %d\n\x00"), v1[0])
+}
+
+// b - transpiled function from  C4GO/examples/ap.c:5
+func b(v1 []int32, size int32) {
+	for size -= 1; size >= 0; size-- {
+		noarch.Printf([]byte("b: %d %d\n\x00"), size, v1[size])
+	}
+}
+
+// main - transpiled function from  C4GO/examples/ap.c:9
+func main() {
+	var i1 int32 = 42
+	a((*[100000000]int32)(unsafe.Pointer(&i1))[:])
+	b((*[100000000]int32)(unsafe.Pointer(&i1))[:], 1)
+	var i2 []int32 = []int32{11, 22}
+	a(i2)
+	b(i2, 2)
+	return
+}
+```
 
 # C standard library implementation
 
diff --git a/examples/ap.c b/examples/ap.c
new file mode 100644
index 0000000..3c75e2b
--- /dev/null
+++ b/examples/ap.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+
+void a(int *v1) { printf("a: %d\n",*v1); }
+
+void b(int v1[], int size) {
+	for (size-- ; size >= 0 ; size-- ) { printf("b: %d %d\n", size,  v1[size]); }
+}
+
+int main() {
+	int i1 = 42;
+	a(&i1);
+	b(&i1, 1);
+
+	int i2[] = {11,22};
+	a(i2);
+	b(i2,2);
+
+	return 0;
+}
diff --git a/noarch/string.go b/noarch/string.go
index bb2c00b..b352505 100644
--- a/noarch/string.go
+++ b/noarch/string.go
@@ -3,6 +3,7 @@ package noarch
 import (
 	"bytes"
 	"reflect"
+	"unsafe"
 )
 
 // Strlen returns the length of a string.
@@ -145,9 +146,19 @@ func Memset(ptr []byte, value byte, num uint32) []byte {
 }
 
 // Memmove move block of memory
-func Memmove(ptr, source interface{}, num uint32) interface{} {
-	p1 := ptr.([]byte)
-	p2 := source.([]byte)
+func Memmove(ptr, src interface{}, num uint32) interface{} {
+	// both types is []byte
+	if p, ok := ptr.([]byte); ok {
+		if s, ok := src.([]byte); ok {
+			for i := int(num); i >= 0; i-- {
+				p[i] = s[i]
+			}
+			return s
+		}
+	}
+
+	p1 := (*[100000]byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&ptr))))
+	p2 := (*[100000]byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&src))))
 	for i := int(num); i >= 0; i-- {
 		p1[i] = p2[i]
 	}
@@ -156,7 +167,7 @@ func Memmove(ptr, source interface{}, num uint32) interface{} {
 
 // Memcmp - compare two buffers
 // Compares the first count characters of the objects pointed to be lhs and rhs
-func Memcmp(lhs []byte, rhs []byte, count uint32) int {
+func Memcmp(lhs []byte, rhs []byte, count uint32) int32 {
 	for i := 0; uint32(i) < count; i++ {
 		if int(lhs[i]) < int(rhs[i]) {
 			return -1
diff --git a/noarch/unistd.go b/noarch/unistd.go
index c3f446c..7eb91cc 100644
--- a/noarch/unistd.go
+++ b/noarch/unistd.go
@@ -3,7 +3,6 @@ package noarch
 import (
 	"fmt"
 	"os"
-	"syscall"
 
 	"golang.org/x/sys/unix"
 )
@@ -38,7 +37,7 @@ func Pipe(p []int32) int32 {
 }
 
 func Read(fd int32, p []byte, num uint) SsizeT {
-	n, err := syscall.Read(int(fd), p)
+	n, err := unix.Read(int(fd), p)
 	if err != nil {
 		return SsizeT(-1)
 	}
@@ -46,7 +45,7 @@ func Read(fd int32, p []byte, num uint) SsizeT {
 }
 
 func Write(fd int32, p []byte, num uint) SsizeT {
-	n, err := syscall.Write(int(fd), p)
+	n, err := unix.Write(int(fd), p)
 	if err != nil {
 		return SsizeT(-1)
 	}
@@ -54,3 +53,11 @@ func Write(fd int32, p []byte, num uint) SsizeT {
 }
 
 type SsizeT int32
+
+func Ftruncate(fd int32, length int64) int32 {
+	err := unix.Ftruncate(int(fd), length)
+	if err != nil {
+		return -1
+	}
+	return 0
+}
diff --git a/program/definition_function.go b/program/definition_function.go
index 2d1234e..c63f93d 100644
--- a/program/definition_function.go
+++ b/program/definition_function.go
@@ -359,8 +359,8 @@ var builtInFunctionDefinitions = map[string][]string{
 		"ssize_t read(int, void *, size_t) -> noarch.Read",
 		"int close(int) -> noarch.CloseOnExec",
 		"int isatty(int) -> noarch.Isatty",
-		"int ftruncate(int , off_t ) -> noarch.Ftruncate",
 		"int unlink(const char *) -> noarch.Unlink",
+		"int ftruncate(int , off_t ) -> noarch.Ftruncate",
 	},
 	"sys/stat.h": {
 		"int fstat(int , struct stat  *) -> noarch.Fstat",
diff --git a/program/warnings.go b/program/warnings.go
index 4ed0afc..2aee274 100644
--- a/program/warnings.go
+++ b/program/warnings.go
@@ -18,6 +18,12 @@ func (p *Program) GenerateWarningMessage(e error, n ast.Node) string {
 		message += fmt.Sprintf("(%T): %s:", n, n.Position().GetSimpleLocation())
 	}
 	message += fmt.Sprintf("%s", e.Error())
+	message = PathSimplification(message)
+	return message
+}
+
+func PathSimplification(message string) string {
 	message = strings.Replace(message, os.Getenv("GOPATH"), "$GOPATH", -1)
+	message = strings.Replace(message, "$GOPATH/src/github.com/Konstantin8105/c4go", "C4GO", -1)
 	return message
 }
diff --git a/transpiler/bind.go b/transpiler/bind.go
index 9ce0e20..cb1e864 100644
--- a/transpiler/bind.go
+++ b/transpiler/bind.go
@@ -59,7 +59,7 @@ func generateBinding(p *program.Program) (bindHeader, bindCode string) {
 		//		return float64(C.frexp(C.double(arg1), unsafe.Pointer(arg2)))
 		// }
 
-		mess := fmt.Sprintf("// Add c-binding for implementate function : `%s`", ds[i].Name)
+		mess := fmt.Sprintf("// Add c-binding for implemention function : `%s`", ds[i].Name)
 		bindCode += mess + "\n"
 
 		code, err := getBindFunction(p, ds[i])
@@ -130,15 +130,9 @@ func getBindFunction(p *program.Program, d program.DefinitionFunction) (code str
 		List: []goast.Stmt{
 			&goast.ReturnStmt{
 				Results: []goast.Expr{
-					&goast.CallExpr{
-						Fun: goast.NewIdent(returnResolvedType),
-						Args: []goast.Expr{
-							&goast.CallExpr{
-								Fun:  goast.NewIdent(fmt.Sprintf("C.%s", d.Name)),
-								Args: arg,
-							},
-						},
-					},
+					util.NewCallExpr(returnResolvedType,
+						util.NewCallExpr(fmt.Sprintf("C.%s", d.Name), arg...),
+					),
 				},
 			},
 		},
@@ -162,6 +156,8 @@ func cgoTypes(goType string) (_ string, ok bool) {
 		return "int", true
 	case "int32":
 		return "int", true
+	case "int64":
+		return "long", true
 	case "float64":
 		return "double", true
 	case "byte":
@@ -178,6 +174,59 @@ func cgoTypes(goType string) (_ string, ok bool) {
 	return "", false
 }
 
+// TODO : add implementation
+//
+// Example:
+// func write(arg0 int32, arg1 interface{}, arg2 uint) noarch.SsizeT {
+//      a := arg1.([]byte)
+//      b := string(a)
+//      c := C.CString(b)
+//      return noarch.SsizeT(C.write(C.int(arg0), (unsafe.Pointer(c)), C.ulong(arg2)))
+// }
+//
+// func read(arg0 int32, arg1 interface{}, arg2 uint) noarch.SsizeT {
+//      a := arg1.([]byte)
+//      b := string(a)
+//      c := C.CString(b)
+//      S := noarch.SsizeT(C.read(C.int(arg0), unsafe.Pointer(c), C.ulong(arg2)))
+//      d := C.GoString(c)
+//      arg1 = []byte(d)
+//      return S
+// }
+//
+//	func read(arg0 int32, arg1 interface{}, arg2 uint) noarch.SsizeT {
+//	   switch v := arg1.(type) {
+//	   case []byte:
+//	   	a := v
+//	   	b := string(a)
+//	   	c := C.CString(b)
+//	   	S := noarch.SsizeT(C.read(C.int(arg0), unsafe.Pointer(c), C.ulong(arg2)))
+//	   	d := C.GoString(c)
+//	   	arg1 = []byte(d)
+//	   	return S
+//	   case *[]byte:
+//	   	a := v
+//	   	b := string(*a)
+//	   	c := C.CString(b)
+//	   	S := noarch.SsizeT(C.read(C.int(arg0), unsafe.Pointer(c), C.ulong(arg2)))
+//	   	d := C.GoString(c)
+//	   	arg1 = []byte(d)
+//	   	return S
+//	   }
+//	   return noarch.SsizeT(C.read(C.int(arg0), unsafe.Pointer(&arg1), C.ulong(arg2)))
+//	}
+//
+// 	func write(arg0 int32, arg1 interface{}, arg2 uint) noarch.SsizeT {
+// 	   switch v := arg1.(type) {
+// 	   case []byte: // []uint8:
+// 	   	a := v
+// 	   	b := string(a)
+// 	   	c := C.CString(b)
+// 	   	return noarch.SsizeT(C.write(C.int(arg0), (unsafe.Pointer(c)), C.ulong(arg2)))
+// 	   }
+// 	   return noarch.SsizeT(C.write(C.int(arg0), (unsafe.Pointer(&arg1)), C.ulong(arg2)))
+// 	}
+
 func ResolveCgoType(p *program.Program, goType string, expr goast.Expr) (a goast.Expr, err error) {
 	if ct, ok := cgoTypes(goType); ok {
 		return &goast.CallExpr{
@@ -238,11 +287,11 @@ func ResolveCgoType(p *program.Program, goType string, expr goast.Expr) (a goast
 
 		p.AddImport("unsafe")
 
-		return util.NewCallExpr(t, util.NewCallExpr("unsafe.Pointer",
+		return util.NewCallExpr("unsafe.Pointer",
 			&goast.UnaryExpr{
 				Op: token.AND,
 				X:  expr,
-			})), nil
+			}), nil
 	}
 
 	return &goast.CallExpr{
diff --git a/transpiler/transpiler.go b/transpiler/transpiler.go
index a846b6c..da60a1a 100644
--- a/transpiler/transpiler.go
+++ b/transpiler/transpiler.go
@@ -8,7 +8,6 @@ import (
 	goast "go/ast"
 	"go/parser"
 	"go/token"
-	"os"
 	"strings"
 	"unicode"
 
@@ -579,7 +578,7 @@ func transpileToNode(node ast.Node, p *program.Program) (
 
 				// location of file
 				location := node.Position().GetSimpleLocation()
-				location = strings.Replace(location, os.Getenv("GOPATH"), "$GOPATH", -1)
+				location = program.PathSimplification(location)
 				doc.List = append([]*goast.Comment{{
 					Text: fmt.Sprintf("// %s - transpiled function from %s",
 						name, location),


Test patch:
diff --git a/cstd_test.go b/cstd_test.go
index 866fc4f..3709ea5 100644
--- a/cstd_test.go
+++ b/cstd_test.go
@@ -16,23 +16,45 @@ import (
 // http://www.cplusplus.com/reference/
 var cstd = map[string][]string{
 	"stdio.h": {
-		"remove",
-		"rename",
-		"tmpfile",
-		"tmpnam",
+		"clearerr",
 		"fclose",
+		"feof",
+		"ferror",
 		"fflush",
+		"fgetc",
+		"fgetpos",
+		"fgets",
 		"fopen",
-		"freopen",
-		"setbuf",
-		"setvbuf",
 		"fprintf",
+		"fputc",
+		"fputs",
+		"fread",
+		"freopen",
 		"fscanf",
+		"fseek",
+		"fsetpos",
+		"ftell",
+		"fwrite",
+		"getc",
+		"getchar",
+		"gets",
+		"perror",
 		"printf",
+		"putc",
+		"putchar",
+		"puts",
+		"remove",
+		"rename",
+		"rewind",
 		"scanf",
+		"setbuf",
+		"setvbuf",
 		"snprintf",
 		"sprintf",
 		"sscanf",
+		"tmpfile",
+		"tmpnam",
+		"ungetc",
 		"vfprintf",
 		"vfscanf",
 		"vprintf",
@@ -40,28 +62,6 @@ var cstd = map[string][]string{
 		"vsnprintf",
 		"vsprintf",
 		"vsscanf",
-		"fgetc",
-		"fgets",
-		"fputc",
-		"fputs",
-		"getc",
-		"getchar",
-		"gets",
-		"putc",
-		"putchar",
-		"puts",
-		"ungetc",
-		"fread",
-		"fwrite",
-		"fgetpos",
-		"fseek",
-		"fsetpos",
-		"ftell",
-		"rewind",
-		"clearerr",
-		"feof",
-		"ferror",
-		"perror",
 	},
 	"assert.h": {"assert"},
 	"ctype.h": {
@@ -90,183 +90,187 @@ var cstd = map[string][]string{
 		"localeconv",
 	},
 	"math.h": {
-		"cos",
-		"sin",
-		"tan",
+		"abs",
 		"acos",
+		"acosh",
 		"asin",
+		"asinh",
 		"atan",
 		"atan2",
-		"cosh",
-		"sinh",
-		"tanh",
-		"acosh",
-		"asinh",
 		"atanh",
+		"cbrt",
+		"ceil",
+		"copysign",
+		"cos",
+		"cosh",
+		"erf",
+		"erfc",
 		"exp",
+		"exp2",
+		"expm1",
+		"fabs",
+		"fdim",
+		"floor",
+		"fma",
+		"fmax",
+		"fmin",
+		"fmod",
 		"frexp",
+		"hypot",
+		"ilogb",
 		"ldexp",
+		"lgamma",
+		"llrint",
+		"llround",
 		"log",
 		"log10",
-		"modf",
-		"exp2",
-		"expm1",
-		"ilogb",
 		"log1p",
 		"log2",
 		"logb",
-		"scalbn",
-		"scalbln",
-		"pow",
-		"sqrt",
-		"cbrt",
-		"hypot",
-		"erf",
-		"erfc",
-		"tgamma",
-		"lgamma",
-		"ceil",
-		"floor",
-		"fmod",
-		"trunc",
-		"round",
-		"lround",
-		"llround",
-		"rint",
 		"lrint",
-		"llrint",
-		"nearbyint",
-		"remainder",
-		"remquo",
-		"copysign",
+		"lround",
+		"modf",
 		"nan",
+		"nearbyint",
 		"nextafter",
 		"nexttoward",
-		"fdim",
-		"fmax",
-		"fmin",
-		"fabs",
-		"abs",
-		"fma",
+		"pow",
+		"remainder",
+		"remquo",
+		"rint",
+		"round",
+		"scalbln",
+		"scalbn",
+		"sin",
+		"sinh",
+		"sqrt",
+		"tan",
+		"tanh",
+		"tgamma",
+		"trunc",
 	},
 	"setjmp.h": {
+		"jmp_buf",
 		"longjmp",
 		"setjmp",
-		"jmp_buf",
 	},
 	"signal.h": {
-		"signal",
 		"raise",
 		"sig_atomic_t",
+		"signal",
 	},
 	"stdarg.h": {
-		"va_list",
-		"va_start",
 		"va_arg",
 		"va_end",
+		"va_list",
+		"va_start",
 	},
 	"stddef.h": {
-		"ptrdiff_t",
-		"size_t",
+		"NULL",
 		"max_align_t",
 		"nullptr_t",
 		"offsetof",
-		"NULL",
+		"ptrdiff_t",
+		"size_t",
 	},
 	"stdlib.h": {
+		"EXIT_FAILURE",
+		"EXIT_SUCCESS",
+		"MB_CUR_MAX",
+		"NULL",
+		"RAND_MAX",
+		"_Exit",
+		"abort",
+		"abs",
+		"at_quick_exit",
+		"atexit",
 		"atof",
 		"atoi",
 		"atol",
 		"atoll",
-		"strtod",
-		"strtof",
-		"strtol",
-		"strtold",
-		"strtoll",
-		"strtoul",
-		"strtoull",
-		"rand",
-		"srand",
+		"bsearch",
 		"calloc",
-		"free",
-		"malloc",
-		"realloc",
-		"abort",
-		"atexit",
-		"at_quick_exit",
+		"div",
+		"div_t",
 		"exit",
+		"free",
 		"getenv",
-		"quick_exit",
-		"system",
-		"_Exit",
-		"bsearch",
-		"qsort",
-		"abs",
-		"div",
 		"labs",
 		"ldiv",
+		"ldiv_t",
 		"llabs",
 		"lldiv",
+		"lldiv_t",
+		"malloc",
 		"mblen",
-		"mbtowc",
-		"wctomb",
 		"mbstowcs",
-		"wcstombs",
-		"EXIT_FAILURE",
-		"EXIT_SUCCESS",
-		"MB_CUR_MAX",
-		"NULL",
-		"RAND_MAX",
-		"div_t",
-		"ldiv_t",
-		"lldiv_t",
+		"mbtowc",
+		"qsort",
+		"quick_exit",
+		"rand",
+		"realloc",
 		"size_t",
+		"srand",
+		"strtod",
+		"strtof",
+		"strtol",
+		"strtold",
+		"strtoll",
+		"strtoul",
+		"strtoull",
+		"system",
+		"wcstombs",
+		"wctomb",
 	},
 	"string.h": {
+		"NULL",
+		"memchr",
+		"memcmp",
 		"memcpy",
 		"memmove",
-		"strcpy",
-		"strncpy",
+		"memset",
+		"size_t",
 		"strcat",
-		"strncat",
-		"memcmp",
+		"strchr",
 		"strcmp",
 		"strcoll",
-		"strncmp",
-		"strxfrm",
-		"memchr",
-		"strchr",
+		"strcpy",
 		"strcspn",
+		"strerror",
+		"strlen",
+		"strncat",
+		"strncmp",
+		"strncpy",
 		"strpbrk",
 		"strrchr",
 		"strspn",
 		"strstr",
 		"strtok",
-		"memset",
-		"strerror",
-		"strlen",
-		"NULL",
-		"size_t",
+		"strxfrm",
 	},
 	"time.h": {
-		"clock",
-		"difftime",
-		"mktime",
-		"time",
+		"CLOCKS_PER_SEC",
+		"NULL",
 		"asctime",
+		"clock",
+		"clock_t",
 		"ctime",
+		"difftime",
 		"gmtime",
 		"localtime",
-		"strftime",
-		"CLOCKS_PER_SEC",
-		"NULL",
-		"clock_t",
+		"mktime",
 		"size_t",
+		"strftime",
+		"time",
 		"time_t",
 		"tm", // "struct tm",
 	},
 	"wchar.h": {
-
+		"NULL",
+		"WCHAR_MAX",
+		"WCHAR_MIN",
+		"WEOF",
+		"btowc",
 		"fgetwc",
 		"fgetws",
 		"fputwc",
@@ -276,10 +280,17 @@ var cstd = map[string][]string{
 		"fwscanf",
 		"getwc",
 		"getwchar",
+		"mbrlen",
+		"mbrtowc",
+		"mbsinit",
+		"mbsrtowcs",
+		"mbstate_t",
 		"putwc",
 		"putwchar",
+		"size_t",
 		"swprintf",
 		"swscanf",
+		"tm", // "struct tm",
 		"ungetwc",
 		"vfwprintf",
 		"vfwscanf",
@@ -287,61 +298,50 @@ var cstd = map[string][]string{
 		"vswscanf",
 		"vwprintf",
 		"vwscanf",
-		"wprintf",
-		"wscanf",
-		"wcstod",
-		"wcstof",
-		"wcstol",
-		"wcstold",
-		"wcstoll",
-		"wcstoul",
-		"wcstoull",
-		"btowc",
-		"mbrlen",
-		"mbrtowc",
-		"mbsinit",
-		"mbsrtowcs",
+		"wchar_t",
 		"wcrtomb",
-		"wctob",
-		"wcsrtombs",
 		"wcscat",
 		"wcschr",
 		"wcscmp",
 		"wcscoll",
 		"wcscpy",
 		"wcscspn",
+		"wcsftime",
 		"wcslen",
 		"wcsncat",
 		"wcsncmp",
 		"wcsncpy",
 		"wcspbrk",
 		"wcsrchr",
+		"wcsrtombs",
 		"wcsspn",
 		"wcsstr",
+		"wcstod",
+		"wcstof",
 		"wcstok",
+		"wcstol",
+		"wcstold",
+		"wcstoll",
+		"wcstoul",
+		"wcstoull",
 		"wcsxfrm",
+		"wctob",
+		"wint_t",
 		"wmemchr",
 		"wmemcmp",
 		"wmemcpy",
 		"wmemmove",
 		"wmemset",
-		"wcsftime",
-		"mbstate_t",
-		"size_t",
-		"tm", // "struct tm",
-		"wchar_t",
-		"wint_t",
-		"NULL",
-		"WCHAR_MAX",
-		"WCHAR_MIN",
-		"WEOF",
+		"wprintf",
+		"wscanf",
 	},
 	"wctype.h": {
-
+		"WEOF",
 		"iswalnum",
 		"iswalpha",
 		"iswblank",
 		"iswcntrl",
+		"iswctype",
 		"iswdigit",
 		"iswgraph",
 		"iswlower",
@@ -350,16 +350,14 @@ var cstd = map[string][]string{
 		"iswspace",
 		"iswupper",
 		"iswxdigit",
+		"towctrans",
 		"towlower",
 		"towupper",
-		"iswctype",
-		"towctrans",
 		"wctrans",
-		"wctype",
 		"wctrans_t",
+		"wctype",
 		"wctype_t",
 		"wint_t",
-		"WEOF",
 	},
 }
 
diff --git a/main_test.go b/main_test.go
index 3f7c92b..d388074 100644
--- a/main_test.go
+++ b/main_test.go
@@ -835,39 +835,61 @@ func TestCodeStyle(t *testing.T) {
 }
 
 func TestExamples(t *testing.T) {
-	var args = DefaultProgramArgs()
-	args.inputFiles = []string{"./examples/prime.c"}
-	args.outputFile = "./testdata/main.go"
-	args.packageName = "main"
-
-	// testing
-	err := Start(args)
-	if err != nil {
-		t.Errorf(err.Error())
+	tcs := []struct {
+		in  string
+		out string
+	}{
+		{
+			in:  "./examples/prime.c",
+			out: "./testdata/prime.go",
+		},
+		{
+			in:  "./examples/math.c",
+			out: "./testdata/math.go",
+		},
+		{
+			in:  "./examples/ap.c",
+			out: "./testdata/ap.go",
+		},
 	}
 
-	var file *os.File
-	file, err = os.Open(args.outputFile)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer file.Close()
+	for i := range tcs {
+		t.Run(tcs[i].in, func(t *testing.T) {
+			var args = DefaultProgramArgs()
+			args.inputFiles = []string{tcs[i].in}
+			args.outputFile = tcs[i].out
+			args.packageName = "main"
 
-	readme, err := ioutil.ReadFile("./README.md")
-	if err != nil {
-		t.Fatal(err)
-	}
+			// testing
+			err := Start(args)
+			if err != nil {
+				t.Errorf(err.Error())
+			}
 
-	scanner := bufio.NewScanner(file)
-	for scanner.Scan() {
-		line := scanner.Text()
-		if !bytes.Contains(readme, []byte(line)) {
-			t.Errorf("Cannot found line : %s", line)
-		}
-	}
+			var file *os.File
+			file, err = os.Open(args.outputFile)
+			if err != nil {
+				t.Fatal(err)
+			}
+			defer file.Close()
 
-	if err := scanner.Err(); err != nil {
-		t.Fatal(err)
+			readme, err := ioutil.ReadFile("./README.md")
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			scanner := bufio.NewScanner(file)
+			for scanner.Scan() {
+				line := scanner.Text()
+				if !bytes.Contains(readme, []byte(line)) {
+					t.Errorf("Cannot found line : %s", line)
+				}
+			}
+
+			if err := scanner.Err(); err != nil {
+				t.Fatal(err)
+			}
+		})
 	}
 }
 
diff --git a/other_test.go b/other_test.go
index 419e032..cce7a19 100644
--- a/other_test.go
+++ b/other_test.go
@@ -6,10 +6,12 @@ import (
 	"bytes"
 	"fmt"
 	"io"
+	"io/ioutil"
 	"net/http"
 	"os"
 	"os/exec"
 	"path/filepath"
+	"strconv"
 	"strings"
 	"sync"
 	"sync/atomic"
@@ -307,6 +309,7 @@ func TestFrame3dd(t *testing.T) {
 	cmd.Stderr = &stderr
 	err = cmd.Run()
 	if err != nil {
+		parseError(t, stderr.String())
 		t.Errorf("cmd.Run() failed with %s : %v\n", err, stderr.String())
 	}
 }
@@ -323,25 +326,25 @@ func TestCsparse(t *testing.T) {
 
 		// download file
 		t.Logf("Download files")
-		err := DownloadFile(
+		err := downloadFile(
 			folder+"csparse.h",
 			"https://people.sc.fsu.edu/~jburkardt/c_src/csparse/csparse.h")
 		if err != nil {
 			t.Fatalf("Cannot download : %v", err)
 		}
-		err = DownloadFile(
+		err = downloadFile(
 			folder+"csparse.c",
 			"https://people.sc.fsu.edu/~jburkardt/c_src/csparse/csparse.c")
 		if err != nil {
 			t.Fatalf("cannot download : %v", err)
 		}
-		err = DownloadFile(
+		err = downloadFile(
 			folder+"csparse_demo1.c",
 			"https://people.sc.fsu.edu/~jburkardt/c_src/csparse/csparse_demo1.c")
 		if err != nil {
 			t.Fatalf("Cannot download : %v", err)
 		}
-		err = DownloadFile(
+		err = downloadFile(
 			folder+"kershaw.st",
 			"https://people.sc.fsu.edu/~jburkardt/c_src/csparse/kershaw.st")
 		if err != nil {
@@ -396,7 +399,7 @@ func TestTriangle(t *testing.T) {
 		// download file
 		t.Logf("Download file")
 		fileUrl := "http://www.netlib.org/voronoi/triangle.zip"
-		err := DownloadFile(folder+"triangle.zip", fileUrl)
+		err := downloadFile(folder+"triangle.zip", fileUrl)
 		if err != nil {
 			t.Logf("Cannot download : %v", err)
 			return
@@ -404,7 +407,7 @@ func TestTriangle(t *testing.T) {
 
 		// extract zip
 		t.Logf("Extract")
-		_, err = Unzip(folder+"triangle.zip", folder)
+		_, err = unzip(folder+"triangle.zip", folder)
 		if err != nil {
 			t.Fatalf("Cannot unzip : %v", err)
 		}
@@ -432,20 +435,54 @@ func TestTriangle(t *testing.T) {
 		t.Log(l)
 	}
 
-	cmd := exec.Command("go", "build", "-o", folder+"triangle",
+	cmd := exec.Command("go", "build", "-o", folder+"triangle", "-gcflags", "-e",
 		args.outputFile)
 	var stdout, stderr bytes.Buffer
 	cmd.Stdout = &stdout
 	cmd.Stderr = &stderr
 	err = cmd.Run()
 	if err != nil {
+		parseError(t, stderr.String())
 		t.Logf("cmd.Run() failed with %s : %v\n", err, stderr.String())
 	}
 }
 
-// Unzip will decompress a zip archive, moving all files and folders
+func parseError(t *testing.T, str string) {
+	// Example:
+	// testdata/git-source/triangle/main.go:2478:41: invalid operation: (operator & not defined on slice)
+	lines := strings.Split(str, "\n")
+	codes := map[string][]string{}
+	for _, line := range lines {
+		line = strings.TrimSpace(line)
+		index := strings.Index(line, ":")
+		if index < 0 {
+			continue
+		}
+		filename := line[:index]
+		if _, err := os.Stat(filename); os.IsNotExist(err) {
+			// filename does not exist
+			continue
+		}
+		if _, ok := codes[filename]; !ok {
+			dat, err := ioutil.ReadFile(filename)
+			if err != nil {
+				continue
+			}
+			codes[filename] = strings.Split(string(dat), "\n")
+		}
+		indexLine := strings.Index(line[index+1:], ":")
+		if indexLine < 0 {
+			continue
+		}
+		if s, err := strconv.Atoi(line[index+1 : index+indexLine+1]); err == nil {
+			t.Logf("Code line %s: %s\n", line[index+1:index+indexLine+1], codes[filename][s-1])
+		}
+	}
+}
+
+// unzip will decompress a zip archive, moving all files and folders
 // within the zip file (parameter 1) to an output directory (parameter 2).
-func Unzip(src string, dest string) ([]string, error) {
+func unzip(src string, dest string) ([]string, error) {
 
 	var filenames []string
 
@@ -504,9 +541,9 @@ func Unzip(src string, dest string) ([]string, error) {
 	return filenames, nil
 }
 
-// DownloadFile will download a url to a local file. It's efficient because it will
+// downloadFile will download a url to a local file. It's efficient because it will
 // write as it downloads and not load the whole file into memory.
-func DownloadFile(filepath string, url string) error {
+func downloadFile(filepath string, url string) error {
 
 	// Create the file
 	out, err := os.Create(filepath)