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  }