ref: 45c9730c403606806969a273b8032dd305cc83df
author: akw <akw@shithub>
date: Thu Mar 26 22:22:13 EDT 2026
initial import
--- /dev/null
+++ b/jawk
@@ -1,0 +1,8 @@
+#!/bin/rc
+jdefs = `''{json2awk}+awk -f <{cat <<‽}+BEGIN{+ $jdefs
+ $*
+}
+‽
--- /dev/null
+++ b/json2awk.c
@@ -1,0 +1,151 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <json.h>
+
+typedef struct Level Level;
+struct Level {+ int noquote;
+ char *name;
+ Level *next;
+ Level *prev;
+};
+
+Level *head = nil;
+Level *tail = nil;
+
+void
+lappend(int q, char *s)
+{+ Level *new;
+
+ if((new = mallocz(sizeof(Level), 1)) == nil)
+ sysfatal("mallocz: %r");+ new->noquote = !q;
+ new->name = s;
+ if(!head)
+ head = new;
+ if(tail)
+ tail->next = new;
+ new->prev = tail;
+ tail = new;
+}
+
+void
+lremove(void)
+{+ void *v;
+
+ v = tail;
+ tail = tail->prev;
+ free(v);
+ if(tail == nil)
+ head = nil;
+ else
+ tail->next = nil;
+}
+
+#pragma varargck type "L" Level*
+int
+Lfmt(Fmt *f)
+{+ Level *l;
+
+ l = va_arg(f->args, Level*);
+ while(l != nil){+ if(l->noquote){+ if(fmtprint(f, "%s", l->name) < 0)
+ return -1;
+ }else
+ if(fmtprint(f, "\"%s\"", l->name) < 0)
+ return -1;
+
+ if(l->next != nil && fmtprint(f, ", ") < 0)
+ return -1;
+ l = l->next;
+ }
+ return 0;
+}
+
+void
+json2awk(JSON *j)
+{+ JSONEl *e;
+ char *s;
+ int i;
+
+ switch(j->t){+ case JSONArray:
+ e = j->first;
+ for(i = 0; e; i++){+ s = smprint("%d", i);+ lappend(0, s);
+ json2awk(e->val);
+ lremove();
+ e = e->next;
+ free(s);
+ }
+ break;
+ case JSONObject:
+ e = j->first;
+ do{+ lappend(1, e->name);
+ json2awk(e->val);
+ lremove();
+ }while(e = e->next);
+ break;
+ case JSONBool:
+ print("json[%L] = %d;\n", head, (int)j->n);+ break;
+ case JSONNumber:
+ print("json[%L] = %g;\n", head, j->n);+ break;
+ case JSONString:
+ print("json[%L] = \"%s\";\n", head, j->s);+ break;
+ case JSONNull:
+ break;
+ }
+}
+
+void
+main(int argc, char **argv)
+{+ Level *l, *ln;
+ Biobuf *b;
+ JSON *J;
+ char *j;
+ int fd;
+
+ switch(argc){+ case 1:
+ fd = 0;
+ break;
+ case 2:
+ fd = open(argv[1], OREAD);
+ break;
+ default:
+ fprint(2, "usage: json2awk [file]");
+ exits("usage");+ }
+
+ /* read it all into j */
+ fmtinstall('L', Lfmt);+ b = Bfdopen(fd, OREAD);
+ j = Brdstr(b, '\0', '\0');
+ if((J = jsonparse(j)) == nil)
+ sysfatal("jsonparse: %r");+
+ json2awk(J);
+
+ jsonfree(J);
+ free(j);
+ free(b);
+ for(l = head; l != nil; l = ln){+ ln = l->next;
+ free(l);
+ }
+
+ exits(0);
+}
+
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,8 @@
+</$objtype/mkfile
+
+TARG=json2awk
+BIN=/$objtype/bin
+OFILES=json2awk.$O
+HFILES=
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/weather.rc
@@ -1,0 +1,49 @@
+#!/bin/rc
+
+fn formparams {+ urlp = $1'?'$2
+ shift 2
+ while(! ~ $#* 0){+ urlp = $urlp'&'$1
+ shift
+ }
+ echo $urlp
+}
+
+fn pull {+ purl = $1
+ shift
+ hget $purl | jawk $*
+}
+
+geourl = 'https://geocoding.geo.census.gov/geocoder/locations/address'
+street = '0000+REDACTED+AVE'
+zip = 99999
+
+geourl = `{formparams $geourl \+ 'street='$street \
+ 'zip='$zip \
+ 'format=json' \
+ 'benchmark=Public_AR_Current'
+}
+
+# get our coordinates
+xy = `{pull $geourl '+ print json["result", "addressMatches", 0, "coordinates", "x"]
+ print json["result", "addressMatches", 0, "coordinates", "y"]
+'}
+
+# get the forecast url for our location
+url = https://api.weather.gov/points/$xy(2)^,$xy(1)
+forecasturl = `{pull $url 'print json["properties", "forecast"]'}+
+# print the forecast
+pull $forecasturl '
+ for(i = 0;; i++){+ when = json["properties", "periods", i, "name"]
+ if(when == "")
+ break;
+ print when
+ print "\t" json["properties", "periods", i, "detailedForecast"]
+ }
+'
--
⑨