Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Tcl_Obj : What is the recommended way to append a object to another object ?

159 views
Skip to first unread message

Nicolas Robert

unread,
May 9, 2022, 4:17:34 AM5/9/22
to
Hello ,
I would like to add single quotes, square brackets, newline... to the left and right of my string.
It seems to me that I have several choices...
Tcl_ObjPrintf("%s", x) , Tcl_AppendObjToObj(...).

Can you advise me one ? or another ?

Thanks

Nicolas

heinrichmartin

unread,
May 9, 2022, 7:32:16 AM5/9/22
to
StringCatCmd uses Tcl_AppendObjToObj. That should be a reasonable choice.

Nicolas

unread,
May 9, 2022, 10:19:22 AM5/9/22
to
Hi,
when I work with strings, I use the Tcl_DString API

++

Nicolas Robert

unread,
May 10, 2022, 2:45:21 PM5/10/22
to
Thank you both for your answers.
I finally chose this function : Tcl_AppendObjToObj(...)
I have a problem, I have two objects to add to a list one on the left and one on the right.
Tcl_Obj* newlist = Tcl_NewObj();
Tcl_AppendObjToObj(newlist, Tcl_NewStringObj("'", 1));
Tcl_AppendObjToObj(newlist, listObj);
Tcl_AppendObjToObj(newlist, Tcl_NewStringObj("'", 1));

puts "newlist : [newlist]"
newlist : '{a 30 c 40}'

How I can remove my curly braces from my 'listObj' ?
To obtain this result : newlist : 'a 30 c 40'

Nicolas

heinrichmartin

unread,
May 10, 2022, 5:10:36 PM5/10/22
to
On Tuesday, May 10, 2022 at 8:45:21 PM UTC+2, Nicolas Robert wrote:
> Le lundi 9 mai 2022 à 16:19:22 UTC+2, Nicolas a écrit :
> > Le lundi 9 mai 2022 à 13:32:16 UTC+2, heinrichmartin a écrit :
> > > On Monday, May 9, 2022 at 10:17:34 AM UTC+2, Nicolas Robert wrote:
> > > > I would like to add single quotes, square brackets, newline... to the left and right of my string.
> > > > It seems to me that I have several choices...
> > > > Tcl_ObjPrintf("%s", x) , Tcl_AppendObjToObj(...).
> > > >
> > > > Can you advise me one ? or another ?
> > > StringCatCmd uses Tcl_AppendObjToObj. That should be a reasonable choice.
> > Hi,
> > when I work with strings, I use the Tcl_DString API
> >
> > ++
> Thank you both for your answers.
> I finally chose this function : Tcl_AppendObjToObj(...)
> I have a problem, I have two objects to add to a list one on the left and one on the right.
> Tcl_Obj* newlist = Tcl_NewObj();
> Tcl_AppendObjToObj(newlist, Tcl_NewStringObj("'", 1));
> Tcl_AppendObjToObj(newlist, listObj);
> Tcl_AppendObjToObj(newlist, Tcl_NewStringObj("'", 1));

I am used to the script level, but
* You could init newlist with the left string already or
* reuse the single quote object left and right.
* If I get https://www.tcl-lang.org/man/tcl8.6/TclLib/StringObj.htm right, then Tcl_AppendObjToObj(Tcl_NewStringObj()) could be simplified to Tcl_AppendToObj().
* I have no experience with refCount, i.e. no idea whether this code is leaking objects. (My guess is that all your Tcl_New*Obj have refCount 0, but they should go through refCount 1, because only _dropping_ to zero would free them ...)

> puts "newlist : [newlist]"

You seem not to share all code. How do you create listObj above?
If newlist is the implementation of a proc, then look into https://www.tcl-lang.org/man/tcl8.6/TclLib/SetResult.htm.

> newlist : '{a 30 c 40}'

listObj already holds these braces; appending quotes is _not_ the issue.

