//--------------|--------------------------------------------- HXRET hxput(HXFILE * hp, char const *recp, int leng) { HXLOCAL loc, *locp = &loc; if (!hp || leng < 0 || !recp || leng > hxmaxrec(hp) || !(hp->mode & HX_UPDATE) || !hp->test) return HXERR_BAD_REQUEST; if (leng && !hx_test(hp, recp, leng)) return HXERR_BAD_RECORD; if (SCANNING(hp) && hx_diff(hp, recp, RECDATA(_hxcurrec(hp)))) return HXERR_BAD_REQUEST; ENTER(locp, hp, recp, 3); _hxlockset(locp, leng ? HIGH_LOCK : HEAD_LOCK); if (IS_MMAP(hp)) _hxremap(locp); int may_find = 1, loops = HX_MAX_CHAIN; int newsize = leng ? leng + sizeof(HXREC) : 0; HXBUF *currp = &locp->buf[0], *prevp = &locp->buf[1]; // If scanning is on an overflow page, and hxdel might // empty the page, hxput after hxnext can't just jump to // the right page, because (prevp) is not loaded, // so deleting currp would hard. _hxload(locp, currp, SCANNING(hp) && (leng || IS_HEAD(hp->buffer.pgno)) ? hp->buffer.pgno : locp->head); while (1) { int pos, hindpos, skip = 0; PAGENO nextpg = currp->next; if (!--loops) LEAVE(locp, HXERR_BAD_FILE); // Search for the key (an old record to be deleted). // If SCANNING: the file is locked, and the matching // record must be there. pos = !may_find ? -1 : !SCANNING(hp) ? _hxfind(locp, currp, locp->hash, recp, &hindpos) : currp->pgno == hp->buffer.pgno ? hp->currpos : -1; if (pos >= 0) { char *oldp = currp->data + pos; COUNT oldsize = RECSIZE(oldp); int delta = newsize - oldsize; locp->ret = RECLENG(oldp); may_find = 0; assert(!currp->delta); currp->delpos = pos; currp->delta = delta; if (!newsize) { // hxdel or remove after inserted previously. _hxremove(currp, pos, oldsize); currp->recs--; if (SCANNING(hp)) hp->recsize = 0; } else if (FITS(hp, currp, delta, 0)) { // replace if (delta) { memmove(oldp + newsize, oldp + oldsize, currp->used - pos - oldsize); currp->used += delta; STSH(leng, oldp + sizeof(PAGENO)); if (SCANNING(hp)) hp->recsize = newsize; DEINDEX(currp); // force indexify } memcpy(oldp + sizeof(HXREC), recp, leng); STAIN(currp); newsize = 0; } else if (SCANNING(hp)) { // At this point we are stuck: if we delete the old copy of // the record, we are committed to inserting the new copy // somewhere else, but that might require changing links // or even growing the file: a NO-NO during a hxnext scan. LEAVE(locp, HXERR_BAD_REQUEST); } else { // Delete old version and continue (insert elsewhere). _hxremove(currp, pos, oldsize); currp->recs--; } } if (currp->used && !IS_HEAD(currp->pgno) && SHRUNK(prevp)) skip = !_hxshift(locp, locp->head, 0, currp, prevp, NULL); // Insert the new record if it fits. if (newsize && FITS(hp, currp, newsize, 1)) { HXREC hdr; STLG(locp->hash, &hdr.hash); STSH(leng, &hdr.leng); _hxappend(currp, (char *)&hdr, sizeof hdr); _hxappend(currp, recp, leng); currp->recs++; newsize = 0; } // If the current page contains only data of OTHER heads // -- and hence, must be at the END of a chain -- // unlink it from this chain. If the page is empty, // unlink it AND put it in the freemap. if (IS_HEAD(currp->pgno)) { skip = 0; } else if (!currp->used) { skip = 1; _hxputfreed(locp, currp); if (SCANNING(hp) && hp->buffer.pgno == currp->pgno) hp->buffer.used = 0; } else if (currp->next || !SHRUNK(currp)) { skip = 0; } else if (!skip) { // If skip not set by _hxshift above... char const *rp, *ep; FOR_EACH_REC(rp, currp, ep) if (locp->head == _hxhead(locp, RECHASH(rp))) break; skip = rp == ep; // No recs for locp->head in this tail. } if (skip) LINK(prevp, nextpg); else SWAP(prevp, currp); sync_save(locp, currp); if (!newsize && !prevp->next) break; if (!newsize && !may_find && !SHRUNK(prevp)) break; if (prevp->next) { _hxload(locp, currp, prevp->next); continue; } // We are at the end of the chain, and rec not yet inserted. // Unlocking is necessary even if tail is not shared; // it may be hp->tail.pgno in some other process. if (!FILE_HELD(hp) && !IS_HEAD(prevp->pgno)) _hxunlock(locp, prevp->pgno, 1); // _hxshare/_hxfindfree may update the map (root etc). // Split MUST be locked before root, else risk deadlock. _hxlockset(locp, BOTH_LOCK); if (IS_MMAP(hp)) _hxremap(locp); // At this point assert: // - head is locked, split is locked, // - head matches hash, npages matches filesize. // After locking the split, no other process can change // the file size. may_find = 0; COUNT need = IS_HEAD(prevp->pgno) ? newsize : 0; if (!_hxshare(locp, currp, need) && !_hxgetfreed(locp, currp) && !_hxfindfree(locp, currp)) { // _hxgrow will zero samehead if it splits locp->head. PAGENO samehead = locp->head; // _hxgrow will change the file length. A concurrent // hxget/hxdel could miscalculate locp->head as // being the newly-added page. _hxlock(locp, locp->npages, 0); _hxgrow(locp, currp, need, &samehead); DEBUG3("head=%u samehead=%u", locp->head, samehead); if (!samehead) { _hxputfreed(locp, currp); _hxpoint(locp); _hxload(locp, currp, locp->head); loops = HX_MAX_CHAIN; continue; } } // _hxgrow may clobber prevp, so we reload it. Even if // prevp->pgno == locp->head, prevp may contain an // obsolete copy of the head page. The empty page is // always appended to head. _hxshare only returns true // if currp is head and currp->next is 0, so it can't // clobber it. _hxsave(locp, prevp); _hxload(locp, prevp, locp->head); LINK(currp, prevp->next); LINK(prevp, currp->pgno); currp->orig = DATASIZE(hp); // make SHRUNK be true }
exprt convert_integer_literal(const std::string &src) { bool is_unsigned=false, is_imaginary=false; unsigned long_cnt=0; unsigned width_suffix=0; unsigned base=10; for(unsigned i=0; i<src.size(); i++) { register char ch=src[i]; if(ch=='u' || ch=='U') is_unsigned=true; else if(ch=='l' || ch=='L') long_cnt++; else if(ch=='i' || ch=='I') { // This can be "1i128" in MS mode, // and "10i" (imaginary) for GCC. // If it's followed by a number, we do MS mode. if((i+1)<src.size() && isdigit(src[i+1])) width_suffix=atoi(src.c_str()+i+1); else is_imaginary=true; } else if(ch=='j' || ch=='J') is_imaginary=true; } mp_integer value; if(src.size()>=2 && src[0]=='0' && tolower(src[1])=='x') { // hex; strip "0x" base=16; std::string without_prefix(src, 2, std::string::npos); value=string2integer(without_prefix, 16); } else if(src.size()>=2 && src[0]=='0' && tolower(src[1])=='b') { // binary; strip "0x" // see http://gcc.gnu.org/onlinedocs/gcc/Binary-constants.html base=2; std::string without_prefix(src, 2, std::string::npos); value=string2integer(without_prefix, 2); } else if(src.size()>=2 && src[0]=='0') { // octal base=8; value=string2integer(src, 8); } else { // The default is base 10. value=string2integer(src, 10); } if(width_suffix!=0) { // this is a Microsoft extension irep_idt c_type; if(width_suffix<=config.ansi_c.int_width) c_type=is_unsigned?ID_unsigned_int:ID_signed_int; else if(width_suffix<=config.ansi_c.long_int_width) c_type=is_unsigned?ID_unsigned_long_int:ID_signed_long_int; else c_type=is_unsigned?ID_unsigned_long_long_int:ID_signed_long_long_int; typet type=typet(is_unsigned?ID_unsignedbv:ID_signedbv); type.set(ID_width, width_suffix); type.set(ID_C_c_type, c_type); exprt result=from_integer(value, type); result.set(ID_C_cformat, src); return result; } mp_integer value_abs=value; if(value<0) value_abs.negate(); bool is_hex_or_oct_or_bin=(base==8) || (base==16) || (base==2); #define FITS(width, signed) \ ((signed?!is_unsigned:(is_unsigned || is_hex_or_oct_or_bin)) && \ (power(2, signed?width-1:width)>value_abs)) unsigned width; bool is_signed=false; irep_idt c_type; if(FITS(config.ansi_c.int_width, true) && long_cnt==0) // int { width=config.ansi_c.int_width; is_signed=true; c_type=ID_signed_int; } else if(FITS(config.ansi_c.int_width, false) && long_cnt==0) // unsigned int { width=config.ansi_c.int_width; is_signed=false; c_type=ID_unsigned_int; } else if(FITS(config.ansi_c.long_int_width, true) && long_cnt!=2) // long int { width=config.ansi_c.long_int_width; is_signed=true; c_type=ID_signed_long_int; } else if(FITS(config.ansi_c.long_int_width, false) && long_cnt!=2) // unsigned long int { width=config.ansi_c.long_int_width; is_signed=false; c_type=ID_unsigned_long_int; } else if(FITS(config.ansi_c.long_long_int_width, true)) // long long int { width=config.ansi_c.long_long_int_width; is_signed=true; c_type=ID_signed_long_long_int; } else if(FITS(config.ansi_c.long_long_int_width, false)) // unsigned long long int { width=config.ansi_c.long_long_int_width; is_signed=false; c_type=ID_unsigned_long_long_int; } else { // Way too large. Should consider issuing a warning. width=config.ansi_c.long_long_int_width; if(is_unsigned) { is_signed=false; c_type=ID_unsigned_long_long_int; } else c_type=ID_signed_long_long_int; } typet type=typet(is_signed?ID_signedbv:ID_unsignedbv); type.set(ID_width, width); type.set(ID_C_c_type, c_type); exprt result; if(is_imaginary) { complex_typet complex_type; complex_type.subtype()=type; result=exprt(ID_complex, complex_type); result.operands().resize(2); result.op0()=gen_zero(type); result.op1()=from_integer(value, type); } else { result=from_integer(value, type); result.set(ID_C_cformat, src); } return result; }
exprt convert_integer_literal( const std::string &src, unsigned base) { bool is_unsigned=false; unsigned long_cnt=0; unsigned width_suffix=0; for(unsigned i=0; i<src.size(); i++) { register char ch=src[i]; if(ch=='u' || ch=='U') is_unsigned=true; else if(ch=='l' || ch=='L') long_cnt++; else if(ch=='i' || ch=='I') width_suffix=atoi(src.c_str()+i+1); } mp_integer value; if(base==10) { value=string2integer(src, 10); } else if(base==8) { value=string2integer(src, 8); } else if(base==16) { std::string without_prefix(src, 2, std::string::npos); value=string2integer(without_prefix, 16); } else assert(false); if(width_suffix!=0) { // this is a Microsoft extension typet type=typet(is_unsigned?ID_unsignedbv:ID_signedbv); type.set(ID_width, width_suffix); exprt result=from_integer(value, type); result.set(ID_C_cformat, src); return result; } mp_integer value_abs=value; if(value<0) value_abs.negate(); unsigned min_width=config.ansi_c.int_width; if(long_cnt==1) min_width=config.ansi_c.long_int_width; else if(long_cnt>=2) min_width=config.ansi_c.long_long_int_width; bool is_hex_or_oct=(base==8) || (base==16); #define FITS(width, signed) \ ((signed?!is_unsigned:(is_unsigned || is_hex_or_oct)) && \ (width>=min_width) && \ (power(2, signed?width-1:width)>value_abs)) unsigned width; bool is_signed=false; if(FITS(config.ansi_c.int_width, true)) // int { width=config.ansi_c.int_width; is_signed=true; } else if(FITS(config.ansi_c.int_width, false)) // unsigned int { width=config.ansi_c.int_width; is_signed=false; } else if(FITS(config.ansi_c.long_int_width, true)) // long int { width=config.ansi_c.long_int_width; is_signed=true; } else if(FITS(config.ansi_c.long_int_width, false)) // unsigned long int { width=config.ansi_c.long_int_width; is_signed=false; } else if(FITS(config.ansi_c.long_long_int_width, true)) // long long int { width=config.ansi_c.long_long_int_width; is_signed=true; } else if(FITS(config.ansi_c.long_long_int_width, false)) // unsigned long long int { width=config.ansi_c.long_long_int_width; is_signed=false; } else { // way too large width=config.ansi_c.long_long_int_width; } typet type=typet(is_signed?ID_signedbv:ID_unsignedbv); type.set(ID_width, width); exprt result=from_integer(value, type); result.set(ID_C_cformat, src); return result; }