initial version of sdkparse, not generating db output yet, just diagnostic info. Successfully parsing most of what we need.

TODO: handle bitfields in structs, preprocessor commands, output csv & xml formats.

svn path=/trunk/; revision=6530
This commit is contained in:
Royce Mitchell III 2003-11-05 20:24:23 +00:00
parent 3911ce2391
commit cb64e58964
23 changed files with 1722 additions and 0 deletions

View file

@ -0,0 +1,15 @@
//
// EnumDirs.h
//
#ifndef __ENUMDIRS_H
#define __ENUMDIRS_H
//#include "win.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
typedef BOOL (*MYENUMDIRSPROC) ( PWIN32_FIND_DATA, long );
BOOL EnumDirs ( const TCHAR* szDirectory, const TCHAR* szFileSpec, MYENUMDIRSPROC pProc, long lParam );
#endif//__ENUMDIRS_H

View file

@ -0,0 +1,42 @@
//
// EnumDirs.cpp
//
#include "EnumDirs.h"
#include <stdio.h>
#if defined(UNDER_CE) && !defined(assert)
#define assert(x)
#endif
BOOL EnumDirs ( const TCHAR* szDirectory_, const TCHAR* szFileSpec, MYENUMDIRSPROC pProc, long lParam )
{
assert ( szDirectory_ && szFileSpec && pProc );
TCHAR szDirectory[MAX_PATH+1];
TCHAR szSearchPath[MAX_PATH+1];
TCHAR szTemp[MAX_PATH+1];
_tcscpy ( szDirectory, szDirectory_ );
if ( szDirectory[_tcslen(szDirectory)-1] != '\\' )
_tcscat ( szDirectory, _T("\\") );
_sntprintf ( szSearchPath, _MAX_PATH, _T("%s%s"), szDirectory, szFileSpec );
WIN32_FIND_DATA wfd;
HANDLE hfind = FindFirstFile ( szSearchPath, &wfd );
if ( hfind == INVALID_HANDLE_VALUE )
return TRUE;
do
{
if ( !_tcscmp ( wfd.cFileName, _T(".") ) || !_tcscmp ( wfd.cFileName, _T("..") ) )
continue;
_sntprintf ( szTemp, _MAX_PATH, _T("%s%s"), szDirectory, wfd.cFileName );
if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
{
if ( !pProc ( &wfd, lParam ) )
{
FindClose ( hfind );
return FALSE;
}
}
} while ( FindNextFile ( hfind, &wfd ) );
FindClose ( hfind );
return TRUE;
}

View file

@ -0,0 +1,11 @@
//
// EnumFiles.h
//
#ifndef ENUMFILES_H
#define ENUMFILES_H
typedef BOOL (*MYENUMFILESPROC) ( PWIN32_FIND_DATA, const TCHAR*, long );
BOOL EnumFilesInDirectory ( const TCHAR* szDirectory, const TCHAR* szFileSpec, MYENUMFILESPROC pProc, long lParam, BOOL bSubsToo, BOOL bSubsMustMatchFileSpec = FALSE );
#endif//ENUMFILES_H

View file

