GFileScanner




I wrote this  because i needed it in my appliction :-)

Maybe this could me implemented in glib?

GFIleScanner is scans directory/file contents and supports
filecompletion (using GCompletion functions).

The API is simple and could be used in to search for files
or in a run application/command line prompt etc...

Three functions:

g_file_scanner_new(GFileScannerFunc func)

/* scan selected directory or show all matches */
g_file_scanner_set_path(GFileScanner *fc,gchar *source);

/* use this to update directory contents */
g_file_scanner_change_path(GFileScanner *fc,gchar *source);

The callback:
typedef gboolean (GFileScannerFunc *) (gchar *filename,struct stat *st,gpointer
data);

/* gchar *filename = filename :-) */
/* struct stat *st= a pointer to fileinformation from the stat() routine */
/* return: FALSE stop iteration TRUE continue */

Do we need it in glib? IMHO yes :-)

Greats

Mikael Hermansson
/*  gfilescanner.c
*  Copyright (C) 2000 by:
** Mikael Hermansson
*
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/


#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <glib.h>
#ifdef G_OS_WIN32
#include <direct.h>
#include <io.h>
#define mkdir(p,m) _mkdir(p)
#ifndef S_ISDIR
#define S_ISDIR(mode) ((mode)&_S_IFDIR)
#endif

#endif /* G_OS_WIN32 */

#include "gfilescanner.h"


static gboolean g_file_scanner_list(GFileScanner *fsc,GList *list);
static void g_file_scanner_clearall(GFileScanner *fsc);
static gboolean g_file_scandir(GFileScanner *fsc,gchar *search);
static void swapstrcat(gpointer data,gpointer data2);

GFileScanner* g_file_scanner_new(GFileScannerFunc func,gpointer data)
{
  GFileScanner *fscanner;
  g_return_val_if_fail(func!=NULL, NULL);

  fscanner=g_new(GFileScanner,1);
  fscanner->func=func;
  fscanner->completion=g_completion_new(NULL);  
  fscanner->data=data;
  fscanner->path=NULL;

  return fscanner;
}

void g_file_scanner_free(GFileScanner *fsc)
{
  g_return_if_fail(fsc!=NULL);

  g_file_scanner_clearall(fsc);
  g_completion_free(fsc->completion);

  g_free(fsc);
}

gboolean g_file_scanner_set_path(GFileScanner *fsc, gchar *insearch)
{
  struct stat st;
  gboolean fileexist;
  gchar *source=NULL;

  g_return_val_if_fail(fsc!=NULL,FALSE);
  g_return_val_if_fail(insearch!=NULL,FALSE);

  g_file_scanner_clearall(fsc);

  source=g_path_full(insearch);
  
  fileexist=stat(source,&st) ? FALSE : TRUE;  
  /* source is a directory just scan contents normally */  
  if(fileexist && S_ISDIR(st.st_mode))  
  {
      g_file_scandir(fsc,source);

      return g_file_scanner_list(fsc,fsc->completion->items);
  }  
  else if(fileexist)  /* source is a file */
  {
      GList *list;

      g_file_scanner_clearall(fsc);
      list=g_list_alloc();

      list->data=g_strdup(source);
      g_completion_add_items(fsc->completion,list);

      return g_file_scanner_list(fsc,list);
  }
  else /* source is not a file/directory  */
  {      /* need to scan for any filematches in parent directory  */
  
      GList *list;
      gchar *tmp;  
   
      /* get parent dir and scan it */  
      tmp=g_path_get_dirname(source);
      g_file_scandir(fsc,tmp);
      g_free(tmp);

      /* get all matches using GCompletion */
      list=g_completion_complete(fsc->completion,source,NULL);

      /* foreach loop */
      return g_file_scanner_list(fsc,list);
  }      
  return FALSE;
}

/* user should only call this after initiated with set_path 
   for example if file points to "/home/mikeh" 
   the user wants to go back to /home 
   you can call this by just add "../" 
   and it will scandirectory contents in /home 
*/

gboolean g_file_scanner_change_path(GFileScanner *fsc,gchar *inpath)
{
  gboolean ret=FALSE;
  gchar *path=NULL;

  if(g_path_is_absolute(inpath) || !fsc->path) 
    return g_file_scanner_set_path(fsc,inpath); 
  else  
    path=g_strdup_printf("%s%s",fsc->path,inpath);

  ret=g_file_scanner_set_path(fsc,path);
  g_free(path);

  return ret;  
}

/* DIR_SEPERATOR and ".." convertor */
/* removes [.] and [..] */

