TheSwamp

Code Red => ARX Programming => Topic started by: LE on December 22, 2005, 11:15:56 PM

Title: Appropiate form to get arguments from a resbuf ?
Post by: LE on December 22, 2005, 11:15:56 PM
I am doing some new functions and while writing I seen several approaches from some sample code styles, and want it to find out a much cleaner/better "way" "form" if is possible.

Here is one of the new functions I am working:

Code: [Select]
//call in autolisp: (getweeknumber 2005 12 22)
static int ads_getweeknumber(void)
{
struct resbuf *rb=acedGetArgs();
int year,month,day;

if (!rb ||
rb->restype != RTSHORT ||
!rb->rbnext ||
rb->rbnext->restype != RTSHORT ||
!rb->rbnext->rbnext ||
rb->rbnext->rbnext->restype != RTSHORT ||
rb->rbnext->rbnext->rbnext
) {
acutPrintf("\nInvalid: function expects three integer arguments!\n" );
return RSERR;
}
else {
// get the first argument
year=rb->resval.rint;
// get the second argument
rb=rb->rbnext;
month=rb->resval.rint;
// get the third argument
rb=rb->rbnext;
day=rb->resval.rint;

// is not required
////acutRelRb(rb);

CWeek date;
date.setDate(year,month,day); //(2005,12,22);
int nWeeknumber=date.getWeeknumber();

// return to autolisp the week number or nil
acedRetInt(nWeeknumber);

//int nWeekday=date.getWeekday();
}//else
return (RSRSLT) ;
}

Or...

Code: [Select]
static int ads_getweeknumber(void)
{
struct resbuf *rb=acedGetArgs();
int year,month,day;

if (rb->restype != RTSHORT){
acutPrintf("\n1st. argument invalid.");
return RSERR;
}
year=rb->resval.rint;
rb=rb->rbnext;
if (rb==NULL || rb->restype != RTSHORT){
acutPrintf("\n2nd. argument invalid.");
return RSERR;
}
month=rb->resval.rint;
rb=rb->rbnext;
if (rb==NULL || rb->restype != RTSHORT){
acutPrintf("\n3rd. argument invalid.");
return RSERR;
}
day=rb->resval.rint;

// is not required
//acutRelRb(rb);

CWeek date;
date.setDate(year,month,day); //(2005,12,22);
int nWeeknumber=date.getWeeknumber();

// return to autolisp the week number or nil
acedRetInt(nWeeknumber);

//int nWeekday=date.getWeekday();
return (RSRSLT) ;
}

Or... something like the following [I did not including any error handler, it is just prototype]

Code: [Select]
static int ads_getweeknumber(void)
{
struct resbuf *rb=acedGetArgs();
int year,month,day;

// get the first argument
if (rb && (rb->restype==RTSHORT)){
year=rb->resval.rint;
rb=rb->rbnext;
}
// get the second argument
if (rb && (rb->restype==RTSHORT)){
month=rb->resval.rint;
rb=rb->rbnext;
}
// get the third argument
if (rb && (rb->restype==RTSHORT)){
day=rb->resval.rint;
rb=rb->rbnext;
}

// is not required
//acutRelRb(rb);

CWeek date;
date.setDate(year,month,day); //(2005,12,22);
int nWeeknumber=date.getWeeknumber();

// return to autolisp the week number or nil
acedRetInt(nWeeknumber);

return (RSRSLT) ;
}

Thanks.
Title: Re: Appropiate form to get arguments from a resbuf ?
Post by: MickD on December 23, 2005, 01:42:22 AM
Hi Luis, I've done something similar in C#, I used a hastable to store each rb node using each number of the the 'for' loop as the 'key' and storing the value in that keys' value. I reckon you could do the same with a std::map object or similar. If you know the order of your rb's you can retrieve them as you need using something like string str = myMap[4];//the fifth element in the map is a string value.

Another way may be to see what type the object is while in a loop and add it to an array of its type then access it using the array index.

Either way I think the best way would be to extract the resbuf into a container that takes different types and access that container later saving all the if statements.

I have to do something similar myself so I'll see if I can set something up and post it if you or someone else dosen't come up with something in the mean time.
Title: Re: Appropiate form to get arguments from a resbuf ?
Post by: LE on December 23, 2005, 11:30:17 AM
Thanks Mick;

On the mean time, I am using the first style on the function I posted on the top.

Yes, I do not like all the IF's calls too.....

I have seen the use of switch, but if we have three times the same type, then for what I know of C++ I still cannot figure out how to set each variable in each case.....