@ -0,0 +1,92 @@
//
// EnumFilesImpl.h
//
#include "EnumFiles.h"
#include "FixLFN.h"
#include "safestr.h"
#ifndef UNDER_CE
#include <direct.h>
#endif//UNDER_CE
#include <stdio.h>
BOOL EnumFilesInDirectory ( const TCHAR* szDirectory_, const TCHAR* szFileSpec, MYENUMFILESPROC pProc, long lParam, BOOL bSubsToo, BOOL bSubsMustMatchFileSpec )
{
TCHAR szDirectory[MAX_PATH+1];
TCHAR szSearchPath[MAX_PATH+1];
TCHAR szTemp[MAX_PATH+1];
if ( safestrlen(szDirectory_) > MAX_PATH || !szFileSpec || !pProc )
return FALSE;
if ( szDirectory_ )
_tcscpy ( szDirectory, szDirectory_ );
else
#ifdef UNDER_CE
_tcscpy ( szDirectory, _T("") );
#else//UNDER_CE
getcwd ( szDirectory, sizeof(szDirectory)-1 );
#endif//UNDER_CE
int dirlen = _tcslen(szDirectory);
if ( dirlen > 0 && szDirectory[dirlen-1] != '\\' )
_tcscat ( szDirectory, _T("\\") );
// first search for all files in directory that match szFileSpec...
_sntprintf ( szSearchPath, sizeof(szSearchPath)-1, _T("%s%s"), szDirectory, szFileSpec );
WIN32_FIND_DATA wfd;
HANDLE hfind = FindFirstFile ( szSearchPath, &wfd );
if ( hfind != INVALID_HANDLE_VALUE )
{
do
{
if ( !_tcscmp ( wfd.cFileName, _T(".") ) || !_tcscmp ( wfd.cFileName, _T("..") ) )
continue;
if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
{
if ( !bSubsMustMatchFileSpec )
continue;
_sntprintf ( szTemp, sizeof(szTemp)-1, _T("%s%s"), szDirectory, wfd.cFileName );
if ( bSubsToo )
{
if ( !EnumFilesInDirectory ( szTemp, szFileSpec, pProc, lParam, bSubsToo, bSubsMustMatchFileSpec ) )
{
FindClose ( hfind );
return FALSE;
}
}
}
_sntprintf ( szTemp, sizeof(szTemp)-1, _T("%s%s"), szDirectory, wfd.cFileName );
FixLFN(szTemp,szTemp);
if ( !pProc ( &wfd, szTemp, lParam ) )
{
FindClose ( hfind );
return FALSE;
}
} while ( FindNextFile ( hfind, &wfd ) );
FindClose ( hfind );
}
if ( !bSubsToo || bSubsMustMatchFileSpec )
return TRUE;
// now search for all subdirectories...
_sntprintf ( szSearchPath, sizeof(szSearchPath)-1, _T("%s*.*"), szDirectory );
hfind = FindFirstFile ( szSearchPath, &wfd );
if ( hfind != INVALID_HANDLE_VALUE )
{
do
{
if ( !_tcscmp ( wfd.cFileName, _T(".") ) || !_tcscmp ( wfd.cFileName, _T("..") ) )
continue;
if ( !(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
continue;
_sntprintf ( szTemp, sizeof(szTemp)-1, _T("%s%s"), szDirectory, wfd.cFileName );
if ( FALSE == EnumFilesInDirectory ( szTemp, szFileSpec, pProc, lParam, bSubsToo, bSubsMustMatchFileSpec ) )
{
FindClose ( hfind );
return FALSE;
}
} while ( FindNextFile ( hfind, &wfd ) );
FindClose ( hfind );
}
return TRUE;
}

View file

@ -0,0 +1,120 @@
// File.cpp
// This file is (C) 2002-2003 Royce Mitchell III and released under the BSD license
#ifdef _MSC_VER
#pragma warning ( disable : 4786 )
#endif//_MSC_VER
#include "File.h"
bool File::open ( const char* filename, const char* mode )
{
close();
_f = fopen ( filename, mode );
return _f != 0;
}
std::string File::getline ( bool strip_crlf /*= false*/ )
{
std::string s = "";
char buf[256];
for ( ;; )
{
*buf = 0;
fgets ( buf, sizeof(buf)-1, _f );
if ( !*buf )
break;
s += buf;
if ( strchr ( "\r\n", buf[strlen(buf)-1] ) )
break;
}
if ( strip_crlf )
{
char* p = strpbrk ( &s[0], "\r\n" );
if ( p )
{
*p = '\0';
s.resize ( p-&s[0] );
}
}
return s;
}
// this function searches for the next end-of-line and puts all data it
// finds until then in the 'line' parameter.
//
// call continuously until the function returns false ( no more data )
bool File::next_line ( std::string& line, bool strip_crlf )
{
line = getline(strip_crlf);
// indicate that we're done *if*:
// 1) there's no more data, *and*
// 2) we're at the end of the file
return line.size()>0 || !eof();
}
/*
example usage:
bool mycallback ( const std::string& line, int line_number, long lparam )
{
std::cout << line << std::endl;
return true; // continue enumeration
}
File f ( "file.txt", "rb" ); // open file for binary read-only ( i.e. "rb" )
f.enum_lines ( mycallback, 0, true );
*/
bool File::enum_lines ( bool (*callback)(const std::string& line, int line_number, long lparam), long lparam, bool strip_crlf )
{
int line_number = 0;
for ( ;; )
{
std::string s = getline(strip_crlf);
line_number++;
if ( !s.size() )
{
if ( eof() )
return true;
else
continue;
}
if ( !(*callback) ( s, line_number, lparam ) )
return false;
}
}
size_t File::length()
{
#ifdef WIN32
return _filelength ( _fileno(_f) );
#elif defined(UNIX)
struct stat file_stat;
verify(fstat(fileno(_f), &file_stat) == 0);
return file_stat.st_size;
#endif
}
void File::close()
{
if ( _f )
{
fclose(_f);
_f = 0;
}
}
/*static*/ bool File::LoadIntoString ( std::string& s, const char* filename )
{
File in ( filename, "rb" );
if ( !in.isopened() )
return false;
size_t len = in.length();
s.resize ( len + 1 );
if ( !in.read ( &s[0], len ) )
return false;
s[len] = '\0';
s.resize ( len );
return true;
}

View file

@ -0,0 +1,110 @@
// File.h
// This file is (C) 2002-2003 Royce Mitchell III and released under the BSD license
#ifndef FILE_H
#define FILE_H
#ifdef WIN32
# include <io.h>
#elif defined(UNIX)
# include <sys/stat.h>
# include <unistd.h>
#endif
#include <string>
class File
{
public:
File() : _f(0)
{
}
File ( const char* filename, const char* mode ) : _f(0)
{
open ( filename, mode );
}
~File()
{
close();
}
bool open ( const char* filename, const char* mode );
bool seek ( long offset )
{
return !fseek ( _f, offset, SEEK_SET );
}
int get()
{
return fgetc ( _f );
}
bool put ( int c )
{
return fputc ( c, _f ) != EOF;
}
std::string getline ( bool strip_crlf = false );
// this function searches for the next end-of-line and puts all data it
// finds until then in the 'line' parameter.
//
// call continuously until the function returns false ( no more data )
bool next_line ( std::string& line, bool strip_crlf );
/*
example usage:
bool mycallback ( const std::string& line, int line_number, long lparam )
{
std::cout << line << std::endl;
return true; // continue enumeration
}
File f ( "file.txt", "rb" ); // open file for binary read-only ( i.e. "rb" )
f.enum_lines ( mycallback, 0, true );
*/
bool enum_lines ( bool (*callback)(const std::string& line, int line_number, long lparam), long lparam, bool strip_crlf );
bool read ( void* data, unsigned len )
{
return len == fread ( data, 1, len, _f );
}
bool write ( const void* data, unsigned len )
{
return len == fwrite ( data, 1, len, _f );
}
size_t length();
void close();
bool isopened()
{
return _f != 0;
}
bool eof()
{
return feof(_f) ? true : false;
}
FILE* operator * ()
{
return _f;
}
static bool LoadIntoString ( std::string& s, const char* filename );
private:
File(const File&) {}
const File& operator = ( const File& ) { return *this; }
FILE * _f;
};
#endif//FILE_H

View file

@ -0,0 +1,32 @@
//
// FixLFN.h
//
#ifndef __FIXLFN_H
#define __FIXLFN_H
#include <string.h>
#include <tchar.h>
#include <shellapi.h>
inline int FixLFN ( const TCHAR* pBadFileName, TCHAR* pGoodFileName )
{
SHFILEINFO sfi;
TCHAR* p;
DWORD dwResult = SHGetFileInfo ( pBadFileName, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME );
if ( dwResult )
{
if ( pGoodFileName != pBadFileName )
_tcscpy ( pGoodFileName, pBadFileName );
if ( (p = _tcsrchr ( pGoodFileName, '\\' )) )
_tcscpy ( p+1, sfi.szDisplayName );
else if ( (p = _tcsrchr ( pGoodFileName, '/' )) )
_tcscpy ( p+1, sfi.szDisplayName );
else
_tcscpy ( pGoodFileName, sfi.szDisplayName );
}
return dwResult;
}
#endif//__FIXLFN_H

View file

@ -0,0 +1,47 @@
//
// assert.h
//
#ifndef __ASSERT_H
#define __ASSERT_H
#ifndef _MFC_VER
#ifdef _WIN32_WCE
#else//_WIN32_WCE
#include <assert.h>
#endif//_WIN32_WCE
#endif
#ifndef ASSERT
#ifdef _DEBUG
#include <crtdbg.h>
#include <stdio.h> // _snprintf
//#ifndef WINVER
#ifdef _CONSOLE
#define ASSERT(x) if(!(x)){printf("ASSERT FAILURE: (%s) at %s:%i\n", #x, __FILE__, __LINE__); _CrtDbgBreak(); }
#else//_CONSOLE/WINVER
#define ASSERT(x) if(!(x)){char stmp_assert[1024+1]; _snprintf(stmp_assert,1024,"ASSERT FAILURE: (%s) at %s:%i\n",#x,__FILE__,__LINE__); ::MessageBox(NULL,stmp_assert,"Assertion Failure",MB_OK|MB_ICONSTOP); _CrtDbgBreak(); }
#endif//_CONSOLE/WINVER
#else//_DEBUG
#define ASSERT(x)
#endif//_DEBUG
#endif//ASSERT
#undef VERIFY
#ifdef _DEBUG
#define VERIFY(x) ASSERT(x)
#else//_DEBUG
#define VERIFY(x) x
#endif//_DEBUG
// code for ASSERTing in Release mode...
#ifdef RELEASE_ASSERT
#undef ASSERT
#include <stdio.h>
#define ASSERT(x) if ( !(x) ) { char s[1024+1]; _snprintf(s,1024,"ASSERTION FAILURE:\n%s\n\n%s: line %i", #x, __FILE__, __LINE__ ); ::MessageBox(NULL,s,"Assertion Failure",MB_OK|MB_ICONERROR); }
#undef VERIFY
#define VERIFY ASSERT
#endif//RELEASE_ASSERT
#endif//__ASSERT_H

View file

@ -0,0 +1,49 @@
// binary2cstr.cpp
#ifdef _MSC_VER
#pragma warning ( disable : 4786 )
#endif//_MSC_VER
#include "binary2cstr.h"
using std::string;
string binary2cstr ( const string& src )
{
string dst;
for ( int i = 0; i < src.size(); i++ )
{
char c = src[i];
switch ( c )
{
case '\n':
dst += "\\n";
break;
case '\r':
dst += "\\r";
break;
case '\t':
dst += "\\t";
break;
case '\v':
dst += "\\v";
break;
case '\"':
dst += "\x22";
break;
default:
if ( isprint ( c ) )
dst += c;
else
{
dst += "\\x";
char tmp[16];
_snprintf ( tmp, sizeof(tmp)-1, "%02X", (unsigned)(unsigned char)c );
tmp[sizeof(tmp)-1] = '\0';
dst += tmp;
}
break;
}
}
return dst;
}

View file

@ -0,0 +1,10 @@
// binary2cstr.h
#ifndef BINARY2CSTR_H
#define BINARY2CSTR_H
#include <string>
std::string binary2cstr ( const std::string& src );
#endif//BINARY2CSTR_H

View file

@ -0,0 +1,58 @@
// iskeyword.cpp
#ifdef _MSC_VER
#pragma warning ( disable : 4786 )
#endif//_MSC_VER
#include <string>
#include "iskeyword.h"
using std::string;
bool iskeyword ( const string& ident )
{
#define I(s) if ( ident == #s ) return true;
switch ( ident[0] )
{
case 'b':
I(bool);
break;
case 'c':
I(char);
I(const);
break;
case 'd':
I(do);
I(double);
break;
case 'f':
I(false);
I(float);
I(for);
break;
case 'i':
I(if);
I(int);
break;
case 'l':
I(long);
break;
case 'r':
I(return);
break;
case 's':
I(short);
I(struct);
I(switch);
break;
case 't':
I(true);
I(typedef);
break;
case 'w':
I(while);
break;
}
return false;
}

View file

@ -0,0 +1,8 @@
// iskeyword.h
#ifndef ISKEYWORD_H
#define ISKEYWORD_H
bool iskeyword ( const std::string& ident );
#endif//ISKEYWORD_H

View file

@ -0,0 +1,61 @@
//
// safestr.h
//
// safe versions of some string manipulation routines
//
#ifndef __SAFESTR_H
#define __SAFESTR_H
#include <tchar.h>
#ifndef tchar
#define tchar TCHAR
#endif//tchar
#include <string.h>
#include "assert.h"
inline size_t safestrlen ( const tchar *string )
{
if ( !string )
return 0;
return _tcslen(string);
}
inline tchar* safestrcpy ( tchar* strDest, const tchar* strSource )
{
ASSERT(strDest);
if ( !strSource )
*strDest = 0;
else
_tcscpy ( strDest, strSource );
return strDest;
}
inline tchar* safestrncpy ( tchar* strDest, const tchar* strSource, size_t count )
{
ASSERT(strDest);
if ( !strSource )
count = 0;
else
_tcsncpy ( strDest, strSource, count );
strDest[count] = 0;
return strDest;
}
inline tchar* safestrlwr ( tchar* str )
{
if ( !str )
return 0;
return _tcslwr(str);
}
inline tchar* safestrupr ( tchar* str )
{
if ( !str )
return 0;
return _tcsupr(str);
}
#endif//__SAFESTR_H

View file

@ -0,0 +1,374 @@
// sdkparse.cpp
#ifdef _MSC_VER
#pragma warning ( disable : 4786 )
#endif//_MSC_VER
#include <string>
#include <vector>
#include <conio.h>
#include "assert.h"
#include "File.h"
#include "binary2cstr.h"
#include "strip_comments.h"
#include "tokenize.h"
#include "skip_ws.h"
#include "iskeyword.h"
using std::string;
using std::vector;
typedef enum
{
T_UNKNOWN = -1,
T_MACRO,
T_DEFINE,
T_VARIABLE,
T_FUNCTION,
T_FUNCTION_PTR,
T_STRUCT
} Type;
bool import_file ( const char* filename );
char* findend ( char* p );
Type identify ( const vector<string>& tokens, int off = 0 );
Type process ( const string& element, vector<string>& names, bool& isTypedef, vector<string>& dependencies );
int parse_type ( Type t, const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies );
int parse_variable ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies );
int parse_struct ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies );
int parse_function ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies );
int parse_function_ptr ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies );
#ifndef ASSERT
#define ASSERT(x) \
do \
{ \
if ( !(x) ) \
{ \
printf("%s:%i - ASSERTION FAILURE: \"%s\"\n", __FILE__, __LINE__, #x); \
getch(); \
exit(0); \
} \
}while(0)
#endif//ASSERT
void main()
{
import_file ( "test.h" );
}
bool import_file ( const char* filename )
{
string s;
if ( !File::LoadIntoString ( s, filename ) )
{
printf ( "Couldn't load \"%s\" for input.\n", filename );
return false;
}
// strip comments from the file...
strip_comments ( s, true );
/*{
string no_comments ( filename );
no_comments += ".nocom.txt";
File::SaveFromString ( s, no_comments );
}*/
char* p = &s[0];
while ( p )
{
// skip whitespace
p = skip_ws ( p );
if ( !*p )
break;
// check for pre-processor command
if ( *p == '#' )
{
p = strchr ( p, '\n' );
if ( p )
p++;
}
else
{
char* end = findend ( p );
if ( !end )
end = p + strlen(p);
else if ( *end )
end++;
string element ( p, end-p );
p = end;
printf ( "\"%s\"\n\n", binary2cstr(element).c_str() );
vector<string> names, dependencies;
bool isTypedef;
Type t = process ( element, names, isTypedef, dependencies );
printf ( "names: " );
if ( names.size() )
{
printf ( "%s", names[0].c_str() );
for ( int i = 1; i < names.size(); i++ )
printf ( ", %s", names[i].c_str() );
}
else
printf ( "(none)" );
printf ( "\n\n" );
printf ( "dependencies: " );
if ( dependencies.size() )
{
printf ( "%s", dependencies[0].c_str() );
for ( int i = 1; i < dependencies.size(); i++ )
printf ( ", %s", dependencies[i].c_str() );
}
else
printf ( "(none)" );
printf ( "\n\n" );
}
}
return true;
}
char* skipsemi ( char* p )
{
if ( *p != '{' ) // }
{
ASSERT(0);
}
p++;
for ( ;; )
{
char* s = strchr ( p, '{' );
char* e = strchr ( p, '}' );
if ( !e )
e = p + strlen(p);
if ( !s || s > e )
{
// make sure we don't return pointer past null
if ( *e )
return e + 1;
else
return e;
}
p = skipsemi ( s );
}
}
char* findend ( char* p )
{
for ( ;; )
{
char* end = strchr ( p, ';' );
if ( !end )
end = p + strlen(p);
char* semi = strchr ( p, '{' );
if ( !semi || semi > end )
return end;
p = skipsemi ( semi );
}
}
Type identify ( const vector<string>& tokens, int off )
{
int parens = 0;
for ( int i = off; i < tokens.size(); i++ )
{
if ( tokens[i] == "(" )
parens++;
else if ( tokens[i] == "struct" && !parens )
return T_STRUCT;
}
if ( parens > 1 )
return T_FUNCTION_PTR;
else if ( parens == 1 )
return T_FUNCTION;
return T_VARIABLE;
}
Type process ( const string& element, vector<string>& names, bool& isTypedef, vector<string>& dependencies )
{
names.resize ( 0 );
isTypedef = false;
dependencies.resize ( 0 );
vector<string> tokens;
tokenize ( element, tokens );
// now let's do the classification...
int i = 0;
if ( tokens[i] == "typedef" )
{
isTypedef = true;
i++;
}
Type t = identify ( tokens, i );
parse_type ( t, tokens, i, names, dependencies );
return t;
}
int parse_type ( Type t, const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies )
{
switch ( t )
{
case T_VARIABLE:
return parse_variable ( tokens, off, names, dependencies );
case T_STRUCT:
return parse_struct ( tokens, off, names, dependencies );
case T_FUNCTION:
return parse_function ( tokens, off, names, dependencies );
case T_FUNCTION_PTR:
return parse_function_ptr ( tokens, off, names, dependencies );
default:
ASSERT(0);
return 0;
}
}
void name ( const string& ident, vector<string>& names )
{
if ( !__iscsymf ( ident[0] ) )
return;
if ( iskeyword ( ident ) )
return;
for ( int i = 0; i < names.size(); i++ )
{
if ( names[i] == ident )
return;
}
names.push_back ( ident );
}
void depend ( const string& ident, vector<string>& dependencies )
{
if ( !__iscsymf ( ident[0] ) )
return;
if ( iskeyword ( ident ) )
return;
for ( int i = 0; i < dependencies.size(); i++ )
{
if ( dependencies[i] == ident )
return;
}
dependencies.push_back ( ident );
}
int parse_variable ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies )
{
// FIXME - handle bitfields properly
depend ( tokens[off++], dependencies );
int done = tokens.size();
while ( off < done && tokens[off] != ";" )
name ( tokens[off++], names );
if ( off < done )
return off + 1;
else
return off;
}
int parse_struct ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies )
{
int done = tokens.size();
while ( off < done && tokens[off] != "struct" )
depend ( tokens[off++], dependencies );
ASSERT ( tokens[off] == "struct" );
if ( tokens[off] != "struct" )
return off;
off++;
if ( tokens[off] != "{" )
name ( tokens[off++], names );
ASSERT ( tokens[off] == "{" );
off++;
// skip through body of struct - noting any dependencies
int indent = 1;
while ( tokens[off] != "}" )
{
vector<string> fauxnames;
Type t = identify ( tokens, off );
off = parse_type ( t, tokens, off, fauxnames, dependencies );
}
// process any trailing dependencies/names...
while ( tokens[off] != ";" )
{
if ( tokens[off+1] == "," || tokens[off+1] == ";" )
name ( tokens[off], names );
else
depend ( tokens[off], dependencies );
off++;
}
return off;
}
int parse_param ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies )
{
while ( tokens[off+1] != "," && tokens[off+1] != ")" )
depend ( tokens[off++], dependencies );
name ( tokens[off++], names );
return off;
}
int parse_function ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies )
{
while ( tokens[off+1] != "(" )
depend ( tokens[off++], dependencies );
name ( tokens[off++], names );
ASSERT ( tokens[off] == "(" );
while ( tokens[off] != ")" )
{
off++;
vector<string> fauxnames;
off = parse_param ( tokens, off, fauxnames, dependencies );
ASSERT ( tokens[off] == "," || tokens[off] == ")" );
}
off++;
ASSERT ( tokens[off] == ";" );
return off;
}
int parse_function_ptr ( const vector<string>& tokens, int off, vector<string>& names, vector<string>& dependencies )
{
while ( tokens[off] != "(" )
depend ( tokens[off++], dependencies );
ASSERT ( tokens[off] == "(" );
off++;
while ( tokens[off+1] != ")" )
depend ( tokens[off++], dependencies );
name ( tokens[off++], names );
ASSERT ( tokens[off] == ")" );
off++;
ASSERT ( tokens[off] == "(" );
while ( tokens[off] != ")" )
{
off++;
vector<string> fauxnames;
off = parse_param ( tokens, off, fauxnames, dependencies );
ASSERT ( tokens[off] == "," || tokens[off] == ")" );
}
off++;
ASSERT ( tokens[off] == ";" );
return off;
}

