Showing posts with label directory. Show all posts
Showing posts with label directory. Show all posts

Monday, 18 June 2012

Undocumented feature - interrupt - part nine

I know that I said I was done after part eight, but I've had a report of some additional functionality that I thought I should add.



5 - Uniface "usys" directory


As previously discussed, using numeric code "5" returns the working directory.  However, you can also use it to display the Uniface "usys" directory...   

  interrupt(5,"USYS")
  uniface = $result



EDIT: Thank you to James Rodger for pointing out the alternative in his comment...


  uniface = $valuepart($fileproperties("usys:","FULLPATH"))


This in itself seems to be an undocumented feature; I can't find any reference to "usys:" being accessible like this in $fileproperties or $lfileproperties.


I tried to access some other Uniface directories in a similar way, such as "adm" and "bin", but it seems that you can only access "usys".


Thank you to Mark R for point this one out.

Friday, 15 June 2012

Undocumented feature - interrupt - part six



Continuing from part five where we looked at "7", "8" and "9"...



10 - Directory listing (files)


This sets $result to be a Uniface list of all the files in the specified directory.  It also sets $status to be the count of files returned, like this...


  interrupt(10,"C:\temp")
  list = $result
  count = $status


In my test case it sets $result to be "test.txt·;test2.txt" and $status to be 2.  At last, there's a nice Uniface function to replace this one; $ldirlist or $dirlist can be used.  These actually return folders and files by default, but you can specify the "FILE" topic to limit it.  Both of these methods allow you to use wildcards.  The functions do not return the number of files found, but as they do return the list, we can easily use $itemcount if you want this as well, like this...

  list = $ldirlist("C:\temp","FILE")
  count = $itemcount(list)


This is much cleaner code, very concise and readable.  So how does it perform, I hear you cry! I tested over 200,000 iterations...

  • interrupt = 00:17.10, 00:16.89, 00:16.96 (around 17 seconds)
  • $ldirlist = 00:14.68, 00:14.72, 00:14.67 (almost 15 seconds)

So there's not a lot in it, but it does performs better.  I think the alternative is definitely the way to go in this case.


11 - Directory listing (folders)


This sets $result to be a Uniface list of all the folders in the specified directory, similar to "10".  It also sets $status to be the count of folders returned, like this...


  interrupt(11,"C:\temp")
  list = $result
  count = $status

In my test case it sets $result to be "test·;test2" and $status to be 2.  Similarly $ldirlist or $dirlist can be used, but specifying the "DIR" topic this time, like this...

  list = $ldirlist("C:\temp","DIR")
  count = $itemcount(list)


Let's test the performance over 200,000 iterations again...

  • interrupt = 00:15.31, 00:15.30, 00:15.24 (over 15 seconds)
  • $ldirlist = 00:13.33, 00:13.37, 00:13.45 (over 13 seconds)

Again there's not a lot in it, but it does performs better.  I think the alternative is definitely the way to go in this case as well.


More unknowns


Having no indication of what they did, I ran some basic tests on the codes "12" to "988" (see the next post for why I stopped there).  Mostly it was pretty uninteresting, generally speaking they set $status to -1 and leave $result unaffected.  There were some that left $status unaffected as well, and most interestingly "18" sets $result to a blank string.  Unfortunately I couldn't work out anything more for any of them, but I'd like to investigate this further.


Summary: Numeric codes "10" and "11" are useful but have been replaced by $ldirlist and $dirlist which do the same thing, but better.  All the codes beyond that, seem to be useless.  Except "989" which we will tackle in the next post.




Undocumented feature - interrupt - part five


Continuing from part four where we looked at "4", "5" and "6"...


7 - Parent directory


This sets $result to be the parent directory of the file path that you specify, like this...


  interrupt(7,"C:\temp\test\")
  parent = $result



In this case $result would be set to "C:\temp\".  You could do this with string manipulation, but you need to be careful that you check to see if the last character is a delimiter or not...

  filepath = "C:\temp\test\"
  if ( $scan(filepath,"/") < 1 ) ;calculate delimiter
    del = "\"
  else
    del = "/"
  endif
  pos = $length(filepath)
  if ( filepath[pos] = del ) ;remove last character if delimiter
    filepath = filepath[1:pos-1] 
  endif
  pos = $rscan(filepath,del) ;find last delimiter
  filepath = filepath[1,pos] ;truncate string

As you can see, this isn't very concise either, and uses $rscan as well as $scan, so it's not likely to perform very well.  As with "6", I'll test with and without the code which calculates the delimiter, over 2,000,000 iterations...

  • interrupt = 00:05.16, 00:05.20, 00:05.09 (just over 5 seconds)
  • alternative = 00:17.74, 00:17.52, 00:17.67 (over 17 seconds)
  • without $scan = 00:15.62, 00:15.39, 00:15.41 (over 15 seconds)

Looking at these times, I'm struggling to argue for using the alternative!  I'm thinking I must be doing something wrong, so I'm going to try and refactor my alternative, without $rscan.  

I've just tried using $replace to convert the file path into a list, remove the last item (or two) and then convert it back again - this took slightly longer!  I'm going to have to give up with this for now, but I hope to tackle this again.


8 - Unknown


I haven't found any indication of what functionality this might be, but it does behave differently to "1" and "4", which are also unknown.  In this case it always returns a $status of 0 and $result is set to the string that you pass in.  I've tried all sorts of weird and wonderful things without getting anywhere, I'm giving up on this one for now too.



9 - Unknown


I haven't found any indication of what functionality this might be either.  This also behaves differently, as it always returns a $status of 0 but $result remains unaffected. 


Summary: Numeric code "7" could be very useful for finding the parent directory quickly, but "8" and "9" remain unknown.



Wednesday, 13 June 2012

Undocumented feature - interrupt - part four


Continuing from part three where we looked at "2" and "3"...


4 - Unknown


I haven't found any indication of what functionality this might be, but it does behave differently to "1", which was also unknown.  In this case it always returns a $status of 0 and $result is a blank string.  I tried folders, subfolders, filenames and a blank string, with no difference in behaviour.  I'm giving up, for now.



5 - Working directory


As discussed in part one, using numeric code "5" returns the working directory...

  interrupt(5,"")
  working = $result

The alternative is to use $ldir...

  working = $ldir()

The alternative is more maintainable, safer and also performs better.


6 - Concatenate file path

This takes the file path which is currently in $result and then concatenates the path you pass in, automatically adding the folder delimiters where necessary.  Here's some example code...


  filepath = "C:\temp"
  $result filepath
  interrupt(6,"test")
  filepath = $result



This will then populate $result with "C:\temp\test\".  As you can see, I had excluded the delimiter from the end of both the original $result value and the value I passed it, but the interrupt command fixed that.  Again, this is another string manipulation example, I came up with something like this...



  filepath = "C:\temp" 
  if ( $scan(filepath,"/") < 1 ) ;calculate delimiter
    del = "\"
  else
    del = "/"
  endif
  pos = $length(filepath)
  if ( filepath[pos] != del ) ;check filepath ends with delimiter
    filepath = "%%filepath%%del%%%"
  endif
  filepath = "%%filepath%%%test%%del%%%" ;concatenate filepath



As you can see, this isn't very concise, primarily because I'm accounting for Windows and Unix environments again, meaning that I have to first calculate the "del" local variable.  You could of course use $concat instead of using substitution, like I have.


I tested these two methods over 2,000,000 iterations with the following results...

  • interrupt = 00:06.67, 00:06.75, 00:06.72 (almost 7 seconds)
  • alternative = 00:12.02, 00:12.00, 00:12.04 (about 12 seconds)
  • without $scan = 00:09.04, 00:09.78, 00:09.74 (almost 10 seconds)

I added a third option which was the alternative but with a hardcoded delimiter instead of calculating it, so the performance can be improved by having a global register that holds this.  Still, in this case the interrupt command is better for performance and is less lines of code.  

Summary: Numeric code "4" remains unknown for now, "5" has been replaced by a better alternative and "6" seems to still be useful, although I think I'd still opt for string manipulation which I know that I can control over an undocumented feature.


Sunday, 10 June 2012

Undocumented feature - interrupt - part one

This is an undocumented feature that has been known about and used for a while, including a good guide on PUUU.  However, Compuware have documented a number of undocumented features in Uniface 9.5 and interrupt is not one of them.  This makes me think that there must be alternative ways of doing most of these things, or at least that's what I hope to determine whilst writing this post.


The most frequent usage, as far as I'm aware, is getting the working directory...


  interrupt(5,"")
  working = $result


The way that interrupt works is that you pass in a numeric code in the first parameter which determines the functionality, and then the second parameter can be used to pass a value in if needed.  The output is then place in $result for you to do with what you need.  Of course, this example is no longer needed as there is now $ldir which returns the same thing...

  working = $ldir()

So clearly the new version is documented and therefore supported, it's also more concise code and easier to maintain.  So once again a familiar question pops into my head... Which performs best?  I tested both of them over 2,000,000 iterations...

  • interrupt = 00:07.31, 00:07.34, 00:07.36 (just over 7 seconds)
  • $ldir = 00:06.11, 00:06.09, 00:06.04 (just over 6 seconds)

So as you can see, $ldir also performs fractionally better.  Given the number of iterations, it's pretty negligible, but on top of all the other reasons, I'm convinced that I should be using it over the old interrupt method.

In the next part I will be going through each of the known interrupt codes, trying to find alternatives that are documented, and testing the performance where appropriate.