Login [Register]
Don't have an account? Register now to chat, post, use our tools, and much more.
This is an archived, read-only copy of the United-TI subforum , including posts and topic from May 2003 to April 2012. If you would like to discuss any of the topics in this forum, you can visit Cemetech's Technology & Calculator Open Topic subforum. Some of these topics may also be directly-linked to active Cemetech topics. If you are a Cemetech member with a linked United-TI account, you can link United-TI topics here with your current Cemetech topics.

This forum is locked: you cannot post, reply to, or edit topics. Community News & Discuss Nspire => Technology & Calculator Open Topic
Author Message
bwang


Member


Joined: 15 Mar 2009
Posts: 128

Posted: 14 Jun 2010 12:19:28 am    Post subject:

How does one list all the files in a directory on the Nspire (in C)?
Back to top
bsl


Advanced Newbie


Joined: 09 Jan 2010
Posts: 94

Posted: 25 Jul 2010 03:45:41 pm    Post subject:

This is to give a very basic idea of how to write such a program.
Look at: Nucleus File Utilities to give you some ideas.
The program below is [s]completely un[/s] [s]partially[/s] tested , [s]but gives a half baked idea of how to proceed.[/s]
I will update this post as improvements come along. [s]I am assuming we are only working on os1.1 noncas .[/s]

Put in os.h:

Code:

#define NU_Get_First        (_oscall(int,  NU_Get_First_, unsigned char* StructDstat, const char* pattern))
#define NU_Get_Next         (_oscall(int,  NU_Get_Next_, unsigned char* StructDstat))
#define NU_Done             (_oscall(void, NU_Done_, unsigned char* StructDstat))
#define NU_Set_Current_Dir  (_oscall(int, NU_Set_Current_Dir_, const char* newdir))
#define NU_Current_Dir      (_oscall(int, NU_Current_Dir_, const char* drive, const char* dirbuffer))
#define read_unaligned_longword       (_oscall(unsigned long,  read_unaligned_longword_, void *ptr ))  // 4 byte longword
#define read_unaligned_word           (_oscall(int,  read_unaligned_word_, void *ptr ))                // 2 byte word
#define strcpy                        (_oscall(char*,  strcpy_, const char *dest, const char *src ))

Put in os_1.1.9253.h:

Code:

#define NU_Get_First_            0x1018b7d0
#define NU_Get_Next_             0x1018b868
#define NU_Done_                 0x1018b8e0
#define NU_Set_Current_Dir_      0x1018bd98
#define NU_Current_Dir_          0x1018be78
#define read_unaligned_longword_ 0x100ec4e4
#define read_unaligned_word_     0x100ec590
#define strcpy_                  0x10187388

Put in os_cas_1.1.9170.h:

Code:

#define NU_Get_First_            0x1018B4D8
#define NU_Get_Next_             0x1018B570
#define NU_Done_                 0x1018B5E8
#define NU_Set_Current_Dir_      0x1018baa0
#define NU_Current_Dir_          0x1018bb80
#define read_unaligned_longword_ 0x100ec514
#define read_unaligned_word_     0x100ec5c0
#define strcpy_                  0x10187090


Here is the program:

Code:

/* dirs.c - list files in a directory */
#include <os.h>

asm(".string \"PRG\"\n");
int main(){

char *pattern = "*.*";  // search pattern - all files & dirs
unsigned char StructDstat[512]; // to be filled by Get_First , and used by Get_Next ; 512 is bigger than we need
char curdir[128];
char buf[64];  //scratch buffer
unsigned char attribute;
unsigned long filesize;

 //NU_Set_Current_Dir("A:\\documents\\examples\\"); // ???? - not sure the difference
      set_current_path("/documents/examples/"); // already in Ndless

 if (NU_Get_First(StructDstat,pattern)){  // 0 == no error, nonzero == error code
  printf("Failed to find first file\n");
  NU_Done(StructDstat); 
  return  -1;
 }
  NU_Current_Dir("A:\\",curdir);  // find current directory on drive "A:"
  printf("Contents of %s\n",curdir);

  //printf("struct dstat address %X\n",(unsigned int)&StructDstat[0]);   //development purposes - comment out if not needed
  //asm("bkpt 0x0000" );   // uncomment to break and check how struct dstat is filled - Yagarto does not like this
   
   // List all the files in the directory with given search pattern
   do
   {
      attribute =  StructDstat[269];
      if (attribute & 0x10)     // found a directory
      {
         printf("     <DIR> %s\n", strcpy(buf, (char*)&StructDstat[13]));
      }
      else                      // found a file
      {
         filesize = read_unaligned_longword(&StructDstat[288]);
         printf("%10ld %s\n", filesize, strcpy(buf,(char*) &StructDstat[13]) );
      }
   }
   while (NU_Get_Next(StructDstat) == 0);   // fill in next find , 0 == no error
   
   NU_Done(StructDstat);  // done - free up resources

return 0;
}

