AmendHub

Download:

jcs

/

detritus

/

amendments

/

29

*: Various tweaks all over the place


jcs made amendment 29 about 1 year ago
--- browser.c Wed Nov 6 22:33:34 2024 +++ browser.c Sat Nov 9 11:34:53 2024 @@ -35,11 +35,13 @@ static Pattern fill_pattern; extern struct uri_handler finger_handler; extern struct uri_handler gemini_handler; extern struct uri_handler gopher_handler; +extern struct uri_handler http_handler; struct uri_handler * uri_handlers[] = { &finger_handler, &gemini_handler, &gopher_handler, + &http_handler, }; bool browser_close(struct focusable *focusable); @@ -82,7 +84,7 @@ browser_idle(struct focusable *focusable, EventRecord if (page->fetch_cookie != NULL || page->download_frefnum) { ret = handler->fetch(page); - /* handle may have grown during fetch */ + /* handle may have grown/moved during fetch */ HLock(browser->loading_page); page = *(browser->loading_page); handler = page->handler; @@ -254,6 +256,7 @@ browser_close(struct focusable *focusable) HLock(fpage); tpage = (*fpage)->fwd_page; (*fpage)->handler->cleanup(*fpage); + /* re-lock */ HLock(fpage); xfree(&(*fpage)->uri); DisposeHandle(fpage); @@ -265,6 +268,7 @@ browser_close(struct focusable *focusable) HLock(bpage); tpage = (*bpage)->back_page; (*bpage)->handler->cleanup(*bpage); + /* re-lock */ HLock(bpage); xfree(&(*bpage)->uri); DisposeHandle(bpage); @@ -273,6 +277,7 @@ browser_close(struct focusable *focusable) HLock(pageh); (*pageh)->handler->cleanup(*pageh); + /* re-lock */ HLock(pageh); xfree(&(*pageh)->uri); DisposeHandle(pageh); @@ -296,7 +301,7 @@ browser_finished_loading(struct browser *browser) { struct URI *redir; size_t size; - bool download = false; + bool download = false, committed; if ((*(browser->loading_page))->redir_to) { browser_follow_redir(browser); @@ -305,17 +310,22 @@ browser_finished_loading(struct browser *browser) if ((*(browser->loading_page))->download_frefnum) { FSClose((*(browser->loading_page))->download_frefnum); - browser_statusf(browser, "Finished downloading %ld bytes", + browser_statusf(browser, "Downloaded (%ld bytes)", (*(browser->loading_page))->download_len); download = true; } + committed = (browser->loading_page == browser->current_page); browser_stop_loading_page(browser); browser->redirs = 0; if (download) return; + if (browser->current_page == NULL) + /* browser_commit_to_loading_page never called */ + Debugger(); + /* release some memory if we can */ if ((*(browser->current_page))->content_size > (*(browser->current_page))->content_len) { @@ -323,9 +333,12 @@ browser_finished_loading(struct browser *browser) (*(browser->current_page))->content_size = size; HUnlock(browser->current_page); SetHandleSize(browser->current_page, sizeof(struct page) + size); + HLock(browser->current_page); } - browser_statusf(browser, "Finished loading %ld bytes", - (*(browser->current_page))->content_len); + + if (committed) + browser_statusf(browser, "Done (%ld bytes)", + (*(browser->current_page))->content_len); } void @@ -337,16 +350,16 @@ browser_stop_loading_page(struct browser *browser) if (!browser->loading_page) return; - HLock(browser->loading_page); page = *(browser->loading_page); page->handler->cleanup(page); - HUnlock(browser->loading_page); if ((*(browser->loading_page))->download_frefnum) FSClose((*(browser->loading_page))->download_frefnum); - + /* only dispose if uncommitted */ - if (browser->current_page != browser->loading_page) { + if (browser->current_page == browser->loading_page) + HUnlock(browser->loading_page); + else { xfree(&(*(browser->loading_page))->uri); DisposeHandle(browser->loading_page); } @@ -365,9 +378,7 @@ browser_follow_redir(struct browser *browser) if (!browser->loading_page) return; - HLock(browser->loading_page); redir = (*(browser->loading_page))->redir_to; - HUnlock(browser->loading_page); browser_stop_loading_page(browser); @@ -667,7 +678,11 @@ browser_go(struct browser *browser, short dir) warn("Out of memory"); return; } + HLock(browser->uri_te); + HLock((*(browser->uri_te))->hText); memcpy(uristr, *((*(browser->uri_te))->hText), len); + HUnlock((*(browser->uri_te))->hText); + HUnlock(browser->uri_te); uristr[len] = '\0'; browser_create_page(browser, uristr); @@ -692,7 +707,13 @@ browser_go(struct browser *browser, short dir) HUnlock(opage); browser->loading_page = NULL; browser_update_buttons(browser); + return; } + + (*opage)->content_pos = 0; + browser_commit_to_loading_page(browser); + + HUnlock(opage); } } @@ -781,11 +802,12 @@ browser_draw_status(struct browser *browser) } size_t -browser_print(struct browser *browser, const char *str, size_t len) +browser_print(struct browser *browser, const char *str, size_t len, + bool newline) { struct TVStyle style; struct browser_link *link; - size_t n; + size_t n, nlines; style.font = BROWSER_FONT; style.size = BROWSER_FONT_SIZE; @@ -811,23 +833,28 @@ browser_print(struct browser *browser, const char *str else if (browser->style & STYLE_H3) style.size += 2; - if (str[len - 1] == '\r' && - (browser->style & (STYLE_H1 | STYLE_H2 | STYLE_H3))) { - /* print newlines in a small size */ - TVAppend(browser->output_tv, &style, (char *)str, len - 1); - style.font = BROWSER_FONT; - style.size = BROWSER_FONT_SIZE; - style.style = 0; - TVAppend(browser->output_tv, &style, "\r", 1); - } else - TVAppend(browser->output_tv, &style, (char *)str, len); + nlines = (*(browser->output_tv))->nlines; + + (newline ? TVAppendLine : TVAppend)(browser->output_tv, &style, + (char *)str, len); + if ((*(browser->output_tv))->nlines != nlines) + TVUpdateScrollbar(browser->output_tv, browser->output_tv_scroller); + return len; } +void +browser_recalc_scrollbar(struct browser *browser) +{ + TVCalcLines(browser->output_tv); + TVUpdate(browser->output_tv); + TVUpdateScrollbar(browser->output_tv, browser->output_tv_scroller); +} + size_t browser_print_link(struct browser *browser, const char *uri, size_t uri_len, - const char *title, size_t title_len) + const char *title, size_t title_len, bool newline) { struct TVStyle style; struct browser_link *link; @@ -863,7 +890,7 @@ browser_print_link(struct browser *browser, const char browser->last_link = link; browser->style |= STYLE_LINK; - browser_print(browser, link->title, link->len); + browser_print(browser, link->title, link->len, newline); browser->style &= ~(STYLE_LINK); return link->len; @@ -883,13 +910,14 @@ browser_commit_to_loading_page(struct browser *browser TESetText((*(browser->loading_page))->uri->str, strlen((*(browser->loading_page))->uri->str), browser->uri_te); TESetSelect(SHRT_MAX, SHRT_MAX, browser->uri_te); - + r = (*(browser->uri_te))->viewRect; TEUpdate(&r, browser->uri_te); - TVAutoCalc(browser->output_tv, true); TVClear(browser->output_tv); TVUpdateScrollbar(browser->output_tv, browser->output_tv_scroller); + TVAutoCalc(browser->output_tv, true); + browser->style = STYLE_NONE; if (browser->current_page) { fpage = (*(browser->current_page))->fwd_page; @@ -934,9 +962,11 @@ browser_start_download(struct browser *browser, char * CtoPstr(buf); SFPutFile(centered_sfput_dialog(), buf, pfilename, NULL, &reply); - if (!reply.good) + if (!reply.good) { + browser_statusf(browser, "Download canceled"); return false; - + } + error = Create(reply.fName, reply.vRefNum, '????', '????'); if (error && error != dupFNErr) { warn("Failed to create file %s: %d", PtoCstr(reply.fName), error); @@ -971,11 +1001,9 @@ browser_grow_page_content(struct page *page, size_t le return NULL; } - HLock(pageh); size = (*pageh)->content_size + MAX(len, PAGE_CONTENT_CHUNK_SIZE); - HUnlock(pageh); - gsize = sizeof(struct page) + size; + HUnlock(pageh); SetHandleSize(pageh, gsize); if (MemError() != 0) { warn("Out of memory growing page to %ld bytes", gsize); --- browser.h Wed Nov 6 22:31:48 2024 +++ browser.h Thu Nov 7 16:55:32 2024 @@ -58,9 +58,10 @@ struct page { size_t content_pos; struct uri_handler *handler; void *fetch_cookie; - char type[32]; - short state; short parse_state; + size_t server_content_len; + short server_status; + char content_type[32]; struct URI *redir_to; short download_frefnum; size_t download_len; @@ -110,8 +111,10 @@ struct uri_handler { struct browser * browser_init(void); size_t browser_statusf(struct browser *browser, const char *format, ...); size_t browser_print_link(struct browser *browser, const char *url, - size_t url_len, const char *title, size_t title_len); -size_t browser_print(struct browser *browser, const char *str, size_t len); + size_t url_len, const char *title, size_t title_len, bool newline); +size_t browser_print(struct browser *browser, const char *str, size_t len, + bool newline); +void browser_recalc_scrollbar(struct browser *browser); struct page * browser_grow_page_content(struct page *page, size_t len); void browser_go_uri(struct browser *browser, char *uristr); void browser_commit_to_loading_page(struct browser *browser); --- finger.c Wed Nov 6 22:07:25 2024 +++ finger.c Sat Nov 9 11:38:24 2024 @@ -54,12 +54,9 @@ finger_init_request(struct page *page) { struct finger_request *finger = NULL; - if (page->content_len) { - /* already fetched, nothing to do here but reset */ - page->content_pos = 0; - browser_commit_to_loading_page(page->browser); + if (page->content_len) + /* already fetched */ return true; - } finger = xmalloczero(sizeof(struct finger_request)); if (finger == NULL) { @@ -142,7 +139,7 @@ finger_fetch(struct page *page) return false; page->content_len += len; - browser_statusf(page->browser, "Read %ld bytes", page->content_len); + browser_statusf(page->browser, "%ld bytes", page->content_len); return true; } @@ -150,13 +147,12 @@ finger_fetch(struct page *page) bool finger_process(struct page *page) { - long n, plines = 0; + long n; bool ret = true; if (page->content_pos == page->content_len) return (page->fetch_cookie != NULL); - TVAutoCalc(page->browser->output_tv, false); page->browser->style = STYLE_PRE; /* text file, convert newlines and display */ @@ -164,46 +160,30 @@ finger_process(struct page *page) if (page->content[n] == '\r') { browser_print(page->browser, page->content + page->content_pos, - n - page->content_pos + 1); + n - page->content_pos + 1, false); page->content_pos = n + 1; if (page->content[n + 1] == '\n') { page->content_pos++; n++; } - plines++; } else if (page->content[n] == '\n') { /* lone \n */ if (n > page->content_pos) browser_print(page->browser, page->content + page->content_pos, - n - page->content_pos); - browser_print(page->browser, "\r", 1); + n - page->content_pos, true); page->content_pos = n + 1; - plines++; } - - if (plines == 25) { - TVCalcLines(page->browser->output_tv); - TVUpdate(page->browser->output_tv); - TVUpdateScrollbar(page->browser->output_tv, - page->browser->output_tv_scroller); - plines = 0; - } } if (page->fetch_cookie == NULL && page->content_pos < page->content_len) { /* no request to fetch more content, finish */ browser_print(page->browser, page->content + page->content_pos, - page->content_len - page->content_pos); + page->content_len - page->content_pos, false); page->content_pos = page->content_len; ret = false; } - - TVCalcLines(page->browser->output_tv); - TVUpdate(page->browser->output_tv); - TVUpdateScrollbar(page->browser->output_tv, - page->browser->output_tv_scroller); return ret; } --- gemini.c Wed Nov 6 22:07:32 2024 +++ gemini.c Fri Nov 8 08:56:25 2024 @@ -24,7 +24,7 @@ enum { PARSE_STATE_HEADER, - PARSE_STATE_GEMTEXT, + PARSE_STATE_BODY, PARSE_STATE_DOWNLOAD }; @@ -33,7 +33,6 @@ struct gemini_request { char message[URI_MAX_STR_LEN + 1]; size_t message_len; - short state; }; struct URI * gemini_parse_uri(char *uristr); @@ -64,9 +63,8 @@ gemini_init_request(struct page *page) struct gemini_request *gemini = NULL; if (page->content_len) { - /* already fetched, nothing to do here but reset */ - page->content_pos = 0; - page->parse_state = PARSE_STATE_HEADER; + /* already fetched */ + page->parse_state = PARSE_STATE_BODY; return true; } @@ -113,22 +111,20 @@ gemini_fetch_tls_write_callback(struct tls_request *re size_t *len) { struct gemini_request *gemini; - page_handle pageh; struct page *page; + page_handle pageh; size_t tlen; - if (cookie == NULL) - return false; - pageh = (page_handle)cookie; - HLock(pageh); + if (pageh == NULL) + return false; page = *pageh; - gemini = (struct gemini_request *)page->fetch_cookie; + if (page == NULL) + return false; - if (page == NULL) { - HUnlock(pageh); + gemini = (struct gemini_request *)page->fetch_cookie; + if (gemini == NULL) return false; - } if (wrote) { if (*len == gemini->message_len) { @@ -145,8 +141,6 @@ gemini_fetch_tls_write_callback(struct tls_request *re *len = tlen; } - HUnlock(pageh); - return true; } @@ -157,29 +151,36 @@ gemini_fetch_tls_read_callback(struct tls_request *req page_handle pageh; struct page *page; size_t tlen; + short err; - if (cookie == NULL) - return false; - pageh = (page_handle)cookie; - HLock(pageh); + if (pageh == NULL) + return false; page = *pageh; - - if (page == NULL) { - HUnlock(pageh); + if (page == NULL) return false; - } - if (page->content_len + len >= page->content_size) { - page = browser_grow_page_content(page, len); - if (page == NULL) + if (page->parse_state == PARSE_STATE_DOWNLOAD) { + tlen = len; + err = FSWrite(page->download_frefnum, &tlen, buf); + if (err || tlen != len) { + warn("Failed to write %ld bytes: %d", len, err); return false; + } + + page->download_len += tlen; + browser_statusf(page->browser, "%ld bytes", page->download_len); + } else { + if (page->content_len + len >= page->content_size) { + page = browser_grow_page_content(page, len); + if (page == NULL) + return false; + } + + memcpy(page->content + page->content_len, buf, len); + page->content_len += len; + browser_statusf(page->browser, "%ld bytes", page->content_len); } - - memcpy(page->content + page->content_len, buf, len); - page->content_len += len; - browser_statusf(browser, "Read %ld bytes", page->content_len); - HUnlock(pageh); return true; } @@ -202,8 +203,6 @@ gemini_fetch(struct page *page) gemini_fetch_tls_read_callback, pageh, gemini_fetch_tls_write_callback, pageh); - HUnlock(pageh); - return ret; } @@ -212,21 +211,19 @@ gemini_process(struct page *page) { page_handle pageh; size_t n, trail, skip, len; - char c; - bool newline, ret; + ssize_t tlen, link_len, title_len, j; + char *link, *title, *tcontent; + struct URI *newuri; + short err; + char c, *filename; + bool newline, gemtext; pageh = (page_handle)RecoverHandle(page); if (page->content_pos == page->content_len) return (page->fetch_cookie != NULL); -handle_state: - ret = true; - - switch (page->parse_state) { - case PARSE_STATE_HEADER: { - short status; - + if (page->parse_state == PARSE_STATE_HEADER) { for (n = page->content_pos; n < page->content_len; n++) { c = page->content[n]; @@ -239,243 +236,262 @@ handle_state: "Header parsing failed, disconnecting")); return false; } - - if (strncmp(page->type, "text/gemini", 10) == 0) { - page->parse_state = PARSE_STATE_GEMTEXT; + + /* ignore any "; charset" after type */ + if (strncasecmp(page->content_type, "text/gemini", 11) == 0 || + strncasecmp(page->content_type, "text/plain", 10) == 0) { + page->parse_state = PARSE_STATE_BODY; browser_commit_to_loading_page(page->browser); - HLock(pageh); - page = *pageh; - } else + } else { page->parse_state = PARSE_STATE_DOWNLOAD; + + filename = strrchr(page->uri->path, '/'); + if (filename && filename[0] == '/') + filename++; + if (!browser_start_download(page->browser, filename)) + return false; + } + page->content_pos = n + 1; - /* avoid a round trip through idle handler */ - goto handle_state; + /* gemini only has one header */ + break; } - if (page->fetch_cookie == NULL) - /* no more data will be coming */ - return false; + if (page->parse_state == PARSE_STATE_BODY) { + /* shift out the header */ + if (page->content_pos == page->content_len) + page->content_pos = page->content_len = 0; + else { + memmove(page->content, page->content + page->content_pos, + page->content_len - page->content_pos); + page->content_len -= page->content_pos; + page->content_pos = 0; + } + } else if (page->parse_state == PARSE_STATE_DOWNLOAD) { + /* dump remaining data after header into our new file */ + tlen = len = page->content_len - page->content_pos; + if (tlen) { + err = FSWrite(page->download_frefnum, &tlen, + page->content + page->content_pos); + if (err || tlen != len) { + warn("Failed to write %ld bytes: %d", len, err); + return false; + } + page->download_len = tlen; + } - break; + /* reset for future writing */ + page->content_pos = page->content_len = 0; + return true; + } } - case PARSE_STATE_DOWNLOAD: - /* TODO */ - break; - case PARSE_STATE_GEMTEXT: - TVAutoCalc(page->browser->output_tv, false); + + if (page->parse_state != PARSE_STATE_BODY) + return true; + + gemtext = (strncasecmp(page->content_type, "text/gemini", 11) == 0); + if (!gemtext) + page->browser->style = STYLE_PRE; + + for (n = page->content_pos; n < page->content_len; n++) { + if (page->content[n] != '\n' && + !(n == page->content_len - 1 && page->fetch_cookie == NULL)) + continue; - for (n = page->content_pos; n < page->content_len; n++) { - if (page->content[n] != '\n' && - !(n == page->content_len - 1 && page->fetch_cookie == NULL)) - continue; + len = n - page->content_pos + 1; + trail = 0; + skip = 0; + newline = false; + + if (page->content[n] == '\n') { + len--; + trail = 1; + newline = true; - len = n - page->content_pos + 1; - trail = 0; - skip = 0; - newline = false; - - if (page->content[n] == '\n') { + if (n > 0 && page->content[n - 1] == '\r') { len--; - trail = 1; - newline = true; - - if (n > 0 && page->content[n - 1] == '\r') { - len--; - trail++; - } - } else if (page->fetch_cookie != NULL) { - /* - * No newline found at the end of the buffer, but the - * buffer isn't full so wait for more data. - */ - break; + trail++; } + } else if (page->fetch_cookie != NULL) + /* no newline at the end and fetching, so wait for more data */ + return true; - /* check for pre first because the other styles can be in it */ - if (page->content[page->content_pos] == '`' && - page->content[page->content_pos + 1] == '`' && - page->content[page->content_pos + 2] == '`') { - /* ``` toggle */ - if (page->browser->style & STYLE_PRE) - page->browser->style = STYLE_NONE; - else - page->browser->style = STYLE_PRE; - - /* the rest of the line can be a description, ignore */ - trail += len; - len = 0; - newline = false; - goto print_line; - } else if (page->browser->style & STYLE_PRE) - goto print_line; + if (!gemtext) + goto print_line; - if (page->content[page->content_pos] == '=' && - page->content[page->content_pos + 1] == '>') { - /* link */ - ssize_t link_len = 0; - ssize_t title_len = 0; - ssize_t j, tlen; - char *link = NULL; - char *title = NULL; - char *tcontent; - struct URI *newuri; - - skip = 2; - len -= 2; - tlen = len; - - tcontent = page->content + page->content_pos + skip; - link = tcontent; - - /* skip leading whitespace */ - while (len && (c = *tcontent) && (c == ' ' || c == '\t')) { - tcontent++; - link++; - len--; - } - - /* consume link */ - while (len && (c = *tcontent) && c != ' ' && c != '\t') { - tcontent++; - len--; - link_len++; - } - - /* consume whitespace after link */ - while (len && (c = *tcontent) && (c == ' ' || c == '\t')) { - tcontent++; - len--; - } - - if (len) { - title = tcontent; - title_len = len; - - /* trim trailing whitespace from title */ - while (title_len && (c = title[title_len - 1]) && - (c == ' ' || c == '\t')) { - title_len--; - } - - if (title_len == 0) - title = NULL; - } - - newuri = build_relative_uri(page->uri, link, link_len); - if (newuri) { - browser_print_link(page->browser, - newuri->str, strlen(newuri->str), title, title_len); - xfree(&newuri); - } else - browser_print_link(page->browser, - link, link_len, title, title_len); + /* check for pre first because the other styles can be in it */ + if (page->content[page->content_pos] == '`' && + page->content[page->content_pos + 1] == '`' && + page->content[page->content_pos + 2] == '`') { + /* ``` toggle */ + if (page->browser->style & STYLE_PRE) page->browser->style = STYLE_NONE; - browser_print(page->browser, "\r", 1); - page->content_pos += skip + tlen + trail; - continue; - } + else + page->browser->style = STYLE_PRE; - if (page->content[page->content_pos] == '#' && - page->content[page->content_pos + 1] == '#' && - page->content[page->content_pos + 2] == '#') { - /* ### h3 */ - page->browser->style = STYLE_H3; - skip = 3; - len -= 3; - while ((c = page->content[page->content_pos + skip]) && - (c == ' ' || c == '\t')) { - skip++; - len--; - } - goto print_line; - } + /* the rest of the line can be a description, ignore */ + trail += len; + len = 0; + newline = false; + goto print_line; + } else if (page->browser->style & STYLE_PRE) + goto print_line; + + if (page->content[page->content_pos] == '=' && + page->content[page->content_pos + 1] == '>') { + /* link */ + link_len = 0; + title_len = 0; + link = NULL; + title = NULL; - if (page->content[page->content_pos] == '#' && - page->content[page->content_pos + 1] == '#') { - /* ## h2 */ - page->browser->style = STYLE_H2; - skip = 2; - len -= 2; - while ((c = page->content[page->content_pos + skip]) && - (c == ' ' || c == '\t')) { - skip++; - len--; - } - goto print_line; - } + skip = 2; + len -= 2; + tlen = len; - if (page->content[page->content_pos] == '#') { - /* # h1 */ - page->browser->style = STYLE_H1; - skip = 1; + tcontent = page->content + page->content_pos + skip; + link = tcontent; + + /* skip leading whitespace */ + while (len && (c = *tcontent) && (c == ' ' || c == '\t')) { + tcontent++; + link++; len--; - while ((c = page->content[page->content_pos + skip]) && - (c == ' ' || c == '\t')) { - skip++; - len--; - } - goto print_line; } - if (page->content[page->content_pos] == '*') { - /* * list item */ - page->browser->style = STYLE_LIST; - skip = 1; + /* consume link */ + while (len && (c = *tcontent) && c != ' ' && c != '\t') { + tcontent++; len--; - while ((c = page->content[page->content_pos + skip]) && - (c == ' ' || c == '\t')) { - skip++; - len--; - } - browser_print(page->browser, " • ", 3); - goto print_line; + link_len++; } - if (page->content[page->content_pos] == '>') { - /* > quote text */ - page->browser->style = STYLE_QUOTE; - skip = 1; + /* consume whitespace after link */ + while (len && (c = *tcontent) && (c == ' ' || c == '\t')) { + tcontent++; len--; - while ((c = page->content[page->content_pos + skip]) && + } + + if (len) { + title = tcontent; + title_len = len; + + /* trim trailing whitespace from title */ + while (title_len && (c = title[title_len - 1]) && (c == ' ' || c == '\t')) { - skip++; - len--; + title_len--; } - goto print_line; + + if (title_len == 0) + title = NULL; } - -print_line: - if (len) - browser_print(page->browser, - page->content + page->content_pos + skip, len); - page->content_pos += skip + len + trail; - - if (!(page->browser->style & STYLE_PRE)) - page->browser->style = STYLE_NONE; - if (newline) - browser_print(page->browser, "\r", 1); + newuri = build_relative_uri(page->uri, link, link_len); + if (newuri) { + browser_print_link(page->browser, newuri->str, + strlen(newuri->str), title, title_len, true); + xfree(&newuri); + } else + browser_print_link(page->browser, link, link_len, title, + title_len, true); + page->browser->style = STYLE_NONE; + page->content_pos += skip + tlen + trail; + continue; } - if (page->fetch_cookie == NULL && - page->content_pos < page->content_len) { - browser_print(page->browser, page->content + page->content_pos, - page->content_len - page->content_pos); - page->content_pos = page->content_len; - ret = false; + if (page->content[page->content_pos] == '#' && + page->content[page->content_pos + 1] == '#' && + page->content[page->content_pos + 2] == '#') { + /* ### h3 */ + page->browser->style = STYLE_H3; + skip = 3; + len -= 3; + while ((c = page->content[page->content_pos + skip]) && + (c == ' ' || c == '\t')) { + skip++; + len--; + } + goto print_line; } - TVAutoCalc(page->browser->output_tv, true); - TVCalcLines(page->browser->output_tv); - TVUpdate(page->browser->output_tv); - TVUpdateScrollbar(page->browser->output_tv, - page->browser->output_tv_scroller); - break; + if (page->content[page->content_pos] == '#' && + page->content[page->content_pos + 1] == '#') { + /* ## h2 */ + page->browser->style = STYLE_H2; + skip = 2; + len -= 2; + while ((c = page->content[page->content_pos + skip]) && + (c == ' ' || c == '\t')) { + skip++; + len--; + } + goto print_line; + } + + if (page->content[page->content_pos] == '#') { + /* # h1 */ + page->browser->style = STYLE_H1; + skip = 1; + len--; + while ((c = page->content[page->content_pos + skip]) && + (c == ' ' || c == '\t')) { + skip++; + len--; + } + goto print_line; + } + + if (page->content[page->content_pos] == '*') { + /* * list item */ + page->browser->style = STYLE_LIST; + skip = 1; + len--; + while ((c = page->content[page->content_pos + skip]) && + (c == ' ' || c == '\t')) { + skip++; + len--; + } + browser_print(page->browser, " • ", 3, false); + goto print_line; + } + + if (page->content[page->content_pos] == '>') { + /* > quote text */ + page->browser->style = STYLE_QUOTE; + skip = 1; + len--; + while ((c = page->content[page->content_pos + skip]) && + (c == ' ' || c == '\t')) { + skip++; + len--; + } + goto print_line; + } + +print_line: + if (len || newline) + browser_print(page->browser, + page->content + page->content_pos + skip, len, newline); + + page->content_pos += skip + len + trail; + + if (!(page->browser->style & STYLE_PRE)) + page->browser->style = STYLE_NONE; } - return ret; + if (page->fetch_cookie == NULL && + page->content_pos < page->content_len) { + browser_print(page->browser, page->content + page->content_pos, + page->content_len - page->content_pos, false); + page->content_pos = page->content_len; + } + + if (page->content_pos == page->content_len) + return (page->fetch_cookie != NULL); + + return true; } static bool @@ -491,44 +507,44 @@ parse_header(struct page *page, char *str, size_t len) return false; } - status = ((str[0] - '0') * 10) + (str[1] - '0'); + page->server_status = ((str[0] - '0') * 10) + (str[1] - '0'); memcpy(fail, str, MIN(len, sizeof(fail))); fail[MIN(len, sizeof(fail) - 1)] = '\0'; - if (status >= 10 && status <= 19) { + if (page->server_status >= 10 && page->server_status <= 19) { /* input, not supported */ browser_statusf(page->browser, "Error: Input not supported (%d)", - status); + page->server_status); return false; } - if (status >= 20 && status <= 29) { + if (page->server_status >= 20 && page->server_status <= 29) { /* success */ - if (len + 3 + 1 > sizeof(page->type)) - len = sizeof(page->type) - 1; - memcpy(page->type, str + 3, len - 2); - page->type[len - 2] = '\0'; + if (len + 3 + 1 > sizeof(page->content_type)) + len = sizeof(page->content_type) - 1; + memcpy(page->content_type, str + 3, len - 2); + page->content_type[len - 2] = '\0'; return true; } - if (status >= 30 && status <= 39) { + if (page->server_status >= 30 && page->server_status <= 39) { /* redirect */ page->redir_to = build_relative_uri(page->uri, str + 3, len - 2); /* TODO: infinite loop detection */ return false; } - if (status >= 40 && status <= 49) { + if (page->server_status >= 40 && page->server_status <= 49) { /* temp fail */ browser_statusf(page->browser, "Error: Server reported temporary " "failure: %s", fail); return false; } - if (status >= 50 && status <= 59) { + if (page->server_status >= 50 && page->server_status <= 59) { /* perm fail */ browser_statusf(page->browser, "Error: Server reported " "permanent failure: %s", fail); return false; } - if (status >= 60 && status <= 69) { + if (page->server_status >= 60 && page->server_status <= 69) { /* auth, not supported */ browser_statusf(page->browser, "Error: Auth not supported (%d)", status); --- gopher.c Wed Nov 6 22:07:39 2024 +++ gopher.c Sat Nov 9 11:54:06 2024 @@ -22,6 +22,9 @@ #define GOPHER_PORT 70 +/* printing line-by-line is slow, so only recalc every n lines */ +#define RECALC_EVERY_N_LINES 25 + static const char showable_types[] = "013i"; struct gopher_request { @@ -60,9 +63,8 @@ gopher_init_request(struct page *page) char *filename; if (page->content_len) { - /* already fetched, nothing to do here but reset */ - page->content_pos = 0; - browser_commit_to_loading_page(page->browser); + /* already fetched */ + page->parse_state = 0; return true; } @@ -87,17 +89,17 @@ gopher_init_request(struct page *page) */ if (page->uri->path[0] == '\0' || (page->uri->path[0] == '/' && page->uri->path[1] == '\0')) { - page->type[0] = '1'; + page->content_type[0] = '1'; gopher->selector_len = snprintf(gopher->selector, sizeof(gopher->selector), "\r\n"); } else { /* /0/blah -> blah */ - page->type[0] = page->uri->path[1]; + page->content_type[0] = page->uri->path[1]; gopher->selector_len = snprintf(gopher->selector, sizeof(gopher->selector), "%s\r\n", page->uri->path + 2); } - browser_statusf(page->browser, "Connected to %s, sending request...", + browser_statusf(page->browser, "Connected to %s, sending selector...", page->uri->hostname); if (!request_tcp_send(&gopher->tcp, page->browser, gopher->selector, @@ -109,7 +111,7 @@ gopher_init_request(struct page *page) page->fetch_cookie = gopher; - if (strchr(showable_types, page->type[0]) == NULL) { + if (strchr(showable_types, page->content_type[0]) == NULL) { if (gopher->selector_len == 2) filename = NULL; else { @@ -157,21 +159,15 @@ gopher_fetch(struct page *page) if (len == 0) return true; - if (page->download_frefnum) { - if (len > page->content_size) - len = page->content_size; - buf = page->content; - } else { - if (page->content_len + len >= page->content_size) { - page = browser_grow_page_content(page, len); - if (page == NULL) - return false; - gopher = (struct gopher_request *)(page->fetch_cookie); - } - buf = page->content + page->content_len; + if (page->content_len + len >= page->content_size) { + page = browser_grow_page_content(page, len); + if (page == NULL) + return false; + gopher = (struct gopher_request *)(page->fetch_cookie); } - len = request_tcp_read(&gopher->tcp, page->browser, buf, len); + len = request_tcp_read(&gopher->tcp, page->browser, + page->content + page->content_len, len); if (len < 0) return false; @@ -182,15 +178,13 @@ gopher_fetch(struct page *page) warn("Failed to write %ld bytes: %d", len, err); return false; } - page->download_len += wlen; - browser_statusf(page->browser, "Wrote %ld bytes", - page->download_len); + browser_statusf(page->browser, "%ld bytes", page->download_len); } else { page->content_len += len; - browser_statusf(page->browser, "Read %ld bytes", page->content_len); + browser_statusf(page->browser, "%ld bytes", page->content_len); - if (strchr(showable_types, page->type[0]) && + if (strchr(showable_types, page->content_type[0]) && page->content_len >= 3 && (page->content_len == 3 || page->content[page->content_len - 4] == '\n') && @@ -217,7 +211,7 @@ gopher_process(struct page *page) TVAutoCalc(page->browser->output_tv, false); - if (page->type[0] == '1') { + if (page->content_type[0] == '1') { /* gopher menu */ for (n = page->content_pos; n < page->content_len; n++) { if (n > 0 && page->content[n - 1] == '\r' && @@ -226,15 +220,6 @@ gopher_process(struct page *page) gopher_print_menu(page, page->content + page->content_pos, n - page->content_pos); page->content_pos = n + 1; - plines++; - - if (plines == 25) { - TVCalcLines(page->browser->output_tv); - TVUpdate(page->browser->output_tv); - TVUpdateScrollbar(page->browser->output_tv, - page->browser->output_tv_scroller); - plines = 0; - } } } @@ -245,58 +230,44 @@ gopher_process(struct page *page) page->content_pos = page->content_len; ret = false; } - } else if (page->type[0] == '0') { + } else if (page->content_type[0] == '0') { /* text file, convert newlines and display */ for (n = page->content_pos; n < page->content_len; n++) { if (page->content[n] == '\r') { browser_print(page->browser, page->content + page->content_pos, - n - page->content_pos + 1); + n - page->content_pos + 1, false); page->content_pos = n + 1; if (page->content[n + 1] == '\n') { page->content_pos++; n++; } - plines++; } else if (page->content[n] == '\n') { /* lone \n */ if (n > page->content_pos) browser_print(page->browser, page->content + page->content_pos, - n - page->content_pos); - browser_print(page->browser, "\r", 1); + n - page->content_pos, true); page->content_pos = n + 1; - plines++; } - - if (plines == 25) { - TVCalcLines(page->browser->output_tv); - TVUpdate(page->browser->output_tv); - TVUpdateScrollbar(page->browser->output_tv, - page->browser->output_tv_scroller); - plines = 0; - } } if (page->fetch_cookie == NULL && page->content_pos < page->content_len) { browser_print(page->browser, page->content + page->content_pos, - page->content_len - page->content_pos); + page->content_len - page->content_pos, false); page->content_pos = page->content_len; ret = false; } } else { - /* anything else, just download it */ + /* anything else, just show it */ browser_print(page->browser, page->content + page->content_pos, - page->content_len - page->content_pos); + page->content_len - page->content_pos, false); page->content_pos = page->content_len; ret = false; } - TVCalcLines(page->browser->output_tv); - TVUpdate(page->browser->output_tv); - TVUpdateScrollbar(page->browser->output_tv, - page->browser->output_tv_scroller); + browser_recalc_scrollbar(page->browser); return ret; } @@ -333,12 +304,11 @@ gopher_print_menu(struct page *page, char *line, size_ switch (type) { case 'i': /* informational */ - browser_print(page->browser, label, strlen(label)); - browser_print(page->browser, "\r", 1); + browser_print(page->browser, label, strlen(label), true); break; default: snprintf(prefix, sizeof(prefix), "[%c] ", type); - browser_print(page->browser, prefix, 4); + browser_print(page->browser, prefix, 4, false); if (type == 'h' && strncmp(selector, "URL:", 4) == 0) tlen = strlcpy(uri, selector + 4, sizeof(uri)); @@ -347,9 +317,9 @@ gopher_print_menu(struct page *page, char *line, size_ type, selector); page->browser->style |= STYLE_BOLD; - browser_print_link(page->browser, uri, tlen, label, strlen(label)); + browser_print_link(page->browser, uri, tlen, label, strlen(label), + true); page->browser->style &= ~(STYLE_BOLD); - browser_print(page->browser, "\r", 1); break; } @@ -357,4 +327,8 @@ gopher_print_menu(struct page *page, char *line, size_ if (line[n] == '\0') line[n] = '\t'; } + + /* stuff number of lines printed into parse state */ + if (++(page->parse_state) % RECALC_EVERY_N_LINES == 0) + browser_recalc_scrollbar(page->browser); } \ No newline at end of file --- main.c Wed Nov 6 22:06:06 2024 +++ main.c Thu Nov 7 21:42:43 2024 @@ -62,7 +62,7 @@ main(void) menu_defaults(); AppendMenu(bookmarks_menu, "\p."); -SetItem(bookmarks_menu, 1, "\pgemini://geminiprotocol.net/"); +SetItem(bookmarks_menu, 1, "\pgemini://geminiprotocol.net/history/"); AppendMenu(bookmarks_menu, "\p."); SetItem(bookmarks_menu, 2, "\pgopher://gopher.floodgap.com/");