embarrassing spaghetti code needs stylistic advice

B

Barry Schwarz

Alright now. I think I've turned a corner with this. And, of course,
everyone who said "use functions!" was spot on.

Hopefully this looks more C-worthy.

lexit-real


#include <ctype.h>
#include <stdio.h>
#include <string.h>

int issign (int c){return !!strchr("+-",c);}
int israd (int c){return !!strchr("#", c);}
int isdot (int c){return !!strchr(".", c);}

Wouldn't return c == '.' be easier?
int ise (int c){return !!strchr("eE",c);}
int isdelim (int c){return !!strchr("()<>{}[]%/",c);}
int isregular(int c){return !isspace(c);}

typedef struct test test;
struct test {
int (*fp)(int); int y,n;
};

You could combine the typedef and the structure definition into a
single declaration.
test decimal[] = {
/* 0*/ { issign, 1, 1 },
/* 1*/ { isdigit, 2, -1 },
/* 2*/ { isdigit, 2, -1 }, //success
};
int dec_accept(int i){ return i==2; }

Would it not work just as well if you eliminated the third element of
decimal and changed this to return i == 1?
test radix[] = {
/* 0*/ { isdigit, 1, -1 },
/* 1*/ { isdigit, 1, 2 },
/* 2*/ { israd, 3, -1 },
/* 3*/ { isdigit, 4, -1 },
/* 4*/ { isdigit, 4, -1 }, //success
};
int rad_accept(int i){ return i==4; }

test real[] = {
/* 0*/ { issign, 1, 1 },
/* 1*/ { isdigit, 2, 4 },
/* 2*/ { isdigit, 2, 3 },
/* 3*/ { isdot, 6, 7 }, //success
/* 4*/ { isdot, 5, -1 },
/* 5*/ { isdigit, 6, -1 },
/* 6*/ { isdigit, 6, 7 }, //success
/* 7*/ { ise, 8, -1 },
/* 8*/ { issign, 9, 9 },
/* 9*/ { isdigit, 10, -1 },
/*10*/ { isdigit, 10, -1 }, //success
};
int real_accept(int i){switch(i){case 3: case 6:case 10:return 1;}
return 0;}

int check(char *buf, test *fsm, int(*yes)(int)){ char *s = buf; int
sta = 0;

Notice how usenet adds line breaks you didn't intend at inopportune
points. Additionally, multiple statements per line tend to hinder
readability.
while(sta!=-1 && *s) {

Why didn't you use buf directly instead of s?
if (fsm[sta].fp(*s))
{ sta = fsm[sta].y; s++; }
else { sta = fsm[sta].n; }
}
sta=yes(sta);
return sta; }

int grok(char *buf) {
if (check(buf,decimal,dec_accept)) { printf( "dec: %s\n",
buf); return 0; }

Here it is even worse. And it destroys your attempt at consistent
indentation.
else if (check(buf,radix, rad_accept)) { printf( "rad: %s\n",
buf); return 0; }
else if (check(buf,real, real_accept)) { printf("real: %s\n",
buf); return 0; }
else { printf("grok? %s\n", buf); return -1; }
}

int puff(char *buf, int nbuf) { char *s = buf; int c;
while ((c=getchar()) != EOF) {

It would be more user friendly if you used '\n' as your terminator
rather than EOF.
if(isspace(c) || isdelim(c))
break;
if(nbuf < s-buf-1)
return -1;
*s++ = c;
}
*s++ = 0;

As a matter of style, recommend '\0' when assigning to a char.
return 0; }

int toke(char *buf, int nbuf) { char *s=buf; int sta = 0;
while(isspace(*s=getchar())) /**/;
if( (sta=puff(buf+1,nbuf-1)) == -1) return -1;

The value assigned to sta is never used.
sta = grok(buf);
return sta; }

#define NBUF 10
int main() { char buf[NBUF] = ""; int sta;
while ( (sta=toke(buf,NBUF)) != -1 )
Ditto.

/**/;
return 0; }
 
L

luser-ex-troll

Wouldn't return c == '.' be easier?

Yes, but I liked the symmetry.
int ise      (int c){return !!strchr("eE",c);}
int isdelim  (int c){return !!strchr("()<>{}[]%/",c);}
int isregular(int c){return !isspace(c);}
typedef struct test test;
struct test {
   int (*fp)(int); int y,n;
};

