Files
commandergenius/project/jni/application/lbreakout2/client/file.c

531 lines
16 KiB
C

/***************************************************************************
file.c - description
-------------------
begin : Thu Jan 18 2001
copyright : (C) 2001 by Michael Speck
email : kulkanie@gmx.net
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include "../common/list.h"
#include "../common/tools.h"
#include "file.h"
//#define FILE_DEBUG
/*
====================================================================
Test file in path as mode.
Return Value: True if sucessful
====================================================================
*/
int file_check( char *path, char *fname, char *mode )
{
char *full_path;
FILE *file = 0;
int ok = 0;
full_path = calloc( strlen( path ) + strlen( fname ) + 2, sizeof( char ) );
sprintf( full_path, "%s/%s", path, fname );
if ( ( file = fopen( full_path, mode ) ) != 0 ) {
fclose( file );
ok = 1;
}
free( full_path );
return ok;
}
/*
====================================================================
Open file in path according to type (write, read, append)
Return Value: File handle if successful else Null
====================================================================
*/
FILE *file_open( char *path, char *fname, int type )
{
FILE *file = 0;
char *full_path;
char mode[3] = "a";
full_path = calloc( strlen( path ) + strlen( fname ) + 2, sizeof( char ) );
sprintf( full_path, "%s/%s", path, fname );
switch ( type ) {
case FILE_READ:
if ( ( file = fopen( full_path, "rb" ) ) == 0 )
fprintf( stderr, "file_open: cannot open file '%s' for reading: permission denied or non-existent\n", full_path );
break;
case FILE_WRITE:
sprintf( mode, "w" );
case FILE_APPEND:
if ( ( file = fopen( full_path, mode ) ) == 0 )
fprintf( stderr, "file_open: cannot open file '%s': permission denied\n", full_path );
break;
}
return file;
}
/*
====================================================================
Read all lines from file pointer and return as static array.
Resets the file pointer. Should only be used when reading a whole
file.
====================================================================
*/
char** file_read_lines( FILE *file, int *count )
{
int nl_count = 0;
char c;
char **lines;
char buffer[1024];
if ( !file ) return 0;
/* count new_lines */
fseek( file, 0, SEEK_SET );
while ( !feof( file ) ) {
fread( &c, sizeof( char ), 1, file );
if ( c == 10 ) nl_count++;
}
fseek( file, 0, SEEK_SET );
nl_count++; /* maybe last lines wasn't terminated */
/* get mem */
lines = calloc( nl_count, sizeof( char* ) );
/* read lines */
*count = 0;
while( !feof( file ) ) {
if ( !fgets( buffer, 1023, file ) ) break;
if ( buffer[0] == 10 ) continue; /* empty line */
buffer[strlen( buffer ) - 1] = 0; /* cancel newline */
lines[*count] = strdup( buffer );
(*count)++;
}
return lines;
}
/* check consistence of file (all brackets/comments closed).
will reset the file pos to the very beginning */
int check_file_cons( FILE *file )
{
int brac = 0, comm = 0;
char c;
int ok = 1;
fseek( file, 0, SEEK_SET );
while ( !feof( file ) ) {
fread( &c, 1, 1, file );
switch ( c ) {
case '(': brac++; break;
case ')': brac--; break;
case '#': comm++; break;
}
}
fseek( file, 0, SEEK_SET );
if ( brac != 0 || ( comm % 2) != 0 ) {
#ifdef FILE_DEBUG
if ( brac != 0 )
printf("the number of opening and closing brackets does not fit!...\n");
else
printf("the number of opening and closing comment hashes does not fit!...\n");
#endif
ok = 0;
}
return ok;
}
/* return line number; keeps current file pos */
int get_line_number( FILE *file ) {
int count = 0;
char c;
int pos = ftell( file );
fseek( file, 0, SEEK_SET );
while ( ftell( file ) < pos - 1 ) {
fread( &c, sizeof( char ), 1, file );
if ( c == 10 ) count++;
}
fseek( file, pos, SEEK_SET );
return count + 1;
}
/* ignore all blanks and jump to next none-blank */
void ignore_blanks( FILE *file )
{
char c;
do {
fread( &c, sizeof( char ), 1, file );
} while ( c <= 32 && !feof( file ) );
if ( !feof( file ) )
fseek( file, -1, SEEK_CUR ); /* restore last none-blank */
}
/* add character to token and check max length; return true if below max length */
int add_char( char *token, int c )
{
int length = strlen( token );
/* check token length */
if ( length == MAX_TOKEN_LENGTH - 1 ) {
fprintf( stderr,
"read_token: token '%s' reached maximum length of %i, reading skipped\n",
token, length );
return 0;
}
token[length++] = c;
token[length] = 0;
return 1;
}
/* read token from current file position; ignore spaces;
tokes are:
(
)
=
# comment #
" string "
normal_token
save token in token and check that MAX_TOKEN_LENGTH is not exceeded
return true if not end of file */
int read_token( FILE *file, char *token )
{
int length = 0; /* token length */
char c;
int read_str = 0; /* if this is set token is a string "..." */
int i;
/* clear token */
token[0] = 0;
/* ignore all blanks before token */
ignore_blanks( file );
while( !feof( file ) ) {
fread( &c, sizeof( char ), 1, file );
/* treat new_lines as blanks */
if ( c == 10 ) c = 32;
/* check if this is a comment; if so ignore all characters in between */
if ( c == '#' && !read_str ) {
/* read all characters until '#' occurs */
do {
fread( &c, sizeof( char ), 1, file );
} while ( c != '#' );
/* ignore all blanks after comment */
ignore_blanks( file );
continue; /* start reading again */
}
/* add char */
if ( !add_char( token, c ) ) {
/* in this case restore last char as it belongs to next token */
fseek( file, -1, SEEK_CUR );
break;
}
else
length++;
/* check if token ends with a special single-character assignment token */
if ( !read_str )
if ( c == '(' || c == ')' || c == '=' ) {
/* if this wasn't the first character it already belongs to a new token, so skip it */
if ( length > 1 ) {
fseek( file, -1, SEEK_CUR );
token[--length] = 0;
}
break;
}
/* check if this char is a blank */
if ( c <= 32 && !read_str ) {
/* remvoe this blank from token */
token[--length] = 0;
break;
}
/* check if this is a long string embraced by "..." */
if ( c == '"' ) {
if ( length > 1 ) {
if ( read_str )
/* termination of string; stop reading */
break;
else {
/* token read and this " belongs to next token */
/* in this case restore last char */
fseek( file, -1, SEEK_CUR );
token[--length] = 0;
break;
}
}
else
read_str = 1;
}
}
if ( read_str ) {
/* delete brackets from token */
for ( i = 1; i < strlen( token ); i++ )
token[i - 1] = token[i];
token[strlen( token ) - 2] = 0;
}
if ( feof( file ) ) return 0;
return 1;
}
/* find a string in the file and set file stream to this position */
int find_token( FILE *file, char *name, int type, int warning )
{
char token[MAX_TOKEN_LENGTH];
if ( type == RESET_FILE_POS )
fseek( file, 0, SEEK_SET );
while( read_token( file, token ) )
if ( strequal( name, token ) ) {
/* adjust position this token must be read */
fseek( file, -strlen( token ) -1, SEEK_CUR );
return 1;
}
if ( warning == WARNING )
fprintf( stderr, "find_token: warning: token '%s' not found\n", name );
return 0;
}
/* read argument string of a single assignment */
char* get_arg( FILE *file, char *name, int type )
{
char token[MAX_TOKEN_LENGTH];
char *arg = 0;
/* search entry_name */
if ( !find_token( file, name, type, WARNING ) ) return 0;
/* token was found so read it */
read_token( file, token );
/* next token must be an equation */
read_token( file, token );
if ( token[0] != '=' ) {
fprintf( stderr,
"get_arg: line %i: '=' expected after token '%s' but found '%s' instead\n", get_line_number( file ), name, token );
return 0;
}
/* get argument */
read_token( file, token );
if ( token[0] == 0 )
fprintf( stderr, "get_arg: line %i: warning: argument for '%s' is empty\n", get_line_number( file ), name );
arg = strdup( token );
#ifdef FILE_DEBUG
printf( "get_arg: %s = %s\n", name, arg );
#endif
return arg;
}
/* read a cluster of arguments and return as static list */
char** get_arg_cluster( FILE *file, char *name, int *count, int type, int warning )
{
List *args;
char token[MAX_TOKEN_LENGTH];
char **arg_list = 0;
int i;
*count = 0;
/* search entry_name */
if ( !find_token( file, name, type, warning ) ) return 0;
/* init list */
args = list_create( LIST_AUTO_DELETE, LIST_NO_CALLBACK );
/* read entry_name */
read_token( file, token );
/* next token must be an '(' */
read_token( file, token );
if ( token[0] != '(' ) {
fprintf( stderr, "get_arg_cluster: line %i: '(' expected after token '%s' but found '%s' instead\n", get_line_number( file ), name, token );
return 0;
}
/* read tokens and add to dynamic list until ')' occurs; if an '=' or '(' is read instead something
gone wrong */
while ( 1 ) {
read_token( file, token );
if ( token[0] == ')' ) break;
if ( token[0] == '(' || token[0] == '=' ) {
fprintf( stderr, "get_arg_cluster: line %i: ')' expected to terminate argument list of entry '%s' but found '%c' instead\n", get_line_number( file ), name, token[0] );
list_clear( args );
return 0;
}
/* everything's ok; add to list */
list_add( args, strdup( token ) );
}
/* static argument list */
arg_list = calloc( args->count, sizeof( char* ) );
for ( i = 0; i < args->count; i++ )
arg_list[i] = strdup( (char*)list_get( args, i ) );
*count = args->count;
list_delete( args );
return arg_list;
}
/* free arg cluster */
void delete_arg_cluster( char **cluster, int count )
{
int i;
if ( cluster ) {
for ( i = 0; i < count; i++ )
if ( cluster[i] )
FREE( cluster[i] );
FREE( cluster );
}
}
/* count number of entries */
int count_arg( FILE *file, char *name )
{
char token[MAX_TOKEN_LENGTH];
int count = 0;
fseek( file, 0, SEEK_SET );
while ( read_token( file, token ) ) {
if ( strequal( name, token ) )
count++;
}
return count;
}
/*
====================================================================
Swap these two pointers.
====================================================================
*/
void swap( char **str1, char **str2 )
{
char *dummy;
dummy = *str1;
*str1 = *str2;
*str2 = dummy;
}
/*
====================================================================
Return a list with all accessible files and directories in path
with the extension ext (if != 0). Don't show hidden files.
Root is the name of the parent directory that can't be left. If this
is next directory up '..' is not added.
====================================================================
*/
Text* get_file_list( char *path, char *ext, char *root )
{
Text *text = 0;
int i, j;
DIR *dir;
DIR *test_dir;
struct dirent *dirent = 0;
List *list = 0;
struct stat fstat;
char file_name[512];
FILE *file;
int len;
/* open this directory */
if ( ( dir = opendir( path ) ) == 0 ) {
fprintf( stderr, "get_file_list: can't open parent directory '%s'\n", path );
return 0;
}
text = calloc( 1, sizeof( Text ) );
/* use dynamic list to gather all valid entries */
list = list_create( LIST_AUTO_DELETE, LIST_NO_CALLBACK );
/* read each entry and check if its a valid entry, then add it to the dynamic list */
while ( ( dirent = readdir( dir ) ) != 0 ) {
/* hiden stuff is not displayed */
if ( dirent->d_name[0] == '.' && dirent->d_name[1] != '.' ) continue;
/* check if it's the root directory */
if ( root )
if ( dirent->d_name[0] == '.' )
if ( strlen( path ) > strlen( root ) )
if ( !strncmp( path + strlen( path ) - strlen( root ), root, strlen( root ) ) )
continue;
/* get stats */
sprintf( file_name, "%s/%s", path, dirent->d_name );
if ( stat( file_name, &fstat ) == -1 ) continue;
/* check directory */
if ( S_ISDIR( fstat.st_mode ) ) {
if ( ( test_dir = opendir( file_name ) ) == 0 ) continue;
closedir( test_dir );
sprintf( file_name, "*%s", dirent->d_name );
list_add( list, strdup( file_name ) );
}
else
/* check regular file */
if ( S_ISREG( fstat.st_mode ) ) {
/* test it */
if ( ( file = fopen( file_name, "r" ) ) == 0 ) continue;
fclose( file );
/* check if this file has the proper extension */
if ( ext )
if ( !strequal( dirent->d_name + ( strlen( dirent->d_name ) - strlen( ext ) ), ext ) )
continue;
list_add( list, strdup( dirent->d_name ) );
}
}
/* close dir */
closedir( dir );
/* convert to static list */
text->count = list->count;
text->lines = calloc( list->count, sizeof( char* ));
for ( i = 0; i < text->count; i++ )
text->lines[i] = strdup( (char*)list_get( list, i ) );
list_delete( list );
/* sort this list: directories at top and everything in alphabetical order */
if ( text->count > 0 )
for ( i = 0; i < text->count - 1; i++ )
for ( j = i + 1; j < text->count; j++ ) {
/* directory comes first */
if ( text->lines[j][0] == '*' ) {
if ( text->lines[i][0] != '*' )
swap( &text->lines[i], &text->lines[j] );
else {
/* do not exceed buffer size of smaller buffer */
len = strlen( text->lines[i] );
if ( strlen( text->lines[j] ) < len ) len = strlen( text->lines[j] );
if ( strncmp( text->lines[j], text->lines[i], len ) < 0 )
swap( &text->lines[i], &text->lines[j] );
}
}
else {
/* do not exceed buffer size of smaller buffer */
len = strlen( text->lines[i] );
if ( strlen( text->lines[j] ) < len ) len = strlen( text->lines[j] );
if ( strncmp( text->lines[j], text->lines[i], len ) < 0 )
swap( &text->lines[i], &text->lines[j] );
}
}
return text;
}