View file

@ -0,0 +1,156 @@
# Microsoft Developer Studio Project File - Name="sdkparse" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=sdkparse - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "sdkparse.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "sdkparse.mak" CFG="sdkparse - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "sdkparse - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "sdkparse - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "sdkparse - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "sdkparse - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "sdkparse - Win32 Release"
# Name "sdkparse - Win32 Debug"
# Begin Source File
SOURCE=.\assert.h
# End Source File
# Begin Source File
SOURCE=.\binary2cstr.cpp
# End Source File
# Begin Source File
SOURCE=.\EnumDirs.h
# End Source File
# Begin Source File
SOURCE=.\EnumDirsImpl.h
# End Source File
# Begin Source File
SOURCE=.\EnumFiles.h
# End Source File
# Begin Source File
SOURCE=.\EnumFilesImpl.h
# End Source File
# Begin Source File
SOURCE=.\File.cpp
# End Source File
# Begin Source File
SOURCE=.\File.h
# End Source File
# Begin Source File
SOURCE=.\FixLFN.h
# End Source File
# Begin Source File
SOURCE=.\iskeyword.cpp
# End Source File
# Begin Source File
SOURCE=.\iskeyword.h
# End Source File
# Begin Source File
SOURCE=.\safestr.h
# End Source File
# Begin Source File
SOURCE=.\sdkparse.cpp
# End Source File
# Begin Source File
SOURCE=.\skip_ws.cpp
# End Source File
# Begin Source File
SOURCE=.\skip_ws.h
# End Source File
# Begin Source File
SOURCE=.\strip_comments.cpp
# End Source File
# Begin Source File
SOURCE=.\strip_comments.h
# End Source File
# Begin Source File
SOURCE=.\tokenize.cpp
# End Source File
# End Target
# End Project

