On Wed, Mar 18, 2026 at 06:13:59PM +0100, Alejandro Colomar via Mutt-dev wrote:
I don't know if there are any other formatters that would be good.

astyle has a reputation for being ok-ish. maybe worth a try.

And I don't think writing a formatter from scratch just for mutt(1)
would be reasonable.

says WHO?! :-D

of course it would be bonkers to create a full formatter, but a simple solution that gets 99% done is easy enough. in fact, i did just that a quarter century ago for my projects. i'm attaching it for everyone's masochistic enjoyment. :-)=)

#! /bin/bash
# XXX this does not handle c++ namespacing.
# XXX this becomes *incredibly* slow for some files -
# have to replace the regexp voodoo with a proper parser, i guess.
# ki18n( "str" ) => ki18n( "str") ?!

me=$(me)
typefile=typedefs.out

it=
ot=
while [ $# -gt 0 ]; do
  case $1 in
  -it) it=$2; shift 2;;
  -ot) ot=$2; shift 2;;
  -h) echo "Usage -it <m> -ot <n> file..."; exit 0;;
  -*) echo "Unrecognized option $1"; exit 1;;
  *) break;;
  esac
done
if [ -z "$it" -o -z "$ot" ]; then
  echo "Must specify both -it and -ot."
  exit 1
fi

if ! test -f $typefile; then
  echo "Collecting types ..."
  find . \( -name '*.c' -o  -name '*.cpp' -o -name '*.h' \) -exec cpp 
-DHAVE_CONFIG_H -I. -I.. -I../.. {} \; 2>/dev/null | \
    perl ${me}_collect.pl | sort -u | tr '\n' '|' | sed 's,|$,,' > $typefile
fi

maybe_expand() {
  if [ $it -gt 0 ]; then
    expand -i -t $it | "$@"
  else
    "$@"
  fi
}

maybe_unexpand() {
  if [ $ot -gt 0 ]; then
    unexpand -t $ot --first-only | "$@"
  else
    "$@"
  fi
}

pty=$(<$typefile)
for i in "$@"; do
  echo "Indenting $i ..."
  maybe_expand maybe_unexpand perl ${me}_spacing.pl "$pty" < $i | perl 
${me}_lineup.pl > $i.tmp && mv $i.tmp $i
done

exit 0
#! /usr/bin/perl

use strict;
use warnings;
use re "eval";

my ($btypes, $bt, $ctypes, $np, $wrd);
$bt = $btypes = "void
(?:(?:un)?signed\\s+)?(?:short\\s+|long\\s+(?:long\\s+)?\\s+)?int
(?:(?:un)?signed\\s+)?(?:short|long(?:\\s+long)?)
(?:un)?signed
(?:(?:un)?signed\\s+)?char
float
(?:long\\s+(?:long\\s+)?)?double";
$ctypes = "(?:struct|union)\\s+\\w+";
$bt =~ s/\n/|/g;
$np = qr{\{(?:(?>[^{}]+)|(??{$np}))*\}}x;
$wrd = qr{(?>\s*)(?>\**)(?>\s*)((?>\b\w+\b))(?{print $^N."\n"})(?>\s*)}x;
read STDIN, $_, 1e9;
s/^\s*typedef\s+(?:$bt\s|(?:struct|union)(?>\s+)(?>\b\w+\b\s+)?(??{$np})|$ctypes\s)$wrd(?:,$wrd)*;//xmg;
s/^\s*class\s+(\w+)(?{print $^N."\n"})//xmg;
print $btypes."\n".$ctypes."\n";
#! /usr/bin/perl

use strict;
use warnings;
use re "eval";

my $pty = $ARGV[0];
my $skw = "if|switch|for|while|return";
my $nskw = "sizeof|offsetof|defined|as|ki18n|i18n|i18nc|i18np|i18npc|I18N_NOOP|I18N_NOOP2|QString::fromLatin1|QLatin1String|SIGNAL|SLOT";

# remove trailing whitespace, append exactly one space after semicolon
sub stws($)
{
  local $_ = shift;
  s/ *$//;
  s/(?<!;);$/; /;
  return $_;
}

