473,383 Members | 1,801 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,383 software developers and data experts.

Text-Based Windows Library

Where can I find a library to created text-based windows applications?
Im looking for a library that can make windows and buttons inside
console.. Many old apps were make like this, i guess

____________________________________
| |
| ------------------ |
| | BUTTON | |
| ------------------ |
| |
| |
L_________________ _________________|

I tried to draw a window here, but im looking for something better
than that,,huahua

Apr 12 '07
95 4926
On Apr 17, 7:20 pm, Keith Thompson <k...@mib.orgwrote:
user923005 <dcor...@connx.comwrites:
On Apr 17, 4:18 pm, Keith Thompson <k...@mib.orgwrote:
user923005 <dcor...@connx.comwrites:
[...]I have seen (for instance) scanf() or sscanf() used with %s used for
reading a string, written by good programmers. This is (of course)
exactly the same danger as gets().
[...]
A "good" programmer would not use scanf() with "%s".
That's false, because good programmers have done it. It's not common,
but it happens.

[...]

Define "good programmer".

Here's a proposed definition: A "good programmer" is one who never
uses scanf() with "%s".
And a good driver never runs a stop sign or exceeds the speed limit.
And a good husband never yells at family members.
And a good lawyer always wins his cases when he is in the right.
But all of us can (and do) make mistakes.
And yes, that's a gross exaggeration. All programmers, even good
ones, make mistakes, and I don't seriously mean to denigrate the
anyone's skills.
Right.
But I know of no programming language in which it is particularly
difficult to write bad code.
I agree. Every language can be used to write bullet-proof treasures.
Every language can be used to write haphazard slop.

I happen to like the C language very much. However, when I see a
fault, I don't say "That's not a fault." Instead, I say "Yes, it's a
defect. So here is how we work around it..."
In fact, you (and all the other C supporters) have been doing the very
same thing. They have been saying "If you are really smart and really
careful you will avoid mistakes." This is (of course) the basic
definition of smart and careful. But no matter how smart or how
careful you are, mistakes are possible. The possibility of error does
not render a tool useless. After all, even a skilled craftsman will
peg himself with a hammer once in a blue moon. I still want my house
built, and I still want a craftsman, and I even still want him to use
the hammer. But when we come to a tool with lots of sharp edges and
that occasionally emits showers of sparks, I want to mention that this
tool is 'dangerous' and even that it might not be a bad idea to think
about ways of improving the tool.

There are no ideal computer languages. C is a very good one because:
1. It is easy to learn
2. It is very efficient
3. It has a certain terse elegance

On the other hand, the C language is not without faults. It is a good
thing to admit to these faults. It is even better to help others
avoid the dangerous bits by explaining the dangers. And it is
ultimately good to eventually repair all of the faults.

IMO-YMMV.

Apr 18 '07 #51
user923005 said:
On Apr 17, 3:14 pm, Kelsey Bjarnason <kbjarna...@ncoldns.comwrote:
>>
Okay, I don't see the problem. You created a char array - not a
string, simply a char array - and passed it to a function that
expects a string.

The only difference between a character array and a string in the C
language is the contents.
Not so. Here's another difference, just to prove my point: there is no
string type in C, whereas there are plenty of character array types.

Now, your "only difference" is a very important difference. strstr
requires a string as input. If you give it something that is not a
string, I fail to see how this is the fault of strings, since no
strings are involved. What you seem to be saying is that it's dangerous
*not* to use strings.

Yes, buffer overrun exploits are a problem in C, but this has about as
much to do with strings as red light violations have to do with cars.
The car itself is not actually the problem.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Apr 18 '07 #52
On Apr 17, 9:06 pm, Richard Heathfield <r...@see.sig.invalidwrote:
user923005 said:
On Apr 17, 3:14 pm, Kelsey Bjarnason <kbjarna...@ncoldns.comwrote:
Okay, I don't see the problem. You created a char array - not a
string, simply a char array - and passed it to a function that
expects a string.
The only difference between a character array and a string in the C
language is the contents.

Not so. Here's another difference, just to prove my point: there is no
string type in C, whereas there are plenty of character array types.
Right. A serious defect to be sure.
Now, your "only difference" is a very important difference. strstr
requires a string as input. If you give it something that is not a
string, I fail to see how this is the fault of strings, since no
strings are involved. What you seem to be saying is that it's dangerous
*not* to use strings.
I have already agreed that the difference between a string and an
array is the contents.
Yes, buffer overrun exploits are a problem in C, but this has about as
much to do with strings as red light violations have to do with cars.
The car itself is not actually the problem.
Cars also kill people from time to time. There are some things about
cars that are clearly unsafe. If the brakes are bad and you hit
someone in a car you borrowed, it was not the driver but the car.
C strings are the bad brakes in the C language.
To pretend that they are not a problem despite the billions of dollars
of damage that has been done directly due to their use by highly
intelligent programmers is a disservice to those who wish to
understand the language.

An acetylene torch is a dangerous thing. You can do lots of wonderful
things with it. Maybe, if it was safer, it would be a lot harder to
get the work done. But when someone comes along and wants to learn
how to weld, I think it prudent to tell the welding student that the
yellow (and sometimes blue) thing that comes out of the end of the
torch is dangerous. If we tell them that it is completely safe, then
we are lying. Not only that, but they are far more liable to damage
of some sort than if properly instructed.

To tell anyone that C strings are safe is a fabrication because the
evidence proves that they are very, very dangerous.
C strings are a box of sweating dynamite. If I said that anything
else had caused billions of dollars of damage in the hands of experts
who were trying their very best not to damage anything, I think you
would admit that it was dangerous.

Look, there's this girl. Both of us think she's amazing. She's
highly intelligent with a quick wit, and pleasant to look at. She has
beautiful flowing hair, is a wonderful conversational master and is
highly athletic. But when something funny happens, she laughs like a
donkey.
Now, that does not change anything about how we feel about her. We
look past the donkey-laugh because of all the other wonderful
qualities. But let's not pretend the donkey-laugh is the best
sounding laugh we ever heard. It's OK for something to be imperfect,
especially if it is possible to change it.

Clearly, C strings are a problem because of all the damage they
cause. If it was only a million dollars here or there, we could say
"Heck, it's only a few million." But despite recognition of the
problem and decades of work trying to clean it up, we still have
billions and billions of dollars of damage flooding forward with no
end in sight. Why not just admit the problem and say, "C strings can
cause problems, even with good programmers because we all make
mistakes. Maybe we should take a look at ways to improve things."

I guess we will probably just end up having to disagree about it.
Quite frankly it is so plain to me that I really cannot imagine how it
is possible to think that they are not a problem. But my opinion is
no better than anyone else's and it is always possible that it is me
who hasn't quite got it right.

Apr 18 '07 #53
Richard Heathfield wrote:
user923005 said:
On Apr 17, 3:14 pm, Kelsey Bjarnason <kbjarna...@ncoldns.comwrote:
Okay, I don't see the problem. You created a char array - not a
string, simply a char array - and passed it to a function that
expects a string.
The only difference between a character array and a string in the C
language is the contents.

Not so. Here's another difference, just to prove my point: there is no
string type in C, whereas there are plenty of character array types.
Note the phrase: "there is no string type in C".
Now, your "only difference" is a very important difference. strstr
requires a string as input.
I'm confused....if there is no string type in C, but strstr
requires a string as input, then what exactly is it that
strstr is expecting as input? For the most part,
I agree that C has no string type, but I also agree
that strstr takes a string as an argument. Someone
(I believe user923005) said else thread that strings
in C are a problem and a reasonable person would
recognize them as being a problem and say "here's
how we work around it." I think it's more accurate to
say that the lack of any support for strings is an aspect
of the language (no judgment on whether it's good or
bad intended) and the "workaround" was to use the
English word "string" to refer to any null-terminated
character array, and all sorts of problems have
followed because of that decision.
If you give it something that is not a
string, I fail to see how this is the fault of strings, since no
strings are involved. What you seem to be saying is that it's dangerous
*not* to use strings.

Yes, buffer overrun exploits are a problem in C, but this has about as
much to do with strings as red light violations have to do with cars.
The car itself is not actually the problem.
I agree (almost). Buffer overrun exploits are a problem in computers.
Programs which are built from C are more prone
to them because the C language provides less protection than
do other languages. Else-thread, the analogy of a suit of
armor with a hole over the chest was given, and this is exactly
the wrong analogy. C isn't armor. It doesn't claim to be armor,
and it never claimed to be armor. It's a tool. If you want armor,
you'd be pretty stupid to strap a hammer on your chest and
complain that it doesn't protect you adequately.

--
Bill Pursell
Apr 18 '07 #54
user923005 said:

<snip>
I guess we will probably just end up having to disagree about it.
I guess you're right there, at least. You see, your analogies don't work
for me.
Quite frankly it is so plain to me that I really cannot imagine how it
is possible to think that they are not a problem.
And likewise, I can't imagine how it is possible to think that they are
- except that I know my good friend user923005, whose opinion I
respect, considers them to be a problem. But, whilst I take your
opinion seriously, I can't bring myself to agree with it. Strings are
not dangerous, and that's flat. Yes, I will grant that there are some
tools around that don't do their job very well (e.g. gets(),
scanf("%s", s) etc), but to blame strings for that is to miss the
point, I feel.

But my opinion is
no better than anyone else's and it is always possible that it is me
who hasn't quite got it right.
Your opinion *about C* carries a fair amount of weight compared to most
other people's, because it is evident that you have studied the
language in depth. Nevertheless, on this occasion I cannot agree with
you. That may, of course, mean that I'm wrong and you're right. But
obviously I don't think so (otherwise I'd have changed my mind!).

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Apr 18 '07 #55
Bill Pursell said:

<snip>
I'm confused....if there is no string type in C, but strstr
requires a string as input, then what exactly is it that
strstr is expecting as input?
A string. That is, a sequence of characters terminated by the first null
character.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Apr 18 '07 #56
On Apr 17, 10:34 pm, Richard Heathfield <r...@see.sig.invalidwrote:
Bill Pursell said:

<snip>
I'm confused....if there is no string type in C, but strstr
requires a string as input, then what exactly is it that
strstr is expecting as input?

A string. That is, a sequence of characters terminated by the first null
character.
The point Richard was making was that there is no object type of
string in C.
The word string is used freely in K&R and in the standard, but never
in reference to a type.

A string is really a convention. We decide that an array that has a
zero element in it will describe a string of data.

We could say that C has a language feature of strings. But those
strings are not really types.
Apr 18 '07 #57
Bill Pursell <bi**********@gmail.comwrites:
[...]
I'm confused....if there is no string type in C, but strstr
requires a string as input, then what exactly is it that
strstr is expecting as input?
[...]

strstr() takes two arguments, of course.

Each argument must be a char* (a type, enforced at compile time) *and*
each argument must point to a string (a data format, not enforced at
compile time). If you try to give it something other than a char*,
your program won't compile. If you give it a char* that doesn't point
to a string (either because it doesn't point to *anything*, or because
it points to something other than a string) you invoke undefined
behavior.

A "string" is, by definition, "a contiguous sequence of characters
terminated by and including the first null character". It's a data
format, not a data type.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Apr 18 '07 #58
On Apr 17, 7:20 pm, Keith Thompson <k...@mib.orgwrote:
user923005 <dcor...@connx.comwrites:
On Apr 17, 4:18 pm, Keith Thompson <k...@mib.orgwrote:
user923005 <dcor...@connx.comwrites:
[...]I have seen (for instance) scanf() or sscanf() used with %s used for
reading a string, written by good programmers. This is (of course)
exactly the same danger as gets().
[...]
A "good" programmer would not use scanf() with "%s".
That's false, because good programmers have done it. It's not common,
but it happens.

[...]

Define "good programmer".

Here's a proposed definition: A "good programmer" is one who never
uses scanf() with "%s".

And yes, that's a gross exaggeration.
Yes, but why is this or any other definition of a good C programmer so
esoteric? And why does a bad C programmer cost the industry billions,
while a bad Java programmer costs the industry far less?
[...] All programmers, even good
ones, make mistakes, and I don't seriously mean to denigrate the
anyone's skills.

But I know of no programming language in which it is particularly
difficult to write bad code.
So all code is bad in an equivalent way?

I know of no programming language (besides C++ and other C variants)
even *CLOSE* to C in its level of danger (especially with regards to
buffer overflows) and undefined behavior. (Note here that assembly
language is *far* safer by this measure.)

Besides, I doubt you have tried Python. It actually *IS* hard to
write bad code in Python -- at least not if you are at least *some*
kind of a programmer. You have to write a few functions and mismatch
types intentionally before you run into anything you could call a
typical anomaly.

But at the end of the day, one can see that there is a technical
equivalency between C and Ada or Pascal on the ability to dereference
dead pointers or leak memory or whatever. So why is C so ridiculously
more unsafe that those languages?

You can't claim C's strings are more powerful than alternatives. My
bstring library puts the C standard functions to shame in terms of
power: 1) You cannot make reference based non-tail substrings of a C
string without modifying it 2) You cannot call any mutating C string
library function calls with aliased string parameters (unless you
consider memmove a string function). 3) The C library has no way of
emulating a file on top of a string (available as an extension in gcc,
but as a portable abstraction in Bstrlib). 4) C strings cannot
contain arbitrary binary contents ('\0' is always a terminator) so a C
string cannot hold both the input and output of encrypted or
serialized data streams. But of course my library is written *in C*
so you can't claim that the C language found some ideal trade off --
they did nothing of the sort. C's strings are in fact *LESS* powerful
than is found in most other languages, and as Bstrlib demonstrates
that its only because C's library was badly designed.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Apr 18 '07 #59
Obviously, there are two streams of thought here, those that think there
is a problem, and those that don't. And some people think that there is
a C string type.

Those that say there isn't a problem, and that it is the programmer's
fault perhaps have forgotten that seat belts were introduced into cars
(and variable crumple rates) to protect people if an accident happens.
It is true that an accident is caused by cars (well, most cars...) but
rather the driver. And it is precisely because drivers do cause
accidents, we have safer cars. Indeed, cars handle much better than
they used to, and have many more safety features built in. And computer
languages should be safer, rather than not (safer). We ALL make mistakes!

And for those people that suggest that C does have a string type, I
would suggest that it doesn't, compared with Pascal, PL/I, COBOL or even
Assembler. It has an array of characters, which is quite different from
a string.

For example, in PL/I, one could write:

Dcl String10 char(10) varying;
Dcl String20 char(20) varying init
('Long 20 Character XX');
String10-string20;

This will automatically truncate the result, rather than copy the 20
bytes and overwrite adjacent storage, as in C.

And so naturally, I agree with those that say there is a problem.
What is needed is for ANSI to bite the bullet and fix the problem. Or
for someone big, like IBM to do it, and force a standard change. (As an
aside, there is a language called D, which has a length word for
strings, I believe. It is written by Walter Bright, who wrote the
original Zortech C compilers. Bright by name, bright by nature... I
think it uses the GCC C compiler as a backend.)

But I shall write to ANSI now. Again, I think....

The thing is that there is quite a lot of straight C code making it's
way into IBM's Z/OS at the moment. And it should take into account
these performance robbing routines, because mainframes usually run
thousands of programs at once, rather than the tens or hundreds that a
Linux box might. Therefore, overheads need to be kept to a minimum (as
they should always be...).
Clem
Apr 18 '07 #60
Keith Thompson wrote:
Bill Pursell <bi**********@gmail.comwrites:
[...]
I'm confused....if there is no string type in C, but strstr
requires a string as input, then what exactly is it that
strstr is expecting as input?
[...]

strstr() takes two arguments, of course.

Each argument must be a char* (a type, enforced at compile time) and
each argument must point to a string (a data format, not enforced at
compile time). If you try to give it something other than a char*,
your program won't compile.
To nitpick, you can also give it a void*, or any other pointer cast to
char* or void*.

Brian

Apr 18 '07 #61
Clem Clarke <os*********@ozemail.com.auwrites:
[...]
And for those people that suggest that C does have a string type, I
would suggest that it doesn't, compared with Pascal, PL/I, COBOL or
even Assembler. It has an array of characters, which is quite
different from a string.
[...]

Those people who suggest that C has a string type simply need to read
the standard, or any decent textbook. C doesn't have a string type,
and I'm not aware that there's any real controversy on that point.
It's understandable that someone not familiar with the language might
not know that.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Apr 18 '07 #62
Kenneth Brody <ke******@spamcop.netwrote:
It's "dangerous" in that a newbie doesn't see the difference between:

char token[6] = "123456";
and
char token[] = "123456";

After all, they only see 6 chars in both.

And, as far as the compiler is concerned, both can be passed to
strstr() without issue.

However, a language that prevents a newbie from doing anything that
you can call "dangerous" is also not going to allow an experienced
programmer from doing anything beyond newbie-stuff.

With power comes responsibility.
It seems to me that the responsible thing to do is to use "safe"
strings unless performance is absolutely critical, otherwise you're
just putting your users at risk.
Apr 18 '07 #63
On Apr 18, 2:29 pm, Ed Jensen <ejen...@visi.comwrote:
Kenneth Brody <kenbr...@spamcop.netwrote:
It's "dangerous" in that a newbie doesn't see the difference between:
char token[6] = "123456";
and
char token[] = "123456";
After all, they only see 6 chars in both.
And, as far as the compiler is concerned, both can be passed to
strstr() without issue.
However, a language that prevents a newbie from doing anything that
you can call "dangerous" is also not going to allow an experienced
programmer from doing anything beyond newbie-stuff.
With power comes responsibility.