> How I can remove my curly braces from my 'listObj' ?
> To obtain this result : newlist : 'a 30 c 40'

Besides looking elsewhere in your code (as stated above), maybe you should reconsider why you are mixing C and script level Tcl code. I cannot guess the real-world use case here.

briang

unread,
May 10, 2022, 5:52:30 PM5/10/22
to
Tcl_Obj* newlist = Tcl_NewObj();
Tcl_Obj** elemv;
Tcl_Obj *blank = Tcl_NewStringObj(" ",1);
int elemc, i;
Tcl_AppendObjToObj(newlist, Tcl_NewStringObj("'", 1));
Tcl_ListObjGetElements(interp, listObj, &elemc, &elemv);
/* Tcl_AppendObjToObj(newlist, listObj); */
/* essentially [join $list " "] */
for(i=0; i<elemc; i++) {
if (i>0) Tcl_AppendObjToObj(newlist, blank);
Tcl_AppendObjToObj(newlist, elemv[i]);
}
Tcl_AppendObjToObj(newlist, Tcl_NewStringObj("'", 1));

So the next question is why? Because the value contained in listObj is a collection of Obj's in the form of a list. Tcl, when asked, will create a string representation of the collection so that the individual values are retained and the string as a whole can be used as if it were a scalar value. In essence this is what your example code is asking it to do when calling Tcl_AppendObjToObj(newlist, listObj);

A Tcl_Obj value is not just simply a string. It is any form of value that also has a string representation that retains its constituent values so that it can be decomposed later when needed.

This would be a good time to go back to the Tcl 12 rules and review them. https://www.tcl-lang.org/man/tcl8.6/TclCmd/Tcl.htm

-Brian

Nicolas Robert

unread,
May 10, 2022, 6:00:22 PM5/10/22
to
You are right , without code you can't see my problem.
I’ll try to follow your advice...

I can’t reproduce my problem with this simple code :
critcl::cproc newlist {Tcl_Interp* interp} ok {

Tcl_Obj *listObj = Tcl_NewListObj (0,NULL);

Tcl_ListObjAppendElement (interp, listObj, Tcl_NewStringObj("a", 1));
Tcl_ListObjAppendElement (interp, listObj, Tcl_NewIntObj(30));
Tcl_ListObjAppendElement (interp, listObj, Tcl_NewStringObj("c", 1));
Tcl_ListObjAppendElement (interp, listObj, Tcl_NewIntObj(40));


Tcl_Obj* newlist = Tcl_NewObj();
Tcl_AppendObjToObj(newlist, Tcl_NewStringObj("'", 1));
Tcl_AppendObjToObj(newlist, listObj);
Tcl_AppendObjToObj(newlist, Tcl_NewStringObj("'", 1));

Tcl_SetObjResult(interp, newlist);

return TCL_OK;
}

puts [newlist] ; # 'a 30 c 40'

I'll continue

Nicolas Robert

unread,
May 11, 2022, 1:16:14 PM5/11/22
to
I finally found , my problem was that my input list was not of this form {a 30 c 40} but like this {{a 30 c 40}}.
problem solved with Tcl_ListObjIndex(...)

Nicolas

Ralf Fassel

unread,
May 11, 2022, 1:25:45 PM5/11/22
to
* Nicolas Robert <nicolasro...@gmail.com>
| I finally found , my problem was that my input list was not of this
| form {a 30 c 40} but like this {{a 30 c 40}}. problem solved with
| Tcl_ListObjIndex(...)

Note that if any of the list elements themselves are (sub-)lists or
have spaces or other special chars in the value, the "{}" might come
back again.

% set list [list a 30 b 40]
a 30 b 40
% lappend list c "10 20"
a 30 b 40 c {10 20}

Note the last element.