my ($np, $fp, $pc);
# complex expression: n times (word or basic expression or parenthesized complex expression)
$pc = qr{
    (?:
        (?>[^()]+)
      |
        (??{$fp})
      |
        (??{$np})
    )*
}xs;
# parenthesized complex expression
$np = qr{\($pc\)}s;
# basic expression: function( n times complex expression )
$fp = qr{
    (
        \b(?:
            new(?>\s+)
          |
            (?!$pty|$skw|$nskw|else)
        )
        (?:\w|\.|::)+
      |
        \(
        \h*\*\h*
        (?:
            (?>[^()]*)
          |
            (??{$np})
        )*
        \)
    )
    (?>\s*)
    \(
    (?>\h*)
    ($pc)
    \)
}xs;

sub ffn($)
{
  local $_ = shift;
  # fix whitespace around function calls
  # XXX maybe correct parens in $1, too?
  s/$fp/my ($f, $p) = ($1, $2); $f."( ".stws(&ffn($p))." )"/eg;
  # fix whitespace around function-like (pseudo-)operators
  s/\b($nskw)\s*\(\s*(?!{~)($pc)\)/my ($o, $p) = ($1, $2); $o."(".stws($p).")"/eg;
  # fix whitespace around c-style type casts
  s/(?<!sizeof)\(($pty)\ *(\**)\ *\)\ *(?!{~)/"(".$1.($2?(" ".$2):"").")"/eg;
  return $_;
}

read STDIN, $_, 1e6;
my @subs = ();
my $csub = 0;
# replace strings and comments with {~###~} tokens
s/(\/\*.*?\*\/|\/\/.*?$|"(?:\\.|[^"])*"|^#(?:\\.|[^\n])+(?:\\\n(?:\\.|[^\n])*)*(?=\n))/push(@subs, $1), "{~".($csub++)."~}"/egsm;
# majority of the conversion
$_ = ffn($_);
# fix whitespace around control statements
s/\b($skw)\s*\(\s*(?!{~)($pc)\)/$1." (".stws($2).")"/eg;
# remove spaces between otherwise empty paren pairs
s/\( +\)/()/g;
# convert non-leading tabs to spaces
s/(?<!^)(?<!\t)\t+/ /mgx;
# replace the {~###~} tokens back with strings
for (my $i = 0; $i < @subs; $i++) {
  s/{~$i~}/$subs[$i]/e;
}
s/[ \t]+$//mg;
print $_;
#! /usr/bin/perl

use strict;
use warnings;

my $il = "";
my $cmt = 0;
my @pcs = ();
my $cpp = 0;
my @ifst = ();
my $els = 0;
my @elst = ();

while (<>) {
  if ($cpp) {
    $cpp = /\\$/;
  } elsif (/^#/) {
    if (/^#\ *if/) {
      push @ifst, ($il, @pcs);
      push @elst, $els;
      $els = 0;
    } elsif (/^# *elif/) {
      ($il, @pcs) = $ifst[$#ifst];
    } elsif (/^# *else/) {
      ($il, @pcs) = pop @ifst;
      $els = 1;
    } elsif (/^# *endif/) {
      if (!$els) {
        ($il, @pcs) = pop @ifst;
      }
      $els = pop @elst;
    }
    $cpp = /\\$/;
  } else {
    $cmt = 1 if /^([ \t]*)\/\*/;
    if (!$cmt) {
      if (@pcs) {
        s/^[ \t]*/$il.(" " x ($pcs[$#pcs] - length($il)))/e;
      } else {
        /^([ \t]*)/;
        $il = $1;
      }
      /^(?>[ \t]*)(?:\((?>\ *)(?{push @pcs, pos;})|\)(?{pop @pcs;})|\/\*.*?\*\/|'(?:\\.|[^'])*'|"(?:\\.|[^"])*"|.)*$/x;
    }
    $cmt = 0 if /\*\/$/;
  }
  print $_;
}
#! /bin/bash
type -p `tr '\0' '\n' < /proc/$PPID/cmdline | sed '1d;/^-/d;q'`

Reply via email to