How to change a Char in a String in a TStringList - c++builder

After writing the content of the text file to the TStringList object, I try to change one character in the line and then write the entire content of the object back to the file. In the saved file, the changed line character was not saved as expected and is still unchanged. To write the change of character to the file I need to use the String object.
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 TStringList *Lista = new TStringList;
 if(OpenDialog1->Execute())
    Lista->LoadFromFile(OpenDialog1->FileName);
Lista->Strings[0][1] = '0'; // this does not work
// Only this way work
String A = Lista->Strings[0];
A[1] = '0';
Lista->Strings[0] = A;
}
I don't understand why the sign change directly in the TStringList object doesn't happen, or if it does, why isn't it written to the file.

The TStringList::Strings[] property getter DOES NOT return a reference to a String object, like you are expecting. It returns a String object by value instead, which means a copy is returned as a temporary object.
Strings[0][1] = ... has no effect because you are modifying that temporary object and not assigning it anywhere afterwards, so it just goes out of scope immediately.
That is why you need to save that temporary object to a local variable first, and then assign that variable back to the Strings[] property after modifying the variable's data.

Related

Buffer.from(string) gives me a UInt8Array

I’m using metalsmith and create a plugin.
I am trying to change the contents, which is a Buffer type.
This is how the metalsmith-partials plugin is doing the same thing.
// get contents string
const contents = fileData.contents.toString();
// creates a new buffer using modified content string
fileData.contents = Buffer.from(contents.replace(markdownInclude.marker, markdownInclude.markerReplacement));
So I copied this code, yet instead of creating a Buffer object, it creates a UInt8Array object.
I am aware that a Buffer is a (subclass?) of UInt8Array but I want to create a Buffer.
How can I force my statement to actually give me a Buffer?

"Can't set data buffer before setting document buffer." for IVsTextLines

In my VSIX project this error is shown on the line:
(AdapterService as IVsEditorAdaptersFactoryService).SetDataBuffer(textLines, projBuffer as IProjectionBuffer);
where textLines is created using CreateInstance method of my package
Type textLinesType = typeof(IVsTextLines);
Guid riid = textLinesType.GUID;
Guid clsid = typeof(VsTextBufferClass).GUID;
IVsTextLines textLines = (_package as Package).CreateInstance(ref clsid, ref riid, textLinesType) as IVsTextLines;
What actually is DocumentTextBuffer property and how do I set it on a newly instantiated IVsTextLines?
What I am trying to do is create a IVsTextLines to pass it as a buffer to IVsCodeWindow.
I changed the initialization of textLines to
textLines = AdapterService.CreateVsTextBufferAdapter(serviceProvider as IOleServiceProvider,
(contentTypeRegistry as IContentTypeRegistryService).GetContentType("csharp")) as IVsTextLines;
and then have used the IVsTextBuffer.InitializeContent method to initialize the Document and Data text buffer to a single space character. After that I was able to successfully use the SetBuffer method.
I am still haven't finalized my extension, so I am not sure how relevant Document Buffer's content is.

Get string value out of a KeySym value

Is there a way to get the string value out of a KeySym value?
For example, out of keyPrintable("a").
If you know the KeySym value is a keyPrintable, you can just get it using the key property. For instance
KeySym kv = ... // something that yields a KeySym
str s = kv.key;
If you don't know it's a keyPrintable you can either check to see if it was built using that constructor, or use pattern matching. So, either
if (kv is keyPrintable) {
// code that uses kv.key to get back the value
}
or
if (keyPrintable(str s) := kv) {
// code that can now use s, which is the key
}
You can also ask if kv has that field, and then use it:
if (kv has key) {
// code that uses kv.key
}
Once you introduce a field name in a constructor, and it has a specific type, you know that same field name has that same type in any additional constructors for the same datatype. So, once we know field key is type str, field key has to be str in any value of type KeySym. That is why it's fine to see if kv has field key and then treat it as a str, nobody could come along later and add a new constructor for KeySym where key has a different type.

How do I get an optional from decodeIntegerForKey instead of 0?

