From 2f658aa0a319eb4e0e31e995dfd1435b05eaceb9 Mon Sep 17 00:00:00 2001 From: tibs Date: Mon, 16 Feb 2009 21:45:34 +0000 Subject: [PATCH] Write some initial code to allow for output redirection --HG-- extra : convert_revision : svn%3Aeff31bef-be4a-0410-a8fe-e47997df2690/trunk%40116 --- Makefile | 21 ++++- Makefile.w32 | 1 + printing.c | 199 +++++++++++++++++++++++++++++++++++++++++++++++ printing_defns.h | 43 ++++++++++ printing_fns.h | 110 ++++++++++++++++++++++++++ test_printing.c | 161 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 532 insertions(+), 3 deletions(-) create mode 100644 printing.c create mode 100644 printing_defns.h create mode 100644 printing_fns.h create mode 100644 test_printing.c diff --git a/Makefile b/Makefile index 4d73db8..15f87f6 100644 --- a/Makefile +++ b/Makefile @@ -102,6 +102,7 @@ SRCS = \ l2audio.c \ misc.c \ nalunit.c \ + printing.c \ ps.c \ pes.c \ pidint.c \ @@ -128,6 +129,7 @@ OBJS = \ ps.o \ pes.o \ pidint.o \ + printing.o \ reverse.o \ ts.o \ tswrite.o \ @@ -161,6 +163,7 @@ PROG_OBJS = \ TS2PS_OBJS = $(OBJDIR)/ts2ps.o TEST_PES_OBJS = $(OBJDIR)/test_pes.o +TEST_PRINTING_OBJS = $(OBJDIR)/test_printing.o TEST_OBJS = \ $(OBJDIR)/test_nal_unit_list.o \ @@ -197,6 +200,7 @@ TS2PS_PROG = $(BINDIR)/ts2ps # Is test_pes still useful? TEST_PES_PROG = $(BINDIR)/test_pes +TEST_PRINTING_PROG = $(BINDIR)/test_printing # And then the testing programs (which we only build if we are # running the tests) @@ -283,6 +287,9 @@ $(BINDIR)/pcapreport: $(OBJDIR)/pcapreport.o $(LIB) $(BINDIR)/test_pes: $(OBJDIR)/test_pes.o $(LIB) $(CC) $< -o $(BINDIR)/test_pes $(LDFLAGS) $(LIBOPTS) +$(BINDIR)/test_printing: $(OBJDIR)/test_printing.o $(LIB) + $(CC) $< -o $(BINDIR)/test_printing $(LDFLAGS) $(LIBOPTS) + $(BINDIR)/test_nal_unit_list: $(OBJDIR)/test_nal_unit_list.o $(LIB) $(CC) $< -o $(BINDIR)/test_nal_unit_list $(LDFLAGS) $(LIBOPTS) $(BINDIR)/test_es_unit_list: $(OBJDIR)/test_es_unit_list.o $(LIB) @@ -305,13 +312,14 @@ REVERSE_H = reverse_fns.h reverse_defns.h FILTER_H = filter_fns.h filter_defns.h $(REVERSE_H) AUDIO_H = adts_fns.h l2audio_fns.h ac3_fns.h audio_fns.h audio_defns.h adts_defns.h -# Everyone depends upon the basic configuration file -$(LIB)($(OBJS)) $(TEST_OBJS) $(PROG_OBJS): compat.h +# Everyone depends upon the basic configuration file, and I assert they all +# want (or may want) printing... +$(LIB)($(OBJS)) $(TEST_OBJS) $(PROG_OBJS): compat.h printing_fns.h # Which library modules depend on which header files is complex, so # lets just be simple $(LIB)($(OBJS)): $(ACCESSUNIT_H) $(NALUNIT_H) $(TS_H) $(ES_H) $(PES_H) \ - misc_fns.h $(PS_H) $(H262_H) $(TSWRITE_H) $(AVS_H) \ + misc_fns.h printing_fns.h $(PS_H) $(H262_H) $(TSWRITE_H) $(AVS_H) \ $(REVERSE_H) $(FILTER_H) $(AUDIO_H) $(OBJDIR)/es2ts.o: es2ts.c $(ES_H) $(TS_H) misc_fns.h version.h @@ -359,6 +367,8 @@ $(OBJDIR)/pcapreport.o: pcapreport.c pcap.h version.h misc_fns.h $(OBJDIR)/test_pes.o: test_pes.c $(TS_H) $(PS_H) $(ES_H) misc_fns.h $(PES_H) version.h $(CC) -c $< -o $@ $(CFLAGS) +$(OBJDIR)/test_printing.o: test_printing.c $(TS_H) $(PS_H) $(ES_H) version.h + $(CC) -c $< -o $@ $(CFLAGS) $(OBJDIR)/test_ps.o: test_ps.c $(PS_H) misc_fns.h version.h $(CC) -c $< -o $@ $(CFLAGS) $(OBJDIR)/test_nal_unit_list.o: test_nal_unit_list.c $(NALUNIT_H) version.h @@ -386,6 +396,7 @@ objclean: -rm -f $(TEST_PROGS) -rm -f $(TS2PS_OBJS) $(TS2PS_PROG) -rm -f $(TEST_PES_OBJS) $(TEST_PES_PROG) + -rm -f $(TEST_PRINTING_OBJS) $(TEST_PRINTING_PROG) -rm -f ES_test3.ts es_test3.ts -rm -f ES_test2.264 es_test3.264 -rm -f es_test_a.ts es_test_a.264 @@ -406,6 +417,10 @@ distclean: clean TESTDATAFILE = /data/video/CVBt_hp_trail.264 +# Only build test_printing if explicitly asked to do so +.PHONY: test_printing +test_printing: $(BINDIR)/test_printing + # Only build test_pes if explicitly asked to do so .PHONY: test_pes test_pes: $(BINDIR)/test_pes diff --git a/Makefile.w32 b/Makefile.w32 index 529eeaf..3bf3679 100644 --- a/Makefile.w32 +++ b/Makefile.w32 @@ -107,6 +107,7 @@ LIB_OBJS = \ $(OBJDIR)\pcap.obj \ $(OBJDIR)\pes.obj \ $(OBJDIR)\pidint.obj \ + $(OBJDIR)\printing.obj \ $(OBJDIR)\ps.obj \ $(OBJDIR)\reverse.obj \ $(OBJDIR)\ts.obj \ diff --git a/printing.c b/printing.c new file mode 100644 index 0000000..0208bba --- /dev/null +++ b/printing.c @@ -0,0 +1,199 @@ +/* + * Support for printing out to stdout/stderr/elsewhere -- functions to use + * instead of printf, etc. + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the MPEG TS, PS and ES tools. + * + * The Initial Developer of the Original Code is Amino Communications Ltd. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. +* + * Contributor(s): + * Amino Communications Ltd, Swavesey, Cambridge UK + * + * ***** END LICENSE BLOCK ***** + */ + +#include +#include + +#include "compat.h" +#include "printing_fns.h" + +// ============================================================ +// Default printing functions +// ============================================================ + +static int print_message_to_stdout(const char *message) +{ + return (fputs(message,stdout) == 0 ? 0:1); +} +static int print_message_to_stderr(const char *message) +{ + return (fputs(message,stderr) == 0 ? 0:1); +} +static int fprint_message_to_stdout(const char *format, va_list arg_ptr) +{ + return (vfprintf(stdout, format, arg_ptr) < 0 ? 1:0); +} +static int fprint_message_to_stderr(const char *format, va_list arg_ptr) +{ + return (vfprintf(stderr, format, arg_ptr) < 0 ? 1:0); +} + +// ============================================================ +// Print redirection +// ============================================================ + +static int (*print_message_fn) (const char *message) = print_message_to_stdout; +static int (*print_error_fn) (const char *message) = print_message_to_stdout; + +static int (*fprint_message_fn) (const char *format, va_list arg_ptr) = fprint_message_to_stdout; +static int (*fprint_error_fn) (const char *format, va_list arg_ptr) = fprint_message_to_stdout; + + +// ============================================================ +// Functions for printing +// ============================================================ +/* + * Prints the given string, as a normal message. + * + * Returns 0 if all goes well, 1 if something goes wrong. + */ +extern int print_msg(const char *text) +{ + return print_message_fn(text); +} + + +/* + * Prints the given string, as an error message. + * + * Returns 0 if all goes well, 1 if something goes wrong. + */ +extern int print_err(const char *text) +{ + return print_error_fn(text); +} + + +/* + * Prints the given format text, as a normal message. + * + * Returns 0 if all goes well, 1 if something goes wrong. + */ +extern int fprint_msg(const char *format, ...) +{ + int retval; + va_list va_arg; + va_start(va_arg, format); + retval = fprint_message_fn(format, va_arg); + va_end(va_arg); + return retval; +} + + +/* + * Prints the given formatted text, as an error message. + * + * Returns 0 if all goes well, 1 if something goes wrong. + */ +extern int fprint_err(const char *format, ...) +{ + int retval; + va_list va_arg; + va_start(va_arg, format); + retval = fprint_error_fn(format, va_arg); + va_end(va_arg); + return retval; +} + +// ============================================================ +// Choosing what the printing functions do +// ============================================================ +/* + * Calling this causes errors to go to stderr, and all other output + * to go to stdout. This is the "traditional" mechanism used by + * Unices. + */ +extern void redirect_output_traditional(void) +{ + print_message_fn = &print_message_to_stdout; + print_error_fn = &print_message_to_stderr; + fprint_message_fn = &fprint_message_to_stdout; + fprint_error_fn = &fprint_message_to_stderr; +} + + +/* + * Calling this causes all output to go to stdout. This is simpler, + * and is likely to be more use to most users. + * + * This is the default state. + */ +extern void redirect_output_stdout(void) +{ + print_message_fn = &print_message_to_stdout; + print_error_fn = &print_message_to_stdout; + fprint_message_fn = &fprint_message_to_stdout; + fprint_error_fn = &fprint_message_to_stdout; +} + + +/* + * This allows the user to specify a set of functions to use for + * formatted printing and non-formatted printing of errors and + * other messages. + * + * It is up to the caller to ensure that all of the functions + * make sense. All four functions must be specified. + * + * * `new_print_message_fn` takes a string and prints it out to the "normal" + * output stream. + * * `new_print_error_fn` takes a string and prints it out to the error output + * stream. + * * `new_fprint_message_fn` takes a printf-style format string and the + * appropriate arguments, and writes the result out to the "normal" output. + * * `new_fprint_error_fn` takes a printf-style format string and the + * appropriate arguments, and writes the result out to the "error" output. + * + * Returns 0 if all goes well, 1 if something goes wrong. + */ +extern int redirect_output( int (*new_print_message_fn) (const char *message), + int (*new_print_error_fn) (const char *message), + int (*new_fprint_message_fn) (const char *format, va_list arg_ptr), + int (*new_fprint_error_fn) (const char *format, va_list arg_ptr) + ) +{ + if (new_print_message_fn == NULL || new_print_error_fn == NULL || + new_fprint_message_fn == NULL || new_fprint_error_fn == NULL) + return 1; + + print_message_fn = new_print_message_fn; + print_error_fn = new_print_error_fn; + fprint_message_fn = new_fprint_message_fn; + fprint_error_fn = new_fprint_error_fn; + + return 0; +} + + +// Local Variables: +// tab-width: 8 +// indent-tabs-mode: nil +// c-basic-offset: 2 +// End: +// vim: set tabstop=8 shiftwidth=2 expandtab: diff --git a/printing_defns.h b/printing_defns.h new file mode 100644 index 0000000..8b3b59a --- /dev/null +++ b/printing_defns.h @@ -0,0 +1,43 @@ +/* + * Support for printing out to stdout/stderr/elsewhere -- functions to use + * instead of printf, etc. + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the MPEG TS, PS and ES tools. + * + * The Initial Developer of the Original Code is Amino Communications Ltd. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Amino Communications Ltd, Swavesey, Cambridge UK + * + * ***** END LICENSE BLOCK ***** + */ + +#ifndef _printing_defns +#define _printing_defns + +#include +#include + +#endif // _printing_defns + +// Local Variables: +// tab-width: 8 +// indent-tabs-mode: nil +// c-basic-offset: 2 +// End: +// vim: set tabstop=8 shiftwidth=2 expandtab: diff --git a/printing_fns.h b/printing_fns.h new file mode 100644 index 0000000..90fb35c --- /dev/null +++ b/printing_fns.h @@ -0,0 +1,110 @@ +/* + * Support for printing out to stdout/stderr/elsewhere -- functions to use + * instead of printf, etc. + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the MPEG TS, PS and ES tools. + * + * The Initial Developer of the Original Code is Amino Communications Ltd. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Amino Communications Ltd, Swavesey, Cambridge UK + * + * ***** END LICENSE BLOCK ***** + */ +#ifndef _printing_fns +#define _printing_fns + +#include "printing_defns.h" + +// ============================================================ +// Functions for printing +// ============================================================ +/* + * Prints the given string, as a normal message. + * + * Returns 0 if all goes well, 1 if something goes wrong. + */ +extern int print_msg(const char *text); +/* + * Prints the given string, as an error message. + * + * Returns 0 if all goes well, 1 if something goes wrong. + */ +extern int print_err(const char *text); +/* + * Prints the given format text, as a normal message. + * + * Returns 0 if all goes well, 1 if something goes wrong. + */ +extern int fprint_msg(const char *format, ...); +/* + * Prints the given formatted text, as an error message. + * + * Returns 0 if all goes well, 1 if something goes wrong. + */ +extern int fprint_err(const char *format, ...); + +// ============================================================ +// Choosing what the printing functions do +// ============================================================ +/* + * Calling this causes errors to go to stderr, and all other output + * to go to stdout. This is the "traditional" mechanism used by + * Unices. + */ +extern void redirect_output_traditional(void); +/* + * Calling this causes all output to go to stdout. This is simpler, + * and is likely to be more use to most users. + * + * This is the default state. + */ +extern void redirect_output_stdout(void); +/* + * This allows the user to specify a set of functions to use for + * formatted printing and non-formatted printing of errors and + * other messages. + * + * It is up to the caller to ensure that all of the functions + * make sense. All four functions must be specified. + * + * * `new_print_message_fn` takes a string and prints it out to the "normal" + * output stream. + * * `new_print_error_fn` takes a string and prints it out to the error output + * stream. + * * `new_fprint_message_fn` takes a printf-style format string and the + * appropriate arguments, and writes the result out to the "normal" output. + * * `new_fprint_error_fn` takes a printf-style format string and the + * appropriate arguments, and writes the result out to the "error" output. + * + * Returns 0 if all goes well, 1 if something goes wrong. + */ +extern int redirect_output( int (*new_print_message_fn) (const char *message), + int (*new_print_error_fn) (const char *message), + int (*new_fprint_message_fn) (const char *format, va_list arg_ptr), + int (*new_fprint_error_fn) (const char *format, va_list arg_ptr) + ); + +#endif // _printing_fns + +// Local Variables: +// tab-width: 8 +// indent-tabs-mode: nil +// c-basic-offset: 2 +// End: +// vim: set tabstop=8 shiftwidth=2 expandtab: diff --git a/test_printing.c b/test_printing.c new file mode 100644 index 0000000..4118cca --- /dev/null +++ b/test_printing.c @@ -0,0 +1,161 @@ +/* + * Test the print redirection facilities + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the MPEG TS, PS and ES tools. + * + * The Initial Developer of the Original Code is Amino Communications Ltd. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Amino Communications Ltd, Swavesey, Cambridge UK + * + * ***** END LICENSE BLOCK ***** + */ + +#include + +#include "printing_fns.h" +#include "version.h" + +// Some example redirection routines + +static int print_message_to_stdout(const char *message) +{ + (void) printf("<<>> %s",message); + return 0; +} +static int print_message_to_stderr(const char *message) +{ + (void) printf("<<>> %s",message); + return 0; +} +static int fprint_message_to_stdout(const char *format, va_list arg_ptr) +{ + printf("<<>> "); + return (vfprintf(stdout, format, arg_ptr) < 0 ? 1:0); +} +static int fprint_message_to_stderr(const char *format, va_list arg_ptr) +{ + printf("<<>> "); + return (vfprintf(stdout, format, arg_ptr) < 0 ? 1:0); +} + +static void print_usage() +{ + printf( + "Usage: test_printing\n" + "\n" + ); + REPORT_VERSION("test_printing"); + printf( + "\n" + " Test the print redirection facilities.\n" + ); +} + +int main(int argc, char **argv) +{ + int err; + + if (argc > 1) + { + print_usage(); + return 1; + } + + printf("A fairly crude set of tests, mainly to check that nothing falls over.\n"); + printf("For each set of tests, you should see 4 messages, all very similar.\n"); + + printf("------------------------------------\n"); + printf("Testing the default output functions\n"); + printf("------------------------------------\n"); + print_msg("1. Printing a normal message\n"); + print_err("2. Printing an error message\n"); + fprint_msg("3. Printing a formatted '%s'\n","message"); + fprint_err("4. Printing a formatted '%s'\n","error"); + + printf("-------------------------------------------\n"); + printf("Choosing 'traditional' output and repeating\n"); + printf("-------------------------------------------\n"); + redirect_output_traditional(); + print_msg("1. Printing a normal message\n"); + print_err("2. Printing an error message\n"); + fprint_msg("3. Printing a formatted '%s'\n","message"); + fprint_err("4. Printing a formatted '%s'\n","error"); + + printf("---------------------------------------------\n"); + printf("Choosing 'all output to stdout' and repeating\n"); + printf("---------------------------------------------\n"); + redirect_output_stdout(); + print_msg("1. Printing a normal message\n"); + print_err("2. Printing an error message\n"); + fprint_msg("3. Printing a formatted '%s'\n","message"); + fprint_err("4. Printing a formatted '%s'\n","error"); + + printf("-----------------------------------------\n"); + printf("Choosing 'custom functions' and repeating\n"); + printf("-----------------------------------------\n"); + err = redirect_output(print_message_to_stdout, + print_message_to_stderr, + fprint_message_to_stdout, + fprint_message_to_stderr); + if (err) + { + printf("Oops -- that went wrong: %d\n",err); + return 1; + } + print_msg("1. Printing a normal message\n"); + print_err("2. Printing an error message\n"); + fprint_msg("3. Printing a formatted '%s'\n","message"); + fprint_err("4. Printing a formatted '%s'\n","error"); + + printf("---------------------------------------------\n"); + printf("Trying to choose only *some* custom functions\n"); + printf("---------------------------------------------\n"); + err = redirect_output(print_message_to_stdout, + print_message_to_stderr, + NULL, + fprint_message_to_stderr); + if (err == 0) + { + printf("Oh dear, that appeared to work: %d\n",err); + printf("So what happens if we try our tests again?\n"); + print_msg("1. Printing a normal message\n"); + print_err("2. Printing an error message\n"); + fprint_msg("3. Printing a formatted '%s'\n","message"); + fprint_err("4. Printing a formatted '%s'\n","error"); + return 1; + } + printf("Which failed - good\n"); + + printf("------------------------------------------------------------------\n"); + printf("After that (expected) failure, all four messages should still work\n"); + printf("------------------------------------------------------------------\n"); + print_msg("1. Printing a normal message\n"); + print_err("2. Printing an error message\n"); + fprint_msg("3. Printing a formatted '%s'\n","message"); + fprint_err("4. Printing a formatted '%s'\n","error"); + + return 0; +} + +// Local Variables: +// tab-width: 8 +// indent-tabs-mode: nil +// c-basic-offset: 2 +// End: +// vim: set tabstop=8 shiftwidth=2 expandtab: