int _vcscanf(int (*__getc)(void*), void (*__rewind)(void*), void *h, const char *format, va_list ap) { char fch, ich; int ret = 0, nch = 0; while( (fch = *format++) ) { union { void *_void; char *_char; short *_short; int *_int; long *_long; long long *_longlong; } ptr; long long ival; //long double rval; int maxlen = 0; // int offset = -1; enum e_vcscanf_sizes size = _VCSCANF_UNDEF; enum e_vcscanf_types valtype; int fail = 0; int nnewch; const char *set_start; int set_len; // Whitespace matches any ammount of whitespace (including none) if( isspace(fch) ) { while( (ich = __getc(h)) && isspace(ich) ) nch ++; if(ich) __rewind(h); continue ; } // Any non-whitespace and non-% characters must match exactly if( fch != '%' ) { if( __getc(h) != fch ) break; nch ++; continue ; } // Format specifier fch = *format++; if(!fch) break; // Catch '%%' early if( fch == '%' ) { if( __getc(h) != '%' ) break; nch ++; continue ; } // %n$ - Direct offset selection, shouldn't be mixed with just % #if 0 for( ; isdigit(fch); fch = *format++ ) maxlen = maxlen * 10 + (fch - '0'); if( fch == '$' ) { offset = maxlen; maxlen = 0; } #endif // Supress assignemnt? if( fch == '*' ) { fch = *format++; ptr._void = NULL; ret --; } else ptr._void = va_arg(ap, void*); // Max field length while( isdigit(fch) ) { maxlen = maxlen * 10 + fch - '0'; fch = *format++; } // Length modifier switch( fch ) { case 'h': // 'short' size = _VCSCANF_SHORT; fch = *format++; if( fch == 'h' ) { // 'char' size = _VCSCANF_CHAR; fch = *format++; } break; case 'l': // 'long' size = _VCSCANF_LONG; fch = *format++; if( fch == 'l' ) { // 'long long' size = _VCSCANF_LONGLONG; fch = *format++; } break; case 'j': // '(u)intmax_t' size = _VCSCANF_INTMAX; fch = *format++; break; case 'z': // 'size_t' size = _VCSCANF_SIZET; fch = *format++; break; case 't': // 'ptrdiff_t' size = _VCSCANF_PTRDIFF; fch = *format++; break; case 'L': // 'long double' (a, A, e, E, f, F, g, G) size = _VCSCANF_LONGDOUBLE; fch = *format++; break; } // Format specifiers switch( fch ) { // Decimal integer case 'd': nnewch = _vcscanf_int(__getc, __rewind, h, 10, maxlen, &ival); if(nnewch==0) fail=1; nch += nnewch; valtype = _VCSCANF_INT; break; // variable-base integer case 'i': nnewch = _vcscanf_int(__getc, __rewind, h, 0, maxlen, &ival); if(nnewch==0) fail=1; nch += nnewch; valtype = _VCSCANF_INT; break; // Octal integer case 'o': nnewch = _vcscanf_int(__getc, __rewind, h, 8, maxlen, &ival); if(nnewch==0) fail=1; nch += nnewch; valtype = _VCSCANF_INT; break; // Hexadecimal integer case 'x': case 'X': nnewch = _vcscanf_int(__getc, __rewind, h, 16, maxlen, &ival); if(nnewch==0) fail=1; nch += nnewch; valtype = _VCSCANF_INT; break; // strtod format float case 'a': case 'A': case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': valtype = _VCSCANF_REAL; break; // `maxlen` or 1 characters case 'c': if( maxlen == 0 ) maxlen = 1; while( maxlen -- && (ich = __getc(h)) ) { if(ptr._char) *ptr._char++ = ich; nch ++; } valtype = _VCSCANF_NOTYPE; break; // sequence of non-whitespace characters case 's': if( maxlen == 0 ) maxlen = -1; ich = 0; while( maxlen -- && (ich = __getc(h)) && !isspace(ich) ) { if(ptr._char) *ptr._char++ = ich; nch ++; } if( maxlen >= 0 && ich ) __rewind(h); if(ptr._char) *ptr._char++ = 0; valtype = _VCSCANF_NOTYPE; break; // match a set of characters case '[': { int invert = 0; if( *format++ == '^' ) { // Invert invert = 1; } set_start = format; set_len = 0; // if the first character is ']' it's part of the set do { // permissable character set_len ++; fch = *format++; } while( fch && fch != ']' ); if( maxlen == 0 ) maxlen = -1; ich = 0; while( maxlen -- && (ich = __getc(h)) && invert == !memchr(set_start, set_len, ich) ) { if(ptr._char) *ptr._char++ = ich; nch ++; } if( maxlen >= 0 && ich ) __rewind(h); if(ptr._char) *ptr._char++ = 0; valtype = _VCSCANF_NOTYPE; break; } case 'p': // read back printf("%p") valtype = _VCSCANF_NOTYPE; break; case 'n': // number of read characters to this point if(ptr._int) { *ptr._int = nch; ret --; // negates the ret ++ at the end } valtype = _VCSCANF_NOTYPE; break; default: // Implimentation defined valtype = _VCSCANF_NOTYPE; break; } if(fail) break; switch(valtype) { case _VCSCANF_NOTYPE: // Used when assignment is done above break; case _VCSCANF_INT: switch(size) { case _VCSCANF_UNDEF: *ptr._int = ival; break; case _VCSCANF_CHAR: *ptr._char = ival; break; case _VCSCANF_SHORT: *ptr._short = ival; break; case _VCSCANF_LONG: *ptr._long = ival; break; case _VCSCANF_LONGLONG: *ptr._longlong = ival; break; default: // ??? break; } break; case _VCSCANF_REAL: break; } ret ++; } return ret; }
// === CODE === int _vcscanf_int(int (*__getc)(void *), void (*__rewind)(void*), void *h, int base, int maxlen, long long *outval) { char ich; int sgn = 1; long long int ret = 0; int n_read = 0; // Initialise output to something sane *outval = 0; // First character // - maxlen == 0 means no limit ich = __getc(h); n_read ++; // Sign? if( ich == '-' || ich == '+' ) { sgn = (ich == '-' ? -1 : 1); if( n_read == maxlen ) return n_read; ich = __getc(h); n_read ++; } // Determine base if( base == 0 ) { if( ich != '0' ) { base = 10; } else { if( n_read == maxlen ) return n_read; ich = __getc(h); n_read ++; if( ich != 'x' ) { base = 8; } else { base = 16; if( n_read == maxlen ) return n_read; ich = __getc(h); n_read ++; } } } if( ich == 0 ) { // Oops? return n_read; } while( ich ) { int next = -1; // Get the digit value if( base <= 10 ) { if( '0' <= ich && ich <= '0'+base-1 ) next = ich - '0'; } else { if( '0' <= ich && ich <= '9' ) next = ich - '0'; if( 'A' <= ich && ich <= 'A'+base-10-1 ) next = ich - 'A' + 10; if( 'a' <= ich && ich <= 'a'+base-10-1 ) next = ich - 'a' + 10; } // if it's not a digit, rewind and break if( next < 0 ) { __rewind(h); n_read --; break; } // Add to the result ret *= base; ret += next; //_SysDebug("- %i/%i read, 0x%x val", n_read, maxlen, ret); // Check if we've reached the limit if( n_read == maxlen ) break ; // Next character ich = __getc(h); n_read ++; } // Apply sign if( sgn == -1 ) ret = -ret; *outval = ret; return n_read; }
static Boolean _lock( struct OBlockGroup* inst ,const char* BlockId ,const char* LocoId ) { iOBlockGroupData data = Data(inst); iOModel model = AppOp.getModel(); Boolean selectShortest = wCtrl.isselectshortestblock( wRocRail.getctrl( AppOp.getIni() ) ); TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "loco %s request to lock blockgroup %s with block %s", LocoId, wLink.getid(data->props), BlockId); if( MapOp.get(data->lockmap, LocoId) != NULL ) { TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "loco %s already locked blockgroup %s", LocoId, wLink.getid(data->props)); return True; } if( MapOp.size(data->lockmap) == 0 ) { iOStrTok tok = StrTokOp.inst( wLink.getdst(data->props), ',' ); Boolean grouplocked = True; TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "loco %s pending to lock blockgroup %s", LocoId, wLink.getid(data->props)); while( StrTokOp.hasMoreTokens(tok) && grouplocked ) { const char* id = StrTokOp.nextToken( tok ); iIBlockBase gblock = ModelOp.getBlock( model, id ); if( gblock != NULL ) { grouplocked = gblock->lockForGroup( gblock, LocoId ); } }; StrTokOp.base.del(tok); if( !grouplocked ) { TraceOp.trc( name, TRCLEVEL_USER1, __LINE__, 9999, "unable to lock blockgroup %s for loco %s", wLink.getid(data->props), LocoId); __rewind(inst, LocoId); data->firstBlock = NULL; data->firstLoco = NULL; } else { /* check the conditions... */ Boolean condOK = True; iONode cond = wLink.getlinkcond(data->props); while( cond != NULL && condOK ) { TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "checking blockgroup %s condition first=%s...", wLink.getid(data->props), wLinkCond.getfirst(cond) ); if( StrOp.equals( wLinkCond.getfirst(cond), BlockId )) { Boolean freeBlock = False; int restlen = 0; iOStrTok tok = StrTokOp.inst(wLinkCond.getfree(cond), ','); while( StrTokOp.hasMoreTokens(tok) ) { const char* id = StrTokOp.nextToken( tok ); iIBlockBase block = ModelOp.getBlock( model, id ); if( block != NULL && block->isFree(block, LocoId) ) { iOLoc loc = ModelOp.getLoc( model, LocoId, NULL, False ); block_suits suits = block->isSuited( block, loc, &restlen, !selectShortest ); if( suits != suits_not ) { freeBlock = True; break; } } }; StrTokOp.base.del(tok); if( freeBlock ) { break; } else { TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "loco %s cannot lock blockgroup %s with block %s because there is no block free. [%s]", LocoId, wLink.getid(data->props), BlockId, wLinkCond.getfree(cond)); condOK = False; grouplocked = False; data->firstBlock = NULL; data->firstLoco = NULL; __rewind(inst, LocoId); } } cond = wLink.nextlinkcond(data->props, cond); } if( condOK ) { TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "loco %s locked blockgroup %s with block %s", LocoId, wLink.getid(data->props), BlockId); data->firstBlock = BlockId; data->firstLoco = LocoId; } } if( grouplocked && !MapOp.haskey(data->lockmap, LocoId) ) { MapOp.put( data->lockmap, LocoId, (obj)LocoId); } return grouplocked; } else if( MapOp.size(data->lockmap) > 0 && data->allowfollowup && data->firstBlock != NULL ) { if( StrOp.equals( BlockId, data->firstBlock) && MapOp.get(data->lockmap, LocoId) == NULL && !data->followupend ) { MapOp.put( data->lockmap, LocoId, (obj)LocoId); TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "loco %s locked blockgroup %s for followup starting in block %s", LocoId, wLink.getid(data->props), BlockId); if( data->maxfollowup > 0 && data->maxfollowup >= MapOp.size( data->lockmap ) ) { data->followupend = True; } return True; } else if( MapOp.get(data->lockmap, LocoId) == NULL ) { TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "loco %s not allowed to followup in blockgroup %s starting in block %s (max=%d/%d)", LocoId, wLink.getid(data->props), BlockId, MapOp.size( data->lockmap ), data->maxfollowup ); } } else { TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "loco %s cannot lock(%d) blockgroup %s for block %s, starting block is %s, followup is %s", LocoId, MapOp.size(data->lockmap), wLink.getid(data->props), BlockId, data->firstBlock!=NULL?data->firstBlock:"-", data->allowfollowup?"allowed":"not allowed"); } return False; }