Some notes:
1) I used the Datalight shell dir command to break on, which gives me more useful output on the console.
[s]2) The filesize offset of 88 is not correct , neither is the attribute byte offset of 0x86 .[/s]
3) The offset of the filename looks good however, here is a dump of struct DSTAT showing 13 as an offset:

Code:

10810130                                      00 00 00 00               ....
10810140  00 00 00 00 00 00 00 00-00 47 65 74 74 69 6E 67   .........Getting
10810150  20 53 74 61 72 74 65 64-2E 74 6E 73 00 00 00 00    Started.tns....
10810160  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
10810170  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
10810180  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
10810190  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................


EDIT HISTORY:
1) July 25 2010: first posting
2) July 31 2010: C syntax corrections . Returning nonzero value is an error code for Get_Next, Get_First(Explore link above for Nucleus error codes).
Changed the filename offset to 12 and added a space character there - not sure compiler handles strings not aligned on 4 byte boundaries
3) August 1 2010: Simplified search pattern - directory paths in a search pattern requires more coding. For this reason added NU_Current_Dir,NU_Set_Current_Dir.
4) August 4 2010: C syntax - char pattern => char *pattern
5) August 5 2010: Added CAS definitions. Cleaned up code, offsets corrected, should work (may be off a byte on attribute) .
6) August30 2010: Added 3 more routines , compiled running examples
Here is my output:

Code:

Contents of \documents\examples\
     <DIR> .
     <DIR> ..
      4273 Getting Started.tns
        16 dcs-noncas.tns
     46880 console.tns
      3028 dirs.tns
     <DIR> testdir

The source is also in the zip:
[attachment=3262:dirs.zip]


Last edited by Guest on 30 Aug 2010 10:36:15 pm; edited 1 time in total
Back to top
ExtendeD


Advanced Newbie


Joined: 30 Aug 2009
Posts: 91

Posted: 30 Jul 2010 04:46:52 pm    Post subject:

bsl, did you manage to make it work?
It seems to prefer "/phoenix/..." rather than "A:" paths, doesn't it?
Also NU_Get_Next() seems return always true...
Back to top
bwang


Member


Joined: 15 Mar 2009
Posts: 128

Posted: 30 Jul 2010 06:48:02 pm    Post subject:

I can't even get the code to display file names Sad
Oh, and bsl, your #define NU_Done is missing a ")".
Back to top
bsl


Advanced Newbie


Joined: 09 Jan 2010
Posts: 94

Posted: 31 Jul 2010 05:48:55 pm    Post subject:

ExtendeD wrote:

bsl, did you manage to make it work?
It seems to prefer "/phoenix/..." rather than "A:" paths, doesn't it?
Also NU_Get_Next() seems return always true...

Turns out a returning nonzero value is an error code - so I made changes above
The code is much closer to working now.
What I am doing is looking at the assembly listing(return values, passed args, ....) and constructing a small C program from that.

The filenames will have a space in front of them - see if changing the 12 back to 13 works(eliminates space in frront of filrname)...

"/phoenix/..." gives you a brief listing , "A:/phoenix/..." gives you an extensive listing. Leaving the "A:" off is good enough for now.

bwang: If this doesnt work I will compile it myself next week some time. Neutral


Last edited by Guest on 01 Aug 2010 12:07:18 am; edited 1 time in total
Back to top
bwang


Member


Joined: 15 Mar 2009
Posts: 128

Posted: 01 Aug 2010 02:09:20 am    Post subject:

blarg, getting there. The code now prints something:
either

Code:

 documents
documents -1

or

Code:

 bmpviewer
bmpviewer -1

or

Code:

Failed to find first file

bmpviewer is the first directory I have on my flash image, so I assume that's why its being printed.
The fact that the printed message changes between runs is not a good thing Sad


Last edited by Guest on 01 Aug 2010 02:09:33 am; edited 1 time in total
Back to top
bsl


Advanced Newbie


Joined: 09 Jan 2010
Posts: 94

