Home » Extra libraries, Code snippets, applications etc. » U++ users applications in progress and useful code snippets, including reference examples! » SetLineKeyValue - in memory (a helper fn to set key/value through regular String - ini like) 
	
		
		
			| SetLineKeyValue - in memory [message #47907] | 
			Fri, 21 April 2017 17:55   | 
		 
		
			
				
				
				
					
						  
						luoganda
						 Messages: 216 Registered: November 2016 
						
					 | 
					Experienced Member  | 
					 | 
		 
		 
	 | 
 
	
		
Empty lines and (// or ;) at start of line are ignored
chkForEqualSign:
  when true - there must be '=' after key(even if it's empty)
  when false - line can contain only a key(withNo=), but it's added before fn returns
NewLine: \n, \r and \r\n are accepted
Update:
  -func now accepts key that has some kind of header,eg SetLineKeyValue(lines,"key","value"); while
   lines has somewhere 'keyAnyHdr'(eg keyLine1\nLine2=value, or key:flg:20,flg2:coffee=value)
  -added 2helperfuncs for pack 2vals in value - chk down code - can be used eg with WithDropChoice<EditString>
 
 
bool SetLineKeyValue(String& lines,const String& key,const String& val,dword startAt=0,bool chkForEqualSign=true,dword *chkForExistanceOnly=0,String *prevBack=0){
  if(!lines.GetCount())return false;
  ASSERT(key.GetCount());
  ASSERT(startAt<lines.GetCount());
  register char *p=(char*)~lines+startAt;
  int64 fpos; char *pst;
  int pos,off,linenum;
  if(prevBack)*prevBack="";
  while(*p){
    fpos=p-~lines; linenum=0;pos=0;pst=p;
    while(*p){if(*p=='\r'&&*p=='\n'){linenum=p-pst;break;}if(*p=='\r'||*p=='\n'){linenum=p-pst;break;}if(*p=='=')pos=p-pst; ++p;}
    if(*p)++p;
    if(linenum==0 && 0==(linenum=p-(*p?1:0)-pst))continue;
    if(linenum&&*pst==';'||linenum>=2&&pst[0]=='/'&&pst[1]=='/')continue;
    if(chkForEqualSign&&!pos)continue;
    if(linenum<key.GetCount()+(chkForEqualSign?1:0)||0!=memcmp(pst,~key,key.GetCount()))continue;
    if(prevBack&&linenum>pos/*key.GetCount()*/+1)*prevBack=lines.Mid(fpos+pos/*key.GetCount()*/+1,linenum-(/*key.GetCount()*/pos+1));
    if(chkForExistanceOnly){*chkForExistanceOnly=(dword)(int32)fpos;return true;}
    fpos+=/*key.GetCount()*/pos+1;
    off=(/*key.GetCount()*/pos+1+val.GetCount())-linenum; //speedup a litle - don't insert/remove twice
    if(off<0)lines.Remove(fpos,abs(off)); else if(off)lines.Insert(fpos,"R",off);
    *(char*)lines.GetIter(fpos-1)='='; memcpy((void*)lines.GetIter(fpos),~val,val.GetCount());
    return true;
    }
  /*
  StringStream ss(lines);
  while(!ss.IsEof()){
    fpos=ss.GetPos();
    line=ss.GetLine();if(chkForEqualSign&&-1==(pos=line.Find('=')))continue;
    if(!line.StartsWith(key+(chkForEqualSign?"=":"")))continue;
    if(pos==-1){insEq;pos=key.GetCount();}
    off=(key.GetCount()+1+val.GetCount())-line.GetCount(); //speedup a litle - don't insert/remove twice
    fpos+=key.GetCount();
    if(off<0)lines.Remove(fpos,abs(off)); else if(off)lines.Insert(fpos," ",off);
    *(char*)lines.GetIter(fpos)='='; memcpy((void*)lines.GetIter(fpos+1),~val,val.GetCount());
    //lines
    break;
    }*/
  return false;
}
 
 
//when editor that edit this can't handle fe \1 chars, use something else 
//errline is just an errorlike func PromptOK can be used instead of it 
inline String SLKVValue2Pack(const String& val1,const String& val2,String withCh="\1"){return val1+withCh+val2;}
static String SLKVValue2Get(const String& val,String *val1=0,const String& sepCh="\1",bool mustBeSepCh=false){
  /*if(val1)*val1="";ifval1==in*/int i=val.ReverseFind(sepCh);
  if(i==-1){if(mustBeSepCh){errline(el,"could not find SLKVValue2Get sepChar");if(val1)*val1="";return String::GetVoid();}if(val1)*val1=val; return "";}
  String ret=val.Mid(i+sepCh.GetCount()); if(val1)*val1=val.Mid(0,i&&sepCh.GetCount()==1&&val[i]=='\n'&&val[i-1]=='\r'?i-1:i); return ret;
}
 
		
		
		[Updated on: Mon, 01 May 2017 20:52] Report message to a moderator  
 |  
	| 
		
	 | 
 
 
 |  
	
		
		
			| Re: SetLineKeyValue - in memory [message #47920 is a reply to message #47907] | 
			Mon, 24 April 2017 10:42    | 
		 
		
			
				
				
				
					
						  
						luoganda
						 Messages: 216 Registered: November 2016 
						
					 | 
					Experienced Member  | 
					 | 
		 
		 
	 | 
 
	
		These can be used when info is known to be contignous, 
errline is just an errorlike func PromptOK can be used instead of it 
All are readOnly funcs 
 
inline bool SLKVSkipEmpty(StringStream &ss){
  bool is=0;
  while(!ss.IsEof()&&(ss.Peek()=='\n'||ss.Peek()=='\r'||ss.Peek()==';'||*(word*)ss.PeekPtr(2)==*(word*)"//")){
    is=1;ss.GetLine();
  }
  return is;
}
inline String SLKVKey(StringStream &ss,bool withEqSign=true){
  String ln=ss.GetLine();
  int i=ln.Find('=');if(i==-1){if(withEqSign){errline(el,"char '=' not found near %s",~ln);return String::GetVoid();}}else ln=ln.Mid(0,i);
  return ln;
}
inline String SLKVValue(StringStream &ss){
  String ln=ss.GetLine();
  int i=ln.Find('=');if(i==-1){errline(el,"char '=' not found near %s",~ln);return String::GetVoid();}
  return ln.Mid(i+1);
}
inline bool SLKVKeyValue(StringStream &ss,String& key,String& val,bool withEqSign=true){
  key=val="";String ln=ss.GetLine();
  int i=ln.Find('=');if(i==-1){if(withEqSign){errline(el,"char '=' not found near %s",~ln);return false;}key=ln;return true;}
  key=ln.Mid(0,i); val=ln.Mid(i+1);
  return true;
}
 
		
		
		[Updated on: Tue, 25 April 2017 23:09] Report message to a moderator  
 |  
	| 
		
	 | 
 
 
 |  
	| 
		
 |  
	| 
		
 |  
	| 
		
 |  
	
		
		
			| Re: SetLineKeyValue - in memory:update2 [message #47979 is a reply to message #47907] | 
			Sun, 30 April 2017 14:33    | 
		 
		
			
				
				
				
					
						  
						luoganda
						 Messages: 216 Registered: November 2016 
						
					 | 
					Experienced Member  | 
					 | 
		 
		 
	 | 
 
	
		Using SetLineKeyValue with StringStream: 
-StringStream: a few funcs should be added to use this,chk down 
 
If you read this, there was also original func update - chk original message 
Usage:
-to speedup and data(lines) is/are known to be contignous,then;
   SetLineKeyValue(ss,"a key","a value");
   ss.GetLine(); //advance pos to next line,so next is found immediatelly
-when keys(data) is not known to be contignous(butAreSearchable),then;
   SetLineKeyValue(ss,"a key","a value"); //just this
 
 
bool SetLineKeyValue(StringStream& ss,const String& key,const String& val,bool chkForEqualSign,dword *chkForExistanceOnly,String *prevBack){
  if(ss.IsEof())return false;
  register char *p=(char*)ss.PeekPtr();
  int64 fpos=ss.GetPos();ss.Seek(0);
  char *pst,*porg=p,*ssSt=(char*)ss.PeekPtr();
  int pos,off,linenum;
  ss.Seek(fpos);
  if(prevBack)*prevBack="";
  while(*p){
    fpos=ss.GetPos(); linenum=0;pos=0;pst=p;
    while(*p){if(*p=='\r'&&*p=='\n'){linenum=p-pst/*p-~lines-fpos*/;break;}if(*p=='\r'||*p=='\n'){linenum=p-pst/*p-~lines-fpos*/;break;}if(*p=='=')pos=p-pst/*p-~lines-fpos*/; ++p;}
    if(*p!=0)++p;
    if(linenum==0 && 0==(linenum=p-(*p?1:0)-pst/*~lines-fpos*/))continue;
    if(linenum&&*pst==';'||linenum>=2&&pst[0]=='/'&&pst[1]=='/')continue;
    if(chkForEqualSign&&!pos)continue;
    if(linenum<key.GetCount()+(chkForEqualSign?1:0)||0!=memcmp(pst,~key,key.GetCount()))continue;if(chkForEqualSign&&pst[key.GetCount()]!='=')continue;
    if(prevBack&&linenum>fpos+/*key.GetCount()*/pos+1)*prevBack=String(pst+/*key.GetCount()*/pos+1/*lines.Mid(fpos+key.GetCount()+1*/,linenum-(/*key.GetCount()*/pos+1));
    if(chkForExistanceOnly){*chkForExistanceOnly=(dword)(int32)fpos;return true;}
    fpos+=/*key.GetCount()*/pos+1;
    off=(/*key.GetCount()*/pos+1+val.GetCount())-linenum; //speedup a litle - don't insert/remove twice
    if(off<0)ss.Remove(abs(off),fpos); else if(off)ss.Insert('R',off,fpos);
    *(char*)ss.GetIter(fpos-1)='='; memcpy((void*)ss.GetIter(fpos),~val,val.GetCount());
    //if(off<0)slns. lines.Remove(fpos,abs(off)); else if(off)lines.Insert(fpos," ",off);
    //*(char*)lines.GetIter(fpos-1)='='; memcpy((void*)lines.GetIter(fpos),~val,val.GetCount());
    return true;
    }
  return false;
}
 
 
StringStream added code for this - but should be revisited; 
StringStream has Put methods but no Remove(Pos isTakenInConsideration), here they are - but are not yet 100% tested 
optimally it should be added between SetSize and Open 
	virtual  void  Insert(int ch,int num=1,int at=-1);
	virtual  void  Insert(const String& str,int at=-1);
	virtual  void  Remove(int num=1,int at=-1);
	virtual  const byte* GetIter(int at){ASSERT(at<GetSize());return buffer+at;}
//cpp files
void StringStream::Insert(int ch,int num,int at){
	Insert(String(ch,num),at);
}
void StringStream::Insert(const String& str,int at){
	if(at==-1)at=GetPos();
	ASSERT(at+str.GetCount()<=GetSize());
	SetReadMode(); //justToKnowWhichToUse...
	int64 npos=at<GetPos()?GetPos()+GetPos()-at:GetPos();
	data.Insert(at,str);
	buffer = (byte *) ~data;  //<=this should be checked,may point to another unknown buffer
	//ptr = wrlim = buffer;
	rdlim = buffer + data.GetCount();
	Seek(npos);
}
void StringStream::Remove(int num,int at){
	if(at==-1)at=GetPos();
	ASSERT(at+num<=GetSize());
	SetReadMode(); //justToKnowWhichToUse...
	int64 npos=at<=GetPos()?GetPos()-num/*+GetPos()-at*/:GetPos();
	data.Remove(at,num);
	//memmove(buffer+at,buffer+at+num,n);
	buffer = (byte *) ~data;
	rdlim = buffer + data.GetCount();
	Seek(npos);
}
 
		
		
		[Updated on: Mon, 01 May 2017 20:33] Report message to a moderator  
 |  
	| 
		
	 | 
 
 
 |  
	| 
		
 |   
Goto Forum:
 
 Current Time: Tue Nov 04 08:37:13 CET 2025 
 Total time taken to generate the page: 0.05307 seconds 
 |