Commit c4a6b418 authored by Dick Hollenbeck's avatar Dick Hollenbeck

++new:

    Completed a good portion of /new class DIR_LIB_SOURCE.
    Added an autonomous CMakeLists.txt file to /new, with new-docs target and
    test program target.
parents 78ef3152 80f21358
......@@ -4,6 +4,13 @@ KiCad ChangeLog 2010
Please add newer entries at the top, list the date and your name with
email address.
2010-Dec-19 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================
++new:
Completed a good portion of /new class DIR_LIB_SOURCE.
Added an autonomous CMakeLists.txt file to /new, with new-docs target and
test program target.
2010-dec-15, UPDATE Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>
================================================================================
Gerbview:
......
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2010 SoftPLC Corporation, <dick@softplc.com>
* Copyright (C) 2010 Kicad Developers, see change_log.txt for contributors.
*
* 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, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef KICAD_EXCEPTIONS_H_
#define KICAD_EXCEPTIONS_H_
/* Just exceptions
*/
#include <wx/string.h>
/**
* Struct IO_ERROR
* is a class used to hold an error message and may be used to throw exceptions
* containing meaningful error messages.
* @author Dick Hollenbeck
*/
struct IO_ERROR
{
wxString errorText;
IO_ERROR( const wxChar* aMsg ) :
errorText( aMsg )
{
}
IO_ERROR( const wxString& aMsg ) :
errorText( aMsg )
{
}
IO_ERROR( const char* aMsg ) :
errorText( wxConvertMB2WX( aMsg ) )
{
}
};
/**
* Class PARSE_ERROR
* contains a filename or source description, a line number, a character offset,
* and an error message.
* @author Dick Hollenbeck
*/
struct PARSE_ERROR : public IO_ERROR
{
wxString source; ///< filename typically, unless from RAM
int lineNumber;
int byteIndex; ///< char offset, starting from 1, into the problem line.
PARSE_ERROR( const wxString& aMsg, const wxString& aSource,
int aLineNumber, int aByteIndex ) :
IO_ERROR( aMsg ),
source( aSource ),
lineNumber( aLineNumber )
{
}
};
#endif // KICAD_EXCEPTIONS_H_
......@@ -6,9 +6,10 @@
*/
#ifndef __INCLUDE__KICAD_STRING_H__
#define __INCLUDE__KICAD_STRING_H__ 1
#ifndef KICAD_STRING_H_
#define KICAD_STRING_H_
#include <wx/string.h>
char* strupper( char* Text );
char* strlower( char* Text );
......@@ -102,4 +103,4 @@ int SplitString( wxString strToSplit,
wxString* strDigits,
wxString* strEnd );
#endif // __INCLUDE__KICAD_STRING_H__
#endif // KICAD_STRING_H_
......@@ -37,30 +37,10 @@
// I really did not want to be dependent on wxWidgets in richio
// but the errorText needs to be wide char so wxString rules.
#include <wx/wx.h>
#include <cstdio> // FILE
#include <cstdio>
#include <kicad_exceptions.h>
/**
* Struct IO_ERROR
* is a class used to hold an error message and may be used to throw exceptions
* containing meaningful error messages.
*/
struct IO_ERROR
{
wxString errorText;
IO_ERROR( const wxChar* aMsg ) :
errorText( aMsg )
{
}
IO_ERROR( const wxString& aMsg ) :
errorText( aMsg )
{
}
};
#define LINE_READER_LINE_DEFAULT_MAX 100000
#define LINE_READER_LINE_INITIAL_SIZE 5000
......@@ -234,18 +214,19 @@ public:
/**
* Class OUTPUTFORMATTER
* is an important interface (abstract) class used to output UTF8 text in a convenient
* way. The primary interface is "printf() - like" but with support for indentation
* control. The destination of the 8 bit wide text is up to the implementer.
* is an important interface (abstract) class used to output UTF8 text in
* a convenient way. The primary interface is "printf() - like" but
* with support for indentation control. The destination of the 8 bit
* wide text is up to the implementer.
* <p>
* The implementer only has to implement the write() function, but can also optionaly
* re-implement GetQuoteChar().
* The implementer only has to implement the write() function, but can
* also optionally re-implement GetQuoteChar().
* <p>
* If you want to output a wxString, then use CONV_TO_UTF8() on it before passing
* it as an argument to Print().
* If you want to output a wxString, then use CONV_TO_UTF8() on it
* before passing it as an argument to Print().
* <p>
* Since this is an abstract interface, only classes derived from this one
* may actually be used.
* Since this is an abstract interface, only classes derived from
* this one may actually be used.
*/
class OUTPUTFORMATTER
{
......@@ -307,7 +288,7 @@ public:
* Function Print
* formats and writes text to the output stream.
*
* @param nestLevel The multiple of spaces to preceed the output with.
* @param nestLevel The multiple of spaces to precede the output with.
* @param fmt A printf() style format string.
* @param ... a variable list of parameters that will get blended into
* the output under control of the format string.
......
set( STAND_ALONE true )
if( STAND_ALONE )
project(kicad-new)
cmake_minimum_required(VERSION 2.6.4 FATAL_ERROR)
set( PROJECT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../ )
# Path to local CMake modules.
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeModules)
include(CheckFindPackageResult)
find_package(Doxygen)
# On Apple only wxwidgets 2.9 or higher doesn't need to find aui part of base
if(APPLE)
find_package(wxWidgets COMPONENTS gl adv html core net base xml QUIET)
else()
find_package(wxWidgets COMPONENTS gl aui adv html core net base xml QUIET)
endif()
check_find_package_result( wxWidgets_FOUND "wxWidgets" )
# Include wxWidgets macros.
include( ${wxWidgets_USE_FILE} )
include_directories( ${PROJECT_SOURCE_DIR}/include )
if(CMAKE_COMPILER_IS_GNUCXX)
# Set default flags for Release build.
set(CMAKE_C_FLAGS_RELEASE "-Wall -O2 -DNDEBUG ")
set(CMAKE_CXX_FLAGS_RELEASE "-Wall -O2 -DNDEBUG")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-s -static-libgcc")
# Set default flags for Debug build.
set(CMAKE_C_FLAGS_DEBUG "-Wall -g3 -ggdb3 -DDEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g3 -ggdb3 -DDEBUG")
endif(CMAKE_COMPILER_IS_GNUCXX)
endif()
#================================================
# Doxygen Output
#================================================
if(DOXYGEN_FOUND)
add_custom_target( new-docs ${DOXYGEN_EXECUTABLE}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS Doxyfile )
else(DOXYGEN_FOUND)
message( STATUS "WARNING: Doxygen not found - new-docs (Source Docs) target not created" )
endif()
include_directories( ${CMAKE_SOURCE_DIR} )
add_executable( test_dir_lib_source sch_dir_lib_source.cpp )
#add_executable( test_dir_lib_source EXCLUDE_FROM_ALL sch_dir_lib_source.cpp )
target_link_libraries( test_dir_lib_source ${wxWidgets_LIBRARIES} )
This diff is collapsed.
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2010 SoftPLC Corporation, <dick@softplc.com>
* Copyright (C) 2010 Kicad Developers, see change_log.txt for contributors.
*
* 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, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* Note: this LIB_SOURCE implementation relies on the posix specified opendir() and
related functions rather than wx functions which might do the same thing. This
is because I did not want to become very dependent on wxWidgets at such a low
level as this, in case someday this code needs to be used on kde or whatever.
Mingw and unix, linux, & osx will all have these posix functions.
MS Visual Studio may need the posix compatible opendir() functions brought in
http://www.softagalleria.net/dirent.php
wx has these but they are based on wxString which can be wchar_t based and wx should
not be introduced at a level this low.
*/
#include <sch_dir_lib_source.h>
using namespace SCH;
#include <kicad_exceptions.h>
#include <dirent.h>
#include <sys/stat.h>
#include <cstring>
#include <cstdio>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <vector>
using namespace std;
/**
* Class DIR_WRAP
* provides a destructor which may be invoked if an exception is thrown.
*/
class DIR_WRAP
{
DIR* dir;
public:
DIR_WRAP( DIR* aDir ) : dir( aDir ) {}
~DIR_WRAP()
{
if( dir )
closedir( dir );
}
DIR* operator->() { return dir; }
DIR* operator*() { return dir; }
};
/**
* Class FILE_WRAP
* provides a destructor which may be invoked if an exception is thrown.
*/
class FILE_WRAP
{
int fh;
public:
FILE_WRAP( int aFileHandle ) : fh( aFileHandle ) {}
~FILE_WRAP()
{
if( fh != -1 )
close( fh );
}
operator int () { return fh; }
};
/**
* Function strrstr
* finds the last instance of needle in haystack, if any.
*/
static const char* strrstr( const char* haystack, const char* needle )
{
const char* ret = 0;
const char* next = haystack;
// find last instance of haystack
while( (next = strstr( next, needle )) != 0 )
{
ret = next;
++next; // don't keep finding the same one.
}
return ret;
}
static const char* endsWithRev( const char* cp, const char* limit )
{
// find last instance of ".rev"
cp = strrstr( cp, ".rev" );
if( cp )
{
const char* rev = cp + 1;
cp += sizeof( ".rev" )-1;
while( isdigit( *cp ) )
++cp;
if( cp != limit ) // there is garbage after "revN.."
rev = 0;
return rev;
}
return 0;
}
bool DIR_LIB_SOURCE::makePartFileName( const char* aEntry,
const STRING& aCategory, STRING* aPartName )
{
const char* cp = strrstr( aEntry, ".part" );
// if base name is not empty, contains ".part", && cp is not NULL
if( cp > aEntry )
{
const char* limit = cp + strlen( cp );
// if file extension is exactly ".part", and no rev
if( cp==limit-5 )
{
if( aCategory.size() )
*aPartName = aCategory + "/";
else
aPartName->clear();
aPartName->append( aEntry, cp - aEntry );
return true;
}
// if versioning, test for a trailing "revN.." type of string
if( useVersioning )
{
const char* rev = endsWithRev( cp + sizeof(".part") - 1, limit );
if( rev )
{
if( aCategory.size() )
*aPartName = aCategory + "/";
else
aPartName->clear();
aPartName->append( aEntry, cp - aEntry );
aPartName->append( "/" );
aPartName->append( rev );
return true;
}
}
}
return false;
}
static bool isCategoryName( const char* aName )
{
return true;
}
#define MAX_PART_FILE_SIZE (1*1024*1024) // sanity check
DIR_LIB_SOURCE::DIR_LIB_SOURCE( const STRING& aDirectoryPath, bool doUseVersioning )
throw( IO_ERROR )
{
useVersioning = doUseVersioning;
sourceURI = aDirectoryPath;
sourceType = "dir";
if( sourceURI.size() == 0 )
{
throw( IO_ERROR( "aDirectoryPath cannot be empty" ) );
}
// remove any trailing separator, so we can add it back later without ambiguity
if( strchr( "/\\", sourceURI[sourceURI.size()-1] ) )
sourceURI.erase( sourceURI.size()-1 );
doOneDir( "" );
}
DIR_LIB_SOURCE::~DIR_LIB_SOURCE()
{
// delete the sweet STRINGS, which "sweets" owns by pointer.
for( DIR_CACHE::iterator it = sweets.begin(); it != sweets.end(); ++it )
{
delete it->second;
}
}
void DIR_LIB_SOURCE::Show()
{
printf( "categories:\n" );
for( STRINGS::const_iterator it = categories.begin(); it!=categories.end(); ++it )
printf( " '%s'\n", it->c_str() );
printf( "\n" );
printf( "parts:\n" );
for( DIR_CACHE::const_iterator it = sweets.begin(); it != sweets.end(); ++it )
{
printf( " '%s'\n", it->first.c_str() );
}
}
void DIR_LIB_SOURCE::doOneDir( const STRING& aCategory ) throw( IO_ERROR )
{
STRING curDir = sourceURI;
if( aCategory.size() )
curDir += "/" + aCategory;
DIR_WRAP dir = opendir( curDir.c_str() );
if( !*dir )
{
STRING msg = strerror( errno );
msg += "; scanning directory " + curDir;
throw( IO_ERROR( msg.c_str() ) );
}
struct stat fs;
STRING partName;
STRING fileName;
dirent* entry;
while( (entry = readdir( *dir )) != NULL )
{
if( !strcmp( ".", entry->d_name ) || !strcmp( "..", entry->d_name ) )
continue;
fileName = curDir + "/" + entry->d_name;
//D( printf("name: '%s'\n", fileName.c_str() );)
if( !stat( fileName.c_str(), &fs ) )
{
if( S_ISREG( fs.st_mode ) && makePartFileName( entry->d_name, aCategory, &partName ) )
{
/*
if( sweets.find( partName ) != sweets.end() )
{
STRING msg = partName;
msg += " has already been encountered";
throw IO_ERROR( msg.c_str() );
}
*/
sweets[partName] = NULL; // NULL for now, load the sweet later.
//D( printf("part: %s\n", partName.c_str() );)
}
else if( S_ISDIR( fs.st_mode ) && !aCategory.size() && isCategoryName( entry->d_name ) )
{
// only one level of recursion is used, controlled by the
// emptiness of aCategory.
//D( printf("category: %s\n", entry->d_name );)
categories.push_back( entry->d_name );
doOneDir( entry->d_name );
}
else
{
//D( printf( "ignoring %s\n", entry->d_name );)
}
}
}
}
#if 1 || defined( TEST_DIR_LIB_SOURCE )
int main( int argc, char** argv )
{
try
{
DIR_LIB_SOURCE uut( argv[1] ? argv[1] : "", true );
uut.Show();
}
catch( IO_ERROR ioe )
{
printf( "exception: %s\n", (const char*) wxConvertWX2MB( ioe.errorText ) );
}
return 0;
}
#endif
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2010 Kicad Developers, see change_log.txt for contributors.
*
* 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, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef DIR_LIB_SOURCE_H_
#define DIR_LIB_SOURCE_H_
#include <sch_lib.h>
#include <map>
/**
* Type DIR_CACHE
* is a tuple, where the key is partname (prefixed with the category if any),
* and value is pointer to Sweet string which is loaded lazily, so can be NULL
* until loaded.
*/
typedef std::map< STRING, STRING* > DIR_CACHE;
namespace SCH {
/**
* Class DIR_LIB_SOURCE
* implements a LIB_SOURCE in a file system directory.
*
* @author Dick Hollenbeck
*/
class DIR_LIB_SOURCE : public LIB_SOURCE
{
friend class LIBS; ///< LIBS::GetLib() can construct one.
bool useVersioning; ///< use files with extension ".revNNN..", else not
DIR_CACHE sweets;
STRINGS categories;
/**
* Function isPartFileName
* returns true iff aName is a valid part file name.
*/
bool isPartFileName( const char* aName );
/**
* Function makePartFileName
* returns true iff aEntry holds a valid part filename, in the form of
* "someroot.part[.revNNNN]" where NNN are number characters [0-9]
* @param aEntry is the raw directory entry without path information.
* @param aCategory is the last portion of the directory path.
* @param aPartName is where to put a part name, assuming aEntry is legal.
* @return bool - true only if aEntry is a legal part file name.
*/
bool makePartFileName( const char* aEntry,
const STRING& aCategory, STRING* aPartName );
/**
* Function doOneDir
* loads part names [and categories] from a directory given by
* "sourceURI + '/' + category"
* Categories are only loaded if processing the top most directory because
* only one level of categories are supported. We know we are in the
* top most directory if aCategory is empty.
*/
void doOneDir( const STRING& aCategory ) throw( IO_ERROR );
//protected:
public:
/**
* Constructor DIR_LIB_SOURCE( const STRING& aDirectoryPath )
* sets up a LIB_SOURCE using aDirectoryPath in a file system.
* @see LIBS::GetLibrary().
*
* @param aDirectoryPath is a full file pathname of a directory which contains
* the library source of part files. Examples might be "C:\kicad_data\mylib" or
* "/home/designer/mylibdir". This is not a URI, but an OS specific path that
* can be given to opendir().
*
* @param doUseVersioning if true means support versioning in the directory tree, otherwise
* only a single version of each part is recognized.
*/
DIR_LIB_SOURCE( const STRING& aDirectoryPath, bool doUseVersioning = false )
throw( IO_ERROR );
~DIR_LIB_SOURCE();
//-----<LIB_SOURCE implementation functions >------------------------------
void ReadPart( STRING* aResult, const STRING& aPartName, const STRING& aRev=StrEmpty )
throw( IO_ERROR )
{
}
void ReadParts( STRING_TOKS* aResults, const STRINGS& aPartNames )
throw( IO_ERROR )
{
}
void GetCategories( STRING_TOKS* aResults ) throw( IO_ERROR )
{
}
void GetCategoricalPartNames( STRING_TOKS* aResults,
const STRING& aCategory=StrEmpty ) throw( IO_ERROR )
{
}
void GetRevisions( STRING_TOKS* aResults, const STRING& aPartName ) throw( IO_ERROR )
{
}
void FindParts( STRING_TOKS* aResults, const STRING& aQuery ) throw( IO_ERROR )
{
}
//-----</LIB_SOURCE implementation functions >------------------------------
/**
* Function Show
* will output a debug dump of contents.
*/
void Show();
};
} // namespace SCH
#endif // DIR_LIB_SOURCE_H_
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment