Page 1 of 1

WritePreferenceString() with string contains line feed

Posted: Thu Mar 05, 2015 3:48 pm
by uwekel
Hi,

if you use the WritePreferencesString() function with a string containing a line feed, the structure of the settings file will be damaged. Also the original value will not be restored, because it is cut-off at the position of the first line feed.

I propose to encode the line feeds with a special character and automatically decode them again when using the ReadPreferenceString().

Regards
Uwe

Re: WritePreferenceString() with string contains line feed

Posted: Thu Mar 05, 2015 4:50 pm
by Michael Vogel
+1

Another, tiny thing with preference files which could be optimized (for Mr.Monk and me) - please remove the first empty line on the top of a preference file (which uses the #PB_Preference_GroupSeparator flag).

Re: WritePreferenceString() with string contains line feed

Posted: Fri Mar 06, 2015 12:39 am
by Dude
Preference strings are meant to be single-line only, by the very definition of the INI file format.

Re: WritePreferenceString() with string contains line feed

Posted: Fri Mar 06, 2015 6:33 am
by Michael Vogel
Dude wrote:Preference strings are meant to be single-line only, by the very definition of the INI file format.
So if more mean the same thing, PB may support this meaning, too. Than it would be nice if only such strings would be written. So if PB handles this, it would be standardized and creates preference files which are compatible with other systems.

Otherwise there are some tons of possibilities to deal with it:
- special tricks could be used to convert the strings when writing/reading: "line 1"+x0D+"line 2" or "line 1\nline 2"
- strings are cutted at the position of the first illegal character: "line 1"
- the readpreferencestring function will get more intelligence (good luck)
- and so on.

Re: WritePreferenceString() with string contains line feed

Posted: Fri Mar 06, 2015 7:56 am
by Danilo
Dude wrote:Preference strings are meant to be single-line only, by the very definition of the INI file format.
I think so, too.

Anyway, some simple ReplaceString will do, if somebody really requires this functionality.

Re: WritePreferenceString() with string contains line feed

Posted: Fri Mar 06, 2015 8:51 am
by uwekel
I think there is nothing bad if the restored string is exactly the same as the stored one. I came across it, when saving and restoring the input of an editor gadget. It could be more simple if the preferences function would take it into account. And linefeeds are not the same on all systems, so you have to take care of it, too.

Re: WritePreferenceString() with string contains line feed

Posted: Fri Mar 06, 2015 10:52 am
by Little John
uwekel wrote:I think there is nothing bad if the restored string is exactly the same as the stored one.
That's a very general statement, and it's true.

However, as Dude wrote, this file format is not designed for storing line feeds.
If in the future INI or PREFS files would exist with line feeds as part of the data, those files could not be read correctly by existing programs. Such a situation is undesirable and would cause unnecessary confusion.
uwekel wrote: I came across it, when saving and restoring the input of an editor gadget.
For this purpose, you can use other file formats that are also supported by PureBasic, for instance XML.
Maybe JSON also allows to store line feeds, I don't know.

You can also design an own file format, e.g.
[ASectionName]
Some text
with line breaks

[AnotherSectionName]
More text ...

Re: WritePreferenceString() with string contains line feed

Posted: Fri Mar 06, 2015 12:34 pm
by uwekel
Little John wrote:For this purpose, you can use other file formats that are also supported by PureBasic, for instance XML.
I prefer to put this setting together with all other settings to the preferences file. Temporarily, i encode it this way:

Code: Select all

ReplaceString(ReplaceString(MyStringWithLinefeed$, #CR$, "#CR$"), #LF$, "#LF$")
But it is not 100% error proof :(

Re: WritePreferenceString() with string contains line feed

Posted: Fri Mar 06, 2015 12:59 pm
by Michael Vogel
Just one (quick and dirty) non-standard approach to handle LF and CR (coded it for ascii, only few adjustments have to be done for unicode).

But...
... it's proprietary, so only usable within your own solutions
... you can't use Chr(1) and Chr(2) anymore (who cares, Chr(0) can't be used either)

Code: Select all

Procedure Mem(*mem1,*mem2,lines=5)

	Protected i,j
	Protected b1,b2
	Protected s.s

	While i<lines
		s=RSet(Hex(i<<4),4,"0")+" "
		For j=0 To 15
			b1=PeekB(*mem1+i<<4+j)&$FF
			b2=PeekB(*mem2+i<<4+j)&$FF
			s+RSet(Hex(b1),2,"0")
			If b1=b2
				s+" "
			Else
				s+"!"
				EndIf
			Next j
			s+"  |   "
		For j=0 To 15
			c=PeekB(*mem1+i<<4+j)
			If c>=' ' And c<='z'
				s+Chr(c)
			Else
				s+"."
			EndIf
		Next j
		Debug s
		i+1
	Wend
	Debug ":"

EndProcedure
Procedure.s AngryBird(s.s,mode)
	
	#Q=#DOUBLEQUOTE$
	#NewLF=1
	#NewCR=2

	Protected c,n

	n=Len(s)
	While n
		n-1
		c=PeekC(@s+n)
		Select c
		Case #LF
			If mode : PokeC(@s+n,#NewLF) : EndIf
		Case #CR
			If mode : PokeC(@s+n,#NewCR) : EndIf
		Case #NewLF
			If mode=0 : PokeC(@s+n,#LF) : EndIf
		Case #NewCR
			If mode=0 : PokeC(@s+n,#CR) : EndIf
		EndSelect
	Wend
	
	If mode
		If PeekC(@s)<>'"' : s=#Q+s+#Q : EndIf
	Else
		If PeekC(@s)='"' : s=Mid(s,2,Len(s)-2) : EndIf
	EndIf
		
	ProcedureReturn s

EndProcedure

sonderbar.s

For i=3 To 255
	sonderbar+RSet(Str(i%100),2,"0")+Chr(i)+" "
Next i

CreatePreferences("sonderbar.ini")
WritePreferenceString("standard",#Q+sonderbar+#Q)
WritePreferenceString("modified",AngryBird(sonderbar,#True))
ClosePreferences()

OpenPreferences("sonderbar.ini")
seltsam.s=ReadPreferenceString("standard","")
wundersam.s=AngryBird(ReadPreferenceString("modified",""),#False)
ClosePreferences()

Mem(@sonderbar,@seltsam)
If sonderbar=seltsam
	Debug "ok"
EndIf

Mem(@sonderbar,@wundersam)
If sonderbar=wundersam
	Debug "ok"
EndIf

Re: WritePreferenceString() with string contains line feed

Posted: Fri Mar 06, 2015 9:20 pm
by Danilo
uwekel wrote:Temporarily, i encode it this way:

Code: Select all

ReplaceString(ReplaceString(MyStringWithLinefeed$, #CR$, "#CR$"), #LF$, "#LF$")
You may want to cover #CRLF$ as well. It is one line break on some electronic typewriters.
Your current solution would probably make 2 line breaks out of one #CRLF$.

Re: WritePreferenceString() with string contains line feed

Posted: Fri Mar 06, 2015 9:35 pm
by uwekel
I now changed the code a bit, and use Chr(1) and Chr(2) as Michael proposed.

Encoding:

Code: Select all

ReplaceString(MyStringWithLinefeeds$, #LF$, Chr(1), #PB_String_InPlace)
ReplaceString(MyStringWithLinefeeds$, #CR$, Chr(2), #PB_String_InPlace)
Decoding:

Code: Select all

ReplaceString(MyStringWithLinefeeds$, Chr(1), #LF$, #PB_String_InPlace)
ReplaceString(MyStringWithLinefeeds$, Chr(2), #CR$, #PB_String_InPlace)
In most cases, Chr(1) and Chr(2) won't be typed into an editor gadget.

Btw, #PB_String_Inplace is really cool!