util  Check-in [70991b55c3]

Overview
Comment:refactor tenki
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 70991b55c336efe6d230977e2f952829c4ddccba4534d2a267ac2ec49031c023
User & Date: lexi on 2019-05-01 01:03:44
Other Links: manifest | tags
Context
2019-05-03
15:21
add vpn tool check-in: 75223838e1 user: lexi tags: trunk
2019-05-01
01:03
refactor tenki check-in: 70991b55c3 user: lexi tags: trunk
2019-04-30
23:26
add tenki check-in: ae8a97d783 user: lexi tags: trunk
Changes

Added tenki/make.sh version [f7f3655bf1].

            1  +#!/bin/bash
            2  +if test -e apikey; then
            3  +	cc -Ofast -Dds_apikey="\"$(cat apikey)\"" tenki.c -lssl -otenki
            4  +else
            5  +	echo "tenki requires an API key. get one from dark sky and put it in a file in this directory named 'apikey' before you try to build"
            6  +fi

Deleted tenki/makefile version [d561bb7339].

     1         -tenki: tenki.cc
     2         -	$(CC) -Ofast tenki.cc -o tenki -lssl

Added tenki/tenki.c version [b2cd504148].

            1  +/* [ʞ] tenki.c
            2  + *  ~ lexi hale <lexi@hale.su>
            3  + *  > ./make.sh
            4  + *  © affero general public license
            5  +
            6  + *  tenki  is a  client for  the Dark  Sky API.  it is  a
            7  + *  bail-early stream parser which  retrieves a fixed set
            8  + *  of keys (this set may  be easily changed in the code)
            9  + *  and prints them  as a formatted string  to stdout. it
           10  + *  was designed purely as a polybar plugin to display my
           11  + *  local  weather, but  it could  be just  as easily  be
           12  + *  reworked for many other purposes
           13  + *
           14  + *  you need to  get an api key from dark  sky before you
           15  + *  compile tenki, and place it in the file apikey - it's
           16  + *  segregated from the main code this way to allow it to
           17  + *  be excluded from version control.
           18  + *
           19  + *  the default language of  the results is Japanese; you
           20  + *  can change  this by  changing the macro  ds_lang from
           21  + *  "ja" to your language  code of choice. the ds_exclude
           22  + *  macro is used to minimize the bandwidth tenki uses by
           23  + *  instructing  the dark  sky server  not to  send those
           24  + *  fields back; if you want to access information in any
           25  + *  of  them, you  need to  remove them  from ds_exclude.
           26  + *  delete the #define entirely if you wish to access all
           27  + *  of the excluded fields.
           28  + *  
           29  + *  the  function main()  contains most  of the  code you
           30  + *  will  likely wish  to alter.  it contains  a variable
           31  + *  "paths" which is used to  specify which fields of the
           32  + *  returned json object you  wish the parser to extract.
           33  + *  each path is a "p-string of p-strings" - that is, its
           34  + *  first  character is  an integer  which specifies  the
           35  + *  depth of the path,  and each "directory" is specified
           36  + *  with a string prefixed  with the number of characters
           37  + *  in  it.  so  the  path "a/bc/def"  would  be  encoded
           38  + *  "\3\1a\2bc\3def" - \3 for  the three constituents "a"
           39  + *  "bc" and "def", \1 for the  strlen of "a", \2 for the
           40  + *  strlen  of "bc",  etc.  shoutout to  the C  standards
           41  + *  committee for forcing me to do this horrible thing.
           42  + *
           43  + *  in conclusion, i should have written this in scheme.
           44  + **/
           45  +
           46  +#define ds_lang    "ja"
           47  +#define ds_exclude "minutely,hourly,daily,alerts,flags"
           48  +
           49  +// posix includes
           50  +#include <stdlib.h>
           51  +#include <stddef.h>
           52  +#include <stdint.h>
           53  +#include <unistd.h>
           54  +
           55  +// libc includes
           56  +#include <stdio.h>
           57  +#include <string.h>
           58  +
           59  +// networking includes
           60  +#include <sys/socket.h>
           61  +#include <netinet/in.h>
           62  +#include <netdb.h>
           63  +#include <openssl/ssl.h>
           64  +
           65  +#ifndef ds_apikey
           66  +#	error missing api key; compile with make.sh
           67  +#   define ds_apikey "" // tidy up errors
           68  +#endif
           69  +
           70  +#ifdef ds_exclude
           71  +#	define _http "?exclude=" ds_exclude "&"
           72  +#else
           73  +#	define _http "?"
           74  +#endif
           75  +#define http _http "lang=" ds_lang " HTTP/1.1\r\nHost: api.darksky.net\r\n\r\n"
           76  +#define start "GET /forecast/" ds_apikey "/"
           77  +
           78  +#define min(x,y) (x>y?y:x)
           79  +#define len(x) (sizeof(x)/sizeof(*x))
           80  +
           81  +typedef enum bool { false, true } bool;
           82  +
           83  +SSL_CTX* sc;
           84  +bool head(size_t* len, char* txt, char** body) {
           85  +	char* hend = strstr(txt, "\r\n\r\n");
           86  +	if (hend == NULL) return false;
           87  +	#define ctlhead "\r\nContent-Length:"
           88  +	char* ctl = strstr(txt, ctlhead);
           89  +	if (ctl == NULL || ctl > hend) return false;
           90  +	ctl += len(ctlhead);
           91  +	*len = 0;
           92  +	while(*ctl != '\r') {
           93  +		if (*ctl >= '0' && *ctl <= '9') *len*=10,*len+=*ctl-'0';
           94  +		++ctl;
           95  +	}
           96  +	*len+=(hend-txt)+4;
           97  +	*body = hend+4;
           98  +	return true;
           99  +}
          100  +size_t get(char* resp, size_t max, const char* msg, size_t total, char** body){
          101  +
          102  +	int port = 443;
          103  +	const char* host = "api.darksky.net";
          104  +	//printf("req: %s\n", msg);	
          105  +	struct hostent* api;
          106  +	struct sockaddr_in api_addr;
          107  +	int sockfd, bytes;
          108  +	size_t sent, recd;
          109  +	
          110  +	sockfd = socket(AF_INET, SOCK_STREAM, 0);
          111  +	if (sockfd < 0) exit(2);
          112  +	SSL *con = SSL_new(sc);
          113  +	SSL_set_fd(con, sockfd);
          114  +
          115  +	api = gethostbyname(host);
          116  +	if (api == NULL) exit(3);
          117  +
          118  +	memset(&api_addr, 0, sizeof(api_addr));
          119  +	api_addr.sin_family = AF_INET;
          120  +	api_addr.sin_port = htons(port);
          121  +	memcpy(&api_addr.sin_addr.s_addr, api -> h_addr, api -> h_length);
          122  +
          123  +	if (connect(sockfd,(struct sockaddr*)&api_addr,sizeof(api_addr)))
          124  +		exit(4);
          125  +	int err = SSL_connect(con);
          126  +
          127  +
          128  +	sent = 0;
          129  +	do {
          130  +		bytes = SSL_write(con,msg+sent,total-sent);
          131  +		if (bytes < 0) exit (4);
          132  +		if (bytes == 0) break;
          133  +		++sent;
          134  +	} while (sent < total);
          135  +	recd = 0;
          136  +	size_t resplen = max;
          137  +	bool rhead = false;
          138  +	do {
          139  +		bytes = SSL_read(con,resp+recd,min(resplen-recd,15000));
          140  +		if (bytes < 0) exit (5);
          141  +		if (bytes == 0) break;
          142  +		if(!rhead)rhead=head(&resplen, resp, body);
          143  +		recd += bytes;
          144  +	} while (recd < resplen - 1);
          145  +
          146  +	close(sockfd);
          147  +	SSL_shutdown(con);
          148  +
          149  +	return recd;
          150  +}
          151  +size_t pos(char* msg, const char* lat, const char* lng) {
          152  +	char* cur = msg + len(start) - 1;
          153  +	size_t latl = strlen(lat);
          154  +	size_t longl = strlen(lng);
          155  +	strcpy(cur, lat); cur += latl;
          156  +	*cur++=','; 
          157  +	strcpy(cur, lng); cur += longl;
          158  +	strcpy(cur, http); cur += len(http);
          159  +	*cur--=0;
          160  +	return cur-msg;
          161  +}
          162  +bool estrc(size_t sz, const char* str1, const char* str2) {
          163  +	for(size_t i = 0;i<sz;++i) {
          164  +		if(*str1 == *str2) {
          165  +			++str1; ++str2;
          166  +		} else if (*str2 =='\\') {
          167  +			++str2;
          168  +			if(*str1 == *str2) {
          169  +				++str1; ++str2;
          170  +			} else return false;
          171  +		} else {
          172  +			return false;
          173  +		}
          174  +	}
          175  +	return true;
          176  +}
          177  +typedef struct pstr {
          178  +	size_t sz;
          179  +	const char* a;
          180  +} pstr;
          181  +typedef union jsv {
          182  +	float f;
          183  +	pstr s;
          184  +} jsv;
          185  +/* void printkey(const char* key) {
          186  +	size_t len = *key++;
          187  +	for (size_t i = 0; i<len; ++i) {
          188  +		printf("/%.*s",*key,key+1);
          189  +		key += *key + 1;
          190  +	};
          191  +	printf("\n");
          192  +} */
          193  +void pplt(const char* str, const char* const end, const char** keys, const char** const keyend, jsv* values) {
          194  +	// initialize parser state
          195  +	size_t depth = 0;
          196  +	const char* fld = NULL;
          197  +	const char* path[32];
          198  +	path[0] = NULL;
          199  +	
          200  +	while(*str++!='{'); //cheat
          201  +	init: {
          202  +		if (keys > keyend) return;
          203  +		if (str > end) return;
          204  +		/* print_path: {
          205  +			printf("current path: /");
          206  +			for (size_t i = 0; i < depth; ++i) {
          207  +				printf("%.*s/",strchr(path[i],'"')-path[i],path[i]);
          208  +			}
          209  +			printf("\n");
          210  +			printf("current key: ");
          211  +			printkey(*keys);
          212  +		} */
          213  +		parse_char: {
          214  +			switch(*str++) {
          215  +				case ' ': case '\t': case '\n':
          216  +					goto parse_char;
          217  +				case '"':
          218  +					path[depth] = str;
          219  +					goto path_find_quote_end;
          220  +				case '}':
          221  +					if (depth == 0) return;
          222  +					depth--;
          223  +					while(*str!=',') ++str; ++str;
          224  +					goto init;
          225  +				default:
          226  +					printf("found illegal char %c\n", *(str-1));
          227  +					exit(6);
          228  +			}
          229  +		}
          230  +		path_find_quote_end: {
          231  +			switch (*str++) {
          232  +				case '\\': ++str; goto path_find_quote_end;
          233  +				case '"': goto read_value;
          234  +				default: goto path_find_quote_end;
          235  +			}
          236  +		}
          237  +		read_value: {
          238  +			if (*str++!=':') {
          239  +				printf("illegal char\n");
          240  +				exit(6);
          241  +			}
          242  +			bool iskey;
          243  +			const char* key = *keys;
          244  +			jsv* value;
          245  +			if (depth + 1 != *key++) {
          246  +				iskey = false;
          247  +				goto comp;
          248  +			} else for (size_t i = 0; i <= depth; ++i) {
          249  +				if (estrc(*key, key+1, path[i])) {
          250  +					key += *key + 1;
          251  +				} else {
          252  +					iskey = false;
          253  +					goto comp;
          254  +				}
          255  +			}
          256  +			iskey = true;
          257  +			value = values;
          258  +			++keys; ++values;
          259  +			comp: if (*str == '{') {
          260  +				++depth; ++str;
          261  +				goto init;
          262  +			} else if (*str == '"') {
          263  +				goto copy_str_value;
          264  +			} else if (*str == '[') {
          265  +				goto skip_array;
          266  +			} else if ((*str >= '0' && *str <= '9') || *str=='-') {
          267  +				goto copy_int_value;
          268  +			} else {
          269  +				printf("illegal character found in value %c\n", *str);
          270  +				exit(6);
          271  +			}
          272  +
          273  +			copy_str_value: {
          274  +				fld = ++str;
          275  +				while (*++str != '"') if (*str == '\\') { ++str; continue; }
          276  +				if (iskey) {
          277  +					value -> s.sz = str - fld;
          278  +					value -> s.a = fld;
          279  +				}
          280  +				while (*++str != ',');
          281  +				++str; goto init;
          282  +			}
          283  +			skip_array: {
          284  +				size_t ard = 0;
          285  +				skip_loop: switch (*++str) {
          286  +					case '{': case '[': ++ard; goto skip_loop;
          287  +					case '"': goto skip_str;
          288  +					case '}': if (ard == 0) {
          289  +								  printf("bad json\n");
          290  +								  exit(7);
          291  +							  } else { --ard; goto skip_loop; }
          292  +					case ']': if (ard == 0) {
          293  +							if (*++str == ',') { ++str; goto init; }
          294  +							else goto init;
          295  +						} else { --ard; }
          296  +					default: goto skip_loop;
          297  +				}
          298  +				skip_str: while (*str != '"') if (*str == '\\') { str += 2; continue; } else ++str; goto skip_loop;
          299  +			}
          300  +			copy_int_value: {
          301  +				if (!iskey) {
          302  +					while(*str++!=',') if (str > end) return;
          303  +					goto init;
          304  +				}
          305  +				value -> f = 0;
          306  +				bool neg;
          307  +				if (*str == '-') { neg=true; ++str; } else neg=false;
          308  +				while(*str >= '0' && *str <= '9') {
          309  +					value -> f *= 10;
          310  +					value -> f += *str - '0';
          311  +					++str;
          312  +				}
          313  +				if(*str == '.') {
          314  +					float fac = 0.1;
          315  +					float val = 0;
          316  +					while(*++str >= '0' && *str <= '9') {
          317  +						val += (((float)(*str - '0')) * fac);
          318  +						fac *= 0.1;
          319  +					}
          320  +					value -> f += val;
          321  +				}
          322  +				if(neg) value -> f *= -1;
          323  +				if (*str == ',') {
          324  +					++str; goto init;
          325  +				} else {
          326  +					printf("illegal character %.*s\n",15,str);
          327  +					exit(6);
          328  +				}
          329  +			}
          330  +		}
          331  +	}
          332  +}
          333  +
          334  +int main(int argc, char** argv) {
          335  +	if (argc != 3) exit(1);
          336  +	SSL_load_error_strings();
          337  +	SSL_library_init();
          338  +	sc = SSL_CTX_new(SSLv23_client_method());
          339  +
          340  +	char msg[256] = start;
          341  +	char resp[32368];
          342  +	char* body;
          343  +
          344  +	// name the fields to extract from the json stream
          345  +	// note: MUST BE LISTED IN ORDER THEY APPEAR
          346  +	// TODO: performance worth lack of flexibility?
          347  +	const char* paths[] = {
          348  +		"\2\x9""currently\7summary",
          349  +		"\2\x9""currently\xfprecipIntensity",
          350  +		"\2\x9""currently\xbtemperature",
          351  +		"\2\x9""currently\x9windspeed",
          352  +	};
          353  +
          354  +	//copy the latitude and longitude into the request
          355  +	size_t msgsz = pos(msg, argv[1], argv[2]);
          356  +		 //msgsz = size of what we're going to transmit
          357  +
          358  +	//for (;;) {
          359  +		size_t rspsz = get(resp, sizeof(resp), msg, msgsz, &body);
          360  +		// if paths contains the keys, this contains the values
          361  +		jsv values[len(paths)]; 
          362  +		
          363  +		parse: {
          364  +			pplt(body, body + (rspsz - (resp - body)), paths, paths+len(paths), values);
          365  +			
          366  +			pstr summary = values[0].s;
          367  +			float pcpint = values[1].f,
          368  +				temp = values[2].f,
          369  +				windspd = values[3].f;
          370  +
          371  +			printf("%.1f°  %%{F#ff9bbb}%.*s\n",
          372  +					summary.sz,
          373  +					summary.a,
          374  +					temp);
          375  +		}
          376  +		// dark sky's API allows us to make 1000 free requests a day.
          377  +		// let's try not to get too near that.
          378  +		// hours in day 24 - minutes in day 24 * 60 = 1440
          379  +		// so once a minute is almost half again too many
          380  +		// 1440 / 2 = 720 leaving reasonable refresh time without
          381  +		// going too near the limit. so we aim for one update
          382  +		// every two minutes.
          383  +	//	sleep(60 * 2);
          384  +//	}
          385  +
          386  +	return 0;
          387  +}

