// File: jaudoux[P]countTags/src/optionparser.h
// Function: option::PrintUsageImplementation::printUsage(option::PrintUsageImplementation::IStringWriter&, option::Descriptor const*, int, int, int)
static void printUsage(IStringWriter& write, const Descriptor usage[], int width = 80, //
                         int last_column_min_percent = 50, int last_column_own_line_max_percent = 75)
  {
    if (width < 1) // protect against nonsense values
      width = 80;

    if (width > 10000) // protect against overflow in the following computation
      width = 10000;

    int last_column_min_width = ((width * last_column_min_percent) + 50) / 100;
    int last_column_own_line_max_width = ((width * last_column_own_line_max_percent) + 50) / 100;
    if (last_column_own_line_max_width == 0)
      last_column_own_line_max_width = 1;

    LinePartIterator part(usage);
    while (part.nextTable())
    {

      /***************** Determine column widths *******************************/

      const int maxcolumns = 8; // 8 columns are enough for everyone
      int col_width[maxcolumns];
      int lastcolumn;
      int leftwidth;
      int overlong_column_threshold = 10000;
      do
      {
        lastcolumn = 0;
        for (int i = 0; i < maxcolumns; ++i)
          col_width[i] = 0;

        part.restartTable();
        while (part.nextRow())
        {
          while (part.next())
          {
            if (part.column() < maxcolumns)
            {
              upmax(lastcolumn, part.column());
              if (part.screenLength() < overlong_column_threshold)
                // We don't let rows that don't use table separators (\t or \v) influence
                // the width of column 0. This allows the user to interject section headers
                // or explanatory paragraphs that do not participate in the table layout.
                if (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t'
                    || part.data()[part.length()] == '\v')
                  upmax(col_width[part.column()], part.screenLength());
            }
          }
        }

        /*
         * If the last column doesn't fit on the same
         * line as the other columns, we can fix that by starting it on its own line.
         * However we can't do this for any of the columns 0..lastcolumn-1.
         * If their sum exceeds the maximum width we try to fix this by iteratively
         * ignoring the widest line parts in the width determination until
         * we arrive at a series of column widths that fit into one line.
         * The result is a layout where everything is nicely formatted
         * except for a few overlong fragments.
         * */

        leftwidth = 0;
        overlong_column_threshold = 0;
        for (int i = 0; i < lastcolumn; ++i)
        {
          leftwidth += col_width[i];
          upmax(overlong_column_threshold, col_width[i]);
        }

      } while (leftwidth > width);

      /**************** Determine tab stops and last column handling **********************/

      int tabstop[maxcolumns];
      tabstop[0] = 0;
      for (int i = 1; i < maxcolumns; ++i)
        tabstop[i] = tabstop[i - 1] + col_width[i - 1];

      int rightwidth = width - tabstop[lastcolumn];
      bool print_last_column_on_own_line = false;
      if (rightwidth < last_column_min_width && rightwidth < col_width[lastcolumn])
      {
        print_last_column_on_own_line = true;
        rightwidth = last_column_own_line_max_width;
      }

      // If lastcolumn == 0 we must disable print_last_column_on_own_line because
      // otherwise 2 copies of the last (and only) column would be output.
      // Actually this is just defensive programming. It is currently not
      // possible that lastcolumn==0 and print_last_column_on_own_line==true
      // at the same time, because lastcolumn==0 => tabstop[lastcolumn] == 0 =>
      // rightwidth==width => rightwidth>=last_column_min_width  (unless someone passes
      // a bullshit value >100 for last_column_min_percent) => the above if condition
      // is false => print_last_column_on_own_line==false
      if (lastcolumn == 0)
        print_last_column_on_own_line = false;

      LineWrapper lastColumnLineWrapper(width - rightwidth, width);
      LineWrapper interjectionLineWrapper(0, width);

      part.restartTable();

      /***************** Print out all rows of the table *************************************/

      while (part.nextRow())
      {
        int x = -1;
        while (part.next())
        {
          if (part.column() > lastcolumn)
            continue; // drop excess columns (can happen if lastcolumn == maxcolumns-1)

          if (part.column() == 0)
          {
            if (x >= 0)
              write("\n", 1);
            x = 0;
          }

          indent(write, x, tabstop[part.column()]);

          if ((part.column() < lastcolumn)
              && (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t'
                  || part.data()[part.length()] == '\v'))
          {
            write(part.data(), part.length());
            x += part.screenLength();
          }
          else // either part.column() == lastcolumn or we are in the special case of
               // an interjection that doesn't contain \v or \t
          {
            // NOTE: This code block is not necessarily executed for
            // each line, because some rows may have fewer columns.

            LineWrapper& lineWrapper = (part.column() == 0) ? interjectionLineWrapper : lastColumnLineWrapper;

            if (!print_last_column_on_own_line)
              lineWrapper.process(write, part.data(), part.length());
          }
        } // while

        if (print_last_column_on_own_line)
        {
          part.restartRow();
          while (part.next())
          {
            if (part.column() == lastcolumn)
            {
              write("\n", 1);
              int _ = 0;
              indent(write, _, width - rightwidth);
              lastColumnLineWrapper.process(write, part.data(), part.length());
            }
          }
        }

        write("\n", 1);
        lastColumnLineWrapper.flush(write);
        interjectionLineWrapper.flush(write);
      }
    }
  }

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x320, %rsp            # imm = 0x320
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl %edx, -0x14(%rbp)
movl %ecx, -0x18(%rbp)
movl %r8d, -0x1c(%rbp)
cmpl $0x1, -0x14(%rbp)
jge 0x81ea
movl $0x50, -0x14(%rbp)
cmpl $0x2710, -0x14(%rbp)    # imm = 0x2710
jle 0x81fa
movl $0x2710, -0x14(%rbp)    # imm = 0x2710
movl -0x14(%rbp), %eax
imull -0x18(%rbp), %eax
addl $0x32, %eax
movl $0x64, %ecx
cltd
idivl %ecx
movl %eax, -0x20(%rbp)
movl -0x14(%rbp), %eax
imull -0x1c(%rbp), %eax
addl $0x32, %eax
movl $0x64, %ecx
cltd
idivl %ecx
movl %eax, -0x24(%rbp)
cmpl $0x0, -0x24(%rbp)
jne 0x8231
movl $0x1, -0x24(%rbp)
movq -0x10(%rbp), %rsi
leaq -0x68(%rbp), %rdi
callq 0x88d0
leaq -0x68(%rbp), %rdi
callq 0x8930
testb $0x1, %al
jne 0x8250
jmp 0x8857
movl $0x8, -0x6c(%rbp)
movl $0x2710, -0x9c(%rbp)    # imm = 0x2710
movl $0x0, -0x94(%rbp)
movl $0x0, -0xa0(%rbp)
cmpl $0x8, -0xa0(%rbp)
jge 0x82a1
movslq -0xa0(%rbp), %rax
movl $0x0, -0x90(%rbp,%rax,4)
movl -0xa0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xa0(%rbp)
jmp 0x8275
leaq -0x68(%rbp), %rdi
callq 0x89f0
leaq -0x68(%rbp), %rdi
callq 0x8a20
testb $0x1, %al
jne 0x82bc
jmp 0x83cc
jmp 0x82be
leaq -0x68(%rbp), %rdi
callq 0x8b10
testb $0x1, %al
jne 0x82d0
jmp 0x83c7
leaq -0x68(%rbp), %rdi
callq 0x8cd0
cmpl $0x8, %eax
jge 0x83c2
leaq -0x68(%rbp), %rdi
callq 0x8cd0
movl %eax, %esi
leaq -0x94(%rbp), %rdi
callq 0x8cf0
leaq -0x68(%rbp), %rdi
callq 0x8d30
cmpl -0x9c(%rbp), %eax
jge 0x83c0
leaq -0x68(%rbp), %rdi
callq 0x8cd0
cmpl $0x0, %eax
jg 0x8386
leaq -0x68(%rbp), %rdi
callq 0x8d50
cmpl $0x0, %eax
jg 0x8386
leaq -0x68(%rbp), %rdi
callq 0x8d70
movq %rax, -0x2b0(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x8d90
movl %eax, %ecx
movq -0x2b0(%rbp), %rax
movslq %ecx, %rcx
movsbl (%rax,%rcx), %eax
cmpl $0x9, %eax
je 0x8386
leaq -0x68(%rbp), %rdi
callq 0x8d70
movq %rax, -0x2b8(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x8d90
movl %eax, %ecx
movq -0x2b8(%rbp), %rax
movslq %ecx, %rcx
movsbl (%rax,%rcx), %eax
cmpl $0xb, %eax
jne 0x83be
leaq -0x68(%rbp), %rdi
callq 0x8cd0
movslq %eax, %rcx
leaq -0x90(%rbp), %rax
shlq $0x2, %rcx
addq %rcx, %rax
movq %rax, -0x2c0(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x8d30
movq -0x2c0(%rbp), %rdi
movl %eax, %esi
callq 0x8cf0
jmp 0x83c0
jmp 0x83c2
jmp 0x82be
jmp 0x82aa
movl $0x0, -0x98(%rbp)
movl $0x0, -0x9c(%rbp)
movl $0x0, -0xa4(%rbp)
movl -0xa4(%rbp), %eax
cmpl -0x94(%rbp), %eax
jge 0x843d
movslq -0xa4(%rbp), %rax
movl -0x90(%rbp,%rax,4), %eax
addl -0x98(%rbp), %eax
movl %eax, -0x98(%rbp)
movslq -0xa4(%rbp), %rax
movl -0x90(%rbp,%rax,4), %esi
leaq -0x9c(%rbp), %rdi
callq 0x8cf0
movl -0xa4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xa4(%rbp)
jmp 0x83ea
jmp 0x843f
movl -0x98(%rbp), %eax
cmpl -0x14(%rbp), %eax
jg 0x8261
movl $0x0, -0xd0(%rbp)
movl $0x1, -0xd4(%rbp)
cmpl $0x8, -0xd4(%rbp)
jge 0x84ae
movl -0xd4(%rbp), %eax
subl $0x1, %eax
cltq
movl -0xd0(%rbp,%rax,4), %ecx
movl -0xd4(%rbp), %eax
subl $0x1, %eax
cltq
addl -0x90(%rbp,%rax,4), %ecx
movslq -0xd4(%rbp), %rax
movl %ecx, -0xd0(%rbp,%rax,4)
movl -0xd4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xd4(%rbp)
jmp 0x8462
movl -0x14(%rbp), %eax
movslq -0x94(%rbp), %rcx
subl -0xd0(%rbp,%rcx,4), %eax
movl %eax, -0xd8(%rbp)
movb $0x0, -0xd9(%rbp)
movl -0xd8(%rbp), %eax
cmpl -0x20(%rbp), %eax
jge 0x84fd
movl -0xd8(%rbp), %eax
movslq -0x94(%rbp), %rcx
cmpl -0x90(%rbp,%rcx,4), %eax
jge 0x84fd
movb $0x1, -0xd9(%rbp)
movl -0x24(%rbp), %eax
movl %eax, -0xd8(%rbp)
cmpl $0x0, -0x94(%rbp)
jne 0x850d
movb $0x0, -0xd9(%rbp)
movl -0x14(%rbp), %esi
subl -0xd8(%rbp), %esi
movl -0x14(%rbp), %edx
leaq -0x1b8(%rbp), %rdi
callq 0x8db0
movl -0x14(%rbp), %edx
leaq -0x290(%rbp), %rdi
xorl %esi, %esi
callq 0x8db0
leaq -0x68(%rbp), %rdi
callq 0x89f0
leaq -0x68(%rbp), %rdi
callq 0x8a20
testb $0x1, %al
jne 0x8551
jmp 0x8852
movl $0xffffffff, -0x294(%rbp) # imm = 0xFFFFFFFF
leaq -0x68(%rbp), %rdi
callq 0x8b10
testb $0x1, %al
jne 0x856d
jmp 0x8760
leaq -0x68(%rbp), %rdi
callq 0x8cd0
cmpl -0x94(%rbp), %eax
jle 0x8580
jmp 0x855b
leaq -0x68(%rbp), %rdi
callq 0x8cd0
cmpl $0x0, %eax
jne 0x85b6
cmpl $0x0, -0x294(%rbp)
jl 0x85ac
movq -0x8(%rbp), %rdi
movq (%rdi), %rax
leaq 0x6dc3(%rip), %rsi      # 0xf368
movl $0x1, %edx
callq *(%rax)
movl $0x0, -0x294(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x2c8(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x8cd0
movq -0x2c8(%rbp), %rdi
cltq
movl -0xd0(%rbp,%rax,4), %edx
leaq -0x294(%rbp), %rsi
callq 0x8e10
leaq -0x68(%rbp), %rdi
callq 0x8cd0
cmpl -0x94(%rbp), %eax
jge 0x86c6
leaq -0x68(%rbp), %rdi
callq 0x8cd0
cmpl $0x0, %eax
jg 0x8673
leaq -0x68(%rbp), %rdi
callq 0x8d50
cmpl $0x0, %eax
jg 0x8673
leaq -0x68(%rbp), %rdi
callq 0x8d70
movq %rax, -0x2d0(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x8d90
movl %eax, %ecx
movq -0x2d0(%rbp), %rax
movslq %ecx, %rcx
movsbl (%rax,%rcx), %eax
cmpl $0x9, %eax
je 0x8673
leaq -0x68(%rbp), %rdi
callq 0x8d70
movq %rax, -0x2d8(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x8d90
movl %eax, %ecx
movq -0x2d8(%rbp), %rax
movslq %ecx, %rcx
movsbl (%rax,%rcx), %eax
cmpl $0xb, %eax
jne 0x86c6
movq -0x8(%rbp), %rax
movq %rax, -0x2e8(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x8d70
movq %rax, -0x2e0(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x8d90
movq -0x2e8(%rbp), %rdi
movq -0x2e0(%rbp), %rsi
movl %eax, %edx
movq (%rdi), %rax
callq *(%rax)
leaq -0x68(%rbp), %rdi
callq 0x8d30
addl -0x294(%rbp), %eax
movl %eax, -0x294(%rbp)
jmp 0x875b
leaq -0x68(%rbp), %rdi
callq 0x8cd0
cmpl $0x0, %eax
jne 0x86e4
leaq -0x290(%rbp), %rax
movq %rax, -0x2f0(%rbp)
jmp 0x86f4
leaq -0x1b8(%rbp), %rax
movq %rax, -0x2f0(%rbp)
jmp 0x86f4
movq -0x2f0(%rbp), %rax
movq %rax, -0x2a0(%rbp)
testb $0x1, -0xd9(%rbp)
jne 0x8759
movq -0x2a0(%rbp), %rax
movq %rax, -0x308(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x300(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x8d70
movq %rax, -0x2f8(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x8d90
movq -0x308(%rbp), %rdi
movq -0x300(%rbp), %rsi
movq -0x2f8(%rbp), %rdx
movl %eax, %ecx
callq 0x8ea0
jmp 0x875b
jmp 0x855b
testb $0x1, -0xd9(%rbp)
je 0x8818
leaq -0x68(%rbp), %rdi
callq 0x9120
leaq -0x68(%rbp), %rdi
callq 0x8b10
testb $0x1, %al
jne 0x8788
jmp 0x8816
leaq -0x68(%rbp), %rdi
callq 0x8cd0
cmpl -0x94(%rbp), %eax
jne 0x8811
movq -0x8(%rbp), %rdi
movq (%rdi), %rax
leaq 0x6bc1(%rip), %rsi      # 0xf368
movl $0x1, %edx
callq *(%rax)
movl $0x0, -0x2a4(%rbp)
movq -0x8(%rbp), %rdi
movl -0x14(%rbp), %edx
subl -0xd8(%rbp), %edx
leaq -0x2a4(%rbp), %rsi
callq 0x8e10
movq -0x8(%rbp), %rax
movq %rax, -0x318(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x8d70
movq %rax, -0x310(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x8d90
movq -0x318(%rbp), %rsi
movq -0x310(%rbp), %rdx
movl %eax, %ecx
leaq -0x1b8(%rbp), %rdi
callq 0x8ea0
jmp 0x8776
jmp 0x8818
movq -0x8(%rbp), %rdi
movq (%rdi), %rax
leaq 0x6b42(%rip), %rsi      # 0xf368
movl $0x1, %edx
callq *(%rax)
movq -0x8(%rbp), %rsi
leaq -0x1b8(%rbp), %rdi
callq 0x9170
movq -0x8(%rbp), %rsi
leaq -0x290(%rbp), %rdi
callq 0x9170
jmp 0x853f
jmp 0x823e
addq $0x320, %rsp            # imm = 0x320
popq %rbp
retq