Posted: 01 Aug 2010 09:16:17 pm    Post subject:

Do a simple change on your last code to:

Code:

char pattern = "*.tns";  // search pattern

This should work. Wink
Directory paths in a search pattern are a little more complicated to do.
Also try "*.*" , this will get all files and subdirectories including "." and ".." .
For this reason I included NU_Current_Dir to let you know which directory you are listing,
and NU_Set_Current_Dir to change to a directory to make a listing.
These new calls are untested , but I get a unique match between noncas1.1 and boot2.raw entries .
Then uncomment the lines I have above:

Code:

  //NU_Current_Dir("A:",curdir);  // find current directory on drive "A:" , a NULL == default drive
  //print("Contents of %s\n",curdir);

and run it.
EDIT: The shell does'nt support globbing [example: REL:A:\documents\examples\>dir *.tns]as well as Windows or *NIX does.


Last edited by Guest on 02 Aug 2010 01:07:58 am; edited 1 time in total
Back to top
bwang


Member


Joined: 15 Mar 2009
Posts: 128

Posted: 02 Aug 2010 12:32:37 pm    Post subject:

blarg, doesn't work Sad
Here's my code:

Code:

#include <os.h>
#include "utils.h"

asm(".string \"PRG\"\n");

/* dir.c - list files in a directory(nonworking pseudocode) */
int main(void){

  char pattern = "*.tns";  // search pattern
  unsigned char StructDstat[512]; // structure to be filled by Get_First , and used by Get_Next ; 512 is bigger than we need
  char curdir[128];
  unsigned char attribute;
  unsigned long filesize;
  int i;

  StructDstat[12] = (unsigned char)0x20; // put a space character here
  if (NU_Get_First(StructDstat,pattern)){  // 0 == no error, nonzero == error code
    printf("Failed to find first file\n");
    return  1;
  }
  NU_Set_Current_Dir("A:/Documents/Examples");
  NU_Current_Dir("A:",curdir);  // find current directory on drive "A:" , a NULL == default drive
  printf("Contents of %s\n",curdir);

  for (i = 0; i < 3; i++) {
    NU_Get_Next(StructDstat);
    attribute =  StructDstat[0x86];
    if (attribute & 0x10)     // found a directory
    {
      printf("  %s   <DIR>\n", (char*) &StructDstat[13]);
    }
    else                      // found a file
    {
      filesize = *(unsigned long *) &StructDstat[88];
      printf("  %s   %ld bytes\n", (char* )&StructDstat[12], filesize);
    }
  }

  NU_Done(StructDstat);  // done - free up resources

  return 0;
}

I changed the do-while loop to a for loop to see if the check in the while loop was wrong. It didn't do anything, though - now the program just prints "bmpviewer <DIR>" or "documents <DIR>" 3 times.
Back to top
bsl


Advanced Newbie


Joined: 09 Jan 2010
Posts: 94

Posted: 03 Aug 2010 11:28:16 pm    Post subject:

Breakout !!! -- Got to the root directory

[attachment=3234:breakout.JPG]

Whats left is listing any file with its extension( not just *.tns )
and some how changing directory attributes for listing directories contents.


Last edited by Guest on 03 Aug 2010 11:40:47 pm; edited 1 time in total
Back to top
bwang


Member


Joined: 15 Mar 2009
Posts: 128

Posted: 03 Aug 2010 11:41:19 pm    Post subject:

Whoa! How did you do that?
Congratulations! Very Happy


Last edited by Guest on 03 Aug 2010 11:42:16 pm; edited 1 time in total
Back to top
bsl


Advanced Newbie


Joined: 09 Jan 2010
Posts: 94

Posted: 03 Aug 2010 11:56:45 pm    Post subject:

As I exited the Datalight Shell back to the Folders Application I break on the set_current_path()
call as the application refreshes its environment - It tries to set its path to /Documents/ , but I
inserted a null character after the "/" so that it sets its path on the root directory instead Evil or Very Mad


Last edited by Guest on 04 Aug 2010 10:01:10 am; edited 1 time in total
Back to top
bwang


Member


Joined: 15 Mar 2009
Posts: 128

Posted: 04 Aug 2010 12:55:37 am    Post subject:

I wonder if this is possible without using the Datalight Shell? Since the shell is not accessible on hardware.
Back to top
bsl


Advanced Newbie


Joined: 09 Jan 2010
Posts: 94

Posted: 04 Aug 2010 01:39:35 am    Post subject:

bwang wrote:

I wonder if this is possible without using the Datalight Shell? Since the shell is not accessible on hardware.

Probably, I have to experiment with this for a while , since I know where the "/documents/" string is in memory.
It may be a simple matter of changing one byte with a program and rebooting. However, even if that succeeds, you
have the same problem that the shell has - listing files under those root level directories ( dev,tmp,phoenix,documents,... ) - they dont show,
you get the Empty Folder. Their subdirectories you can
usually list files like /documents/examples or /phoenix/syst.


Last edited by Guest on 04 Aug 2010 10:00:40 am; edited 1 time in total
Back to top
bwang


Member


Joined: 15 Mar 2009
Posts: 128

Posted: 04 Aug 2010 03:40:45 am    Post subject:

Random possibly useful thought:
calc84 uploaded a oncalc disassembler yesterday here: http://otbp.tifreakware.net/files/console.tns
It may help.
Back to top
bsl


Advanced Newbie


Joined: 09 Jan 2010
Posts: 94

Posted: 04 Aug 2010 09:59:47 am    Post subject:

You can also set to a path of your choosing , here I changed it to /phoenix/

[attachment=3236:phoenix_dir.JPG]

Notice the ndls directory

I will see if calc84's console program will do this.
Its interesting that the addresses between the CAS and nonCAS for changing this are the same !!!!

EDIT: grammer


Last edited by Guest on 08 Aug 2010 08:42:37 pm; edited 1 time in total
Back to top
bwang


Member


Joined: 15 Mar 2009
Posts: 128

Posted: 04 Aug 2010 06:40:02 pm    Post subject:

w00t!
The directory listing code works now Smile
It turns out I had a typo; the first line said

Code:

char pattern

instead of

Code:

char* pattern
Back to top
bsl


Advanced Newbie


Joined: 09 Jan 2010
Posts: 94

Posted: 06 Aug 2010 12:03:55 am    Post subject:

Here it is , but you wont be able to do much with it for now ( Jailed in the root directory).

Use calc84's console program [ which runs on both calcs ] to get to the root directory.
Do it on the emulator only. If you do it on the calculator you will have to reinstall the OS. Sad

Code:

NONCAS:
Run the console program and enter:
w 1057a950 2f
q
------------------------------------------------------
CAS:
Run the console program and enter:
w 1054E950 2f
q
Back to top
bwang


Member


Joined: 15 Mar 2009
Posts: 128

Posted: 06 Aug 2010 12:17:04 am    Post subject:

I tried that yesterday, and a reset changed the current directory back to /documents/. No need to reinstall Smile
Back to top
calc84maniac


Elite


Joined: 22 Jan 2007
Posts: 770

Posted: 08 Aug 2010 01:21:17 am    Post subject:

bwang wrote:

I tried that yesterday, and a reset changed the current directory back to /documents/. No need to reinstall Smile

This is true. No matter what modifications you make to the OS in RAM, the encrypted/signed version in flash is unaffected.
Back to top
bsl


Advanced Newbie


Joined: 09 Jan 2010
Posts: 94

Posted: 20 Aug 2010 02:33:25 am    Post subject:

I disassemble the console program .
It has an ASCII character bitmap table for the screen.
drawstring & drawchar routines for that table.
keyboard routines - iskeypressed, ....
screen routines - clearscreen, scrolling, ...
A lengthy disassemble routine with an opcode table.
Hexdump routines
Short read and write routines.
command parsing routines.
2 undocumented commands [ p <addr> ] which works.
and 'a' which does not work - looks incomplete.

You can use this on a CAS as is, but using the 'c' command would
be a little easier if you are going to work with files.
The program has a table of entry points with English names for making calls easier.
example:
> c fopen 10835674 1083584
> returns the handle value here ....
where 10835674 == address of string "memdump.tns\0"
and 10835684 == address of "wb\0".

The program has empty space for data between ORG+0x3680 and ORG+0xb700 where you can
define such variables for calls using the hex editor.

Here, you would not have to put in the hex value entry point for fopen on a CAS if you
convert the program to CAS entry points.

Here is a small perl program that patches the console program for a CAS.

[attachment=3238:patchconsole.zip]


Last edited by Guest on 21 Aug 2010 02:40:38 am; edited 1 time in total
Back to top
Display posts from previous:   
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
    » Goto page 1, 2  Next
» View previous topic :: View next topic  
Page 1 of 2 » All times are GMT - 5 Hours

 

Advertisement