View file

@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "sdkparse"=.\sdkparse.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View file

@ -0,0 +1,12 @@
// skip_ws.cpp
#include <string.h>
#include "skip_ws.h"
const char* ws = " \t\r\n\v";
char* skip_ws ( char* p )
{
return p + strspn ( p, ws );
}

View file

@ -0,0 +1,8 @@
// skip_ws.h
#ifndef SKIP_WS_H
#define SKIP_WS_H
char* skip_ws ( char* );
#endif//SKIP_WS_H

View file

@ -0,0 +1,39 @@
// strip_comments.cpp
#ifdef _MSC_VER
#pragma warning ( disable : 4786 )
#endif//_MSC_VER
#include "strip_comments.h"
void strip_comments ( std::string& s, bool strip_lf )
{
char* src = &s[0];
char* dst = src;
while ( *src )
{
if ( src[0] == '/' && src[1] == '/' )
{
src += 2;
while ( *src && *src != '\n' )
src++;
if ( *src )
src++; // skip newline
}
else if ( src[0] == '/' && src[1] == '*' )
{
src += 2;
while ( *src && ( src[0] != '*' || src[1] != '/' ) )
src++;
if ( *src )
src += 2;
}
else if ( src[0] == '\r' && strip_lf )
src++;
else
*dst++ = *src++;
}
*dst = '\0';
s.resize ( dst-&s[0] );
}

