Changeset b3ee5f5 in git


Ignore:
Timestamp:
03/03/15 10:05:26 (5 years ago)
Author:
Olly Betts <olly@…>
Branches:
line_contents, master, stereo, travis-osx
Children:
9b658f2
Parents:
7b9b700
git-author:
Olly Betts <olly@…> (03/03/15 10:04:41)
git-committer:
Olly Betts <olly@…> (03/03/15 10:05:26)
Message:

src/cavernlog.cc: Rework code to read cavern's output. In
particular, we no longer mix buffered I/O with select() on the
file descriptor.

Files:
2 edited

Legend:

Unmodified
Added
Removed
  • ChangeLog

    r7b9b700 rb3ee5f5  
     1Tue Mar 03 10:03:21 GMT 2015  Olly Betts <olly@survex.com>
     2
     3        * src/cavernlog.cc: Rework code to read cavern's output.  In
     4          particular, we no longer mix buffered I/O with select() on the
     5          file descriptor.
     6
    17Mon Mar 02 11:45:41 GMT 2015  Olly Betts <olly@survex.com>
    28
  • src/cavernlog.cc

    r7b9b700 rb3ee5f5  
    22 * Run cavern inside an Aven window
    33 *
    4  * Copyright (C) 2005,2006,2010,2011,2012,2014 Olly Betts
     4 * Copyright (C) 2005,2006,2010,2011,2012,2014,2015 Olly Betts
    55 *
    66 * This program is free software; you can redistribute it and/or modify
     
    248248    wxString cur;
    249249    int link_count = 0;
    250     // We're only guaranteed one character of pushback by ungetc() but we
    251     // need two so for portability we implement the second ourselves.
    252     int left = EOF;
    253     while (!feof(cavern_out)) {
     250    unsigned char buf[1024];
     251    unsigned char * end = buf;
     252    while (true) {
    254253        fd_set rfds, efds;
    255254        FD_ZERO(&rfds);
     
    257256        FD_ZERO(&efds);
    258257        FD_SET(cavern_fd, &efds);
    259         // Timeout instantly.
     258        // Timeout instantly the first time, and call Update() so the window
     259        // contents get updated.  If we're still waiting for output after that,
     260        // wait for output for 0.1 seconds, then call wxYield() so that the UI
     261        // doesn't block.
    260262        struct timeval timeout;
    261263        timeout.tv_sec = 0;
    262264        timeout.tv_usec = 0;
    263         if (select(cavern_fd + 1, &rfds, NULL, &efds, &timeout) == 0) {
    264             Update();
     265        bool first = true;
     266        while (select(cavern_fd + 1, &rfds, NULL, &efds, &timeout) == 0) {
     267            if (first) {
     268                first = false;
     269                Update();
     270            } else {
     271                wxYield();
     272            }
    265273            FD_SET(cavern_fd, &rfds);
    266274            FD_SET(cavern_fd, &efds);
     
    268276            timeout.tv_sec = 0;
    269277            timeout.tv_usec = 100000;
    270             if (select(cavern_fd + 1, &rfds, NULL, &efds, &timeout) == 0) {
    271                 wxYield();
    272                 continue;
    273             }
    274278        }
    275279        if (!FD_ISSET(cavern_fd, &rfds)) {
     
    277281            break;
    278282        }
    279         int ch;
    280         if (left == EOF) {
    281             ch = GETC(cavern_out);
    282             if (ch == EOF) break;
    283         } else {
    284             ch = left;
    285             left = EOF;
    286         }
    287         // Decode UTF-8 first to avoid security issues with <, >, &, etc
    288         // encoded using multibyte encodings.
    289         if (ch >= 0xc0 && ch < 0xf0) {
    290             int ch1 = GETC(cavern_out);
    291             if ((ch1 & 0xc0) != 0x80) {
    292                 left = ch1;
    293             } else if (ch < 0xe0) {
    294                 /* 2 byte sequence */
    295                 ch = ((ch & 0x1f) << 6) | (ch1 & 0x3f);
    296             } else {
    297                 /* 3 byte sequence */
    298                 int ch2 = GETC(cavern_out);
    299                 if ((ch2 & 0xc0) != 0x80) {
    300                     ungetc(ch2, cavern_out);
    301                     left = ch1;
     283
     284        ssize_t r = read(cavern_fd, end, sizeof(buf) - (end - buf));
     285        if (r <= 0) {
     286            if (r == 0 && buf != end) {
     287                // FIXME: Truncated UTF-8 sequence.
     288            }
     289            break;
     290        }
     291        end += r;
     292
     293        const unsigned char * p = buf;
     294
     295        while (p != end) {
     296            int ch = *p++;
     297            if (ch >= 0x80) {
     298                // Decode multi-byte UTF-8 sequence.
     299                if (ch < 0xc0) {
     300                    // FIXME: Invalid UTF-8 sequence.
     301                    goto abort;
     302                } else if (ch < 0xe0) {
     303                    /* 2 byte sequence */
     304                    if (p == end) {
     305                        // Incomplete UTF-8 sequence - try to read more.
     306                        break;
     307                    }
     308                    int ch1 = *p++;
     309                    if ((ch1 & 0xc0) != 0x80) {
     310                        // FIXME: Invalid UTF-8 sequence.
     311                        goto abort;
     312                    }
     313                    ch = ((ch & 0x1f) << 6) | (ch1 & 0x3f);
     314                } else if (ch < 0xf0) {
     315                    /* 3 byte sequence */
     316                    if (end - p <= 1) {
     317                        // Incomplete UTF-8 sequence - try to read more.
     318                        break;
     319                    }
     320                    int ch1 = *p++;
     321                    ch = ((ch & 0x1f) << 12) | ((ch1 & 0x3f) << 6);
     322                    if ((ch1 & 0xc0) != 0x80) {
     323                        // FIXME: Invalid UTF-8 sequence.
     324                        goto abort;
     325                    }
     326                    int ch2 = *p++;
     327                    if ((ch2 & 0xc0) != 0x80) {
     328                        // FIXME: Invalid UTF-8 sequence.
     329                        goto abort;
     330                    }
     331                    ch |= (ch2 & 0x3f);
    302332                } else {
    303                     ch = ((ch & 0x1f) << 12) | ((ch1 & 0x3f) << 6) | (ch2 & 0x3f);
     333                    // FIXME: Overlong UTF-8 sequence.
     334                    goto abort;
    304335                }
    305336            }
    306         }
    307 
    308         switch (ch) {
    309             case '\r':
    310                 // Ignore.
    311                 break;
    312             case '\n': {
    313                 if (cur.empty()) continue;
     337
     338            switch (ch) {
     339                case '\r':
     340                    // Ignore.
     341                    break;
     342                case '\n': {
     343                    if (cur.empty()) continue;
    314344#ifndef __WXMSW__
    315                 size_t colon = cur.find(':');
    316 #else
    317                 // If the path is "C:\path\to\file.svx" then don't split at the
    318                 // : after the drive letter!  FIXME: better to look for ": "?
    319                 size_t colon = cur.find(':', 2);
    320 #endif
    321                 if (colon != wxString::npos && colon < cur.size() - 2) {
    322                     ++colon;
    323                     size_t i = colon;
    324                     while (i < cur.size() - 2 &&
    325                            cur[i] >= wxT('0') && cur[i] <= wxT('9')) {
    326                         ++i;
    327                     }
    328                     if (i > colon && cur[i] == wxT(':') ) {
    329                         colon = i;
    330                         // Check for column number.
    331                         while (++i < cur.size() - 2 &&
    332                            cur[i] >= wxT('0') && cur[i] <= wxT('9')) { }
    333                         if (i > colon + 1 && cur[i] == wxT(':') ) {
     345                    size_t colon = cur.find(':');
     346#else
     347                    // If the path is "C:\path\to\file.svx" then don't split at the
     348                    // : after the drive letter!  FIXME: better to look for ": "?
     349                    size_t colon = cur.find(':', 2);
     350#endif
     351                    if (colon != wxString::npos && colon < cur.size() - 2) {
     352                        ++colon;
     353                        size_t i = colon;
     354                        while (i < cur.size() - 2 &&
     355                               cur[i] >= wxT('0') && cur[i] <= wxT('9')) {
     356                            ++i;
     357                        }
     358                        if (i > colon && cur[i] == wxT(':') ) {
    334359                            colon = i;
     360                            // Check for column number.
     361                            while (++i < cur.size() - 2 &&
     362                               cur[i] >= wxT('0') && cur[i] <= wxT('9')) { }
     363                            if (i > colon + 1 && cur[i] == wxT(':') ) {
     364                                colon = i;
     365                            }
     366                            wxString tag = wxT("<a href=\"");
     367                            tag.append(cur, 0, colon);
     368                            while (cur[++i] == wxT(' ')) { }
     369                            tag += wxT("\" target=\"");
     370                            tag.append(cur, i, wxString::npos);
     371                            tag += wxT("\">");
     372                            cur.insert(0, tag);
     373                            cur.insert(colon + tag.size(), wxT("</a>"));
     374                            ++link_count;
    335375                        }
    336                         wxString tag = wxT("<a href=\"");
    337                         tag.append(cur, 0, colon);
    338                         while (cur[++i] == wxT(' ')) { }
    339                         tag += wxT("\" target=\"");
    340                         tag.append(cur, i, wxString::npos);
    341                         tag += wxT("\">");
    342                         cur.insert(0, tag);
    343                         cur.insert(colon + tag.size(), wxT("</a>"));
    344                         ++link_count;
    345                     }
     376                    }
     377
     378                    // Save the scrollbar positions.
     379                    int scroll_x = 0, scroll_y = 0;
     380                    GetViewStart(&scroll_x, &scroll_y);
     381
     382                    cur += wxT("<br>\n");
     383                    AppendToPage(cur);
     384
     385                    if (!link_count) {
     386                        // Auto-scroll the window until we've reported a warning or
     387                        // error.
     388                        int x, y;
     389                        GetVirtualSize(&x, &y);
     390                        int xs, ys;
     391                        GetClientSize(&xs, &ys);
     392                        y -= ys;
     393                        int xu, yu;
     394                        GetScrollPixelsPerUnit(&xu, &yu);
     395                        Scroll(scroll_x, y / yu);
     396                    } else {
     397                        // Restore the scrollbar positions.
     398                        Scroll(scroll_x, scroll_y);
     399                    }
     400
     401                    cur.clear();
     402                    break;
    346403                }
    347 
    348                 // Save the scrollbar positions.
    349                 int scroll_x = 0, scroll_y = 0;
    350                 GetViewStart(&scroll_x, &scroll_y);
    351 
    352                 cur += wxT("<br>\n");
    353                 AppendToPage(cur);
    354 
    355                 if (!link_count) {
    356                     // Auto-scroll the window until we've reported a warning or
    357                     // error.
    358                     int x, y;
    359                     GetVirtualSize(&x, &y);
    360                     int xs, ys;
    361                     GetClientSize(&xs, &ys);
    362                     y -= ys;
    363                     int xu, yu;
    364                     GetScrollPixelsPerUnit(&xu, &yu);
    365                     Scroll(scroll_x, y / yu);
    366                 } else {
    367                     // Restore the scrollbar positions.
    368                     Scroll(scroll_x, scroll_y);
    369                 }
    370 
    371                 cur.clear();
    372                 break;
    373             }
    374             case '<':
    375                 cur += wxT("&lt;");
    376                 break;
    377             case '>':
    378                 cur += wxT("&gt;");
    379                 break;
    380             case '&':
    381                 cur += wxT("&amp;");
    382                 break;
    383             case '"':
    384                 cur += wxT("&#22;");
    385                 continue;
    386             default:
    387                 if (ch >= 128) {
    388                     cur += wxString::Format(wxT("&#%u;"), ch);
    389                 } else {
    390                     cur += (char)ch;
    391                 }
    392         }
    393     }
     404                case '<':
     405                    cur += wxT("&lt;");
     406                    break;
     407                case '>':
     408                    cur += wxT("&gt;");
     409                    break;
     410                case '&':
     411                    cur += wxT("&amp;");
     412                    break;
     413                case '"':
     414                    cur += wxT("&#22;");
     415                    continue;
     416                default:
     417                    if (ch >= 128) {
     418                        cur += wxString::Format(wxT("&#%u;"), ch);
     419                    } else {
     420                        cur += (char)ch;
     421                    }
     422            }
     423        }
     424
     425        size_t left = end - p;
     426        end = buf + left;
     427        if (left) memmove(buf, p, left);
     428    }
     429abort:
    394430
    395431    int retval = pclose(cavern_out);
Note: See TracChangeset for help on using the changeset viewer.