#include "cache.h"#include "refs.h"intprefixcmp(constchar*str,constchar*prefix){for(;;str++,prefix++)if(!*prefix)return0;elseif(*str!=*prefix)return(unsignedchar)*prefix-(unsignedchar)*str;}intsuffixcmp(constchar*str,constchar*suffix){intlen=strlen(str),suflen=strlen(suffix);if(len<suflen)return-1;elsereturnstrcmp(str+len-suflen,suffix);}/* * Used as the default ->buf value, so that people can always assume * buf is non NULL and ->buf is NUL terminated even for a freshly * initialized strbuf. */charstrbuf_slopbuf[1];voidstrbuf_init(structstrbuf*sb,size_thint){sb->alloc=sb->len=0;sb->buf=strbuf_slopbuf;if(hint)strbuf_grow(sb,hint);}voidstrbuf_release(structstrbuf*sb){if(sb->alloc){free(sb->buf);strbuf_init(sb,0);}}char*strbuf_detach(structstrbuf*sb,size_t*sz){char*res;strbuf_grow(sb,0);res=sb->buf;if(sz)*sz=sb->len;strbuf_init(sb,0);returnres;}voidstrbuf_attach(structstrbuf*sb,void*buf,size_tlen,size_talloc){strbuf_release(sb);sb->buf=buf;sb->len=len;sb->alloc=alloc;strbuf_grow(sb,0);sb->buf[sb->len]='\0';}voidstrbuf_grow(structstrbuf*sb,size_textra){intnew_buf=!sb->alloc;if(unsigned_add_overflows(extra,1)||unsigned_add_overflows(sb->len,extra+1))die("you want to use way too much memory");if(new_buf)sb->buf=NULL;ALLOC_GROW(sb->buf,sb->len+extra+1,sb->alloc);if(new_buf)sb->buf[0]='\0';}voidstrbuf_trim(structstrbuf*sb){char*b=sb->buf;while(sb->len>0&&isspace((unsignedchar)sb->buf[sb->len-1]))sb->len--;while(sb->len>0&&isspace(*b)){b++;sb->len--;}memmove(sb->buf,b,sb->len);sb->buf[sb->len]='\0';}voidstrbuf_rtrim(structstrbuf*sb){while(sb->len>0&&isspace((unsignedchar)sb->buf[sb->len-1]))sb->len--;sb->buf[sb->len]='\0';}voidstrbuf_ltrim(structstrbuf*sb){char*b=sb->buf;while(sb->len>0&&isspace(*b)){b++;sb->len--;}memmove(sb->buf,b,sb->len);sb->buf[sb->len]='\0';}structstrbuf**strbuf_split_buf(constchar*str,size_tslen,intterminator,intmax){structstrbuf**ret=NULL;size_tnr=0,alloc=0;structstrbuf*t;while(slen){intlen=slen;if(max<=0||nr+1<max){constchar*end=memchr(str,terminator,slen);if(end)len=end-str+1;}t=xmalloc(sizeof(structstrbuf));strbuf_init(t,len);strbuf_add(t,str,len);ALLOC_GROW(ret,nr+2,alloc);ret[nr++]=t;str+=len;slen-=len;}ALLOC_GROW(ret,nr+1,alloc);/* In case string was empty */ret[nr]=NULL;returnret;}voidstrbuf_list_free(structstrbuf**sbs){structstrbuf**s=sbs;while(*s){strbuf_release(*s);free(*s++);}free(sbs);}intstrbuf_cmp(conststructstrbuf*a,conststructstrbuf*b){intlen=a->len<b->len?a->len:b->len;intcmp=memcmp(a->buf,b->buf,len);if(cmp)returncmp;returna->len<b->len?-1:a->len!=b->len;}voidstrbuf_splice(structstrbuf*sb,size_tpos,size_tlen,constvoid*data,size_tdlen){if(unsigned_add_overflows(pos,len))die("you want to use way too much memory");if(pos>sb->len)die("`pos' is too far after the end of the buffer");if(pos+len>sb->len)die("`pos + len' is too far after the end of the buffer");if(dlen>=len)strbuf_grow(sb,dlen-len);memmove(sb->buf+pos+dlen,sb->buf+pos+len,sb->len-pos-len);memcpy(sb->buf+pos,data,dlen);strbuf_setlen(sb,sb->len+dlen-len);}voidstrbuf_insert(structstrbuf*sb,size_tpos,constvoid*data,size_tlen){strbuf_splice(sb,pos,0,data,len);}voidstrbuf_remove(structstrbuf*sb,size_tpos,size_tlen){strbuf_splice(sb,pos,len,NULL,0);}voidstrbuf_add(structstrbuf*sb,constvoid*data,size_tlen){strbuf_grow(sb,len);memcpy(sb->buf+sb->len,data,len);strbuf_setlen(sb,sb->len+len);}voidstrbuf_adddup(structstrbuf*sb,size_tpos,size_tlen){strbuf_grow(sb,len);memcpy(sb->buf+sb->len,sb->buf+pos,len);strbuf_setlen(sb,sb->len+len);}voidstrbuf_addf(structstrbuf*sb,constchar*fmt,...){va_listap;va_start(ap,fmt);strbuf_vaddf(sb,fmt,ap);va_end(ap);}voidstrbuf_vaddf(structstrbuf*sb,constchar*fmt,va_listap){intlen;va_listcp;if(!strbuf_avail(sb))strbuf_grow(sb,64);va_copy(cp,ap);len=vsnprintf(sb->buf+sb->len,sb->alloc-sb->len,fmt,cp);va_end(cp);if(len<0)die("BUG: your vsnprintf is broken (returned %d)",len);if(len>strbuf_avail(sb)){strbuf_grow(sb,len);len=vsnprintf(sb->buf+sb->len,sb->alloc-sb->len,fmt,ap);if(len>strbuf_avail(sb))die("BUG: your vsnprintf is broken (insatiable)");}strbuf_setlen(sb,sb->len+len);}voidstrbuf_expand(structstrbuf*sb,constchar*format,expand_fn_tfn,void*context){for(;;){constchar*percent;size_tconsumed;percent=strchrnul(format,'%');strbuf_add(sb,format,percent-format);if(!*percent)break;format=percent+1;if(*format=='%'){strbuf_addch(sb,'%');format++;continue;}consumed=fn(sb,format,context);if(consumed)format+=consumed;elsestrbuf_addch(sb,'%');}}size_tstrbuf_expand_dict_cb(structstrbuf*sb,constchar*placeholder,void*context){structstrbuf_expand_dict_entry*e=context;size_tlen;for(;e->placeholder&&(len=strlen(e->placeholder));e++){if(!strncmp(placeholder,e->placeholder,len)){if(e->value)strbuf_addstr(sb,e->value);returnlen;}}return0;}voidstrbuf_addbuf_percentquote(structstrbuf*dst,conststructstrbuf*src){inti,len=src->len;for(i=0;i<len;i++){if(src->buf[i]=='%')strbuf_addch(dst,'%');strbuf_addch(dst,src->buf[i]);}}size_tstrbuf_fread(structstrbuf*sb,size_tsize,FILE*f){size_tres;size_toldalloc=sb->alloc;strbuf_grow(sb,size);res=fread(sb->buf+sb->len,1,size,f);if(res>0)strbuf_setlen(sb,sb->len+res);elseif(oldalloc==0)strbuf_release(sb);returnres;}ssize_tstrbuf_read(structstrbuf*sb,intfd,size_thint){size_toldlen=sb->len;size_toldalloc=sb->alloc;strbuf_grow(sb,hint?hint:8192);for(;;){ssize_tcnt;cnt=xread(fd,sb->buf+sb->len,sb->alloc-sb->len-1);if(cnt<0){if(oldalloc==0)strbuf_release(sb);elsestrbuf_setlen(sb,oldlen);return-1;}if(!cnt)break;sb->len+=cnt;strbuf_grow(sb,8192);}sb->buf[sb->len]='\0';returnsb->len-oldlen;}#define STRBUF_MAXLINK (2*PATH_MAX)intstrbuf_readlink(structstrbuf*sb,constchar*path,size_thint){size_toldalloc=sb->alloc;if(hint<32)hint=32;while(hint<STRBUF_MAXLINK){intlen;strbuf_grow(sb,hint);len=readlink(path,sb->buf,hint);if(len<0){if(errno!=ERANGE)break;}elseif(len<hint){strbuf_setlen(sb,len);return0;}/* .. the buffer was too small - try again */hint*=2;}if(oldalloc==0)strbuf_release(sb);return-1;}intstrbuf_getwholeline(structstrbuf*sb,FILE*fp,intterm){intch;if(feof(fp))returnEOF;strbuf_reset(sb);while((ch=fgetc(fp))!=EOF){strbuf_grow(sb,1);sb->buf[sb->len++]=ch;if(ch==term)break;}if(ch==EOF&&sb->len==0)returnEOF;sb->buf[sb->len]='\0';return0;}intstrbuf_getline(structstrbuf*sb,FILE*fp,intterm){if(strbuf_getwholeline(sb,fp,term))returnEOF;if(sb->buf[sb->len-1]==term)strbuf_setlen(sb,sb->len-1);return0;}intstrbuf_getwholeline_fd(structstrbuf*sb,intfd,intterm){strbuf_reset(sb);while(1){charch;ssize_tlen=xread(fd,&ch,1);if(len<=0)returnEOF;strbuf_addch(sb,ch);if(ch==term)break;}return0;}intstrbuf_read_file(structstrbuf*sb,constchar*path,size_thint){intfd,len;fd=open(path,O_RDONLY);if(fd<0)return-1;len=strbuf_read(sb,fd,hint);close(fd);if(len<0)return-1;returnlen;}voidstrbuf_add_lines(structstrbuf*out,constchar*prefix,constchar*buf,size_tsize){while(size){constchar*next=memchr(buf,'\n',size);next=next?(next+1):(buf+size);strbuf_addstr(out,prefix);strbuf_add(out,buf,next-buf);size-=next-buf;buf=next;}strbuf_complete_line(out);}voidstrbuf_addstr_xml_quoted(structstrbuf*buf,constchar*s){while(*s){size_tlen=strcspn(s,"\"<>&");strbuf_add(buf,s,len);s+=len;switch(*s){case'"':strbuf_addstr(buf,"&quot;");break;case'<':strbuf_addstr(buf,"&lt;");break;case'>':strbuf_addstr(buf,"&gt;");break;case'&':strbuf_addstr(buf,"&amp;");break;case0:return;}s++;}}staticintis_rfc3986_reserved(charch){switch(ch){case'!':case'*':case'\'':case'(':case')':case';':case':':case'@':case'&':case'=':case'+':case'$':case',':case'/':case'?':case'#':case'[':case']':return1;}return0;}staticintis_rfc3986_unreserved(charch){returnisalnum(ch)||ch=='-'||ch=='_'||ch=='.'||ch=='~';}staticvoidstrbuf_add_urlencode(structstrbuf*sb,constchar*s,size_tlen,intreserved){strbuf_grow(sb,len);while(len--){charch=*s++;if(is_rfc3986_unreserved(ch)||(!reserved&&is_rfc3986_reserved(ch)))strbuf_addch(sb,ch);elsestrbuf_addf(sb,"%%%02x",ch);}}voidstrbuf_addstr_urlencode(structstrbuf*sb,constchar*s,intreserved){strbuf_add_urlencode(sb,s,strlen(s),reserved);}intprintf_ln(constchar*fmt,...){intret;va_listap;va_start(ap,fmt);ret=vprintf(fmt,ap);va_end(ap);if(ret<0||putchar('\n')==EOF)return-1;returnret+1;}intfprintf_ln(FILE*fp,constchar*fmt,...){intret;va_listap;va_start(ap,fmt);ret=vfprintf(fp,fmt,ap);va_end(ap);if(ret<0||putc('\n',fp)==EOF)return-1;returnret+1;}