You could combine the typedef and the structure definition into a
single declaration.

Yes. I think I will. I was considering making the machines recursively
nested instead of arrays, but then I'd have to build them dynamically.
test decimal[] = {
/* 0*/ { issign,  1,  1 },
/* 1*/ { isdigit, 2, -1 },
/* 2*/ { isdigit, 2, -1 }, //success
};
int dec_accept(int i){ return i==2; }

Would it not work just as well if you eliminated the third element of
decimal and changed this to return i == 1?

I think not. That way a single "+" would be interpreted as a decimal
because it terminates in state 1. The 'n' transition is only followed
if there is a next character && it doesn't match.
test radix[] = {
/* 0*/ { isdigit, 1, -1 },
/* 1*/ { isdigit, 1,  2 },
/* 2*/ { israd,   3, -1 },
/* 3*/ { isdigit, 4, -1 },
/* 4*/ { isdigit, 4, -1 }, //success
};
int rad_accept(int i){ return i==4; }
test real[] = {
/* 0*/ { issign,  1, 1 },
/* 1*/ { isdigit, 2, 4 },
/* 2*/ { isdigit, 2, 3 },
/* 3*/ { isdot,   6, 7 }, //success
/* 4*/ { isdot,   5, -1 },
/* 5*/ { isdigit, 6, -1 },
/* 6*/ { isdigit, 6, 7 }, //success
/* 7*/ { ise,     8, -1 },
/* 8*/ { issign,  9, 9 },
/* 9*/ { isdigit, 10, -1 },
/*10*/ { isdigit, 10, -1 }, //success
};
int real_accept(int i){switch(i){case 3: case 6:case 10:return 1;}
return 0;}
int check(char *buf, test *fsm, int(*yes)(int)){ char *s = buf; int
sta = 0;

Notice how usenet adds line breaks you didn't intend at inopportune
points.  Additionally, multiple statements per line tend to hinder
readability.

Yes, irritating, but acknowledged.
Why didn't you use buf directly instead of s?

There isn't a real reason in this function, I justed followed the same
idiom throughout. Again, notions of symmetry.
   if (fsm[sta].fp(*s))
   { sta = fsm[sta].y; s++; }
   else { sta = fsm[sta].n; }
   }
   sta=yes(sta);
return sta; }
int grok(char *buf) {
   if      (check(buf,decimal,dec_accept)) { printf( "dec: %s\n",
buf); return 0; }

Here it is even worse.  And it destroys your attempt at consistent
indentation.

I know. But it's so pretty with 85 columns. I'll split such things for
future postings, but I'm keeping it this way on disk.
It would be more user friendly if you used '\n' as your terminator
rather than EOF.

I don't understand: the program should reject an EOF and demand the
line be finished?! A newline separator is handled by isspace on the
next line.
As a matter of style, recommend '\0' when assigning to a char.

Yes. But it's a pain on my tiny keyboard.
The value assigned to sta is never used.

Yes. I played with these lines more after posting. My favorite is:
(void)( (-1== (sta=puff(s,nbuf-1)) )
|| (-1== (sta=grok(buf)) ) );
   sta = grok(buf);
return sta; }
#define NBUF 10
int main() { char buf[NBUF] = ""; int sta;
   while ( (sta=toke(buf,NBUF)) != -1 )
Ditto.

   /**/;
return 0; }

Thanks a bunch. I'll keep the lines much shorter to guard against ugly
splits. Is there any way to defend against those extra newlines?
 
L

luser-ex-troll

Traced, debugged, sieved, and splinted; is it stylish yet?

There's still a long line (75chars), but with real C comments, it
should be safe for transmission.

/*
590(1)01:42 PM:podvig 0> make t3
cc -g -pedantic -Wall -Wextra -lm t3.c -o t3
591(1)01:43 PM:podvig 0> splint +boolint -boolops -exportlocal t3.c
Splint 3.1.2 --- 23 Aug 2008

Finished checking --- no warnings
592(1)01:43 PM:podvig 0>

*/

#include <ctype.h>
#include <stdio.h>
#include <string.h>

int israd (int c){return (int)'#'==c;}
int isdot (int c){return (int)'.'==c;}
int ise (int c){return !!strchr("eE",c);}
int issign (int c){return !!strchr("+-",c);}
int isdelim (int c){return !!strchr("()<>{}[]%/",c);}
int isregular(int c)
{return c!=EOF && !isspace(c) && !isdelim(c);}