Deleted tenki/tenki.cc version [eaa2ec3cc1].

     1         -#include <stdio.h>
     2         -#include <stdlib.h>
     3         -#include <unistd.h>
     4         -#include <string.h>
     5         -#include <sys/socket.h>
     6         -#include <netinet/in.h>
     7         -#include <netdb.h>
     8         -#include <stdint.h>
     9         -#include <openssl/ssl.h>
    10         -
    11         -#define ds_apikey "a6aa0337fafd8b8fcfafe84a403ed24f"
    12         -#define ds_lang "ja"
    13         -#define ds_exclude "minutely,hourly,daily,alerts,flags"
    14         -
    15         -#define req "GET /forecast/"
    16         -#define http "?exclude=" ds_exclude "&lang=" ds_lang " HTTP/1.1\r\nHost: api.darksky.net\r\n\r\n"
    17         -
    18         -#define len(x) (sizeof(x)/sizeof(*x))
    19         -#define start req ds_apikey "/"
    20         -#define min(x,y) (x>y?y:x)
    21         -
    22         -SSL_CTX* sc;
    23         -bool head(size_t* len, char* txt, char** body) {
    24         -	char* hend = strstr(txt, "\r\n\r\n");
    25         -	if (hend == nullptr) return false;
    26         -	#define ctlhead "\r\nContent-Length:"
    27         -	char* ctl = strstr(txt, ctlhead);
    28         -	if (ctl == nullptr or ctl > hend) return false;
    29         -	ctl += len(ctlhead);
    30         -	*len = 0;
    31         -	while(*ctl != '\r') {
    32         -		if (*ctl >= '0' and *ctl <= '9') *len*=10,*len+=*ctl-'0';
    33         -		++ctl;
    34         -	}
    35         -	*len+=(hend-txt)+4;
    36         -	*body = hend+4;
    37         -	return true;
    38         -}
    39         -size_t get(char* resp, size_t max, const char* msg, size_t total, char** body){
    40         -
    41         -	int port = 443;
    42         -	const char* host = "api.darksky.net";
    43         -	//printf("req: %s\n", msg);	
    44         -	struct hostent* api;
    45         -	struct sockaddr_in api_addr;
    46         -	int sockfd, bytes;
    47         -	size_t sent, recd;
    48         -	
    49         -	sockfd = socket(AF_INET, SOCK_STREAM, 0);
    50         -	if (sockfd < 0) exit(2);
    51         -	SSL *con = SSL_new(sc);
    52         -	SSL_set_fd(con, sockfd);
    53         -
    54         -	//printf("getting host\n");
    55         -	api = gethostbyname(host);
    56         -	if (api == nullptr) exit(3);
    57         -
    58         -	memset(&api_addr, 0, sizeof(api_addr));
    59         -	api_addr.sin_family = AF_INET;
    60         -	api_addr.sin_port = htons(port);
    61         -	memcpy(&api_addr.sin_addr.s_addr, api -> h_addr, api -> h_length);
    62         -
    63         -	//printf("connecting\n");
    64         -	if (connect(sockfd,(struct sockaddr*)&api_addr,sizeof(api_addr)))
    65         -		exit(4);
    66         -	int err = SSL_connect(con);
    67         -
    68         -
    69         -	sent = 0;
    70         -//	printf("writing\n");
    71         -	do {
    72         -	//	printf("writing byte %x\n",*(msg+sent));
    73         -		bytes = SSL_write(con,msg+sent,total-sent);
    74         -		if (bytes < 0) exit (4);
    75         -		if (bytes == 0) break;
    76         -		++sent;
    77         -	} while (sent < total);
    78         -//	printf("receiving\n");
    79         -	recd = 0;
    80         -	size_t resplen = max;
    81         -	bool rhead = false;
    82         -	do {
    83         -	//	printf("\n\nreading - addr %x; max %d\n",resp+recd,resplen-recd);
    84         -		bytes = SSL_read(con,resp+recd,min(resplen-recd,15000));
    85         -		if (bytes < 0) exit (5);
    86         -		if (bytes == 0) break;
    87         -		if(!rhead)rhead=head(&resplen, resp, body);
    88         -		// printf("got %d bytes: %s", bytes, resp+recd);
    89         -		recd += bytes;
    90         -	} while (recd < resplen - 1);
    91         -
    92         -	close(sockfd);
    93         -	SSL_shutdown(con);
    94         -
    95         -	return recd;
    96         -}
    97         -size_t pos(char* msg, const char* lat, const char* lng) {
    98         -	char* cur = msg + len(start) - 1;
    99         -	size_t latl = strlen(lat);
   100         -	size_t longl = strlen(lng);
   101         -	strcpy(cur, lat); cur += latl;
   102         -	*cur++=','; 
   103         -	strcpy(cur, lng); cur += longl;
   104         -	strcpy(cur, http); cur += len(http);
   105         -	*cur--=0;
   106         -	return cur-msg;
   107         -}
   108         -bool estrc(size_t sz, const char* str1, const char* str2) {
   109         -	for(size_t i = 0;i<sz;++i) {
   110         -		if(*str1 == *str2) {
   111         -			++str1; ++str2;
   112         -		} else if (*str2 =='\\') {
   113         -			++str2;
   114         -			if(*str1 == *str2) {
   115         -				++str1; ++str2;
   116         -			} else return false;
   117         -		} else {
   118         -			return false;
   119         -		}
   120         -	}
   121         -	return true;
   122         -}
   123         -struct pstr {
   124         -	size_t sz;
   125         -	const char* a;
   126         -};
   127         -union jsv {
   128         -	float f;
   129         -	pstr s;
   130         -};
   131         -/* void printkey(const char* key) {
   132         -	size_t len = *key++;
   133         -	for (size_t i = 0; i<len; ++i) {
   134         -		printf("/%.*s",*key,key+1);
   135         -		key += *key + 1;
   136         -	};
   137         -	printf("\n");
   138         -} */
   139         -void pplt(const char* str, const char* const end, const char** keys, const char** const keyend, jsv* values) {
   140         -	// initialize parser state
   141         -	size_t depth = 0;
   142         -	const char* fld = nullptr;
   143         -	const char* path[32];
   144         -	path[0] = nullptr;
   145         -	
   146         -	while(*str++!='{'); //cheat
   147         -	init: {
   148         -		if (keys > keyend) return;
   149         -		if (str > end) return;
   150         -		/* print_path: {
   151         -			printf("current path: /");
   152         -			for (size_t i = 0; i < depth; ++i) {
   153         -				printf("%.*s/",strchr(path[i],'"')-path[i],path[i]);
   154         -			}
   155         -			printf("\n");
   156         -			printf("current key: ");
   157         -			printkey(*keys);
   158         -		} */
   159         -		parse_char: {
   160         -			switch(*str++) {
   161         -				case ' ': case '\t': case '\n':
   162         -					goto parse_char;
   163         -				case '"':
   164         -					path[depth] = str;
   165         -					goto path_find_quote_end;
   166         -				case '}':
   167         -					if (depth == 0) return;
   168         -					depth--;
   169         -					while(*str!=',') ++str; ++str;
   170         -					goto init;
   171         -				default:
   172         -					printf("found illegal char %c\n", *(str-1));
   173         -					exit(6);
   174         -			}
   175         -		}
   176         -		path_find_quote_end: {
   177         -			switch (*str++) {
   178         -				case '\\': ++str; goto path_find_quote_end;
   179         -				case '"': goto read_value;
   180         -				default: goto path_find_quote_end;
   181         -			}
   182         -		}
   183         -		read_value: {
   184         -			if (*str++!=':') {
   185         -				printf("illegal char\n");
   186         -				exit(6);
   187         -			}
   188         -			bool iskey;
   189         -			const char* key = *keys;
   190         -			jsv* value;
   191         -			if (depth + 1 != *key++) {
   192         -				iskey = false;
   193         -				goto comp;
   194         -			} else for (size_t i = 0; i <= depth; ++i) {
   195         -				if (estrc(*key, key+1, path[i])) {
   196         -					key += *key + 1;
   197         -				} else {
   198         -					iskey = false;
   199         -					goto comp;
   200         -				}
   201         -			}
   202         -			iskey = true;
   203         -			value = values;
   204         -			++keys; ++values;
   205         -			comp: if (*str == '{') {
   206         -				++depth; ++str;
   207         -				goto init;
   208         -			} else if (*str == '"') {
   209         -				goto copy_str_value;
   210         -			} else if (*str == '[') {
   211         -				goto skip_array;
   212         -			} else if ((*str >= '0' and *str <= '9') or *str=='-') {
   213         -				goto copy_int_value;
   214         -			} else {
   215         -				printf("illegal character found in value %c\n", *str);
   216         -				exit(6);
   217         -			}
   218         -
   219         -			copy_str_value: {
   220         -				fld = ++str;
   221         -				while (*++str != '"') if (*str == '\\') { ++str; continue; }
   222         -				if (iskey) {
   223         -					value -> s.sz = str - fld;
   224         -					value -> s.a = fld;
   225         -				}
   226         -				while (*++str != ',');
   227         -				++str; goto init;
   228         -			}
   229         -			skip_array: {
   230         -				size_t ard = 0;
   231         -				skip_loop: switch (*++str) {
   232         -					case '{': case '[': ++ard; goto skip_loop;
   233         -					case '"': goto skip_str;
   234         -					case '}': if (ard == 0) {
   235         -								  printf("bad json\n");
   236         -								  exit(7);
   237         -							  } else { --ard; goto skip_loop; }
   238         -					case ']': if (ard == 0) {
   239         -							if (*++str == ',') { ++str; goto init; }
   240         -							else goto init;
   241         -						} else { --ard; }
   242         -					default: goto skip_loop;
   243         -				}
   244         -				skip_str: while (*str != '"') if (*str == '\\') { str += 2; continue; } else ++str; goto skip_loop;
   245         -			}
   246         -			copy_int_value: {
   247         -				if (!iskey) {
   248         -					while(*str++!=',') if (str > end) return;
   249         -					goto init;
   250         -				}
   251         -				value -> f = 0;
   252         -				bool neg;
   253         -				if (*str == '-') { neg=true; ++str; } else neg=false;
   254         -				while(*str >= '0' and *str <= '9') {
   255         -					value -> f *= 10;
   256         -					value -> f += *str - '0';
   257         -					++str;
   258         -				}
   259         -				if(*str == '.') {
   260         -					float fac = 0.1;
   261         -					float val = 0;
   262         -					while(*++str >= '0' and *str <= '9') {
   263         -						val += (((float)(*str - '0')) * fac);
   264         -						fac *= 0.1;
   265         -					}
   266         -					value -> f += val;
   267         -				}
   268         -				if(neg) value -> f *= -1;
   269         -				if (*str == ',') {
   270         -					++str; goto init;
   271         -				} else {
   272         -					printf("illegal character %.*s\n",15,str);
   273         -					exit(6);
   274         -				}
   275         -			}
   276         -		}
   277         -	}
   278         -}
   279         -int main(int argc, char** argv) {
   280         -	if (argc != 3) exit(1);
   281         -	SSL_load_error_strings();
   282         -	SSL_library_init();
   283         -	sc = SSL_CTX_new(SSLv23_client_method());
   284         -
   285         -	char msg[256] = start;
   286         -	char resp[32368];
   287         -	char* body;
   288         -
   289         -	// name the fields to extract from the json stream
   290         -	// note: MUST BE LISTED IN ORDER THEY APPEAR
   291         -	// paths are encoded as sequences of pstrings
   292         -	// initial value indicates depth of path
   293         -	// TODO: performance worth lack of flexibility?
   294         -	const char* paths[] = {
   295         -		"\2\x9""currently\7summary",
   296         -		"\2\x9""currently\xfprecipIntensity",
   297         -		"\2\x9""currently\xbtemperature",
   298         -		"\2\x9""currently\x9windspeed",
   299         -	};
   300         -
   301         -	size_t msgsz = pos(msg, argv[1], argv[2]);
   302         -		//msgsz = size of transmit
   303         -	//for (;;) {
   304         -		size_t rspsz = get(resp, sizeof(resp), msg, msgsz, &body);
   305         -		// if paths contains the keys, this contains the values
   306         -		jsv values[len(paths)]; 
   307         -		
   308         -		parse: {
   309         -			pplt(body, body + (rspsz - (resp - body)), paths, paths+len(paths), values);
   310         -			
   311         -			pstr summary = values[0].s;
   312         -			float pcpint = values[1].f,
   313         -				temp = values[2].f,
   314         -				windspd = values[3].f;
   315         -
   316         -			printf("%.1f°  %%{F#ff9bbb}%.*s\n",
   317         -					summary.sz,
   318         -					summary.a,
   319         -					temp);
   320         -		}
   321         -		// dark sky's API allows us to make 1000 free requests a day.
   322         -		// let's try not to get too near that.
   323         -		// hours in day 24 - minutes in day 24 * 60 = 1440
   324         -		// so once a minute is almost half again too many
   325         -		// 1440 / 2 = 720 leaving reasonable refresh time without
   326         -		// going too near the limit. so we aim for one update
   327         -		// every two minutes.
   328         -	//	sleep(60 * 2);
   329         -//	}
   330         -
   331         -	return 0;
   332         -}