It seems to me that the responsible thing to do is to use "safe"
strings unless performance is absolutely critical, otherwise you're
just putting your users at risk.
Uhh ... are you making a false choice here -- I mean a *REALLY REALLY*
false choice? Length delimited strings are both safer *AND* faster.
Truly the only advantage of using C's raw char * strings is where you
want to minimize your code size footprint. Otherwise, using an
alternative is usually always better.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Apr 18 '07 #64
[snips]

On Tue, 17 Apr 2007 18:55:34 -0400, Kenneth Brody wrote:
It's "dangerous" in that a newbie doesn't see the difference between:

char token[6] = "123456";
and
char token[] = "123456";

After all, they only see 6 chars in both.
As you said, "newbie". Someone not properly competent to be releasing
software unto the world - nor likely to do so, one would hope.
And, as far as the compiler is concerned, both can be passed to strstr()
without issue.
If so, then there's no problem and the issue is irrelevant.

Whoops... there *is* a problem, because they cannot both be passed to
strstr without issue; one of them distinctly does have issues, because -
as noted previously - you cannot chuck incorrect data about and expect to
get correct results.
With power comes responsibility.
Indeed; as a programmer you have the power to corrupt data, crash systems,
wreak all kinds of havoc; if you haven't got enough responsibility to get
something as basic as your data types right, you have no business
releasing your software on an unsuspecting world.
Apr 18 '07 #65
[snips]

On Wed, 18 Apr 2007 14:53:58 -0700, websnarf wrote:
Uhh ... are you making a false choice here -- I mean a *REALLY REALLY*
false choice? Length delimited strings are both safer *AND* faster.
Are they? Doesn't that depend on how they're implemented? Take a simple
example: looping over the characters in a string. Here's a couple
different ways:

size_t idx;
for ( idx = 0; idx < string.length(); idx++ )
...

size_t idx;
for ( idx = 0; idx < string.length; idx++ )
...

char *ptr = string;
while( *ptr++ )
...

Depending on what's in "..." the first may actually require a
re-evaluation of length() at each iteration. Now, length() may do nothing
but returning a value from inside a structure, but it's still got the
overhead of a function call on top of the comparison.

The second strikes me as likely to be the fastest of the lot... but if the
length member is exposed this way, it also strikes me as risking it being
changed outside the scope of the proper string operators - thus making the
"safe" part of "safe strings" somewhat questionable.

The last method relies solely on the data in the string and has the
overhead of incrementing a pointer, rather than calling a function: while
neither is guaranteed to be faster or slower than the other, experience
suggests that pointer increments tend to be faster than function calls.

The only particular dangers with the last option are what happens if
"string" is freed inside the loop, or altered to be shorter than where ptr
is currently pointing? Certainly possible, but I can't say I've ever seen
the latter happen... and the former is one of those things you test for
anyhow if there's a risk of it happening.

It seems to me there are cases where "safe strings" can certainly be
faster than conventional strings, but it seems as well there are cases
where the speed gains are very much in doubt.
Apr 18 '07 #66
[snips]

On Tue, 17 Apr 2007 18:31:27 -0700, user923005 wrote:
I can show you literally dozens of posts -- written in this forum by
experts respected by all -- that contain buffer overrun exploits.
In released production code, or in something tossed off here on the spur
of the moment with minimal testing and no code review?
There is no debate as to whether the construct is dangerous or not.
The fact that it has caused billions of dollars of damage means that
it *is* _by definition_ dangerous.
That doesn't make the construct dangerous, it makes improper use of it
dangerous. A hammer is not particularly dangerous in and of itself, but
used incorrectly - say by dropping it off a tall building - can be fatal.
Does this mean the hammer is improperly designed and it should have been
made out of soft foam? Or does it mean that any tool, in the hands of
people failing to apply due care and diligence, can be dangerous?
I belive that those who say that C strings are not dangerous are not
clear thinkers, or are simply so in love with C that they refuse to
look at the wart on her nose and say that it is anything less than
breathtakingly beautiful.
Or they simply wish to point the blame where it belongs. Replacing all
the tools in your toolbox with replacements made by Nerf might make
the world a little safer... but it doesn't actually buy anything. It
places the blame on the tool, instead of the person wielding the tool.
Apr 18 '07 #67
[snips]

On Tue, 17 Apr 2007 21:50:46 -0700, user923005 wrote:
Cars also kill people from time to time. There are some things about
cars that are clearly unsafe. If the brakes are bad and you hit
someone in a car you borrowed, it was not the driver but the car.
As Kenneth Brody said, "With power comes responsibility." The driver has
gained the power to get about quickly, to transport goods efficiently, to
be sure, but he has also gained the power to kill, maim and otherwise
cause damage. The responsibility is to ensure he has the skill to avoid
this as much as is humanly possible... but it is *also* his responsibility
to ensure the tools he use are maintained correctly - such as checking the
brakes before relying on them.

Incorrect or unsafe use of a tool does not make the tool unsafe, it simply
means the user of it is being irresponsible.
C strings are the bad brakes in the C language.
Except they're not. They never wear out. They never fail to do exactly
the same thing, exactly the same way, whether you use them once or a
million times. They need no maintenance, no care, no looking after.
An acetylene torch is a dangerous thing. You can do lots of wonderful
things with it. Maybe, if it was safer, it would be a lot harder to
get the work done. But when someone comes along and wants to learn
how to weld, I think it prudent to tell the welding student that the
yellow (and sometimes blue) thing that comes out of the end of the
torch is dangerous. If we tell them that it is completely safe, then
we are lying. Not only that, but they are far more liable to damage
of some sort than if properly instructed.
Exactly. The worker needs to learn the _correct use_ of the tools. The
tools, in and of themselves, are not the problem; it is the incorrect use
of them that is the problem.

You're making the point for us: it's not the C strings that are the
problem, but the people who use them carelessly. Yes, isn't that what
people have been telling you?
To tell anyone that C strings are safe is a fabrication because the
evidence proves that they are very, very dangerous.
Few things are "safe" in an absolute sense. Things are safe when used
correctly. That's true of water, of oxygen, of welding torches and of
C-style strings.
Clearly, C strings are a problem because of all the damage they cause.
By this argument, you might as well say it's the end users who are the
problem: after all, they're the ones who cause the damage, by running the
programs, entering the data. If we got rid of the users, the problems
would simply cease to exist.

It's a silly argument. The tools are there, to be used. You can use them
correctly and safely, or incorrectly and dangerously. Blaming the tool
because the programmer can't use it properly is pointless.
Apr 18 '07 #68
[snips]

On Tue, 17 Apr 2007 18:50:19 -0700, user923005 wrote:
>A "good" programmer would not use scanf() with "%s".

That's false, because good programmers have done it. It's not common,
but it happens.
Damned rarely... particularly in released versions of production code.
Now, Lawrence Kirby was not only familiar with the problem of buffer
overrun with scanf() of fscanf() combined with %s, but he often
counseled against it. Certainly, this is not some polished work that
he did and neither was it his original work, but rather a correction
of someone else's work. But if such an attrocity can escape from the
fingers of one Lawrence Kirby, then it can escape from the fingers of
us all.
This, too, is a bit silly. The OP was obviously a newbie, learning his
way about the language. While it would be a good idea to instill good
habits - such as not using scanf this way - in a newbie, this needs to be
balanced against the readiness of the recipient to have such information
imparted.

One must walk before one can run; this person was obviously at the stage
of having learned to walk but not having quite mastered it yet.
Explaining to them the finer points of running - speed versus stamina,
training methods for each and their pros and cons - is pointless; they're
not at that stage yet.

I'm willing to bet if you examined Kirby's released production code, you'd
be hard pressed to find such constructs - but then, he's past the stage of
simply toddling.
Apr 18 '07 #69
user923005 wrote:
Now, Lawrence Kirby was not only familiar with the problem of buffer
overrun with scanf() of fscanf() combined with %s, but he often
counseled against it. Certainly, this is not some polished work that
he did and neither was it his original work, but rather a correction
of someone else's work. But if such an attrocity can escape from the
fingers of one Lawrence Kirby, then it can escape from the fingers of
us all.

You will find other scintillating stars of c.l.c also guilty in this
regard.
A bulletproof input routine using fscanf:

http://www.mindspring.com/~pfilandr/...fscanf_input.c

--
pete
Apr 19 '07 #70
On Apr 18, 4:03 pm, Kelsey Bjarnason <kbjarna...@ncoldns.comwrote:
[snips]

On Tue, 17 Apr 2007 21:50:46 -0700, user923005 wrote:
Cars also kill people from time to time. There are some things about
cars that are clearly unsafe. If the brakes are bad and you hit
someone in a car you borrowed, it was not the driver but the car.