ie:
Code: [Select]
struct resbuf *rb=acedGetArgs();
switch (rb->restype) {
case RTREAL : {
double Num=rb->resval.rreal ;
}
break;
case RTSTR : {
strcpy(Str, rb->resval.rstring);
}
break;
case RTSHORT : {
// here is on how [if possible] to set up not just one variable,
// like in the case of this functions all the arguments are short type
short iNum=rb->resval.rint;
}
break;
}// end of switch

I like the idea of put it into a container.... but they are already in the dynamic linked list [resbuf].... I wonder how the masters come up with this...

BTW, in gbpoly I used the second style, but in there are a lot of IF's calls, everything works, no problems, I am just looking for better ways.

Thanks.
Title: Re: Appropiate form to get arguments from a resbuf ?
Post by: LE on December 23, 2005, 01:01:50 PM
For those interested on this new GetWeekNumber   function that can be use to extend the capabilities of autolisp, the compiled version is already in the "download" [freeones] section of my web site.

http://www.geometricad.com

Title: Re: Appropiate form to get arguments from a resbuf ?
Post by: LE on December 23, 2005, 03:33:47 PM
Base on my research I can only see that no more than 11 topics are related with the use of acedGetArgs, means that C++ programmers do not care of exporting functions into autolisp, since everything can be done within.

OK, I will keep using something like this:

