Continuation callbackOnJobQueue ( JobQueue& jobQueue, std::string const& name, JobType jobType) { return Continuation ([name, jobType, &jobQueue] (Callback const& cb) { jobQueue.addJob (jobType, name, [cb] (Job&) { cb(); }); }); }
static BOOL Parameter( myFILE *InFile, BOOL (*pfunc)(char *, char *), int c ) /* ------------------------------------------------------------------------ ** * Scan a parameter name and value, and pass these two fields to pfunc(). * * Input: InFile - The input source. * pfunc - A pointer to the function that will be called to * process the parameter, once it has been scanned. * c - The first character of the parameter name, which * would have been read by Parse(). Unlike a comment * line or a section header, there is no lead-in * character that can be discarded. * * Output: True if the parameter name and value were scanned and processed * successfully, else False. * * Notes: This function is in two parts. The first loop scans the * parameter name. Internal whitespace is compressed, and an * equal sign (=) terminates the token. Leading and trailing * whitespace is discarded. The second loop scans the parameter * value. When both have been successfully identified, they are * passed to pfunc() for processing. * * ------------------------------------------------------------------------ ** */ { int i = 0; /* Position within bufr. */ int end = 0; /* bufr[end] is current end-of-string. */ int vstart = 0; /* Starting position of the parameter value. */ char *func = "params.c:Parameter() -"; /* Read the parameter name. */ while( 0 == vstart ) /* Loop until we've found the start of the value. */ { if( i > (bSize - 2) ) /* Ensure there's space for next char. */ { bSize += BUFR_INC; bufr = Realloc( bufr, bSize ); if( NULL == bufr ) { DEBUG(0, ("%s Memory re-allocation failure.", func) ); return( False ); } } switch( c ) { case '=': /* Equal sign marks end of param name. */ if( 0 == end ) /* Don't allow an empty name. */ { DEBUG(0, ("%s Invalid parameter name in config. file.\n", func )); return( False ); } bufr[end++] = '\0'; /* Mark end of string & advance. */ i = end; /* New string starts here. */ vstart = end; /* New string is parameter value. */ bufr[i] = '\0'; /* New string is nul, for now. */ break; case '\n': /* Find continuation char, else error. */ i = Continuation( bufr, i ); if( i < 0 ) { bufr[end] = '\0'; DEBUG(1,("%s Ignoring badly formed line in configuration file: %s\n", func, bufr )); return( True ); } end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i); c = mygetc( InFile ); /* Read past eoln. */ break; case '\0': /* Shouldn't have EOF within param name. */ case EOF: bufr[i] = '\0'; DEBUG(1,("%s Unexpected end-of-file at: %s\n", func, bufr )); return( True ); default: if( isspace( c ) ) /* One ' ' per whitespace region. */ { bufr[end] = ' '; i = end + 1; c = EatWhitespace( InFile ); } else /* All others verbatim. */ { bufr[i++] = c; end = i; c = mygetc( InFile ); } } } /* Now parse the value. */ c = EatWhitespace( InFile ); /* Again, trim leading whitespace. */ while( (EOF !=c) && (c > 0) ) { if( i > (bSize - 2) ) /* Make sure there's enough room. */ { bSize += BUFR_INC; bufr = Realloc( bufr, bSize ); if( NULL == bufr ) { DEBUG(0, ("%s Memory re-allocation failure.", func) ); return( False ); } } switch( c ) { case '\r': /* Explicitly remove '\r' because the older */ c = mygetc( InFile ); /* version called fgets_slash() which also */ break; /* removes them. */ case '\n': /* Marks end of value unless there's a '\'. */ i = Continuation( bufr, i ); if( i < 0 ) c = 0; else { for( end = i; (end >= 0) && isspace(bufr[end]); end-- ) ; c = mygetc( InFile ); } break; default: /* All others verbatim. Note that spaces do */ bufr[i++] = c; /* not advance <end>. This allows trimming */ if( !isspace( c ) ) /* of whitespace at the end of the line. */ end = i; c = mygetc( InFile ); break; } } bufr[end] = '\0'; /* End of value. */ return( pfunc( bufr, &bufr[vstart] ) ); /* Pass name & value to pfunc(). */ } /* Parameter */
static BOOL Section( myFILE *InFile, BOOL (*sfunc)(char *) ) /* ------------------------------------------------------------------------ ** * Scan a section name, and pass the name to function sfunc(). * * Input: InFile - Input source. * sfunc - Pointer to the function to be called if the section * name is successfully read. * * Output: True if the section name was read and True was returned from * <sfunc>. False if <sfunc> failed or if a lexical error was * encountered. * * ------------------------------------------------------------------------ ** */ { int c; int i; int end; char *func = "params.c:Section() -"; i = 0; /* <i> is the offset of the next free byte in bufr[] and */ end = 0; /* <end> is the current "end of string" offset. In most */ /* cases these will be the same, but if the last */ /* character written to bufr[] is a space, then <end> */ /* will be one less than <i>. */ c = EatWhitespace( InFile ); /* We've already got the '['. Scan */ /* past initial white space. */ while( (EOF != c) && (c > 0) ) { /* Check that the buffer is big enough for the next character. */ if( i > (bSize - 2) ) { bSize += BUFR_INC; bufr = Realloc( bufr, bSize ); if( NULL == bufr ) { DEBUG(0, ("%s Memory re-allocation failure.", func) ); return( False ); } } /* Handle a single character. */ switch( c ) { case ']': /* Found the closing bracket. */ bufr[end] = '\0'; if( 0 == end ) /* Don't allow an empty name. */ { DEBUG(0, ("%s Empty section name in configuration file.\n", func )); return( False ); } if( !sfunc( bufr ) ) /* Got a valid name. Deal with it. */ return( False ); (void)EatComment( InFile ); /* Finish off the line. */ return( True ); case '\n': /* Got newline before closing ']'. */ i = Continuation( bufr, i ); /* Check for line continuation. */ if( i < 0 ) { bufr[end] = '\0'; DEBUG(0, ("%s Badly formed line in configuration file: %s\n", func, bufr )); return( False ); } end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i); c = mygetc( InFile ); /* Continue with next line. */ break; default: /* All else are a valid name chars. */ if( isspace( c ) ) /* One space per whitespace region. */ { bufr[end] = ' '; i = end + 1; c = EatWhitespace( InFile ); } else /* All others copy verbatim. */ { bufr[i++] = c; end = i; c = mygetc( InFile ); } } } /* We arrive here if we've met the EOF before the closing bracket. */ DEBUG(0, ("%s Unexpected EOF in the configuration file: %s\n", func, bufr )); return( False ); } /* Section */
static bool Parameter( DATA_BLOB *buf, myFILE *InFile, bool (*pfunc)(const char *, const char *, void *), int c, void *userdata ) { int i = 0; /* Position within bufr. */ int end = 0; /* bufr[end] is current end-of-string. */ int vstart = 0; /* Starting position of the parameter value. */ const char *func = "params.c:Parameter() -"; /* Read the parameter name. */ while( 0 == vstart ) { /* Loop until we've found the start of the value. */ if( i > (buf->length - 2) ) { /* Ensure there's space for next char. */ uint8_t *tb = (uint8_t *)SMB_REALLOC_KEEP_OLD_ON_ERROR( buf->data, buf->length + BUFR_INC ); if (!tb) { DEBUG(0, ("%s Memory re-allocation failure.", func) ); return False; } buf->data = tb; buf->length += BUFR_INC; } switch(c) { case '=': /* Equal sign marks end of param name. */ if( 0 == end ) { /* Don't allow an empty name. */ DEBUG(0, ("%s Invalid parameter name in config. file.\n", func )); return False; } buf->data[end++] = '\0'; /* Mark end of string & advance. */ i = end; /* New string starts here. */ vstart = end; /* New string is parameter value. */ buf->data[i] = '\0'; /* New string is nul, for now. */ break; case '\n': /* Find continuation char, else error. */ i = Continuation( buf->data, i ); if( i < 0 ) { buf->data[end] = '\0'; DEBUG(1,("%s Ignoring badly formed line in configuration file: %s\n", func, buf->data )); return True; } end = ( (i > 0) && (' ' == buf->data[i - 1]) ) ? (i - 1) : (i); c = mygetc( InFile ); /* Read past eoln. */ break; case '\0': /* Shouldn't have EOF within param name. */ case EOF: buf->data[i] = '\0'; DEBUG(1,("%s Unexpected end-of-file at: %s\n", func, buf->data )); return True; default: if(isspace( c )) { /* One ' ' per whitespace region. */ buf->data[end] = ' '; i = end + 1; c = EatWhitespace( InFile ); } else { buf->data[i++] = c; end = i; c = mygetc( InFile ); } } } /* Now parse the value. */ c = EatWhitespace( InFile ); /* Again, trim leading whitespace. */ while( (EOF !=c) && (c > 0) ) { if( i > (buf->length - 2) ) { /* Make sure there's enough room. */ uint8_t *tb = (uint8_t *)SMB_REALLOC_KEEP_OLD_ON_ERROR( buf->data, buf->length + BUFR_INC ); if (!tb) { DEBUG(0, ("%s Memory re-allocation failure.", func)); return False; } buf->data = tb; buf->length += BUFR_INC; } switch(c) { case '\r': /* Explicitly remove '\r' because the older */ c = mygetc( InFile ); /* version called fgets_slash() which also */ break; /* removes them. */ case '\n': /* Marks end of value unless there's a '\'. */ i = Continuation( buf->data, i ); if( i < 0 ) { c = 0; } else { for( end = i; (end >= 0) && isspace((int)buf->data[end]); end-- ) ; c = mygetc( InFile ); } break; default: /* All others verbatim. Note that spaces do not advance <end>. This allows trimming */ buf->data[i++] = c; if( !isspace( c ) ) /* of whitespace at the end of the line. */ end = i; c = mygetc( InFile ); break; } } buf->data[end] = '\0'; /* End of value. */ return( pfunc( (char *)buf->data, (char *)&buf->data[vstart], userdata ) ); /* Pass name & value to pfunc(). */ }
static bool Section( DATA_BLOB *buf, myFILE *InFile, bool (*sfunc)(const char *, void *), void *userdata ) { int c; int i; int end; const char *func = "params.c:Section() -"; i = 0; /* <i> is the offset of the next free byte in bufr[] and */ end = 0; /* <end> is the current "end of string" offset. In most */ /* cases these will be the same, but if the last */ /* character written to bufr[] is a space, then <end> */ /* will be one less than <i>. */ /* Find the end of the section. We must use mb functions for this. */ if (!FindSectionEnd(InFile)) { DEBUG(0, ("%s No terminating ']' character in section.\n", func) ); return False; } c = EatWhitespace( InFile ); /* We've already got the '['. Scan */ /* past initial white space. */ while( (EOF != c) && (c > 0) ) { /* Check that the buffer is big enough for the next character. */ if( i > (buf->length - 2) ) { uint8_t *tb = (uint8_t *)SMB_REALLOC_KEEP_OLD_ON_ERROR(buf->data, buf->length+BUFR_INC ); if(!tb) { DEBUG(0, ("%s Memory re-allocation failure.", func) ); return False; } buf->data = tb; buf->length += BUFR_INC; } /* Handle a single character other than section end. */ switch( c ) { case '\n': /* Got newline before closing ']'. */ i = Continuation( buf->data, i ); /* Check for line continuation. */ if( i < 0 ) { buf->data[end] = '\0'; DEBUG(0, ("%s Badly formed line in configuration file: %s\n", func, buf->data )); return False; } end = ( (i > 0) && (' ' == buf->data[i - 1]) ) ? (i - 1) : (i); c = mygetc( InFile ); /* Continue with next line. */ break; default: /* All else are a valid name chars. */ if(isspace( c )) { /* One space per whitespace region. */ buf->data[end] = ' '; i = end + 1; c = EatWhitespace( InFile ); } else { buf->data[i++] = c; end = i; c = mygetc( InFile ); } } if (AtSectionEnd(InFile)) { /* Got to the closing bracket. */ buf->data[end] = '\0'; if( 0 == end ) { /* Don't allow an empty name. */ DEBUG(0, ("%s Empty section name in configuration file.\n", func )); return False; } if( !sfunc((char *)buf->data, userdata) ) /* Got a valid name. Deal with it. */ return False; EatComment( InFile ); /* Finish off the line. */ return True; } } /* We arrive here if we've met the EOF before the closing bracket. */ DEBUG(0, ("%s Unexpected EOF in the configuration file: %s\n", func, buf->data )); return False; }
void test (int chunkSize, Strings const& expected) { auto name = std::to_string (chunkSize); setup (name); std::string buffer; Json::Output output = Json::stringOutput (buffer); auto makeContinuation = [&] (std::string const& data) { return Continuation ([=] (Callback const& cb) { output (data + " "); cb(); }); }; Strings result; SuspendCallback suspendCallback ([&] (Suspend const& suspend) { Callback yield = suspendForContinuation ( suspend, makeContinuation ("*")); auto out = chunkedYieldingOutput (output, yield, chunkSize); out ("hello "); result.push_back (buffer); suspend (makeContinuation("HELLO")); result.push_back (buffer); out ("there "); result.push_back (buffer); suspend (makeContinuation("THERE")); result.push_back (buffer); out ("world "); result.push_back (buffer); suspend (makeContinuation("WORLD")); result.push_back (buffer); }); Coroutine (suspendCallback).run(); expectCollectionEquals (result, expected); static auto const printResults = false; if (! printResults) return; std::string indent1 = " "; std::string indent2 = indent1 + " "; std::cerr << indent1 << "test (" + name + ", {"; for (auto i = 0; i < result.size(); ++i) { if (i) std::cerr << ","; std::cerr << "\n" << indent2; std::cerr << '"' << result[i] << '"'; } std::cerr << "\n" << indent2 << "});\n"; expect(true); }