/*****************************************************************************\ * Copyright (c) 2004 Mark Aylett * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * * "Software"), to deal in the Software without restriction, including * * without limitation the rights to use, copy, modify, merge, publish, * * distribute, sublicense, and/or sell copies of the Software, and to permit * * persons to whom the Software is furnished to do so, subject to the * * following conditions: * * * * The above copyright notice and this permission notice shall be included * * in all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * * USE OR OTHER DEALINGS IN THE SOFTWARE. * \*****************************************************************************/ static const char rcsid[] = "$Id: mar_main_c.c,v 1.8 2004/12/14 13:09:23 marayl Exp $"; #include "mar_debug_c.h" #include "mar_getopt_c.h" #include "mar_util_c.h" #include #include #define MAR_CREATEOPT 0x01 #define MAR_FORCEOPT 0x02 #define MAR_READOPT 0x04 #define MAR_STDINOPT 0x08 #define MAR_WRITEOPT 0x10 #define MAR_OPTIONS "fhi:klm:rs:tu:x:z" #define MAR_FORCETEXT "no prompt for confirmation" #define MAR_HELPTEXT "display this help, then exit" #define MAR_INSERTTEXT "insert user data from file" #define MAR_KEYSTEXT "list all meta data keys" #define MAR_LENGTHTEXT "print length of user data" #define MAR_LISTTEXT "list all meta data pairs" #define MAR_METATEXT "print meta data by key" #define MAR_REMOVETEXT "remove all meta data pairs" #define MAR_SETTEXT "set meta data from source" #define MAR_UNSETTEXT "unset meta data by key" #define MAR_EXTRACTTEXT "extract user data to file" #define MAR_ZEROTEXT "zero truncate user data" #define MAR_FORCE (MAR_FORCEOPT & options) static unsigned int options = 0; static int mar_fileset(mar_t mar, const char* filename) { FILE* stream; if (0 == strcmp(filename, "-")) { if (-1 == mar_streamset_(mar, stdin)) return -1; } else { if (!(stream = fopen(filename, "r"))) return -1; if (-1 == mar_streamset_(mar, stream)) goto fail; if (0 != fclose(stream)) return -1; } return 0; fail: fclose(stream); return -1; } static int mar_doextract(mar_t mar, const char* filename) { if (0 == strcmp(filename, "-")) { const void* data; size_t size; if (!(data = mar_user(mar, &size))) return -1; if (size != fwrite(data, 1, size, stdout)) return -1; } else { if (-1 == mar_extract(mar, filename)) return -1; } return 0; } static void mar_dohelp(void) { printf("Meta Archive Utility\n" "\nUsage:\n" " mar option... archivename\n" "\nOptions:\n" " -f " MAR_FORCETEXT "\n" " -h " MAR_HELPTEXT "\n" " -i filename " MAR_INSERTTEXT "\n" " -k " MAR_KEYSTEXT "\n" " -l " MAR_LENGTHTEXT "\n" " -m key " MAR_METATEXT "\n" " -r " MAR_REMOVETEXT "\n" " -s source " MAR_SETTEXT "\n" " -t " MAR_LISTTEXT "\n" " -u key " MAR_UNSETTEXT "\n" " -x filename " MAR_EXTRACTTEXT "\n" " -z " MAR_ZEROTEXT "\n" "\nReport bugs to \n"); } static int mar_doinsert(mar_t mar, const char* filename) { if (0 == strcmp(filename, "-")) { if (-1 == mar_insertstream_(mar, stdin)) return -1; } else { if (-1 == mar_insert(mar, filename)) return -1; } return 0; } static int mar_dokeys(mar_t mar) { int i; for (i = 0; ; ++i) { mar_key_t key; if (-1 == mar_tokey(mar, key, i)) return -1; if ('\0' == *key) break; printf("%s\n", key); } if (EOF == fflush(stdout)) return -1; return 0; } static int mar_dolength(mar_t mar) { size_t size; if (-1 == mar_usersize(mar, &size)) return -1; printf("%d\n", size); return 0; } static int mar_dolist(mar_t mar) { int i; for (i = 0; ; ++i) { mar_pair_t pair; if (-1 == mar_metapair(mar, &pair, i)) return -1; if (!pair.data_) break; printf("%s=", pair.key_); if (-1 == mar_writedata_(stdout, pair.data_, pair.size_)) return -1; } if (EOF == fflush(stdout)) return -1; return 0; } static int mar_dometa(mar_t mar, const char* name) { const void* data; size_t size; if (!(data = mar_metabykey(mar, name, &size))) return -1; if (-1 == mar_writedata_(stdout, data, size)) return -1; if (EOF == fflush(stdout)) return -1; return 0; } static int mar_doremove(mar_t mar) { if (!MAR_FORCE && !mar_confirm_(MAR_REMOVETEXT)) return 0; return mar_removepairs(mar); } static int mar_doset(mar_t mar, const char* source) { mar_pair_t pair; if (-1 == mar_atopair_(&pair, source)) return mar_fileset(mar, source); return mar_setpair(mar, &pair, NULL); } static int mar_dounset(mar_t mar, const char* name) { if (!MAR_FORCE && !mar_confirm_(MAR_UNSETTEXT)) return 0; return mar_unsetbykey(mar, name, NULL); } static int mar_dozero(mar_t mar) { if (!MAR_FORCE && !mar_confirm_(MAR_ZEROTEXT)) return 0; return mar_truncate(mar, 0); } #if defined(MAR_STATIC) static void mar_exit(void) { MAR_DUMPLEAKS(); } #endif /* MAR_STATIC */ static void mar_perror(const char* s) { fprintf(stderr, "%s: %s\n", s, strerror(mar_errno())); } static int mar_run(int argc, char* argv[], const char* archivename) { int flags = 0; mode_t mode = 0; mar_t mar; char ch; switch (options & (MAR_READOPT | MAR_WRITEOPT)) { case MAR_READOPT: flags = MAR_RDONLY; break; case MAR_WRITEOPT: flags = MAR_WRONLY; break; case MAR_READOPT | MAR_WRITEOPT: flags = MAR_RDWR; break; } if (options & MAR_CREATEOPT) { flags |= MAR_CREAT; mode = 0666; } if (!(mar = mar_open(archivename, flags, mode))) { mar_perror("Failed to create archive"); return -1; } while (-1 != (ch = mar_getopt(argc, argv, MAR_OPTIONS))) switch (ch) { case 'f': break; case 'i': if (-1 == mar_doinsert(mar, mar_optarg)) { mar_perror("Failed to " MAR_INSERTTEXT); goto fail; } break; case 'k': if (-1 == mar_dokeys(mar)) { mar_perror("Failed to " MAR_KEYSTEXT); goto fail; } break; case 'l': if (-1 == mar_dolength(mar)) { mar_perror("Failed to " MAR_LENGTHTEXT); goto fail; } break; case 'm': if (-1 == mar_dometa(mar, mar_optarg)) { mar_perror("Failed to " MAR_METATEXT); goto fail; } break; case 'r': if (-1 == mar_doremove(mar)) { mar_perror("Failed to " MAR_REMOVETEXT); goto fail; } break; case 's': if (-1 == mar_doset(mar, mar_optarg)) { mar_perror("Failed to " MAR_SETTEXT); goto fail; } break; case 't': if (-1 == mar_dolist(mar)) { mar_perror("Failed to " MAR_LISTTEXT); goto fail; } break; case 'u': if (-1 == mar_dounset(mar, mar_optarg)) { mar_perror("Failed to " MAR_UNSETTEXT); goto fail; } break; case 'x': if (-1 == mar_doextract(mar, mar_optarg)) { mar_perror("Failed to " MAR_EXTRACTTEXT); goto fail; } break; case 'z': if (-1 == mar_dozero(mar)) { mar_perror("Failed to " MAR_ZEROTEXT); goto fail; } break; case 'h': case '?': default: fprintf(stderr, "Unexpected option '-%c'\n", mar_optopt); goto fail; } return mar_release(mar); fail: mar_release(mar); return -1; } int main(int argc, char* argv[]) { char ch; const char* archivename = NULL; mar_opterr = 0; #if defined(MAR_STATIC) MAR_INITLEAKDUMP(); if (-1 == atexit(mar_exit)) { mar_perror("Failed to install exit handler"); goto fail; } #endif /* MAR_STATIC */ while (-1 != (ch = mar_getopt(argc, argv, MAR_OPTIONS))) switch (ch) { case 'i': case 's': if (0 == strcmp(mar_optarg, "-")) { if (options & MAR_STDINOPT) { fprintf(stderr, "Multiple use of stdin"); goto info; } options |= MAR_STDINOPT; } options |= (MAR_CREATEOPT | MAR_WRITEOPT); break; case 'f': options |= MAR_FORCEOPT; break; case 'h': mar_dohelp(); return 0; case 'k': case 'l': case 'm': case 't': case 'x': options |= MAR_READOPT; break; case 'r': case 'u': case 'z': options |= MAR_WRITEOPT; break; case '?': default: fprintf(stderr, "Unknown option `-%c'", mar_optopt); goto info; } if (mar_optind < (argc - 1)) { fprintf(stderr, "Too many arguments"); goto info; } if (mar_optind == argc) { fprintf(stderr, "Archive not specified"); goto info; } archivename = argv[mar_optind]; mar_optind = 0; if (-1 == mar_run(argc, argv, archivename)) goto fail; return 0; info: fprintf(stderr, ": Try `mar -h' for more information\n"); fail: return 1; }