github.com/gotranspile/cxgo@v0.3.7/runtime/stdio/print.go (about) 1 package stdio 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io" 8 "os" 9 "strings" 10 "unsafe" 11 12 "github.com/gotranspile/cxgo/runtime/libc" 13 ) 14 15 func FprintfGo(w io.Writer, format string, args ...interface{}) (int, error) { 16 words := parseFormat(format) 17 var ( 18 goFormat bytes.Buffer 19 goArgs = make([]interface{}, 0, len(args)) 20 left = args 21 ) 22 popArg := func() (interface{}, error) { 23 if len(left) == 0 { 24 return nil, errors.New("not enough arguments to print") 25 } 26 v := left[0] 27 left = left[1:] 28 return v, nil 29 } 30 for _, w := range words { 31 if !w.Verb { 32 goFormat.WriteString(w.Str) 33 continue 34 } 35 if strings.HasPrefix(w.Str, "%*") { 36 // scanf-specific 37 return 0, errors.New("cannot skip args in printf") 38 } 39 switch w.Str { 40 case "%%": 41 goFormat.WriteString("%%") 42 continue 43 case "%c": 44 v, err := popArg() 45 if err != nil { 46 return 0, err 47 } 48 iv, err := asUint(v) 49 if err != nil { 50 return 0, err 51 } 52 goFormat.WriteString("%c") 53 goArgs = append(goArgs, rune(iv)) 54 continue 55 } 56 last := w.Str[len(w.Str)-1] 57 switch last { 58 case 's', 'S': 59 v, err := popArg() 60 if err != nil { 61 return 0, err 62 } 63 s, err := asString(v) 64 if err != nil { 65 return 0, err 66 } 67 goFormat.WriteString(strings.ToLower(w.Str)) 68 goArgs = append(goArgs, s) 69 continue 70 case 'p': 71 v, err := popArg() 72 if err != nil { 73 return 0, err 74 } 75 p, err := libc.AsPtr(v) 76 if err != nil { 77 return 0, err 78 } 79 goFormat.WriteString(w.Str) 80 goArgs = append(goArgs, p) 81 continue 82 case 'i', 'd', 'u', 'o', 'x': 83 if last == 'i' || last == 'u' { 84 w.Str = w.Str[:len(w.Str)-1] + "d" 85 } 86 w.Str = strings.ReplaceAll(w.Str, "l", "") 87 v, err := popArg() 88 if err != nil { 89 return 0, err 90 } 91 d, err := asUint(v) 92 if err != nil { 93 return 0, err 94 } 95 goFormat.WriteString(w.Str) 96 switch last { 97 case 'i', 'd': 98 goArgs = append(goArgs, int64(d)) 99 default: 100 goArgs = append(goArgs, d) 101 } 102 continue 103 case 'f', 'e', 'g', 'F', 'E', 'G': 104 v, err := popArg() 105 if err != nil { 106 return 0, err 107 } 108 f, err := asFloat(v) 109 if err != nil { 110 return 0, err 111 } 112 goFormat.WriteString(w.Str) 113 goArgs = append(goArgs, f) 114 continue 115 default: 116 return 0, fmt.Errorf("unsupported verb: %q", w.Str) 117 } 118 } 119 return fmt.Fprintf(w, goFormat.String(), goArgs...) 120 } 121 122 func FprintlnfGo(w io.Writer, format string, args ...interface{}) (int, error) { 123 if !strings.HasSuffix(format, "\n") { 124 format += "\n" 125 } 126 return FprintfGo(w, format, args...) 127 } 128 129 func Printf(format string, args ...interface{}) int { 130 n, _ := FprintfGo(os.Stdout, format, args...) 131 return n 132 } 133 134 func Vprintf(format string, args libc.ArgList) int { 135 return Printf(format, args.Args()...) 136 } 137 138 func Dprintf(format string, args ...interface{}) int { 139 n, _ := FprintlnfGo(os.Stderr, format, args...) 140 return n 141 } 142 143 func Sprintf(buf *byte, format string, args ...interface{}) int { 144 var b bytes.Buffer 145 n, _ := FprintfGo(&b, format, args...) 146 dst := unsafe.Slice(buf, b.Len()+1) 147 copy(dst, b.Bytes()) 148 dst[b.Len()] = 0 149 return n 150 } 151 152 func Vsprintf(buf *byte, format string, args libc.ArgList) int { 153 return Sprintf(buf, format, args.Args()...) 154 } 155 156 func Snprintf(buf *byte, sz int, format string, args ...interface{}) int { 157 var b bytes.Buffer 158 _, _ = FprintfGo(&b, format, args...) 159 dst := unsafe.Slice(buf, sz) 160 n := copy(dst, b.Bytes()) 161 if b.Len() < len(dst) { 162 dst[b.Len()] = 0 163 } 164 return n 165 } 166 167 func Vsnprintf(buf *byte, sz int, format string, args libc.ArgList) int { 168 return Snprintf(buf, sz, format, args.Args()...) 169 } 170 171 func Fprintf(file *File, format string, args ...interface{}) int { 172 n, err := FprintfGo(file.file, format, args...) 173 if err != nil { 174 file.err = err 175 return -1 176 } 177 return n 178 } 179 180 func Vfprintf(file *File, format string, args libc.ArgList) int { 181 return Fprintf(file, format, args.Args()...) 182 }