As Kenneth Brody said, "With power comes responsibility." The driver has
gained the power to get about quickly, to transport goods efficiently, to
be sure, but he has also gained the power to kill, maim and otherwise
cause damage. The responsibility is to ensure he has the skill to avoid
this as much as is humanly possible... but it is *also* his responsibility
to ensure the tools he use are maintained correctly - such as checking the
brakes before relying on them.

Incorrect or unsafe use of a tool does not make the tool unsafe, it simply
means the user of it is being irresponsible.
A tool that by design is unsafe to use is a badly designed tool. If
there were not literally hundreds of exploits in production code that
have actually been used for evil purposes, then these "C strings are
safe" arguments would make sense. Expert coders who are trying their
hardest still cause errors in this regard.

So now, let the first person who has written at least 10,000 lines of
code and who has also never had even one bug in his code raise his
hand.

What? No hands raised? Then perhaps we should assume that the users
of the tools are not perfect and (in fact) prone to mistakes.

These mistakes do happen, on a frequent basis. These mistakes also
cause billions of dollars in damage. This is not a theoretical
argument. It is a statement of fact, using what we actually observe.
The claim is that responsible coders will not introduce mistakes that
cause damage because of the way C strings are designed.
This claim is clearly and obviously wrong, because these mistakes are
made by senior level programmers.
Now, you can say it was the programmer's fault and that is fine. But
the fact that it happens again and again shows that even competent,
well meaning, conscientious programmers make mistakes which are
avoidable given a real string type that knows how to protect itself.

Apr 19 '07 #71
user923005 said:

<snip>
A tool that by design is unsafe to use is a badly designed tool.
Agreed. Strings are not tools. They are, perhaps, wood. The unsafe tools
are gets(), scanf("%s", etc. Let us write decent, safe tools for
handling our raw materials, by all means. Nobody is suggesting
otherwise.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Apr 19 '07 #72
[snips]

On Wed, 18 Apr 2007 17:56:16 -0700, user923005 wrote:
>Incorrect or unsafe use of a tool does not make the tool unsafe, it simply
means the user of it is being irresponsible.

A tool that by design is unsafe to use is a badly designed tool.
So let's get rid of hammers, axes, knives, screwdrivers, cutting torches,
most saws, drills, forks, pencils, pens, computers, TVs, cars, toasters...

Every single one of those is a tool. Every single one, used improperly,
is dangerous - even potentially fatal. Most *cannot* be designed to be
safe if used improperly; therefore, by your argument, they are badly
designed and need to be replaced... except... if they cannot be designed
to meet your requirements, all that's left is to abandon them completely.

This, to you, makes sense, does it?
If
there were not literally hundreds of exploits in production code that
have actually been used for evil purposes
And tens of thousands of people killed in car crashes, by knives,
thousands more killed by assorted workshop tools, more still killed by TVs
and radios and toasters...
>, then these "C strings are
safe" arguments would make sense. Expert coders who are trying their
hardest still cause errors in this regard.
First, a string isn't a tool; it's a piece of data. The tools in this
case are the functions which operate upon strings. Those tools, like any,
require a certain attention to detail, a certain skill.

Part of that skill, part of that attention, is simply knowing how to use
them correctly in the first place. Another part, at least for "critical"
code, involves items such as code reviews, use of unit testing, use of
scattershot and other randomized testing tools and so forth.

I'm willing to bet you will find *damned* few instances of
C-string-related exploits which have passed a proper testing and
examination regimen.
So now, let the first person who has written at least 10,000 lines of
code and who has also never had even one bug in his code raise his hand.
Umm... er... okay. Mine. 35,000+ lines in a single project... over
200,000 units shipped. While there were a few design issues that came up
- as in "it'd be nice if it could do this" - not a *single* actual bug
report.
What? No hands raised?
Mine is.
Then perhaps we should assume that the users of
the tools are not perfect and (in fact) prone to mistakes.
A tool cannot be prone to anything; it is inert, sitting there waiting for
you to use it. *How* you use it determines the risk. If you choose to
walk into a crowded mall with a high powered rifle, put on a blindfold and
empty the clip in random directions, it is not the fault of the tool that
someone gets hurt.
These mistakes do happen, on a frequent basis.
No, they don't - at least, not to seasoned developers using proper
development, testing and verification strategies.

It is *precisely* when one becomes blase about the use of the tools - I'm
not talking strcpy and the like, I'm talking the entire language, and even
more generally, the entire world of software development, regardless of
language or platform - that dangers arise.

There's an old adage, it goes something like this: "If engineers built
buildings the way programmers built buildings, the first woodpecker to
come along would destroy civilization."

There's a certain truth to that. I have met far too many developers over
the years who simply _don't care_. They rely on functions to "just work"
and don't bother checking return codes. They assume allocations succeed.
They assume they have enough space to copy a string or write a block of
data.

There is *nothing* you can do about such people other than identify them
and either train them properly or try to prevent them ever developing
software. No language, no tool in existence will ever stop them writing
bad software, software full of holes, full of risks. They are simply
incapable - through lack of training, lack of concern, whatever - of
producing quality software.

But that's the whole point: there is *nothing* you can do, from a language
perspective, to stop them. Nothing. They will always manage to do
something wrong. If it's not a failed string copy, it's a division where
they don't check for division by zero. Or something, anything. Lacking
the skills or the concern to do it right, they do it wrong, and the only
way to prevent it is to prevent them writing software - not to try to
create some magical language where it is impossible to write bad code.

Professional developers, writing production code, use professional
methods. They use well-structured designs, for starters. They examine
and handle errors and allocation failures. They make sure buffers are
large enough.

However, a professional developer *also* knows he is human and can make
mistakes, so he'll use other things to help him. Compilers with maximal
warning levels, and he'll treat warnings as fatal errors. He'll run lint
and similar tools. He'll do coverage analysis. He'll use random
injection tests to validate that a piece of code doesn't break when handed
data too large or too small or with improper values. Where possible,
he'll submit the code to review.

Check that failing code you go on about. See how much of it has gone
through all those levels of design, testing and validation and *still*
managed to produce fatal errors.
These mistakes also
cause billions of dollars in damage. This is not a theoretical
argument. It is a statement of fact, using what we actually observe.
Really? Tell you what. How about you provide a single example where the
tools - say the C string handling functions - actually caused billions in
damages... when used correctly.
The claim is that responsible coders will not introduce mistakes that
cause damage because of the way C strings are designed.
No, the claim is that professional developers apply professionalism to
development and take steps to ensure that this sort of thing doesn't
happen in programs properly designed and used within the limits of those
designs. The claim, further, is that professional programmers apply
professionalism to testing and verifying that their code actually does
work as intended, despite being given garbage data.

There's another old saying, GIGO - Garbage In, Garbage Out. However,
while trite and well known, it is actually the mark of a poor programmer.
The saying suggests that it is okay - even expected - that if bad data is
given to a program, producing flawed results is acceptable.

Ask any professional programmer what his routines do when they encounter a
value out of range, for example. The response will almost invariably be
something like "bail out, reporting an error."

There's a reason for it; if something is outside the realm of what the
code is designed to handle, then something has gone fatally wrong: the
program is being used incorrectly, or outside the scope of the design it
was built to, or a device - or user - is giving it invalid input, or some
other routine has failed in some manner.

Garbage in does not mean garbage out, not if you're a pro; it means
_errors_ out. Not crashes, not overflows, not random writes to random
bits of memory - errors. As in "I don't know what to do with this, so
tell someone about it and let them sort it out."

Again, it is precisely the lack of concern and diligence that causes these
problems - not the tools. Short of making a "perfect" - and perfectly
unusable - language, you cannot stop poor developers writing poor code.
The best you can accomplish is making it difficult for good programmers to
write good code - and a good programmer doesn't need that hand-holding in
the first place. He already has the tools necessary to detect and deal
with these problems, and he already *uses* those tools.

--
Do not contact me at kb********@ncoldns.com
Apr 19 '07 #73
user923005 wrote:
>
.... snip ...
>
Now, you can say it was the programmer's fault and that is fine.
But the fact that it happens again and again shows that even
competent, well meaning, conscientious programmers make mistakes
which are avoidable given a real string type that knows how to
protect itself.
All you are saying is that the programmer should choose the
language to fit the project. Pascal, Ada, and others come to mind.

--
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>
<http://www.securityfocus.com/columnists/423>
<http://www.aaxnet.com/editor/edit043.html>

"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews

--
Posted via a free Usenet account from http://www.teranews.com

Apr 19 '07 #74
pete wrote:
>
.... snip ...
>
A bulletproof input routine using fscanf:

http://www.mindspring.com/~pfilandr/...fscanf_input.c
It would have been much simpler to simply publish it right here.
However, according to N869:

s Matches a sequence of non-white-space
characters.228)

The following is quoted from the reference and modified to reduce
whitespace:
#include <stdio.h>

