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
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.
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
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.
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
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!
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
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
|
|
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
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.
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 |
|
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
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 |
|
|
|