cmd/dist: remove C sources, rename some to Go files

This CL makes the next one have nice cross-file diffs.

Change-Id: I9ce897dc505dea9923be4e823bae31f4f7fa2ee2
Reviewed-on: https://go-review.googlesource.com/2471
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Russ Cox 2015-01-07 11:37:04 -05:00
parent ce5cb037d1
commit ad6ee36cac
12 changed files with 0 additions and 2317 deletions

165
src/cmd/dist/a.h vendored
View file

@ -1,165 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
typedef int bool;
// The Time unit is unspecified; we just need to
// be able to compare whether t1 is older than t2 with t1 < t2.
typedef long long Time;
#define nil ((void*)0)
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
#ifndef PLAN9
#define USED(x) ((void)(x))
#endif
// A Buf is a byte buffer, like Go's []byte.
typedef struct Buf Buf;
struct Buf
{
char *p;
int len;
int cap;
};
// A Vec is a string vector, like Go's []string.
typedef struct Vec Vec;
struct Vec
{
char **p;
int len;
int cap;
};
// Modes for run.
enum {
CheckExit = 1,
};
// buf.c
bool bequal(Buf *s, Buf *t);
void bsubst(Buf *b, char *x, char *y);
void bfree(Buf *b);
void bgrow(Buf *b, int n);
void binit(Buf *b);
char* bpathf(Buf *b, char *fmt, ...);
char* bprintf(Buf *b, char *fmt, ...);
void bwritef(Buf *b, char *fmt, ...);
void breset(Buf *b);
char* bstr(Buf *b);
char* btake(Buf *b);
void bwrite(Buf *b, void *v, int n);
void bwriteb(Buf *dst, Buf *src);
void bwritestr(Buf *b, char *p);
void bswap(Buf *b, Buf *b1);
void vadd(Vec *v, char *p);
void vcopy(Vec *dst, char **src, int n);
void vfree(Vec *v);
void vgrow(Vec *v, int n);
void vinit(Vec *v);
void vreset(Vec *v);
void vuniq(Vec *v);
void splitlines(Vec*, char*);
void splitfields(Vec*, char*);
// build.c
extern char *goarch;
extern char *gobin;
extern char *gochar;
extern char *gohostarch;
extern char *gohostos;
extern char *goos;
extern char *goroot;
extern char *goroot_final;
extern char *goextlinkenabled;
extern char *goversion;
extern char *defaultcc;
extern char *defaultcxxtarget;
extern char *defaultcctarget;
extern char *workdir;
extern char *tooldir;
extern char *slash;
extern bool rebuildall;
extern bool defaultclang;
int find(char*, char**, int);
void init(void);
void cmdbanner(int, char**);
void cmdbootstrap(int, char**);
void cmdclean(int, char**);
void cmdenv(int, char**);
void cmdinstall(int, char**);
void cmdversion(int, char**);
// buildgc.c
void gcopnames(char*, char*);
void mkanames(char*, char*);
// buildruntime.c
void mkzasm(char*, char*);
void mkzsys(char*, char*);
void mkzgoarch(char*, char*);
void mkzgoos(char*, char*);
void mkzruntimedefs(char*, char*);
void mkzversion(char*, char*);
void mkzexperiment(char*, char*);
// buildgo.c
void mkzdefaultcc(char*, char*);
// main.c
extern int vflag;
extern int sflag;
void usage(void);
void xmain(int argc, char **argv);
// portability layer (plan9.c, unix.c, windows.c)
bool contains(char *p, char *sep);
void errprintf(char*, ...);
void fatal(char *msg, ...);
bool hasprefix(char *p, char *prefix);
bool hassuffix(char *p, char *suffix);
bool isabs(char*);
bool isdir(char *p);
bool isfile(char *p);
char* lastelem(char*);
Time mtime(char*);
void readfile(Buf*, char*);
void copyfile(char*, char*, int);
void run(Buf *b, char *dir, int mode, char *cmd, ...);
void runv(Buf *b, char *dir, int mode, Vec *argv);
void bgrunv(char *dir, int mode, Vec *argv);
void bgwait(void);
bool streq(char*, char*);
bool cansse2(void);
void writefile(Buf*, char*, int);
void xatexit(void (*f)(void));
void xexit(int);
void xfree(void*);
void xgetenv(Buf *b, char *name);
void xgetwd(Buf *b);
void* xmalloc(int n);
void* xmalloc(int);
int xmemcmp(void*, void*, int);
void xmemmove(void*, void*, int);
void xmkdir(char *p);
void xmkdirall(char*);
Time xmtime(char *p);
void xprintf(char*, ...);
void xqsort(void*, int, int, int(*)(const void*, const void*));
void xreaddir(Vec *dst, char *dir);
void* xrealloc(void*, int);
void xrealwd(Buf *b, char *path);
void xremove(char *p);
void xremoveall(char *p);
void xsetenv(char*, char*);
int xstrcmp(char*, char*);
char* xstrdup(char *p);
int xstrlen(char*);
char* xstrrchr(char*, int);
char* xstrstr(char*, char*);
char* xworkdir(void);
int xsamefile(char*, char*);
char* xgetgoarm(void);
int xtryexecfunc(void (*)(void));

49
src/cmd/dist/arg.h vendored
View file

@ -1,49 +0,0 @@
/*
Derived from Inferno include/kern.h.
http://code.google.com/p/inferno-os/source/browse/include/kern.h
Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
Portions Copyright © 2009 The Go Authors. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/* command line */
extern char *argv0;
#define ARGBEGIN for((argv0=(argv0?argv0:*argv)),argv++,argc--;\
argv[0] && argv[0][0]=='-' && argv[0][1];\
argc--, argv++) {\
char *_args, *_argt;\
char _argc;\
_args = &argv[0][1];\
if(_args[0]=='-' && _args[1]==0){\
argc--; argv++; break;\
}\
while((_argc = *_args++) != 0)\
switch(_argc)
#define ARGEND _argt=0;USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
#define ARGF() (_argt=_args, _args="",\
(*_argt? _argt: argv[1]? (argc--, *++argv): 0))
#define EARGF(x) (_argt=_args, _args="",\
(*_argt? _argt: argv[1]? (argc--, *++argv): ((x), fatal("usage"), (char*)0)))
#define ARGC() _argc

72
src/cmd/dist/arm.c vendored
View file

@ -1,72 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "a.h"
#ifndef __ARMEL__
char *
xgetgoarm(void)
{
return "6";
}
#else
static void useVFPv3(void);
static void useVFPv1(void);
char *
xgetgoarm(void)
{
#if defined(__FreeBSD__)
// FreeBSD has broken VFP support
return "5";
#endif
// NaCl always has VFP support.
if(streq(goos, "nacl") || xtryexecfunc(useVFPv3))
return "7";
else if(xtryexecfunc(useVFPv1))
return "6";
return "5";
}
static void
useVFPv3(void)
{
// try to run VFPv3-only "vmov.f64 d0, #112" instruction
// we can't use that instruction directly, because we
// might be compiling with a soft-float only toolchain.
//
// some newer toolchains are configured to use thumb
// by default, so we need to do some mode changing magic
// here.
// We can use "bx pc; nop" here, but GNU as(1) insists
// on warning us
// "use of r15 in bx in ARM mode is not really useful"
// so we workaround that by using "bx r0"
__asm__ __volatile__ ("mov r0, pc");
__asm__ __volatile__ ("bx r0");
__asm__ __volatile__ (".word 0xeeb70b00"); // vmov.f64 d0, #112
__asm__ __volatile__ (".word 0xe12fff1e"); // bx lr
}
static void
useVFPv1(void)
{
// try to run "vmov.f64 d0, d0" instruction
// we can't use that instruction directly, because we
// might be compiling with a soft-float only toolchain
//
// some newer toolchains are configured to use thumb
// by default, so we need to do some mode changing magic
// here.
// We can use "bx pc; nop" here, but GNU as(1) insists
// on warning us
// "use of r15 in bx in ARM mode is not really useful"
// so we workaround that by using "bx r0"
__asm__ __volatile__ ("mov r0, pc");
__asm__ __volatile__ ("bx r0");
__asm__ __volatile__ (".word 0xeeb00b40"); // vomv.f64 d0, d0
__asm__ __volatile__ (".word 0xe12fff1e"); // bx lr
}
#endif

284
src/cmd/dist/buf.c vendored
View file

