%% options copyright owner = Dirk Krause copyright year = 2011-2014 license = bsd %% module #include "dk3all.h" #include "dkt.h" $!trace-include /** Job structure for dkt hex and dkt oct. */ typedef struct { dk3_app_t *app; /**< Application. */ dk3_option_set_t *opt; /**< Option set. */ dkChar const * const *msg; /**< Localized messages. */ dkChar const * const *kwnl; /**< Keywords, not localized. */ int exval; /**< Exit status code. */ int f_oct; /**< Flag: Run octal. */ int f_txt; /**< Flag: Show text. */ int f_add; /**< Flag: Show address. */ } DKT_HEX_J; /** Data for the option set. */ static dk3_option_t const dkt_hex_options[] = { { dkT('t'), dkT("text"), 0 }, { dkT('a'), dkT("addresses"), 0 } }; /** Number of options in the dkt_hex_options array. */ static size_t const dkt_hex_szoptions = sizeof(dkt_hex_options)/sizeof(dk3_option_t); /** Initialize job structure. @param j Structure to initialize. */ static void dkt_hex_job_init(DKT_HEX_J *j) { j->app = NULL; j->opt = NULL; j->msg = NULL; j->kwnl = NULL; j->exval = DKT_RESULT_ERR_UNSPECIFIC; j->f_oct = 0; j->f_txt = 0; j->f_add = 0; } /** Clean up job structure. @param j Job structure to clean up. */ static void dkt_hex_job_cleanup(DKT_HEX_J *j) { if(j->opt) { dk3opt_close(j->opt); } j->opt = NULL; } /** Process command line arguments. @param j Job structure. @return 1 on success, 0 on error. */ static int dkt_hex_process_arguments(DKT_HEX_J *j) { int back = 0; int xargc; dkChar const * const *xargv; xargc = dk3app_get_argc(j->app); xargv = dk3app_get_argv(j->app); xargc--; xargc--; xargv++; xargv++; j->opt = dk3opt_open_app( dkt_hex_options, dkt_hex_szoptions, dkT('\0'), NULL, xargc, xargv, j->app ); if(j->opt) { if(0 == dk3opt_get_error_code(j->opt)) { back = 1; if(dk3opt_is_set(j->opt, dkT('t'))) { j->f_txt = 1; } if(dk3opt_is_set(j->opt, dkT('a'))) { j->f_add = 1; } } else { j->exval = DKT_RESULT_ERR_OPTION; } } else { j->exval = DKT_RESULT_ERR_OPTION; } return back; } /** Copy string to another position, do not write finalizer 0x00. @param d Destination pointer. @param s Source pointer. */ static void dkt_hex_copy_chars(dkChar *d, dkChar const *s) { dkChar const *sptr = NULL; dkChar *dptr = NULL; dptr = d; sptr = s; while(*sptr) { *(dptr++) = *(sptr++); } } /** Process an opened file. @param j Job structure. @param fipo Input file, opened for binary reading. */ static void dkt_hex_process_fipo(DKT_HEX_J *j, FILE *fipo) { unsigned char buffer[4096]; /* Input buffer. */ dkChar addrb[32]; /* Address buffer. */ dkChar ol[256]; /* Output line. */ dkChar c; unsigned long addr = 0UL; /* Address. */ unsigned u = 0; size_t rb = 0; /* Bytes read into buffer. */ size_t i = 0; /* Current byte to process. */ size_t n = 16; /* Bytes per line. */ size_t m = 2; /* Length of each byte. */ size_t d = 0; /* Start of data. */ size_t t = 50; /* Start of text. */ size_t z = 48; /* End of line index. */ size_t pil = 0; /* Current byte in line. */ size_t p = 0; /* Text position in line. */ size_t k = 0; /* Used to reset output line. */ /* Calculate positions. */ #if VERSION_BEFORE_20140721 if(j->f_add) { d = 11; } #else if(j->f_add) { d = 2 * DK3_SIZEOF_UM + 3; } #endif if(j->f_oct) { m = 3; if((j->f_add) || (j->f_txt)) { n = 8; } } else { if((j->f_add) && (j->f_txt)) { n = 8; } } if(j->f_txt) { t = d + n * (m + 1) + 2; z = d + n * (m + 2) + 2; } else { z = d + n * (m + 1) - 1; } /* Process file contents. */ pil = 0; do { rb = dk3sf_fread_app(buffer, 1, sizeof(buffer), fipo, j->app); if(rb > 0) { for(i = 0; i < rb; i++) { /* Get character to process. */ u = (unsigned)(buffer[i]); u &= 0x00FFU; /* Initialize line if necessary. */ if(pil == 0) { for(k = 0; k < DK3_SIZEOF(ol,dkChar); k++) { ol[k] = dkT(' '); } ol[DK3_SIZEOF(ol,dkChar) - 1] = dkT('\0'); if(j->f_add) { #if VERSION_BEFORE_20140716 dk3sf_sprintf3(addrb, dkT("%08lx"), addr); #else dk3ma_um_to_hex_string( addrb, DK3_SIZEOF(addrb,dkChar), (dk3_um_t)addr, 1 ); #endif dkt_hex_copy_chars(ol, addrb); } } /* Insert data into line. */ if(j->f_oct) { dk3sf_sprintf3(addrb, dkT("%03o"), u); } else { dk3sf_sprintf3(addrb, dkT("%02x"), u); } p = d + pil * (m + 1); dkt_hex_copy_chars(&(ol[p]), addrb); /* Write text. */ if(j->f_txt) { c = dkT('.'); if(isascii(buffer[i])) { if(isprint(buffer[i])) { c = (dkChar)(buffer[i]); } } ol[t + pil] = c; } /* Increase position, flush line if necessary. */ pil++; if(pil >= n) { ol[z] = dkT('\0'); dk3sf_fputs(ol, stdout); dk3sf_fputc(dkT('\n'), stdout); pil = 0; addr += (unsigned long)n; } } } } while(rb > 0); if(pil) { /* Write final line. */ ol[z] = dkT('\0'); dk3sf_fputs(ol, stdout); dk3sf_fputc(dkT('\n'), stdout); } } /** Process one file name. @param j Job structure. @param fn File name. @param f_showfn Flag: Show file name. */ static void dkt_hex_process_filename(DKT_HEX_J *j, dkChar const *fn, int f_showfn) { FILE *fipo = NULL; /* Input file. */ fipo = dk3sf_fopen_app(fn, dk3app_not_localized(36), j->app); if(fipo) { dk3sf_initialize_stdout(); if(f_showfn) { dk3sf_fputs(fn, stdout); dk3sf_fputc(dkT('\n'), stdout); } dkt_hex_process_fipo(j, fipo); fclose(fipo); } else { /* ERROR: Failed to open file! */ j->exval = DKT_RESULT_ERR_FILENAME; } } /** Show file hexadecimally. @param j job structure. */ static void dkt_hex_run(DKT_HEX_J *j) { int found = 0; /* Flag: At least one file name found. */ int nfn = 0; /* Number of file names. */ int i = 0; /* Index of current file name. */ dkChar const *arg = NULL; /* Current file name. */ dkChar const *en = NULL; /* File name from expander. */ dk3_dir_t *fne = NULL; /* File name expander. */ #if DK3_ON_WINDOWS int oldmode = _O_TEXT; /* Old stdin mode. */ #endif dkChar bu[DK3_MAX_PATH]; /* Buffer for file name. */ nfn = dk3opt_get_num_args(j->opt); if(nfn > 0) { /* Process file names specified on command line. */ for(i = 0; i < nfn; i++) { arg = dk3opt_get_arg(j->opt, i); if(arg) { if(dk3str_len(arg) < DK3_SIZEOF(bu,dkChar)) { dk3str_cpy_not_overlapped(bu, arg); dk3str_correct_filename(bu); if(dk3sf_must_expand(bu)) { fne = dk3dir_fne_open_app(bu, j->app); if(fne) { while(dk3dir_get_next_file(fne)) { en = dk3dir_get_fullname(fne); if(en) { dkt_hex_process_filename(j, en, 1); } else { /* BUG */ } } dk3dir_close(fne); if(!found) { /* ERROR: No such file! */ dk3app_log_i3(j->app, DK3_LL_ERROR, 215, 216, arg); } } else { /* ERROR: File name expander */ j->exval = DKT_RESULT_ERR_MEMORY; } } else { dkt_hex_process_filename(j, bu, ((nfn > 1) ? 1 : 0)); } } else { /* ERROR: File name too long! */ dk3app_log_i3(j->app, DK3_LL_ERROR, 65, 66, arg); j->exval = DKT_RESULT_ERR_FILENAME; } } else { /* BUG */ } } } else { /* Process standard input. */ #if DK3_ON_WINDOWS oldmode = _setmode(_fileno(stdin), _O_BINARY); #endif dkt_hex_process_fipo(j, stdin); #if DK3_ON_WINDOWS _setmode(_fileno(stdin), oldmode); #endif } } int dkt_hex( dk3_app_t *app, dkChar const *sn, dkChar const * const *msg, dkChar const * const *kwnl, int f_oct ) { int back = DKT_RESULT_ERR_UNSPECIFIC; DKT_HEX_J j; $? "+ dkt_hex" dkt_hex_job_init(&j); j.app = app; j.msg = msg; j.kwnl = kwnl; j.f_oct = f_oct; if(dkt_hex_process_arguments(&j)) { j.exval = DKT_RESULT_OK; dkt_hex_run(&j); } back = j.exval; dkt_hex_job_cleanup(&j); $? "- dkt_hex %d", back return back; } /* vim: set ai sw=2 : */