View file

@ -0,0 +1,10 @@
// strip_comments.h
#ifndef STRIP_COMMENTS_H
#define STRIP_COMMENTS_H
#include <string>
void strip_comments ( std::string& s, bool strip_lf = false );
#endif//STRIP_COMMENTS_H

View file

@ -0,0 +1,246 @@
/* $Id: test.h,v 1.1 2003/11/05 20:24:23 royce Exp $
*/
/*
* test.h
*
* This file is a combination of a couple different headers
* from ReactOS's include/ folder, and a little bit of custom
* hacking as well for the purpose of testing sdkparse.
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* This source code is offered for use in the public domain. You may
* use, modify or distribute it freely.
*
* This code is distributed in the hope that it will be useful but
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
* DISCLAMED. This includes but is not limited to warranties of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#ifndef __INTERNAL_PSAPI_H_INCLUDED__
#define __INTERNAL_PSAPI_H_INCLUDED__
typedef struct foo_
{
int lonibble : 4;
int hinibble : 4;
} foo;
/* INCLUDES */
#define NTOS_MODE_USER
#include <ntos.h>
/* OBJECTS */
typedef struct
{
LPSTR LeftVolumeName;
LPSTR RightVolumeName;
ULONG DefaultVolume;
ULONG Type;
ULONG DeviceType;
char Key[4];
LPSTR PrototypeName;
PVOID DeferredRoutine;
PVOID ExclusionRoutine;
PVOID DispatchRoutine;
PVOID DevCapsRoutine;
PVOID HwSetVolume;
ULONG IoMethod;
}SOUND_DEVICE_INIT;
/* TYPES */
typedef NTSTATUS NTAPI (*PPROC_ENUM_ROUTINE)
(
IN PSYSTEM_PROCESSES CurrentProcess,
IN OUT PVOID CallbackContext
);
typedef NTSTATUS NTAPI (*PTHREAD_ENUM_ROUTINE)
(
IN PSYSTEM_THREADS CurrentThread,
IN OUT PVOID CallbackContext
);
typedef NTSTATUS NTAPI (*PSYSMOD_ENUM_ROUTINE)
(
IN PSYSTEM_MODULE_INFORMATION_ENTRY CurrentModule,
IN OUT PVOID CallbackContext
);
typedef NTSTATUS NTAPI (*PPROCMOD_ENUM_ROUTINE)
(
IN HANDLE ProcessHandle,
IN PLDR_MODULE CurrentModule,
IN OUT PVOID CallbackContext
);
/* CONSTANTS */
#define FAILED_WITH_STATUS DEFINE_DBG_MSG("%s() failed, status 0x%08X")
/* PROTOTYPES */
/* Processes and threads */
/* enumeration */
NTSTATUS
NTAPI
PsaEnumerateProcessesAndThreads
(
IN PPROC_ENUM_ROUTINE ProcessCallback,
IN OUT PVOID ProcessCallbackContext,
IN PTHREAD_ENUM_ROUTINE ThreadCallback,
IN OUT PVOID ThreadCallbackContext
);
NTSTATUS
NTAPI
PsaEnumerateProcesses
(
IN PPROC_ENUM_ROUTINE Callback,
IN OUT PVOID CallbackContext
);
NTSTATUS
NTAPI
PsaEnumerateThreads
(
IN PTHREAD_ENUM_ROUTINE Callback,
IN OUT PVOID CallbackContext
);
/* capturing & walking */
NTSTATUS
NTAPI
PsaCaptureProcessesAndThreads
(
OUT PSYSTEM_PROCESSES * ProcessesAndThreads
);
NTSTATUS
NTAPI
PsaWalkProcessesAndThreads
(
IN PSYSTEM_PROCESSES ProcessesAndThreads,
IN PPROC_ENUM_ROUTINE ProcessCallback,
IN OUT PVOID ProcessCallbackContext,
IN PTHREAD_ENUM_ROUTINE ThreadCallback,
IN OUT PVOID ThreadCallbackContext
);
NTSTATUS
NTAPI
PsaWalkProcesses
(
IN PSYSTEM_PROCESSES ProcessesAndThreads,
IN PPROC_ENUM_ROUTINE Callback,
IN OUT PVOID CallbackContext
);
NTSTATUS
NTAPI
PsaWalkThreads
(
IN PSYSTEM_PROCESSES ProcessesAndThreads,
IN PTHREAD_ENUM_ROUTINE Callback,
IN OUT PVOID CallbackContext
);
PSYSTEM_PROCESSES
FASTCALL
PsaWalkFirstProcess
(
IN PSYSTEM_PROCESSES ProcessesAndThreads
);
PSYSTEM_PROCESSES
FASTCALL
PsaWalkNextProcess
(
IN PSYSTEM_PROCESSES CurrentProcess
);
PSYSTEM_THREADS
FASTCALL
PsaWalkFirstThread
(
IN PSYSTEM_PROCESSES CurrentProcess
);
PSYSTEM_THREADS
FASTCALL
PsaWalkNextThread
(
IN PSYSTEM_THREADS CurrentThread
);
/* System modules */
/* enumeration */
NTSTATUS
NTAPI
PsaEnumerateSystemModules
(
IN PSYSMOD_ENUM_ROUTINE Callback,
IN OUT PVOID CallbackContext
);
/* capturing & walking */
NTSTATUS
NTAPI
PsaCaptureSystemModules
(
OUT PSYSTEM_MODULE_INFORMATION * SystemModules
);
NTSTATUS
NTAPI
PsaWalkSystemModules
(
IN PSYSTEM_MODULE_INFORMATION SystemModules,
IN PSYSMOD_ENUM_ROUTINE Callback,
IN OUT PVOID CallbackContext
);
PSYSTEM_MODULE_INFORMATION_ENTRY
FASTCALL
PsaWalkFirstSystemModule
(
IN PSYSTEM_MODULE_INFORMATION SystemModules
);
PSYSTEM_MODULE_INFORMATION_ENTRY
FASTCALL
PsaWalkNextSystemModule
(
IN PSYSTEM_MODULE_INFORMATION CurrentSystemModule
);
/* Process modules */
NTSTATUS
NTAPI
PsaEnumerateProcessModules
(
IN HANDLE ProcessHandle,
IN PPROCMOD_ENUM_ROUTINE Callback,
IN OUT PVOID CallbackContext
);
/* Miscellaneous */
VOID
NTAPI
PsaFreeCapture
(
IN PVOID Capture
);
/* The user must define these functions. They are called by PSAPI to allocate
memory. This allows PSAPI to be called from any environment */
void *PsaiMalloc(SIZE_T size);
void *PsaiRealloc(void *ptr, SIZE_T size);
void PsaiFree(void *ptr);
/* MACROS */
#define DEFINE_DBG_MSG(__str__) "PSAPI: " __str__ "\n"
#endif /* __INTERNAL_PSAPI_H_INCLUDED__ */
/* EOF */

