shithub: riscv

ref: 4d69aacea023546a7150d92e147e531c38de822f
dir: /sys/src/cmd/aux/gps/util.c/

View raw version
#include <u.h>
#include <libc.h>
#include "dat.h"

Place nowhere = {
	Undef, Undef
};

static void
setlat(Place *p, double lat)
{
	p->lat = lat;
}

static void
setlon(Place *p, double lon)
{
	p->lon = lon;
}

static int
printlatlon(char *p, int n, double lat, char po, char ne)
{
	char c;
	double d;
	int deg, min, sec;

	if(lat > 0)
		c = po;
	else if(lat < 0){
		c = ne;
		lat = -lat;
	} else
		c = ' ';
	sec = 3600 * modf(lat, &d);
	deg = d;
	min = sec/60;
	sec = sec % 60;
	return snprint(p, n, "%#3.3d°%#2.2d′%#2.2d″%c", deg, min, sec, c);
}

int
placeconv(Fmt *fp)
{
	char str[256];
	int n;
	Place pl;

	pl = va_arg(fp->args, Place);
	n = 0;
	n += printlatlon(str+n, sizeof(str)-n, pl.lat, 'N', 'S');
	n += snprint(str+n, sizeof(str)-n, ", ");
	printlatlon(str+n, sizeof(str)-n, pl.lon, 'E', 'W');
	return fmtstrcpy(fp, str);
}

int
strtolatlon(char *p, char **ep, Place *pl)
{
	double latlon;
	int neg = 0;

	while(*p == '0') p++;
	latlon = strtod(p, &p);
	if(latlon < 0){
		latlon = -latlon;
		neg = 1;
	}
	if(*p == ':'){
		p++;
		while(*p == '0') p++;
		latlon += strtod(p, &p)/60.0;
		if(*p == ':'){
			p++;
			while(*p == '0') p++;
			latlon += strtod(p, &p)/3600.0;
		}
	}
	switch (*p++){
	case 'N':
	case 'n':
		if(neg) latlon = -latlon;
		if(pl->lat != Undef)
			return -1;
		setlat(pl, latlon);
		break;
	case 'S':
	case 's':
		if(!neg) latlon = -latlon;
		if(pl->lat != Undef)
			return -1;
		setlat(pl, latlon);
		break;
	case 'E':
	case 'e':
		if(neg) latlon = -latlon;
		if(pl->lon != Undef)
			return -1;
		setlon(pl, latlon);
		break;
	case 'W':
	case 'w':
		if(!neg) latlon = -latlon;
		if(pl->lon != Undef)
			return -1;
		setlon(pl, latlon);
		break;
	case '\0':
	case ' ':
	case '\t':
	case '\n':
		p--;
		if(neg) latlon = -latlon;
		if(pl->lat == Undef){
			setlat(pl, latlon);
		} else if(pl->lon == Undef){
			latlon = -latlon;
			setlon(pl, latlon);
		} else return -1;
		break;
	default:
		return -1;
	}
	if(ep)
		*ep = p;
	return 0;
}

Place
strtopos(char *p, char **ep)
{
	Place pl = nowhere;

	if(strtolatlon(p, &p, &pl) < 0)
		return nowhere;
	while(*p == ' ' || *p == '\t' || *p == '\n')
		p++;
	if(strtolatlon(p, &p, &pl) < 0)
		return nowhere;
	if(ep)
		*ep = p;
	return pl;
}

void
rtcset(long t)
{
	static int fd = -1;
	long r;
	int n;
	char buf[32];

	if(fd < 0 && (fd = open("#r/rtc", ORDWR)) < 0){
		fprint(2, "Can't open #r/rtc: %r\n");
		return;
	}
	n = read(fd, buf, sizeof buf - 1);
	if(n <= 0){
		fprint(2, "Can't read #r/rtc: %r\n");
		return;
	}
	buf[n] = '\0';
	r = strtol(buf, nil, 0);
	if(r <= 0){
		fprint(2, "ridiculous #r/rtc: %ld\n", r);
		return;
	}
	if(r - t > 1 || t - r > 0){
		seek(fd, 0, 0);
		fprint(fd, "%ld", t);
		fprint(2, "correcting #r/rtc: %ld → %ld\n", r, t);
	}
	seek(fd, 0, 0);
}