# HG changeset patch # User Tero Marttila # Date 1261944077 -7200 # Node ID cff7fac35cc2d79075b71dcdd2eb02351f446d51 initial code diff -r 000000000000 -r cff7fac35cc2 Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Sun Dec 27 22:01:17 2009 +0200 @@ -0,0 +1,80 @@ +# :set noexpandtab + +# warnings, and use C99 with GNU extensions +CFLAGS = -Wall -std=gnu99 -g + +# preprocessor flags +CPPFLAGS = -Isrc/ + +# output name +DIST_NAME = 78949E-as1 +DIST_RESOURCES = README "Learning Diary.pdf" + +all: depend bin/daemon lib/libnetdaemon.so bin/client + +bin/daemon : lib/libnetdaemon.so \ + build/obj/daemon/daemon.o build/obj/daemon/service.o build/obj/daemon/client.o build/obj/daemon/commands.o \ + build/obj/daemon/process.o \ + build/obj/shared/select.o build/obj/shared/log.o build/obj/shared/util.o build/obj/shared/signal.o + +lib/libnetdaemon.so : \ + build/obj/lib/client.o build/obj/lib/commands.o \ + build/obj/shared/proto.o + +bin/client : lib/libnetdaemon.so build/obj/shared/log.o + +SRC_PATHS = $(wildcard src/*/*.c) +SRC_NAMES = $(patsubst src/%,%,$(SRC_PATHS)) +SRC_DIRS = $(dir $(SRC_NAMES)) + +.PHONY : dirs clean depend dist + +dirs: + mkdir -p bin lib run dist + mkdir -p $(SRC_DIRS:%=build/deps/%) + mkdir -p $(SRC_DIRS:%=build/obj/%) + +clean: + rm -f build/obj/*/*.o build/deps/*/*.d + rm -f bin/* lib/*.so run/* + rm -rf dist/* + +# .h dependencies +depend: $(SRC_NAMES:%.c=build/deps/%.d) + +build/deps/%.d : src/%.c + @set -e; rm -f $@; \ + $(CC) -MM -MT __ $(CPPFLAGS) $< > $@.$$$$; \ + sed 's,__[ :]*,build/obj/$*.o $@ : ,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$ + +include $(wildcard build/deps/*/*.d) + +# build (potential) library targets with specific cflags +# XXX: just build everything with -fPIC? +build/obj/shared/%.o : src/shared/%.c + $(CC) -c -fPIC $(CPPFLAGS) $(CFLAGS) $< -o $@ + +build/obj/lib/%.o : src/lib/%.c + $(CC) -c -fPIC $(CPPFLAGS) $(CFLAGS) $< -o $@ + +# general binary objects +build/obj/%.o : src/%.c + $(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@ + +# output binaries +bin/% : build/obj/%/main.o + $(CC) $(LDFLAGS) $+ $(LOADLIBES) $(LDLIBS) -o $@ + +# output libraries +lib/lib%.so : + $(CC) -shared $(LDFLAGS) $+ $(LOADLIBES) $(LDLIBS) -o $@ + +dist: + mkdir -p dist/$(DIST_NAME) + cp -rv Makefile $(DIST_RESOURCES) src/ dist/$(DIST_NAME)/ + rm dist/$(DIST_NAME)/src/*/.*.sw[op] + make -C dist/$(DIST_NAME) dirs + tar -C dist -czvf dist/$(DIST_NAME).tar.gz $(DIST_NAME) + @echo "*** Output at dist/$(DIST_NAME).tar.gz" + diff -r 000000000000 -r cff7fac35cc2 src/lib/cache.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/cache.c Sun Dec 27 22:01:17 2009 +0200 @@ -0,0 +1,55 @@ +#include "cache.h" + +static int pt_cache_new (struct pt_cache **cache_ptr) +{ + struct pt_cache *cache; + + if ((cache = calloc(1, sizeof(*cache))) == NULL) + return -1; + + // ok + *cache_ptr = cache; + + return 0; +} + +int pt_cache_open (struct pt_cache **cache_ptr, struct pt_image *img, int mode) +{ + struct pt_cache *cache; + + // alloc + if (pt_cache_new(&cache)) + return -1; + + +} + +bool pt_cache_fresh (struct pt_cache *cache) +{ + // TODO: stat + mtime + return false; +} + +/** + * Create a new cache file, open it, and write out the header. + */ +static int pt_cache_create (struct pt_cache *cache, struct pt_cache_header *header) +{ + +} + +int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info) +{ + struct pt_cache_header header; + + memset(&header, 0, sizeof(header)); + + // fill in basic info + header->width = png_get_image_width(png, info); + header->height = png_get_image_height(png, info); + header->bit_depth = png_get_bit_depth(png, info); + header->color_type = png_get_color_type(png, info); + + // fill in other info + header->row_bytes = png_get_rowbytes(png, info); +} diff -r 000000000000 -r cff7fac35cc2 src/lib/cache.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/cache.h Sun Dec 27 22:01:17 2009 +0200 @@ -0,0 +1,47 @@ +#ifndef PNGTILE_CACHE_H +#define PNGTILE_CACHE_H + +/** + * @file + * + * Internal image cache implementation + */ +#include "image.h" + +/** + * State for cache access + */ +struct pt_cache { + +}; + +/** + * On-disk header + */ +struct pt_cache_header { + /** Pixel dimensions of image */ + uint32_t width, height; + + /** Pixel format */ + uint8_t bit_depth, color_type; + + /** Convenience field for number of bytes per row */ + uint32_t row_bytes; +}; + +/** + * Construct the image cache info object associated with the given image. + */ +int pt_cache_open (struct pt_cache **cache_ptr, struct pt_image *img, int mode); + +/** + * Verify if the cached data is still fresh compared to the original. + */ +bool pt_cache_fresh (struct pt_cache *cache); + +/** + * Update the cache data from the given PNG image. + */ +int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info); + +#endif diff -r 000000000000 -r cff7fac35cc2 src/lib/image.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/image.c Sun Dec 27 22:01:17 2009 +0200 @@ -0,0 +1,152 @@ +#include "image.h" + +static int pt_image_new (struct pt_image **img_ptr, struct pt_ctx *ctx, const char *png_path) +{ + struct pt_image *img; + + // alloc + if ((img = calloc(1, sizeof(*img))) == NULL) + return -1; + + if ((img->png_path = strdup(png_path)) == NULL) + goto error; + + // init + img->ctx = ctx; + + // ok + *img_ptr = img; + + return 0; + +error: + pt_image_destroy(img); + + return -1; +} + +/** + * Open the image's FILE + */ +static int pt_image_open_file (struct pt_image *img, FILE **file_ptr) +{ + FILE *fp; + + // open + if (fopen(img->png_path, "rb") < 0) + return -1; + + // ok + *file_ptr = fp; + + return 0; +} + +/** + * Open the PNG image, setting up the I/O and returning the png_structp and png_infop + */ +static int pt_image_open_png (struct pt_image *img, png_structp *png_ptr, png_infop *info_ptr) +{ + FILE *fp = NULL; + png_structp png = NULL; + png_infop info = NULL; + + // open I/O + if (pt_image_open_file(img, &fp)) + goto error; + + // create the struct + if ((png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL) + goto error; + + // create the info + if ((info = png_create_info_struct(png)) == NULL) + goto error; + + // setup error trap for the I/O + if (setjmp(png_jmpbuf(png))) + goto error; + + // setup I/O to FILE + png_init_io(png, fp); + + // ok + *png_ptr = png; + *info_ptr = info; + + return 0; + +error: + // cleanup file + if (fp) fclose(fp); + + // cleanup PNG state + png_destroy_read_struct(&png, &info, NULL); + + return -1; +} + +/** + * Open the PNG image, and write out to the cache + */ +static int pt_image_update_cache (struct pt_image *img) +{ + png_structp png; + png_infop info; + + // open .png + if (pt_image_open_png(img, &png, &info)) + return -1; + + // setup error trap + if (setjmp(png_jmpbuf(png))) + goto error; + + // read meta-info + png_read_info(png, info); + + // pass to cache object + if (pt_cache_update_png(img->cache, png, info)) + goto error; + + // finish off, ignore trailing data + png_read_end(png, NULL); + + // clean up + png_destroy_read_struct(&png, &info); + + return 0; + +error: + // clean up + png_destroy_read_struct(&png, &info); + + return -1; +} + +int pt_image_open (struct pt_image **img_ptr, struct pt_ctx *ctx, const char *png_path, int cache_mode) +{ + struct pt_image *img; + + // XXX: verify that the png_path exists and looks like a PNG file + + // alloc + if (pt_image_new(&img, ctx, png_path)) + return -1; + + // open the cache object for this image + if (pt_cache_open(&img->cache, img, mode)) + goto error; + + // update if not fresh + if (!pt_cache_fresh(img->cache)) + pt_image_update_cache(img); + + // ok, ready for access + *img_ptr = img; + + return 0; + +error: + pt_image_destroy(img); +} diff -r 000000000000 -r cff7fac35cc2 src/lib/image.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/image.h Sun Dec 27 22:01:17 2009 +0200 @@ -0,0 +1,24 @@ +#ifndef PNGTILE_IMAGE_H +#define PNGTILE_IMAGE_H + +/** + * @file + * + * Internal pt_image state + */ +#include "pngtile.h" + +struct pt_image { + /** Associated global state */ + struct pt_ctx *ctx; + + /** Path to .png */ + char *png_path; + + /** Cache object */ + struct pt_cache *cache; +}; + + + +#endif diff -r 000000000000 -r cff7fac35cc2 src/lib/pngtile.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/pngtile.h Sun Dec 27 22:01:17 2009 +0200 @@ -0,0 +1,40 @@ +#ifndef PNGTILE_H +#define PNGTILE_H + +/** + * @file + * + * Tile-based access to large PNG images. + */ + +/** + * "Global" context shared between images + */ +struct pt_ctx; + +/** + * Per-image state + */ +struct pt_image; + +enum pt_image_mode { + PT_IMG_READ = 0x01, + PT_IMG_WRITE = 0x02, +}; + + +int pt_ctx_new (struct pt_ctx **ctx_ptr); + +/** + * Open a new pt_image for use. + * + * @param img_ptr returned pt_image handle + * @param ctx global state to use + * @param path filesystem path to .png file + * @param mode combination of PT_IMG_* flags + */ +int pt_image_open (struct pt_image **img_ptr, struct pt_ctx *ctx, const char *png_path, int cache_mode); + + + +#endif diff -r 000000000000 -r cff7fac35cc2 src/shared/log.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/shared/log.c Sun Dec 27 22:01:17 2009 +0200 @@ -0,0 +1,144 @@ +#include "log.h" + +#include +#include +#include +#include +#include + +/** + * The global log level + */ +static enum log_level _log_level = LOG_LEVEL_DEFAULT; + +/** + * List of log level names + */ +const char *log_level_names[] = { + "DEBUG", + "INFO", + "WARN", + "ERROR", + "FATAL", + NULL +}; + +#define _LOG_LEVEL_NAME(ll) case LOG_ ## ll: return #ll; +const char *log_level_name (enum log_level level) +{ + switch (level) { + _LOG_LEVEL_NAME(DEBUG) + _LOG_LEVEL_NAME(INFO) + _LOG_LEVEL_NAME(WARN) + _LOG_LEVEL_NAME(ERROR) + _LOG_LEVEL_NAME(FATAL) + default: return "???"; + } +} +#undef _LOG_LEVEL_NAME + +void set_log_level (enum log_level level) +{ + // meep meep + _log_level = level; +} + +size_t str_append_fmt_va (char *buf_ptr, size_t *buf_size, const char *fmt, va_list args) +{ + int ret; + + if (*buf_size && (ret = vsnprintf(buf_ptr, *buf_size, fmt, args)) < 0) + return 0; + + if (ret > *buf_size) + *buf_size = 0; + + else + *buf_size -= ret; + + return ret; +} + +size_t str_append_fmt (char *buf_ptr, size_t *buf_size, const char *fmt, ...) +{ + va_list vargs; + size_t ret; + + va_start(vargs, fmt); + ret = str_append_fmt_va(buf_ptr, buf_size, fmt, vargs); + va_end(vargs); + + return ret; +} + +void log_output_tag_va (enum log_level level, const char *tag, const char *func, const char *user_fmt, va_list user_fmtargs, const char *log_fmt, va_list log_fmtargs) +{ + char buf[LOG_MSG_MAX], *buf_ptr = buf; + size_t buf_size = sizeof(buf); + + // filter out? + if (level < _log_level) + return; + + buf_ptr += str_append_fmt(buf_ptr, &buf_size, "[%5s] %20s : ", tag, func); + + // output the user data + if (user_fmt) + buf_ptr += str_append_fmt_va(buf_ptr, &buf_size, user_fmt, user_fmtargs); + + // output the suffix + if (log_fmt) + buf_ptr += str_append_fmt_va(buf_ptr, &buf_size, log_fmt, log_fmtargs); + + // display + // XXX: handle SIGINTR? + fprintf(stderr, "%s\n", buf); +} + +void log_output_tag (enum log_level level, const char *tag, const char *func, const char *user_fmt, va_list user_fmtargs, const char *log_fmt, ...) +{ + va_list vargs; + + va_start(vargs, log_fmt); + log_output_tag_va(level, tag, func, user_fmt, user_fmtargs, log_fmt, vargs); + va_end(vargs); +} + +void _log_msg (enum log_level level, const char *func, const char *format, ...) +{ + va_list vargs; + + // formatted output: no suffix + va_start(vargs, format); + log_output_tag(level, log_level_name(level), func, format, vargs, NULL); + va_end(vargs); +} + +void _log_msg_va2 (enum log_level level, const char *func, const char *fmt1, va_list fmtargs1, const char *fmt2, va_list fmtargs2) +{ + log_output_tag_va(level, log_level_name(level), func, fmt1, fmtargs1, fmt2, fmtargs2); +} + +void _log_errno (enum log_level level, const char *func, const char *format, ...) +{ + va_list vargs; + + // formatted output: suffix strerror() + va_start(vargs, format); + log_output_tag(level, log_level_name(level), func, format, vargs, ": %s", strerror(errno)); + va_end(vargs); +} + +void _log_exit (enum log_level level, int exit_code, const char *func, const char *format, ...) +{ + va_list vargs; + + // formatted output without any suffix + va_start(vargs, format); + log_output_tag(level, "EXIT", func, format, vargs, NULL); + va_end(vargs); + + // exit + exit(exit_code); +} + diff -r 000000000000 -r cff7fac35cc2 src/shared/log.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/shared/log.h Sun Dec 27 22:01:17 2009 +0200 @@ -0,0 +1,112 @@ +#ifndef SHARED_LOG_H +#define SHARED_LOG_H + +#include + +/** + * Log level definitions + * + * XXX: these names conflict with + */ +enum log_level { + LOG_DEBUG, + LOG_INFO, + LOG_WARN, + LOG_ERROR, + LOG_FATAL, +}; + +/** + * List of log_level values as strings, NULL-terminated + */ +extern const char *log_level_names[]; + +/** + * The default log level + */ +#define LOG_LEVEL_DEFAULT LOG_INFO + +/** + * Maximum length of a log message, including terminating NUL + */ +#define LOG_MSG_MAX 1024 + +/** + * Set the current log level to filter out messages below the given level + */ +void set_log_level (enum log_level level); +/** + * Internal logging func, meant for using custom level tags. This performs the filtering of log levels. + * + * Format the full output line, and pass it to the log_output_func. The line will be of the form: + * "[] : [ ]" + */ +void log_output_tag (enum log_level level, const char *tag, const char *func, const char *user_fmt, va_list user_fmtargs, const char *log_fmt, ...) + __attribute__ ((format (printf, 6, 7))); + +/** + * va_list version of log_output_tag + */ +void log_output_tag_va (enum log_level level, const char *tag, const char *func, const char *user_fmt, va_list user_fmtargs, const char *log_fmt, va_list log_fmtargs); + +/** + * Log a message with the given level + */ +#define log_msg(level, ...) _log_msg(level, __func__, __VA_ARGS__) +void _log_msg (enum log_level level, const char *func, const char *format, ...) + __attribute__ ((format (printf, 3, 4))); + +/** + * Log a message with the given level with the given format and varargs + */ +#define log_msg_va2(level, fmt1, vargs1, fmt2, vargs2) _log_msg_va(level, __func__, fmt1, vargs1, fmt2, vargs2) +void _log_msg_va2 (enum log_level level, const char *func, const char *fmt1, va_list fmtargs1, const char *fmt2, va_list fmtargs2); + + +/** + * Shorthand for log_msg + */ +#define log_debug(...) log_msg(LOG_DEBUG, __VA_ARGS__) +#define log_info(...) log_msg(LOG_INFO, __VA_ARGS__) +#define log_warn(...) log_msg(LOG_WARN, __VA_ARGS__) +#define log_error(...) log_msg(LOG_ERROR, __VA_ARGS__) +#define log_fatal(...) log_msg(LOG_FATAL, __VA_ARGS__) + +/** + * Log using errno. + */ +#define log_errno(...) _log_errno(LOG_ERROR, __func__, __VA_ARGS__) +#define log_warn_errno(...) _log_errno(LOG_WARN, __func__, __VA_ARGS__) +void _log_errno (enum log_level level, const char *func, const char *format, ...) + __attribute__ ((format (printf, 3, 4))); + +/** + * Log with an [EXIT] tag at given level, and then exit with given exit code + */ +#define log_exit(level, exit_code, ...) _log_exit(level, exit_code, __func__, __VA_ARGS__) +void _log_exit (enum log_level level, int exit_code, const char *func, const char *format, ...) + __attribute__ ((format (printf, 4, 5))) + __attribute__ ((noreturn)); + +// for abort() +#include + +/** + * log_fatal + exit failure + */ +#define FATAL(...) do { log_fatal(__VA_ARGS__); abort(); } while (0) + +/** + * log_perr + exit failure + */ +#define FATAL_ERRNO(...) do { _log_errno(LOG_FATAL, __func__, __VA_ARGS__); abort(); } while (0) + +/** + * Exit with given code, also logging a message at LOG_... with anĀ [EXIT] tag + */ +#define EXIT_INFO(exit_code, ...) log_exit(LOG_INFO, exit_code, __VA_ARGS__) +#define EXIT_WARN(exit_code, ...) log_exit(LOG_WARN, exit_code, __VA_ARGS__) +#define EXIT_ERROR(exit_code, ...) log_exit(LOG_ERROR, exit_code, __VA_ARGS__) +#define EXIT_FATAL(exit_code, ...) log_exit(LOG_FATAL, exit_code, __VA_ARGS__) + +#endif /* LOG_H */