@ -1,284 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Byte buffers and string vectors.
#include "a.h"
// binit prepares an uninitialized buffer for use.
void
binit(Buf *b)
{
b->p = nil;
b->len = 0;
b->cap = 0;
}
// breset truncates the buffer back to zero length.
void
breset(Buf *b)
{
b->len = 0;
}
// bfree frees the storage associated with a buffer.
void
bfree(Buf *b)
{
xfree(b->p);
binit(b);
}
// bgrow ensures that the buffer has at least n more bytes
// between its len and cap.
void
bgrow(Buf *b, int n)
{
int want;
want = b->len+n;
if(want > b->cap) {
b->cap = 2*want;
if(b->cap < 64)
b->cap = 64;
b->p = xrealloc(b->p, b->cap);
}
}
// bwrite appends the n bytes at v to the buffer.
void
bwrite(Buf *b, void *v, int n)
{
bgrow(b, n);
xmemmove(b->p+b->len, v, n);
b->len += n;
}
// bwritestr appends the string p to the buffer.
void
bwritestr(Buf *b, char *p)
{
bwrite(b, p, xstrlen(p));
}
// bstr returns a pointer to a NUL-terminated string of the
// buffer contents. The pointer points into the buffer.
char*
bstr(Buf *b)
{
bgrow(b, 1);
b->p[b->len] = '\0';
return b->p;
}
// btake takes ownership of the string form of the buffer.
// After this call, the buffer has zero length and does not
// refer to the memory that btake returned.
char*
btake(Buf *b)
{
char *p;
p = bstr(b);
binit(b);
return p;
}
// bwriteb appends the src buffer to the dst buffer.
void
bwriteb(Buf *dst, Buf *src)
{
bwrite(dst, src->p, src->len);
}
// bequal reports whether the buffers have the same content.
bool
bequal(Buf *s, Buf *t)
{
return s->len == t->len && xmemcmp(s->p, t->p, s->len) == 0;
}
// bsubst rewites b to replace all occurrences of x with y.
void
bsubst(Buf *b, char *x, char *y)
{
char *p;
int nx, ny, pos;
nx = xstrlen(x);
ny = xstrlen(y);
pos = 0;
for(;;) {
p = xstrstr(bstr(b)+pos, x);
if(p == nil)
break;
if(nx != ny) {
if(nx < ny) {
pos = p - b->p;
bgrow(b, ny-nx);
p = b->p + pos;
}
xmemmove(p+ny, p+nx, (b->p+b->len)-(p+nx));
}
xmemmove(p, y, ny);
pos = p+ny - b->p;
b->len += ny - nx;
}
}
// The invariant with the vectors is that v->p[0:v->len] is allocated
// strings that are owned by the vector. The data beyond v->len may
// be garbage.
// vinit prepares an uninitialized vector for use.
void
vinit(Vec *v)
{
v->p = nil;
v->len = 0;
v->cap = 0;
}
// vreset truncates the vector back to zero length.
void
vreset(Vec *v)
{
int i;
for(i=0; i<v->len; i++) {
xfree(v->p[i]);
v->p[i] = nil;
}
v->len = 0;
}
// vfree frees the storage associated with the vector.
void
vfree(Vec *v)
{
vreset(v);
xfree(v->p);
vinit(v);
}
// vgrow ensures that the vector has room for at least
// n more entries between len and cap.
void
vgrow(Vec *v, int n)
{
int want;
want = v->len+n;
if(want > v->cap) {
v->cap = 2*want;
if(v->cap < 64)
v->cap = 64;
v->p = xrealloc(v->p, v->cap*sizeof v->p[0]);
}
}
// vcopy copies the srclen strings at src into the vector.
void
vcopy(Vec *dst, char **src, int srclen)
{
int i;
// use vadd, to make copies of strings
for(i=0; i<srclen; i++)
vadd(dst, src[i]);
}
// vadd adds a copy of the string p to the vector.
void
vadd(Vec *v, char *p)
{
vgrow(v, 1);
if(p != nil)
p = xstrdup(p);
v->p[v->len++] = p;
}
// vaddn adds a string consisting of the n bytes at p to the vector.
static void
vaddn(Vec *v, char *p, int n)
{
char *q;
vgrow(v, 1);
q = xmalloc(n+1);
xmemmove(q, p, n);
q[n] = '\0';
v->p[v->len++] = q;
}
static int
strpcmp(const void *a, const void *b)
{
return xstrcmp(*(char**)a, *(char**)b);
}
// vuniq sorts the vector and then discards duplicates,
// in the manner of sort | uniq.
void
vuniq(Vec *v)
{
int i, n;
xqsort(v->p, v->len, sizeof(v->p[0]), strpcmp);
n = 0;
for(i=0; i<v->len; i++) {
if(n>0 && streq(v->p[i], v->p[n-1]))
xfree(v->p[i]);
else
v->p[n++] = v->p[i];
}
v->len = n;
}
// splitlines replaces the vector v with the result of splitting
// the input p after each \n. If there is a \r immediately before
// each \n, it will be removed.
void
splitlines(Vec *v, char *p)
{
int i;
char *start;
vreset(v);
start = p;
for(i=0; p[i]; i++) {
if((p[i] == '\r' && p[i+1] == '\n') || p[i] == '\n') {
vaddn(v, start, (p+i+1)-start);
if(p[i] == '\r') {
v->p[v->len-1][(p+i)-start] = '\n';
i++;
}
start = p+i+1;
}
}
if(*start != '\0')
vadd(v, start);
}
// splitfields replaces the vector v with the result of splitting
// the input p into non-empty fields containing no spaces.
void
splitfields(Vec *v, char *p)
{
char *start;
vreset(v);
for(;;) {
while(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
p++;
if(*p == '\0')
break;
start = p;
while(*p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' && *p != '\0')
p++;
vaddn(v, start, p-start);
}
}

758
src/cmd/dist/plan9.c vendored
View file

@ -1,758 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// These #ifdefs are being used as a substitute for
// build configuration, so that on any system, this
// tool can be built with the local equivalent of
// cc *.c
//
#ifdef PLAN9
#include <u.h>
#include <libc.h>
#include <stdio.h>
#undef nil
#undef nelem
#include "a.h"
// bprintf replaces the buffer with the result of the printf formatting
// and returns a pointer to the NUL-terminated buffer contents.
char*
bprintf(Buf *b, char *fmt, ...)
{
va_list arg;
char buf[4096];
breset(b);
va_start(arg, fmt);
vsnprintf(buf, sizeof buf, fmt, arg);
va_end(arg);
bwritestr(b, buf);
return bstr(b);
}
// bpathf is the same as bprintf (on windows it turns / into \ after the printf).
// It returns a pointer to the NUL-terminated buffer contents.
char*
bpathf(Buf *b, char *fmt, ...)
{
va_list arg;
char buf[4096];
breset(b);
va_start(arg, fmt);
vsnprintf(buf, sizeof buf, fmt, arg);
va_end(arg);
bwritestr(b, buf);
return bstr(b);
}
// bwritef is like bprintf but does not reset the buffer
// and does not return the NUL-terminated string.
void
bwritef(Buf *b, char *fmt, ...)
{
va_list arg;
char buf[4096];
va_start(arg, fmt);
vsnprintf(buf, sizeof buf, fmt, arg);
va_end(arg);
bwritestr(b, buf);
}
// breadfrom appends to b all the data that can be read from fd.
static void
breadfrom(Buf *b, int fd)
{
int n;
for(;;) {
bgrow(b, 4096);
n = read(fd, b->p+b->len, 4096);
if(n < 0)
fatal("read");
if(n == 0)
break;
b->len += n;
}
}
// xgetenv replaces b with the value of the named environment variable.
void
xgetenv(Buf *b, char *name)
{
char *p;
breset(b);
p = getenv(name);
if(p != nil)
bwritestr(b, p);
}
static void genrun(Buf *b, char *dir, int mode, Vec *argv, int bg);
// run runs the command named by cmd.
// If b is not nil, run replaces b with the output of the command.
// If dir is not nil, run runs the command in that directory.
// If mode is CheckExit, run calls fatal if the command is not successful.
void
run(Buf *b, char *dir, int mode, char *cmd, ...)
{
va_list arg;
Vec argv;
char *p;
vinit(&argv);
vadd(&argv, cmd);
va_start(arg, cmd);
while((p = va_arg(arg, char*)) != nil)
vadd(&argv, p);
va_end(arg);
runv(b, dir, mode, &argv);
vfree(&argv);
}
// runv is like run but takes a vector.
void
runv(Buf *b, char *dir, int mode, Vec *argv)
{
genrun(b, dir, mode, argv, 1);
}
// bgrunv is like run but runs the command in the background.
// bgwait waits for pending bgrunv to finish.
void
bgrunv(char *dir, int mode, Vec *argv)
{
genrun(nil, dir, mode, argv, 0);
}
#define MAXBG 4 /* maximum number of jobs to run at once */
static struct {
int pid;
int mode;
char *cmd;
Buf *b;
} bg[MAXBG];
static int nbg;
static int maxnbg = nelem(bg);
static void bgwait1(void);
// genrun is the generic run implementation.
static void
genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
{
int i, p[2], pid;
Buf b1, cmd;
char *q;
while(nbg >= maxnbg)
bgwait1();
binit(&b1);
binit(&cmd);
if(!isabs(argv->p[0])) {
bpathf(&b1, "/bin/%s", argv->p[0]);
free(argv->p[0]);
argv->p[0] = xstrdup(bstr(&b1));
}
// Generate a copy of the command to show in a log.
// Substitute $WORK for the work directory.
for(i=0; i<argv->len; i++) {
if(i > 0)
bwritestr(&cmd, " ");
q = argv->p[i];
if(workdir != nil && hasprefix(q, workdir)) {
bwritestr(&cmd, "$WORK");
q += strlen(workdir);
}
bwritestr(&cmd, q);
}
if(vflag > 1)
errprintf("%s\n", bstr(&cmd));
if(b != nil) {
breset(b);
if(pipe(p) < 0)
fatal("pipe");
}
switch(pid = fork()) {
case -1:
fatal("fork");
case 0:
if(b != nil) {
close(0);
close(p[0]);
dup(p[1], 1);
dup(p[1], 2);
if(p[1] > 2)
close(p[1]);
}
if(dir != nil) {
if(chdir(dir) < 0) {
fprint(2, "chdir: %r\n");
_exits("chdir");
}
}
vadd(argv, nil);
exec(argv->p[0], argv->p);
fprint(2, "%s\n", bstr(&cmd));
fprint(2, "exec: %r\n");
_exits("exec");
}
if(b != nil) {
close(p[1]);
breadfrom(b, p[0]);
close(p[0]);
}
if(nbg < 0)
fatal("bad bookkeeping");
bg[nbg].pid = pid;
bg[nbg].mode = mode;
bg[nbg].cmd = btake(&cmd);
bg[nbg].b = b;
nbg++;
if(wait)
bgwait();
bfree(&cmd);
bfree(&b1);
}
// bgwait1 waits for a single background job.
static void
bgwait1(void)
{
Waitmsg *w;
int i, mode;
char *cmd;
Buf *b;
w = wait();
if(w == nil)
fatal("wait");
for(i=0; i<nbg; i++)
if(bg[i].pid == w->pid)
goto ok;
fatal("wait: unexpected pid");
ok:
cmd = bg[i].cmd;
mode = bg[i].mode;
bg[i].pid = 0;
b = bg[i].b;
bg[i].b = nil;
bg[i] = bg[--nbg];
if(mode == CheckExit && w->msg[0]) {
if(b != nil)
xprintf("%s\n", bstr(b));
fatal("FAILED: %s", cmd);
}
xfree(cmd);
}
// bgwait waits for all the background jobs.
void
bgwait(void)
{
while(nbg > 0)
bgwait1();
}
// xgetwd replaces b with the current directory.
void
xgetwd(Buf *b)
{
char buf[4096];
breset(b);
if(getwd(buf, sizeof buf) == nil)
fatal("getwd");
bwritestr(b, buf);
}
// xrealwd replaces b with the 'real' name for the given path.
// real is defined as what getcwd returns in that directory.
void
xrealwd(Buf *b, char *path)
{
char buf[4096];
int fd;
fd = open(path, OREAD);
if(fd2path(fd, buf, sizeof buf) < 0)
fatal("fd2path");
close(fd);
breset(b);
bwritestr(b, buf);
}
// isdir reports whether p names an existing directory.
bool
isdir(char *p)
{
Dir *d;
ulong mode;
d = dirstat(p);
if(d == nil)
return 0;
mode = d->mode;
free(d);
return (mode & DMDIR) == DMDIR;
}
// isfile reports whether p names an existing file.
bool
isfile(char *p)
{
Dir *d;
ulong mode;
d = dirstat(p);
if(d == nil)
return 0;
mode = d->mode;
free(d);
return (mode & DMDIR) == 0;
}
// mtime returns the modification time of the file p.
Time
mtime(char *p)
{
Dir *d;
ulong t;
d = dirstat(p);
if(d == nil)
return 0;
t = d->mtime;
free(d);
return (Time)t;
}
// isabs reports whether p is an absolute path.
bool
isabs(char *p)
{
return hasprefix(p, "/");
}
// readfile replaces b with the content of the named file.
void
readfile(Buf *b, char *file)
{
int fd;
breset(b);
fd = open(file, OREAD);
if(fd < 0)
fatal("open %s", file);
breadfrom(b, fd);
close(fd);
}
// writefile writes b to the named file, creating it if needed.
void
writefile(Buf *b, char *file, int exec)
{
int fd;
Dir d;
fd = create(file, ORDWR, 0666);
if(fd < 0)
fatal("create %s", file);
if(write(fd, b->p, b->len) != b->len)
fatal("short write");
if(exec) {
nulldir(&d);
d.mode = 0755;
dirfwstat(fd, &d);
}
close(fd);
}
// xmkdir creates the directory p.
void
xmkdir(char *p)
{
int fd;
if(isdir(p))
return;
fd = create(p, OREAD, 0777|DMDIR);
close(fd);
if(fd < 0)
fatal("mkdir %s", p);
}
// xmkdirall creates the directory p and its parents, as needed.
void
xmkdirall(char *p)
{
char *q;
if(isdir(p))
return;
q = strrchr(p, '/');
if(q != nil) {
*q = '\0';
xmkdirall(p);
*q = '/';
}
xmkdir(p);
}
// xremove removes the file p.
void
xremove(char *p)
{
if(vflag > 2)
errprintf("rm %s\n", p);
remove(p);
}
// xremoveall removes the file or directory tree rooted at p.
void
xremoveall(char *p)
{
int i;
Buf b;
Vec dir;
binit(&b);
vinit(&dir);
if(isdir(p)) {
xreaddir(&dir, p);
for(i=0; i<dir.len; i++) {
bprintf(&b, "%s/%s", p, dir.p[i]);
xremoveall(bstr(&b));
}
}
if(vflag > 2)
errprintf("rm %s\n", p);
remove(p);
bfree(&b);
vfree(&dir);
}
// xreaddir replaces dst with a list of the names of the files in dir.
// The names are relative to dir; they are not full paths.
void
xreaddir(Vec *dst, char *dir)
{
Dir *d;
int fd, i, n;
vreset(dst);
fd = open(dir, OREAD);
if(fd < 0)
fatal("open %s", dir);
n = dirreadall(fd, &d);
for(i=0; i<n; i++)
vadd(dst, d[i].name);
free(d);
close(fd);
}
// xworkdir creates a new temporary directory to hold object files
// and returns the name of that directory.
char*
xworkdir(void)
{
Buf b;
char *p;
int fd, tries;
binit(&b);
fd = 0;
for(tries=0; tries<1000; tries++) {
bprintf(&b, "/tmp/go-cbuild-%06x", nrand((1<<24)-1));
fd = create(bstr(&b), OREAD|OEXCL, 0700|DMDIR);
if(fd >= 0)
goto done;
}
fatal("xworkdir create");
done:
close(fd);
p = btake(&b);
bfree(&b);
return p;
}
// fatal prints an error message to standard error and exits.
void
fatal(char *msg, ...)
{
va_list arg;
fflush(stdout);
fprintf(stderr, "go tool dist: ");
va_start(arg, msg);
vfprintf(stderr, msg, arg);
va_end(arg);
fprintf(stderr, "\n");
bgwait();
exits(msg);
}
// xmalloc returns a newly allocated zeroed block of n bytes of memory.
// It calls fatal if it runs out of memory.
void*
xmalloc(int n)
{
void *p;
p = malloc(n);
if(p == nil)
fatal("out of memory");
memset(p, 0, n);
return p;
}
// xstrdup returns a newly allocated copy of p.
// It calls fatal if it runs out of memory.
char*
xstrdup(char *p)
{
p = strdup(p);
if(p == nil)
fatal("out of memory");
return p;
}
// xrealloc grows the allocation p to n bytes and
// returns the new (possibly moved) pointer.
// It calls fatal if it runs out of memory.
void*
xrealloc(void *p, int n)
{
p = realloc(p, n);
if(p == nil)
fatal("out of memory");
return p;
}
// xfree frees the result returned by xmalloc, xstrdup, or xrealloc.
void
xfree(void *p)
{
free(p);
}
// hassuffix reports whether p ends with suffix.
bool
hassuffix(char *p, char *suffix)
{
int np, ns;
np = strlen(p);
ns = strlen(suffix);
return np >= ns && streq(p+np-ns, suffix);
}
// hasprefix reports whether p begins with prefix.
bool
hasprefix(char *p, char *prefix)
{
return strncmp(p, prefix, strlen(prefix)) == 0;
}
// contains reports whether sep appears in p.
bool
contains(char *p, char *sep)
{
return strstr(p, sep) != nil;
}
// streq reports whether p and q are the same string.
bool
streq(char *p, char *q)
{
return strcmp(p, q) == 0;
}
// lastelem returns the final path element in p.
char*
lastelem(char *p)
{
char *out;
out = p;
for(; *p; p++)
if(*p == '/')
out = p+1;
return out;
}
// xmemmove copies n bytes from src to dst.
void
xmemmove(void *dst, void *src, int n)
{
memmove(dst, src, n);
}
// xmemcmp compares the n-byte regions starting at a and at b.
int
xmemcmp(void *a, void *b, int n)
{
return memcmp(a, b, n);
}
// xstrlen returns the length of the NUL-terminated string at p.
int
xstrlen(char *p)
{
return strlen(p);
}
// xexit exits the process with return code n.
void
xexit(int n)
{
char buf[32];
snprintf(buf, sizeof buf, "%d", n);
exits(buf);
}
// xatexit schedules the exit-handler f to be run when the program exits.
void
xatexit(void (*f)(void))
{
atexit(f);
}
// xprintf prints a message to standard output.
void
xprintf(char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
vprintf(fmt, arg);
va_end(arg);
}
// errprintf prints a message to standard output.
void
errprintf(char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
vfprintf(stderr, fmt, arg);
va_end(arg);
}
// xsetenv sets the environment variable $name to the given value.
void
xsetenv(char *name, char *value)
{
putenv(name, value);
}
// main takes care of OS-specific startup and dispatches to xmain.
void
main(int argc, char **argv)
{
Buf b;
setvbuf(stdout, nil, _IOLBF, BUFSIZ);
setvbuf(stderr, nil, _IOLBF, BUFSIZ);
binit(&b);
rfork(RFENVG);
slash = "/";
gohostos = "plan9";
xgetenv(&b, "objtype");
if(b.len == 0)
fatal("$objtype is unset");
gohostarch = btake(&b);
srand(time(0)+getpid());
init();
xmain(argc, argv);
bfree(&b);
exits(nil);
}
// xqsort is a wrapper for the C standard qsort.
void
xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
{
qsort(data, n, elemsize, cmp);
}
// xstrcmp compares the NUL-terminated strings a and b.
int
xstrcmp(char *a, char *b)
{
return strcmp(a, b);
}
// xstrstr returns a pointer to the first occurrence of b in a.
char*
xstrstr(char *a, char *b)
{
return strstr(a, b);
}
// xstrrchr returns a pointer to the final occurrence of c in p.
char*
xstrrchr(char *p, int c)
{
return strrchr(p, c);
}
// xsamefile reports whether f1 and f2 are the same file (or dir)
int
xsamefile(char *f1, char *f2)
{
return streq(f1, f2); // suffice for now
}
// xtryexecfunc tries to execute function f, if any illegal instruction
// signal received in the course of executing that function, it will
// return 0, otherwise it will return 1.
int
xtryexecfunc(void (*f)(void))
{
USED(f);
return 0; // suffice for now
}
bool
cansse2(void)
{
// if we had access to cpuid, could answer this question
// less conservatively.
return 0;
}
#endif // PLAN9

989
src/cmd/dist/windows.c vendored
View file

@ -1,989 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// These #ifdefs are being used as a substitute for
// build configuration, so that on any system, this
// tool can be built with the local equivalent of
// cc *.c
//
#ifdef WIN32
// Portability layer implemented for Windows.
// See unix.c for doc comments about exported functions.
#include "a.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
/*
* Windows uses 16-bit rune strings in the APIs.
* Define conversions between Rune* and UTF-8 char*.
*/
typedef unsigned char uchar;
typedef unsigned short Rune; // same as Windows
// encoderune encodes the rune r into buf and returns
// the number of bytes used.
static int
encoderune(char *buf, Rune r)
{
if(r < 0x80) { // 7 bits
buf[0] = r;
return 1;
}
if(r < 0x800) { // 5+6 bits
buf[0] = 0xc0 | (r>>6);
buf[1] = 0x80 | (r&0x3f);
return 2;
}
buf[0] = 0xe0 | (r>>12);
buf[1] = 0x80 | ((r>>6)&0x3f);
buf[2] = 0x80 | (r&0x3f);
return 3;
}
// decoderune decodes the rune encoding at sbuf into r
// and returns the number of bytes used.
static int
decoderune(Rune *r, char *sbuf)
{
uchar *buf;
buf = (uchar*)sbuf;
if(buf[0] < 0x80) {
*r = buf[0];
return 1;
}
if((buf[0]&0xe0) == 0xc0 && (buf[1]&0xc0) == 0x80) {
*r = (buf[0]&~0xc0)<<6 | (buf[1]&~0x80);
if(*r < 0x80)
goto err;
return 2;
}
if((buf[0]&0xf0) == 0xe0 && (buf[1]&0xc0) == 0x80 && (buf[2]&0xc0) == 0x80) {
*r = (buf[0]&~0xc0)<<12 | (buf[1]&~0x80)<<6 | (buf[2]&~0x80);
if(*r < 0x800)
goto err;
return 3;
}
err:
*r = 0xfffd;
return 1;
}
// toutf replaces b with the UTF-8 encoding of the rune string r.
static void
toutf(Buf *b, Rune *r)
{
int i, n;
char buf[4];
breset(b);
for(i=0; r[i]; i++) {
n = encoderune(buf, r[i]);
bwrite(b, buf, n);
}
}
// torune replaces *rp with a pointer to a newly allocated
// rune string equivalent of the UTF-8 string p.
static void
torune(Rune **rp, char *p)
{
Rune *r, *w;
r = xmalloc((strlen(p)+1) * sizeof r[0]);
w = r;
while(*p)
p += decoderune(w++, p);
*w = 0;
*rp = r;
}
// errstr returns the most recent Windows error, in string form.
static char*
errstr(void)
{
DWORD code;
Rune *r;
Buf b;
binit(&b);
code = GetLastError();
r = nil;
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
nil, code, 0, (Rune*)&r, 0, nil);
toutf(&b, r);
return bstr(&b); // leak but we're dying anyway
}
void
xgetenv(Buf *b, char *name)
{
Rune *buf;
int n;
Rune *r;
breset(b);
torune(&r, name);
n = GetEnvironmentVariableW(r, NULL, 0);
if(n > 0) {
buf = xmalloc((n+1)*sizeof buf[0]);
GetEnvironmentVariableW(r, buf, n+1);
buf[n] = '\0';
toutf(b, buf);
xfree(buf);
}
xfree(r);
}
void
xsetenv(char *name, char *value)
{
Rune *rname, *rvalue;
torune(&rname, name);
torune(&rvalue, value);
SetEnvironmentVariableW(rname, rvalue);
xfree(rname);
xfree(rvalue);
}
char*
bprintf(Buf *b, char *fmt, ...)
{
va_list arg;
char buf[4096];
breset(b);
va_start(arg, fmt);
vsnprintf(buf, sizeof buf, fmt, arg);
va_end(arg);
bwritestr(b, buf);
return bstr(b);
}
void
bwritef(Buf *b, char *fmt, ...)
{
va_list arg;
char buf[4096];
// no reset
va_start(arg, fmt);
vsnprintf(buf, sizeof buf, fmt, arg);
va_end(arg);
bwritestr(b, buf);
}
// bpathf is like bprintf but replaces / with \ in the result,
// to make it a canonical windows file path.
char*
bpathf(Buf *b, char *fmt, ...)
{
int i;
va_list arg;
char buf[4096];
breset(b);
va_start(arg, fmt);
vsnprintf(buf, sizeof buf, fmt, arg);
va_end(arg);
bwritestr(b, buf);
for(i=0; i<b->len; i++)
if(b->p[i] == '/')
b->p[i] = '\\';
return bstr(b);
}
static void
breadfrom(Buf *b, HANDLE h)
{
DWORD n;
for(;;) {
if(b->len > 1<<22)
fatal("unlikely file size in readfrom");
bgrow(b, 4096);
n = 0;
if(!ReadFile(h, b->p+b->len, 4096, &n, nil)) {
// Happens for pipe reads.
break;
}
if(n == 0)
break;
b->len += n;
}
}
void
run(Buf *b, char *dir, int mode, char *cmd, ...)
{
va_list arg;
Vec argv;
char *p;
vinit(&argv);
vadd(&argv, cmd);
va_start(arg, cmd);
while((p = va_arg(arg, char*)) != nil)
vadd(&argv, p);
va_end(arg);
runv(b, dir, mode, &argv);
vfree(&argv);
}
static void genrun(Buf*, char*, int, Vec*, int);
void
runv(Buf *b, char *dir, int mode, Vec *argv)
{
genrun(b, dir, mode, argv, 1);
}
void
bgrunv(char *dir, int mode, Vec *argv)
{
genrun(nil, dir, mode, argv, 0);
}
#define MAXBG 4 /* maximum number of jobs to run at once */
static struct {
PROCESS_INFORMATION pi;
int mode;
char *cmd;
} bg[MAXBG];
static int nbg;
static void bgwait1(void);
static void
genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
{
// Another copy of this logic is in ../../lib9/run_windows.c.
// If there's a bug here, fix the logic there too.
int i, j, nslash;
Buf cmd;
char *q;
Rune *rcmd, *rexe, *rdir;
STARTUPINFOW si;
PROCESS_INFORMATION pi;
HANDLE p[2];
while(nbg >= nelem(bg))
bgwait1();
binit(&cmd);
for(i=0; i<argv->len; i++) {
q = argv->p[i];
if(i == 0 && streq(q, "hg"))
bwritestr(&cmd, "cmd.exe /c ");
if(i > 0)
bwritestr(&cmd, " ");
if(contains(q, " ") || contains(q, "\t") || contains(q, "\"") || contains(q, "\\\\") || hassuffix(q, "\\")) {
bwritestr(&cmd, "\"");
nslash = 0;
for(; *q; q++) {
if(*q == '\\') {
nslash++;
continue;
}
if(*q == '"') {
for(j=0; j<2*nslash+1; j++)
bwritestr(&cmd, "\\");
nslash = 0;
}
for(j=0; j<nslash; j++)
bwritestr(&cmd, "\\");
nslash = 0;
bwrite(&cmd, q, 1);
}
for(j=0; j<2*nslash; j++)
bwritestr(&cmd, "\\");
bwritestr(&cmd, "\"");
} else {
bwritestr(&cmd, q);
}
}
if(vflag > 1)
errprintf("%s\n", bstr(&cmd));
torune(&rcmd, bstr(&cmd));
rexe = nil;
rdir = nil;
if(dir != nil)
torune(&rdir, dir);
memset(&si, 0, sizeof si);
si.cb = sizeof si;
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = INVALID_HANDLE_VALUE;
if(b == nil) {
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
} else {
SECURITY_ATTRIBUTES seci;
memset(&seci, 0, sizeof seci);
seci.nLength = sizeof seci;
seci.bInheritHandle = 1;
breset(b);
if(!CreatePipe(&p[0], &p[1], &seci, 0))
fatal("CreatePipe: %s", errstr());
si.hStdOutput = p[1];
si.hStdError = p[1];
}
if(!CreateProcessW(rexe, rcmd, nil, nil, TRUE, 0, nil, rdir, &si, &pi)) {
if(mode!=CheckExit)
return;
fatal("%s: %s", argv->p[0], errstr());
}
if(rexe != nil)
xfree(rexe);
xfree(rcmd);
if(rdir != nil)
xfree(rdir);
if(b != nil) {
CloseHandle(p[1]);
breadfrom(b, p[0]);
CloseHandle(p[0]);
}
if(nbg < 0)
fatal("bad bookkeeping");
bg[nbg].pi = pi;
bg[nbg].mode = mode;
bg[nbg].cmd = btake(&cmd);
nbg++;
if(wait)
bgwait();
bfree(&cmd);
}
// closes the background job for bgwait1
static void
bgwaitclose(int i)
{
if(i < 0 || i >= nbg)
return;
CloseHandle(bg[i].pi.hProcess);
CloseHandle(bg[i].pi.hThread);
bg[i] = bg[--nbg];
}
// bgwait1 waits for a single background job
static void
bgwait1(void)
{
int i, mode;
char *cmd;
HANDLE bgh[MAXBG];
DWORD code;
if(nbg == 0)
fatal("bgwait1: nothing left");
for(i=0; i<nbg; i++)
bgh[i] = bg[i].pi.hProcess;
i = WaitForMultipleObjects(nbg, bgh, FALSE, INFINITE);
if(i < 0 || i >= nbg)
fatal("WaitForMultipleObjects: %s", errstr());
cmd = bg[i].cmd;
mode = bg[i].mode;
if(!GetExitCodeProcess(bg[i].pi.hProcess, &code)) {
bgwaitclose(i);
fatal("GetExitCodeProcess: %s", errstr());
return;
}
if(mode==CheckExit && code != 0) {
bgwaitclose(i);
fatal("FAILED: %s", cmd);
return;
}
bgwaitclose(i);
}
void
bgwait(void)
{
while(nbg > 0)
bgwait1();
}
// rgetwd returns a rune string form of the current directory's path.
static Rune*
rgetwd(void)
{
int n;
Rune *r;
n = GetCurrentDirectoryW(0, nil);
r = xmalloc((n+1)*sizeof r[0]);
GetCurrentDirectoryW(n+1, r);
r[n] = '\0';
return r;
}
void
xgetwd(Buf *b)
{
Rune *r;
r = rgetwd();
breset(b);
toutf(b, r);
xfree(r);
}
void
xrealwd(Buf *b, char *path)
{
Rune *old;
Rune *rnew;
old = rgetwd();
torune(&rnew, path);
if(!SetCurrentDirectoryW(rnew))
fatal("chdir %s: %s", path, errstr());
xfree(rnew);
xgetwd(b);
if(!SetCurrentDirectoryW(old)) {
breset(b);
toutf(b, old);
fatal("chdir %s: %s", bstr(b), errstr());
}
}
bool
isdir(char *p)
{
DWORD attr;
Rune *r;
torune(&r, p);
attr = GetFileAttributesW(r);
xfree(r);
return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY);
}
bool
isfile(char *p)
{
DWORD attr;
Rune *r;
torune(&r, p);
attr = GetFileAttributesW(r);
xfree(r);
return attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY);
}
Time
mtime(char *p)
{
HANDLE h;
WIN32_FIND_DATAW data;
Rune *r;
FILETIME *ft;
torune(&r, p);
h = FindFirstFileW(r, &data);
xfree(r);
if(h == INVALID_HANDLE_VALUE)
return 0;
FindClose(h);
ft = &data.ftLastWriteTime;
return (Time)ft->dwLowDateTime + ((Time)ft->dwHighDateTime<<32);
}
bool
isabs(char *p)
{
// c:/ or c:\ at beginning
if(('A' <= p[0] && p[0] <= 'Z') || ('a' <= p[0] && p[0] <= 'z'))
return p[1] == ':' && (p[2] == '/' || p[2] == '\\');
// / or \ at beginning
return p[0] == '/' || p[0] == '\\';
}
void
readfile(Buf *b, char *file)
{
HANDLE h;
Rune *r;
breset(b);
if(vflag > 2)
errprintf("read %s\n", file);
torune(&r, file);
h = CreateFileW(r, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if(h == INVALID_HANDLE_VALUE)
fatal("open %s: %s", file, errstr());
breadfrom(b, h);
CloseHandle(h);
}
void
writefile(Buf *b, char *file, int exec)
{
HANDLE h;
Rune *r;
DWORD n;
USED(exec);
if(vflag > 2)
errprintf("write %s\n", file);
torune(&r, file);
h = CreateFileW(r, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, nil, CREATE_ALWAYS, 0, 0);
if(h == INVALID_HANDLE_VALUE)
fatal("create %s: %s", file, errstr());
n = 0;
if(!WriteFile(h, b->p, b->len, &n, 0))
fatal("write %s: %s", file, errstr());
CloseHandle(h);
}
void
xmkdir(char *p)
{
Rune *r;
torune(&r, p);
if(!CreateDirectoryW(r, nil))
fatal("mkdir %s: %s", p, errstr());
xfree(r);
}
void
xmkdirall(char *p)
{
int c;
char *q, *q2;
if(isdir(p))
return;
q = strrchr(p, '/');
q2 = strrchr(p, '\\');
if(q2 != nil && (q == nil || q < q2))
q = q2;
if(q != nil) {
c = *q;
*q = '\0';
xmkdirall(p);
*q = c;
}
xmkdir(p);
}
void
xremove(char *p)
{
int attr;
Rune *r;
torune(&r, p);
attr = GetFileAttributesW(r);
if(attr >= 0) {
if(attr & FILE_ATTRIBUTE_DIRECTORY)
RemoveDirectoryW(r);
else
DeleteFileW(r);
}
xfree(r);
}
void
xreaddir(Vec *dst, char *dir)
{
Rune *r;
Buf b;
HANDLE h;
WIN32_FIND_DATAW data;
char *p, *q;
binit(&b);
vreset(dst);
bwritestr(&b, dir);
bwritestr(&b, "\\*");
torune(&r, bstr(&b));
h = FindFirstFileW(r, &data);
xfree(r);
if(h == INVALID_HANDLE_VALUE)
goto out;
do{
toutf(&b, data.cFileName);
p = bstr(&b);
q = xstrrchr(p, '\\');
if(q != nil)
p = q+1;
if(!streq(p, ".") && !streq(p, ".."))
vadd(dst, p);
}while(FindNextFileW(h, &data));
FindClose(h);
out:
bfree(&b);
}
char*
xworkdir(void)
{
Rune buf[1024];
Rune tmp[MAX_PATH];
Rune go[3] = {'g', 'o', '\0'};
int n;
Buf b;
n = GetTempPathW(nelem(buf), buf);
if(n <= 0)
fatal("GetTempPath: %s", errstr());
buf[n] = '\0';
if(GetTempFileNameW(buf, go, 0, tmp) == 0)
fatal("GetTempFileName: %s", errstr());
DeleteFileW(tmp);
if(!CreateDirectoryW(tmp, nil))
fatal("create tempdir: %s", errstr());
binit(&b);
toutf(&b, tmp);
return btake(&b);
}
void
xremoveall(char *p)
{
int i;
Buf b;
Vec dir;
Rune *r;
binit(&b);
vinit(&dir);
torune(&r, p);
if(isdir(p)) {
xreaddir(&dir, p);
for(i=0; i<dir.len; i++) {
bprintf(&b, "%s/%s", p, dir.p[i]);
xremoveall(bstr(&b));
}
RemoveDirectoryW(r);
} else {
DeleteFileW(r);
}
xfree(r);
bfree(&b);
vfree(&dir);
}
void
fatal(char *msg, ...)
{
static char buf1[1024];
va_list arg;
va_start(arg, msg);
vsnprintf(buf1, sizeof buf1, msg, arg);
va_end(arg);
errprintf("go tool dist: %s\n", buf1);
bgwait();
ExitProcess(1);
}
// HEAP is the persistent handle to the default process heap.
static HANDLE HEAP = INVALID_HANDLE_VALUE;
void*
xmalloc(int n)
{
void *p;
if(HEAP == INVALID_HANDLE_VALUE)
HEAP = GetProcessHeap();
p = HeapAlloc(HEAP, 0, n);
if(p == nil)
fatal("out of memory allocating %d: %s", n, errstr());
memset(p, 0, n);
return p;
}
char*
xstrdup(char *p)
{
char *q;
q = xmalloc(strlen(p)+1);
strcpy(q, p);
return q;
}
void
xfree(void *p)
{
if(HEAP == INVALID_HANDLE_VALUE)
HEAP = GetProcessHeap();
HeapFree(HEAP, 0, p);
}
void*
xrealloc(void *p, int n)
{
if(p == nil)
return xmalloc(n);
if(HEAP == INVALID_HANDLE_VALUE)
HEAP = GetProcessHeap();
p = HeapReAlloc(HEAP, 0, p, n);
if(p == nil)
fatal("out of memory reallocating %d", n);
return p;
}
bool
hassuffix(char *p, char *suffix)
{
int np, ns;
np = strlen(p);
ns = strlen(suffix);
return np >= ns && streq(p+np-ns, suffix);
}
bool
hasprefix(char *p, char *prefix)
{
return strncmp(p, prefix, strlen(prefix)) == 0;
}
bool
contains(char *p, char *sep)
{
return strstr(p, sep) != nil;
}
bool
streq(char *p, char *q)
{
return strcmp(p, q) == 0;
}
char*
lastelem(char *p)
{
char *out;
out = p;
for(; *p; p++)
if(*p == '/' || *p == '\\')
out = p+1;
return out;
}
void
xmemmove(void *dst, void *src, int n)
{
memmove(dst, src, n);
}
int
xmemcmp(void *a, void *b, int n)
{
return memcmp(a, b, n);
}
int
xstrlen(char *p)
{
return strlen(p);
}
void
xexit(int n)
{
ExitProcess(n);
}
void
xatexit(void (*f)(void))
{
atexit(f);
}
void
xprintf(char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
vprintf(fmt, arg);
va_end(arg);
}
void
errprintf(char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
vfprintf(stderr, fmt, arg);
va_end(arg);
}
int
main(int argc, char **argv)
{
SYSTEM_INFO si;
setvbuf(stdout, nil, _IOLBF, 0);
setvbuf(stderr, nil, _IOLBF, 0);
slash = "\\";
gohostos = "windows";
GetSystemInfo(&si);
switch(si.wProcessorArchitecture) {
case PROCESSOR_ARCHITECTURE_AMD64:
gohostarch = "amd64";
break;
case PROCESSOR_ARCHITECTURE_INTEL:
gohostarch = "386";
break;
default:
fatal("unknown processor architecture");
}
init();
xmain(argc, argv);
return 0;
}
void
xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
{
qsort(data, n, elemsize, cmp);
}
int
xstrcmp(char *a, char *b)
{
return strcmp(a, b);
}
char*
xstrstr(char *a, char *b)
{
return strstr(a, b);
}
char*
xstrrchr(char *p, int c)
{
char *ep;
ep = p+strlen(p);
for(ep=p+strlen(p); ep >= p; ep--)
if(*ep == c)
return ep;
return nil;
}
// xsamefile reports whether f1 and f2 are the same file (or dir)
int
xsamefile(char *f1, char *f2)
{
Rune *ru;
HANDLE fd1, fd2;
BY_HANDLE_FILE_INFORMATION fi1, fi2;
int r;
// trivial case
if(streq(f1, f2))
return 1;
torune(&ru, f1);
// refer to ../../os/stat_windows.go:/sameFile
fd1 = CreateFileW(ru, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
xfree(ru);
if(fd1 == INVALID_HANDLE_VALUE)
return 0;
torune(&ru, f2);
fd2 = CreateFileW(ru, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
xfree(ru);
if(fd2 == INVALID_HANDLE_VALUE) {
CloseHandle(fd1);
return 0;
}
r = GetFileInformationByHandle(fd1, &fi1) != 0 && GetFileInformationByHandle(fd2, &fi2) != 0;
CloseHandle(fd2);
CloseHandle(fd1);
if(r != 0 &&
fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber &&
fi1.nFileIndexHigh == fi2.nFileIndexHigh &&
fi1.nFileIndexLow == fi2.nFileIndexLow)
return 1;
return 0;
}
// xtryexecfunc tries to execute function f, if any illegal instruction
// signal received in the course of executing that function, it will
// return 0, otherwise it will return 1.
int
xtryexecfunc(void (*f)(void))
{
return 0; // suffice for now
}
static void
cpuid(int dst[4], int ax)
{
// NOTE: This asm statement is for mingw.
// If we ever support MSVC, use __cpuid(dst, ax)
// to use the built-in.
#if defined(__i386__) || defined(__x86_64__)
asm volatile("cpuid"
: "=a" (dst[0]), "=b" (dst[1]), "=c" (dst[2]), "=d" (dst[3])
: "0" (ax));
#else
dst[0] = dst[1] = dst[2] = dst[3] = 0;
#endif
}
bool
cansse2(void)
{
int info[4];
cpuid(info, 1);
return (info[3] & (1<<26)) != 0; // SSE2
}
#endif // __WINDOWS__