summaryrefslogtreecommitdiff
path: root/deg.c
blob: 8a480e30812f2d7c0da886021a93876aad195503 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <u.h>
#include <libc.h>

typedef struct DMS DMS;
struct DMS
{
	vlong	d;	/* degrees (°) */
	vlong	m;	/* minutes (') */
	double	s;	/* seconds (") */
};

#pragma varargck type "D" DMS
int
Dfmt(Fmt *f)
{
	DMS dms;

	dms = va_arg(f->args, DMS);
	if(dms.d < 0){
		dms.m = -dms.m;
		dms.s = -dms.s;
	}
	return fmtprint(f, "%lld°%lld'%g\"", dms.d, dms.m, dms.s);
}

DMS
deg2dms(double deg)
{
	DMS dms;

	dms.d = deg;
	deg -= dms.d;
	dms.m = deg = deg*60;
	deg -= dms.m;
	dms.s = deg*60;
	return dms;
}

double
dms2deg(DMS dms)
{
	return dms.d + dms.m/60.0 + dms.s/3600.0;
}

void
usage(void)
{
	fprint(2, "usage: %s deg\n", argv0);
	exits("usage");
}

void
main(int argc, char *argv[])
{
	DMS dms;
	Rune r;
	char *s;
	double degs;

	fmtinstall('D', Dfmt);
	ARGBEGIN{
	default: usage();
	}ARGEND;
	if(argc != 1)
		usage();
	s = argv[0];
	degs = strtod(s, &s);
	if(*s != 0){
		memset(&dms, 0, sizeof(DMS));
		while(*s != 0){
			s += chartorune(&r, s);
			switch(r){
			case L'°':
				dms.d = degs;
				degs = strtod(s, &s);
				break;
			case '\'':
				dms.m = dms.d < 0? -degs: degs;
				degs = strtod(s, &s);
				break;
			case '\"':
				dms.s = dms.d < 0? -degs: degs;
				break;
			default:
				sysfatal("unknown format");
			}
		}
		degs = dms2deg(dms);
		print("%g°\n", degs);
	}else{
		dms = deg2dms(degs);
		print("%D\n", dms);
	}
	exits(0);
}