edit: Fix and unify handling of invalid country numbers
Negative numbers and numbers greater or equal than MAXNOC are invalid.
edit handles such arguments inconsistently:
cmd key struct member arg < 0 arg >= MAXNOC
---------------------------------------------------
edit l o sct_own reject MAXNOC - 1
O sct_oldown reject MAXNOC - 1
X sct_che_target 0 MAXNOC - 1
edit s O shp_own cast skip
edit u O lnd_own cast skip
edit p O pln_own cast skip
Legend:
0 replace arg by 0
MAXNOC - 1 replace arg by MAXNOC - 1
reject command fails
cast replace arg by (natid)arg
bug: can be >= MAXNOC!
skip ignore this key and arg
bug: telexes the owner he lost the unit, which is a lie
Unify to reject. Matches setsector.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
cname() calls getnatp(), and returns a null pointer when it fails.
Some systems (GNU, Windows) deal gracefully with printing null
strings, others crash.
Because we keep table EF_NATION entirely in memory, getnatp() should
fail only on invalid country number.
Rewrite prnatid() to catch this error and recover.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
edit: Rename some of helpers, and reorder parameters
doland() edits a sector, not a land unit. That one's called dounit().
Lacks taste. Call the helper for editing a FOO edit_FOO(), and make
the FOO * the first parameter instead of the last.
Rename the print helpers to print_FOO(), for consistency. Also frees
up identifier prnat for the next commit.
While there, clean up an unused #define.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
tests/actofgod: New, disabled for now because it oopses
This is a fairly comprehensive test of the deity commands to edit game
state: edit, setresource, setsector, give, swapsector.
The test makes edit screw up game state, triggering oopses. The
server refuses to start without -F then, and empdump -x warns "export
has errors, not importable as is". Until these bugs are fixed, skip
this test in "make check".
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
tests: Capture player output via journal instead of client
Capturing the client's output tests both client and server, which is
nice. However, player input isn't visible in the resulting file,
which makes it more difficult to understand.
Route player output to journal (econfig key "keep_journal 2"), and
ignore client output.
Separate tests for the client would be useful.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
satmap: Separate and align columns in output properly
Land unit coordinates run into efficiency in output of satellite when
the y coordinate is wider than three characters. Broken in Empire 2.
Restore the separating space.
Both ship and land unit table header aren't aligned with the table
body. Affects recon and sweep with spy planes, and satellite. Fix
the header.
Reported-by: William Fittge <ptkei2@gmail.com> Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
doc/coding section "git" is now redundant, except for the note on
avoiding whitespace changes. Move that to section "Code formatting",
and delete section "git".
Fix read beyond end of conditional argument on missing operand
nstr_parse_val() interprets argument "" as (empty) identifier, then
returns a pointer right beyond the end of the string.
The argument points into player->argbuf[]. If another argument
follows the conditional, it gets appended to the conditional. Else,
whatever's left there from previous commands gets appended. If the
argument is at the very end of player->argbuf[], we parse beyond the
buffer, until we run into a syntax error, or a zero byte.
Since player->argbuf[] is followed by a bunch of pointers, a syntax
error is almost certain. If we somehow manage to parse all the
pointers and player->lasttime, the runaway parse will end at
player->btused, because that's definitely zero when conditionals get
parsed.
Consistently require guns for dropping depth charges
The fire command requires at least one gun for depth charging, but
missions and return fire don't. Has always been that way, except
between 4.0.6 and commit a3ad623 (v4.3.12), when depth charging worked
exactly like gun fire, and guns were consistently required.
Change econfig key rollover_avail_max from 0 to 50
So you don't have to micromanage workers to maximize useful work.
The previous commit made the problem a bit worse. If you had a few
workers too many before, you perhaps produced an extra unit. Now, you
get to keep the extra work instead. Useless, unless it rolls over.
produce() limits production to how many units the workers can produce,
rounding randomly. It charges work for the units actually produced,
discarding fractions.
If you get lucky with the random rounding, you may get a bit of extra
work done for free. Else, you get to keep the unused work, and may
even be undercharged a tiny bit of work. Has always been that way.
The production command assumes the random rounding rounds up if and
only if the probability to do so is at least 50%. Thus, it's
frequently off by one for sectors producing at their worker limit.
The budget command runs the update code, and is therefore also off by
one, only differently.
Rather annoying for tech and research centers, where a single unit
matters. A tech center with full civilian population can produce 37.5
units in 60 etus. Given enough materials, it'll fluctuate between 37
and 38. Production consistently predicts 38, and budget randomly
predicts either 37 or 38. Both are off by one half the time.
Fix this as follows: limit production to the amount the workers can
produce (no rounding). Work becomes a hard limit, not subject to
random fluctuations. Randomly round the work charged for actual
production. On average, this charges exactly the work that's used.
More importantly, production and budget now predict how much gets
produced more accurately. They're still not exact, as the amount of
work available for production remains slightly random.
This also "fixes" the smoke test on a i686 Debian 6 box for me. The
root problem is that floating-point subexpressions may either be
computed in double precision or extended precision. Different
machines (or different compilers, or even different compiler flags)
may use different precision, and get different results.
Example: producing 108 units at one work per unit, sector p.e. 0.4
needs to charge 108 / 0.4 work. Computed in double precision, this
gets rounded to 270.0, then truncated to 270. In 80 bit extended
precision, it gets rounded to 269.999999999, then truncated to 269.
With random rounding instead of truncation, the probability for a
different result is vanishingly small. However, this commit
introduces truncation in another place. It just happens not to mess
up the smoke test there. I doubt this is the last time this kind of
problem upsets the smoke test.
Fix xdump nat column ip for connections from "long" IPv6 addresses
Broken in commit 3a7d7fa, which enlarged struct natstr member
nat_hostaddr[] from 32 to 46 characters, but neglected to update the
ca_len in nat_ca[]. Consequently, the address is truncated in xdump.
Can also break country * ?ip=... and such, but that's exotic.
Fix five year old show stopper bugs on big endian hosts
emp_server and empdump refuse to start on most big endian hosts,
because ef_verify_config() chokes on mdchr_ca[]:
Config meta uid 0 field type: value 0 is not in symbol table meta-type
Config meta uid 1 field type: value 0 is not in symbol table meta-type
Config meta uid 2 field type: value 0 is not in symbol table meta-type
Config meta uid 3 field type: value 0 is not in symbol table meta-type
Config meta uid 4 field type: value 0 is not in symbol table meta-type
Broken in commit 06a0036 (v4.3.12), which changed struct castr member
ca_type from packed_nsc_type (typedef'ed to char) to enum nsc_type,
but neglected to update the ca_type in mdchr_ca[].
On little endian hosts, the selector reads the least significant byte,
with sign extension. Happens to work, because the type values are all
sufficiently small integers.
On big endian hosts, the selector reads the most signiciant byte.
which is always zero (NSC_NOTYPE). Makes ef_verify_config() fail.
Except when sizeof(enum nsc_notype) == 1. Then selector type works
fine, and ef_verify_config() succeeds, but we run into the next
problem: the same commit also changed member ca_flags from nsc_flags
(typedef'ed to unsigned char) to int without updating the ca_type in
mdchr_ca[]. This breaks "only" xdump meta column flags.
v4.3.12 was released in April 2008. Either nobody has tried to run a
game on a big endian host since, or all who did gave up quietly,
without reporting the problem.
We clearly need to test on a wider range of machines.
Broken in commit 14ea670 (v4.3.8), which changed struct trdstr member
trd_type from char to short, but neglected to update the ca_type in
trade_ca[].
On little endian hosts, the selector reads the least significant byte,
with sign extension. Happens to work, because the type values are all
sufficiently small integers.
On big endian hosts, the selector reads the most signiciant byte,
which is always zero (EF_SECTOR). Messes up xdump trade badly.
Broken in commit 09248d0 (v4.3.8), which changed struct loststr member
lost_type from char to short, but neglected to update the ca_type in
lost_ca[].
On little endian hosts, the selector reads the least significant byte,
with sign extension. Happens to work, because the type values are all
sufficiently small integers.
On big endian hosts, the selector reads the most signiciant byte,
which is always zero (EF_SECTOR). Messes up xdump lost badly. Also
breaks lost * ?type=..., but that's exotic.
"Unusually long" topics are marked with a "!" in subject indexes.
This should use the line count of the formatted page, but that's too
much trouble, so commit 4c0b4c0 (v4.3.27) approximated it by "source
file has more than 9999 bytes". Change that to "source file has more
than 300 lines".
Declare subjects instead of picking them up automatically
Since subjects were added in Empire 2, we've always picked them up
from .SA requests. If you mistype a subject there, you get a "is a
NEW subject" warning, and incorrect subject pages. When building a
pristine tree, you get bogus "is a NEW subject" warnings for all
subjects. If you somehow delete the generated subjects.mk, but not
the generated subject files, the build breaks.
Declare subjects in Make variable subjects. Drop generated makefile
subject.mk.
Treat unknown topics in .SA arguments as errors. This replaces the
"$subj is a NEW subject" warning.
Treat subjects without member pages as errors. This replaces the "The
subject $subj has been removed" warning.
We used to do all the info indexing work in info.pl: find subjects,
create subjects.mk (to tell make the list of subjects), the subject
pages, and TOP.t. Worked, but touching an info page triggered a full
rebuild of all subject pages and TOP.t.
Commit 2f14064 (v4.3.0) tried to avoid that by splitting info.pl into
findsubj.pl, mksubj.pl, mktop.pl. findsubj.pl puts not just the
subjects into subjects.mk, but also make rules for the subject pages,
to guide their remaking. mksubj.pl creates a single subject page.
mktop.pl creates TOP.t.
Unfortunately, this doesn't work so well. Since subjects.mk doesn't
exist in a virgin tree, we use -include. Unwanted consequence:
findsubj.pl failure doesn't stop make. Moreover, the complex make
machinery breaks down when info sources get removed or subjects get
dropped.
Go back to the old method, except keep mktop.pl separate, as that part
works just fine, and use simpler make rules. mksubj.pl now creates
subjects.mk and all subject pages, like info.pl did.
This effectively reverts most of commit 2f14064. I'll address the
excessive rebuilding of subject pages in a different way shortly.
Remaking config.h and config.h.in updates the target only when its
contents actually changes. This is important, because after updating
config.h we need to recompile everything.
The make rules to do that are straight from the Autoconf manual. But
they don't work: the rules that connect config.h and config.h.in to
stamp-h and stamp-h.in don't have recipes. Since make doesn't have an
implicit rule either, it concludes that the target remains unchanged.
It still updates the prerequisites. The recipe for updating the stamp
files then change the the targetes behind make's back. Make misses
the change of config.h and/or config.h.in, and we get an incomplete
rebuild.
The rules need empty recipes instead. This Autoconf manual was fixed
accordingly in autoconf.git commit 6b42b38.
Mark obsolete pages with '+' in subject pages. Drop the separate
"Obsolete" subject page: move "info Innards" to subject "Server", and
"info update" to "Updates" (where it came from in commit a5764534,
v4.3.10).
Document GNU libc lossage in listen_addr doc string
Systems using GNU libc such as Linux are frequently configured in a
way getaddrinfo(NULL, ...) put the IPv4 wildcard "0.0.0.0" *before*
the IPv6 wildcard "::" in the result. Because of that, listen_addr ""
listens only on all IPv4 addresses. Workaround: listen_addr "::".
Fix wildcard bind to at least bind IPv4 or else IPv6 on OpenBSD
OpenBSD refuses to implement IPV6_V6ONLY, in violation of RFC 3493.
RFC 4038 frowningly recognizes this practice. The only way to bind
both IPv4 and IPv4 there is two separate sockets. Requires more
surgery than I can do now.
Since we can't have both IPv6 and IPv6 on OpenBSD with our single
socket, prefer IPv4, but if that doesn't work, do IPv6.
To prefer IPv6 instead, put 'listen_addr "::"' into econfig. Document
that in listen_addr's doc string.
Fix wildcard bind to bind both IPv6 and IPv4 on Windows & BSD
We rely on AF_INET6 wildcard bind() binding the AF_INET port, too,
i.e. IPV6_V6ONLY off. This should be the default according to RFC
3493 section 5.3, but isn't on Windows and BSD. RFC 4038 recognizes
this fact in section 4.2.
When IPV6_V6ONLY is on, an AF_INET6 wildcard bind only accepts
connections from IPv6 addresses. Thus, IPv4 doesn't work when
getaddrinfo() returns an AF_INET6 address first (which it should do
when the system has an IPv6 address configured).
Switch off IPV6_V6ONLY explicitly instead of relying on the default.
This makes IPv6 work on systems where IPV6_V6ONLY is on by default,
such as Windows and BSD.
Except for OpenBSD, which does not support switching it off. To be
addressed in the next commit.
Shouldn't fail. If it fails, but bind() works, the failure doesn't
matter. If bind() fails, we can just as well report that failure
instead of setsockopt()'s.
Change fairland island size probability distribution
Island size is randomly chosen from the interval [1..2*is+1], with
expected value is. Use two dice to roll the size instead of one.
This makes extreme sizes much less likely.
Make smoke test time out instead of hang when server misbehaves
The smoke test waits for the server completing startup by trying to
connect until it works. Hangs if the server doesn't complete startup
for some reason. Make it give up after 5s.
Likewise, The smoke test waits for the server to terminate by trying
kill -0 until it fails. Hangs if the server doesn't terminate. Make
it give up after 5s.
Fix extension of market bidding time when high bidder changes
Lots stay on the market until there's a bid and bidding time expires.
When the highest bidder changes, and less than five minutes of bidding
time are left, it gets extended by five minutes (since 4.0.7, actually
works since 4.0.9).
Normally, this ensures that the competition has at least five minutes
to react. Except when this is the first bid, bidding time may have
expired already. If it expired less than five minutes ago, the
competition still gets time to react, just less than it should. If it
expired earlier, the sale is executed immediately for units. For
commodities, the bidding time is set to expire in five minutes (since
4.2.0).
Instead of extending bidding time by five minutes, set it to expire in
five minutes, both for commodities and for units.
check_trade() converts the price to float, which can lose precision,
although only for ridiculously high prices. Has been broken since
4.0.0 introduced the market.
Avoid the conversion. Bulletins now show pre-tax price as $N instead
of $N.00.
Code dealing with money mixes int and long pretty haphazardly.
Harmless, because practical amounts of money fit into int on any
machine capable of running the server. Clean up anyway.
Fix melting of big piles of stuff by ridiculously heavy fallout
meltitems() computes #items * etus per update * fallout in type long.
Theoretical maximum is ITEM_MAX * etus * FALLOUT_MAX = 99980001 *
etus. Can overflow 32 bits for etus > 21. Has been broken since the
introduction of fallout in KSU.
Code dealing with reserves mixes int and long pretty haphazardly.
Harmless, because practical reserves fit easily on any machine capable
of running the server. Clean up anyway.