typedef struct test test;
struct test {
int (*fp)(int); int y, n;
};

/* ^[+-]?\d+$ */
test fsm_dec[] = {
/* 0*/ { issign, 1, 1 },
/* 1*/ { isdigit, 2, -1 }, /* [+-]?! ??(\d)?? */
/* 2*/ { isdigit, 2, -1 }, /* [+-]?\d\d* yes! */
};
/*acceptable decimal?*/
int acc_dec(int i){
return i==2;
}

/* ^\d+[#][a-Z0-9]+$ */
test fsm_rad[] = {
/* 0*/ { isdigit, 1, -1 },
/* 1*/ { isdigit, 1, 2 }, /* \d\d* */
/* 2*/ { israd, 3, -1 }, /* \d\d*[^\d] */
/* 3*/ { isalnum, 4, -1 }, /* \d\d*# */
/* 4*/ { isalnum, 4, -1 }, /* \d\d*#\x\x* yes! */
};
/*acceptable radix?*/
int acc_rad(int i){
return i==4;
}

/* ^[+-]?(\d+(\.\d*)?)|(\d*\.\d+)([eE][+-]?\d+)?$ */
test fsm_real[] = {
/* 0*/ { issign, 1, 1 },
/* 1*/ { isdigit, 2, 4 }, /* [+-]? */
/* 2*/ { isdigit, 2, 3 }, /* [+-]?\d\d* yes! */
/* 3*/ { isdot, 6, 7 }, /* [+-]?\d\d*[^\d] */
/* 4*/ { isdot, 5, -1 }, /* [+-]?[^\d] */
/* 5*/ { isdigit, 6, -1 }, /* [+-]?\. */
/* 6*/ { isdigit, 6, 7 }, /* [+-]?(\d\d*)?\.\d* yes! */
/* 7*/ { ise, 8, -1 }, /* [+-]?(\d\d*)?(\.\d*)? */
/* 8*/ { issign, 9, 9 }, /* [+-]?(\d\d*)?(\.\d*)?[eE] */
/* 9*/ { isdigit, 10, -1 }, /* [+-]?(\d\d*)?(\.\d*)?[eE][+-]? */
/*10*/ { isdigit, 10, -1 }, /* [+-]?(\d\d*)?(\.\d*)?[eE][+-]?\d\d*
yes! */
};
/*acceptable real*/
int acc_real(int i){
switch(i) {case 2:case 6:case 10:return 1;}
return 0; }

int czek(char *s, test *fsm, int(*yes)(int)){
int sta = 0;
while(sta!=-1 && *s) {
if (fsm[sta].fp((int)*s))
{ sta = fsm[sta].y; s++; }
else{ sta = fsm[sta].n; }
}
sta=yes(sta); /*did it end in success?*/
return sta; }

int grok(char *s) {
if (czek(s, fsm_dec, acc_dec )) {
printf( "dec: %s\n", s); return 0; }
else if (czek(s, fsm_rad, acc_rad )) {
printf( "rad: %s\n", s); return 0; }
else if (czek(s, fsm_real,acc_real)) {
printf("real: %s\n", s); return 0; }
else {
printf("grok? %s\n", s);
}
return -1; }

int puff(char *buf, int nbuf) {
int c; char *s = buf;
while ( (c=getchar()), isregular(c) ) {
if(s-buf >= nbuf-1) return -1;
*s++ = (char)c;
}
*s = (char)0;
return 0; }

int toke(char *buf, int nbuf) {
int sta = 0; char *s=buf;
while(isspace(*s=(char)getchar())) /**/;
s++;
(void)( (-1== (sta=puff(s,nbuf-1)) )
|| (-1== (sta=grok(buf)) ) );
return sta; }

#define NBUF 10
int main() { char buf[NBUF] = "";
while (-1 != toke(buf,NBUF)) /**/;
return 0; }

/*eof*/
 
K

Keith Thompson

luser-ex-troll said:
Traced, debugged, sieved, and splinted; is it stylish yet?

Just a few random comments; I haven't read it closely enough to make
an overall critique.

[...]
int israd (int c){return (int)'#'==c;}
int isdot (int c){return (int)'.'==c;}

