jcs
/wikipedia
/amendments
/13
browser: Add live search drop-down list
Move request buffers into the http_request struct so each request
automatically gets them.
jcs made amendment 13 over 2 years ago
--- browser.c Wed Aug 24 20:50:52 2022
+++ browser.c Thu Aug 25 14:14:13 2022
@@ -35,6 +35,8 @@ void browser_mouse_down(struct focusable *focusable, E
bool browser_handle_menu(struct focusable *focusable, short menu,
short item);
void browser_atexit(struct focusable *focusable);
+void browser_live_search(struct browser *browser);
+void browser_hide_search_results(struct browser *browser);
Pattern fill_pattern;
@@ -44,57 +46,41 @@ browser_idle(struct focusable *focusable, EventRecord
struct browser *browser = (struct browser *)focusable->cookie;
size_t len;
- TEIdle(browser->input_te);
-
- if (browser->wpr)
- wikipedia_request_process(browser->wpr);
-
-#if 0
switch (browser->state) {
case BROWSER_STATE_IDLE:
- if (browser->need_refresh) {
- browser->need_refresh = false;
- browser->state = BROWSER_STATE_UPDATE_AMENDMENT_LIST;
+ TEIdle(browser->input_te);
+
+ if (browser->last_input_for_search != 0 &&
+ (Ticks - browser->last_input_for_search > 30)) {
+ browser->last_input_for_search = 0;
+ browser_live_search(browser);
}
break;
- case BROWSER_STATE_ADD_FILE:
- if (repo_add_file(browser->repo) == NULL)
+ case BROWSER_STATE_DO_SEARCH: {
+ TERec *te;
+ char *input;
+
+ HLock(browser->input_te);
+ te = *(browser->input_te);
+ HLock(te->hText);
+ (*(te->hText))[te->teLength] = '\0';
+ input = xstrdup(*(te->hText), "browser te input");
+ HUnlock(te->hText);
+ HUnlock(browser->input_te);
+ browser->wpr = wikipedia_fetch_article(browser, input);
+ xfree(&input);
+ browser->state = BROWSER_STATE_PROCESS_SEARCH;
+ break;
+ }
+ case BROWSER_STATE_PROCESS_SEARCH:
+ if (browser->wpr == NULL) {
browser->state = BROWSER_STATE_IDLE;
- else
- browser->state = BROWSER_STATE_UPDATE_FILE_LIST;
+ break;
+ }
+
+ wikipedia_request_process(browser->wpr);
break;
- case BROWSER_STATE_UPDATE_FILE_LIST:
- browser_add_files(browser);
- browser->state = BROWSER_STATE_IDLE;
- break;
- case BROWSER_STATE_UPDATE_AMENDMENT_LIST:
- browser_filter_amendments(browser);
- browser->state = BROWSER_STATE_IDLE;
- break;
- case BROWSER_STATE_OPEN_COMMITTER:
- committer_init(browser);
- browser->state = BROWSER_STATE_WAITING_FOR_COMMITTER;
- break;
- case BROWSER_STATE_WAITING_FOR_COMMITTER:
- break;
- case BROWSER_STATE_DISCARD_CHANGES:
- browser_discard_changes(browser);
- browser->state = BROWSER_STATE_IDLE;
- break;
- case BROWSER_STATE_EXPORT_PATCH:
- browser_export_patch(browser);
- browser->state = BROWSER_STATE_IDLE;
- break;
- case BROWSER_STATE_APPLY_PATCH:
- browser_apply_patch(browser);
- browser->state = BROWSER_STATE_IDLE;
- break;
- case BROWSER_STATE_EDIT_AMENDMENT:
- browser_edit_amendment(browser);
- browser->state = BROWSER_STATE_IDLE;
- break;
}
-#endif
}
struct browser *
@@ -107,7 +93,7 @@ browser_init(void)
Rect data_bounds = { 0, 0, 0, 1 }; /* tlbr */
Point cell_size = { 0, 0 };
Cell cell = { 0 };
- short n;
+ short n, width, height;
browser = xmalloczero(sizeof(struct browser), "browser");
browser->state = BROWSER_STATE_IDLE;
@@ -115,11 +101,14 @@ browser_init(void)
GetIndPattern(&fill_pattern, sysPatListID, 22);
/* main window */
- bounds.left = (PADDING / 2);
- bounds.top = screenBits.bounds.top + (GetMBarHeight() * 2) - 1 +
- (PADDING / 2);
- bounds.right = screenBits.bounds.right - 1 - (PADDING / 2);
- bounds.bottom = screenBits.bounds.bottom - 1 - (PADDING / 2);
+ width = screenBits.bounds.right - screenBits.bounds.left - PADDING;
+ if (width > 620)
+ width = 620;
+ height = screenBits.bounds.bottom - screenBits.bounds.top -
+ PADDING - (GetMBarHeight() * 2);
+ if (height > 340)
+ height = 340;
+ center_in_screen(width, height, true, &bounds);
snprintf(title, sizeof(title), "%s", PROGRAM_NAME);
CtoPstr(title);
@@ -129,6 +118,7 @@ browser_init(void)
err(1, "Can't create window");
SetPort(browser->win);
+ /* search input TE */
bounds.top = PADDING;
bounds.left = PADDING;
bounds.right = browser->win->portRect.right - PADDING;
@@ -141,7 +131,8 @@ browser_init(void)
TEAutoView(true, browser->input_te);
TEActivate(browser->input_te);
- bounds.top = bounds.bottom + PADDING;
+ /* main article TE */
+ bounds.top = (*(browser->input_te))->viewRect.bottom + PADDING;
bounds.left = PADDING;
bounds.right = browser->win->portRect.right - SCROLLBAR_WIDTH - PADDING;
bounds.bottom = browser->win->portRect.bottom - PADDING;
@@ -191,7 +182,7 @@ browser_close(struct focusable *focusable)
TEDispose(browser->te);
DisposeWindow(browser->win);
- free(browser);
+ xfree(&browser);
return true;
}
@@ -262,6 +253,14 @@ browser_update(struct focusable *focusable, EventRecor
InsetRect(&r, -1, -1);
FrameRect(&r);
+ if (browser->search_results != NULL) {
+ r = (*(browser->search_results))->rView;
+ InsetRect(&r, -1, -1);
+ FillRect(&r, white);
+ FrameRect(&r);
+ LUpdate(browser->win->visRgn, browser->search_results);
+ }
+
UpdtControl(browser->win, browser->win->visRgn);
browser_update_menu(browser);
@@ -273,13 +272,13 @@ browser_update(struct focusable *focusable, EventRecor
void
browser_mouse_down(struct focusable *focusable, EventRecord *event)
{
- Cell selected = { 0 }, now = { 0 };
+ struct browser *browser = (struct browser *)focusable->cookie;
+ char str[255];
+ Cell selected = { 0 };
Point p;
ControlHandle control;
Rect r;
- struct browser *browser = (struct browser *)focusable->cookie;
- short val, adj, page, was_selected, part, i, data_len;
- char *path;
+ short val, adj, page, i, len, part;
p = event->where;
GlobalToLocal(&p);
@@ -291,6 +290,25 @@ browser_mouse_down(struct focusable *focusable, EventR
return;
}
+ if (browser->search_results != NULL) {
+ r = (*(browser->search_results))->rView;
+ r.right += SCROLLBAR_WIDTH;
+ if (PtInRect(p, &r)) {
+ LClick(p, event->modifiers, browser->search_results);
+ selected.v = 0;
+ if (LGetSelect(true, &selected, browser->search_results)) {
+ len = sizeof(str);
+ LGetCell(&str, &len, selected, browser->search_results);
+ TESetText(str, len, browser->input_te);
+ InvalRect(&(*(browser->input_te))->viewRect);
+ browser_hide_search_results(browser);
+ browser->state = BROWSER_STATE_DO_SEARCH;
+ }
+
+ return;
+ }
+ }
+
r = (*(browser->te))->viewRect;
if (PtInRect(p, &r)) {
TEClick(p, ((event->modifiers & shiftKey) != 0), browser->te);
@@ -331,26 +349,96 @@ void
browser_key_down(struct focusable *focusable, EventRecord *event)
{
struct browser *browser = (struct browser *)(focusable->cookie);
- TERec *te;
- char *input, k;
-
+ char k;
+
k = (event->message & charCodeMask);
if (k == '\r') {
- HLock(browser->input_te);
- te = *(browser->input_te);
- HLock(te->hText);
- (*(te->hText))[te->teLength] = '\0';
- input = xstrdup(*(te->hText), "browser te input");
- HUnlock(te->hText);
- HUnlock(browser->input_te);
- browser->wpr = wikipedia_fetch_article(browser, input);
- free(input);
+ browser->state = BROWSER_STATE_DO_SEARCH;
} else {
TEKey(k, browser->input_te);
TESelView(browser->input_te);
+ browser->last_input_for_search = Ticks;
}
}
+void
+browser_live_search(struct browser *browser)
+{
+ TERec *te;
+ Rect bounds = { 0 };
+ Rect data_bounds = { 0, 0, 0, 1 }; /* tlbr */
+ char *input, **results, k;
+ size_t nresults, n;
+ Point cell_size = { 0, 0 };
+ Cell cell = { 0, 0 };
+ Rect r;
+
+ HLock(browser->input_te);
+ te = *(browser->input_te);
+
+ if (te->teLength == 0) {
+ HUnlock(browser->input_te);
+ browser_hide_search_results(browser);
+ return;
+ }
+
+ SetCursor(*(GetCursor(watchCursor)));
+
+ HLock(te->hText);
+ (*(te->hText))[te->teLength] = '\0';
+ input = xstrdup(*(te->hText), "browser te input");
+ HUnlock(te->hText);
+ HUnlock(browser->input_te);
+ nresults = wikipedia_fetch_search_results(browser, input, &results);
+ xfree(&input);
+
+ bounds.top = (*(browser->input_te))->viewRect.bottom + 1;
+ bounds.left = PADDING;
+ bounds.bottom = bounds.top + 70;
+ bounds.right = bounds.left + 200;
+
+ browser->search_results = LNew(&bounds, &data_bounds, cell_size, 0,
+ browser->win, false, false, false, true);
+ if (!browser->search_results)
+ panic("LNew failed");
+ (*(browser->search_results))->selFlags = lOnlyOne;
+ LAddColumn(1, 0, browser->search_results);
+
+ for (n = 0; n < nresults; n++) {
+ LAddRow(1, cell.v, browser->search_results);
+ LSetCell(results[n], strlen(results[n]), cell,
+ browser->search_results);
+ cell.v++;
+ xfree(&results[n]);
+ }
+
+ r = (*(browser->search_results))->rView;
+ FillRect(&r, white);
+ InsetRect(&r, -1, -1);
+ FrameRect(&r);
+ LDoDraw(true, browser->search_results);
+ LUpdate(browser->win->visRgn, browser->search_results);
+
+ SetCursor(&arrow);
+}
+
+void
+browser_hide_search_results(struct browser *browser)
+{
+ Rect r;
+
+ if (browser->search_results == NULL)
+ return;
+
+ r = (*(browser->search_results))->rView;
+ r.right += SCROLLBAR_WIDTH;
+ InsetRect(&r, -1, -1);
+ InvalRect(&r);
+
+ LDispose(browser->search_results);
+ browser->search_results = NULL;
+}
+
bool
browser_handle_menu(struct focusable *focusable, short menu, short item)
{
@@ -483,9 +571,9 @@ no_overflow:
progress(NULL);
TEStylInsert(str, len, scrp_rec_h, browser->te);
- TEPinScroll(0, -INT_MAX, browser->te);
- SetCtlValue(browser->te_scroller, GetCtlMax(browser->te_scroller));
+ SetCtlValue(browser->te_scroller, GetCtlMin(browser->te_scroller));
UpdateScrollbarForTE(browser->te_scroller, browser->te, false);
+ UpdtControl(browser->win, browser->win->visRgn);
HUnlock(browser->te);
last_style = style;
--- browser.h Wed Aug 24 17:30:16 2022
+++ browser.h Thu Aug 25 12:19:52 2022
@@ -21,7 +21,9 @@
#include "http.h"
enum {
- BROWSER_STATE_IDLE
+ BROWSER_STATE_IDLE,
+ BROWSER_STATE_DO_SEARCH,
+ BROWSER_STATE_PROCESS_SEARCH
};
#define STYLE_BOLD (1 << 0)
@@ -37,8 +39,10 @@ struct browser {
short state;
WindowPtr win;
TEHandle input_te;
+ unsigned long last_input_for_search;
TEHandle te;
ControlHandle te_scroller;
+ ListHandle search_results;
struct wikipedia_request *wpr;
};
--- http.c Wed Aug 24 13:19:56 2022
+++ http.c Thu Aug 25 11:06:19 2022
@@ -91,6 +91,42 @@ cleanup:
return url;
}
+char *
+url_encode(char *str)
+{
+ char *ret = NULL;
+ size_t len, n;
+ bool encode = false;
+ char a, b;
+
+encode:
+ for (n = 0, len = 0; str[n] != '\0'; n++) {
+ if ((str[n] >= 'A' && str[n] <= 'Z') ||
+ (str[n] >= 'a' && str[n] <= 'z') ||
+ (str[n] >= '0' && str[n] <= '9') ||
+ (str[n] == '-' || str[n] == '_' || str[n] == '.' ||
+ str[n] == '~')) {
+ if (ret)
+ ret[len] = str[n];
+ len++;
+ } else {
+ if (ret) {
+ sprintf(ret + len, "%%%02X", str[n]);
+ }
+ len += 3;
+ }
+ }
+
+ if (ret) {
+ ret[len] = '\0';
+ return ret;
+ }
+
+ ret = xmalloc(len + 1, "url_encode");
+ len = 0;
+ goto encode;
+}
+
struct http_request *
http_get(const char *surl)
{
@@ -201,6 +237,75 @@ http_req_read(struct http_request *req, char *data, si
return rlen;
}
+bool
+http_req_skip_header(struct http_request *req)
+{
+ size_t len, n;
+
+ for (;;) {
+ if (req->chunk_len > 3) {
+ /*
+ * Leave last 3 bytes of previous read in case \r\n\r\n happens
+ * across reads.
+ */
+ memmove(req->chunk, req->chunk + req->chunk_len - 3,
+ req->chunk_len - 3);
+ req->chunk_len = 3;
+ }
+ len = http_req_read(req, req->chunk + req->chunk_len,
+ sizeof(req->chunk) - req->chunk_len);
+ if (len < 0)
+ return false;
+ if (len == 0)
+ continue;
+ req->chunk_len += len;
+
+ for (n = 3; n < req->chunk_len; n++) {
+ if (req->chunk[n - 3] != '\r' || req->chunk[n - 2] != '\n' ||
+ req->chunk[n - 1] != '\r' || req->chunk[n] != '\n')
+ continue;
+
+ req->chunk_len -= n + 1;
+ memmove(req->chunk, req->chunk + n + 1, req->chunk_len);
+ req->chunk_off = 0;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+short
+http_req_chunk_peek(void *cookie)
+{
+ struct http_request *req = (struct http_request *)cookie;
+
+ if (req->chunk_len == 0 || (req->chunk_off + 1 > req->chunk_len)) {
+ req->chunk_len = http_req_read(req, req->chunk, sizeof(req->chunk));
+ req->chunk_off = 0;
+ }
+
+ if (req->chunk_len == 0 || (req->chunk_off + 1 > req->chunk_len))
+ return EOF;
+
+ return req->chunk[req->chunk_off];
+}
+
+short
+http_req_chunk_read(void *cookie)
+{
+ struct http_request *req = (struct http_request *)cookie;
+ short c;
+
+ c = http_req_chunk_peek(req);
+ if (c == EOF)
+ return c;
+
+ req->chunk_off++;
+
+ return c;
+}
+
void
http_req_free(void *reqptr)
{
@@ -213,9 +318,9 @@ http_req_free(void *reqptr)
_TCPRelease(&req->tcp_iopb, req->tcp_stream, nil, nil, false);
- if (req->message != NULL)
- xfree(&req->message);
- xfree(&req->tcp_buf);
- xfree(&req->url);
- xfree(reqptr);
+// if (req->message != NULL)
+// xfree(&req->message);
+// xfree(&req->tcp_buf);
+// xfree(&req->url);
+// xfree(reqptr);
}
--- http.h Fri Aug 19 14:08:56 2022
+++ http.h Wed Aug 24 22:17:37 2022
@@ -39,12 +39,20 @@ struct http_request {
TCPStatusPB tcp_status_pb;
char *message;
+
+ char chunk[1024];
+ size_t chunk_len;
+ size_t chunk_off;
};
struct url * url_parse(const char *str);
+char * url_encode(char *str);
struct http_request * http_get(const char *url);
ssize_t http_req_read(struct http_request *req, char *data, size_t len);
+bool http_req_skip_header(struct http_request *req);
+short http_req_chunk_peek(void *req);
+short http_req_chunk_read(void *req);
void http_req_free(void *reqptr);
#endif
--- wikipedia.c Wed Aug 24 17:56:32 2022
+++ wikipedia.c Thu Aug 25 14:13:25 2022
@@ -26,7 +26,10 @@
/* en.wikipedia.org doesn't support non-TLS :( */
#define WIKIPEDIA_HOST "wikipedia.jcs.org"
+/* {"query":{"normalized":[{"to": */
#define NORMALIZED_TITLE_CONTEXT "{\"query\":{\"normalized\":[{\"to\":"
+
+/* {"query":{"pages":[{"revisions":[{"slots":{"main":{"content": */
#define ARTICLE_TEXT_CONTEXT "{\"query\":{\"pages\":[{\"revisions\":[{\"slots\":{\"main\":{\"content\":"
short wikipedia_json_peek(void *cookie);
@@ -37,11 +40,10 @@ wikipedia_fetch_article(struct browser *browser, char
{
static char url[256];
struct wikipedia_request *wpr;
- struct http_request *req;
short state;
char *c;
- /* XXX */
+ /* "Macintosh Plus" -> "Macintosh_Plus" */
for (c = name; *c != '\0'; c++) {
if (*c == ' ')
*c = '_';
@@ -54,15 +56,71 @@ wikipedia_fetch_article(struct browser *browser, char
progress("Contacting Wikipedia...");
snprintf(url, sizeof(url), "http://%s/w/api.php?action=query&"
- "prop=revisions&rvslots=*&rvprop=content&formatversion=2&"
- "format=json&titles=%s", WIKIPEDIA_HOST, name);
+ "prop=revisions&rvslots=*&rvprop=content&"
+ "format=json&formatversion=2&titles=%s", WIKIPEDIA_HOST, name);
wpr->http_request = http_get(url);
- wpr->state = WP_STATE_FIND_BODY;
+ http_req_skip_header(wpr->http_request);
+ wpr->state = WP_STATE_PARSE_JSON;
wpr->normalized_title = xstrdup(name, "normalized_title");
return wpr;
}
+size_t
+wikipedia_fetch_search_results(struct browser *browser, char *query,
+ char ***results)
+{
+ static char url[256];
+ json_stream json;
+ struct http_request *req;
+ char *qencoded;
+ enum json_type type;
+ short strings = 0;
+ char **rets = NULL;
+ size_t nrets = 0;
+
+ qencoded = url_encode(query);
+
+ snprintf(url, sizeof(url), "http://%s/w/api.php?action=opensearch&"
+ "format=json&formatversion=2&namespace=0&limit=10&"
+ "search=%s", WIKIPEDIA_HOST, qencoded);
+ xfree(&qencoded);
+ req = http_get(url);
+ http_req_skip_header(req);
+
+ json_open_user(&json, http_req_chunk_read, http_req_chunk_peek, req);
+
+ for (;;) {
+ type = json_next(&json);
+
+ if (type == JSON_ERROR || type == JSON_DONE ||
+ type == JSON_ARRAY_END)
+ break;
+
+ if (type == JSON_STRING) {
+ strings++;
+
+ /* skip first, it'll be our query */
+ if (strings == 1)
+ continue;
+
+ nrets++;
+ rets = xreallocarray(rets, sizeof(Ptr), nrets);
+ rets[nrets - 1] = xstrdup(json_get_string(&json, NULL),
+ "search result");
+ } else if (type == JSON_ARRAY_END) {
+ break;
+ }
+ }
+
+ json_close(&json);
+ http_req_free(&req);
+
+ *results = rets;
+
+ return nrets;
+}
+
struct wikipedia_request *
wikipedia_read_cached_article(struct browser *browser, char *name)
{
@@ -103,7 +161,7 @@ wikipedia_read_cached_article(struct browser *browser,
FSClose(frefnum);
- wpr->state = WP_STATE_FIND_BODY;
+ wpr->state = WP_STATE_PARSE_JSON;
wpr->normalized_title = xstrdup(name, "normalized_title");
return wpr;
@@ -113,172 +171,138 @@ short
wikipedia_json_peek(void *cookie)
{
struct wikipedia_request *wpr = (struct wikipedia_request *)cookie;
+ struct http_request *req = wpr->http_request;
- if (wpr->buf_len == 0 || (wpr->buf_off + 1 > wpr->buf_len)) {
- wpr->buf_len = http_req_read(wpr->http_request, wpr->buf,
- sizeof(wpr->buf));
- wpr->buf_off = 0;
- }
-
- if (wpr->buf_len == 0 || (wpr->buf_off + 1 > wpr->buf_len))
- return EOF;
-
- return wpr->buf[wpr->buf_off];
+ return http_req_chunk_peek(req);
}
short
wikipedia_json_get(void *cookie)
{
struct wikipedia_request *wpr = (struct wikipedia_request *)cookie;
- short c;
+ struct http_request *req = wpr->http_request;
- c = wikipedia_json_peek(cookie);
- if (c == EOF)
- return c;
-
- wpr->buf_off++;
-
- return c;
+ return http_req_chunk_read(req);
}
void
wikipedia_request_process(struct wikipedia_request *wpr)
{
+ struct http_request *req = wpr->http_request;
size_t len, n;
switch (wpr->state) {
- case WP_STATE_FIND_BODY:
- if (wpr->buf_len > 3) {
- /*
- * Leave last 3 bytes of previous read in case \r\n\r\n happens
- * across reads.
- */
- memmove(wpr->buf, wpr->buf + wpr->buf_len - 3,
- wpr->buf_len - 3);
- wpr->buf_len = 3;
- }
- len = http_req_read(wpr->http_request, wpr->buf + wpr->buf_len,
- sizeof(wpr->buf) - wpr->buf_len);
- wpr->buf_len += len;
- if (!len)
- break;
-
- for (n = 3; n < wpr->buf_len; n++) {
- if (wpr->buf[n - 3] != '\r' || wpr->buf[n - 2] != '\n' ||
- wpr->buf[n - 1] != '\r' || wpr->buf[n] != '\n')
- continue;
-
- wpr->buf_off = n + 1;
- wpr->state = WP_STATE_PARSE_JSON;
- wpr->json_context_depth = 0;
-
- progress("Parsing JSON response...");
- json_open_user(&wpr->json, wikipedia_json_get,
- wikipedia_json_peek, wpr);
- break;
- }
-
- break;
case WP_STATE_PARSE_JSON: {
- static char context_str[PDJSON_STACK_MAX * 32];
+ char context_str[PDJSON_STACK_MAX * 32];
const char *str;
enum json_type type, context_type;
size_t tmp_depth;
- type = json_next(&wpr->json);
+ wpr->json_context_depth = 0;
+
+ progress("Parsing JSON response...");
+ json_open_user(&wpr->json, wikipedia_json_get, wikipedia_json_peek,
+ wpr);
+
+ for (;;) {
+ type = json_next(&wpr->json);
- if (type == JSON_ERROR || type == JSON_DONE) {
- if (type == JSON_ERROR) {
- char err[100];
- size_t len;
- len = snprintf(err, sizeof(err), "%s at line %ld pos %ld",
- json_get_error(&wpr->json), json_get_lineno(&wpr->json),
- json_get_position(&wpr->json));
- browser_print(wpr->browser, err, len, 0);
+ if (type == JSON_ERROR || type == JSON_DONE) {
+ if (type == JSON_ERROR) {
+ char err[100];
+ size_t len;
+ len = snprintf(err, sizeof(err),
+ "%s at line %ld pos %ld", json_get_error(&wpr->json),
+ json_get_lineno(&wpr->json),
+ json_get_position(&wpr->json));
+ browser_print(wpr->browser, err, len, 0);
+ }
+ json_close(&wpr->json);
+ if (wpr->http_request != NULL)
+ http_req_free(&wpr->http_request);
+ if (type == JSON_ERROR)
+ wpr->state = WP_STATE_DONE;
+ else {
+ wpr->state = WP_STATE_PARSE_WIKITEXT;
+ progress("Formatting article...");
+ }
+ break;
}
- json_close(&wpr->json);
- if (wpr->http_request != NULL)
- http_req_free(&wpr->http_request);
- if (type == JSON_ERROR)
- wpr->state = WP_STATE_DONE;
- else {
- wpr->state = WP_STATE_PARSE_WIKITEXT;
- progress("Formatting article...");
- }
- break;
- }
-
- context_type = json_get_context(&wpr->json, &tmp_depth);
+ context_type = json_get_context(&wpr->json, &tmp_depth);
+
#define wprjcd wpr->json_context[wpr->json_context_depth]
- switch (type) {
- case JSON_OBJECT:
- snprintf(wprjcd, sizeof(wprjcd), "{");
- wpr->json_context_depth++;
- break;
- case JSON_OBJECT_END:
- snprintf(wprjcd, sizeof(wprjcd), "}");
- wpr->json_context_depth--;
- break;
- case JSON_ARRAY:
- snprintf(wprjcd, sizeof(wprjcd), "[");
- wpr->json_context_depth++;
- break;
- case JSON_ARRAY_END:
- snprintf(wprjcd, sizeof(wprjcd), "]");
- wpr->json_context_depth--;
- break;
- case JSON_STRING:
- snprintf(wprjcd, sizeof(wprjcd), "\"%s\"",
- json_get_string(&wpr->json, NULL));
- break;
- case JSON_NUMBER:
- snprintf(wprjcd, sizeof(wprjcd), "%s",
- json_get_string(&wpr->json, NULL));
- break;
- case JSON_TRUE:
- snprintf(wprjcd, sizeof(wprjcd), "true");
- break;
- case JSON_FALSE:
- snprintf(wprjcd, sizeof(wprjcd), "false");
- break;
- case JSON_NULL:
- snprintf(wprjcd, sizeof(wprjcd), "null");
- break;
- }
-
- if (tmp_depth > 0 && (tmp_depth % 2) != 0)
- strlcat(wprjcd, ":", sizeof(wprjcd));
-
- if (type != JSON_STRING)
- goto next_context;
+ switch (type) {
+ case JSON_OBJECT:
+ snprintf(wprjcd, sizeof(wprjcd), "{");
+ wpr->json_context_depth++;
+ break;
+ case JSON_OBJECT_END:
+ snprintf(wprjcd, sizeof(wprjcd), "}");
+ wpr->json_context_depth--;
+ break;
+ case JSON_ARRAY:
+ snprintf(wprjcd, sizeof(wprjcd), "[");
+ wpr->json_context_depth++;
+ break;
+ case JSON_ARRAY_END:
+ snprintf(wprjcd, sizeof(wprjcd), "]");
+ wpr->json_context_depth--;
+ break;
+ case JSON_STRING:
+ snprintf(wprjcd, sizeof(wprjcd), "\"%s\"",
+ json_get_string(&wpr->json, NULL));
+ break;
+ case JSON_NUMBER:
+ snprintf(wprjcd, sizeof(wprjcd), "%s",
+ json_get_string(&wpr->json, NULL));
+ break;
+ case JSON_TRUE:
+ snprintf(wprjcd, sizeof(wprjcd), "true");
+ break;
+ case JSON_FALSE:
+ snprintf(wprjcd, sizeof(wprjcd), "false");
+ break;
+ case JSON_NULL:
+ snprintf(wprjcd, sizeof(wprjcd), "null");
+ break;
+ }
- context_str[0] = '\0';
- for (n = 0; n < wpr->json_context_depth; n++)
- strlcat(context_str, wpr->json_context[n], sizeof(context_str));
+ if (tmp_depth > 0 && (tmp_depth % 2) != 0)
+ strlcat(wprjcd, ":", sizeof(wprjcd));
+
+ if (type != JSON_STRING)
+ goto next_context;
+
+ context_str[0] = '\0';
+ for (n = 0; n < wpr->json_context_depth; n++)
+ strlcat(context_str, wpr->json_context[n],
+ sizeof(context_str));
- if (strcmp(context_str, NORMALIZED_TITLE_CONTEXT) == 0) {
- xfree(&wpr->normalized_title);
- wpr->normalized_title =
- xstrdup(json_get_string(&wpr->json, NULL), "normalized_title");
- } else if (strcmp(context_str, ARTICLE_TEXT_CONTEXT) == 0) {
- str = json_get_string(&wpr->json, &wpr->article_len);
- wpr->article = xmalloc(wpr->article_len, "article");
- for (n = 0; n < wpr->article_len; n++) {
- if (str[n] == '\n')
- wpr->article[n] = '\r';
- else
- wpr->article[n] = str[n];
+ if (strcmp(context_str, NORMALIZED_TITLE_CONTEXT) == 0) {
+ xfree(&wpr->normalized_title);
+ wpr->normalized_title =
+ xstrdup(json_get_string(&wpr->json, NULL),
+ "normalized_title");
+ } else if (strcmp(context_str, ARTICLE_TEXT_CONTEXT) == 0) {
+ str = json_get_string(&wpr->json, &wpr->article_len);
+ wpr->article = xmalloc(wpr->article_len, "article");
+ for (n = 0; n < wpr->article_len; n++) {
+ if (str[n] == '\n')
+ wpr->article[n] = '\r';
+ else
+ wpr->article[n] = str[n];
+ }
}
- }
next_context:
- if (context_type == JSON_OBJECT && tmp_depth > 0) {
- if (tmp_depth % 2 == 0)
- wpr->json_context_depth--;
- else
- wpr->json_context_depth++;
+ if (context_type == JSON_OBJECT && tmp_depth > 0) {
+ if (tmp_depth % 2 == 0)
+ wpr->json_context_depth--;
+ else
+ wpr->json_context_depth++;
+ }
}
break;
}
--- wikipedia.h Wed Aug 24 17:20:19 2022
+++ wikipedia.h Thu Aug 25 08:50:29 2022
@@ -42,7 +42,6 @@ extern MenuHandle file_menu, edit_menu;
void menu_defaults(void);
enum {
- WP_STATE_FIND_BODY,
WP_STATE_PARSE_JSON,
WP_STATE_PARSE_WIKITEXT,
WP_STATE_DONE
@@ -53,9 +52,6 @@ struct wikipedia_request {
struct browser *browser;
struct http_request *http_request;
char *normalized_title;
- char buf[1024];
- size_t buf_len;
- size_t buf_off;
json_stream json;
char *article;
size_t article_len;
@@ -65,6 +61,8 @@ struct wikipedia_request {
struct wikipedia_request * wikipedia_fetch_article(struct browser *,
char *);
+size_t wikipedia_fetch_search_results(struct browser *browser, char *query,
+ char ***results);
struct wikipedia_request * wikipedia_read_cached_article(struct browser *browser,
char *name);
void wikipedia_request_process(struct wikipedia_request *wpr);