Shop OBEX P1 Docs P2 Docs Learn Events
C: SimpleIDE... Directory Listing of SD Card Files — Parallax Forums

C: SimpleIDE... Directory Listing of SD Card Files

idbruceidbruce Posts: 6,197
edited 2015-05-09 14:00 in Propeller 1
I have been searching for hours..... Does anyone know of an an example for SimpleIDE, for recursively searching and/or listing SD card files and/or directories?

Basically, I want to list all the files and/or directories on an LCD display, so that a user can navigate this list, through the use of pushbuttons, to select a desired file.
«13

Comments

  • Dave HeinDave Hein Posts: 6,347
    edited 2015-04-30 04:42
    When you say SimpleIDE you mean in C, right? Look up opendir, readdir and closedir. Those are the functions that are used to get a directory list in C.
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-04-30 05:26
    Here's the filetest program from the PropGCC demos directory. It is configured for the C3 card, but you can change it to your SD configuration by changing the #define's at the beginning of the program and changing the pin numbers.
  • idbruceidbruce Posts: 6,197
    edited 2015-04-30 05:39
    Thanks Dave

    Just what I needed.
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-04-30 09:38
    I noticed that filetest.c does not use the d_name element in the dirent struct. d_name was added after filetest.c was written, and it contains the 8.3 version of the filename. The struct element name contains the raw file name that is in the FAT directory entry. The dirent struct is defined as follows:
    struct dirent {
        uint8_t name[11];        // filename
        uint8_t attr;            // attributes
        uint8_t reserved;        // reserved, must be 0
        uint8_t crttimetenth;    // create time, 10ths of a second (0-199)
        uint8_t crttime_0;       // creation time byte 0
        uint8_t crttime_1;       // creation time byte 1
        uint8_t crtdate_0;       // creation date byte 0
        uint8_t crtdate_1;       // creation date byte 1
        uint8_t lstaccdate_l;    // last access date byte 0
        uint8_t lstaccdate_h;    // last access date byte 1
        uint8_t startcluster_2;  // first cluster, byte 2 (FAT32)
        uint8_t startcluster_3;  // first cluster, byte 3 (FAT32)
        uint8_t wrttime_0;       // last write time byte 0
        uint8_t wrttime_1;       // last write time byte 1
        uint8_t wrtdate_0;       // last write date byte 0
        uint8_t wrtdate_1;       // last write date byte 1
        uint8_t startcluster_0;  // first cluster, byte 0
        uint8_t startcluster_1;  // first cluster, byte 1
        uint8_t filesize_0;      // file size, byte 0
        uint8_t filesize_1;      // file size, byte 1
        uint8_t filesize_2;      // file size, byte 2
        uint8_t filesize_3;      // file size, byte 3
        char d_name[13];         // filename in file.ext format
    };
    
  • idbruceidbruce Posts: 6,197
    edited 2015-04-30 09:55
    Thanks for the heads up and the example. That example is a nice piece of work. I was just toying around with it...

    I am surprised this example is not more publicized.
  • idbruceidbruce Posts: 6,197
    edited 2015-05-01 04:53
    For those folks that may want a small snippet... Here ya go... If desired, sorting could be added.
    #include <propeller.h>
    #include <dirent.h>
    #include "simpletools.h"
    
    #define SD_DO 22
    #define SD_CLK 23
    #define SD_DI 24
    #define SD_CS 25
    
    int main()
    {
        DIR *sd_dir;
        struct dirent *dir_entry;
    
        sd_mount(SD_DO, SD_CLK, SD_DI, SD_CS);
    
        sd_dir = opendir("./");
    
        if(sd_dir != NULL)
        {
            while((dir_entry = readdir(sd_dir)))
            {
                print("%s\n", dir_entry->d_name);
            }        
    
            closedir(sd_dir);
        }
        else
        {
            print("Directory could not be opened");
        }        
    
        return 0;
    }
    
  • Heater.Heater. Posts: 21,230
    edited 2015-05-01 05:24
    Looks like a good start. Now you only need the recursive search part :)
  • idbruceidbruce Posts: 6,197
    edited 2015-05-01 06:48
    Now you only need the recursive search part

    Yea, the title is definitely misleading, because I stated it incorrectly. Bsaically, I just wanted a directory listing, which could be searched further, with chdir, etc...
  • Heater.Heater. Posts: 21,230
    edited 2015-05-01 07:15
    idbruce,
    I just wanted a directory listing, which could be searched further, with chdir,
    But that "searched further" part is the recursive thing. Is it not?

    Sorry. I'm being a bit of a wind up. It's because writing a recursive directory search that will list all files in all directories and subdirectories from the the root downwards is an interesting exercise. Many C programmers, or indeed users of other languages never get their heads around such recursion.

    Is it what you want to do? Is it practical on the Prop? No idea.
  • idbruceidbruce Posts: 6,197
    edited 2015-05-01 08:55
    Sorry. I'm being a bit of a wind up. It's because writing a recursive directory search that will list all files in all directories and subdirectories from the the root downwards is an interesting exercise. Many C programmers, or indeed users of other languages never get their heads around such recursion.

    In the past, I have worked with recursive directory searching on two occassions, with both of them involving a Tree control. I cannot remember if I ever got it working correctly, but I think so. However, yes it is very interesting, without it, you would never find the word "scudattle", located in a file named "podunk.txt", buried deeply within a highly complex directory structure, of F: drive :)
    Is it what you want to do?

    Nah, as indicated, I used the word recursive without thinking about correct usage.
    Is it practical on the Prop?

    I suppose it could be useful, depending on the project of course. Perhaps famous quotations of various authors, musicians, and politicians, being indexed according to the category, and then by person.
  • Heater.Heater. Posts: 21,230
    edited 2015-05-01 09:16
    Ah, you are jumping ahead there into the land of text search within files. I was only thinking of searching all directories and sub-directories to create a listing of the tree structure of the files.

    That can lead to a C function that calls itself recursively. That is a big conceptual headache for many.
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-05-01 09:41
    Here's a program that does a recursive listing. It works under cygwin, but I haven't tested it on the Prop. I had to test for the directories "." and ".." to prevent it from getting into an infinite loop.
    #include <stdio.h>
    #include <dirent.h>
    #ifdef __PROPELLER__
    #include <propeller.h>
    #include "simpletools.h"
    
    #define SD_DO 22
    #define SD_CLK 23
    #define SD_DI 24
    #define SD_CS 25
    #endif
    
    void listfiles(char *dirname)
    {
        DIR *sd_dir = opendir(dirname);
        struct dirent *dir_entry;
    
        if(!sd_dir) return;
    
        // List files in this directory
        printf("\n%s:\n", dirname);
        while((dir_entry = readdir(sd_dir)))
            printf("%s\n", dir_entry->d_name);
        closedir(sd_dir);
    
        // List files in sub-directories
        sd_dir = opendir(dirname);
        while((dir_entry = readdir(sd_dir)))
        {
            if (strcmp(dir_entry->d_name, ".") && strcmp(dir_entry->d_name, ".."))
                listfiles(dir_entry->d_name);
        }
        closedir(sd_dir);
    }
    
    int main()
    {
    #ifdef __PROPELLER__
        sd_mount(SD_DO, SD_CLK, SD_DI, SD_CS);
    #endif
        listfiles("./");
        return 0;
    }
    
  • idbruceidbruce Posts: 6,197
    edited 2015-05-01 09:53
    Ah, you are jumping ahead there into the land of text search within files. I was only thinking of searching all directories and sub-directories to create a listing of the tree structure of the files.

    That can lead to a C function that calls itself recursively. That is a big conceptual headache for many.

    It is really not all that different, once you have a directory, simply iterate, open, and search the files. Following the directories is the hard part. And then as Dave mentions, you have to watch out for "." and ".."
  • idbruceidbruce Posts: 6,197
    edited 2015-05-01 09:57
    Now you guys have me digging.... Let me see what I can find :)
  • Heater.Heater. Posts: 21,230
    edited 2015-05-01 10:06
    It's that call to listfiles(..) in the middle of the listfiles() function that is the conceptual stumbling block for many. This is not just iteration.

    Then the issue of the base case, as Dave demonstrates above.

    Edit: No wait: the "." and ".." things are a looping within the recursive structure one is searching recursively...A kind of meta-recursion.

    Headache time!
  • idbruceidbruce Posts: 6,197
    edited 2015-05-01 10:11
    As mentioned, this was many years ago, and I am not sure if I ever got this working correctly. Very complicated. Recursive searching is one thing, but then adding the complexities of a tree control, image lists, etc... Enough to make your head spin..
    // FavTreeCtrl.cpp: 
    // 
    // wrapped CTreeCtrl to select and or display folders and files (optional )
    // 
    
    #include "stdafx.h"
    
    #include "FavTreeCtrl.h"
    #include "SortStringArray.h"
    
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    /////////////////////////////////////////////////////////////////////////////
    // CFavTreeCtrl
    
    CFavTreeCtrl::CFavTreeCtrl()
    {
    	m_strRoot = "";
    	bFirstExpand = TRUE;
    	bFirstSelect = TRUE;
    	bFirstExpandedSelect = TRUE;
    	bFirstDisplay = TRUE;
    //	AfxBeginThread(MonitorMyEmotesDir, GetSafeHwnd());
    }
    
    CFavTreeCtrl::~CFavTreeCtrl()
    {
    	m_imgList.Detach();
    }
    
    
    BEGIN_MESSAGE_MAP(CFavTreeCtrl, CTreeCtrl)
    	//{{AFX_MSG_MAP(CFavTreeCtrl)
    	ON_NOTIFY_REFLECT(TVN_ITEMEXPANDED, OnItemexpanded)
    	ON_NOTIFY_REFLECT(TVN_SELCHANGING, OnSelchanging)
    	//}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    
    /////////////////////////////////////////////////////////////////////////////
    
    
    BOOL CFavTreeCtrl::DisplayTree(LPCTSTR strRoot, BOOL bFiles)
    {
    	DWORD dwStyle = GetStyle();   // read the windowstyle
    	if ( dwStyle & TVS_EDITLABELS ) 
    	{
    		// Don't allow the user to edit ItemLabels
    		ModifyStyle( TVS_EDITLABELS , 0 );
    	}
    	
    	// Display the DirTree with the Rootname e.g. C:\
    	// if Rootname == NULL then Display all Drives on this PC
        // First, we need the system-ImageList
    	
    	DeleteAllItems();
    
    	if ( !GetSysImgList() )
    		return FALSE;
        m_bFiles = bFiles;  // if TRUE, Display Path- and Filenames 
    	if ( strRoot == NULL || strRoot[0] == '\0' )
    	{
    		m_strRoot = "";
    	}
        else
    	{
    		m_strRoot = strRoot;
    		if ( m_strRoot.Right(1) != '\\' )
    			m_strRoot += "\\";
    		HTREEITEM hParent = AddItem( TVI_ROOT, m_strRoot );		
    		DisplayPath( hParent, strRoot );
    		Expand(hParent,TVE_EXPAND );		
    	}
    
    	return TRUE;	
    }
    /////////////////////////////////////////////////
    BOOL CFavTreeCtrl::GetSysImgList()
    /////////////////////////////////////////////////
    {
    	SHFILEINFO shFinfo;
    	HIMAGELIST hImgList = NULL;
    
    	if ( GetImageList( TVSIL_NORMAL ) )
    		m_imgList.Detach();
    	
    	hImgList = (HIMAGELIST)SHGetFileInfo( "C:\\",
    							  0,
    							  &shFinfo,
    							  sizeof( shFinfo ),
    							  SHGFI_SYSICONINDEX | 
    							  SHGFI_SMALLICON );
    	if ( !hImgList )
    	{
    		m_strError = "Cannot retrieve the Handle of SystemImageList!";
    		return FALSE;
    	}
    
    	m_imgList.m_hImageList = hImgList;    
        
    	SetImageList( &m_imgList, TVSIL_NORMAL );
    	return TRUE;   // OK
    }
    
    void CFavTreeCtrl::DisplayPath(HTREEITEM hParent, LPCTSTR strPath)
    {
    //	MessageBox(strPath, "TEST 1", MB_OK);
    	//
    	// Displaying the Path in the TreeCtrl
    	//
    	CString strTemp;
    	CFileFind find;
    	CString   strPathFiles = strPath;
    	BOOL      bFind;
    	CSortStringArray strDirArray;
    	CSortStringArray strFileArray;
    	
    	if ( strPathFiles.Right(1) != "\\" )
    	{
    		strPathFiles += "\\";
    	}
    	strPathFiles += "*.*";
    
    	bFind = find.FindFile( strPathFiles );
    
    	while ( bFind )
    	{
            bFind = find.FindNextFile();
    		if ( find.IsDirectory() && !find.IsDots() )
    		{		
    			strDirArray.Add( find.GetFilePath() );
    		}
    		if ( !find.IsDirectory() && m_bFiles )
    		{
                    //NOTE: this is the new code ...
    			strTemp = find.GetFileName();
    			if(strTemp.Right(3) == "url" ||
    				strTemp.Right(3) == "URL")
    			{
    				strFileArray.Add( find.GetFilePath() );
    			}
    		}
    	}
        
    	strDirArray.Sort();
    	SetRedraw( FALSE );
    	CWaitCursor wait;
        
    	for ( int i = 0; i < strDirArray.GetSize(); i++ )
    	{
    		HTREEITEM hItem = AddItem( hParent, strDirArray.GetAt(i) );
    			if ( FindSubDir( strDirArray.GetAt(i) ) )
    			{
    				InsertItem( "", 0, 0, hItem );
    			}
    	}
    
    	if ( m_bFiles )
    	{
    		strFileArray.Sort();
    		for ( i = 0; i < strFileArray.GetSize(); i++ )
    		{
    			HTREEITEM hItem = AddItem( hParent, strFileArray.GetAt(i) );
    		}
    	}	
    	HTREEITEM hTreeParent = GetRootItem();
    	SetRedraw( TRUE );
    	SetItemText(hTreeParent, "My Emotes");
    }
    
    HTREEITEM CFavTreeCtrl::AddItem(HTREEITEM hParent, LPCTSTR strPath)
    {
    	// Adding the Item to the TreeCtrl with the current Icons
    	SHFILEINFO shFinfo;
    	int iIcon, iIconSel;
        CString    strTemp = strPath;
        
    	if ( strTemp.Right(1) != '\\' )
    		 strTemp += "\\";
    	if ( !SHGetFileInfo( strTemp,
    						0,
    						&shFinfo,
    						sizeof( shFinfo ),
    						SHGFI_ICON | 
    					    SHGFI_SMALLICON ) )
    	{
    		m_strError = "Error Gettting SystemFileInfo!";
    		return NULL;
    	}
    
    	iIcon = shFinfo.iIcon;
    
    	// we only need the index from the system image list
    
    	DestroyIcon( shFinfo.hIcon );
    
    	if ( !SHGetFileInfo( strTemp,
    						0,
    						&shFinfo,
    						sizeof( shFinfo ),
    						SHGFI_ICON | SHGFI_OPENICON |
    					    SHGFI_SMALLICON ) )
    	{
    		m_strError = "Error Gettting SystemFileInfo!";
    		return NULL;
    	}
    
    	iIconSel = shFinfo.iIcon;
    
    	// we only need the index of the system image list
    
    	DestroyIcon( shFinfo.hIcon );
    
    	if ( strTemp.Right(1) == "\\" )
    		strTemp.SetAt( strTemp.GetLength() - 1, '\0' );
    	
    	if ( hParent == TVI_ROOT )
    		return InsertItem( strTemp, iIcon, iIconSel, hParent );
    	
    	return InsertItem( GetSubPath( strTemp ), iIcon, iIconSel, hParent );
    }
    
    LPCTSTR CFavTreeCtrl::GetSubPath(LPCTSTR strPath)
    {
    	//
    	// getting the last SubPath from a PathString
    	// e.g. C:\temp\readme.txt
    	// the result = readme.txt
    	static CString strTemp;
    	int     iPos;
    
    	strTemp = strPath;
    	if ( strTemp.Right(1) == '\\' )
    		 strTemp.SetAt( strTemp.GetLength() - 1, '\0' );
    	iPos = strTemp.ReverseFind( '\\' );
    	if ( iPos != -1 )
    	    strTemp = strTemp.Mid( iPos + 1);
    
    	return (LPCTSTR)strTemp;
    }
    
    BOOL CFavTreeCtrl::FindSubDir( LPCTSTR strPath)
    {
    	//
    	// Are there subDirs ?
    	//
    	CFileFind find;
    	CString   strTemp = strPath;
    	BOOL      bFind;
    
    	if ( strTemp[strTemp.GetLength()-1] == '\\' )
    		strTemp += "*.*";
    	else
    		strTemp += "\\*.*";
    		
    	bFind = find.FindFile( strTemp );
    	
    	
    	while ( bFind )
    	{
    		bFind = find.FindNextFile();
    
    		if ( find.IsDirectory() && !find.IsDots() )
    		{
    			return TRUE;
    		}
    		if ( !find.IsDirectory() && m_bFiles && !find.IsHidden() )
    			return TRUE;
    		
    	}
    
    	return FALSE;
    
    }
    
    void CFavTreeCtrl::OnSelchanging(NMHDR* pNMHDR, LRESULT* pResult) 
    {
    	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
    	// TODO: Add your control notification handler code here
    	
    	
    	CString strExtension;
    	strExtension = GetFullPath(pNMTreeView->itemNew.hItem);
    
    	if (pNMTreeView->itemNew.state & TVIS_EXPANDED)
    	{
    		if(bFirstExpandedSelect == TRUE)
    		{
    			GetItemImage(pNMTreeView->itemNew.hItem, nExpandedSelectClosedFolder, nExpandedSelectOpenFolder);
    			bFirstExpandedSelect = FALSE;
    		}
    
    		SetItemImage(pNMTreeView->itemNew.hItem, nExpandedSelectClosedFolder, nExpandedSelectOpenFolder);
    	}
    	else
    	{
    		if(bFirstSelect == TRUE)
    		{
    			GetItemImage(pNMTreeView->itemNew.hItem, nSelectClosedFolder, nSelectOpenFolder);
    			bFirstSelect = FALSE;
    		}
    
    		if(strExtension.Right(3) == "url" || 
    			strExtension.Right(3) == "URL")
    		{
    			
    		}
    		else
    		{
    			SetItemImage(pNMTreeView->itemNew.hItem, nSelectClosedFolder, nSelectClosedFolder);
    		}
    	}
    	
    	*pResult = 0;
    }
    
    void CFavTreeCtrl::OnItemexpanded(NMHDR* pNMHDR, LRESULT* pResult) 
    {
    	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
    	CString strPath;
    
    	if(bFirstExpand == TRUE)
    	{
    		GetItemImage(pNMTreeView->itemNew.hItem, nExpandClosedFolder, nExpandOpenFolder);
    		bFirstExpand = FALSE;
    	}
    		 
    	if ( pNMTreeView->itemNew.state & TVIS_EXPANDED )
    	{
    		SetItemImage(pNMTreeView->itemNew.hItem, nExpandOpenFolder, nExpandOpenFolder);
    		ExpandItem( pNMTreeView->itemNew.hItem, TVE_EXPAND );
    	}
    	else
    	{
    		if (pNMTreeView->itemNew.state & TVIS_SELECTED)
    		{
    			SetItemImage(pNMTreeView->itemNew.hItem, nExpandClosedFolder, nExpandClosedFolder);
    		}
    		else
    		{
    			SetItemImage(pNMTreeView->itemNew.hItem, nExpandClosedFolder, nExpandOpenFolder);
    		}
    //		SetItemImage(pNMTreeView->itemNew.hItem, nExpandClosedFolder, nExpandOpenFolder);
    		//
    		// Delete the Items, but leave one there, for 
    		// expanding the item next time
    		//
    		HTREEITEM hChild = GetChildItem( pNMTreeView->itemNew.hItem );
    				
    		while ( hChild ) 
    		{
    			DeleteItem( hChild );
    			hChild = GetChildItem( pNMTreeView->itemNew.hItem );
    		}
    		InsertItem( "", pNMTreeView->itemNew.hItem );
    	}
    
    	*pResult = 0;
    }
    
    CString CFavTreeCtrl::GetFullPath(HTREEITEM hItem)
    {
    	// get the Full Path of the item
    	CString strReturn;
    	CString strTemp;
    	HTREEITEM hParent = hItem;
    
    	strReturn = "";
    
    	while ( hParent )
    	{
    		
    		strTemp  = GetItemText( hParent );
    		if(strTemp == "My Emotes")
    		{
    			strTemp = m_strRoot;
    			strTemp.TrimRight( '\\' );
    		}
    		strTemp += "\\";
    		strReturn = strTemp + strReturn;
    		hParent = GetParentItem( hParent );
    	}
        
    	strReturn.TrimRight( '\\' );
    
        return strReturn;
    
    }
    
    BOOL CFavTreeCtrl::SetSelPath(LPCTSTR strPath)
    {
    	// Setting the Selection in the Tree
    	HTREEITEM hParent  = TVI_ROOT;
    	int       iLen    = strlen(strPath) + 2;
    	char*     pszPath = new char[iLen];
    	char*     pPath   = pszPath;
    	BOOL      bRet    = FALSE;
        
    	if ( !IsValidPath( strPath ) )
    	{
    		delete [] pszPath; // this must be added 29.03.99
    		return FALSE;
    	}
    		
    	strcpy( pszPath, strPath );
    	strupr( pszPath );
    	
    	if ( pszPath[strlen(pszPath)-1] != '\\' )
    		strcat( pszPath, "\\" );
        
    	int iLen2 = strlen( pszPath );
    	
    	for (WORD i = 0; i < iLen2; i++ )
    	{
    		if ( pszPath[i] == '\\' )
    		{
    			SetRedraw( FALSE );
    			pszPath[i] = '\0';
    			hParent = SearchSiblingItem( hParent, pPath );
    			if ( !hParent )  // Not found!
    				break;
    			else
    			{				
    				// Info:
    				// the notification OnItemExpanded 
    				// will not called every time 
    				// after the call Expand. 
    				// You must call Expand with TVE_COLLAPSE | TVE_COLLAPSERESET
    				// to Reset the TVIS_EXPANDEDONCE Flag
    				
    				UINT uState;
    				uState = GetItemState( hParent, TVIS_EXPANDEDONCE );
    				if ( uState )
    				{
    					Expand( hParent, TVE_EXPAND );
    					Expand( hParent, TVE_COLLAPSE | TVE_COLLAPSERESET );
    					InsertItem("", hParent ); // insert a blank child-item
    					Expand( hParent, TVE_EXPAND ); // now, expand send a notification
    				}
    				else
    					Expand( hParent, TVE_EXPAND );
    			}
    			pPath += strlen(pPath) + 1;
    		}
    	}
    
    	delete [] pszPath;
    	
    	if ( hParent ) // Ok the last subpath was found
    	{		
    		SelectItem( hParent ); // select the last expanded item
    		bRet = TRUE;
    	}
    	else
    	{
    		bRet = FALSE;
    	}
    	
    	SetRedraw( TRUE );
    
        return bRet;
    }
    
    HTREEITEM CFavTreeCtrl::SearchSiblingItem( HTREEITEM hItem, LPCTSTR strText)
    {
    	HTREEITEM hFound = GetChildItem( hItem );
    	CString   strTemp;
    	while ( hFound )
    	{
    		strTemp = GetItemText( hFound );
            strTemp.MakeUpper();
    		if ( strTemp == strText )
    			return hFound;
    		hFound = GetNextItem( hFound, TVGN_NEXT );
    	}
    
    	return NULL;
    }
    
    void CFavTreeCtrl::ExpandItem(HTREEITEM hItem, UINT nCode)
    {	
    	CString strPath;
    	
    	if ( nCode == TVE_EXPAND )
    	{
    		HTREEITEM hChild = GetChildItem( hItem );
    		while ( hChild )
    		{
    			DeleteItem( hChild );
    			hChild = GetChildItem( hItem );
    		}
    
    		strPath = GetFullPath( hItem );
     
    		DisplayPath( hItem, strPath );
    	}
    }
    
    BOOL CFavTreeCtrl::IsValidPath(LPCTSTR strPath)
    {
    	// This function check the Pathname
    	
    	HTREEITEM hChild;
    	CString   strItem;
    	CString   strTempPath = strPath;
    	BOOL      bFound = FALSE;
    	CFileFind find;
    
    	hChild = GetChildItem( TVI_ROOT );
    	strTempPath.MakeUpper();
    	strTempPath.TrimRight('\\');
    
    	while ( hChild )
    	{
    		strItem = GetItemText( hChild );
    		strItem.MakeUpper();
    		if ( strItem == strTempPath.Mid( 0, strItem.GetLength() ) )
    		{
    			bFound = TRUE;
    			break;
    		}
    		hChild = GetNextItem( hChild, TVGN_NEXT );
    	}
        
    	if ( !bFound )
    		return FALSE;
    
    	strTempPath += "\\nul";
    	if ( find.FindFile( strTempPath ) )
    		return TRUE;
         
    	return FALSE;
    }
    
  • idbruceidbruce Posts: 6,197
    edited 2015-05-01 10:29
    Referring to "." and ".." and the code I posted above, MFC had the CFileFind class, and one of the class functions, was called IsDots(), and you can see it being used above as if ( find.IsDirectory() && !find.IsDots() )

    Not that it is applicable, just you guys got me thinking about this stuff :)
  • idbruceidbruce Posts: 6,197
    edited 2015-05-01 10:43
    Dave
    Here's a program that does a recursive listing. It works under cygwin, but I haven't tested it on the Prop. I had to test for the directories "." and ".." to prevent it from getting into an infinite loop.

    If you get that tested on the Prop, please let us know the results. I would test it, but I only have three files on my SD card.
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-05-01 19:36
    I ran it on the Prop, and it worked fine with one level of sub-directories, but not with multiple levels. I wasn't providing a complete path name, so it was always doing opendir on a directory in the root directory. After I created a full path name it worked fine for multiple levels of sub-directories.
    #include <stdio.h>
    #include <propeller.h>
    #include "simpletools.h"
    #include <dirent.h>
    
    #define SD_DO 22
    #define SD_CLK 23
    #define SD_DI 24
    #define SD_CS 25
    
    void listfiles(char *dirname)
    {
        DIR *sd_dir = opendir(dirname);
        struct dirent *dir_entry;
        char subdir[80];
        int len = strlen(dirname);
    
        if(!sd_dir) return;
    
        // List files in this directory
        printf("\n%s:\n", dirname);
        while((dir_entry = readdir(sd_dir)))
            printf("%s\n", dir_entry->d_name);
        closedir(sd_dir);
    
        // List files in sub-directories
        sd_dir = opendir(dirname);
        while((dir_entry = readdir(sd_dir)))
        {
            if (strcmp(dir_entry->d_name, ".") && strcmp(dir_entry->d_name, ".."))
            {
                strcpy(subdir, dirname);
                if (dirname[len-1] != '/') strcat(subdir, "/");
                strcat(subdir, dir_entry->d_name);
                listfiles(subdir);
            }            
        }
        closedir(sd_dir);
    }
    
    int main()
    {
        waitcnt(CNT+CLKFREQ);
        sd_mount(SD_DO, SD_CLK, SD_DI, SD_CS);
        listfiles("/");
        return 0;
    }
    
  • idbruceidbruce Posts: 6,197
    edited 2015-05-02 00:14
    Well Dave...

    I do believe you have managed to sidetrack me a little. Please allow me to explain.

    I have always prided myself with the ability to program and navigate files, folders, and disk paths, although in a Windows environment, where different functions were utilized. As it stands now, I feel like a duck out of water, with a completely new set of rules and functions, and I somehow feel obligated to learn these new rules and functions.

    I was going to take the easy way out, and just store individual files within the root of the SD, but now that you have exposed me to various file and folder functions, I think I will create a directory tree and explore a little, just to acquire navigational skills. I don't know where this is leading, but hopefully I will be able to wrap my head around it fairly quickly.
    I ran it on the Prop, and it worked fine with one level of sub-directories, but not with multiple levels. I wasn't providing a complete path name, so it was always doing opendir on a directory in the root directory. After I created a full path name it worked fine for multiple levels of sub-directories.

    That seems odd that it would only go one level deep in the root, but with a full path it would go further. Okay, time to go educate myself :)
  • Heater.Heater. Posts: 21,230
    edited 2015-07-01 22:28
    "side tracked"? Dave was only answering the original question. And very nicely too.

    Welcome to the freedom of the world outside Windows. Take a deep breath of the fresh air and dive in (Is that an odd mix of metaphors?)

    It's a *****, you can spend years thinking you know how to program and every now and then be reminded you know nothing and all your assumptions may not be absolute truths. JavaScript gave me that jolt as it throws away some dearly held conceptions and introduces other subtle ways to program. Just now I'm playing with Erlang, again a language built around a totally different view of the programming problem.

    Sorry, just rambling again...
  • idbruceidbruce Posts: 6,197
    edited 2015-05-02 03:08
    Dave was only answering the original question. And very nicely too.

    Yes indeed.
    Take a deep breath of the fresh air and dive in

    LOL I have taken the leap.... As I swim about, it appears that it is not only direct C library functions that are being utilized. It is a llittle confusing, but muddling my way through it.

    As far as I can determine.... remove, rename, chdir, rmdir, and mkdir all return 0 on success and -1 for failure. Is this correct?

    And.... When making file paths, should a forwardslash or a backslash be used? I read that either can be used for SD. I would assume that the backslash is the norm for creating paths, with "\" being the delimiter, since that is the delimiter for print commands.
  • Heater.Heater. Posts: 21,230
    edited 2015-05-02 03:43
    I believe 0 for success and -1 for error is true for all of them. You can check here for example http://www.tutorialspoint.com/c_standard_library/c_function_rename.htm

    If you use anything other than "/" as a path separator I will have to come round your place and taunt you.

    I wonder if they set errno when there is an error. Which can then be translated and printed as a string with perror() or just converted to a string with strerror().
  • idbruceidbruce Posts: 6,197
    edited 2015-05-02 03:54
    I believe 0 for success and -1 for error is true for all of them. You can check here for example http://www.tutorialspoint.com/c_stan...ion_rename.htm

    I was there earlier, and their documentation is what I was basing my assumptions upon :)
    If you use anything other than "/" as a path separator I will have to come round your place and taunt you.

    That's good to know, since I assumed the "\".
    I wonder if they set errno when there is an error. Which can then be translated and printed as a string with perror() or just converted to a string with strerror().

    If so, once again assuming... I would assume this would be a "last known error", which must be used immediately, before being replaced???
  • Heater.Heater. Posts: 21,230
    edited 2015-05-02 04:03
    Yep, I always thought the errno thing was crazy.
  • idbruceidbruce Posts: 6,197
    edited 2015-05-02 04:09
    Heater

    Since you are being kind enough to answer some of my lingering questions, let me ask you another.

    Many of the functions have a parameter of "path", whereas "remove" and "rename" take file names. Do I have to be in the working directory to call these functions or can I also just supply a path to these functions?
  • Heater.Heater. Posts: 21,230
    edited 2015-05-02 04:14
    As far as I know that tutorial description is wrong. Man pages for stdio describe it as:

    #include <stdio.h>

    int remove(const char *pathname);
  • idbruceidbruce Posts: 6,197
    edited 2015-05-02 04:22
    Thanks Heater

    I will just try it out and see what happens.

    I am currently working on a file and folder functions wrapper for SD card access. I figure one file for all the necessary operations, just to make file access and manipulation a little easier.

    Here is what I have so far, with the lower functions still needing to be defined. I have the mindless stuff done already :) Now it will get a little more difficult :)
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <propeller.h>
    #include <dirent.h>
    #include "simpletools.h"
    
    #define FSLASH TEXT('/')
    
    
    int create_directory(const char *path)
    {
        int ret;
        
        ret = mkdir(path, 0);
        
        return ret;
    }    
    int delete_directory(const char *path)
    {
        int ret;
        
        ret = rmdir(path);
        
        return ret;
    }
    
    int delete_file(char *filename)
    {
        int ret;
        
        ret = remove(filename);
        
        return ret;
    }       
    get_current_directory
    set_current_directory
    list_directory_files
    path_get_root
    path_add_backslash
    path_append
    create_directory_path
    is_path_valid
    is_directory
    
  • Heater.Heater. Posts: 21,230
    edited 2015-05-02 04:28
    I'm not sure I see the point of wrapping one line calls to stdio functions. Isn't that just generating more code and wasting HUB space for almost no benefit?
  • idbruceidbruce Posts: 6,197
    edited 2015-05-02 04:38
    Well it is definitely a waste of space....

    However, in the past, I created something similar for Windows and found it to be extremely useful, instead of trying to remember all the various functions and includes. I would simply add one header file and one source file, and then I was ready to perform almost any file and folder operation that I wanted to do, with the header file being a handy quick reference at my disposal.

    One include and you are good to go.
Sign In or Register to comment.