The cast is unnecessary; character constants are already of type int.
(And I personally dislike the "constant == variable" style, but I know
a lot of people like and use it.)
int ise (int c){return !!strchr("eE",c);}

I would have written this as
strchr(...) != NULL
rather than
!!strchr(...)

Trsnss s nt lwys a vrt.

Excuse men, I mean:
Terseness is not always a virtue.

[...]
int toke(char *buf, int nbuf) {
int sta = 0; char *s=buf;
while(isspace(*s=(char)getchar())) /**/;

The cast is unnecessary; without it, the result of getchar() will be
implicitly converted to char by the assignment.

In fact, *most* casts are unnecessary.
s++;
(void)( (-1== (sta=puff(s,nbuf-1)) )
|| (-1== (sta=grok(buf)) ) );
return sta; }

In the statement before the return, you're computing results and
throwing them away -- and discarding clarity along with them. I think
the statement is equivalent to:

if ((sta=puff(s,nbuf-1)) != -1) {
sta=grok(buf);
}

or, even better:

if ((sta = puff(s, nbuf - 1)) != -1) {
sta = grok(buf);
}

#define NBUF 10
int main() { char buf[NBUF] = "";
while (-1 != toke(buf,NBUF)) /**/;
return 0; }

/*eof*/

I find your code layout to be jarring. I'd write the above as:

int main(void)
{
char buf[NBUF] = "";
while (-1 != toke(buf, NBUF)) {
continue;
}
return 0;
}

(Actually there are some other changes I'd make, but I limited myself
to adding the void keyword and changing the layout.)
 
L

luser-ex-troll

Just a few random comments; I haven't read it closely enough to make
an overall critique.

I'm grateful nonetheless.
[...]
int israd    (int c){return (int)'#'==c;}
int isdot    (int c){return (int)'.'==c;}

The cast is unnecessary; character constants are already of type int.
(And I personally dislike the "constant == variable" style, but I know
a lot of people like and use it.)

I chose it here so the 'c's would line up nicely relative to the
strchr counterparts, and then followed through elsewhere for
consistency.
I would have written this as
    strchr(...) != NULL
rather than
    !!strchr(...)

Trsnss s nt lwys a vrt.

Excuse men, I mean:
Terseness is not always a virtue.

With the exception of wooing a Russian princess will billiard chalk, I
agree. I started with no punctuation at all but splint complained
about type mismatching, and with focus on brevity, I opted for the
minimal syntax adjustment (another option was adding -type to splint,
but that seemed to be throwing out the baby).
[...]
int toke(char *buf, int nbuf) {
    int sta = 0; char *s=buf;
    while(isspace(*s=(char)getchar())) /**/;

The cast is unnecessary; without it, the result of getchar() will be
implicitly converted to char by the assignment.

In fact, *most* casts are unnecessary.

Indeed, but splint demands either this or a +charint switch.
In the statement before the return, you're computing results and
throwing them away -- and discarding clarity along with them.  I think
the statement is equivalent to:

    if ((sta=puff(s,nbuf-1)) != -1) {
        sta=grok(buf);
    }

or, even better:

    if ((sta = puff(s, nbuf - 1)) != -1) {
        sta = grok(buf);
    }

Yes. That's 500% better. Thanks.
#define NBUF 10
int main() { char buf[NBUF] = "";
    while (-1 != toke(buf,NBUF)) /**/;
return 0; }

I find your code layout to be jarring.  I'd write the above as:

    int main(void)
    {
        char buf[NBUF] = "";
        while (-1 != toke(buf, NBUF)) {
            continue;
        }
        return 0;
    }

(Actually there are some other changes I'd make, but I limited myself
to adding the void keyword and changing the layout.)

Seriously? 8 lines versus 3? Perhaps my hardware constraints have
suggested more terseness (The olpc xo-1 has a 6"x4.5" lcd), but here I
think it really pays off. It is, after all, a stub for testing the
module before linking into the larger program.

But I'm truly curious to know how you would really format it: blank
lines after declarations and before return?
 
K

Keith Thompson

luser-ex-troll said:
#define NBUF 10
int main() { char buf[NBUF] = "";
    while (-1 != toke(buf,NBUF)) /**/;
return 0; }

I find your code layout to be jarring.  I'd write the above as:

    int main(void)
    {
        char buf[NBUF] = "";
        while (-1 != toke(buf, NBUF)) {
            continue;
        }
        return 0;
    }

(Actually there are some other changes I'd make, but I limited myself
to adding the void keyword and changing the layout.)

Seriously? 8 lines versus 3? Perhaps my hardware constraints have
suggested more terseness (The olpc xo-1 has a 6"x4.5" lcd), but here I
think it really pays off. It is, after all, a stub for testing the
module before linking into the larger program.

But I'm truly curious to know how you would really format it: blank
lines after declarations and before return?

There are several minor style points here on which I'm undecided. I
might put the opening brace for the function either on the same line
as the prototype or on the next line by itself; the former is more
consistent with they way I use braces in other contexts, and the
latter is probably a throwback to K&R C, where parameter declarations
are typically separated from the function declaration.

How to write a loop with an emtpy body is another thing on which I'm
undecided. I always use braces for compound statements, even when
they're not necessary (a habit I picked up from Perl where they're
always mandatory, but I find it safer and more consistent in C as
well). I used the "continue" keyword here because I think it clearly
expresses what's going on; I might use an empty comment instead if I
were in the mood. I wouldn't use
while (condition);
because it's just too terse for my tastes, and too easy to mistake for
a typo. Your own empty comment on the same line isn't bad.