% lappend list d \{
a 30 b 40 c {10 20} d \{

Again...

If it is *really* important that there is no {} (or \ for the same
reason) in the printed string, you would need to check for that and take
appropriate action if there is.

R'

Nicolas Robert

unread,
May 11, 2022, 1:57:42 PM5/11/22
to
I would be surprised if I had this kind of case, since I work with structured lists. (huddle list).
If that were the case, I don’t think I can find a solution, as my knowledge of the C language is limited...

Nicolas

Nicolas Robert

unread,
May 25, 2022, 12:03:33 PM5/25/22
to
Le mercredi 11 mai 2022 à 19:57:42 UTC+2, Nicolas Robert a écrit :
> Le mercredi 11 mai 2022 à 19:25:45 UTC+2, Ralf Fassel a écrit :
> > * Nicolas Robert
> > | I finally found , my problem was that my input list was not of this
> > | form {a 30 c 40} but like this {{a 30 c 40}}. problem solved with
> > | Tcl_ListObjIndex(...)
> > Note that if any of the list elements themselves are (sub-)lists or
> > have spaces or other special chars in the value, the "{}" might come
> > back again.
> >
> > % set list [list a 30 b 40]
> > a 30 b 40
> > % lappend list c "10 20"
> > a 30 b 40 c {10 20}
> >
> > Note the last element.
> >
> > % lappend list d \{
> > a 30 b 40 c {10 20} d \{
> >
> > Again...
> >
> > If it is *really* important that there is no {} (or \ for the same
> > reason) in the printed string, you would need to check for that and take
> > appropriate action if there is.
> >
> > R'
> I would be surprised if I had this kind of case, since I work with structured lists. (huddle list).
> If that were the case, I don’t think I can find a solution, as my knowledge of the C language is limited...
>
> Nicolas

Hello ,
I have 2 questions
I need this result : > s {Hello World}

I encountered problems when my string contained spaces as in the above result ,
to avoid this, I added my string obj in a list.

Tcl_Obj* defaultTag = Tcl_NewObj();

Tcl_AppendObjToObj(defaultTag, Tcl_NewStringObj("s ", 2));
if (Tcl_DStringLength(srcObj) == 0) {
Tcl_AppendObjToObj(defaultTag, Tcl_NewStringObj("{}", 2));
} else {
Tcl_Obj *listStringObj = Tcl_NewListObj (0,NULL);
Tcl_ListObjAppendElement(interp, listStringObj, srcObj);
Tcl_AppendObjToObj(defaultTag, listStringObj);
}

Is that a correct solution? Or I’ll do it another way

2nd question :
'srcObj' can be empty... Checking its length is a correct solution ?

Nicolas

briang

unread,
May 25, 2022, 12:17:27 PM5/25/22
to
No, this is not the correct solution. The mistake made here is that the code is trying to guess the correct string form of a list. This is re-inventing the code that already exists in Tcl to correctly manage a list.
Just don't do this and let Tcl do it for you.

Assuming that "defaultTag" is intended to be a list, then only List operations should be used to modify this Tcl_Obj value.

Tcl_Obj* defaultTag = Tcl_NewObj();
Tcl_Obj* s = Tcl_NewStringObj("s", 1);

Tcl_ListObjAppendElement(interp, defaultTag, s);
Tcl_ListObjAppendElement(interp, defaultTag, srcObj);

Work smarter, not harder.

>
> 2nd question :
> 'srcObj' can be empty... Checking its length is a correct solution ?

Answered above.

-Brian

Nicolas Robert

unread,
May 26, 2022, 4:16:09 AM5/26/22
to
Thanks for the advice, it’s much cleaner.

Nicolas

Harald Oehlmann

unread,
May 26, 2022, 4:34:19 AM5/26/22
to
I personally find it good practice to check eventual returned errors
from Tcl_ListObjAppendElement.
This is hypotetical in this case, as there may not be any error.
The typical error would be, that "defaultTag" is not a list. This may
not happen here.

Sorry, just noise,
Harald
0 new messages