%% options copyright owner = Dirk Krause copyright year = 2011-2013 license = bsd %% module #include "dk3all.h" #include "dkt.h" $!trace-include /** Job structure for tape numbers. */ typedef struct { dk3_app_t *app; /**< Application structure. */ dkChar const * const *msg; /**< Localized message texts. */ dkChar const * const *kwnl; /**< Keywords, not localized. */ dkChar const *filename; /**< File name for tape file. */ dk3_option_set_t *opt; /**< Option set. */ dkChar **line_texts; /**< 30 texts from the 10 lines. */ dkChar *b01; /**< Line for tape 1. */ dkChar *b02; /**< Line for tape 2. */ dkChar *b03; /**< Line for tape 3. */ dkChar *b04; /**< Line for tape 4. */ dkChar *b05; /**< Line for tape 5. */ dkChar *b06; /**< Line for tape 6. */ dkChar *b07; /**< Line for tape 7. */ dkChar *b08; /**< Line for tape 8. */ dkChar *b09; /**< Line for tape 9. */ dkChar *b10; /**< Line for tape 10. */ unsigned long *tapeuses; /**< 10 numbers (one for each tape). */ size_t bsz; /**< Line size. */ int lineno; /**< Current line number. */ int f_plain; /**< Flag: Plain text output. */ int f_confirm; /**< Flag: Confirm current tape. */ int f_reset; /**< Flag: Period completed. */ int exval; /**< Exit status code. */ int f_old_input; /**< Input file was old style. */ int enc_f; /**< Input file encoding. */ unsigned tape_to_use; /**< Current tape number. */ unsigned tape_day; /**< Current day in period. */ } DKT_TAPE_J; /** Job structure for dkt tapeset. */ typedef struct { dk3_app_t *app; /**< Application structure. */ dkChar const * const *msg; /**< Localized message texts. */ dkChar const * const *kwnl; /**< Keywords, not localized. */ dkChar const *filename; /**< File name. */ dkChar **names; /**< Pointers into the splitted line. */ dkChar *nb; /**< Tape set names line buffer. */ dk3_option_set_t *opt; /**< Options. */ size_t nbs; /**< Size of \a nb. */ size_t nnames; /**< Pointers in \a names. */ size_t unames; /**< No of pointer used in \a names. */ int enc_f; /**< File encoding. */ int f_plain; /**< Flag: Plain output. */ int f_confirm; /**< Flag: Confirm tape set. */ int exval; /**< Exit status code. */ int lineno; /**< Current line number. */ unsigned day; /**< Current day. */ } DKT_TS_J; /** Options used by dkt ls. */ static dk3_option_t const dkt_tape_options[] = { { dkT('p'), dkT("plain"), 0 }, /* Plain input. */ { dkT('a'), dkT("ascii"), 0 }, /* Plain output. */ { dkT('R'), dkT("reset"), 0 }, /* Reset all options. */ { dkT('i'), dkT("input-encoding"), 1 } /* Specify input encoding. */ }; /** Number of options in the dkt_tape_options array. */ static size_t const dkt_tape_szoptions = sizeof(dkt_tape_options)/sizeof(dk3_option_t); /** Configuration file key names. */ static dkChar const * const dkt_tape_long_options[] = { dkT("reset"), dkT("file-encoding"), }; /** Commands for dkt tape. */ dkChar const * const dkt_tape_commands[] = { dkT("get"), dkT("confirm"), NULL }; /** Tape numbers in order of usage. This implements the 10 tape rotation scheme. At every time we will have backups of different ages. During 200 backups each of the 10 tapes is used 20 times. */ static unsigned const dkt_tape_numbers[] = { 1, 2, 3, 4, 5, 1, 2, 3, 4, 6, 1, 2, 3, 4, 7, 1, 2, 3, 4, 8, 2, 3, 4, 5, 6, 2, 3, 4, 5, 7, 2, 3, 4, 5, 8, 2, 3, 4, 5, 9, 3, 4, 5, 6, 7, 3, 4, 5, 6, 8, 3, 4, 5, 6, 9, 3, 4, 5, 6, 10, 4, 5, 6, 7, 8, 4, 5, 6, 7, 9, 4, 5, 6, 7, 10, 4, 5, 6, 7, 1, 5, 6, 7, 8, 9, 5, 6, 7, 8, 10, 5, 6, 7, 8, 1, 5, 6, 7, 8, 2, 6, 7, 8, 9, 10, 6, 7, 8, 9, 1, 6, 7, 8, 9, 2, 6, 7, 8, 9, 3, 7, 8, 9, 10, 1, 7, 8, 9, 10, 2, 7, 8, 9, 10, 3, 7, 8, 9, 10, 4, 8, 9, 10, 1, 2, 8, 9, 10, 1, 3, 8, 9, 10, 1, 4, 8, 9, 10, 1, 5, 9, 10, 1, 2, 3, 9, 10, 1, 2, 4, 9, 10, 1, 2, 5, 9, 10, 1, 2, 6, 10, 1, 2, 3, 4, 10, 1, 2, 3, 5, 10, 1, 2, 3, 6, 10, 1, 2, 3, 7 }; /** Initialize job structure. @param j Job structure to initialize. */ static void dkt_tape_job_init(DKT_TAPE_J *j) { j->app = NULL; j->msg = NULL; j->kwnl = NULL; j->filename = NULL; j->opt = NULL; j->line_texts = NULL; j->b01 = j->b02 = j->b03 = j->b04 = j->b05 = NULL; j->b06 = j->b07 = j->b08 = j->b09 = j->b10 = NULL; j->tapeuses = NULL; j->bsz = 0; j->lineno = 0; j->f_plain = 0; j->f_confirm = 0; j->exval = DKT_RESULT_ERR_UNSPECIFIC; j->f_old_input = 0; j->enc_f = 0; j->tape_to_use = 0; j->tape_day = 0; j->f_reset = 0; } /** Clean up job structure after use. @param j Job structure to clean. */ static void dkt_tape_job_cleanup(DKT_TAPE_J *j) { if(j->opt) { dk3opt_close(j->opt); } j->opt = NULL; } /** Reset job structure for -R or --reset. @param j Job structure. */ static void dkt_tape_job_reset(DKT_TAPE_J *j) { j->enc_f = dk3app_get_default_file_encoding(j->app); j->f_plain = 0; } /** Process the command line arguments and options, find name of tape file. @param j Job structure. @return 1 on success, 0 on error. */ static int dkt_tape_process_arguments(DKT_TAPE_J *j) { int back = 0; int xargc = 0; /* Number of cmd line args. */ int res = 0; /* Line processing result. */ dkChar const * const *xargv = NULL; /* Cmd line args array. */ dkChar const *arg = NULL; /* Current argument to process. */ xargc = dk3app_get_argc(j->app); xargv = dk3app_get_argv(j->app); xargv++; xargv++; xargc--; xargc--; j->opt = dk3opt_open_app( dkt_tape_options, dkt_tape_szoptions, 0x00, NULL, xargc, xargv, j->app ); if(j->opt) { if(0 == dk3opt_get_error_code(j->opt)) { /* Process options. */ if(dk3opt_is_set(j->opt, dkT('R'))) { dkt_tape_job_reset(j); } if(dk3opt_is_set(j->opt, dkT('a'))) { j->f_plain = 1; } if(dk3opt_is_set(j->opt, dkT('p'))) { j->enc_f = DK3_FILE_ENCODING_ASCII; if(dk3opt_is_set(j->opt, dkT('i'))) { back = 0; /* ERROR: -i and -p are exclusive! */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 0); } } else { if(dk3opt_is_set(j->opt, dkT('i'))) { arg = dk3opt_get_short_arg(j->opt, dkT('i')); if(arg) { res = dkt_tool_set_encoding( j->app, &(j->enc_f), arg, dk3app_get_input_file_encoding(j->app) ); if(!(res)) { back = 0; } } else { back = 0; } } } /* Find command and file name. */ if(dk3opt_get_num_args(j->opt) > 1) { switch(dk3str_array_index(dkt_tape_commands,dk3opt_get_arg(j->opt,0),0)) { case 0: { back = 1; } break; case 1: { back = 1; j->f_confirm = 1; } break; default: { /* ERROR: Unknown command... */ dk3app_log_i3( j->app, DK3_LL_ERROR, 139, 140, dk3opt_get_arg(j->opt, 0) ); j->exval = DKT_RESULT_ERR_OPTION; } break; } if(back) { back = 0; j->filename = dk3opt_get_arg(j->opt, 1); if(j->filename) { back = 1; } if(back) { if(dk3opt_get_num_args(j->opt) > 2) { /* Warning: Ignoring argument... */ dk3app_log_i3( j->app, DK3_LL_ERROR, 137, 138, dk3opt_get_arg(j->opt, 2) ); } } else { j->exval = DKT_RESULT_ERR_OPTION; } } } else { j->exval = DKT_RESULT_ERR_OPTION; } } else { j->exval = DKT_RESULT_ERR_OPTION; } } else { j->exval = DKT_RESULT_ERR_OPTION; } return back; } /** Process one date/time/number line from tape file. @param j Job structure. @param il Input line. @param lineno Line number. @param buffer Destination buffer to store line. @return 1 on success, -1 on error. */ static int dkt_tape_save_line( DKT_TAPE_J *j, dkChar *il, size_t lineno, dkChar *buffer ) { int back = -1; dkChar *p1 = NULL; /* Date. */ dkChar *p2 = NULL; /* Time. */ dkChar *p3 = NULL; /* Number of uses as text. */ unsigned long u = 0UL; /* Number of uses. */ $? "+ dkt_tape_save_line %u", (unsigned)lineno if(dk3str_len(il) < j->bsz) { dk3str_cpy(buffer, il); p1 = dk3str_start(buffer, NULL); if(p1) { $? ". text (date) found" p2 = dk3str_chr(p1, ((j->f_old_input) ? dkT('_') : dkT(' '))); if(p2) { $? ". time found" *(p2++) = dkT('\0'); p2 = dk3str_start(p2, NULL); if(p2) { $? ". number found" p3 = dk3str_next(p2, NULL); if(p3) { (j->line_texts)[3 * lineno ] = p1; (j->line_texts)[3 * lineno + 1] = p2; (j->line_texts)[3 * lineno + 2] = p3; if(dk3sf_sscanf3(p3, dkT("%lu"), &u) == 1) {$? ". number ok" back = 1; (j->tapeuses)[lineno] = u; } else { $? "! number text not numeric" } } } else { $? "! no number found" } } else { $? "! no time found" if(j->f_old_input) { p2 = dk3str_next(p1, NULL); if(p2) { if(dk3str_cmp(p1, (j->kwnl)[6]) == 0) { if(dk3str_cmp(p2, (j->kwnl)[7]) == 0) { back = 1; } } } } } } else { $? "! not text found" } } $? "- dkt_tape_save_line %d", back return back; } /** Process one line from tape file. @param obj Job structure. @param il Input line. @return 1 on success, -1 on error. */ static int dkt_tape_line_handler(void *obj, dkChar *il) { int back = -1; DKT_TAPE_J *j = NULL; /* Job structure. */ dkChar *p1 = NULL; /* Start of line. */ dkChar *p2 = NULL; /* Flag: Confirmed. */ unsigned day = 0; /* Day. */ unsigned conf = 0; /* Flag: Confirmed. */ j = (DKT_TAPE_J *)obj; $? "+ dkt_tape_line_handler %u", (unsigned)(j->lineno) dk3str_delnl(il); switch(j->lineno) { case 0: { p1 = dk3str_start(il, NULL); if(p1) { $? ". text ok" p2 = dk3str_next(p1, NULL); if(p2) { $? ". second text ok" j->f_old_input = 1; } if(dk3sf_sscanf3(p1, dkT("%u"), &day) == 1) { $? ". number 1 ok" back = 1; if(p2) { if(dk3sf_sscanf3(p2, dkT("%u"), &conf) == 1) { $? ". number 2 ok" if(conf) { day++; } } else { $? "! number 2" } } j->tape_day = day; $? ". tape day = %u", day } else { $? "! number 1" } } else { $? ". no text" back = -1; } } break; case 1: { back = dkt_tape_save_line(j, il, 0, j->b01); } break; case 2: { back = dkt_tape_save_line(j, il, 1, j->b02); } break; case 3: { back = dkt_tape_save_line(j, il, 2, j->b03); } break; case 4: { back = dkt_tape_save_line(j, il, 3, j->b04); } break; case 5: { back = dkt_tape_save_line(j, il, 4, j->b05); } break; case 6: { back = dkt_tape_save_line(j, il, 5, j->b06); } break; case 7: { back = dkt_tape_save_line(j, il, 6, j->b07); } break; case 8: { back = dkt_tape_save_line(j, il, 7, j->b08); } break; case 9: { back = dkt_tape_save_line(j, il, 8, j->b09); } break; case 10: { back = dkt_tape_save_line(j, il, 9, j->b10); } break; } j->lineno += 1; if(back == -1) { /* Syntax error! */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 27); j->exval = DKT_RESULT_ERR_INPUT; } $? "- dkt_tape_line_handler %d", back return back; } /** Read tape file. @param j Job structure. @return 1 on success, 0 on error. */ static int dkt_tape_read_file(DKT_TAPE_J *j) { int back = 0; FILE *fipo = NULL; /* Input file. */ dkChar bu[256]; /* Buffer for input lines. */ $? "+ dkt_tape_read_file" bu[0] = dkT('\0'); fipo = dk3sf_fopen_app(j->filename, dk3app_not_localized(22), NULL); if(fipo) { back = dk3stream_process_file_lines_app( (void *)j, dkt_tape_line_handler, fipo, j->filename, bu, DK3_SIZEOF(bu,dkChar), dk3app_get_encoding(j->app), j->enc_f, j->app ); if(back == 1) { if(j->lineno != 11) { back = -1; /* Syntax error! */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 27); j->exval = DKT_RESULT_ERR_INPUT; } } fclose(fipo); } else { back = 1; } $? "- dkt_tape_read_file %d", back return back; } /** Write updated tape file. @param j Job structure. */ static void dkt_tape_write_file(DKT_TAPE_J *j) { FILE *fipo = NULL; /* Output file. */ dkChar bu[256]; /* Buffer for numeric value. */ dkChar const *p1 = NULL; /* Date. */ dkChar const *p2 = NULL; /* Time. */ size_t i = 0; /* Current tape line number. */ dk3_time_t timer; /* Current time. */ if(j->exval == DKT_RESULT_OK) { fipo = dk3sf_fopen_app(j->filename ,dk3app_not_localized(24), j->app); if(fipo) { if(dk3sf_sprintf3(bu, dkT("%u"), j->tape_day)) { /* Write current tape day. */ dk3sf_fputs(bu, fipo); dk3sf_fputc(dkT('\n'), fipo); /* Write lines with date, time, number of uses for each of the 10 tapes. */ for(i = 0; i < 10; i++) { p1 = (j->line_texts)[3 * i ]; p2 = (j->line_texts)[3 * i + 1]; if(!(p1)) { p1 = (j->kwnl)[8]; } if(!(p2)) { p2 = (j->kwnl)[9]; } if((i != (j->tape_to_use - 1)) || (!(j->f_confirm))) { /* Line content does not need modification. */ dk3sf_fputs(p1, fipo); dk3sf_fputc(dkT(' '), fipo); dk3sf_fputs(p2, fipo); } else { /* Line content probably modified. */ if(j->f_reset) { /* No modification if we just completed a period. */ dk3sf_fputs(p1, fipo); dk3sf_fputc(dkT(' '), fipo); dk3sf_fputs(p2, fipo); } else { /* Line content modified during tape confirmation. */ if(dk3sf_time(&timer)) { if(dk3sf_time_convert_app(bu,DK3_SIZEOF(bu,dkChar),&timer,j->app)) { dk3sf_fputs(bu, fipo); } else { dk3sf_fputs(p1, fipo); dk3sf_fputc(dkT(' '), fipo); dk3sf_fputs(p2, fipo); j->exval = DKT_RESULT_ERR_UNSPECIFIC; } } else { /* ERROR: Failed to obtain current time! */ j->exval = DKT_RESULT_ERR_UNSPECIFIC; dk3app_log_i1(j->app, DK3_LL_ERROR, 80); } } } /* The end of line is the number how often the tape was used. */ dk3sf_fputc(dkT(' '), fipo); if(dk3sf_sprintf3(bu, dkT("%lu"), (j->tapeuses)[i])) { dk3sf_fputs(bu, fipo); } else { j->exval = DKT_RESULT_ERR_UNSPECIFIC; /* ERROR: Conversion failed! */ } dk3sf_fputc(dkT('\n'), fipo); } } else { j->exval = DKT_RESULT_ERR_UNSPECIFIC; } if(!dk3sf_fclose_fn_app(fipo, j->filename, j->app)) { j->exval = DKT_RESULT_ERR_UNSPECIFIC; } } else { j->exval = DKT_RESULT_ERR_FILENAME; } } } /** Backup period completed. The user has to change the media set (10 new backup media). We write a backup of the tape file and initialize things for the next period. @param j Job structure. */ static void dkt_tape_period_completed(DKT_TAPE_J *j) { dkChar bu[DK3_MAX_PATH]; /* File name of backup file. */ dkChar const *oldfn = NULL; /* File name from command line. */ size_t i = 0; /* Traverse the tapes. */ if(dk3str_len(j->filename) < DK3_SIZEOF(bu,dkChar)) { dk3str_cpy(bu, j->filename); if((dk3str_len(j->filename) + dk3str_len((j->kwnl)[10])) < DK3_SIZEOF(bu,dkChar) ) { dk3str_cat(bu, (j->kwnl)[10]); oldfn = j->filename; j->filename = bu; dkt_tape_write_file(j); j->filename = oldfn; j->f_reset = 1; for(i = 0; i < 30; i++) { (j->line_texts)[i] = NULL; } for(i = 0; i < 10; i++) { (j->tapeuses)[i] = 0UL; } } else { /* ERROR: File name too long */ dk3app_log_i3(j->app, DK3_LL_ERROR, 65, 66, j->filename); j->exval = DKT_RESULT_ERR_FILENAME; } } else { /* ERROR: File name too long */ dk3app_log_i3(j->app, DK3_LL_ERROR, 65, 66, j->filename); j->exval = DKT_RESULT_ERR_FILENAME; } } /** Run one tape operation. @param j Job structure. */ static void dkt_tape_run(DKT_TAPE_J *j) { dkChar bu[32]; $? "+ dkt_tape_run" if(dkt_tape_read_file(j)) { $? ". read success" if(j->f_confirm) { /* Tape number to confirm. */ j->tape_to_use = dkt_tape_numbers[(j->tape_day) % 200]; (j->tapeuses)[j->tape_to_use - 1] += 1UL; j->tape_day += 1; if(j->tape_day >= 200) { j->tape_day = 0; dkt_tape_period_completed(j); /* NOTICE: Backup period completed, Change tape set. */ dk3app_log_1(j->app, DK3_LL_INFO, j->msg, 28); } } else { /* Tape number to print. */ j->tape_to_use = dkt_tape_numbers[(j->tape_day) % 200]; if(j->f_plain) { printf("%u\n", j->tape_to_use); } else { if(dk3sf_sprintf3(bu, dkT("%u"), j->tape_to_use)) { dk3sf_initialize_stdout(); dk3sf_fputs(bu, stdout); dk3sf_fputc(dkT('\n'), stdout); } } } dkt_tape_write_file(j); } $? "- dkt_tape_run" } /** Process one line from configuration file. @param vj Job structure. @param key Key found in line. @param val Value found in line, may be NULL. @return 1 on success, 0 on error. */ static int dkt_tape_conf_line(void *vj, dkChar const *key, dkChar const *val) { int back = 0; DKT_TAPE_J *j; j = (DKT_TAPE_J *)vj; $? "+ dkt_tape_conf_fline" switch(dk3str_array_index(dkt_tape_long_options, key, 0)) { case 0: { /* reset */ dkt_tape_job_reset(j); back = 1; } break; case 1: { /* file encoding = ... */ if(val) { back = dkt_tool_set_encoding( j->app, &(j->enc_f), val, dk3app_get_input_file_encoding(j->app) ); } } break; } $? "- dkt_tape_conf_fline %d", back return back; } int dkt_tape( dk3_app_t *app, dkChar const *sn, dkChar const * const *msg, dkChar const * const *kwnl ) { int back; DKT_TAPE_J j; dkChar b01[64]; /* Buffer for tape lines. */ dkChar b02[DK3_SIZEOF(b01,dkChar)]; dkChar b03[DK3_SIZEOF(b01,dkChar)]; dkChar b04[DK3_SIZEOF(b01,dkChar)]; dkChar b05[DK3_SIZEOF(b01,dkChar)]; dkChar b06[DK3_SIZEOF(b01,dkChar)]; dkChar b07[DK3_SIZEOF(b01,dkChar)]; dkChar b08[DK3_SIZEOF(b01,dkChar)]; dkChar b09[DK3_SIZEOF(b01,dkChar)]; dkChar b10[DK3_SIZEOF(b01,dkChar)]; dkChar *line_texts[30]; /* Tape lines splitted. */ unsigned long tu[10]; /* Use numbers for tapes. */ size_t i = 0; /* Used as index in init. */ /* Initialize job structure. */ dkt_tape_job_init(&j); j.app = app; j.msg = msg; j.kwnl = kwnl; j.enc_f = dk3app_get_input_file_encoding(app); j.b01 = b01; j.b02 = b02; j.b03 = b03; j.b04 = b04; j.b05 = b05; j.b06 = b06; j.b07 = b07; j.b08 = b08; j.b09 = b09; j.b10 = b10; /* Initialize pointers and numbers. */ b01[0] = b02[0] = b03[0] = b04[0] = b05[0] = b06[0] = b07[0] = b08[0] = b09[0] = b10[0] = dkT('\0'); j.line_texts = line_texts; j.tapeuses = tu; for(i = 0; i < 10; i++) { tu[i] = 0; } for(i = 0; i < 30; i++) { line_texts[i] = NULL; } j.bsz = DK3_SIZEOF(b01,dkChar); /* Process configuration file(s). */ dkt_tool_read_conf(app, sn, (void *)(&j), dkt_tape_conf_line); /* Now run job. */ if(dkt_tape_process_arguments(&j)) { j.exval = DKT_RESULT_OK; dkt_tape_run(&j); } /* Clean up and return. */ dkt_tape_job_cleanup(&j); back = j.exval; return back; } /** Initialize job structure. @param j Job structure to initialize. */ static void dkt_ts_job_init(DKT_TS_J *j) { j->app = NULL; j->msg = NULL; j->kwnl = NULL; j->opt = NULL; j->enc_f = 0; j->exval = DKT_RESULT_ERR_UNSPECIFIC; j->f_plain = 0; j->f_confirm = 0; j->filename = NULL; j->lineno = 0; j->day = 0; j->names = NULL; j->nnames = 0; j->unames = 0; j->nb = NULL; j->nbs = 0; } /** Clean up job structure. @param j Job structure to clean up. */ static void dkt_ts_job_cleanup(DKT_TS_J *j) { if(j->opt) { dk3opt_close(j->opt); } j->opt = NULL; } /** Reset job structure for -R or --reset. @param j Job structure to reset. */ static void dkt_ts_job_reset(DKT_TS_J *j) { j->enc_f = dk3app_get_default_file_encoding(j->app); } /** Process one line form configuration file. @param vj Job structure as void *. @param key Key found line line. @param val Value found in line (if any), may be NULL. @return 1 on success, 0 on error. */ static int dkt_ts_conf_line(void *vj, dkChar const *key, dkChar const *val) { int back = 0; DKT_TS_J *j; j = (DKT_TS_J *)vj; $? "+ dkt_ts_conf_line" switch(dk3str_array_index(dkt_tape_long_options, key, 0)) { case 0: { /* reset */ dkt_ts_job_reset(j); back = 1; } break; case 1: { /* file encoding = ... */ if(val) { back = dkt_tool_set_encoding( j->app, &(j->enc_f), val, dk3app_get_input_file_encoding(j->app) ); } } break; } $? "- dkt_ts_conf_line %d", back return back; } /** Process command line arguments. @param j Job structure. @return 1 on success, 0 on error. */ static int dkt_ts_process_arguments(DKT_TS_J *j) { int back = 0; int xargc = 0; /* Number of cmd line args. */ int res = 0; /* Line processing result. */ dkChar const *arg = NULL; /* Current argument. */ dkChar const * const *xargv = NULL; /* Cmd line args array. */ $? "+ dkt_ts_process_arguments" xargc = dk3app_get_argc(j->app); xargv = dk3app_get_argv(j->app); xargv++; xargv++; xargc--; xargc--; j->opt = dk3opt_open_app( dkt_tape_options, dkt_tape_szoptions, 0x00, NULL, xargc, xargv, j->app ); if(j->opt) { if(0 == dk3opt_get_error_code(j->opt)) { if(dk3opt_get_num_args(j->opt) > 1) { /* Process options. */ if(dk3opt_is_set(j->opt, dkT('R'))) { dkt_ts_job_reset(j); } if(dk3opt_is_set(j->opt, dkT('a'))) { j->f_plain = 1; } if(dk3opt_is_set(j->opt, dkT('p'))) { j->enc_f = DK3_FILE_ENCODING_ASCII; if(dk3opt_is_set(j->opt, dkT('i'))) { back = 0; j->exval = DKT_RESULT_ERR_OPTION; dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 0); } } else { if(dk3opt_is_set(j->opt, dkT('i'))) { arg = dk3opt_get_short_arg(j->opt, dkT('i')); if(arg) { res = dkt_tool_set_encoding( j->app, &(j->enc_f), arg, dk3app_get_input_file_encoding(j->app) ); if(!(res)) { back = 0; j->exval = DKT_RESULT_ERR_OPTION; } } else { back = 0; j->exval = DKT_RESULT_ERR_OPTION; } } } switch(dk3str_array_index(dkt_tape_commands,dk3opt_get_arg(j->opt,0),0)) { case 0: { back = 1; } break; case 1: { back = 1; j->f_confirm = 1; } break; default: { dk3app_log_i3( j->app, DK3_LL_ERROR, 139, 140, dk3opt_get_arg(j->opt, 0) ); j->exval = DKT_RESULT_ERR_OPTION; } break; } j->filename = dk3opt_get_arg(j->opt, 1); if(!(j->filename)) { back = 0; /* ERROR: Missing filename */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 25); } if(dk3opt_get_num_args(j->opt) > 2) { dk3app_log_i3( j->app, DK3_LL_ERROR, 137, 138, dk3opt_get_arg(j->opt, 2) ); } } else { j->exval = DKT_RESULT_ERR_OPTION; /* ERROR: Missing file name! */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 25); } } else { j->exval = DKT_RESULT_ERR_OPTION; } } else { j->exval = DKT_RESULT_ERR_OPTION; } $? "- dkt_ts_process_arguments %d", back return back; } /** Process one line from tapeset file. @param vj Job structure. @param il Input line. @return 1 on success, -1 on error. */ static int dkt_ts_line_handler(void *vj, dkChar *il) { int back = -1; DKT_TS_J *j = NULL; /* Job structure. */ unsigned u = 0; /* Used in text to number conversions. */ j = (DKT_TS_J *)vj; $? "+ dkt_ts_line_handler line %d", j->lineno dk3str_delnl(il); switch(j->lineno) { case 0: { if(dk3str_len(il) < j->nbs) { dk3str_cpy(j->nb, il); j->unames = dk3str_explode(j->names, j->nnames, j->nb, NULL); if(j->unames > 0) { back = 1; j->lineno = 1; } else { /* ERROR: No text! */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 29); } } else { /* ERROR: Line too long! */ dk3app_log_i1(j->app, DK3_LL_ERROR, 108); } } break; case 1: { u = 0; if(dk3sf_sscanf3(il, dkT("%u"), &u) == 1) { j->day = u; if(j->unames > 0) { j->day = (j->day) % (unsigned)(j->unames); j->lineno = 2; back = 1; } else { /* ERROR: No Tape set names! */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 29); } } else { /* Syntax error, not a number! */ dk3app_log_i3(j->app, DK3_LL_ERROR, 141, 142, il); } } break; default: { /* ERROR: Too many lines */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 30); } break; } $? "- dkt_ts_line_handler %d", back return back; } /** Read tape set file. @param j job structure. @return 1 on success, 0 on error. */ static int dkt_ts_read_file(DKT_TS_J *j) { int back = 0; int res = 0; /* File processing result. */ dkChar bu[DKT_TS_LINE_SIZE]; /* Buffer for input file lines. */ $? "+ dkt_ts_read_file \"%s\"", TR_STR(j->filename) if(j->filename) { res = dk3stream_process_filename_lines_app( (void *)j, dkt_ts_line_handler, j->filename, bu, DK3_SIZEOF(bu,dkChar), dk3app_get_encoding(j->app), j->enc_f, j->app ); if(res == 1) { if((j->lineno == 1) || (j->lineno == 2)) { back = 1; } else { /* Syntax error! */ j->exval = DKT_RESULT_ERR_INPUT; dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 31); } } } else { j->exval = DKT_RESULT_ERR_FILENAME; } $? "- dkt_ts_read_file %d", back return back; } /** Write a new tape set file. @param j Job structure. */ static void dkt_ts_write_file(DKT_TS_J *j) { FILE *fipo; /* Output file. */ int is_first = 1; /* Flag: First name in line. */ size_t i = 0; /* Traverse the used names. */ dkChar bu[64]; /* Buffer for numeric value. */ $? "+ dkt_ts_write_file \"%s\"", TR_STR(j->filename) fipo = dk3sf_fopen_app(j->filename, dk3app_not_localized(24), j->app); if(fipo) { #if DK3_CHAR_SIZE > 1 dk3sf_fputc((dkChar)0xFEFF, fipo); #endif for(i = 0; i < j->unames; i++) { if(!(is_first)) { dk3sf_fputc(dkT(' '), fipo); } is_first = 0; dk3sf_fputs((j->names)[i], fipo); } dk3sf_fputc(dkT('\n'), fipo); if(dk3sf_sprintf3(bu, dkT("%u"), j->day)) { dk3sf_fputs(bu, fipo); dk3sf_fputc(dkT('\n'), fipo); } else { j->exval = DKT_RESULT_ERR_UNSPECIFIC; } if(!dk3sf_fclose_fn_app(fipo, j->filename, j->app)) { j->exval = DKT_RESULT_ERR_UNSPECIFIC; } } else { j->exval = DKT_RESULT_ERR_FILENAME; } $? "- dkt_ts_write_file" } /** Run dkt ts command. @param j Job structure. @return 1 on success, 0 on error. */ static void dkt_ts_run(DKT_TS_J *j) { dkChar *name = NULL; /* Tape set name. */ char bu[DKT_TS_LINE_SIZE]; /* Buffer for input lines. */ $? "+ dkt_ts_run" if(dkt_ts_read_file(j)) { if(j->f_confirm) { j->day += 1; if(j->unames > 0) { j->day = (j->day) % ((unsigned)(j->unames)); } else { j->exval = DKT_RESULT_ERR_UNSPECIFIC; } } else { if(j->unames > 0) { name = (j->names)[(j->day) % ((unsigned)(j->unames))]; if(name) { if(j->f_plain) { if(dk3str_string_to_c8_simple_app( bu, DK3_SIZEOF(bu,dkChar), name, j->app ) ) { fputs(bu, stdout); fputc('\n', stdout); } else { j->exval = DKT_RESULT_ERR_UNSPECIFIC; /* ERROR: Not plain text! */ } } else { dk3sf_initialize_stdout(); dk3sf_fputs(name, stdout); dk3sf_fputc(dkT('\n'), stdout); } } else { j->exval = DKT_RESULT_ERR_UNSPECIFIC; } } else { j->exval = DKT_RESULT_ERR_UNSPECIFIC; } } dkt_ts_write_file(j); } $? "- dkt_ts_run" } int dkt_tapeset( dk3_app_t *app, dkChar const *sn, dkChar const * const *msg, dkChar const * const *kwnl ) { int back; DKT_TS_J j; dkChar nb[DKT_TS_LINE_SIZE]; /* Input line buffer. */ dkChar *names[DK3_SIZEOF(nb,dkChar)]; $? "+ dkt_tapeset" /* Initialize job structure. */ dkt_ts_job_init(&j); j.app = app; j.msg = msg; j.kwnl = kwnl; j.enc_f = dk3app_get_input_file_encoding(app); j.nb = nb; j.names = names; j.nbs = DK3_SIZEOF(nb,dkChar); j.nnames = DK3_SIZEOF(nb,dkChar); /* Read configuration file(s). */ dkt_tool_read_conf(app, sn, (void *)(&j), dkt_ts_conf_line); /* Now process request. */ if(dkt_ts_process_arguments(&j)) { j.exval = DKT_RESULT_OK; dkt_ts_run(&j); } /* Clean up and return. */ dkt_ts_job_cleanup(&j); back = j.exval; $? "- dkt_tapeset %d", back return back; } /* vim: set ai sw=2 : */