I might put a blank line between the declarations and statements, but
I might not bother for something this small.

I think I see why you put the return statement on a different
indentation than the rest of the function body, but I wouldn't do it
that way; syntactically, return is just another statement. And I
really dislike putting code on a line after a '{', or before a '}'.

Here's another way I might write it if I were a bit more concerned
with vertical space.

int main(void) {
char buf[NBUF] = "";
while (toke(buf, NBUF) != -1) continue;
return 0;
}

In real life, I'd follow my employer's coding standards if I were
writing code for work, or the style of the existing code if I were
working on an existing project. But if I were writing my own code for
my own purposes, I'd feel free to indulge my own idiosyncracies (which
are of course far more rational and consistent than everyone else's
idiosyncracies).
 
L

luser-ex-troll

luser-ex-troll said:
#define NBUF 10
int main() { char buf[NBUF] = "";
    while (-1 != toke(buf,NBUF)) /**/;
return 0; }
/*eof*/
I find your code layout to be jarring.  I'd write the above as:
    int main(void)
    {
        char buf[NBUF] = "";
        while (-1 != toke(buf, NBUF)) {
            continue;
        }
        return 0;
    }
(Actually there are some other changes I'd make, but I limited myself
to adding the void keyword and changing the layout.)
Seriously? 8 lines versus 3? Perhaps my hardware constraints have
suggested more terseness (The olpc xo-1 has a 6"x4.5" lcd), but here I
think it really pays off. It is, after all, a stub for testing the
module before linking into the larger program.
But I'm truly curious to know how you would really format it: blank
lines after declarations and before return?

There are several minor style points here on which I'm undecided.  I
might put the opening brace for the function either on the same line
as the prototype or on the next line by itself; the former is more
consistent with they way I use braces in other contexts, and the
latter is probably a throwback to K&R C, where parameter declarations
are typically separated from the function declaration.

How to write a loop with an emtpy body is another thing on which I'm
undecided.  I always use braces for compound statements, even when
they're not necessary (a habit I picked up from Perl where they're
always mandatory, but I find it safer and more consistent in C as
well).  I used the "continue" keyword here because I think it clearly
expresses what's going on; I might use an empty comment instead if I
were in the mood.  I wouldn't use
    while (condition);
because it's just too terse for my tastes, and too easy to mistake for
a typo.  Your own empty comment on the same line isn't bad.

I might put a blank line between the declarations and statements, but
I might not bother for something this small.

I think I see why you put the return statement on a different
indentation than the rest of the function body, but I wouldn't do it
that way; syntactically, return is just another statement.  And I
really dislike putting code on a line after a '{', or before a '}'.

Here's another way I might write it if I were a bit more concerned
with vertical space.

    int main(void) {
        char buf[NBUF] = "";
        while (toke(buf, NBUF) != -1) continue;
        return 0;
    }

In real life, I'd follow my employer's coding standards if I were
writing code for work, or the style of the existing code if I were
working on an existing project.  But if I were writing my own code for
my own purposes, I'd feel free to indulge my own idiosyncracies (which
are of course far more rational and consistent than everyone else's
idiosyncracies).