#define LENGTH 40
#define str(x) # x
#define xstr(x) str(x)

int main(void)
{
int rc;
char array[LENGTH + 1];

puts("The LENGTH macro is " xstr(LENGTH) ".");
do {
fputs("Enter any line of text to continue,\n"
"or just hit the Enter key to quit:", stdout);
fflush(stdout);
rc = fscanf(stdin, "%" xstr(LENGTH) "[^\n]%*[^\n]", array);
if (!feof(stdin)) getc(stdin);
if (rc == 0) array[0] = '\0';
if (rc == EOF) puts("rc equals EOF");
else printf("rc is %d. Your string is:%s\n\n", rc, array);
} while (rc == 1);
return 0;
}
which doesn't seem to match the specification here. How come?

--
Please do not top-post. Your answer belongs after (or intermixed
with) the quoted material to which you reply, after snipping all
irrelevant material. See the following links:

<http://www.catb.org/~esr/faqs/smart-questions.html>
<http://www.caliburn.nl/topposting.html>
<http://www.netmeister.org/news/learn2quote.html>
<http://cfaj.freeshell.org/google/ (taming google)
<http://members.fortunecity.com/nnqweb/ (newusers)
--
Posted via a free Usenet account from http://www.teranews.com

Apr 19 '07 #75
On Apr 18, 5:08 pm, pete <pfil...@mindspring.comwrote:
user923005 wrote:
Now, Lawrence Kirby was not only familiar with the problem of buffer
overrun with scanf() of fscanf() combined with %s, but he often
counseled against it. Certainly, this is not some polished work that
he did and neither was it his original work, but rather a correction
of someone else's work. But if such an attrocity can escape from the
fingers of one Lawrence Kirby, then it can escape from the fingers of
us all.
You will find other scintillating stars of c.l.c also guilty in this
regard.

A bulletproof input routine using fscanf:

http://www.mindspring.com/~pfilandr/...fscanf_input.c
Uhh ... this is bullet broof? You have to hand synchronize the LENGTH
and remember the +1 in the array declaration ... using some global
macro namespace for str() ... and this thing doesn't exactly roll off
the tongue does it? Here are the Bstrlib way of doing things:

bstring b = bgets ((bNgetc) getc, stdin, '\n');

Or:

bstring b = bSecureInput (LENGTH, '\n', (bNgetc) getc, stdin);

if the truncation semantics are that important to you. Its one line,
and there is no confusion, ambiguity or danger. Its also more
powerful as you can easily implement this on top of sockets or other
interesting input streams.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Apr 19 '07 #76
On Apr 18, 8:52 pm, CBFalconer <cbfalco...@yahoo.comwrote:
user923005 wrote:

... snip ...
Now, you can say it was the programmer's fault and that is fine.
But the fact that it happens again and again shows that even
competent, well meaning, conscientious programmers make mistakes
which are avoidable given a real string type that knows how to
protect itself.

All you are saying is that the programmer should choose the
language to fit the project. Pascal, Ada, and others come to mind.
No he is not saying that at all. Where do you even read that as an
implication?

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Apr 19 '07 #77
we******@gmail.com wrote:
>It seems to me that the responsible thing to do is to use "safe"
strings unless performance is absolutely critical, otherwise you're
just putting your users at risk.

Uhh ... are you making a false choice here -- I mean a *REALLY REALLY*
false choice? Length delimited strings are both safer *AND* faster.
Truly the only advantage of using C's raw char * strings is where you
want to minimize your code size footprint. Otherwise, using an
alternative is usually always better.
You are, of course, correct.
Apr 19 '07 #78
>>>>"KB" == Kelsey Bjarnason <kb********@ncoldns.comwrites:

KBOn Tue, 17 Apr 2007 21:50:46 -0700, user923005 wrote:
>An acetylene torch is a dangerous thing. You can do lots of
wonderful things with it. Maybe, if it was safer, it would be
a lot harder to get the work done. But when someone comes
along and wants to learn how to weld, I think it prudent to
tell the welding student that the yellow (and sometimes blue)
thing that comes out of the end of the torch is dangerous. If
we tell them that it is completely safe, then we are lying.
Not only that, but they are far more liable to damage of some
sort than if properly instructed.
KBExactly. The worker needs to learn the _correct use_ of the
KBtools. The tools, in and of themselves, are not the problem;
KBit is the incorrect use of them that is the problem.

Beyond that, continuing the analogy, when you need a worker to weld
things together but can't trust that he will use the acetylene torch
correctly, you build a custom tool. But you don't elminate the
acetylene torch from your toolset entirely, because there will be
situations in which the acetylene torch in the hands of a competent
welder is the only tool that can get a particular job done under a
certain set of constraints.

Likewise, when you need a programmer to manipulate strings, but can't
trust that he will use C strings correctly, you build a custom tool.
But you don't eliminate C strings from your toolset entirely, because
there will be situations in which C strings in the hands of a
competent programmer is the only tool that can get a particular job
done under a certain set of constraints.

What makes this argument even more ludicrous is that there *are*
custom C string libraries that solve all of these problems. Look at
CFString in Apple's Core Foundation library, for instance. If you
want safer strings in C, you've got them!

Charlton

--
Charlton Wilbur
cw*****@chromatico.net
Apr 19 '07 #79
Kelsey Bjarnason wrote:
>
[snips]

On Tue, 17 Apr 2007 18:55:34 -0400, Kenneth Brody wrote:
It's "dangerous" in that a newbie doesn't see the difference between:

char token[6] = "123456";
and
char token[] = "123456";

After all, they only see 6 chars in both.

As you said, "newbie". Someone not properly competent to be releasing
software unto the world - nor likely to do so, one would hope.
And, as far as the compiler is concerned, both can be passed to strstr()
without issue.

If so, then there's no problem and the issue is irrelevant.

Whoops... there *is* a problem, because they cannot both be passed to
strstr without issue; one of them distinctly does have issues, because -
as noted previously - you cannot chuck incorrect data about and expect to
get correct results.
Note my qualification of "as far as the compiler is concerned".
With power comes responsibility.

Indeed; as a programmer you have the power to corrupt data, crash systems,
wreak all kinds of havoc; if you haven't got enough responsibility to get
something as basic as your data types right, you have no business
releasing your software on an unsuspecting world.
Well, the point here is that they are both character arrays. The
data in the arrays is different, of course.

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h|
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:Th*************@gmail.com>

Apr 19 '07 #80
we******@gmail.com wrote:
>
On Apr 18, 5:08 pm, pete <pfil...@mindspring.comwrote:
A bulletproof input routine using fscanf:

http://www.mindspring.com/~pfilandr/...fscanf_input.c

Uhh ... this is bullet broof?
It's only for situations when you know that you can
cut lines down to the first LENGTH number of characters
without causing a problem.

For arbitrary line length input, I have get_line:

http://www.mindspring.com/~pfilandr/...ine/get_line.c

--
pete
Apr 19 '07 #81
CBFalconer wrote:
>
pete wrote:
... snip ...

A bulletproof input routine using fscanf:

http://www.mindspring.com/~pfilandr/...fscanf_input.c

It would have been much simpler to simply publish it right here.
However, according to N869:

s Matches a sequence of non-white-space
characters.228)

The following is quoted from the reference and modified to reduce
whitespace:
#include <stdio.h>

#define LENGTH 40
#define str(x) # x
#define xstr(x) str(x)

int main(void)
{
int rc;
char array[LENGTH + 1];

puts("The LENGTH macro is " xstr(LENGTH) ".");
do {
fputs("Enter any line of text to continue,\n"
"or just hit the Enter key to quit:", stdout);
fflush(stdout);
rc = fscanf(stdin, "%" xstr(LENGTH) "[^\n]%*[^\n]", array);
if (!feof(stdin)) getc(stdin);
if (rc == 0) array[0] = '\0';
if (rc == EOF) puts("rc equals EOF");
else printf("rc is %d. Your string is:%s\n\n", rc, array);
} while (rc == 1);
return 0;
}

which doesn't seem to match the specification here. How come?
I think the circumflex with the newline causes
all of the characters except the newline to be in the scanset.

The net effect is the same as from get_line(),

http://www.mindspring.com/~pfilandr/...ine/get_line.c

except that with fscanf_input way of doing it,
the strings are cut short down to LENGTH number of characters.

--
pete
Apr 19 '07 #82
we******@gmail.com writes:
On Apr 18, 5:08 pm, pete <pfil...@mindspring.comwrote:
>user923005 wrote:
[...]
>A bulletproof input routine using fscanf:

http://www.mindspring.com/~pfilandr/...fscanf_input.c

Uhh ... this is bullet broof? You have to hand synchronize the LENGTH
and remember the +1 in the array declaration ... using some global
macro namespace for str() ... and this thing doesn't exactly roll off
the tongue does it? Here are the Bstrlib way of doing things:

