char* GLineReader::getLine(FILE* stream, off_t& f_pos) { if (pushed) { pushed=false; return buf; } //reads a char at a time until \n and/or \r are encountered len=0; int c=0; while ((c=getc(stream))!=EOF) { if (len>=allocated-1) { allocated+=1024; GREALLOC(buf, allocated); } if (c=='\n' || c=='\r') { buf[len]='\0'; if (c=='\r') { //DOS file -- special case if ((c=getc(stream))!='\n') ungetc(c,stream); else f_pos++; } f_pos++; lcount++; return buf; } f_pos++; buf[len]=(char)c; len++; } //while i<buf_cap-1 if (c==EOF) { isEOF=true; if (len==0) return NULL; } buf[len]='\0'; lcount++; return buf; }
/* DOS/UNIX safer fgets : reads a text line from a (binary) file and update the file position accordingly and the buffer capacity accordingly. The given buf is resized to read the entire line in memory -- even when it's abnormally long */ char* fgetline(char* & buf, int& buf_cap, FILE *stream, off_t* f_pos, int* linelen) { //reads a char at a time until \n and/or \r are encountered int i=0; int c=0; off_t fpos=(f_pos!=NULL) ? *f_pos : 0; while ((c=getc(stream))!=EOF) { if (i>=buf_cap-1) { buf_cap+=1024; GREALLOC(buf, buf_cap); } if (c=='\n' || c=='\r') { if (c=='\r') { if ((c=getc(stream))!='\n') ungetc(c,stream); else fpos++; } fpos++; break; } fpos++; buf[i]=(char)c; i++; } //while i<buf_cap-1 if (linelen!=NULL) *linelen=i; if (f_pos!=NULL) *f_pos=fpos; if (c==EOF && i==0) return NULL; buf[i]='\0'; return buf; }
GArgs::GArgs(int argc, char* const argv[], char* format) { /* format is: <letter>[:] for e.g. p:hT <- -p testing -ptesting -h -T <string>= for e.g. PID=S= <- PID=50 S=3.5 This means that the = options, if present, must NEVER be given after dashed switches (non-value) directly */ //parse format string first: char* fstr=format; fmtcount=0; count=0; nonOptCount=0; nonOptPos=0; optPos=0; errarg=0; args=NULL; fmt=NULL; int fmtlen=strlen(format); while (fstr-format < fmtlen ) { int l=strcspn(fstr, ":="); if (fstr[l]=='\0') { //end of string reached //all previous chars are just switches: GREALLOC(fmt, (fmtcount+l)*sizeof(fmtdef)); //store each switches for (int i=0; i<l;i++) { GCALLOC(fmt[fmtcount+i].opt, 2); //one char length fmt[fmtcount+i].opt[0]=fstr[i]; fmt[fmtcount+i].type = 0; } fmtcount+=l; break; } else { if (fstr[l]==':') { //fstr[l-1] is an argument, but all the previous are just switches GREALLOC(fmt, (fmtcount+l)*sizeof(fmtdef)); //store each switches AND the option for (int i=0; i<l;i++) { GCALLOC(fmt[fmtcount+i].opt, 2); //one char length fmt[fmtcount+i].opt[0]=fstr[i]; fmt[fmtcount+i].type = (i==l-1)?1:0; } fmtcount+=l; } else { // fstr[l]=='=' case! //all these chars are one = style argument GREALLOC(fmt, (fmtcount+1)*sizeof(fmtdef)); GMALLOC(fmt[fmtcount].opt, l+1); strncpy(fmt[fmtcount].opt, fstr, l); fmt[fmtcount].opt[l]='\0'; fmt[fmtcount].type=2; fmtcount++; } fstr+=l+1; } } //---- that was the parsing of the format string //now parse the arguments based on given format specification int p=1; //skip program name int f=0; //GMessage("argc=%d\n", argc); while (p<argc) { if (argv[p][0]=='-') { //dashed argument? int cpos=1; char c=argv[p][cpos]; if (c=='\0') { //special case, plain argument '-' GREALLOC(args, (count+1)*sizeof(argdata)); args[count].opt=NULL; GCALLOC(args[count].value, 2); args[count].value[0]='-'; count++; nonOptCount++; } else { //dashed argument or switch COLLAPSED: if ((f=validOpt(c))>=0) { if (fmt[f].type==0) {//switch type GREALLOC(args, (count+1)*sizeof(argdata)); GCALLOC(args[count].opt, 2); args[count].opt[0]=c; GCALLOC(args[count].value, 1); count++; // only switches can be grouped with some other switches or options if (argv[p][cpos+1]!='\0') { cpos++; c=argv[p][cpos]; goto COLLAPSED; } } else if (fmt[f].type==1) { //dash argument GREALLOC(args, (count+1)*sizeof(argdata)); GCALLOC(args[count].opt, 2); args[count].opt[0]=c; if (argv[p][cpos+1]=='\0') { if (p+1<argc) { //value is the whole next argument p++; GMALLOC(args[count].value, strlen(argv[p])+1); strcpy(args[count].value, argv[p]); } else { errarg=p; return; } } else { //value immediately follows the dash-option GMALLOC(args[count].value, strlen(argv[p])-cpos); strcpy(args[count].value, (argv[p]+cpos+1)); //GMessage("args[%d].value = '%s'",count, args[count].value); } count++; } else {//inconsistent type errarg=p; return; } } //was validOpt else { //option not found in format definition! errarg=p; return; } } } else {//not a dashed argument char* e=strchr(argv[p],'='); if (e!=NULL && strchr(format,'=')!=NULL && e!=argv[p] && *(e-1)!='\\') { //this must be an '=' option //yet the '=' char can be preceded by a '\' in order to not be parsed //as a = option char part[30]; strncpy(part, argv[p], e-argv[p]); part[e-argv[p]]='\0'; if ((f=validOpt(part))>=0 && fmt[f].type==2) { GREALLOC(args, (count+1)*sizeof(argdata)); args[count].opt=Gstrdup(part); if (strlen(argv[p])-strlen(part)>0) { GMALLOC(args[count].value, strlen(argv[p])-strlen(part)+1); strcpy(args[count].value, e+1); } else { args[count].value=NULL; } count++; } else { //error - format does not match this '=' argument errarg=p; return; } } else { //it seems it's just a plain argument, like a filename, etc. GREALLOC(args, (count+1)*sizeof(argdata)); args[count].opt=NULL; //it's not an option args[count].value=Gstrdup(argv[p]); count++; nonOptCount++; } } p++; } }
char* AceParser::readSeq(LytSeqInfo* sqinfo) { //assumes the next line is where a sequence starts! //stops at the next empty line encountered char* buf; static char rlenbuf[12]= {0,0,0,0,0,0,0,0,0,0,0,0}; //buffer for parsing the gap length int rlenbufacc=0; //how many digits accumulated in rlenbuf so far int buflen=512; GMALLOC(buf, buflen); //this MUST be freed by the caller buf[0]='\0'; int accrd=0; //accumulated read length so far -- excludes interseg gaps! int rgpos=0; //accumulated offset including interseg gaps! char *r = linebuf->getLine(f,f_pos); int linelen=linebuf->length(); char r_splice=0, l_splice=0; while (linelen>0) { if (r==NULL) { GMessage("AceParser: error reading sequence data\n"); return NULL; } //-- pass the line content for accumulation int i=0; while (r[i]) { while (r[i] && isdigit(r[i])) { rlenbuf[rlenbufacc]=r[i]; rlenbufacc++; i++; } if (r[i]==0) break; //end of line reached already //now r[i] is surely a non-digit char if (rlenbufacc>0) { //have we just had a number before? rlenbuf[rlenbufacc]=0; if (r[i]=='=' || r[i]=='-') { i++; if (r[i]==0) break; } else { //check for splice site markers for this introns if (r[i]=='('||r[i]=='[') { l_splice=r[i]; i++; if (r[i]==0) break; } if (r[i]==')'||r[i]==']') { r_splice=r[i]; i++; if (r[i]==0) break; } }//splice check add_intron(buf, accrd, rgpos, rlenbuf, sqinfo, l_splice, r_splice); rlenbufacc=0; r_splice=0; l_splice=0; //i++;//skip the gap character } //check for digits here and break the linebuf as needed int bi=i; //start of non-digit run while (r[i] && !isdigit(r[i])) i++; int nl=(i-bi); //length of non-digit run if (nl>0) { int si=accrd; accrd+=nl; rgpos+=nl; if (accrd>=buflen-1) { buflen=accrd+512; GREALLOC(buf,buflen); } //append these non-digit chars for(int b=0; b<nl; b++) { buf[si+b]=r[bi+b]; } }//non-digit run } //while line chars /* //-- append the line to buf accrd+=linelen; if (accrd>=buflen) { buflen+=1024; GREALLOC(buf,buflen); } strcat(buf, r); */ r=linebuf->getLine(f,f_pos); linelen=linebuf->length(); }//while linelen>0 //add the 0-ending buf[accrd]=0; return buf; }
int GArgs::parseArgs(bool nodigitopts) { int p=1; //skip program name int f=0; while (p<_argc) { // silly patch for annnoying MacOS gdb/eclipse issues: #if defined(__APPLE__) && defined(DEBUG) dbg_dequote(_argv[p]); #endif //-- if (_argv[p][0]=='-' && (_argv[p][1]==0 || _argv[p][1]!='-')) { //single-dash argument int cpos=1; char c=_argv[p][cpos]; if (c==0 || (nodigitopts && isdigit(c)) || (c=='.' && isdigit(_argv[p][cpos+1]))) { //special case: plain argument '-' or just a negative number GREALLOC(args, (count+1)*sizeof(argdata)); args[count].opt=NULL; args[count].fmti=-1; if (c==0) { GCALLOC(args[count].value, 2); args[count].value[0]='-'; } else { //negative number given args[count].value=Gstrdup(_argv[p]); } count++; nonOptCount++; } else { //single-dash argument or switch COLLAPSED: if ((f=validShortOpt(c))>=0) { GREALLOC(args, (count+1)*sizeof(argdata)); GCALLOC(args[count].opt, 2); args[count].opt[0]=c; args[count].fmti=f; if (!fmt[f].req_value) {//switch type GCALLOC(args[count].value,1);//so getOpt() functions would not return NULL count++; // only switches can be grouped with some other switches or options if (_argv[p][cpos+1]!='\0') { cpos++; c=_argv[p][cpos]; goto COLLAPSED; } } else { //single-dash argument followed by a value if (_argv[p][cpos+1]=='\0') { if (p+1<_argc && _argv[p+1][0]!=0) { //value is the whole next argument p++; #if defined(__APPLE__) && defined(DEBUG) dbg_dequote(_argv[p]); #endif args[count].value=Gstrdup(_argv[p]); } else { errarg=p; err_valmissing=true; return errarg; } } else { //value immediately follows the dash-option args[count].value=Gstrdup(_argv[p]+cpos+1); } count++; } } //was validShortOpt else { //option not found in format definition! errarg=p; return errarg; } } } //-single-dash else {//not a single-dash argument char* ap=_argv[p]; bool is_longopt=false; if (*ap=='-' && ap[1]=='-') { //double-dash option is_longopt=true; ap+=2; } char* e=strchr(ap+1,'='); while (e!=NULL && *(e-1)=='\\') e=strchr(e,'='); if (e==NULL && is_longopt) { e=ap; while (*e!=0 && *e!=' ') e++; //e will be on eos or next space } if (e!=NULL && e>ap) { //this must be a long option //e is on eos, space or '=' if ((f=validLongOpt(ap,e-1))>=0) { GREALLOC(args, (count+1)*sizeof(argdata)); args[count].opt=Gstrdup(ap,e-1); args[count].fmti=f; if (fmt[f].req_value) { if (*e==0) { //value is the next argument if (p+1<_argc && _argv[p+1][0]!=0) { p++; args[count].value=Gstrdup(_argv[p]); } else { errarg=p; err_valmissing=true; return errarg; } } else { //value is in the same argument //while (*e!=0 && (*e==' ' || *e=='=')) e++; if (*e=='=') e++; if (*e==0) { errarg=p; err_valmissing=true; return errarg; } args[count].value=Gstrdup(e); } } //value required else { //no value expected GCALLOC(args[count].value,1); //do not return NULL } count++; } else { //error - this long argument not recognized errarg=p; return errarg; } } else { //just a plain non-option argument if (e==ap) { //i.e. just "--" errarg=p; return errarg; } GREALLOC(args, (count+1)*sizeof(argdata)); args[count].opt=NULL; //it's not an option args[count].value=Gstrdup(_argv[p]); args[count].fmti=-1; count++; nonOptCount++; } } p++;//check next arg string } //while arguments return errarg; }
GArgs::GArgs(int argc, char* argv[], const char* format, bool nodigitopts) { /* format can be: <string>{;|=} e.g. disable-test;PID=S= for --disable-test PID=50 (or --PID 50) S=3.5 etc. <letter>[:] e.g. p:hT for -p testing (or -ptesting) -h -T */ const char* fstr=format; fmtcount=0; count=0; nonOptCount=0; nonOptPos=0; optPos=0; errarg=0; err_valmissing=false; args=NULL; fmt=NULL; _argc=argc; _argv=argv; int fmtlen=strlen(format); //---- first parse the format string while (fstr-format < fmtlen ) { int l=strcspn(fstr, ";=:"); if (fstr[l]==0) { //end of string reached //all previous chars are just switches: GREALLOC(fmt, (fmtcount+l)*sizeof(fmtdef)); //store each switch for (int i=0; i<l;i++) { fmt[fmtcount+i].longopt=NULL; fmt[fmtcount+i].opt=fstr[i]; fmt[fmtcount+i].req_value = false; fmt[fmtcount+i].code=fmtcount+i+1; } fmtcount+=l; break; } else { if (fstr[l]==':') { //fstr[l-1] is an argument, but all the previous are just switches GREALLOC(fmt, (fmtcount+l)*sizeof(fmtdef)); //store each switch AND the option for (int i=0; i<l;i++) { fmt[fmtcount+i].longopt=NULL; //one char length fmt[fmtcount+i].opt=fstr[i]; fmt[fmtcount+i].req_value = (i==l-1); fmt[fmtcount+i].code=fmtcount+i+1; } fmtcount+=l; } else { // fstr[l]=='=' or ';' GREALLOC(fmt, (fmtcount+1)*sizeof(fmtdef)); fmt[fmtcount].longopt=Gstrdup(fstr, fstr+l-1); fmt[fmtcount].opt=0; fmt[fmtcount].req_value=(fstr[l]=='='); fmt[fmtcount].code=fmtcount+1; fmtcount++; } fstr+=l+1; } } //-- now parse the arguments based on the given format specification parseArgs(nodigitopts); }