diff --git a/src/apps/bin/makeudfimage/Debug.cpp b/src/apps/bin/makeudfimage/Debug.cpp new file mode 100644 index 0000000000..2f04a78164 --- /dev/null +++ b/src/apps/bin/makeudfimage/Debug.cpp @@ -0,0 +1,329 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// This version copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net +// Initial version copyright (c) 2002 Axel Dörfler, axeld@pinc-software.de +//---------------------------------------------------------------------- + +/*! \file Debug.cpp + + Support code for handy debugging macros. +*/ + +#include "Debug.h" + +#include +#include + +//---------------------------------------------------------------------- +// Long-winded overview of the debug output macros: +//---------------------------------------------------------------------- +/*! \def DEBUG_INIT() + \brief Increases the indentation level, prints out the enclosing function's + name, and creates a \c DebugHelper object on the stack to automatically + decrease the indentation level upon function exit. + + This macro should be called at the very beginning of any function in + which you wish to use any of the other debugging macros. + + If DEBUG is undefined, does nothing. +*/ +//---------------------------------------------------------------------- +/*! \def PRINT(x) + \brief Prints out the enclosing function's name followed by the contents + of \a x at the current indentation level. + + \param x A printf-style format string enclosed in an extra set of parenteses, + e.g. PRINT(("%d\n", 0)); + + If DEBUG is undefined, does nothing. +*/ +//---------------------------------------------------------------------- +/*! \def LPRINT(x) + \brief Identical to \c PRINT(x), except that the line number in the source + file at which the macro is invoked is also printed. + + \param x A printf-style format string enclosed in an extra set of parenteses, + e.g. PRINT(("%d\n", 0)); + + If DEBUG is undefined, does nothing. +*/ +//---------------------------------------------------------------------- +/*! \def SIMPLE_PRINT(x) + \brief Directly prints the contents of \a x with no extra formatting or + information included (just like a straight \c printf() call). + + \param x A printf-style format string enclosed in an extra set of parenteses, + e.g. PRINT(("%d\n", 0)); + + If DEBUG is undefined, does nothing. +*/ +//---------------------------------------------------------------------- +/*! \def PRINT_INDENT() + \brief Prints out enough indentation characters to indent the current line + to the current indentation level (assuming the cursor was flush left to + begin with...). + + This function is called by the other \c *PRINT* macros, and isn't really + intended for general consumption, but you might find it useful. + + If DEBUG is undefined, does nothing. +*/ +//---------------------------------------------------------------------- +/*! \def REPORT_ERROR(error) + \brief Calls \c LPRINT(x) with a format string listing the error + code in \c error (assumed to be a \c status_t value) and the + corresponding text error code returned by a call to \c strerror(). + + This function is called by the \c RETURN* macros, and isn't really + intended for general consumption, but you might find it useful. + + \param error A \c status_t error code to report. + + If DEBUG is undefined, does nothing. +*/ +//---------------------------------------------------------------------- +/*! \def RETURN_ERROR(error) + \brief Calls \c REPORT_ERROR(error) if error is a an error code (i.e. + negative), otherwise remains silent. In either case, the enclosing + function is then exited with a call to \c "return error;". + + \param error A \c status_t error code to report (if negative) and return. + + If DEBUG is undefined, silently returns the value in \c error. +*/ +//---------------------------------------------------------------------- +/*! \def RETURN(error) + \brief Prints out a description of the error code being returned + (which, in this case, may be either "erroneous" or "successful") + and then exits the enclosing function with a call to \c "return error;". + + \param error A \c status_t error code to report and return. + + If DEBUG is undefined, silently returns the value in \c error. +*/ +//---------------------------------------------------------------------- +/*! \def FATAL(x) + \brief Prints out a fatal error message. + + This one's still a work in progress... + + \param x A printf-style format string enclosed in an extra set of parenteses, + e.g. PRINT(("%d\n", 0)); + + If DEBUG is undefined, does nothing. +*/ +//---------------------------------------------------------------------- +/*! \def INFORM(x) + \brief Directly prints the contents of \a x with no extra formatting or + information included (just like a straight \c printf() call). Does so + whether \c DEBUG is defined or not. + + \param x A printf-style format string enclosed in an extra set of parenteses, + e.g. PRINT(("%d\n", 0)); + + I'll say it again: Prints its output regardless to DEBUG being defined or + undefined. +*/ +//---------------------------------------------------------------------- +/*! \def DBG(x) + \brief If debug is defined, \a x is passed along to the code and + executed unmodified. If \c DEBUG is undefined, the contents of + \a x disappear into the ether. + + \param x Damn near anything resembling valid C\C++. +*/ +//---------------------------------------------------------------------- +/*! \def DIE(x) + \brief Drops the user into the appropriate debugger (user or kernel) + after printing out the handy message bundled in the parenthesee + enclosed printf-style format string found in \a x. + + \param x A printf-style format string enclosed in an extra set of parenteses, + e.g. PRINT(("%d\n", 0)); +*/ + + +//---------------------------------------------------------------------- +// declarations +//---------------------------------------------------------------------- + +static void indent(uint8 tabCount); +static void unindent(uint8 tabCount); +static int32 get_tls_handle(); + +//! Used to keep the tls handle from being allocated more than once. +vint32 tls_spinlock = 0; + +/*! \brief Used to flag whether the tls handle has been allocated yet. + + Not sure if this really needs to be \c volatile or not... +*/ +volatile bool tls_handle_initialized = false; + +//! The tls handle of the tls var used to store indentation info. +int32 tls_handle = 0; + +//---------------------------------------------------------------------- +// public functions +//---------------------------------------------------------------------- + +/*! \brief Returns the current debug indentation level for the + current thread. + + NOTE: indentation is currently unsupported for R5::kernelland due + to lack of thread local storage support. +*/ +int32 +_get_debug_indent_level() +{ + return (int32)tls_get(get_tls_handle()); +} + +//---------------------------------------------------------------------- +// static functions +//---------------------------------------------------------------------- + +/*! \brief Increases the current debug indentation level for + the current thread by 1. +*/ +void +indent(uint8 tabCount) +{ + tls_set(get_tls_handle(), (void*)(_get_debug_indent_level()+tabCount)); +} + +/*! \brief Decreases the current debug indentation level for + the current thread by 1. +*/ +void +unindent(uint8 tabCount) +{ + tls_set(get_tls_handle(), (void*)(_get_debug_indent_level()-tabCount)); +} + +/*! \brief Returns the thread local storage handle used to store + indentation information, allocating the handle first if + necessary. +*/ +int32 +get_tls_handle() +{ + // Init the tls handle if this is the first call. + if (!tls_handle_initialized) { + if (atomic_or(&tls_spinlock, 1) == 0) { + // First one in gets to init + tls_handle = tls_allocate(); + tls_handle_initialized = true; + atomic_and(&tls_spinlock, 0); + } else { + // All others must wait patiently + while (!tls_handle_initialized) { + snooze(1); + } + } + } + return tls_handle; +} + +/*! \brief Helper class for initializing the debugging output + file. + + Note that this hummer isn't threadsafe, but it doesn't really + matter for our concerns, since the worst it'll result in is + a dangling file descriptor, and that would be in the case of + two or more volumes being mounted almost simultaneously... + not too big of a worry. +*/ +class DebugOutputFile { +public: + DebugOutputFile(const char *filename = NULL) + : fFile(-1) + { + Init(filename); + } + + ~DebugOutputFile() { + if (fFile >= 0) + close(fFile); + } + + void Init(const char *filename) { + if (fFile < 0 && filename) + fFile = open(filename, O_RDWR | O_CREAT | O_TRUNC); + } + + int File() const { return fFile; } +private: + int fFile; +}; + +DebugOutputFile *out = NULL; + +/*! \brief It doesn't appear that the constructor for the global + \c out variable is called when built as an R5 filesystem add-on, + so this function needs to be called in udf_mount to let the + magic happen. +*/ +void initialize_debugger(const char *filename) +{ +#if DEBUG_TO_FILE + if (!out) { + out = new DebugOutputFile(filename); + dbg_printf("out was NULL!\n"); + } else { + DebugOutputFile *temp = out; + out = new DebugOutputFile(filename); + dbg_printf("out was %p!\n", temp); + } +#endif +} + +// dbg_printf, stolen from Ingo's ReiserFS::Debug.cpp. +void +dbg_printf(const char *format,...) +{ +#if DEBUG_TO_FILE + if (!out) + return; + + char buffer[1024]; + va_list args; + va_start(args, format); + // no vsnprintf() on PPC + #if defined(__INTEL__) + vsnprintf(buffer, sizeof(buffer) - 1, format, args); + #endif + va_end(args); + buffer[sizeof(buffer) - 1] = '\0'; + write(out->File(), buffer, strlen(buffer)); +#endif +} + +//---------------------------------------------------------------------- +// DebugHelper +//---------------------------------------------------------------------- + +/*! \brief Increases the current indentation level. +*/ +DebugHelper::DebugHelper(const char *className, uint8 tabCount) + : fTabCount(tabCount) + , fClassName(NULL) +{ + indent(fTabCount); + if (className) { + fClassName = (char*)malloc(strlen(className)+1); + if (fClassName) + strcpy(fClassName, className); + } +} + +/*! \brief Decreases the current indentation level. +*/ +DebugHelper::~DebugHelper() +{ + unindent(fTabCount); + free(fClassName); +} + diff --git a/src/apps/bin/makeudfimage/Debug.h b/src/apps/bin/makeudfimage/Debug.h new file mode 100644 index 0000000000..1b3c890414 --- /dev/null +++ b/src/apps/bin/makeudfimage/Debug.h @@ -0,0 +1,227 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// This version copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net +// Initial version copyright (c) 2002 Axel Dörfler, axeld@pinc-software.de +// dbg_printf() function copyright (c) 2003 Ingo Weinhold, bonefish@cs.tu-berlin.edu +//---------------------------------------------------------------------- +#ifndef MY_DEBUG_H +#define MY_DEBUG_H + +/*! \file Debug.h + + Handy debugging macros. +*/ + +#include + +#include +#ifdef DEBUG +# include +#endif +#include + +#define DEBUG_TO_FILE 0 + +#if DEBUG_TO_FILE +# include +# include +# define __out dbg_printf + void dbg_printf(const char *format,...); + void initialize_debugger(const char *filename); +#else +# include +# include +# define __out printf +#endif + +class DebugHelper; + +int32 _get_debug_indent_level(); + +/*! \brief Helper class that is allocated on the stack by + the \c DEBUG_INIT() macro. On creation, it increases the + current indentation level by the amount specified via its + constructor's \c tabCount parameter; on destruction, it + decreases it. +*/ +class DebugHelper +{ +public: + DebugHelper(const char *className = NULL, uint8 tabCount = 1); + ~DebugHelper(); + + uint8 TabCount() const { return fTabCount; } + const char* ClassName() const { return fClassName; } + +private: + uint8 fTabCount; + char *fClassName; +}; + +//---------------------------------------------------------------------- +// NOTE: See Debug.cpp for complete descriptions of the following +// debug macros. +//---------------------------------------------------------------------- + + +//---------------------------------------------------------------------- +// DEBUG-independent macros +//---------------------------------------------------------------------- +#define INFORM(x) { __out("mkudf: "); __out x; } +#ifdef USER +# define DIE(x) debugger x +#else +# define DIE(x) kernel_debugger x +#endif + +//---------------------------------------------------------------------- +// DEBUG-dependent macros +//---------------------------------------------------------------------- +#ifdef DEBUG + #if DEBUG_TO_FILE + #define INITIALIZE_DEBUGGING_OUTPUT_FILE(filename) initialize_debugger(filename); + #else + #define INITIALIZE_DEBUGGING_OUTPUT_FILE(filename) ; + #endif + + #define DEBUG_INIT_SILENT(className) \ + DebugHelper _debugHelper(className, 2); + + #define DEBUG_INIT(className) \ + DEBUG_INIT_SILENT(className); \ + PRINT(("\n")); + + #define DEBUG_INIT_ETC(className, arguments) \ + DEBUG_INIT_SILENT(className) \ + { \ + PRINT_INDENT(); \ + if (_debugHelper.ClassName()) { \ + __out("mkudf: %s::%s(", \ + _debugHelper.ClassName(), __FUNCTION__); \ + } else { \ + __out("mkudf: %s(", __FUNCTION__); \ + } \ + __out arguments; \ + __out("):\n"); \ + } + + #define DUMP_INIT(categoryFlags, className) \ + DEBUG_INIT_SILENT(className); + + #define PRINT(x) { \ + { \ + PRINT_INDENT(); \ + if (_debugHelper.ClassName()) { \ + __out("mkudf: %s::%s(): ", \ + _debugHelper.ClassName(), __FUNCTION__); \ + } else { \ + __out("mkudf: %s(): ", __FUNCTION__); \ + } \ + __out x; \ + } \ + } + + #define LPRINT(x) { \ + { \ + PRINT_INDENT(); \ + if (_debugHelper.ClassName()) { \ + __out("mkudf: %s::%s(): line %d: ", \ + _debugHelper.ClassName(), __FUNCTION__, __LINE__); \ + } else { \ + __out("mkudf: %s(): line %d: ", \ + __FUNCTION__, __LINE__); \ + } \ + __out x; \ + } \ + } + + #define SIMPLE_PRINT(x) { \ + { \ + __out x; \ + } \ + } + + #define PRINT_INDENT() { \ + { \ + int32 _level = _get_debug_indent_level(); \ + for (int32 i = 0; i < _level-_debugHelper.TabCount(); i++) { \ + __out(" "); \ + } \ + } \ + } + + #define PRINT_DIVIDER() \ + PRINT_INDENT(); \ + SIMPLE_PRINT(("------------------------------------------------------------\n")); + + #define DUMP(object) \ + { \ + (object).dump(); \ + } + + #define PDUMP(objectPointer) \ + { \ + (objectPointer)->dump(); \ + } + + #define REPORT_ERROR(error) { \ + LPRINT(("returning error 0x%lx, `%s'\n", error, strerror(error))); \ + } + + #define RETURN_ERROR(error) { \ + status_t _status = error; \ + if (_status < (status_t)B_OK) \ + REPORT_ERROR(_status); \ + return _status; \ + } + + #define RETURN(error) { \ + status_t _status = error; \ + if (_status < (status_t)B_OK) { \ + REPORT_ERROR(_status); \ + } else if (_status == (status_t)B_OK) { \ + LPRINT(("returning B_OK\n")); \ + } else { \ + LPRINT(("returning 0x%lx = %ld\n", _status, _status)); \ + } \ + return _status; \ + } + + #define FATAL(x) { \ + PRINT(("fatal error: ")); SIMPLE_PRINT(x); \ + } + + #define DBG(x) x ; + +#else // ifdef DEBUG + #define INITIALIZE_DEBUGGING_OUTPUT_FILE(filename) ; + #define DEBUG_INIT_SILENT(className) ; + #define DEBUG_INIT(className) ; + #define DEBUG_INIT_ETC(className, arguments) ; + #define DUMP_INIT(className) ; + #define PRINT(x) ; + #define LPRINT(x) ; + #define SIMPLE_PRINT(x) ; + #define PRINT_INDENT(x) ; + #define PRINT_DIVIDER() ; + #define DUMP(object) ; + #define PDUMP(objectPointer) ; + #define REPORT_ERROR(status) ; + #define RETURN_ERROR(status) return status; + #define RETURN(status) return status; + #define FATAL(x) { __out("mkudf: fatal error: "); __out x; } + #define DBG(x) ; + #define DUMP(x) ; +#endif // ifdef DEBUG else + +#define TRACE(x) DBG(dprintf x) + +// These macros turn on or off extensive and generally unnecessary +// debugging output regarding table of contents parsing +//#define WARN(x) (dprintf x) +//#define WARN(x) +#define WARN(x) DBG(dprintf x) + +#endif // MY_DEBUG_H diff --git a/src/apps/bin/makeudfimage/Jamfile b/src/apps/bin/makeudfimage/Jamfile new file mode 100644 index 0000000000..7fe13ffa5f --- /dev/null +++ b/src/apps/bin/makeudfimage/Jamfile @@ -0,0 +1,10 @@ +SubDir OBOS_TOP src apps bin makeudfimage ; + +BinCommand makeudfimage + : makeudfimage.cpp + Debug.cpp + Shell.cpp + : stdc++.r4 + +; + diff --git a/src/apps/bin/makeudfimage/Shell.cpp b/src/apps/bin/makeudfimage/Shell.cpp new file mode 100644 index 0000000000..35f2974c1d --- /dev/null +++ b/src/apps/bin/makeudfimage/Shell.cpp @@ -0,0 +1,66 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net +//---------------------------------------------------------------------- + +/*! \file Shell.cpp + + Command-line shell for makeudfimage +*/ + +#include "Shell.h" + +#include + +#include "Debug.h" + +Shell::Shell() +{ +} + +void +Shell::Run(int argc, char *argv[]) +{ + DEBUG_INIT("Shell"); + _ProcessArguments(argc, argv); + PRINT(("finished\n")); +} + +status_t +Shell::_ProcessArguments(int argc, char *argv[]) { + DEBUG_INIT_ETC("Shell", ("argc: %d", argc)); + + // If we're given no parameters, the default settings + // will do just fine + if (argc < 2) + return B_OK; + + // Handle each command line argument (skipping the first + // which is just the app name) + for (int i = 1; i < argc; i++) { + std::string str(argv[i]); + + status_t error = _ProcessArgument(str, argc, argv); + if (error) + RETURN(error); + } + + RETURN(B_OK); +} + +status_t +Shell::_ProcessArgument(std::string arg, int argc, char *argv[]) { + DEBUG_INIT_ETC("Shell", ("arg: `%s'", arg.c_str())); + if (arg == "--help") { + _PrintHelp(); + RETURN(B_ERROR); + } + RETURN(B_ERROR); +} + +void +Shell::_PrintHelp() { + printf("usage: makeudfimage\n"); +} diff --git a/src/apps/bin/makeudfimage/Shell.h b/src/apps/bin/makeudfimage/Shell.h new file mode 100644 index 0000000000..62d88885db --- /dev/null +++ b/src/apps/bin/makeudfimage/Shell.h @@ -0,0 +1,29 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net +//---------------------------------------------------------------------- + +/*! \file Shell.h +*/ + +#ifndef _SHELL_H +#define _SHELL_H + +#include + +#include "SupportDefs.h" + +class Shell { +public: + Shell(); + void Run(int argc, char *argv[]); +private: + status_t _ProcessArguments(int argc, char *argv[]); + status_t _ProcessArgument(std::string arg, int argc, char *argv[]); + void _PrintHelp(); +}; + + +#endif // _SHELL_H diff --git a/src/apps/bin/makeudfimage/makeudfimage.cpp b/src/apps/bin/makeudfimage/makeudfimage.cpp new file mode 100644 index 0000000000..5df5bd9b27 --- /dev/null +++ b/src/apps/bin/makeudfimage/makeudfimage.cpp @@ -0,0 +1,20 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net +//---------------------------------------------------------------------- + +/*! \file makeudfimage.cpp + + UDF image builder. +*/ + +#include "Shell.h" + +int main(int argc, char *argv[]) +{ + Shell shell; + shell.Run(argc, argv); + return 0; +}