Code: [Select]
if (!rb ||
rb->restype != RTSHORT ||
!rb->rbnext ||
rb->rbnext->restype != RTSHORT ||
!rb->rbnext->rbnext ||
rb->rbnext->rbnext->restype != RTSHORT ||
rb->rbnext->rbnext->rbnext
) {

Something I learned from Owen Wengerd [from www.manusoft.com]

Of course if a better approach is found, then I would like to hear....

Have fun.
Title: Re: Appropiate form to get arguments from a resbuf ?
Post by: LE on December 24, 2005, 01:53:43 PM
In case someone has noticed:

Code: [Select]
struct resbuf *rb=acedGetArgs();

There are three rules about resbuf's or result buffers:
1. Check if is not NULL
2. Check for restype
3. Release dynamically allocated resbuf when done

In this function case, since we are using: acedGetArgs() it is the only case [and the only global objectarx function] that we do not have to release the returned linked list.
Title: Re: Appropiate form to get arguments from a resbuf ?
Post by: Glenn R on December 28, 2005, 07:28:29 PM
Louis,

For what it's worth, here's how I was doing it a couple of years ago when I got a bee in my bonnet about writing 'native' Lisp API's:

Code: [Select]
*///-----------------------------------------------------------------------------
// This is command 'TCGSVPFREEZE, by Glenn Ryan [8/11/2003], , TCGSoftware
//
// Description: Freezes or thaws a layer in a particular viewport
// Usage: (tcgs-vp-freeze <Viewport Ename> <Layer name> <T or nil>)
// Returns: T if successful, nil otherwise.

typedef AcDbObjectPointer<AcDbViewport> AcDbViewportPointer;

int TCGSVPFreeze()
{
#ifdef OARXWIZDEBUG
acutPrintf ("\nOARXWIZDEBUG - TCGSVPFreeze() called.");
#endif // OARXWIZDEBUG

// TODO: Implement the command
resbuf *pArg =acedGetArgs () ;
CString layerName;
bool frzLayer = false;

Acad::ErrorStatus es = Acad::eOk;
AcDbObjectId viewportId = AcDbObjectId::kNull;

if (!pArg)
return RTERROR;
// get the entity name
if (pArg && (pArg->restype == RTENAME)) {
// convert ename to objectid
es = acdbGetObjectId(viewportId, pArg->resval.rlname);
if (es != Acad::eOk) {
acutPrintf("\nerror: Unable to convert entityname to objectId - %s.", acadErrorStatusText(es));
return RSERR;
}
pArg = pArg->rbnext;
} else if (pArg && (pArg->restype == RTLONG)) {
viewportId.setFromOldId(pArg->resval.rlong);
pArg = pArg->rbnext;
} else {
acutPrintf("\nerror: Invalid first argument: expects an entity name or vla objectId.\n");
return RSERR;
}
// get the string for the layer
if (pArg && (pArg->restype == RTSTR)) {
layerName = pArg->resval.rstring;
pArg = pArg->rbnext;
} else {
acutPrintf("\nerror: Invalid second argument: expects a valid layer name string.\n");
return RSERR;
}
// get True of False value
// T will freeze layer, nil will thaw it
if (pArg && (pArg->restype == RTT)) {
frzLayer = true;
pArg = pArg->rbnext;
} else if (pArg && (pArg->restype == RTNIL)) {
frzLayer = false;
pArg = pArg->rbnext;
} else {
acutPrintf("\nerror: Invalid third argument: expects T or nil.\n");
return RSERR;
}

if (pArg) {
acutPrintf("\nerror: Invalid number of arguments: usage (tcgs-vp-freeze <Entityname> <Layer name> <T or nil>.\n");
return RSERR;
}


// check we can find the layer in the layer table
AcDbDatabase* pCurDb = 0;
pCurDb = acdbHostApplicationServices()->workingDatabase();
if (!pCurDb) {
acutPrintf("\nerror: Unable to get pointer to current database.\n");
return RSERR;
}

AcDbObjectId layerTblId = AcDbObjectId::kNull;
// get the object id of the layer table
layerTblId = pCurDb->layerTableId();
// check we got a valid object id
if (layerTblId.isNull()) {
acutPrintf("\nerror: Unable to get objectId of layer table.\n");
return RSERR;
}

// try and open the layer table for read
AcDbLayerTablePointer pLayerTbl(layerTblId, AcDb::kForRead);
es = pLayerTbl.openStatus();
if (es != Acad::eOk) {
acutPrintf("\nerror: Unable to open layer table for read - %s.", acadErrorStatusText(es));
return RSERR;
}

AcDbObjectId layTblRcdId = AcDbObjectId::kNull;
// check if layer table has layer
if (!pLayerTbl->has(layerName)) {
acutPrintf("\nerror: No matching layer name found.\n");
return RSERR;
} else {
//got layer so grabs it's objectid
es = pLayerTbl->getAt(layerName, layTblRcdId);
if (es != Acad::eOk) {
acutPrintf("\nerror: Unable to objectId of layer - %s.", acadErrorStatusText(es));
return RSERR;
}
}

// check if we got a viewport entityname
AcDbViewportPointer pViewport(viewportId, AcDb::kForWrite);
es = pViewport.openStatus();
if (es != Acad::eOk) {
if (es == Acad::ErrorStatus::eNotThatKindOfClass) {
acutPrintf("\nerror: Invalid entityname - must be a viewport.\n");
return RSERR;
}
acutPrintf("\nerror: Unable to open viewport for write - %s.",acadErrorStatusText(es));
return RSERR;
}

// toss layer tabel record objectid into array
AcDbObjectIdArray idArr;
idArr.append(layTblRcdId);

if (frzLayer) { // freeze the layer
es = pViewport->freezeLayersInViewport(idArr);
if (es != Acad::eOk) {
acedRetNil();
return RSERR;
}
acedRetT();
} else { // want to thaw the layer
es = pViewport->thawLayersInViewport(idArr);
if (es != Acad::eOk) {
acedRetNil();
return RSERR;
}
acedRetT();
}

return (RSRSLT) ;
}

Cheers,
Glenn.
Title: Re: Appropiate form to get arguments from a resbuf ?
Post by: LE on December 28, 2005, 09:09:51 PM
Thank you Glenn;

Nice code sample!

[I see that everyday very few are staying into C++ and less on ObjectARX]
Title: Re: Appropiate form to get arguments from a resbuf ?
Post by: Glenn R on December 28, 2005, 09:51:03 PM
You're welcome Louis. One other point: If the resbuf chain you're chasing is longer than a few elements,
I would use a while loop with an embedded switch statement.

Merry Xmas and a Happy New Year,
Glenn.
Title: Re: Appropiate form to get arguments from a resbuf ?
Post by: LE on December 28, 2005, 10:03:54 PM
Merry Xmas and a Happy New Year,

Thank you;

The same to you and your family.
Title: Re: Appropiate form to get arguments from a resbuf ?
Post by: MickD on January 03, 2006, 10:14:42 PM
Had a bit of time to play around so how about something like this? I didn't test it as it didn't compile without error (which header did you include for CWeek Luis?) but it gives you the general idea.

Code: [Select]
//call in autolisp: (getweeknumber 2005 12 22)
static int ads_getweeknumber(void)
{
struct resbuf *rb=acedGetArgs();
int iArray[3];
int year,month,day;
if (!rb)
{
acutPrintf("\nError: failed to get resbuf!\n" );
return RSERR;
}
for(int i = 0; i < 3; i++)
{
if(rb->restype != RTSHORT)
{
acutPrintf("\nInvalid parameter, failed on iteration %d!\n",i );
return RSERR;
}
iArray[i] = rb->resval.rint;
rb = rb->rbnext;//ready for next loop
}

// get the first argument
year = iArray[0];
// get the second argument
month = iArray[1];
// get the third argument
day = iArray[2];

CWeek date;
date.setDate(year,month,day); //(2005,12,22);
int nWeeknumber=date.getWeeknumber();

// return to autolisp the week number or nil
acedRetInt(nWeeknumber);

//int nWeekday=date.getWeekday();

return (RSRSLT) ;
}

WARNING: not tested, issued for discussion only :-)
Title: Re: Appropiate form to get arguments from a resbuf ?
Post by: LE on January 03, 2006, 10:49:26 PM
Had a bit of time to play around so how about something like this? I didn't test it as it didn't compile without error (which header did you include for CWeek Luis?) but it gives you the general idea.