bstring b = bgets ((bNgetc) getc, stdin, '\n');

Or:

bstring b = bSecureInput (LENGTH, '\n', (bNgetc) getc, stdin);

if the truncation semantics are that important to you. Its one line,
and there is no confusion, ambiguity or danger. Its also more
powerful as you can easily implement this on top of sockets or other
interesting input streams.
getc is a function that takes a FILE* argument and returns an int.
Your sample code converts a pointer to the getc function to type
bNgetc, which happens to be a typedef:

typedef int (*bNgetc) (void *parm);

It's legal to convert any pointer-to-function type to any other
pointer-to-function type, but using the result without converting it
back to the original type invokes undefined behavior (C99 6.3.2.3p8).

It will probably happen to work in most implementations (assuming that
function pointers have the same representation, and that void* and
FILE* are passed as arguments in the same way), and perhaps that's
good enough for your purposes, but it's worth mentioning that this is
not strictly portable.

There's a similar issue for the "compar" arguments of the standard
bsearch() and qsort() functions. The usual solution is to use a
wrapper function. For example (untested code):

int getc_wrapper(void *parm)
{
return getc((FILE*)param);
}

...

bstring b = bgets (getc_wrapper, stdin, '\n');

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Apr 19 '07 #83
Ed Jensen <ej*****@visi.comwrites:
we******@gmail.com wrote:
>>It seems to me that the responsible thing to do is to use "safe"
strings unless performance is absolutely critical, otherwise you're
just putting your users at risk.

Uhh ... are you making a false choice here -- I mean a *REALLY REALLY*
false choice? Length delimited strings are both safer *AND* faster.
Truly the only advantage of using C's raw char * strings is where you
want to minimize your code size footprint. Otherwise, using an
alternative is usually always better.

You are, of course, correct.
It's not clear that length delimited strings are faster than
terminated strings in all cases. It depends on what you do with them.
Using plain C strings, it's often possible to remember the length
rather than recomputing it.

A string is a data structure. Data structures don't have a speed; an
algorithm you apply to a data structure has a speed. The design of
the data structure, of course, can make it easy, difficult, or
impossible to implement fast algorithms that work with it, so this is
a fairly minor quibble, but it would be clearer to discuss the speed
of algorithms.

A commonly used example is strcat():

char big_string[BIG_ENOUGH];

strcpy(big_string, foo);
strcat(big_string, bar);

The call to strcat() has to re-scan the target string from the
beginning to find the terminating '\0' before it can begin copying
characters; if foo is big, the overhead can be significant. But if
you can remember the length of foo from a previous computation, you
can use that to avoid re-scanning:

strcpy(big_string, foo);
strcpy(big_string + foo_len, bar);

This isn't always possible. For example, foo might have been
initialized by some function that doesn't tell you either its length
or the location of the terminating '\0'. But a lot of the overhead
caused by using plain C strings naively can be avoided by using them
more cleverly.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Apr 19 '07 #84
[snips]

On Thu, 19 Apr 2007 15:29:52 -0400, Kenneth Brody wrote:
And, as far as the compiler is concerned, both can be passed to strstr()
without issue.

If so, then there's no problem and the issue is irrelevant.

Whoops... there *is* a problem, because they cannot both be passed to
strstr without issue; one of them distinctly does have issues, because -
as noted previously - you cannot chuck incorrect data about and expect to
get correct results.

Note my qualification of "as far as the compiler is concerned".
Sure. As far as the compiler is concerned, you can get away with hundreds
of different types of undefined behavior as well; the compiler is under
_no_ obligation to even _try_ to figure it out. This doesn't mean that
such code is properly built - just as passing the wrong thing to the str*
functions may get past the compiler, but that doesn't mean the code is
right.

If you're a code monkey, the only question is what _sort_ of code monkey
are you: the sort who takes the time to get things right, within
reasonable limits, or the sort who is liable to say "It compiles... ship
it"?

The former sort tend not to have this sort of problem as a rule. The
latter... well... fine, yes, they do have this problem. They also tend to
have 197 other sorts of problems, so focusing on this one in particular
seems a bit pointless.

--
Do not contact me at kb********@ncoldns.com
Apr 19 '07 #85
On Apr 19, 3:44 pm, Keith Thompson <k...@mib.orgwrote:
Ed Jensen <ejen...@visi.comwrites:
websn...@gmail.com wrote:
>It seems to me that the responsible thing to do is to use "safe"
strings unless performance is absolutely critical, otherwise you're
just putting your users at risk.
Uhh ... are you making a false choice here -- I mean a *REALLY REALLY*
false choice? Length delimited strings are both safer *AND* faster.
Truly the only advantage of using C's raw char * strings is where you
want to minimize your code size footprint. Otherwise, using an
alternative is usually always better.
You are, of course, correct.

It's not clear that length delimited strings are faster than
terminated strings in all cases. [...]
Actually its clear to anyone who has measured it.
[...] It depends on what you do with them.
Using plain C strings, it's often possible to remember the length
rather than recomputing it.
Remember it? Remember it where? In a variable somewhere? How about
just holding it in another field instead? Wait! That's exactly what
length delimited strings are isn't it?
A string is a data structure. Data structures don't have a speed; an
algorithm you apply to a data structure has a speed. The design of
the data structure, of course, can make it easy, difficult, or
impossible to implement fast algorithms that work with it, so this is
a fairly minor quibble, but it would be clearer to discuss the speed
of algorithms.

A commonly used example is strcat():

char big_string[BIG_ENOUGH];
Of course this may lead to a load-time error. But that's never
discussed.
strcpy(big_string, foo);
strcat(big_string, bar);
And these of course are just buffer overflows waiting to happen
anyways.
The call to strcat() has to re-scan the target string from the
beginning to find the terminating '\0' before it can begin copying
characters; if foo is big, the overhead can be significant.
You are also ignoring the fact that each character from foo and bar
are checked against '\0' for no really good reason. Block copying
mechanisms from the underlying platform are not available. So *both*
the strcpy and strcat functions are potentially slower than they need
to be.
[...] But if
you can remember the length of foo from a previous computation, you
can use that to avoid re-scanning:

strcpy(big_string, foo);
strcpy(big_string + foo_len, bar);

This isn't always possible.
And it *ALWAYS* increases danger, because there are no language
semantics or assistance available to you to keep bigs_string and
foo_len in synch. Its horrible in this case because what happens if
you decide you want to insert a strcat (big_string, "|"); in between
those two lines? Writing code like this is just inherently
unmaintainable.

And of course, in a discussion about performance you completely miss
the real performance opportunity:

memcpy (big_string, foo, foo_len);
strcpy(big_string + foo_len, bar);

Which, of course, should generally go faster, but does nothing to
alleviate the danger of buffer overflows or maintenance issues.
Though there still isn't anything being done about the second
strcpy().
[...] For example, foo might have been
initialized by some function that doesn't tell you either its length
or the location of the terminating '\0'. But a lot of the overhead
caused by using plain C strings naively can be avoided by using them
more cleverly.
Besides arguing incorrectly, you argue by straw man:

1) With length delimited string you can perform unrolled string
searching algorithms without testing each character for '\0'.
Furthermore if the two strings are of similar length, and they
completely mismatch, then you avoid any comparisons which would take
the tail of the search string beyond the tail of the string you are
searching in.

2) String comparison includes length checking which speeds up the
typical scenario of long prefix matching for different strings.

3) Operations such as insert and delete can be done in one pass.

