github.com/shijuvar/go@v0.0.0-20141209052335-e8f13700b70c/src/cmd/dist/windows.c (about)

     1  // Copyright 2012 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // These #ifdefs are being used as a substitute for
     6  // build configuration, so that on any system, this
     7  // tool can be built with the local equivalent of
     8  //	cc *.c
     9  //
    10  #ifdef WIN32
    11  
    12  // Portability layer implemented for Windows.
    13  // See unix.c for doc comments about exported functions.
    14  
    15  #include "a.h"
    16  #include <windows.h>
    17  #include <stdio.h>
    18  #include <stdlib.h>
    19  #include <stdarg.h>
    20  
    21  /*
    22   * Windows uses 16-bit rune strings in the APIs.
    23   * Define conversions between Rune* and UTF-8 char*.
    24   */
    25  
    26  typedef unsigned char uchar;
    27  typedef unsigned short Rune;  // same as Windows
    28  
    29  // encoderune encodes the rune r into buf and returns
    30  // the number of bytes used.
    31  static int
    32  encoderune(char *buf, Rune r)
    33  {
    34  	if(r < 0x80) {  // 7 bits
    35  		buf[0] = r;
    36  		return 1;
    37  	}
    38  	if(r < 0x800) {  // 5+6 bits
    39  		buf[0] = 0xc0 | (r>>6);
    40  		buf[1] = 0x80 | (r&0x3f);
    41  		return 2;
    42  	}
    43  	buf[0] = 0xe0 | (r>>12);
    44  	buf[1] = 0x80 | ((r>>6)&0x3f);
    45  	buf[2] = 0x80 | (r&0x3f);
    46  	return 3;
    47  }
    48  
    49  // decoderune decodes the rune encoding at sbuf into r
    50  // and returns the number of bytes used.
    51  static int
    52  decoderune(Rune *r, char *sbuf)
    53  {
    54  	uchar *buf;
    55  
    56  	buf = (uchar*)sbuf;
    57  	if(buf[0] < 0x80) {
    58  		*r = buf[0];
    59  		return 1;
    60  	}
    61  	if((buf[0]&0xe0) == 0xc0 && (buf[1]&0xc0) == 0x80) {
    62  		*r = (buf[0]&~0xc0)<<6 | (buf[1]&~0x80);
    63  		if(*r < 0x80)
    64  			goto err;
    65  		return 2;
    66  	}
    67  	if((buf[0]&0xf0) == 0xe0 && (buf[1]&0xc0) == 0x80 && (buf[2]&0xc0) == 0x80) {
    68  		*r = (buf[0]&~0xc0)<<12 | (buf[1]&~0x80)<<6 | (buf[2]&~0x80);
    69  		if(*r < 0x800)
    70  			goto err;
    71  		return 3;
    72  	}
    73  err:
    74  	*r = 0xfffd;
    75  	return 1;
    76  }
    77  
    78  // toutf replaces b with the UTF-8 encoding of the rune string r.	
    79  static void
    80  toutf(Buf *b, Rune *r)
    81  {
    82  	int i, n;
    83  	char buf[4];
    84  
    85  	breset(b);
    86  	for(i=0; r[i]; i++) {
    87  		n = encoderune(buf, r[i]);
    88  		bwrite(b, buf, n);
    89  	}
    90  }
    91  
    92  // torune replaces *rp with a pointer to a newly allocated
    93  // rune string equivalent of the UTF-8 string p.
    94  static void
    95  torune(Rune **rp, char *p)
    96  {
    97  	Rune *r, *w;
    98  
    99  	r = xmalloc((strlen(p)+1) * sizeof r[0]);
   100  	w = r;
   101  	while(*p)
   102  		p += decoderune(w++, p);
   103  	*w = 0;
   104  	*rp = r;
   105  }
   106  
   107  // errstr returns the most recent Windows error, in string form.
   108  static char*
   109  errstr(void)
   110  {
   111  	DWORD code;
   112  	Rune *r;
   113  	Buf b;
   114  
   115  	binit(&b);
   116  	code = GetLastError();
   117  	r = nil;
   118  	FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
   119  		nil, code, 0, (Rune*)&r, 0, nil);
   120  	toutf(&b, r);
   121  	return bstr(&b);  // leak but we're dying anyway
   122  }
   123  
   124  void
   125  xgetenv(Buf *b, char *name)
   126  {
   127  	Rune *buf;
   128  	int n;
   129  	Rune *r;
   130  
   131  	breset(b);
   132  	torune(&r, name);
   133  	n = GetEnvironmentVariableW(r, NULL, 0);
   134  	if(n > 0) {
   135  		buf = xmalloc((n+1)*sizeof buf[0]);
   136  		GetEnvironmentVariableW(r, buf, n+1);
   137  		buf[n] = '\0';
   138  		toutf(b, buf);
   139  		xfree(buf);
   140  	}
   141  	xfree(r);
   142  }
   143  
   144  void
   145  xsetenv(char *name, char *value)
   146  {
   147  	Rune *rname, *rvalue;
   148  
   149  	torune(&rname, name);
   150  	torune(&rvalue, value);
   151  	SetEnvironmentVariableW(rname, rvalue);
   152  	xfree(rname);
   153  	xfree(rvalue);
   154  }
   155  
   156  char*
   157  bprintf(Buf *b, char *fmt, ...)
   158  {
   159  	va_list arg;
   160  	char buf[4096];
   161  	
   162  	breset(b);
   163  	va_start(arg, fmt);
   164  	vsnprintf(buf, sizeof buf, fmt, arg);
   165  	va_end(arg);
   166  	bwritestr(b, buf);
   167  	return bstr(b);
   168  }
   169  
   170  void
   171  bwritef(Buf *b, char *fmt, ...)
   172  {
   173  	va_list arg;
   174  	char buf[4096];
   175  	
   176  	// no reset
   177  	va_start(arg, fmt);
   178  	vsnprintf(buf, sizeof buf, fmt, arg);
   179  	va_end(arg);
   180  	bwritestr(b, buf);
   181  }
   182  
   183  // bpathf is like bprintf but replaces / with \ in the result,
   184  // to make it a canonical windows file path.
   185  char*
   186  bpathf(Buf *b, char *fmt, ...)
   187  {
   188  	int i;
   189  	va_list arg;
   190  	char buf[4096];
   191  	
   192  	breset(b);
   193  	va_start(arg, fmt);
   194  	vsnprintf(buf, sizeof buf, fmt, arg);
   195  	va_end(arg);
   196  	bwritestr(b, buf);
   197  
   198  	for(i=0; i<b->len; i++)
   199  		if(b->p[i] == '/')
   200  			b->p[i] = '\\';
   201  
   202  	return bstr(b);
   203  }
   204  
   205  
   206  static void
   207  breadfrom(Buf *b, HANDLE h)
   208  {
   209  	DWORD n;
   210  
   211  	for(;;) {
   212  		if(b->len > 1<<22)
   213  			fatal("unlikely file size in readfrom");
   214  		bgrow(b, 4096);
   215  		n = 0;
   216  		if(!ReadFile(h, b->p+b->len, 4096, &n, nil)) {
   217  			// Happens for pipe reads.
   218  			break;
   219  		}
   220  		if(n == 0)
   221  			break;
   222  		b->len += n;
   223  	}
   224  }
   225  
   226  void
   227  run(Buf *b, char *dir, int mode, char *cmd, ...)
   228  {
   229  	va_list arg;
   230  	Vec argv;
   231  	char *p;
   232  	
   233  	vinit(&argv);
   234  	vadd(&argv, cmd);
   235  	va_start(arg, cmd);
   236  	while((p = va_arg(arg, char*)) != nil)
   237  		vadd(&argv, p);
   238  	va_end(arg);
   239  	
   240  	runv(b, dir, mode, &argv);
   241  	
   242  	vfree(&argv);
   243  }
   244  
   245  static void genrun(Buf*, char*, int, Vec*, int);
   246  
   247  void
   248  runv(Buf *b, char *dir, int mode, Vec *argv)
   249  {
   250  	genrun(b, dir, mode, argv, 1);
   251  }
   252  
   253  void
   254  bgrunv(char *dir, int mode, Vec *argv)
   255  {
   256  	genrun(nil, dir, mode, argv, 0);
   257  }
   258  
   259  #define MAXBG 4 /* maximum number of jobs to run at once */
   260  
   261  static struct {
   262  	PROCESS_INFORMATION pi;
   263  	int mode;
   264  	char *cmd;
   265  } bg[MAXBG];
   266  
   267  static int nbg;
   268  
   269  static void bgwait1(void);
   270  
   271  static void
   272  genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
   273  {
   274  	// Another copy of this logic is in ../../lib9/run_windows.c.
   275  	// If there's a bug here, fix the logic there too.
   276  	int i, j, nslash;
   277  	Buf cmd;
   278  	char *q;
   279  	Rune *rcmd, *rexe, *rdir;
   280  	STARTUPINFOW si;
   281  	PROCESS_INFORMATION pi;
   282  	HANDLE p[2];
   283  
   284  	while(nbg >= nelem(bg))
   285  		bgwait1();
   286  
   287  	binit(&cmd);
   288  
   289  	for(i=0; i<argv->len; i++) {
   290  		q = argv->p[i];
   291  		if(i == 0 && streq(q, "hg"))
   292  			bwritestr(&cmd, "cmd.exe /c ");
   293  		if(i > 0)
   294  			bwritestr(&cmd, " ");
   295  		if(contains(q, " ") || contains(q, "\t") || contains(q, "\"") || contains(q, "\\\\") || hassuffix(q, "\\")) {
   296  			bwritestr(&cmd, "\"");
   297  			nslash = 0;
   298  			for(; *q; q++) {
   299  				if(*q == '\\') {
   300  					nslash++;
   301  					continue;
   302  				}
   303  				if(*q == '"') {
   304  					for(j=0; j<2*nslash+1; j++)
   305  						bwritestr(&cmd, "\\");
   306  					nslash = 0;
   307  				}
   308  				for(j=0; j<nslash; j++)
   309  					bwritestr(&cmd, "\\");
   310  				nslash = 0;
   311  				bwrite(&cmd, q, 1);
   312  			}
   313  			for(j=0; j<2*nslash; j++)
   314  				bwritestr(&cmd, "\\");
   315  			bwritestr(&cmd, "\"");
   316  		} else {
   317  			bwritestr(&cmd, q);
   318  		}
   319  	}
   320  	if(vflag > 1)
   321  		errprintf("%s\n", bstr(&cmd));
   322  
   323  	torune(&rcmd, bstr(&cmd));
   324  	rexe = nil;
   325  	rdir = nil;
   326  	if(dir != nil)
   327  		torune(&rdir, dir);
   328  
   329  	memset(&si, 0, sizeof si);
   330  	si.cb = sizeof si;
   331  	si.dwFlags = STARTF_USESTDHANDLES;
   332  	si.hStdInput = INVALID_HANDLE_VALUE;
   333  	if(b == nil) {
   334  		si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
   335  		si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
   336  	} else {
   337  		SECURITY_ATTRIBUTES seci;
   338  
   339  		memset(&seci, 0, sizeof seci);
   340  		seci.nLength = sizeof seci;
   341  		seci.bInheritHandle = 1;
   342  		breset(b);
   343  		if(!CreatePipe(&p[0], &p[1], &seci, 0))
   344  			fatal("CreatePipe: %s", errstr());
   345  		si.hStdOutput = p[1];
   346  		si.hStdError = p[1];
   347  	}
   348  
   349  	if(!CreateProcessW(rexe, rcmd, nil, nil, TRUE, 0, nil, rdir, &si, &pi)) {
   350  		if(mode!=CheckExit)
   351  			return;
   352  		fatal("%s: %s", argv->p[0], errstr());
   353  	}
   354  	if(rexe != nil)
   355  		xfree(rexe);
   356  	xfree(rcmd);
   357  	if(rdir != nil)
   358  		xfree(rdir);
   359  	if(b != nil) {
   360  		CloseHandle(p[1]);
   361  		breadfrom(b, p[0]);
   362  		CloseHandle(p[0]);
   363  	}
   364  
   365  	if(nbg < 0)
   366  		fatal("bad bookkeeping");
   367  	bg[nbg].pi = pi;
   368  	bg[nbg].mode = mode;
   369  	bg[nbg].cmd = btake(&cmd);
   370  	nbg++;
   371  
   372  	if(wait)
   373  		bgwait();
   374  
   375  	bfree(&cmd);
   376  }
   377  
   378  // closes the background job for bgwait1
   379  static void
   380  bgwaitclose(int i)
   381  {
   382  	if(i < 0 || i >= nbg)
   383  		return;
   384  
   385  	CloseHandle(bg[i].pi.hProcess);
   386  	CloseHandle(bg[i].pi.hThread);
   387  	
   388  	bg[i] = bg[--nbg];
   389  }
   390  
   391  // bgwait1 waits for a single background job
   392  static void
   393  bgwait1(void)
   394  {
   395  	int i, mode;
   396  	char *cmd;
   397  	HANDLE bgh[MAXBG];
   398  	DWORD code;
   399  
   400  	if(nbg == 0)
   401  		fatal("bgwait1: nothing left");
   402  
   403  	for(i=0; i<nbg; i++)
   404  		bgh[i] = bg[i].pi.hProcess;
   405  	i = WaitForMultipleObjects(nbg, bgh, FALSE, INFINITE);
   406  	if(i < 0 || i >= nbg)
   407  		fatal("WaitForMultipleObjects: %s", errstr());
   408  
   409  	cmd = bg[i].cmd;
   410  	mode = bg[i].mode;
   411  	if(!GetExitCodeProcess(bg[i].pi.hProcess, &code)) {
   412  		bgwaitclose(i);
   413  		fatal("GetExitCodeProcess: %s", errstr());
   414  		return;
   415  	}
   416  
   417  	if(mode==CheckExit && code != 0) {
   418  		bgwaitclose(i);
   419  		fatal("FAILED: %s", cmd);
   420  		return;
   421  	}
   422  
   423  	bgwaitclose(i);
   424  }
   425  
   426  void
   427  bgwait(void)
   428  {
   429  	while(nbg > 0)
   430  		bgwait1();
   431  }
   432  
   433  // rgetwd returns a rune string form of the current directory's path.
   434  static Rune*
   435  rgetwd(void)
   436  {
   437  	int n;
   438  	Rune *r;
   439  
   440  	n = GetCurrentDirectoryW(0, nil);
   441  	r = xmalloc((n+1)*sizeof r[0]);
   442  	GetCurrentDirectoryW(n+1, r);
   443  	r[n] = '\0';
   444  	return r;
   445  }
   446  
   447  void
   448  xgetwd(Buf *b)
   449  {
   450  	Rune *r;
   451  
   452  	r = rgetwd();
   453  	breset(b);
   454  	toutf(b, r);
   455  	xfree(r);
   456  }
   457  
   458  void
   459  xrealwd(Buf *b, char *path)
   460  {
   461  	Rune *old;
   462  	Rune *rnew;
   463  
   464  	old = rgetwd();
   465  	torune(&rnew, path);
   466  	if(!SetCurrentDirectoryW(rnew))
   467  		fatal("chdir %s: %s", path, errstr());
   468  	xfree(rnew);
   469  	xgetwd(b);
   470  	if(!SetCurrentDirectoryW(old)) {
   471  		breset(b);
   472  		toutf(b, old);
   473  		fatal("chdir %s: %s", bstr(b), errstr());
   474  	}
   475  }
   476  
   477  bool
   478  isdir(char *p)
   479  {
   480  	DWORD attr;
   481  	Rune *r;
   482  
   483  	torune(&r, p);
   484  	attr = GetFileAttributesW(r);
   485  	xfree(r);
   486  	return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY);
   487  }
   488  
   489  bool
   490  isfile(char *p)
   491  {
   492  	DWORD attr;
   493  	Rune *r;
   494  
   495  	torune(&r, p);
   496  	attr = GetFileAttributesW(r);
   497  	xfree(r);
   498  	return attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY);
   499  }
   500  
   501  Time
   502  mtime(char *p)
   503  {
   504  	HANDLE h;
   505  	WIN32_FIND_DATAW data;
   506  	Rune *r;
   507  	FILETIME *ft;
   508  
   509  	torune(&r, p);
   510  	h = FindFirstFileW(r, &data);
   511  	xfree(r);
   512  	if(h == INVALID_HANDLE_VALUE)
   513  		return 0;
   514  	FindClose(h);
   515  	ft = &data.ftLastWriteTime;
   516  	return (Time)ft->dwLowDateTime + ((Time)ft->dwHighDateTime<<32);
   517  }
   518  
   519  bool
   520  isabs(char *p)
   521  {
   522  	// c:/ or c:\ at beginning
   523  	if(('A' <= p[0] && p[0] <= 'Z') || ('a' <= p[0] && p[0] <= 'z'))
   524  		return p[1] == ':' && (p[2] == '/' || p[2] == '\\');
   525  	// / or \ at beginning
   526  	return p[0] == '/' || p[0] == '\\';
   527  }
   528  
   529  void
   530  readfile(Buf *b, char *file)
   531  {
   532  	HANDLE h;
   533  	Rune *r;
   534  
   535  	breset(b);
   536  	if(vflag > 2)
   537  		errprintf("read %s\n", file);
   538  	torune(&r, file);
   539  	h = CreateFileW(r, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
   540  	if(h == INVALID_HANDLE_VALUE)
   541  		fatal("open %s: %s", file, errstr());
   542  	breadfrom(b, h);
   543  	CloseHandle(h);
   544  }
   545  
   546  void
   547  writefile(Buf *b, char *file, int exec)
   548  {
   549  	HANDLE h;
   550  	Rune *r;
   551  	DWORD n;
   552  
   553  	USED(exec);
   554  
   555  	if(vflag > 2)
   556  		errprintf("write %s\n", file);
   557  	torune(&r, file);
   558  	h = CreateFileW(r, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, nil, CREATE_ALWAYS, 0, 0);
   559  	if(h == INVALID_HANDLE_VALUE)
   560  		fatal("create %s: %s", file, errstr());
   561  	n = 0;
   562  	if(!WriteFile(h, b->p, b->len, &n, 0))
   563  		fatal("write %s: %s", file, errstr());
   564  	CloseHandle(h);
   565  }
   566  	
   567  
   568  void
   569  xmkdir(char *p)
   570  {
   571  	Rune *r;
   572  
   573  	torune(&r, p);
   574  	if(!CreateDirectoryW(r, nil))
   575  		fatal("mkdir %s: %s", p, errstr());
   576  	xfree(r);
   577  }
   578  
   579  void
   580  xmkdirall(char *p)
   581  {
   582  	int c;
   583  	char *q, *q2;
   584  	
   585  	if(isdir(p))
   586  		return;
   587  	q = strrchr(p, '/');
   588  	q2 = strrchr(p, '\\');
   589  	if(q2 != nil && (q == nil || q < q2))
   590  		q = q2;
   591  	if(q != nil) {
   592  		c = *q;
   593  		*q = '\0';
   594  		xmkdirall(p);
   595  		*q = c;
   596  	}
   597  	xmkdir(p);
   598  }
   599  
   600  void
   601  xremove(char *p)
   602  {
   603  	int attr;
   604  	Rune *r;
   605  
   606  	torune(&r, p);
   607  	attr = GetFileAttributesW(r);
   608  	if(attr >= 0) {
   609  		if(attr & FILE_ATTRIBUTE_DIRECTORY)
   610  			RemoveDirectoryW(r);
   611  		else
   612  			DeleteFileW(r);
   613  	}
   614  	xfree(r);
   615  }
   616  
   617  void
   618  xreaddir(Vec *dst, char *dir)
   619  {
   620  	Rune *r;
   621  	Buf b;
   622  	HANDLE h;
   623  	WIN32_FIND_DATAW data;
   624  	char *p, *q;
   625  
   626  	binit(&b);
   627  	vreset(dst);
   628  
   629  	bwritestr(&b, dir);
   630  	bwritestr(&b, "\\*");
   631  	torune(&r, bstr(&b));
   632  
   633  	h = FindFirstFileW(r, &data);
   634  	xfree(r);
   635  	if(h == INVALID_HANDLE_VALUE)
   636  		goto out;
   637  	do{
   638  		toutf(&b, data.cFileName);
   639  		p = bstr(&b);
   640  		q = xstrrchr(p, '\\');
   641  		if(q != nil)
   642  			p = q+1;
   643  		if(!streq(p, ".") && !streq(p, ".."))
   644  			vadd(dst, p);
   645  	}while(FindNextFileW(h, &data));
   646  	FindClose(h);
   647  
   648  out:
   649  	bfree(&b);
   650  }
   651  
   652  char*
   653  xworkdir(void)
   654  {
   655  	Rune buf[1024];
   656  	Rune tmp[MAX_PATH];
   657  	Rune go[3] = {'g', 'o', '\0'};
   658  	int n;
   659  	Buf b;
   660  
   661  	n = GetTempPathW(nelem(buf), buf);
   662  	if(n <= 0)
   663  		fatal("GetTempPath: %s", errstr());
   664  	buf[n] = '\0';
   665  
   666  	if(GetTempFileNameW(buf, go, 0, tmp) == 0)
   667  		fatal("GetTempFileName: %s", errstr());
   668  	DeleteFileW(tmp);
   669  	if(!CreateDirectoryW(tmp, nil))
   670  		fatal("create tempdir: %s", errstr());
   671  	
   672  	binit(&b);
   673  	toutf(&b, tmp);
   674  	return btake(&b);
   675  }
   676  
   677  void
   678  xremoveall(char *p)
   679  {
   680  	int i;
   681  	Buf b;
   682  	Vec dir;
   683  	Rune *r;
   684  
   685  	binit(&b);
   686  	vinit(&dir);
   687  
   688  	torune(&r, p);
   689  	if(isdir(p)) {
   690  		xreaddir(&dir, p);
   691  		for(i=0; i<dir.len; i++) {
   692  			bprintf(&b, "%s/%s", p, dir.p[i]);
   693  			xremoveall(bstr(&b));
   694  		}
   695  		RemoveDirectoryW(r);
   696  	} else {
   697  		DeleteFileW(r);
   698  	}
   699  	xfree(r);
   700  	
   701  	bfree(&b);
   702  	vfree(&dir);	
   703  }
   704  
   705  void
   706  fatal(char *msg, ...)
   707  {
   708  	static char buf1[1024];
   709  	va_list arg;
   710  
   711  	va_start(arg, msg);
   712  	vsnprintf(buf1, sizeof buf1, msg, arg);
   713  	va_end(arg);
   714  
   715  	errprintf("go tool dist: %s\n", buf1);
   716  	
   717  	bgwait();
   718  	ExitProcess(1);
   719  }
   720  
   721  // HEAP is the persistent handle to the default process heap.
   722  static HANDLE HEAP = INVALID_HANDLE_VALUE;
   723  
   724  void*
   725  xmalloc(int n)
   726  {
   727  	void *p;
   728  
   729  	if(HEAP == INVALID_HANDLE_VALUE)
   730  		HEAP = GetProcessHeap();
   731  	p = HeapAlloc(HEAP, 0, n);
   732  	if(p == nil)
   733  		fatal("out of memory allocating %d: %s", n, errstr());
   734  	memset(p, 0, n);
   735  	return p;
   736  }
   737  
   738  char*
   739  xstrdup(char *p)
   740  {
   741  	char *q;
   742  
   743  	q = xmalloc(strlen(p)+1);
   744  	strcpy(q, p);
   745  	return q;
   746  }
   747  
   748  void
   749  xfree(void *p)
   750  {
   751  	if(HEAP == INVALID_HANDLE_VALUE)
   752  		HEAP = GetProcessHeap();
   753  	HeapFree(HEAP, 0, p);
   754  }
   755  
   756  void*
   757  xrealloc(void *p, int n)
   758  {
   759  	if(p == nil)
   760  		return xmalloc(n);
   761  	if(HEAP == INVALID_HANDLE_VALUE)
   762  		HEAP = GetProcessHeap();
   763  	p = HeapReAlloc(HEAP, 0, p, n);
   764  	if(p == nil)
   765  		fatal("out of memory reallocating %d", n);
   766  	return p;
   767  }
   768  
   769  bool
   770  hassuffix(char *p, char *suffix)
   771  {
   772  	int np, ns;
   773  
   774  	np = strlen(p);
   775  	ns = strlen(suffix);
   776  	return np >= ns && streq(p+np-ns, suffix);
   777  }
   778  
   779  bool
   780  hasprefix(char *p, char *prefix)
   781  {
   782  	return strncmp(p, prefix, strlen(prefix)) == 0;
   783  }
   784  
   785  bool
   786  contains(char *p, char *sep)
   787  {
   788  	return strstr(p, sep) != nil;
   789  }
   790  
   791  bool
   792  streq(char *p, char *q)
   793  {
   794  	return strcmp(p, q) == 0;
   795  }
   796  
   797  char*
   798  lastelem(char *p)
   799  {
   800  	char *out;
   801  
   802  	out = p;
   803  	for(; *p; p++)
   804  		if(*p == '/' || *p == '\\')
   805  			out = p+1;
   806  	return out;
   807  }
   808  
   809  void
   810  xmemmove(void *dst, void *src, int n)
   811  {
   812  	memmove(dst, src, n);
   813  }
   814  
   815  int
   816  xmemcmp(void *a, void *b, int n)
   817  {
   818  	return memcmp(a, b, n);
   819  }
   820  
   821  int
   822  xstrlen(char *p)
   823  {
   824  	return strlen(p);
   825  }
   826  
   827  void
   828  xexit(int n)
   829  {
   830  	ExitProcess(n);
   831  }
   832  
   833  void
   834  xatexit(void (*f)(void))
   835  {
   836  	atexit(f);
   837  }
   838  
   839  void
   840  xprintf(char *fmt, ...)
   841  {
   842  	va_list arg;
   843  	
   844  	va_start(arg, fmt);
   845  	vprintf(fmt, arg);
   846  	va_end(arg);
   847  }
   848  
   849  void
   850  errprintf(char *fmt, ...)
   851  {
   852  	va_list arg;
   853  	
   854  	va_start(arg, fmt);
   855  	vfprintf(stderr, fmt, arg);
   856  	va_end(arg);
   857  }
   858  
   859  int
   860  main(int argc, char **argv)
   861  {
   862  	SYSTEM_INFO si;
   863  
   864  	setvbuf(stdout, nil, _IOLBF, 0);
   865  	setvbuf(stderr, nil, _IOLBF, 0);
   866  
   867  	slash = "\\";
   868  	gohostos = "windows";
   869  
   870  	GetSystemInfo(&si);
   871  	switch(si.wProcessorArchitecture) {
   872  	case PROCESSOR_ARCHITECTURE_AMD64:
   873  		gohostarch = "amd64";
   874  		break;
   875  	case PROCESSOR_ARCHITECTURE_INTEL:
   876  		gohostarch = "386";
   877  		break;
   878  	default:
   879  		fatal("unknown processor architecture");
   880  	}
   881  
   882  	init();
   883  
   884  	xmain(argc, argv);
   885  	return 0;
   886  }
   887  
   888  void
   889  xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
   890  {
   891  	qsort(data, n, elemsize, cmp);
   892  }
   893  
   894  int
   895  xstrcmp(char *a, char *b)
   896  {
   897  	return strcmp(a, b);
   898  }
   899  
   900  char*
   901  xstrstr(char *a, char *b)
   902  {
   903  	return strstr(a, b);
   904  }
   905  
   906  char*
   907  xstrrchr(char *p, int c)
   908  {
   909  	char *ep;
   910  	
   911  	ep = p+strlen(p);
   912  	for(ep=p+strlen(p); ep >= p; ep--)
   913  		if(*ep == c)
   914  			return ep;
   915  	return nil;
   916  }
   917  
   918  // xsamefile reports whether f1 and f2 are the same file (or dir)
   919  int
   920  xsamefile(char *f1, char *f2)
   921  {
   922  	Rune *ru;
   923  	HANDLE fd1, fd2;
   924  	BY_HANDLE_FILE_INFORMATION fi1, fi2;
   925  	int r;
   926  
   927  	// trivial case
   928  	if(streq(f1, f2))
   929  		return 1;
   930  	
   931  	torune(&ru, f1);
   932  	// refer to ../../os/stat_windows.go:/sameFile
   933  	fd1 = CreateFileW(ru, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
   934  	xfree(ru);
   935  	if(fd1 == INVALID_HANDLE_VALUE)
   936  		return 0;
   937  	torune(&ru, f2);
   938  	fd2 = CreateFileW(ru, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
   939  	xfree(ru);
   940  	if(fd2 == INVALID_HANDLE_VALUE) {
   941  		CloseHandle(fd1);
   942  		return 0;
   943  	}
   944  	r = GetFileInformationByHandle(fd1, &fi1) != 0 && GetFileInformationByHandle(fd2, &fi2) != 0;
   945  	CloseHandle(fd2);
   946  	CloseHandle(fd1);
   947  	if(r != 0 &&
   948  	   fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber &&
   949  	   fi1.nFileIndexHigh == fi2.nFileIndexHigh &&
   950  	   fi1.nFileIndexLow == fi2.nFileIndexLow)
   951  	   	return 1;
   952  	return 0;
   953  }
   954  
   955  // xtryexecfunc tries to execute function f, if any illegal instruction
   956  // signal received in the course of executing that function, it will
   957  // return 0, otherwise it will return 1.
   958  int
   959  xtryexecfunc(void (*f)(void))
   960  {
   961  	return 0; // suffice for now
   962  }
   963  
   964  static void
   965  cpuid(int dst[4], int ax)
   966  {
   967  	// NOTE: This asm statement is for mingw.
   968  	// If we ever support MSVC, use __cpuid(dst, ax)
   969  	// to use the built-in.
   970  #if defined(__i386__) || defined(__x86_64__)
   971  	asm volatile("cpuid"
   972  		: "=a" (dst[0]), "=b" (dst[1]), "=c" (dst[2]), "=d" (dst[3])
   973  		: "0" (ax));
   974  #else
   975  	dst[0] = dst[1] = dst[2] = dst[3] = 0;
   976  #endif
   977  }
   978  
   979  bool
   980  cansse2(void)
   981  {
   982  	int info[4];
   983  	
   984  	cpuid(info, 1);
   985  	return (info[3] & (1<<26)) != 0;	// SSE2
   986  }
   987  
   988  
   989  #endif // __WINDOWS__