Let me tested, looks good, I think this thread is going the same direction as the one of "code right"..... I will say.....  :-)

The CWeek is a calendar class.

Thanks.
Title: Re: Appropiate form to get arguments from a resbuf ?
Post by: Kerry on January 03, 2006, 11:07:55 PM
Seeing it's become a discussion .. :-)

Wouldn't the result be determined by the local environment ie
ISO
US
etc ..

http://msdn2.microsoft.com/en-us/library/system.globalization.calendar.getweekofyear.aspx

the rules :
http://msdn2.microsoft.com/en-us/library/system.globalization.calendarweekrule.aspx


or, is that all handled by this call < from Micks >.
int nWeeknumber=date.getWeeknumber();

and does that mean there is NO definitive answer, because "It Depends" on the computer settings. ? ?
Title: Re: Appropiate form to get arguments from a resbuf ?
Post by: MickD on January 03, 2006, 11:46:40 PM
...
or, is that all handled by this call < from Micks >.
int nWeeknumber=date.getWeeknumber();

and does that mean there is NO definitive answer, because "It Depends" on the computer settings. ? ?


I think that would be the case, also not the setDate parameters ;)
Title: Re: Appropiate form to get arguments from a resbuf ?
Post by: MickD on January 04, 2006, 12:14:47 AM
.... I think this thread is going the same direction as the one of "code right"..... I will say..... :-)


if we want to go that way we probably should do something like this -
Code: [Select]
class MyWeek
{
public://constructor/destructor/functions
MyWeek(struct resbuf * rb)
{
//init our class in constructor
_rb = rb;
setUpVars();
};

~MyWeek() {/*clean up if required*/};

int WeekNumber();

private://member variables
struct resbuf * _rb;
CWeek _date;
int _year,_month,_day,_weekNumber;
int iArray[3];

private://functions
void setUpVars();
};//end class definition

void MyWeek::setUpVars()
{
if (!_rb)
{
acutPrintf("\nError: failed to get resbuf!\n" );
}
for(int i = 0; i < 3; i++)
{
if(_rb->restype != RTSHORT)
{
acutPrintf("\nInvalid parameter, failed on iteration %i!\n",i );

}
iArray[i] = _rb->resval.rint;
_rb = _rb->rbnext;//ready for next loop
}

// get the first argument
_year = iArray[0];
// get the second argument
_month = iArray[1];
// get the third argument
_day = iArray[2];
_date.setDate(_year,_month,_day); //(2005,12,22);
_weeknumber = _date.getWeeknumber();

}

int MyWeek::WeekNumber()
{
return _weekNumber;
}

Then simply use it like this -

Code: [Select]
//call in autolisp: (getweeknumber 2005 12 22)
static int ads_getweeknumber(void)
{
                struct resbuf *rb=acedGetArgs()
MyWeek date(rb);
acedRetInt(date.WeekNumber());
return (RSRSLT) ;
}

A bit of overkill though  :lol:
Title: Re: Appropiate form to get arguments from a resbuf ?
Post by: LE on January 04, 2006, 10:02:10 AM
Seeing it's become a discussion .. :-)

Wouldn't the result be determined by the local environment ie
ISO
US
etc ..

http://msdn2.microsoft.com/en-us/library/system.globalization.calendar.getweekofyear.aspx

the rules :
http://msdn2.microsoft.com/en-us/library/system.globalization.calendarweekrule.aspx


or, is that all handled by this call < from Micks >.
int nWeeknumber=date.getWeeknumber();

and does that mean there is NO definitive answer, because "It Depends" on the computer settings. ? ?


Thanks for those links Kerry,

Well, all I did was to do a research, for formulas, etc etc etc etc etc, others samples.... and reinvent the wheel again  :ugly:
Then I simple put it together all the pieces and built a function to get the week number.... and yep.... you are right it will depend on the machine settings.... at the end  :-)