%%
%% This is file `ducksay.code.v2.tex',
%% generated with the docstrip utility.
%%
%% The original source files were:
%%
%% ducksay.dtx  (with options: `code.v2')
%% 
%% --------------------------------------------------------------
%% ducksay -- cowsay for LaTeX
%% E-mail: jspratte@yahoo.de
%% Released under the LaTeX Project Public License v1.3c or later
%% See http://www.latex-project.org/lppl.txt
%% --------------------------------------------------------------
%% 
%% Copyright (C) 2017-2025 Jonathan P. Spratte
%% 
%% This  work may be  distributed and/or  modified under  the conditions  of the
%% LaTeX Project Public License (LPPL),  either version 1.3c  of this license or
%% (at your option) any later version.  The latest version of this license is in
%% the file:
%% 
%%   http://www.latex-project.org/lppl.txt
%% 
%% This work is "maintained" (as per LPPL maintenance status) by
%%   Jonathan P. Spratte.
%% 
%% This work consists of the file  ducksay.dtx
%% and the derived files           ducksay.pdf
%%                                 ducksay.sty
%%                                 ducksay.code.v1.tex
%%                                 ducksay.code.v2.tex and
%%                                 ducksay.animals.tex.
%% 
\ProvidesFile{ducksay.code.v2.tex}
  [\ducksay@date\space v\ducksay@version\space ducksay code version 2]
\RequirePackage{array,grabbox}
\msg_new:nnn { ducksay } { justify~unavailable }
  {
    Justified~content~is~not~available~for~tabular~argument~mode~without~fixed~
    width.~`l`~column~is~used~instead.
  }
\msg_new:nnn { ducksay } { v1-key-only }
  { The~`\l_keys_key_str`~key~is~only~available~for~`version=1`. }
\msg_new:nnn { ducksay } { zero-baselineskip }
  { Current~ baselineskip~ is~ 0pt. }
