9fans.net/go@v0.0.7/cmd/sam/io.go (about)

     1  package main
     2  
     3  import (
     4  	"log"
     5  	"os"
     6  	"os/exec"
     7  	"unicode/utf8"
     8  )
     9  
    10  const (
    11  	NSYSFILE = 3
    12  	NOFILE   = 128
    13  )
    14  
    15  func checkqid(f *File) {
    16  	w := whichmenu(f)
    17  	for i := 1; i < len(file); i++ {
    18  		g := file[i]
    19  		if w == i {
    20  			continue
    21  		}
    22  		if os.SameFile(f.info, g.info) {
    23  			warn_SS(Wdupfile, &f.name, &g.name)
    24  		}
    25  	}
    26  }
    27  
    28  var genc string
    29  
    30  func writef(f *File) {
    31  	newfile := 0
    32  	samename := Strcmp(&genstr, &f.name) == 0
    33  	name := Strtoc(&f.name)
    34  	info, err := os.Stat(name)
    35  	if err != nil {
    36  		newfile++
    37  	} else if samename && (!os.SameFile(f.info, info) || f.info.Size() != info.Size() || !f.info.ModTime().Equal(info.ModTime())) {
    38  		f.info = info
    39  		warn_S(Wdate, &genstr)
    40  		return
    41  	}
    42  	genc = string(genstr.s)
    43  	iofile, err = os.Create(genc)
    44  	if err != nil {
    45  		error_r(Ecreate, genc, err)
    46  	}
    47  	dprint("%s: ", genc)
    48  	if info, err := iofile.Stat(); err == nil && info.Mode()&os.ModeAppend != 0 && info.Size() > 0 {
    49  		error_(Eappend)
    50  	}
    51  	n := writeio(f)
    52  	if len(f.name.s) == 0 || samename {
    53  		if addr.r.p1 == 0 && addr.r.p2 == f.b.nc {
    54  			f.cleanseq = f.seq
    55  		}
    56  		mod := Clean
    57  		if f.cleanseq != f.seq {
    58  			mod = Dirty
    59  		}
    60  		state(f, mod)
    61  	}
    62  	if newfile != 0 {
    63  		dprint("(new file) ")
    64  	}
    65  	if addr.r.p2 > 0 && filereadc(f, addr.r.p2-1) != '\n' {
    66  		warn(Wnotnewline)
    67  	}
    68  	closeio(n)
    69  	if len(f.name.s) == 0 || samename {
    70  		if info, err := os.Stat(name); err == nil {
    71  			f.info = info
    72  			checkqid(f)
    73  		}
    74  	}
    75  }
    76  
    77  func readio(f *File, nulls *bool, setdate, toterm bool) Posn {
    78  	p := addr.r.p2
    79  	*nulls = false
    80  	b := 0
    81  	var nt Posn
    82  	if f.unread {
    83  		nt = bufload(&f.b, 0, iofile, nulls)
    84  		if toterm {
    85  			raspload(f)
    86  		}
    87  	} else {
    88  		var nr int
    89  		for nt = 0; ; nt += nr {
    90  			var buf [BLOCKSIZE]byte
    91  			n, err := iofile.Read(buf[b:])
    92  			if err != nil || n == 0 {
    93  				break
    94  			}
    95  			n += b
    96  			b = 0
    97  			nr := 0
    98  			s := buf[:n]
    99  			for len(s) > 0 {
   100  				if s[0] < utf8.RuneSelf {
   101  					if s[0] != 0 {
   102  						genbuf[nr] = rune(s[0])
   103  						nr++
   104  					} else {
   105  						*nulls = true
   106  					}
   107  					s = s[1:]
   108  					continue
   109  				}
   110  				if utf8.FullRune(s) {
   111  					r, w := utf8.DecodeRune(s)
   112  					if r != 0 {
   113  						genbuf[nr] = r
   114  						nr++
   115  					} else {
   116  						*nulls = true
   117  					}
   118  					s = s[w:]
   119  					continue
   120  				}
   121  				b = copy(buf[:], s)
   122  				break
   123  			}
   124  			loginsert(f, p, genbuf[:nr])
   125  		}
   126  	}
   127  	if b != 0 {
   128  		*nulls = true
   129  	}
   130  	if *nulls {
   131  		warn(Wnulls)
   132  	}
   133  	if setdate {
   134  		if info, err := iofile.Stat(); err == nil {
   135  			f.info = info
   136  			checkqid(f)
   137  		}
   138  	}
   139  	return nt
   140  }
   141  
   142  func writeio(f *File) Posn {
   143  	p := addr.r.p1
   144  	for p < addr.r.p2 {
   145  		var n int
   146  		if addr.r.p2-p > BLOCKSIZE {
   147  			n = BLOCKSIZE
   148  		} else {
   149  			n = addr.r.p2 - p
   150  		}
   151  		bufread(&f.b, p, genbuf[:n])
   152  		c := []byte(string(genbuf[:n])) // TODO(rsc)
   153  		if nw, err := iofile.Write(c); err != nil || nw != len(c) {
   154  			// free(c)
   155  			if p > 0 {
   156  				p += n
   157  			}
   158  			break
   159  		}
   160  		// free(c)
   161  		p += n
   162  	}
   163  	return p - addr.r.p1
   164  }
   165  
   166  func closeio(p Posn) {
   167  	iofile.Close()
   168  	iofile = nil
   169  	if p >= 0 {
   170  		dprint("#%d\n", p)
   171  	}
   172  }
   173  
   174  var remotefd0 IOFile = os.Stdin
   175  var remotefd1 IOFile = os.Stdout
   176  
   177  func bootterm(machine string, argv []string) {
   178  	if machine != "" {
   179  		cmd := exec.Command(argv[0], argv[1:]...)
   180  		cmd.Stdin = remotefd0
   181  		cmd.Stdout = remotefd1
   182  		if err := cmd.Start(); err != nil {
   183  			log.Fatal(err)
   184  		}
   185  		if err := cmd.Wait(); err != nil {
   186  			log.Fatalf("samterm: %v", err)
   187  		}
   188  		os.Exit(0)
   189  	}
   190  
   191  	cmd := exec.Command(samterm, argv[1:]...)
   192  	r1, w1, err := os.Pipe()
   193  	if err != nil {
   194  		log.Fatal(err)
   195  	}
   196  	r2, w2, err := os.Pipe()
   197  	if err != nil {
   198  		log.Fatal(err)
   199  	}
   200  	cmd.Stdin = r1
   201  	cmd.Stdout = w2
   202  	cmd.Stderr = os.Stderr
   203  	err = cmd.Start()
   204  	if err != nil {
   205  		log.Fatalf("samterm: %v", err)
   206  	}
   207  	r1.Close()
   208  	w2.Close()
   209  
   210  	os.Stdin = r2
   211  	os.Stdout = w1
   212  }
   213  
   214  func connectto(machine string, files []string) {
   215  	av := append([]string{RX, machine, rsamname, "-R"}, files...)
   216  	cmd := exec.Command(av[0], av[1:]...)
   217  	stdin, err := cmd.StdinPipe()
   218  	if err != nil {
   219  		log.Fatal(err)
   220  	}
   221  	stdout, err := cmd.StdoutPipe()
   222  	if err != nil {
   223  		log.Fatal(err)
   224  	}
   225  	err = cmd.Start()
   226  	if err != nil {
   227  		log.Fatalf("%s: %v", RX, err)
   228  	}
   229  	remotefd0 = stdout.(IOFile)
   230  	remotefd1 = stdin.(IOFile)
   231  }
   232  
   233  func startup(machine string, Rflag bool, argv []string, files []string) {
   234  	if machine != "" {
   235  		connectto(machine, files)
   236  	}
   237  	if !Rflag {
   238  		bootterm(machine, argv)
   239  	}
   240  	downloaded = true
   241  	outTs(Hversion, VERSION)
   242  }