My app saves settings to a file on an iOS device by archiving instances of a class with properties. The class uses the NSCoding protocol, and therefore, I encode these properties using encodeWithCoder. I then try to read these files back into memory using a command such as tempInt = decoder.decodeIntegerForKey("profileFlags") as Int
This has worked well so far, but now I need to be able to store additional properties and retrieve them. In essence, the structure of this archived object is being changed, but users will already have files with the old structure (which has fewer properties). If the user has a file with the new structure (additional properties), then I want to read them. If not, I want to be able to execute code to handle that and provide default values.
I tried using a nonexistent key tempInt = decoder.decodeIntegerForKey("nonExistentKey") as Int, expecting to get a nil value, but it returned a zero. Unfortunately, this is one place where I really need an optional, because 0 is a valid value.
The closest help article I can find is Swift: decodeObjectForKey crashes if key doesn't exist but that doesn't seem to apply here. It seems like decodeObjectForKey returns an optional and decodeIntegerForKey returns an Integer.
Any ideas on how to do this?
You can check using decoder.containsValueForKey("nonExistentKey") wether or not there is an actual value present and only if it is extract it with decodeIntegerForKey:
if decoder.containsValueForKey("nonExistentKey") {
let tempInt = decoder.decodeIntegerForKey("nonExistentKey")
}
You can use decodeObjectForKey that returns nil instead of zero. You just need to downcast to Int as follow:
decoder.decodeObjectForKey("profileFlags") as? Int
#luk2302 gave you the answer, but I wanted to adjust the syntax slightly and expand on it:
var tempInt: Int?
let key = "profileFlags"
let hasValue = decoder.containsValueForKey(key)
tempInt = hasValue ? decoder.decodeIntegerForKey(key) : nil
The last statement is using the "tertiary operator", which has the same effect as:
if hasValue
{
tempInt = decoder.decodeIntegerForKey(key)
}
else
{
tempInt = nil
}
...but all in 1 line. It's a little odd-looking until you get used to it, but it is a very concise way to express this sort of thing.

Delphi - deferring assignment to an out parameter

In Delphi, suppose I have a method with a (much simplified) signature like this:
procedure abc( const prop1:string; const arg1:TValue; const prop2:string;
out arg2:TValue );
I'm building a TList<PPropValPair> of records like this using the parameters provided:
type
TPVPType = (ptIn, ptOut);
PPropValPair = ^TPropValPair;
TPropValPair = record
io : TPVPType;
prop : string; // property name
iVal : TValue; // input value
oVar : Variant; // <-- how to save for later use??? Variant? TValue?
end;
(On the face of it, this example looks silly. Again, it's quite simplified just to communicate the problem.)
At run-time, I want to stuff all of the input values ival (where io=ptIn) into each public property 'prop' in a class, call a class method, then extract the values of all public properites 'prop' (where io=ptOut) into oVar.
The input side is working fine using RTTI.
However, I need to somehow save a REFERENCE to the output vars in oVar so I can save the value of the associated properties after the class method has been called.
I'm not assigning anything to arg2 directly. Rather, I'm saving a reference to arg2 and assigning the value indirectly later on.
The trick is ... I don't want to have to do any additional annotations of the output parameters in abc(...).
In C++, you can declare a parameter as a 'reference' by prepending it with '&'. So in C++ terms this might be defined roughly as:
procedure abc( arg1 : TValue; &arg2 : TValue );
Later, you can refer to &arg2 and it's using a POINTER to the object. But in calling the function, you just say:
abc( somevar1, somevar2 );
somevar1 is passed by value, and somevar2 is passed by reference. Inside the function, I can save somevar2 in a reference var, then later on assign a value to it via the pointer (if it's a string) by saying &arg2ref = 'abc'.
I'm guessing there's a way to do this in Delphi, either with a Variant as the oVar type, or using RTTI, or something else. I just haven't figured out the magic combination of pieces yet. (I just don't use pointers very often in Delphi.)
Maybe I need to save a raw pointer in oVar along with the type (say, oType), and cast a value through the pointer to save the property's value?
I'm hoping someone here might have some clear ideas.
BTW, I'm using Delphi XE3.
Use a pointer. It doesn't have to (and indeed shouldn't) be a "raw" pointer. Use a typed pointer, PValue. Pass in a PValue to your function, and then store that in oVal, which you should also declare a a PValue. Use # to create a pointer, and ^ to dereference.
I would not recommend passing arg2 by reference. Although you can still use # on it to get a pointer to the original variable passed to abc, the reference parameter disguises the fact that the variable needs to remain available indefinitely. Instead, declare arg2 as PValue so it's more obvious to the caller that indirection is involved.
// declaration
procedure abc(...; arg2: PValue);
// call
abc(..., #somevar2);

Resources