gchar * g_path_full(gchar *inp)
{
  register gint i;
  gint killnext=0;
  gchar *newpath=NULL; 
  gchar *ap;  
  GList *list=NULL;
  g_return_val_if_fail(inp,NULL);  

  list=g_list_alloc();
  if(!g_path_is_absolute(inp)) {
    gchar *tmp=g_get_current_dir();
    ap=g_strdup_printf("%s%s%s",tmp,G_DIR_SEPARATOR_S,inp);  
    g_free(tmp);        
  }
  else
    ap=g_strdup(inp);

  i=strlen(ap)-1;
  newpath=g_malloc(i+1);
  newpath[0]='\0';
  while(i >= 0)  
  { 
    if(ap[i]=='~')  {
      i--;
      list=g_list_prepend(list,g_get_home_dir());
      ap[i]='\0';
    }
    else if(ap[i]=='*')  
      ap[i--]='\0';
    else if(ap[i]=='.')  {
      if(i>0 && ap[i-1]=='.')
      {   i-=2;       killnext++;  }

      ap[i]='\0';
    }
    else if (ap[i]==G_DIR_SEPARATOR && killnext)
    {  killnext--;   ap[i]='\0';  } 
    else if (ap[i]==G_DIR_SEPARATOR)   
    {  ap[i]='\0'; if(ap[i+1]) list=g_list_prepend(list,g_strdup(&ap[i+1]));  }

    i--;
  };  
   
  g_list_foreach(list,(GFunc)swapstrcat,newpath);
  g_list_foreach(list,(GFunc)g_free,NULL);
  g_list_free(list);

  return newpath;
}

/* g_file_scanner_list */
/* this function is calling the users callbackfunc */
/* GFileScannerFunc(gchar *filename,struct stat *st,gpointer data) */
/* The filenames is NOT sorted */
/* user can return FALSE to stop iterate files */

gboolean g_file_scanner_list(GFileScanner *fsc,GList *list)
{
  GList *cur;
  struct stat st;
  
  cur=g_list_first(list);
  while(cur && cur->data)  
  {
    if(stat((gchar*)cur->data,&st)!=0)
          g_warning("Could not stat dir/file [%s]!?",(gchar *)cur->data);

    if(!fsc->func((gchar *)cur->data,&st,fsc->data))
      return FALSE;  /* user stoped iteration */
    
    cur=g_list_next(cur);      
  };
  return TRUE;
}

/*-------------------------------------------*/
/*   static member functions                                                               */
/*--------------------------------------------*/

gboolean g_file_scandir(GFileScanner *fsc,gchar *search)
{
  GList* list;
  DIR *dir;
  struct dirent *direntry;

  dir=opendir(search);
  if(!dir)
    return FALSE;
  
  fsc->path=g_strdup(search);
  if(fsc->completion->items)
    g_completion_clear_items(fsc->completion);       
  
  list=g_list_alloc();
  direntry=readdir(dir);      
  while(direntry)    
  {
      list->data=g_strdup_printf("%s%s%s",search,G_DIR_SEPARATOR_S,direntry->d_name);
      g_completion_add_items(fsc->completion,list);

      direntry=readdir(dir);      
  }
  closedir(dir);
  return TRUE;
}

static void g_file_scanner_clearall(GFileScanner *fsc)
{
  if(fsc->completion->items)  {
    g_list_foreach(fsc->completion->items,(GFunc)g_free,NULL);
    g_completion_clear_items(fsc->completion);
  }
  if(fsc->path)  {
    g_free(fsc->path);
    fsc->path=NULL;
  }
}

void swapstrcat(gpointer data,gpointer data2)
{
  if(!data)
    return ;

  strcat(data2,G_DIR_SEPARATOR_S);
  strcat(data2,data);
}

/*-------------------------------------------*/
/* TESTAPPLICATION                                                                 */
/*--------------------------------------------*/

gboolean cb(gchar *file,struct stat *st,gpointer data)
{
  if(S_ISDIR(st->st_mode))
    g_print("Directoryname %s\n",file);
  else 
    g_print("Filename %s\n",file);


   return TRUE;
};


int main(int argc, char *argv[])
{
  GFileScanner *fc;
  if(argc<2)  {
    g_print("filetest directory\n");
    return -1;
  }

  fc=g_file_scanner_new(cb,NULL);
  g_file_scanner_set_path(fc,argv[1]);
   g_file_scanner_free(fc);

  return 0;     
}

/*  gfilescanner.h
*  Copyright (C) 2000 by:
** Mikael Hermansson
*
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#ifndef __GFILESCANNER_H__
#define __GFILESCANNER_H__

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */ 

typedef gboolean ( *GFileScannerFunc)(gchar *filename, struct stat *st, gpointer userdata);

typedef struct _GFileScanner GFileScanner;

struct _GFileScanner
{
  GList* items;
  GFileScannerFunc func;
  GCompletion *completion;  
  gchar *path;
  gpointer data;

};


GFileScanner* g_file_scanner_new(GFileScannerFunc func, gpointer userdata);

/* return false if callback is aborted when scann */

gboolean g_file_scanner_set_path(GFileScanner *fsc,gchar *filename);
gboolean g_file_scanner_change_path(GFileScanner *fsc,gchar *inpath);
gchar* g_path_full(gchar *filename);


#ifdef __cplusplus
}
#endif /* __cplusplus */ 
#endif /* end of __GFILESCANNER_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]