\tl_new:N \l_ducksay_msg_align_vbox_tl
\box_new:N \l_ducksay_msg_box
\bool_new:N \l_ducksay_eat_arg_box_bool
\bool_new:N \l_ducksay_eat_arg_tab_verb_bool
\bool_new:N \l_ducksay_mirrored_body_bool
\bool_new:N \l_ducksay_msg_eq_body_width_bool
\coffin_new:N \l_ducksay_body_coffin
\coffin_new:N \l_ducksay_bubble_close_coffin
\coffin_new:N \l_ducksay_bubble_open_coffin
\coffin_new:N \l_ducksay_bubble_top_coffin
\coffin_new:N \l_ducksay_msg_coffin
\dim_new:N \l_ducksay_hpad_dim
\dim_new:N \l_ducksay_bubble_bottom_kern_dim
\dim_new:N \l_ducksay_bubble_top_kern_dim
\dim_new:N \l_ducksay_msg_width_dim
\keys_define:nn { ducksay }
  {
    ,arg .choice:
    ,arg / box  .code:n = \bool_set_true:N  \l_ducksay_eat_arg_box_bool
    ,arg / tab  .code:n =
      {
        \bool_set_false:N \l_ducksay_eat_arg_box_bool
        \bool_set_false:N \l_ducksay_eat_arg_tab_verb_bool
      }
    ,arg / tab* .code:n =
      {
        \bool_set_false:N \l_ducksay_eat_arg_box_bool
        \bool_set_true:N  \l_ducksay_eat_arg_tab_verb_bool
      }
    ,arg .initial:n = tab
    ,wd* .dim_set:N = \l_ducksay_msg_width_dim
    ,wd* .initial:n = -\c_max_dim
    ,wd* .value_required:n = true
    ,wd-eq-body    .bool_set:N = \l_ducksay_msg_eq_body_width_bool
    ,none          .bool_set:N = \l_ducksay_no_body_bool
    ,no-bubble     .bool_set:N = \l_ducksay_no_bubble_bool
    ,body-mirrored .bool_set:N = \l_ducksay_mirrored_body_bool
    ,ignore-body   .bool_set:N = \l_ducksay_ignored_body_bool
    ,body-x      .dim_set:N = \l_ducksay_body_x_offset_dim
    ,body-x      .value_required:n = true
    ,body-y      .dim_set:N = \l_ducksay_body_y_offset_dim
    ,body-y      .value_required:n = true
    ,body-to-msg .tl_set:N  = \l_ducksay_body_to_msg_align_body_tl
    ,msg-to-body .tl_set:N  = \l_ducksay_body_to_msg_align_msg_tl
    ,body-align .choice:
    ,body-align / l .meta:n = { body-to-msg = l , msg-to-body = l }
    ,body-align / c .meta:n = { body-to-msg = hc , msg-to-body = hc }
    ,body-align / r .meta:n = { body-to-msg = r , msg-to-body = r }
    ,body-align  .initial:n = l
    ,body-bigger .int_set:N = \l_ducksay_body_bigger_int
    ,body-bigger .initial:n = \c_zero_int
    ,msg-align   .choice:
    ,msg-align  / l .code:n = { \tl_set:Nn \l_ducksay_msg_align_tl { l } }
    ,msg-align  / c .code:n = { \tl_set:Nn \l_ducksay_msg_align_tl { c } }
    ,msg-align  / r .code:n = { \tl_set:Nn \l_ducksay_msg_align_tl { r } }
    ,msg-align  / j .code:n = { \tl_set:Nn \l_ducksay_msg_align_tl { j } }
    ,msg-align-l .tl_set:N  = \l_ducksay_msg_align_l_tl
    ,msg-align-l .initial:n = \raggedright
    ,msg-align-c .tl_set:N  = \l_ducksay_msg_align_c_tl
    ,msg-align-c .initial:n = \centering
    ,msg-align-r .tl_set:N  = \l_ducksay_msg_align_r_tl
    ,msg-align-r .initial:n = \raggedleft
    ,msg-align-j .tl_set:N  = \l_ducksay_msg_align_j_tl
    ,msg-align-j .initial:n = {}
    ,out-h   .tl_set:N  = \l_ducksay_output_h_pole_tl
    ,out-h   .initial:n = l
    ,out-v   .tl_set:N  = \l_ducksay_output_v_pole_tl
    ,out-v   .initial:n = vc
    ,out-x   .dim_set:N = \l_ducksay_output_x_offset_dim
    ,out-x   .value_required:n = true
    ,out-y   .dim_set:N = \l_ducksay_output_y_offset_dim
    ,out-y   .value_required:n = true
    ,t       .meta:n    = { out-v = t }
    ,c       .meta:n    = { out-v = vc }
    ,b       .meta:n    = { out-v = b }
    ,body*   .tl_set:N  = \l_ducksay_body_fount_tl
    ,msg*    .tl_set:N  = \l_ducksay_msg_fount_tl
    ,bubble* .tl_set:N  = \l_ducksay_bubble_fount_tl
    ,body*   .initial:n = \verbatim@font
    ,msg*    .initial:n = \verbatim@font
    ,bubble* .initial:n = \verbatim@font
    ,body    .code:n    = \tl_put_right:Nn \l_ducksay_body_fount_tl   { #1 }
    ,msg     .code:n    = \tl_put_right:Nn \l_ducksay_msg_fount_tl    { #1 }
    ,bubble  .code:n    = \tl_put_right:Nn \l_ducksay_bubble_fount_tl { #1 }
    ,MSG     .meta:n    = { msg  = #1 , bubble  = #1 }
    ,MSG*    .meta:n    = { msg* = #1 , bubble* = #1 }
    ,hpad    .int_set:N = \l_ducksay_hpad_int
    ,hpad    .initial:n = 2
    ,hpad    .value_required:n = true
    ,vpad    .int_set:N = \l_ducksay_vpad_int
    ,vpad    .value_required:n = true
    ,col     .tl_set:N  = \l_ducksay_msg_tabular_column_tl
    ,bubble-top-kern  .tl_set:N  = \l_ducksay_bubble_top_kern_tl
    ,bubble-top-kern  .initial:n = { -.5ex }
    ,bubble-top-kern  .value_required:n = true
    ,bubble-bot-kern  .tl_set:N  = \l_ducksay_bubble_bottom_kern_tl
    ,bubble-bot-kern  .initial:n = { .2ex }
    ,bubble-bot-kern  .value_required:n = true
    ,bubble-side-kern .tl_set:N  = \l_ducksay_bubble_side_kern_tl
    ,bubble-side-kern .initial:n = { .2em }
    ,bubble-side-kern .value_required:n = true
    ,bubble-delim-top     .tl_set:N  = \l_ducksay_bubble_delim_top_tl
    ,bubble-delim-left-1  .tl_set:N  = \l_ducksay_bubble_delim_left_a_tl
    ,bubble-delim-left-2  .tl_set:N  = \l_ducksay_bubble_delim_left_b_tl
    ,bubble-delim-left-3  .tl_set:N  = \l_ducksay_bubble_delim_left_c_tl
    ,bubble-delim-left-4  .tl_set:N  = \l_ducksay_bubble_delim_left_d_tl
    ,bubble-delim-right-1 .tl_set:N  = \l_ducksay_bubble_delim_right_a_tl
    ,bubble-delim-right-2 .tl_set:N  = \l_ducksay_bubble_delim_right_b_tl
    ,bubble-delim-right-3 .tl_set:N  = \l_ducksay_bubble_delim_right_c_tl
    ,bubble-delim-right-4 .tl_set:N  = \l_ducksay_bubble_delim_right_d_tl
    ,bubble-delim-top     .initial:n = { { - } }
    ,bubble-delim-left-1  .initial:n = (
    ,bubble-delim-left-2  .initial:n = /
    ,bubble-delim-left-3  .initial:n = |
    ,bubble-delim-left-4  .initial:n = \c_backslash_str
    ,bubble-delim-right-1 .initial:n = )
    ,bubble-delim-right-2 .initial:n = \c_backslash_str
    ,bubble-delim-right-3 .initial:n = |
    ,bubble-delim-right-4 .initial:n = /
    ,strip-spaces .bool_set:N  = \l_ducksay_msg_strip_spaces_bool
  }
\clist_map_inline:nn
  { align, rel-align }
  {
    \keys_define:nn { ducksay }
      { #1 .code:n = \msg_error:nn { ducksay } { v1-key-only } }
  }
\cs_new:Npn \ducksay_evaluate_message_alignment_fixed_width_common:
  {
    \str_case:Vn \l_ducksay_msg_align_tl
      {
        { l } { \exp_not:N \l_ducksay_msg_align_l_tl }
        { c } { \exp_not:N \l_ducksay_msg_align_c_tl }
        { r } { \exp_not:N \l_ducksay_msg_align_r_tl }
        { j } { \exp_not:N \l_ducksay_msg_align_j_tl }
      }
  }
\cs_new:Npn \ducksay_evaluate_message_alignment_fixed_width_tabular:
  {
    \tl_if_empty:NT \l_ducksay_msg_tabular_column_tl
      {
        \tl_set:Nx \l_ducksay_msg_tabular_column_tl
          {
            >
            {
              \ducksay_evaluate_message_alignment_fixed_width_common:
              \exp_not:N \arraybackslash
            }
            p { \exp_not:N \l_ducksay_msg_width_dim }
          }
      }
  }
\cs_new:Npn \ducksay_evaluate_message_alignment_fixed_width_vbox:
  {
    \tl_set:Nx \l_ducksay_msg_align_vbox_tl
      { \ducksay_evaluate_message_alignment_fixed_width_common: }
  }
\cs_new:Npn \ducksay_calculate_msg_width_from_int:
  {
    \hbox_set:Nn \l_ducksay_tmpa_box { { \l_ducksay_msg_fount_tl M } }
    \dim_set:Nn \l_ducksay_msg_width_dim
      { \l_ducksay_msg_width_int \box_wd:N \l_ducksay_tmpa_box }
  }
\cs_new:Npn \ducksay_msg_tabular_begin:
  {
    \ducksay_msg_tabular_begin_inner:V \l_ducksay_msg_tabular_column_tl
  }
\cs_new:Npn \ducksay_msg_tabular_begin_inner:n #1
  {
    \begin { tabular } { @{} #1 @{} }
  }
\cs_generate_variant:Nn \ducksay_msg_tabular_begin_inner:n { V }
\cs_new:Npn \ducksay_msg_tabular_end:
  {
    \end { tabular }
  }
\cs_new:Npn \ducksay_width_case_none_int_dim:nnn #1 #2 #3
  {
    \dim_compare:nNnTF { \l_ducksay_msg_width_dim } < { \c_zero_dim }
      {
        \int_compare:nNnTF { \l_ducksay_msg_width_int } < { \c_zero_int }
          { #1 }
          { #2 }
      }
      { #3 }
  }
\cs_new:Npn \ducksay_digest_options:n #1
  {
    \group_begin:
    \keys_set:nn { ducksay } { #1 }
    \ducksay_default_or_random_animal:
    \bool_if:NF \l_ducksay_no_body_bool
      {
        \hcoffin_set:Nn \l_ducksay_body_coffin
          {
            \frenchspacing
            \l_ducksay_body_fount_tl
            \begin{tabular} { @{} l @{} }
              \l_ducksay_animal_tl
              \ducksay_make_body_bigger:
              \relax
            \end{tabular}
          }
        \bool_if:NT \l_ducksay_msg_eq_body_width_bool
          {
            \bool_lazy_and:nnT
              { \int_compare_p:nNn \l_ducksay_msg_width_int < \c_zero_int }
              { \dim_compare_p:nNn \l_ducksay_msg_width_dim < \c_zero_dim }
              {
                \dim_set:Nn \l_ducksay_msg_width_dim
                  { \coffin_wd:N \l_ducksay_body_coffin }
              }
          }
      }
    \bool_if:NTF \l_ducksay_eat_arg_box_bool
      {
        \ducksay_width_case_none_int_dim:nnn
          { \ducksay_eat_argument_hbox:w }
          {
            \ducksay_calculate_msg_width_from_int:
            \ducksay_eat_argument_vbox:w
          }
          { \ducksay_eat_argument_vbox:w }
      }
      {
        \ducksay_width_case_none_int_dim:nnn
          {
            \tl_if_empty:NT \l_ducksay_msg_tabular_column_tl
              {
                \str_case:Vn \l_ducksay_msg_align_tl
                  {
                    { l } { \tl_set:Nn \l_ducksay_msg_tabular_column_tl { l } }
                    { c } { \tl_set:Nn \l_ducksay_msg_tabular_column_tl { c } }
                    { r } { \tl_set:Nn \l_ducksay_msg_tabular_column_tl { r } }
                    { j }
                      {
                        \msg_error:nn { ducksay } { justify~unavailable }
                        \tl_set:Nn \l_ducksay_msg_tabular_column_tl { l }
                      }
                  }
              }
          }
          {
            \ducksay_calculate_msg_width_from_int:
            \ducksay_evaluate_message_alignment_fixed_width_tabular:
          }
          { \ducksay_evaluate_message_alignment_fixed_width_tabular: }
        \ducksay_eat_argument_tabular:w
      }
  }
\cs_new:Npn \ducksay_set_bubble_top_kern:
  {
    \group_begin:
    \l_ducksay_bubble_fount_tl
    \exp_args:NNNx
    \group_end:
    \dim_set:Nn \l_ducksay_bubble_top_kern_dim
      { \dim_eval:n { \l_ducksay_bubble_top_kern_tl } }
  }
\cs_new:Npn \ducksay_set_bubble_bottom_kern:
  {
    \group_begin:
    \l_ducksay_bubble_fount_tl
    \exp_args:NNNx
    \group_end:
    \dim_set:Nn \l_ducksay_bubble_bottom_kern_dim
      { \dim_eval:n { \l_ducksay_bubble_bottom_kern_tl } }
  }
\cs_new:Npn \ducksay_make_body_bigger:
  { \prg_replicate:nn \l_ducksay_body_bigger_int \\ }
\cs_new_protected_nopar:Npn \ducksay_baselineskip:
  {
    \the\dimexpr
      \ifdim \baselineskip = \c_zero_dim
        \ifdim \normalbaselineskip = \c_zero_dim
          \msg_expandable_error:nn { ducksay } { zero-baselineskip } { 12pt }
          12pt
        \else
          \normalbaselineskip
        \fi
      \else
        \baselineskip
      \fi
    \relax
  }
\cs_new_protected_nopar:Npn \ducksay_measure_msg:
  {
    \hbox_set:Nn \l_ducksay_tmpa_box
      { \l_ducksay_bubble_fount_tl \l_ducksay_bubble_delim_top_tl }
    \int_set:Nn \l_ducksay_msg_width_int
      {
        \fp_eval:n
          {
            ceil
              ( \box_wd:N \l_ducksay_msg_box / \box_wd:N \l_ducksay_tmpa_box )
          }
      }
    \group_begin:
    \l_ducksay_bubble_fount_tl
    \exp_args:NNNx
    \group_end:
    \int_set:Nn \l_ducksay_msg_height_int
      {
        \int_max:nn
          {
            \fp_eval:n
              {
                ceil
                  (
                    (
                      \box_ht:N \l_ducksay_msg_box
                      + \box_dp:N \l_ducksay_msg_box
                    )
                    / ( \arraystretch * \ducksay_baselineskip: )
                  )
              }
            + \l_ducksay_vpad_int
          }
          { \l_ducksay_msg_height_int }
      }
  }
\cs_new_protected_nopar:Npn \ducksay_set_bubble_coffins:
  {
    \hcoffin_set:Nn \l_ducksay_bubble_open_coffin
      {
        \l_ducksay_bubble_fount_tl
        \begin{tabular}{@{}l@{}}
          \int_compare:nNnTF { \l_ducksay_msg_height_int } = { \c_one_int }
            {
              \l_ducksay_bubble_delim_left_a_tl
            }
            {
              \l_ducksay_bubble_delim_left_b_tl\\
              \int_step_inline:nnn
                { 3 } { \l_ducksay_msg_height_int }
                {
                  \kern-\l_ducksay_bubble_side_kern_tl
                  \l_ducksay_bubble_delim_left_c_tl
                  \\
                }
              \l_ducksay_bubble_delim_left_d_tl
            }
        \end{tabular}
      }
    \hcoffin_set:Nn \l_ducksay_bubble_close_coffin
      {
        \l_ducksay_bubble_fount_tl
        \begin{tabular}{@{}r@{}}
          \int_compare:nNnTF { \l_ducksay_msg_height_int } = { \c_one_int }
            {
              \l_ducksay_bubble_delim_right_a_tl
            }
            {
              \l_ducksay_bubble_delim_right_b_tl \\
              \int_step_inline:nnn
                { 3 } { \l_ducksay_msg_height_int }
                {
                  \l_ducksay_bubble_delim_right_c_tl
                  \kern-\l_ducksay_bubble_side_kern_tl
                  \\
                }
              \l_ducksay_bubble_delim_right_d_tl
            }
        \end{tabular}
      }
    \hcoffin_set:Nn \l_ducksay_bubble_top_coffin
      {
        \l_ducksay_bubble_fount_tl
        \int_step_inline:nn
          { \l_ducksay_msg_width_int + \l_ducksay_hpad_int }
          { \l_ducksay_bubble_delim_top_tl }
      }
  }
\cs_new_protected_nopar:Npn \ducksay_join_bubble_to_msg_coffin:
  {
    \dim_set:Nn \l_ducksay_hpad_dim
      {
        (
          \coffin_wd:N \l_ducksay_bubble_top_coffin
          - \coffin_wd:N \l_ducksay_msg_coffin
        ) / 2
      }
    \coffin_join:NnnNnnnn
      \l_ducksay_msg_coffin         { l } { vc }
      \l_ducksay_bubble_open_coffin { r } { vc }
      { - \l_ducksay_hpad_dim } { \c_zero_dim }
    \coffin_join:NnnNnnnn
      \l_ducksay_msg_coffin          { r } { vc }
      \l_ducksay_bubble_close_coffin { l } { vc }
      { \l_ducksay_hpad_dim } { \c_zero_dim }
    \coffin_join:NnnNnnnn
      \l_ducksay_msg_coffin        { hc } { t }
      \l_ducksay_bubble_top_coffin { hc } { b }
      { \c_zero_dim } { \l_ducksay_bubble_top_kern_dim }
    \coffin_join:NnnNnnnn
      \l_ducksay_msg_coffin        { hc } { b }
      \l_ducksay_bubble_top_coffin { hc } { t }
      { \c_zero_dim } { \l_ducksay_bubble_bottom_kern_dim }
  }
\cs_new_protected:Npn \ducksay_shipout:
  {
    \hcoffin_set:Nn \l_ducksay_msg_coffin { \box_use:N \l_ducksay_msg_box }
    \bool_if:NF \l_ducksay_no_bubble_bool
      {
        \ducksay_measure_msg:
        \ducksay_set_bubble_coffins:
        \ducksay_set_bubble_top_kern:
        \ducksay_set_bubble_bottom_kern:
        \ducksay_join_bubble_to_msg_coffin:
      }
    \bool_if:NF \l_ducksay_no_body_bool
      {
        \bool_if:NT \l_ducksay_mirrored_body_bool
          {
            \coffin_scale:Nnn \l_ducksay_body_coffin
              { -\c_one_int } { \c_one_int }
            \str_case:Vn \l_ducksay_body_to_msg_align_body_tl
              {
                { l } { \tl_set:Nn \l_ducksay_body_to_msg_align_body_tl { r } }
                { r } { \tl_set:Nn \l_ducksay_body_to_msg_align_body_tl { l } }
              }
          }
        \bool_if:NTF \l_ducksay_ignored_body_bool
          { \coffin_attach:NVnNVnnn }
          { \coffin_join:NVnNVnnn   }
          \l_ducksay_msg_coffin  \l_ducksay_body_to_msg_align_msg_tl  { b }
          \l_ducksay_body_coffin \l_ducksay_body_to_msg_align_body_tl { t }
          { \l_ducksay_body_x_offset_dim } { \l_ducksay_body_y_offset_dim }
      }
    \coffin_typeset:NVVnn \l_ducksay_msg_coffin
      \l_ducksay_output_h_pole_tl \l_ducksay_output_v_pole_tl
      { \l_ducksay_output_x_offset_dim } { \l_ducksay_output_y_offset_dim }
    \group_end:
  }
\cs_new:Npn \ducksay_eat_argument_tabular:w
  {
    \bool_if:NTF \l_ducksay_eat_arg_tab_verb_bool
      { \ducksay_eat_argument_tabular_verb:w }
      { \ducksay_eat_argument_tabular_normal:w }
  }
\cs_new:Npn \ducksay_eat_argument_tabular_inner:w #1
  {
    \hbox_set:Nn \l_ducksay_msg_box
      {
        \l_ducksay_msg_fount_tl
        \ducksay_msg_tabular_begin:
          #1
        \ducksay_msg_tabular_end:
      }
    \ducksay_shipout:
  }
\NewDocumentCommand \ducksay_eat_argument_tabular_verb:w
  { >{ \ducksay_process_verb_newline:nnn { ~ } { ~ \par } } +v }
  {
    \ducksay_eat_argument_tabular_inner:w
      {
        \group_begin:
          \__ducksay_everyeof:w { \exp_not:N }
          \exp_after:wN
        \group_end:
        \__ducksay_scantokens:w { #1 }
      }
  }
\NewDocumentCommand \ducksay_eat_argument_tabular_normal:w { +m }
  { \ducksay_eat_argument_tabular_inner:w { #1 } }
\cs_new_protected_nopar:Npn \ducksay_eat_argument_hbox:w
  {
    \bool_if:NTF \l_ducksay_msg_strip_spaces_bool
      { \@grabbox }
      { \@grabbox* }
      {} \l_ducksay_msg_box \l_ducksay_msg_fount_tl \hbox {} \ducksay_shipout:
  }
\cs_new_protected_nopar:Npn \ducksay_eat_argument_vbox:w
  {
    \ducksay_evaluate_message_alignment_fixed_width_vbox:
    \bool_if:NTF \l_ducksay_msg_strip_spaces_bool
      { \@grabbox }
      { \@grabbox* }
      {
        \hsize \l_ducksay_msg_width_dim
        \linewidth \hsize
        \l_ducksay_msg_align_vbox_tl
        \@afterindentfalse
        \@afterheading
      }
      \l_ducksay_msg_box \l_ducksay_msg_fount_tl \vbox {} \ducksay_shipout:
  }
\cs_generate_variant:Nn \coffin_join:NnnNnnnn { NVnNVnnn }
\cs_generate_variant:Nn \coffin_attach:NnnNnnnn { NVnNVnnn }
\cs_generate_variant:Nn \coffin_typeset:Nnnnn { NVVnn }
\cs_generate_variant:Nn \str_case:nn { Vn }
\NewDocumentCommand \ducksay { O{} }
  {
    \ducksay_digest_options:n { #1 }
  }
\NewDocumentCommand \duckthink { O{} }
  {
    \ducksay_digest_options:n { think, #1 }
  }
%% 
%%
%% End of file `ducksay.code.v2.tex'.