4) And as long as we talking about "clever tricks", any block-based
algorithms (such as is possible for things like "toupper" or "tolower"
or character scanning) become unavailable unless the length is known.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Apr 20 '07 #86
As long as programmers are able to code carefully (read 'without bugs
in their code') then a better string type for C will not be helpful.
Keep in mind that a corporation destroying bug is not dangerous
because all you have to do is never make a mistake and it won't
happen.
On the other hand, for those of us who do have a bug once in a great
while, it is comforting to know that a mistrake won't wipe out the
entire corporation.

Apr 20 '07 #87
On Wed, 18 Apr 2007 21:12:57 -0700, Kelsey Bjarnason wrote:
i not agree with you because:

speaking not for the C language but for its library

one thing is to have a set of functions in a library that can allow
20_000_000 type of differents errors
other thing is to have a set of functions in a library that allow
200 type of differents errors
Apr 20 '07 #88
In article <13*************@corp.supernews.com>, SM Ryan
<wy*****@tango-sierra-oscar-foxtrot-tango.fake.orgwrites
>"hstagni" <st****@gmail.comwrote:
# Where can I find a library to created text-based windows applications?

Possibly....on Unix the library is called curses. If you google
"curses library windows" it will show you some candidate libraries
you can investigate. Using curses will simplify porting to Unix
if you should ever want to.

There are several "Curses" libraries for the PC. I should have on if you
can't find one.
>
# Im looking for a library that can make windows and buttons inside
# console.. Many old apps were make like this, i guess
#
# ____________________________________
# | |
# | ------------------ |
# | | BUTTON | |
# | ------------------ |
# | |
# | |
# L_________________ _________________|
#
# I tried to draw a window here, but im looking for something better
# than that,,huahua
#
#
#

--
SM Ryan http://www.rawbw.com/~wyrmwif/
You hate people.
But I love gatherings. Isn't it ironic.
--
\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
\/\/\/\/\ Chris Hills Staffs England /\/\/\/\/
/\/\/ ch***@phaedsys.org www.phaedsys.org \/\/\
\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/

Apr 20 '07 #89
[snips]

On Thu, 19 Apr 2007 21:45:03 -0700, websnarf wrote:
>It's not clear that length delimited strings are faster than
terminated strings in all cases. [...]

Actually its clear to anyone who has measured it.
Really. Explain how such strings will improve the speed of strchr.

Using the conventional approach, each operation involves the following:

Dereference the pointer
Compare value against \0
If comparison fails, compare value against "needle"
If comparison fails, increment pointer and loop

With an integer-stored-length string variant, the operation is more like:
Compare index to length
if comparison fails, dereference pointer+index
Compare value against "needle"
If comparison fails, increment index and loop

One might argue that comparing the index to the length might be faster
than comparing the characters, but if so it should be pointed out that the
base+index computation may well be slower than the pointer dereference; it
is not clear that either is guaranteed to be a performance win on all
possible implementations.

Pedantic, perhaps, but the statement involved "all cases", not just some.
>[...] It depends on what you do with them. Using plain C strings, it's
often possible to remember the length rather than recomputing it.

Remember it? Remember it where? In a variable somewhere? How about
just holding it in another field instead? Wait! That's exactly what
length delimited strings are isn't it?
Yes, but that involves additional computation with any string-modifying
operation, when such computation may only be necessary - or even desirable
- in a small number of cases.
>A commonly used example is strcat():

char big_string[BIG_ENOUGH];

Of course this may lead to a load-time error. But that's never
discussed.
Depends how large BIG_ENOUGH is; if it's 256 bytes, it is unlikely to
cause problems. If it's 256K, there's no expectation the code will work
at all, except in a limited number of cases.
>
> strcpy(big_string, foo);
strcat(big_string, bar);

And these of course are just buffer overflows waiting to happen anyways.
Assuming one doesn't know how long foo and bar are. Generally, when I
write my code, I actually pay attention to such details.
You are also ignoring the fact that each character from foo and bar are
checked against '\0' for no really good reason. Block copying
mechanisms from the underlying platform are not available. So *both*
the strcpy and strcat functions are potentially slower than they need to
be.
Sure; length-specified strings can be faster in some cases. I think
you'll find it hard to prove they're faster in all cases, as you assert.
> strcpy(big_string, foo);
strcpy(big_string + foo_len, bar);

This isn't always possible.

And it *ALWAYS* increases danger, because there are no language
semantics or assistance available to you to keep bigs_string and foo_len
in synch.
Umm... so? It doesn't take any particular genius to load a block of data
from a file, for example, then compare length of input + length of
existing data to length of buffer.
Its horrible in this case because what happens if you decide
you want to insert a strcat (big_string, "|"); in between those two
lines?
Then you increment your size by one.
And of course, in a discussion about performance you completely miss
the real performance opportunity:

memcpy (big_string, foo, foo_len);
strcpy(big_string + foo_len, bar);

Which, of course, should generally go faster, but does nothing to
alleviate the danger of buffer overflows or maintenance issues.
Hmm. This would seem to require either that memcpy be replaced with a
function which has innate knowledge of the new length-managed string type,
or exposing the string data itself to the outside world - outside the
control of the built-in string functions. This means we can modify the
buffer directly - potentially making the length field completely invalid.

I the point here is to prevent bad programming practices - the sort that
lead to buffer overflows - this strikes me as a not overly good approach.
You need to keep the entire thing in an opaque type, but if you do, this
removes the option of doing the memcpy above.
Besides arguing incorrectly, you argue by straw man:

1) With length delimited string you can perform unrolled string
searching algorithms without testing each character for '\0'.
You have to compare the index to the length, instead. Replacing one
integer comparison with another doesn't seem all that significant.
Furthermore if the two strings are of similar length, and they
completely mismatch, then you avoid any comparisons which would take the
tail of the search string beyond the tail of the string you are
searching in.
Not sure what that means. Example:

a_str = "abcde";
b_str = "fghijkl";

Similar strings, complete mismatches. Comparison of the strings involves
comparison of _one_ character: 'a' is not equivalent to 'f', so the
strings don't compare, so why compare further? Or perhaps you mean
strstr, rather than strcmp? In which case:

a_str = "xxx";
b_str = "abcdef";

Similar lengths, complete mismatch... but a maximum of four character
comparisons, plus determination of length, are required to determine this.
In the case of long strings, the gains could be more significant, but if
you're comparing long strings on a regular basis, I'd tend to think Boyer
Moore or the like would be more appropriate, and these perform quite well;
your only gain would be in calculating end-of-string, and that's assuming
the code doesn't already have such information available.
2) String comparison includes length checking which speeds up the
typical scenario of long prefix matching for different strings.
Assuming one doesn't already have such information available. If I'm
writing code to process thousands of strings, each potentially thousands
or even tens of thousands of characters long, I'm _already_ going to be
recording string lengths, and using modified algorithms which make use of
this information.
3) Operations such as insert and delete can be done in one pass.
4) And as long as we talking about "clever tricks", any block-based
algorithms (such as is possible for things like "toupper" or "tolower"
or character scanning) become unavailable unless the length is known.
Yes, yes, again, some operations can be improved. Even most. However,
once again, the key concept was "all cases". It has not been demonstrated
that this mechanism would, in fact, improve all cases. The simple example
of strchr, for example, throws the notion in doubt.
--
Do not contact me at kb********@ncoldns.com
Apr 22 '07 #90
On Sun, 22 Apr 2007 11:39:38 -0700, Kelsey Bjarnason
<kb********@ncoldns.comwrote:
>[snips]

On Thu, 19 Apr 2007 21:45:03 -0700, websnarf wrote:
>>It's not clear that length delimited strings are faster than
terminated strings in all cases. [...]

Actually its clear to anyone who has measured it.

Really. Explain how such strings will improve the speed of strchr.

Using the conventional approach, each operation involves the following:

Dereference the pointer
Compare value against \0
If comparison fails, compare value against "needle"
If comparison fails, increment pointer and loop

With an integer-stored-length string variant, the operation is more like:
Compare index to length
if comparison fails, dereference pointer+index
Compare value against "needle"
If comparison fails, increment index and loop

One might argue that comparing the index to the length might be faster
than comparing the characters, but if so it should be pointed out that the
base+index computation may well be slower than the pointer dereference; it
is not clear that either is guaranteed to be a performance win on all
possible implementations.
This is a bad example; if you have a length count you can unroll the
loop and avoid most of the comparisons between length and index. This
is a standard optimization; many compilers will even do it for you. If
you are scanning a \0 terminated string loop unrolling is not available.
Apr 23 '07 #91
[snips]

On Mon, 23 Apr 2007 16:55:28 +0000, Richard Harter wrote:
>>One might argue that comparing the index to the length might be faster
than comparing the characters, but if so it should be pointed out that the
base+index computation may well be slower than the pointer dereference; it
is not clear that either is guaranteed to be a performance win on all
possible implementations.

This is a bad example; if you have a length count you can unroll the
loop and avoid most of the comparisons between length and index.
You're still left with address and offset computation, or conversion to
pointer+incrementing. Any changes in speed one way or the other are
going to be at best minimal.
--
Do not contact me at kb********@ncoldns.com
Apr 23 '07 #92
In article <46***************@news.sbtc.net>
Richard Harter <cr*@tiac.netwrote:
>... if you have a length count you can unroll the [strchr-or-equivalent]
loop and avoid most of the comparisons between length and index. This
is a standard optimization; many compilers will even do it for you. If
you are scanning a \0 terminated string loop unrolling is not available.
Well, yes, except that implementations can "cheat", and unroll
strchr() anyway, after first ensuring that the address is (say) 0
mod 4. On some architectures (e.g., the original Alpha or MIPS)
this is pretty much the only way to handle the loop.

The obvious way to create an artificial situation in which
counted-length-strings underperfom zero-terminated-strings
is to create a lot of single-character strings in the first
version, and re-use the zero-terminator in the second:

loop {
newstr = substring(original, pos, 1);
if (compare_strings(newstr, looking_for) == match) ...
release_string(newstr);
}

vs:

newstr[1] = '\0';
loop {
newstr[0] = char_at(original, pos);
if (compare_strings(newstr, looking_for) == match) ...
}