View file

@ -0,0 +1,185 @@
// tokenize.cpp
#ifdef _MSC_VER
#pragma warning ( disable : 4786 )
#endif//_MSC_VER
#include <string>
#include <vector>
#include "assert.h"
#include "tokenize.h"
#include "skip_ws.h"
using std::string;
using std::vector;
void tokenize ( const string& text, vector<string>& tokens )
{
tokens.resize ( 0 );
string s ( text );
char* p = &s[0];
while ( *p )
{
// skip whitespace
p = skip_ws ( p );
// check for literal string
if ( *p == '\"' )
{
// skip initial quote
char* end = p + 1;
for ( ;; )
{
if ( *end == '\\' )
{
end++;
switch ( *end )
{
case 'x':
case 'X':
ASSERT(0); // come back to this....
break;
case '0':
ASSERT(0);
break;
default:
p++;
break;
}
}
else if ( *end == '\"' )
{
end++;
break;
}
}
tokens.push_back ( string ( p, end-p ) );
p = end;
}
else if ( __iscsymf(*p) )
{
char* end = p + 1;
while ( __iscsym ( *end ) )
end++;
tokens.push_back ( string ( p, end-p ) );
p = end;
}
else if ( isdigit(*p) || *p == '.' )
{
char* end = p;
while ( isdigit(*end) )
end++;
bool f = false;
if ( *end == '.' )
{
end++;
while ( isdigit(*end) )
end++;
f = true;
}
if ( *end == 'f' || *end == 'F' )
end++;
else if ( !f && ( *end == 'l' || *end == 'L' ) )
end++;
tokens.push_back ( string ( p, end-p ) );
p = end;
}
else switch ( *p )
{
case '.':
tokens.push_back ( "." );
p++;
break;
case ',':
tokens.push_back ( "," );
p++;
break;
case '(':
tokens.push_back ( "(" );
p++;
break;
case ')':
tokens.push_back ( ")" );
p++;
break;
case '{':
tokens.push_back ( "{" );
p++;
break;
case '}':
tokens.push_back ( "}" );
p++;
break;
case '[':
tokens.push_back ( "[" );
p++;
break;
case ']':
tokens.push_back ( "]" );
p++;
break;
case ';':
tokens.push_back ( ";" );
p++;
break;
case '*':
switch ( p[1] )
{
case '=':
tokens.push_back ( string ( p, 2 ) );
p += 2;
break;
default:
tokens.push_back ( "*" );
p++;
break;
}
break;
case '/':
switch ( p[1] )
{
case '=':
tokens.push_back ( string ( p, 2 ) );
p += 2;
break;
default:
tokens.push_back ( "/" );
p++;
break;
}
break;
case '+':
switch ( p[1] )
{
case '+':
case '=':
tokens.push_back ( string ( p, 2 ) );
p += 2;
break;
default:
tokens.push_back ( "+" );
p++;
break;
}
break;
case '-':
switch ( p[1] )
{
case '-':
case '=':
tokens.push_back ( string ( p, 2 ) );
p += 2;
break;
default:
tokens.push_back ( "-" );
p++;
break;
}
break;
default:
printf ( "choked on '%c' in tokenize()\n", *p );
p++;
break;
}
}
}

View file

@ -0,0 +1,8 @@
// tokenize.h
#ifndef TOKENIZE_H
#define TOKENIZE_H
void tokenize ( const std::string& text, std::vector<std::string>& tokens );
#endif//TOKENIZE_H