Thanks. This is exactly what I've been itching for.

My final super-terse version actually began like the 5-line version
here. Then while doing lots of scrolling up and down I thought: J J
<< . And then it seemed nice to put the return type and the return
value on the same level to help keep straight when the int is
representing true/false as 1/0 or 0/-1. I don't plan on adopting this
format as a general habit, but the specific situation suggested a
benefit.

Fortunately, I am at my own mercy for decisions of this sort, but that
makes me responsible for the decision as well.

For most purposes I agree with your recommendations and appreciate the
sound ground upon which they stand.
 
L

luser-ex-troll

That's not the entire problem.
Sometimes the next line can be easily mistaken
for part of the loop.

what about?

while(condition) { /* :) ;) */; }

smiles are free!
 
K

Keith Thompson

luser-ex-troll said:
what about?

while(condition) { /* :) ;) */; }

smiles are free!

It's cute.

Determining whether I meant that as a compliment is left as an
exercise.
 
L

luser-ex-troll

[...]
what about?
while(condition) { /* :) ;) */; }
smiles are free!

It's cute.

Determining whether I meant that as a compliment is left as an
exercise.

Though that remain a mystery (subjunctive, right? cause /he/ knows),
this thread should provide useful fodder for anyone searching the
archive for replacing gotos, coding a finite state machine to execute
a regular expression, how to make C look like something else, and
unnecessary cuteness.
 
N

Nate Eldredge

luser-ex-troll said:
nice. but what about:

while(condition){;}

I personally tend to write

while (condition) ;

I think the added space draws more attention to the empty body, since I
ordinarily don't leave spaces before semicolons at the end of a statement.

I also sometimes do

while (condition) /* keep going */ ;
 
C

CBFalconer

Richard said:
CBFalconer said:

Putting the 'continue' on a separate line makes it clearer exactly
when the condition is met (when stepping through the code with a
debugger - not something I do a lot nowadays, but I used to, and
some people still do). And using the (optional) braces to mark off
the loop body is a good habit to get into, as it can save all kinds
of embarrassment later when the loop is maintained.

Since those are not among my objectives, I would do none of them.
 
N

Nate Eldredge

pete said:
I don't like to write trivial comments.
The thing about comments, especially trivial ones,
is that they don't always get updated
when the code changes when the programmers are busy
trying to get the code to do what they want it to do.

It's a good point. I think this is a little different from the usual

x = 3; /* assign 3 to x */

because in some sense the comment *is* the code. But it's a subtle
distinction even in my mind.
 
F

Flash Gordon

Nate said:
I personally tend to write

while (condition) ;

I think the added space draws more attention to the empty body, since I
ordinarily don't leave spaces before semicolons at the end of a statement.

I also sometimes do

while (condition) /* keep going */ ;

Someone else once suggested
while (condition) continue;
I decided I like it so now use it.
 
P

Phil Carmody

CBFalconer said:
Since those are not among my objectives, I would do none of them.

You never intend to maintain your code? Yikes, that's a
scary attitude.

Phil
 
P

Phil Carmody

Unwrapping the echelon, putting names next to styles:
while (condition) {
;
}

while(condition){;}

Nate Eldredge wrote:
while (condition) ;
while (condition) /* keep going */ ;


while (condition) continue;


I can see continue's merits. I might try that and see if it fits.
I find I don't use continue for anything (I've even worked in a
company where it was against the coding standards as it was a
'confusing minority technique' or some crap like that), so it
seems as if it might feel odd typing it. At least the first few
times.

Traditionally I'm between Pete and l-e-t:
while(condition) { ; }
as I like to draw a little attention, but only a little, to the
empty block. I'm a religious block-rather-than-statement user.

Phil
 
K

Keith Thompson

I dare say you have; people have all sorts of notions. Perhaps I
am wrong but I would have supposed that good coders indent only
when a new block is started or when a single statement is being
written on more than one line. (Or in special situations not
covered by these two cases. :))
[...]

I've seen too many cases where the indentation is inconsistent because
the author had a different tabstop setting than I do (e.g., 4 columns
vs. 8). I've even seen inconsistencies within the same file, where
apparently two maintainers had different tabstop settings.

Coding standards should ban the use of tab characters in C source
code.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top