Of course, you can make the first one perform the same as the second
by doing character (instead of string) operations (on newstr[0]
instead of newstr) -- but in languages that have counted-length-strings
as built-in primitive types, one often finds programmers allocating
and releasing single-character "strings" inside inner loops. This
may be where some of the "anti-counted-length-strings" bias comes
from. (I believe another chunk of bias comes from implementations
that limit counted-length strings to 255 bytes maximum: clearly a
bad idea, yet it occurs over and over again.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Apr 23 '07 #93
On 23 Apr 2007 18:27:18 GMT, Chris Torek <no****@torek.netwrote:
>In article <46***************@news.sbtc.net>
Richard Harter <cr*@tiac.netwrote:
>>... if you have a length count you can unroll the [strchr-or-equivalent]
loop and avoid most of the comparisons between length and index. This
is a standard optimization; many compilers will even do it for you. If
you are scanning a \0 terminated string loop unrolling is not available.

Well, yes, except that implementations can "cheat", and unroll
strchr() anyway, after first ensuring that the address is (say) 0
mod 4. On some architectures (e.g., the original Alpha or MIPS)
this is pretty much the only way to handle the loop.
Point conceded. To be fair though, once we are looking under the hood
at particular implementations, there are a lot of little tricks one can
use to juice performance in count delimited strings. The original
posting said in all instances; that has to be an overstatement.
>
The obvious way to create an artificial situation in which
counted-length-strings underperfom zero-terminated-strings
is to create a lot of single-character strings in the first
version, and re-use the zero-terminator in the second:

loop {
newstr = substring(original, pos, 1);
if (compare_strings(newstr, looking_for) == match) ...
release_string(newstr);
}

vs:

newstr[1] = '\0';
loop {
newstr[0] = char_at(original, pos);
if (compare_strings(newstr, looking_for) == match) ...
}

Of course, you can make the first one perform the same as the second
by doing character (instead of string) operations (on newstr[0]
instead of newstr) -- but in languages that have counted-length-strings
as built-in primitive types, one often finds programmers allocating
and releasing single-character "strings" inside inner loops.
How depressing.

It seems to me that for count-strings one wants a substring operation
that just points to a position in the original string. One
distinguishes between strings with modifiable content and those with
non-modifiable content. With that concept your first instance is simply

loop {
newstr = substring(original, pos, 1);
if (compare_strings(newstr, looking_for) == match) ...
}

and under the hood we have something like:

newstr.ptr = original.ptr + pos;
newstr.cnt = 1;

An advantage of count-strings is that you can refer to arbitrary
substrings of an original string. With terminated-strings you can only
refer to suffix substrings.

>This
may be where some of the "anti-counted-length-strings" bias comes
from. (I believe another chunk of bias comes from implementations
that limit counted-length strings to 255 bytes maximum: clearly a
bad idea, yet it occurs over and over again.)
There's a little issue involved. Commonly the count in a count-string
is packaged into the start of the string. When you do that then you're
stuck with a fixed format for the count (well, yes, you can wiggle
around it but that has a cost). But if you don't package the count with
the string then the count can go irretrievably lost. The advantage of
having a terminating character is the length can't go lost.
Apr 23 '07 #94
qed
Chris Torek wrote:
In article <46***************@news.sbtc.net>
Richard Harter <cr*@tiac.netwrote:
>... if you have a length count you can unroll the [strchr-or-equivalent]
loop and avoid most of the comparisons between length and index. This
is a standard optimization; many compilers will even do it for you. If
you are scanning a \0 terminated string loop unrolling is not available.

Well, yes, except that implementations can "cheat", and unroll
strchr() anyway, after first ensuring that the address is (say) 0
mod 4. On some architectures (e.g., the original Alpha or MIPS)
this is pretty much the only way to handle the loop.
Yes but you still must perform and additional '\0' scan. Its still an
unroll, but not a very effective one.
The obvious way to create an artificial situation in which
counted-length-strings underperfom zero-terminated-strings
is to create a lot of single-character strings in the first
version, and re-use the zero-terminator in the second:

loop {
newstr = substring(original, pos, 1);
if (compare_strings(newstr, looking_for) == match) ...
release_string(newstr);
}

vs:

newstr[1] = '\0';
loop {
newstr[0] = char_at(original, pos);
if (compare_strings(newstr, looking_for) == match) ...
}
Ok, but this is clearly nonsense. You obviously would write:

if (1 == looking_for->slen) {
lffc = looking_for->data[0];
do {
if (original->data[pos] == lffc) ...
...
} ...
}
Of course, you can make the first one perform the same as the second
by doing character (instead of string) operations (on newstr[0]
instead of newstr) -- but in languages that have counted-length-strings
as built-in primitive types, one often finds programmers allocating
and releasing single-character "strings" inside inner loops.
Ok, well this is comp.lang.c. You are conflating the fast single
character primitives with '\0' termination as if they only went with
each other.
[...] This
may be where some of the "anti-counted-length-strings" bias comes
from. (I believe another chunk of bias comes from implementations
that limit counted-length strings to 255 bytes maximum: clearly a
bad idea, yet it occurs over and over again.)
So the bias just comes from pure nonsense? This is a bias against other
languages, not against length delimited strings.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Apr 26 '07 #95
On Wed, 18 Apr 2007 22:23:52 +0800, Clem Clarke
<os*********@ozemail.com.auwrote:
<snip>
And for those people that suggest that C does have a string type, I
would suggest that it doesn't, compared with Pascal, PL/I, COBOL or even
Assembler. It has an array of characters, which is quite different from
a string.
COBOL, FORTRAN, and PL/I have a true(?) string type, i.e., distinct
from array. APL and Pascal and Ada in the basic case do use 'array of
char', but they all have (unlike C) safe arrays (of all types), and
APL and Ada have additional features for arrays (of all types) some of
which are particularly useful for treating array of char as string.
Pascal, except for a few library functions, is rather a pain for doing
string handling, which was probably one of the reasons for the
underwhelmingness of its success. And none of them treat char(acter)
as just a small integer/number, as C does.

Most assembly languages (there are many that used the simple and
obvious name assembler) support string data (AFAIK always just as
bytes) and whatever instructions the underlying machine has for
operating on them -- which typically also just deal with bytes. As a
simple and basic example, S/360 MVC can as easily do the right size or
the wrong size,and IIRC BAL *defaults* to the declared (presumably
right) size but can be overridden.
For example, in PL/I, one could write:

Dcl String10 char(10) varying;
Dcl String20 char(20) varying init
('Long 20 Character XX');
String10-string20;

This will automatically truncate the result, rather than copy the 20
bytes and overwrite adjacent storage, as in C.
Assuming you meant string10 = string20, and compared to strcpy in C,
since plain assignment won't even compile, and some other kinds of
copy like strlcpy won't have the problem.

And assuming STRINGSIZE is not enabled with an applicable handler that
forces something different -- but even then it would still be safe.

<snip rest>
- formerly david.thompson1 || achar(64) || worldnet.att.net
May 21 '07 #96

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: joes | last post by:
Hello there ! I rendering a PDF with XSLT using Xalan and FOP. I like to place in my article an image, so that the text is floating around the image. I tried several things but it didn't work so...
3
by: Xerxes | last post by:
Hi, I need help in setting up a page where the text wraps around an image. Right now, I am using table, with text in one <td> and the image in the adjacent <td>. The problem is when the text is...
2
by: Macsicarr | last post by:
Hi All Wonder if you could help me. I have created a CMS system that allows the user to enter text and pic 'tags' for their own About us page, eg text.... text.... text.... text.......
2
by: Jiri Palecek | last post by:
I have a question on web authoring (probably HTML+CSS). Is it somehow possible to put two words above each other inside a paragraph so the result would be valid and render at least in Mozilla? I...
0
by: TadPole | last post by:
I am using FOP to create PDF documents. I have the problem where I need to create line of text on a document in a certain line (absolute position), then the rest of the text needs to follow...
2
by: Buddy Ackerman | last post by:
Apparently .NET strips these white space characters (MSXML doesn't) regardless of what the output method is set to. I'm using <xsl:text> </xsl:text> to output a tab character and...
14
by: Joe | last post by:
Hello All: I am trying to dynamically populate a web page with literal content and controls (textboxes and checkboxes (and eventually two buttons - the buttons do not appear in the code yet). I...
3
by: jweinberg1975 | last post by:
I would like for users to be able to select from a small number of options that come from a little drop down menu which then closes. .....
3
by: bbepristis | last post by:
Hey all I have this code that reads from one text file writes to another unless im on a certian line then it writes the new data however it only seems to do about 40 lines then quits and I cant...
16
by: Neil | last post by:
I posted a few days ago that it seems to me that the Access 2007 rich text feature does not support: a) full text justification; b) programmatic manipulation. I was hoping that someone might...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.