/*
 * see if a string can represent a (base10) integer
 */
static int __is_int(char *str, int strlen) {
	char *p;
	char *end = str + strlen;

	for(p = str; p<end; ++p) {
		if(*p == '.') { return 0; }
	}

	return 1;
}

/*
 * verify pid is an integer... or else "abc" becomes (int)(0)
 * note: if the scalar isn't in int-ready format, make it so and
 * do error checking to rule out strings like "abc", floats like
 * 1.32, and negative integers
 */
static int get_pid(SV* pid_sv) {
	STRLEN len;
	char *pidstr = SvPV(pid_sv, len);
	int pid;

	if(!SvIOKp(pid_sv)) {
		pidstr = SvPV(pid_sv, len);
		if(__is_int(pidstr, len)) {
			if(sscanf(pidstr, "%d", &pid) == 0) {
				croak("got non-number pid: '%s'", pidstr);
			} else {
				/* warn("converted %s to int: %d outside of perlapi", pidstr, pid); */
			}
		} else {
			croak("got non-integer pid: '%s'", pidstr);
		}
	} else {
		pid = SvIV(pid_sv);
	}
	if (pid < 0) {
		croak("got negative pid: '%s'", SvPV(pid_sv, len));
	}
	return pid;
}

/*
 * do whatever platform-specific goop is necessary to determine if
 * a single pid exists or not
 */
static int __pexists(int pid) {
#ifdef WIN32
	/*
	 * this is much faster than iterating over a process snapshot,
	 * and more closely mirrors the POSIX code, but it has a weirdness
	 * on NTish systems - namely if these exists a pid 4, pid's 5, 6,
	 * and 7 will also return true. something in the windows guts is
	 * chopping off the bottom two bits, see:
	 * http://blogs.msdn.com/oldnewthing/archive/2008/02/28/7925962.aspx
	 */
	HANDLE hProcess;

#ifdef win32_pids_mult4
	if(pid % 4) {
		warn("windows ignored the bottom 2 bits of the pid %d, beware!", pid);
	};
#endif

	hProcess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, pid );
	if(hProcess == NULL) { 
		return 0;
	} else {
		CloseHandle( hProcess );
		return 1;
	}
#else
	int ret;

	ret = kill(pid, 0);
	/*
	 * existent process w/ perms:  ret: 0
	 * existent process w/o perms: ret: -1, err: EPERM
	 * nonexistent process:        ret: -1, err: ESRCH
	 */
	if(ret == 0) {
		return 1;
	} else if(ret == -1) {
		if(errno == EPERM) {
			return 1;
		} else if(errno == ESRCH) {
			return 0;
		} else {
			croak("unknown errno: %d", errno);
		}
	} else {
		croak("kill returned something other than 0 or -1: %d", ret);
	}
#endif
	croak("internal error: we should never get here");

}

