%% options copyright owner = Dirk Krause copyright year = 2011-2014 license = bsd %% module #include "dk3all.h" #include "dkt.h" $!trace-include /** Job structure. */ 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. */ dkChar const *title; /**< Page title for full page. */ int exval; /**< Exit status code. */ int enc_s; /**< Encoding for stdin. */ int enc_f; /**< Encoding for files. */ int f_fp; /**< Flag: Produce full page. */ int f_em; /**< Flag: Echo mode. */ int f_nl; /**< Flag: Last was newline. */ int f_ln; /**< Flag: Add code for line numbers. */ int coli; /**< Code line number. */ int cols; /**< Code line numbering state. */ } DKT_HTML_J; /** Long options / configuration file keywords. */ static dkChar const * const dkt_html_long_opt[] = { dkT("stdin-encoding"), dkT("file-encoding"), dkT("reset"), NULL }; /** Data for the option set. */ static dk3_option_t const dkt_html_options[] = { { dkT('R'), dkT("reset"), 0 }, { dkT('t'), dkT("title"), 1 }, { dkT('f'), dkT("full"), 0 }, { dkT('i'), dkT("input-encoding"), 1 }, { dkT('p'), dkT("plain"), 0 }, { dkT('e'), dkT("echo"), 0 }, { dkT('l'), dkT("line-numbers"), 0 } }; /** Number of options in the dkt_html_options array. */ static size_t const dkt_html_szoptions = sizeof(dkt_html_options)/sizeof(dk3_option_t); /** Translation table for ASCII characters. */ static char const * const dkt_html_translation_table[] = { /* 0 00 */ NULL, /* 1 01 */ NULL, /* 2 02 */ NULL, /* 3 03 */ NULL, /* 4 04 */ NULL, /* 5 05 */ NULL, /* 6 06 */ NULL, /* 7 07 */ NULL, /* 8 08 */ NULL, /* 9 09 */ "\t", /* 10 0a */ NULL, /* 11 0b */ NULL, /* 12 0c */ NULL, /* 13 0d */ NULL, /* 14 0e */ NULL, /* 15 0f */ NULL, /* 16 10 */ NULL, /* 17 11 */ NULL, /* 18 12 */ NULL, /* 19 13 */ NULL, /* 20 14 */ NULL, /* 21 15 */ NULL, /* 22 16 */ NULL, /* 23 17 */ NULL, /* 24 18 */ NULL, /* 25 19 */ NULL, /* 26 1a */ NULL, /* 27 1b */ NULL, /* 28 1c */ NULL, /* 29 1d */ NULL, /* 30 1e */ NULL, /* 31 1f */ NULL, /* 32 20 */ " ", /* 33 21 */ "!", /* 34 22 */ """, /* 35 23 */ "#", /* 36 24 */ "$", /* 37 25 */ "%", /* 38 26 */ "&", /* 39 27 */ "'", /* 40 28 */ "(", /* 41 29 */ ")", /* 42 2a */ "*", /* 43 2b */ "+", /* 44 2c */ ",", /* 45 2d */ "-", /* 46 2e */ ".", /* 47 2f */ "/", /* 48 30 */ "0", /* 49 31 */ "1", /* 50 32 */ "2", /* 51 33 */ "3", /* 52 34 */ "4", /* 53 35 */ "5", /* 54 36 */ "6", /* 55 37 */ "7", /* 56 38 */ "8", /* 57 39 */ "9", /* 58 3a */ ":", /* 59 3b */ ";", /* 60 3c */ "<", /* 61 3d */ "=", /* 62 3e */ ">", /* 63 3f */ "?", /* 64 40 */ "@", /* 65 41 */ "A", /* 66 42 */ "B", /* 67 43 */ "C", /* 68 44 */ "D", /* 69 45 */ "E", /* 70 46 */ "F", /* 71 47 */ "G", /* 72 48 */ "H", /* 73 49 */ "I", /* 74 4a */ "J", /* 75 4b */ "K", /* 76 4c */ "L", /* 77 4d */ "M", /* 78 4e */ "N", /* 79 4f */ "O", /* 80 50 */ "P", /* 81 51 */ "Q", /* 82 52 */ "R", /* 83 53 */ "S", /* 84 54 */ "T", /* 85 55 */ "U", /* 86 56 */ "V", /* 87 57 */ "W", /* 88 58 */ "X", /* 89 59 */ "Y", /* 90 5a */ "Z", /* 91 5b */ "[", /* 92 5c */ "\\", /* 93 5d */ "]", /* 94 5e */ "^", /* 95 5f */ "_", /* 96 60 */ "`", /* 97 61 */ "a", /* 98 62 */ "b", /* 99 63 */ "c", /* 100 64 */ "d", /* 101 65 */ "e", /* 102 66 */ "f", /* 103 67 */ "g", /* 104 68 */ "h", /* 105 69 */ "i", /* 106 6a */ "j", /* 107 6b */ "k", /* 108 6c */ "l", /* 109 6d */ "m", /* 110 6e */ "n", /* 111 6f */ "o", /* 112 70 */ "p", /* 113 71 */ "q", /* 114 72 */ "r", /* 115 73 */ "s", /* 116 74 */ "t", /* 117 75 */ "u", /* 118 76 */ "v", /* 119 77 */ "w", /* 120 78 */ "x", /* 121 79 */ "y", /* 122 7a */ "z", /* 123 7b */ "{", /* 124 7c */ "|", /* 125 7d */ "}", /* 126 7e */ "~", /* 127 7f */ NULL, /* 128 80 */ NULL, /* 129 81 */ NULL, /* 130 82 */ NULL, /* 131 83 */ NULL, /* 132 84 */ NULL, /* 133 85 */ NULL, /* 134 86 */ NULL, /* 135 87 */ NULL, /* 136 88 */ NULL, /* 137 89 */ NULL, /* 138 8a */ NULL, /* 139 8b */ NULL, /* 140 8c */ NULL, /* 141 8d */ NULL, /* 142 8e */ NULL, /* 143 8f */ NULL, /* 144 90 */ NULL, /* 145 91 */ NULL, /* 146 92 */ NULL, /* 147 93 */ NULL, /* 148 94 */ NULL, /* 149 95 */ NULL, /* 150 96 */ NULL, /* 151 97 */ NULL, /* 152 98 */ NULL, /* 153 99 */ NULL, /* 154 9a */ NULL, /* 155 9b */ NULL, /* 156 9c */ NULL, /* 157 9d */ NULL, /* 158 9e */ NULL, /* 159 9f */ NULL, /* 160 a0 */ " ", /* 161 a1 */ "¡", /* 162 a2 */ "¢", /* 163 a3 */ "£", /* 164 a4 */ "¤", /* 165 a5 */ "¥", /* 166 a6 */ "¦", /* 167 a7 */ "§", /* 168 a8 */ "¨", /* 169 a9 */ "©", /* 170 aa */ "ª", /* 171 ab */ "«", /* 172 ac */ "¬", /* 173 ad */ "", /* 174 ae */ "®", /* 175 af */ "¯", /* 176 b0 */ "°", /* 177 b1 */ "±", /* 178 b2 */ "²", /* 179 b3 */ "³", /* 180 b4 */ "´", /* 181 b5 */ "µ", /* 182 b6 */ "¶", /* 183 b7 */ "·", /* 184 b8 */ "¸", /* 185 b9 */ "¹", /* 186 ba */ "º", /* 187 bb */ "»", /* 188 bc */ "¼", /* 189 bd */ "½", /* 190 be */ "¾", /* 191 bf */ "¿", /* 192 c0 */ "À", /* 193 c1 */ "Á", /* 194 c2 */ "Â", /* 195 c3 */ "Ã", /* 196 c4 */ "Ä", /* 197 c5 */ "Å", /* 198 c6 */ "Æ", /* 199 c7 */ "Ç", /* 200 c8 */ "È", /* 201 c9 */ "É", /* 202 ca */ "Ê", /* 203 cb */ "Ë", /* 204 cc */ "/Igrave;", /* 205 cd */ "Í", /* 206 ce */ "Î", /* 207 cf */ "Ï", /* 208 d0 */ "Ð", /* 209 d1 */ "Ñ", /* 210 d2 */ "Ò", /* 211 d3 */ "Ó", /* 212 d4 */ "Ô", /* 213 d5 */ "Õ", /* 214 d6 */ "Ö", /* 215 d7 */ "×", /* 216 d8 */ "Ø", /* 217 d9 */ "Ù", /* 218 da */ "Ú", /* 219 db */ "Û", /* 220 dc */ "Ü", /* 221 dd */ "Ý", /* 222 de */ "Þ", /* 223 df */ "ß", /* 224 e0 */ "à", /* 225 e1 */ "á", /* 226 e2 */ "â", /* 227 e3 */ "ã", /* 228 e4 */ "ä", /* 229 e5 */ "å", /* 230 e6 */ "æ", /* 231 e7 */ "ç", /* 232 e8 */ "è", /* 233 e9 */ "é", /* 234 ea */ "ê", /* 235 eb */ "ë", /* 236 ec */ "ì", /* 237 ed */ "í", /* 238 ee */ "î", /* 239 ef */ "ï", /* 240 f0 */ "ð", /* 241 f1 */ "ñ", /* 242 f2 */ "ò", /* 243 f3 */ "ó", /* 244 f4 */ "ô", /* 245 f5 */ "õ", /* 246 f6 */ "ö", /* 247 f7 */ "÷", /* 248 f8 */ "ø", /* 249 f9 */ "ù", /* 250 fa */ "ú", /* 251 fb */ "û", /* 252 fc */ "ü", /* 253 fd */ "ý", /* 254 fe */ "þ", /* 255 ff */ "ÿ" }; /** First part of a full HTML file. */ static char const * const dkt_html_part1[] = { "", "", "
", "", "", NULL }; /** Last part of a full HTML file. */ static char const * const dkt_html_part2[] = { "", "", "", NULL }; /** End of HTML header. */ static char const * const dkt_html_part3[] = { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", NULL }; /** Strings to construct the title tag. */ static char const * const dkt_html_title[] = { "
\n",
};
/**	Keywords.
*/
static char const * const dkt_html_c8_kw[] = {
$!string-table
#
# 0 1 2 3 4
#
%03d
   
#
#
#
$!end
};
/**	Reset the job structure.
	@param	j	Job structure.
*/
static
void
dkt_html_job_reset(DKT_HTML_J *j)
{
  $? "+ dkt_html_job_reset"
  j->enc_f = dk3app_get_default_file_encoding(j->app); $? ". enc_f=%d", j->enc_f
  j->enc_s = dk3app_get_default_stdin_encoding(j->app); $? ". enc_s=%d",j->enc_s
  j->f_fp  = 0;
  j->f_em  = 0;
  j->title = NULL;
  $? "- dkt_html_job_reset"
}
/**	Initialize job structure.
	@param	j	Job structure.
*/
static
void
dkt_html_job_init(DKT_HTML_J *j)
{
  $? "+ dkt_html_job_init"
  j->exval = DKT_RESULT_ERR_UNSPECIFIC;
  j->opt = NULL;
  dkt_html_job_reset(j);
  j->enc_f = dk3app_get_input_file_encoding(j->app);  $? ". enc_f=%d", j->enc_f
  j->enc_s = dk3app_get_input_stdin_encoding(j->app); $? ". enc_s=%d", j->enc_s
  j->f_nl = 0;
  j->f_ln = 0;
  j->coli = 1;
  j->cols = 0;
  $? "- dkt_html_job_init"
}
/**	Clean up job structure.
	@param	j	Job structure.
*/
static
void
dkt_html_job_cleanup(DKT_HTML_J *j)
{
  $? "+ dkt_html_job_cleanup"
  /* Release option set. */
  if(j->opt) {
    dk3opt_close(j->opt);
  } j->opt = NULL;
  j->title = NULL;
  $? "- dkt_html_job_cleanup"
}
/**	Process one key/value pair, either long option or config file line.
	@param	job	Job structure.
	@param	key	Key (option name).
	@param	val	Value.
	@param	ori	Original text.
	@param	verb	Flag: Verbose.
	@return	1 on success, 0 on error.
*/
static
int
dkt_html_long_opt_handler(
  DKT_HTML_J *job,
  dkChar const *key,
  dkChar const *val,
  dkChar const *ori,
  int		verb
)
{
  int back = 0;
  int i = 0;	/* Index of long option keyword in array. */
  $? "+ dkt_html_long_opt_handler"
  if((job) && (key) && (ori)) {
    i = dk3str_array_index(dkt_html_long_opt, key, 0);
    switch(i) {
      case 0: {
        back = dkt_tool_set_encoding(
	  job->app, &(job->enc_s), val,
	  dk3app_get_input_stdin_encoding(job->app)
	); $? ". enc_s=%d", job->enc_s
      } break;
      case 1: {
        back = dkt_tool_set_encoding(
	  job->app, &(job->enc_f), val,
	  dk3app_get_input_file_encoding(job->app)
	); $? ". enc_f=%d", job->enc_f
      } break;
      case 2: {
        dkt_html_job_reset(job);
        back = 1;
      } break;
      default: {
        if(verb) {
	  /* ERROR: Unknown option */
	  dk3app_log_i3(job->app, DK3_LL_ERROR, 139, 140, key);
	}
      } break;
    }
  } $? "- dkt_html_long_opt_handler %d", back
  return back;
}
/**	Process one key/value pair.
	@param	jv	Pointer to job structure casted to void *.
	@param	k	Key.
	@param	v	Value.
	@return	1 to indicate success.
*/
static
int
dkt_html_conf_line(void *jv, dkChar const *k, dkChar const *v)
{
  $? "+ dkt_html_conf_line k=\"%s\" v=\"%s\"", TR_STR(k), TR_STR(v)
  (void)dkt_html_long_opt_handler((DKT_HTML_J *)jv, k, v, k, 0);
  $? "- dkt_html_conf_line"
  return 1;
}
/**	Process command line arguments.
	@param	j	Job structure.
	@return	1 on success, 0 on error.
*/
static
int
dkt_html_process_arguments(DKT_HTML_J *j)
{
  int back = 0;
  int			 xargc	= 0;	/* Number of command line arguments. */
  dkChar const * const	*xargv	= NULL;	/* Command line arguments array. */
  dkChar const		*x	= NULL;	/* Option argument. */
  int			 res	= 0;	/* Result of set encoding operation. */
  $? "+ dkt_html_process_arguments"
  xargc = dk3app_get_argc(j->app);
  xargv = dk3app_get_argv(j->app);
  xargv++; xargv++; xargc--; xargc--;
  j->opt = dk3opt_open_app(
    dkt_html_options,
    dkt_html_szoptions,
    dkT('\0'),
    NULL,
    xargc,
    xargv,
    j->app
  );
  if(j->opt) {
    if(dk3opt_get_error_code(j->opt) == 0) {
      back = 1;
      if(dk3opt_is_set(j->opt, dkT('R'))) {
        dkt_html_job_reset(j);
      }
      if(dk3opt_is_set(j->opt, dkT('f'))) {
        j->f_fp = 1;
        if(dk3opt_is_set(j->opt, dkT('t'))) {
          j->title = dk3opt_get_short_arg(j->opt, dkT('t'));
        }
      }
      if(dk3opt_is_set(j->opt, dkT('i'))) {
        x = dk3opt_get_short_arg(j->opt, dkT('i'));
        if(x) {
          res = dkt_tool_set_encoding(
	    j->app, &(j->enc_s), x,
	    dk3app_get_input_stdin_encoding(j->app)
	  ); $? ". enc_s=%d", j->enc_s
	  if(res) {
	    j->enc_f = j->enc_s;
	  } else {
	    back = 0; j->exval = DKT_RESULT_ERR_OPTION;
	  }
        } else {
          back = 0; j->exval = DKT_RESULT_ERR_OPTION;
        }
      } else {
        if(dk3opt_is_set(j->opt, dkT('p'))) {
          j->enc_f = j->enc_s = DK3_FILE_ENCODING_ASCII;
        }
      }
      if(dk3opt_is_set(j->opt, dkT('e'))) {
        j->f_em = 1;
      }
      if (dk3opt_is_set(j->opt, dkT('l'))) {
        if (j->f_em) {
	  /* WARNING -l ignored for -e */
	  dk3app_log_1(j->app, DK3_LL_WARNING, j->msg, 75);
	} else {
	  j->f_ln = 1;
	}
      }
    } else {
      j->exval = DKT_RESULT_ERR_OPTION;
    }
  } else {
    j->exval = DKT_RESULT_ERR_MEMORY;
  } $? "- dkt_html_process_arguments %d", back
  return back;
}
/**	Write one 32-bit character to output.
	@param	j	Job structure.
	@param	c32	Character to write.
*/
static
void
dkt_html_out_c32(DKT_HTML_J *j, dk3_c32_t c32)
{
  int		done	= 0;	/* Flag: Character already handled. */
  size_t	sz	= 0;	/* Index into fixed decodings array. */
  if((unsigned long)c32 < 0x00000100UL) {
    sz = (size_t)c32;
    sz &= 0x00FFU;
    if(dkt_html_translation_table[sz]) {
      fputs(dkt_html_translation_table[sz], stdout);
      done = 1;
    }
  }
  if(!done) {
#if DK3_SIZEOF_WCHAR_T == 4
    if((unsigned long)c32 > 0x000000FFUL) {
      if((unsigned long)c32 > 0x0000FFFFUL) {
        if((unsigned long)c32 > 0x00FFFFFFUL) {
	  fprintf(stdout, "%08lx;", (unsigned long)c32);
	} else {
	  fprintf(stdout, "%06lx;", (unsigned long)c32);
	}
      } else {
        fprintf(stdout, "%04lx;", (unsigned long)c32);
      }
    } else {
      fprintf(stdout, "%02lx;", (unsigned long)c32);
    }
#else
    if((unsigned long)c32 > 0x000000FFUL) {
      if((unsigned long)c32 > 0x0000FFFFUL) {
        if((unsigned long)c32 > 0x00FFFFFFUL) {
	  fprintf(stdout, "%08lx;", c32);
	} else {
	  fprintf(stdout, "%06lx;", c32);
	}
      } else {
        fprintf(stdout, "%04lx;", c32);
      }
    } else {
      fprintf(stdout, "%02lx;", c32);
    }
#endif
  }
}
/**	Open a code tag.
	@param	j	Job structure.
	@return	1 on success, 0 on error.
*/
static
int
dkt_html_open_code_tag(DKT_HTML_J *j)
{
  int		 back = 1;
  if (j->f_ln) {
    if (0 == j->cols) {
      if (EOF == fputs(dkt_html_c8_kw[0], stdout)) { back = 0; }
      if (1000 > j->coli) {
        if (0 > fprintf(stdout, dkt_html_c8_kw[3], j->coli)) { back = 0; }
      } else {
        if (EOF == fputs(dkt_html_c8_kw[4], stdout)) { back = 0; }
      }
      if (EOF == fputs(dkt_html_c8_kw[1], stdout)) { back = 0; }
      j->cols =  1;
      j->coli += 1;
      if (1000 == j->coli) {
        back = 0;
	/* Too many code lines */
	dk3app_log_1(j->app, DK3_LL_WARNING, j->msg, 76);
      }
    }
  }
  return back;
}
/**	Close code tag.
	@param	j	Job structure.
	@return	1 on success, 0 on error.
*/
static
int
dkt_html_close_code_tag(DKT_HTML_J *j)
{
  int		 back = 1;
  if (j->f_ln) {
    if (!(j->cols)) {
      if (!dkt_html_open_code_tag(j)) { back = 0; }
      if (EOF == fputc(' ', stdout)) { back = 0; }
    }
    if (j->cols) {
      if (EOF == fputs(dkt_html_c8_kw[2], stdout)) { back = 0; }
      j->cols = 0;
    }
  }
  return back;
}
/**	Handler function to process one 32-bit character.
	@param	vj	Job structure, casted to void *.
	@param	c32	The character to write.
	@return	1 to indicate success.
*/
static
int
dkt_html_char_handler(void *vj, dk3_c32_t c32)
{
  DKT_HTML_J	*j;
  int		 back	= 1;
  j = (DKT_HTML_J *)vj;
  if(c32 == 0x0000000DUL) {
    j->f_nl = 0;
  } else {
    if(c32 == 0x0000000AUL) {
      if (!dkt_html_close_code_tag((DKT_HTML_J *)vj)) { back = 0; }
      fputc('\n', stdout);
      j->f_nl = 1;
    } else {
      j->f_nl = 0;
      if (!dkt_html_open_code_tag((DKT_HTML_J *)vj)) { back = 0; }
      dkt_html_out_c32((DKT_HTML_J *)vj, c32);
    }
  }
  return back;
}
/**	Write a dkChar string to HTML, used to write page title.
	@param	j	Job structure.
	@param	tx	Text to write.
*/
static
void
dkt_html_print_text(DKT_HTML_J *j, dkChar const *tx)
{
  dk3_c32_t		c32	= 0UL;	/* 32-bit character. */
#if DK3_CHAR_SIZE > 1
  dk3_c16_t const	*sp	= NULL;	/* Source pointer. */
  size_t		 sl	= 0;	/* Remaining source length. */
  size_t		 used	= 0;	/* Number of bytes used. */
  $? "+ dkt_html_print_text \"%s\"", tx
  sp = (dk3_c16_t const *)tx;
  sl = dk3str_c16_len(sp);
  while(sl > 0) {
    used = 0;
    if(dk3enc_utf162uc(&c32, sp, sl, &used)) {
      dkt_html_out_c32(j, c32);
      if(used > 0) {
        if(sl >= used) {
	  sl = sl - used;
	  sp = &(sp[used]);
	} else {
	  sl = 0;
	  /* ERROR: Decoding! */
	  dk3app_log_i1(j->app, DK3_LL_ERROR, 119);
	}
      } else {
        sl = 0;
	/* ERROR: Decoding! */
	dk3app_log_i1(j->app, DK3_LL_ERROR, 119);
      }
    } else {
      sl = 0;
      /* ERROR: Decoding! */
      dk3app_log_i1(j->app, DK3_LL_ERROR, 119);
    }
  }
#else
  unsigned char const	*sp	= NULL;	/* Source pointer. */
  unsigned char		c	= 0x00;	/* Current character. */
  size_t		sl	= 0;	/* Remaining source length. */
  size_t		used	= 0;	/* Number of bytes used. */
  $? "+ dkt_html_print_text \"%s\"", tx
  if(dk3app_get_encoding(j->app) == DK3_ENCODING_UTF8) {
    sp = (unsigned char const *)tx;
    sl = dk3str_c8_len(tx);
    while(sl > 0) {
      used = 0;
      if(dk3enc_utf82uc(&c32, sp, sl, &used)) {
        dkt_html_out_c32(j, c32);
	if(used > 0) {
	  if(sl >= used) {
	    sl = sl - used;
	    sp = &(sp[used]);
	  } else {
	    sl = 0;
	    /* Decoding problem! */
	    dk3app_log_i1(j->app, DK3_LL_ERROR, 118);
	  }
	} else {
	  sl = 0;
	  /* Decoding problem! */
	  dk3app_log_i1(j->app, DK3_LL_ERROR, 118);
	}
      } else {
        sl = 0;
	/* Decoding problem! */
	dk3app_log_i1(j->app, DK3_LL_ERROR, 118);
      }
    }
  } else {
    sp = (unsigned char const *)tx;
    while(*sp) {
      c = *(sp++);
      c32 = (dk3_c32_t)c;
      c32 &= 0x000000FFUL;
      dkt_html_out_c32(j, c32);
    }
  }
#endif
}
/**	Write one text paragraph.
	@param	j	Job structure.
	@param	t	Text.
*/
static
void
dkt_html_write_paragraph(DKT_HTML_J *j, char const * const *t)
{
  char const * const *ptr = NULL;	/* Current source line. */
  ptr = t;
  while(*ptr) {
    fputs(*(ptr++), stdout);
    fputc('\n', stdout);
  }
}
/**	Print start of HTML page.
	@param	j	Job structure.
*/
static
void
dkt_html_start_page(DKT_HTML_J *j)
{
  dkt_html_write_paragraph(j, dkt_html_part1);
  fputs(dkt_html_title[0], stdout);
  if(j->title) {
    dkt_html_print_text(j, j->title);
  } else {
    fputs(dkt_html_title[2], stdout);
  }
  fputs(dkt_html_title[1], stdout);
  dkt_html_write_paragraph(j, dkt_html_part3);
}
/**	Print HTML page end.
	@param	j	Job structure.
*/
static
void
dkt_html_end_page(DKT_HTML_J *j)
{
  dkt_html_write_paragraph(j, dkt_html_part2);
}
/**	Process one file name (correction and expansion is already done).
	@param	j	Job structure.
	@param	fn	File name.
	@param	de	Default encoding if no BOM found at start of file.
*/
static
void
dkt_html_process_one_file(DKT_HTML_J *j, dkChar const *fn, int de)
{
  int back;
  $? "+ dkt_html_process_one_file \"%s\"", TR_STR(fn)
  j->f_nl = 0;
  back = dk3stream_process_filename_chars_app(
    (void *)j,
    dkt_html_char_handler,
    fn,
    de,
    j->app
  );
  if ((j->f_ln) && (j->cols)) {
    if (!dkt_html_close_code_tag(j)) { back = 0; }
  }
  if(!(j->f_nl)) {
    fputc('\n', stdout);
  }
  if(!back) {
    j->exval = DKT_RESULT_ERR_FOPEN;
  } $? "- dkt_html_process_one_file %d", back
}
/**	Process the file names.
	@param	j	Job structure.
	@param	nfn	Number of file names.
*/
static
void
dkt_html_process_files(DKT_HTML_J *j, int nfn)
{
  dkChar	fnb[DK3_MAX_PATH];	/* File name buffer for correction. */
  dkChar const	*fn	= NULL;		/* Current file name as specified. */
  dkChar const	*en	= NULL;		/* Current expander result. */
  int		i	= 0;		/* Index of current file name. */
  dk3_dir_t	*fne	= NULL;		/* File name expander. */
  $? "+ dkt_html_process_files"
  for(i = 0; i < nfn; i++) {
    fn = dk3opt_get_arg(j->opt, i);
    if(fn) {
      if(dk3str_len(fn) < DK3_SIZEOF(fnb,dkChar)) {
        dk3str_cpy_not_overlapped(fnb, fn);
	dk3str_correct_filename(fnb);
	if(dk3sf_must_expand(fnb)) {
	  fne = dk3dir_fne_open_app(fnb, j->app);
	  if(fne) {
	    if(dk3dir_get_number_of_files(fne)) {
	      while(dk3dir_get_next_file(fne)) {
	        en = dk3dir_get_fullname(fne);
		if(en) {
		  dkt_html_process_one_file(j, en, j->enc_f);
		}
	      }
	    } else {
	      j->exval = DKT_RESULT_ERR_FILENAME;
	      /* ERROR: No such file! */
	      dk3app_log_i3(j->app, DK3_LL_ERROR, 215, 216, fn);
	    }
	    dk3dir_close(fne);
	  } else {
	    j->exval = DKT_RESULT_ERR_MEMORY;
	  }
	} else {
	  dkt_html_process_one_file(j, fnb, j->enc_f);
	}
      } else {
        j->exval = DKT_RESULT_ERR_FILENAME;
        /* ERROR: File name too long! */
	dk3app_log_i3(j->app, DK3_LL_ERROR, 65, 66, fn);
      }
    }
  } $? "- dkt_html_process_files"
}
/**	Process arguments in echo mode.
	@param	j	Job structure.
	@param	nfn	Number of command line arguments.
*/
static
void
dkt_html_process_echo_arguments(DKT_HTML_J *j, int nfn)
{
  int i;
  dkChar const	*arg = NULL;	/* Current argument to process. */
  for(i = 0; i < nfn; i++) {
    arg = dk3opt_get_arg(j->opt, i);
    if(arg) {
      if(i > 0) { fputc(' ', stdout); }
      dkt_html_print_text(j, arg);
    }
  }
  fputc('\n', stdout);
}
/**	Do processing.
	@param	j	Job structure.
*/
static
void
dkt_html_run(DKT_HTML_J *j)
{
  int nfn;		/* Number of file names. */
  $? "+ dkt_html_run"
  nfn = dk3opt_get_num_args(j->opt);
  /* Write HTML page start */
  if(j->f_fp) {
    dkt_html_start_page(j);
  }
  /* Process input */
  if(nfn > 0) {
    if(j->f_em) {
      dkt_html_process_echo_arguments(j, nfn);
    } else {
      dkt_html_process_files(j, nfn);
    }
  } else {
    j->f_nl = 0;
    dk3app_process_stdin_chars(j->app,(void *)j,dkt_html_char_handler,j->enc_s);
    if(!(j->f_nl)) { fputc('\n', stdout); }
  }
  /* Write HTML page end */
  if(j->f_fp) {
    dkt_html_end_page(j);
  }
  $? "- dkt_html_run"
}
int
dkt_html(
  dk3_app_t		*app,
  dkChar const		*sn,
  dkChar const * const	*msg,
  dkChar const * const	*kwnl
)
{
  int back = DKT_RESULT_ERR_UNSPECIFIC;
  DKT_HTML_J	j;
  $? "+ dkt_html"
  j.app = app; j.msg = msg; j.kwnl = kwnl;
  dkt_html_job_init(&j);
  dkt_tool_read_conf(app, sn, (void *)(&j), dkt_html_conf_line);
  $? ". file encoding = %d, stdin encoding = %d", j.enc_f, j.enc_s
  if(dkt_html_process_arguments(&j)) {
    j.exval = DKT_RESULT_OK;
    dkt_html_run(&j);
  }
  back = j.exval;
  dkt_html_job_cleanup(&j);
  $? "- dkt_html %d", back
  return back;
}
/* vim: set ai sw=2 : */