How to get current routine line?
I am familiar with $TEXT which can get you any line in the current routine provided you know the offset. For example, $T(+1) will get you the first line of the current routine at the run time. In the same vein, how do I reference the current line number/offset at the run time? Something like $T(+$CURRENTLINENUMBER) where $CURRENTLINENUMBER is not yet known to me function. The sample below would write 3 as the line number.
RTNNAME
S A=1
W $CURRENTLINENUMBER
Comments
Hi Cristiano,
This might do for my ultimate purposes, thanks, but strictly speaking $STACK does not return the line number which in this case is 7 (Teste+2). It returns line number relative to the enclosing function only. So I'll wait in case there is a different solution as well.
Hi Anna,
You can look at the property CurrentSrcLine of %SYS.ProcessQuery class (guess SMP uses it showing process details on Process page). Keep in mind that there is more sense to examine the state of some other process rather than the current one as in the last case you will see the very code line where you are examining the process :).
Not quite what I was looking for but very interesting in its own right. Thanks, Alexey!
Hi Anna. I have written a function to work for MAC, INT and INT generated from Classes, based on stack comment earlier. For user to test and confirm suitable for purpose :)
Usage from a class method or routine. Returns the line number. Arguments optional to capture other context.
// how to call set linenumber=##class(DC.LineNumber).SrcLineNumberFromStack(.routine,.label,.offset,.src) // debugwrite !,"routine: ",routinewrite !,"label: ",labelwrite !,"offset: ",offsetwrite !,"linenumber: ",linenumberwrite !,"src:",src
Implementation:
Class DC.LineNumber [ Abstract ]{ClassMethod SrcLineNumber(routine As %String, label As %String, offset As %Integer = 0, Output src) As %Integer{if '$Data(^rMAC(routine)),$Data(^ROUTINE(routine)) {// INT code only possibly generatedset globref="^ROUTINE" } else {set globref="^rMAC" }set labelLen=$Length(label)set line=0for {// Try use rMAC if available as ROUTINE may have subsequent imported includes changing original line offsetsset line=$Order(@globref@(routine,0,line),1,data)// reached the end of the routinequit:line=""set matchTest=$Extract(data,1,labelLen)// discard non-matching linescontinue:$Extract(data,1,labelLen)'=label// Looking for an exact match eg: Myline// skip linelabels with prefix same as exact line label// eg: MyLableBefore, MyLableAfter// ie comprised by following alphanumeric character continue:$Extract(data,labelLen+1)?1AN// Found the line so quit herequit:matchTest=label}set line=line+offsetset src=$Select(line>0:$Get(@globref@(routine,0,line)),1:"")quit line}/// Unpack current locationClassMethod SrcLineNumberFromStack(Output routine As %String, Output label As %Integer, Output offset As %Integer, Output src As %String) As %Integer{quit:$Stack=1 0set place=$Stack(($Stack)-1,"PLACE")set routine=$Piece($Piece(place,"^",2)," ")set offset=+$P($Piece(place,"^"),"+",2)set label=$P($Piece(place,"^"),"+")set line=(..SrcLineNumber(routine,label,offset,.src))quit line}Things are not so easy as they seem, you have to consider scopes too. Take the above class (DC.LineNumber) and add three more methods:
ClassMethod CaseA(x)
{
ifxgoto zTest
quit"A0"
zTest quit"A1"
}
ClassMethod CaseB(x)
{
ifxgoto Test
quit"B0"
Test quit"B1"
}
ClassMethod Test()
{
write..CaseA(0),..CaseA(1) set linenumber=..SrcLineNumberFromStack(.routine,.label,.offset,.src) do prt
write..CaseB(1),..CaseB(0) set linenumber=..SrcLineNumberFromStack(.routine,.label,.offset,.src) do prt
quit// debug
prt write !,"routine: ",routine
write !,"label: ",label
write !,"offset: ",offset
write !,"linenumber: ",linenumber
write !,"src:",src,!!
}
and now do the test:
do##class(DC.LineNumber).Test()and check the output...
OK, I know, this is a (very) constructed case and shouldn't coincide with an everyday development style, but who knows, what a mad programer sometimes produces...
Thanks a lot, Alex!
Write $Stack($Stack,"PLACE")
Or, if you're really interested in the code at that line:
$Stack($Stack,"MCODE")
ROUTINE ztest
line ; the entry point
w $Stack($stack,"MCODE"),!
qIf run, it would apparently print the current source line... which does nothing but printing itself:
USER> do line^ztestw$Stack($stack,"MCODE"),!Oh yes, while the offset from the beginning is meaningful in a .mac or .int routine, within a .cls, it's a mostly meaningless number, whereas the offset from the start of the current method is the meaningful one there.
When using the "MCODE" feature, it does indeed help if there is something else in that line that is worth tracing...
Agree with you. IMHO, the original question has no definite answer: to get the executed code line offset of the current process, this (arbitrary!) line of code should contain the call of some "checker". Or there should be the limited number of selfsufficient "points of interest" in the code.
Routine offset can be converted into the method offset, check this answer.
💡 This question is considered a Key Question. More details here.
.png)