static void getRestOfHeader(TConn * const connectionP, char * const lineEnd, time_t const deadline, const char ** const headerEndP, bool * const errorP) { /*---------------------------------------------------------------------------- Given that the read buffer for connection *connectionP contains (at its current read position) the first line of an HTTP header, which ends at position 'lineEnd', find the rest of it. Some or all of the rest of the header may be in the buffer already; we read more from the connection as necessary, but not if it takes past 'deadline'. In the latter case, we fail. We return the location of the end of the whole header as *headerEndP. We do not remove the header from the buffer, but we do modify the buffer so as to join the multiple lines of the header into a single line, and to NUL-terminate the header. -----------------------------------------------------------------------------*/ char * const headerStart = connectionP->buffer.t + connectionP->bufferpos; char * headerEnd; /* End of the header lines we've seen at so far */ bool gotWholeHeader; bool error; headerEnd = lineEnd; /* initial value - end of 1st line */ for (gotWholeHeader = FALSE, error = FALSE; !gotWholeHeader && !error;) { char * nextLineEnd; /* Note that we are guaranteed, assuming the HTTP stream is valid, that there is at least one more line in it. Worst case, it's the empty line that marks the end of the headers. */ getLineInBuffer(connectionP, headerEnd, deadline, &nextLineEnd, &error); if (!error) { if (isContinuationLine(headerEnd)) { /* Join previous line to this one */ convertLineEnd(headerEnd, headerStart, ' '); /* Add this line to the header */ headerEnd = nextLineEnd; } else { gotWholeHeader = TRUE; /* NUL-terminate the whole header */ convertLineEnd(headerEnd, headerStart, '\0'); } } } *headerEndP = headerEnd; *errorP = error; }
/* Returns the recommended indent for the bottom line of yyProgram if that line is standalone (or should be indented likewise). Indenting a standalone line is tricky, mostly because of braceless control statements. Grossly, we are looking backwards for a special line, a "hook line", that we can use as a starting point to indent, and then modify the indentation level according to the braces met along the way to that hook. Let's consider a few examples. In all cases, we want to indent the bottom line. Example 1: x = 1; y = 2; The hook line is "x = 1;". We met 0 opening braces and 0 closing braces. Therefore, "y = 2;" inherits the indent of "x = 1;". Example 2: if ( x ) { y; The hook line is "if ( x ) {". No matter what precedes it, "y;" has to be indented one level deeper than the hook line, since we met one opening brace along the way. Example 3: if ( a ) while ( b ) { c; } d; To indent "d;" correctly, we have to go as far as the "if ( a )". Compare with if ( a ) { while ( b ) { c; } d; Still, we're striving to go back as little as possible to accommodate people with irregular indentation schemes. A hook line near at hand is much more reliable than a remote one. */ static int indentForStandaloneLine() { for ( int i = 0; i < SmallRoof; i++ ) { if ( !*yyLeftBraceFollows ) { YY_SAVE(); if ( matchBracelessControlStatement() ) { /* The situation is this, and we want to indent "z;": if ( x && y ) z; yyLine is "if ( x &&". */ return indentOfLine( *yyLine ) + ppIndentSize; } YY_RESTORE(); } if ( yyLine->endsWith(";") || yyLine->contains('{') ) { /* The situation is possibly this, and we want to indent "z;": while ( x ) y; z; We return the indent of "while ( x )". In place of "y;", any arbitrarily complex compound statement can appear. */ if ( *yyBraceDepth > 0 ) { do { if ( !readLine() ) break; } while ( *yyBraceDepth > 0 ); } LinizerState hookState; while ( isContinuationLine() ) readLine(); hookState = *yyLinizerState; readLine(); if ( *yyBraceDepth <= 0 ) { do { if ( !matchBracelessControlStatement() ) break; hookState = *yyLinizerState; } while ( readLine() ); } *yyLinizerState = hookState; while ( isContinuationLine() ) readLine(); /* Never trust lines containing only '{' or '}', as some people (Richard M. Stallman) format them weirdly. */ if ( yyLine->trimmed().length() > 1 ) return indentOfLine( *yyLine ) - *yyBraceDepth * ppIndentSize; } if ( !readLine() ) return -*yyBraceDepth * ppIndentSize; } return 0; }
/* Returns the recommended indent for the bottom line of yyProgram, assuming it's a continuation line. We're trying to align the continuation line against some parenthesis or other bracked left opened on a previous line, or some interesting operator such as '='. */ static int indentForContinuationLine() { int braceDepth = 0; int delimDepth = 0; bool leftBraceFollowed = *yyLeftBraceFollows; for ( int i = 0; i < SmallRoof; i++ ) { int hook = -1; int j = yyLine->length(); while ( j > 0 && hook < 0 ) { j--; QChar ch = (*yyLine)[j]; switch ( ch.unicode() ) { case ')': case ']': delimDepth++; break; case '}': braceDepth++; break; case '(': case '[': delimDepth--; /* An unclosed delimiter is a good place to align at, at least for some styles (including Trolltech's). */ if ( delimDepth == -1 ) hook = j; break; case '{': braceDepth--; /* A left brace followed by other stuff on the same line is typically for an enum or an initializer. Such a brace must be treated just like the other delimiters. */ if ( braceDepth == -1 ) { if ( j < (int) yyLine->length() - 1 ) { hook = j; } else { return 0; // shouldn't happen } } break; case '=': /* An equal sign is a very natural alignment hook because it's usually the operator with the lowest precedence in statements it appears in. Case in point: int x = 1 + 2; However, we have to beware of constructs such as default arguments and explicit enum constant values: void foo( int x = 0, int y = 0 ); And not void foo( int x = 0, int y = 0 ); These constructs are caracterized by a ',' at the end of the unfinished lines or by unbalanced parentheses. */ if ( QString("!=<>").indexOf((*yyLine)[j - 1]) == -1 && (*yyLine)[j + 1] != '=' ) { if ( braceDepth == 0 && delimDepth == 0 && j < (int) yyLine->length() - 1 && !yyLine->endsWith(",") && (yyLine->contains('(') == yyLine->contains(')')) ) hook = j; } } } if ( hook >= 0 ) { /* Yes, we have a delimiter or an operator to align against! We don't really align against it, but rather against the following token, if any. In this example, the following token is "11": int x = ( 11 + 2 ); If there is no such token, we use a continuation indent: static QRegExp foo( QString( "foo foo foo foo foo foo foo foo foo") ); */ hook++; while ( hook < (int) yyLine->length() ) { if ( !(*yyLine)[hook].isSpace() ) return columnForIndex( *yyLine, hook ); hook++; } return indentOfLine( *yyLine ) + ppContinuationIndentSize; } if ( braceDepth != 0 ) break; /* The line's delimiters are balanced. It looks like a continuation line or something. */ if ( delimDepth == 0 ) { if ( leftBraceFollowed ) { /* We have int main() { or Bar::Bar() : Foo( x ) { The "{" should be flush left. */ if ( !isContinuationLine() ) return indentOfLine( *yyLine ); } else if ( isContinuationLine() || yyLine->endsWith(",") ) { /* We have x = a + b + c; or int t[] = { 1, 2, 3, 4, 5, 6 The "c;" should fall right under the "b +", and the "4, 5, 6" right under the "1, 2, 3,". */ return indentOfLine( *yyLine ); } else { /* We have stream << 1 + 2; We could, but we don't, try to analyze which operator has precedence over which and so on, to obtain the excellent result stream << 1 + 2; We do have a special trick above for the assignment operator above, though. */ return indentOfLine( *yyLine ) + ppContinuationIndentSize; } } if ( !readLine() ) break; } return 0; }
static void readHeader(TConn * const connectionP, time_t const deadline, bool * const endOfHeadersP, char ** const headerP, bool * const errorP) { /*---------------------------------------------------------------------------- Read an HTTP header, or the end of headers empty line, on connection *connectionP. An HTTP header is basically a line, except that if a line starts with white space, it's a continuation of the previous line. A line is delimited by either LF or CRLF. The first line of an HTTP header is never empty; an empty line signals the end of the HTTP headers and beginning of the HTTP body. We call that empty line the EOH mark. We assume the connection is positioned to a header or EOH mark. In the course of reading, we read at least one character past the line delimiter at the end of the header or EOH mark; we may read much more. But we leave everything after the header or EOH (and its line delimiter) in the internal buffer, with the buffer pointer pointing to it. We use stuff already in the internal buffer (perhaps left by a previous call to this subroutine) before reading any more from from the channel. We return as *headerP the next header as an ASCIIZ string, with no line delimiter. That string is stored in the "unused" portion of the connection's internal buffer. Iff there is no next header, we return *endOfHeadersP == true and nothing meaningful as *headerP. -----------------------------------------------------------------------------*/ char * const bufferStart = connectionP->buffer.t + connectionP->bufferpos; bool error; char * lineEnd; getLineInBuffer(connectionP, bufferStart, deadline, &lineEnd, &error); if (!error) { if (isContinuationLine(bufferStart)) error = TRUE; else if (isEmptyLine(bufferStart)) { /* Consume the EOH mark from the buffer */ connectionP->bufferpos = lineEnd - connectionP->buffer.t; *endOfHeadersP = TRUE; } else { /* We have the first line of a header; there may be more. */ const char * headerEnd; *endOfHeadersP = FALSE; getRestOfHeader(connectionP, lineEnd, deadline, &headerEnd, &error); if (!error) { *headerP = bufferStart; /* Consume the header from the buffer (but be careful -- you can't reuse that part of the buffer because the string we will return is in it! */ connectionP->bufferpos = headerEnd - connectionP->buffer.t; } } } *errorP = error; }
void pngtxt_addChunk(struct pngx * const pngxP, FILE * const tfP, bool const ztxt, bool const itxt, bool const verbose) { /*---------------------------------------------------------------------------- Add text chunks (tEXt, zTXt, or iTXt) to the PNG image represented by *pngxP as directed by file *tfP. 'itxt' means to make them international language (iTXt) chunks. Otherwise they are either tEXt or zTXt chunks, depending upon 'ztxt'. 'ztxt' means to make the text compressed. If the chunks are not international (i.e. 'itxt' is false), this means the chunks are zTXt chunks instead of 'tEXt' chunks. -----------------------------------------------------------------------------*/ bool noChunksYet; bool eof; png_textp text; /* An array; one chunk per element */ unsigned int chunkCt; /* Number of chunks we have completed in the 'text' array */ unsigned int allocatedChunkCt; /* Number of entries currently allocated for the PNG text array */ /* In an international text string file, the first entry tells the language of all of the chunks, by having key 'Language'. */ allocatedChunkCt = 256; /* initial value */ MALLOCARRAY(text, allocatedChunkCt); if (text == NULL) pm_error("unable to allocate memory for text chunk array"); for (chunkCt = 0, noChunksYet = true, eof = false; !eof; ) { const char * textline; unsigned int lineLength; getFileLine(tfP, &textline, &lineLength); if (textline == NULL) eof = true; else { if (lineLength == 0) { /* skip this empty line */ } else { handleArrayAllocation(&text, &allocatedChunkCt, chunkCt); if (!isContinuationLine(textline)) { png_text * textChunkP; if (noChunksYet) { /* No previous chunk to move past */ } else ++chunkCt; noChunksYet = false; textChunkP = &text[chunkCt]; if (itxt) startTextChunkIntl(textChunkP, textline, lineLength, ztxt, verbose); else startTextChunkEngl(textChunkP, textline, lineLength, ztxt, verbose); } else { png_text * const textChunkP = &text[chunkCt]; /* Line starts with whitespace, which means it is a continuation of the current text string. */ if (noChunksYet) pm_error("Invalid text string file format: " "first line is a continuation line! " "(It starts with whitespace)"); continueTextString(textChunkP, textline, lineLength); } } pm_strfree(textline); } } if (!noChunksYet) ++chunkCt; if (verbose) reportChunkCt(ztxt, itxt, chunkCt); if (chunkCt > 0) pngx_setText(pngxP, text, chunkCt); free(text); }