Feature #1397 » 0031-Change-behaviour-to-behavior.patch
| ai/default/daidata.h | ||
|---|---|---|
|
struct player;
|
||
|
enum winning_strategy {
|
||
|
WIN_OPEN, /* still undetermined */
|
||
|
WIN_WAR, /* we have no other choice than to crush all opposition */
|
||
|
WIN_SPACE, /* we will race for space, peace very important */
|
||
|
WIN_CAPITAL /* we cannot win unless we take war_target's capital */
|
||
|
WIN_OPEN, /* Still undetermined */
|
||
|
WIN_WAR, /* We have no other choice than to crush all opposition */
|
||
|
WIN_SPACE, /* We will race for space, peace very important */
|
||
|
WIN_CAPITAL /* We cannot win unless we take war_target's capital */
|
||
|
};
|
||
|
#define SPECENUM_NAME war_reason
|
||
|
#define SPECENUM_VALUE0 DAI_WR_BEHAVIOUR
|
||
|
#define SPECENUM_VALUE0NAME "Behaviour"
|
||
|
#define SPECENUM_VALUE0 DAI_WR_BEHAVIOR
|
||
|
#define SPECENUM_VALUE0NAME "Behavior"
|
||
|
#define SPECENUM_VALUE1 DAI_WR_SPACE
|
||
|
#define SPECENUM_VALUE1NAME "Space"
|
||
|
#define SPECENUM_VALUE2 DAI_WR_EXCUSE
|
||
| ai/default/daidiplomacy.c | ||
|---|---|---|
|
player_name(pplayer));
|
||
|
adip->countdown = -10;
|
||
|
break;
|
||
|
case DAI_WR_BEHAVIOUR:
|
||
|
case DAI_WR_BEHAVIOR:
|
||
|
dai_diplo_notify(target,
|
||
|
_("*%s (AI)* I have tolerated your vicious antics "
|
||
|
"long enough! To war!"),
|
||
| ... | ... | |
|
"Long live our glorious alliance!"),
|
||
|
player_name(pplayer));
|
||
|
break;
|
||
|
case DAI_WR_BEHAVIOUR:
|
||
|
case DAI_WR_BEHAVIOR:
|
||
|
case DAI_WR_EXCUSE:
|
||
|
dai_diplo_notify(ally,
|
||
|
PL_("*%s (AI)* %s has grossly violated their treaties "
|
||
| ... | ... | |
|
&& dai_diplomacy_get(ait, pplayer, aplayer)->countdown == -1) {
|
||
|
DIPLO_LOG(ait, LOG_DIPL2, pplayer, aplayer, "Plans war in revenge");
|
||
|
war_countdown(ait, pplayer, aplayer, map_size_checked(),
|
||
|
DAI_WR_BEHAVIOUR);
|
||
|
DAI_WR_BEHAVIOR);
|
||
|
}
|
||
|
} players_iterate_end;
|
||
| ai/default/daitools.c | ||
|---|---|---|
|
if (unit_has_type_flag(punit, UTYF_WORKERS)) {
|
||
|
parameter->get_TB = no_fights;
|
||
|
} else if (long_path && unit_is_cityfounder(punit)) {
|
||
|
/* Default tile behaviour;
|
||
|
/* Default tile behavior;
|
||
|
* move as far along the path to the destination as we can;
|
||
|
* that is, ignore the presence of enemy units when computing the
|
||
|
* path.
|
||
| ... | ... | |
|
parameter->get_TB = no_fights;
|
||
|
} else if (is_losing_hp(punit)) {
|
||
|
/* Losing hitpoints over time (helicopter in default rules) */
|
||
|
/* Default tile behaviour */
|
||
|
/* Default tile behavior */
|
||
|
} else if (utype_may_act_at_all(unit_type_get(punit))) {
|
||
|
switch (unit_data->task) {
|
||
|
case AIUNIT_AUTO_WORKER:
|
||
| ... | ... | |
|
parameter->get_TB = no_fights;
|
||
|
break;
|
||
|
case AIUNIT_NONE:
|
||
|
/* Default tile behaviour */
|
||
|
/* Default tile behavior */
|
||
|
break;
|
||
|
}
|
||
|
} else {
|
||
| client/audio_sdl.c | ||
|---|---|---|
|
};
|
||
|
/* Sounds don't sound good on Windows unless the buffer size is 4k,
|
||
|
* but this seems to cause strange behaviour on other systems,
|
||
|
* but this seems to cause strange behavior on other systems,
|
||
|
* such as a delay before playing the sound. */
|
||
|
#ifdef FREECIV_MSWINDOWS
|
||
|
const size_t buf_size = 4096;
|
||
| client/citydlg_common.c | ||
|---|---|---|
|
{
|
||
|
size_t i;
|
||
|
/* Likely to lead to quadratic behaviour, but who cares: */
|
||
|
/* Likely to lead to quadratic behavior, but who cares: */
|
||
|
for (i = 0; i < sum->n; i++) {
|
||
|
fc_assert(sum->sums != NULL);
|
||
|
if ((strcmp(sum->sums[i].posdesc, posdesc) == 0)
|
||
| client/gui-gtk-3.22/editprop.c | ||
|---|---|---|
|
lists of patterns. A pattern may be preceded by '!' to have its result
|
||
|
negated.
|
||
|
NB: If you change the behaviour of this function, be sure to update
|
||
|
NB: If you change the behavior of this function, be sure to update
|
||
|
the filter tooltip in property_page_new().
|
||
|
****************************************************************************/
|
||
|
static struct property_filter *property_filter_new(const char *filter)
|
||
| ... | ... | |
|
a|b&c - Matches all properties whose names contain either an "a",
|
||
|
or contain both "b" and "c".
|
||
|
NB: If you change the behaviour of this function, be sure to update
|
||
|
NB: If you change the behavior of this function, be sure to update
|
||
|
the filter tooltip in property_page_new().
|
||
|
****************************************************************************/
|
||
|
static bool property_filter_match(struct property_filter *pf,
|
||
| client/gui-gtk-4.0/editprop.c | ||
|---|---|---|
|
lists of patterns. A pattern may be preceded by '!' to have its result
|
||
|
negated.
|
||
|
NB: If you change the behaviour of this function, be sure to update
|
||
|
NB: If you change the behavior of this function, be sure to update
|
||
|
the filter tooltip in property_page_new().
|
||
|
****************************************************************************/
|
||
|
static struct property_filter *property_filter_new(const char *filter)
|
||
| ... | ... | |
|
a|b&c - Matches all properties whose names contain either an "a",
|
||
|
or contain both "b" and "c".
|
||
|
NB: If you change the behaviour of this function, be sure to update
|
||
|
NB: If you change the behavior of this function, be sure to update
|
||
|
the filter tooltip in property_page_new().
|
||
|
****************************************************************************/
|
||
|
static bool property_filter_match(struct property_filter *pf,
|
||
| client/gui-gtk-5.0/editprop.c | ||
|---|---|---|
|
lists of patterns. A pattern may be preceded by '!' to have its result
|
||
|
negated.
|
||
|
NB: If you change the behaviour of this function, be sure to update
|
||
|
NB: If you change the behavior of this function, be sure to update
|
||
|
the filter tooltip in property_page_new().
|
||
|
****************************************************************************/
|
||
|
static struct property_filter *property_filter_new(const char *filter)
|
||
| ... | ... | |
|
a|b&c - Matches all properties whose names contain either an "a",
|
||
|
or contain both "b" and "c".
|
||
|
NB: If you change the behaviour of this function, be sure to update
|
||
|
NB: If you change the behavior of this function, be sure to update
|
||
|
the filter tooltip in property_page_new().
|
||
|
****************************************************************************/
|
||
|
static bool property_filter_match(struct property_filter *pf,
|
||
| client/mapctrl_common.c | ||
|---|---|---|
|
bool rbutton_down = FALSE;
|
||
|
bool rectangle_active = FALSE;
|
||
|
/* This changes the behaviour of left mouse
|
||
|
/* This changes the behavior of left mouse
|
||
|
button in Area Selection mode. */
|
||
|
bool tiles_hilited_cities = FALSE;
|
||
| client/options.c | ||
|---|---|---|
|
/* More backwards compatibility, for removed options that had been
|
||
|
* folded into then-existing options. Here, the backwards-compatibility
|
||
|
* behaviour overrides the "destination" option. */
|
||
|
* behavior overrides the "destination" option. */
|
||
|
/* Removed in 2.4 */
|
||
|
if (!secfile_lookup_bool_default(sf, TRUE,
|
||
| client/tilespec.c | ||
|---|---|---|
|
views.
|
||
|
NB: The 'layer' argument is NOT a LAYER_* value, but rather one of 0, 1, 2.
|
||
|
Using other values for 'layer' here will result in undefined behaviour. ;)
|
||
|
Using other values for 'layer' here will result in undefined behavior. ;)
|
||
|
****************************************************************************/
|
||
|
int fill_basic_terrain_layer_sprite_array(struct tileset *t,
|
||
|
struct drawn_sprite *sprs,
|
||
| common/aicore/citymap.c | ||
|---|---|---|
|
* the negative of the ID of the city or unit that has reserved the
|
||
|
* tile.
|
||
|
*
|
||
|
* Code that uses the citymap should modify its behaviour based on
|
||
|
* Code that uses the citymap should modify its behavior based on
|
||
|
* positive values encountered, and never attempt to steal a tile
|
||
|
* which has a negative value.
|
||
|
*/
|
||
| common/aicore/path_finding.h | ||
|---|---|---|
|
* The intended meaning for EC is "how much we want to avoid this tile",
|
||
|
* see DISCUSSION below for more.
|
||
|
*
|
||
|
* tile behaviour (TB): the extra information about a tile which
|
||
|
* tile behavior (TB): the extra information about a tile which
|
||
|
* tells us whether we can enter and leave tile as normal (see enum
|
||
|
* tile_behavior).
|
||
|
*
|
||
| ... | ... | |
|
* paths/tiles we want to consider. For example, a trireme might want to
|
||
|
* never enter deep sea. A chariot, would like to find paths going to
|
||
|
* enemy cities but not going _through_ them. This can be achieved
|
||
|
* through an additional tile_behaviour callback, which would return
|
||
|
* through an additional tile_behavior callback, which would return
|
||
|
* TB_IGNORE for tiles we don't want to visit and TB_DONT_LEAVE for tiles
|
||
|
* we won't be able to leave (at least alive).
|
||
|
*
|
||
| ... | ... | |
|
*
|
||
|
*
|
||
|
* FORMULAE:
|
||
|
* For calculating total_MC (given particular tile_behaviour)
|
||
|
* For calculating total_MC (given particular tile_behavior)
|
||
|
* total_MC = ((turn + 1) * move_rate - moves_left)
|
||
|
*
|
||
|
* For calculating total_CC:
|
||
| ... | ... | |
|
* not guaranteed to get the one with the least steps in it. If you care,
|
||
|
* specifying EC to be 1 will do the job.
|
||
|
* 3. To prevent AI from thinking that it can pass through "chokepoints"
|
||
|
* controlled by enemy cities, you can specify tile behaviour of each
|
||
|
* controlled by enemy cities, you can specify tile behavior of each
|
||
|
* occupied enemy city to be TB_DONT_LEAVE.
|
||
|
*/
|
||
| common/aicore/pf_tools.c | ||
|---|---|---|
|
}
|
||
|
/* NB: if there are UTYF_NEVER_PROTECTS units on the tile, 'attack_any'
|
||
|
has to get set TRUE at least once to enable an attack to the tile,
|
||
|
which is exactly correct behaviour. */
|
||
|
which is exactly correct behavior. */
|
||
|
}
|
||
|
} unit_list_iterate_end;
|
||
| ... | ... | |
|
}
|
||
|
/* ===================== Tile Behaviour Callbacks ==================== */
|
||
|
/* ===================== Tile Behavior Callbacks ===================== */
|
||
|
/************************************************************************//**
|
||
|
PF callback to prohibit going into the unknown. Also makes sure we
|
||
| ... | ... | |
|
A callback for amphibious movement
|
||
|
****************************************************************************/
|
||
|
static enum tile_behavior
|
||
|
amphibious_behaviour(const struct tile *ptile, enum known_type known,
|
||
|
const struct pf_parameter *param)
|
||
|
amphibious_behavior(const struct tile *ptile, enum known_type known,
|
||
|
const struct pf_parameter *param)
|
||
|
{
|
||
|
struct pft_amphibious *amphibious = param->data;
|
||
|
const bool ferry_move = is_native_tile(amphibious->sea.utype, ptile);
|
||
| ... | ... | |
|
parameter->combined.move_rate = move_rate;
|
||
|
parameter->combined.get_MC = amphibious_move;
|
||
|
parameter->combined.get_move_scope = amphibious_move_scope;
|
||
|
parameter->combined.get_TB = amphibious_behaviour;
|
||
|
parameter->combined.get_TB = amphibious_behavior;
|
||
|
parameter->combined.get_EC = amphibious_extra_cost;
|
||
|
if (NULL != parameter->land.is_pos_dangerous
|
||
|
|| NULL != parameter->sea.is_pos_dangerous) {
|
||
| common/chat.h | ||
|---|---|---|
|
#define FC__CHAT_H
|
||
|
/* Definitions related to interpreting chat messages.
|
||
|
* Behaviour generally can't be changed at whim because client and
|
||
|
* Behavior generally can't be changed at whim because client and
|
||
|
* server are assumed to agree on these details. */
|
||
|
#ifdef __cplusplus
|
||
| data/alien/nations.ruleset | ||
|---|---|---|
|
; Descriptions of nation groups
|
||
|
; These are more cosmetic than sets; they affect the "pick nation" dialog,
|
||
|
; random nation selection, and possibly ruleset behaviour.
|
||
|
; random nation selection, and possibly ruleset behavior.
|
||
|
; It`s OK to not define any nation groups at all.
|
||
|
; name = name of the group (used adjectivally)
|
||
|
; hidden = TRUE to not include this group in the "pick nation" dialog
|
||
| data/civ1/nations.ruleset | ||
|---|---|---|
|
; Descriptions of nation groups
|
||
|
; These are more cosmetic than sets; they affect the "pick nation" dialog,
|
||
|
; random nation selection, and possibly ruleset behaviour.
|
||
|
; random nation selection, and possibly ruleset behavior.
|
||
|
; It`s OK to not define any nation groups at all.
|
||
|
; name = name of the group (used adjectivally)
|
||
|
; hidden = TRUE to not include this group in the "pick nation" dialog
|
||
| data/civ2/nations.ruleset | ||
|---|---|---|
|
; Descriptions of nation groups
|
||
|
; These are more cosmetic than sets; they affect the "pick nation" dialog,
|
||
|
; random nation selection, and possibly ruleset behaviour.
|
||
|
; random nation selection, and possibly ruleset behavior.
|
||
|
; It`s OK to not define any nation groups at all.
|
||
|
; name = name of the group (used adjectivally)
|
||
|
; hidden = TRUE to not include this group in the "pick nation" dialog
|
||
| data/default/nationlist.ruleset | ||
|---|---|---|
|
; Descriptions of nation groups
|
||
|
; These are more cosmetic than sets; they affect the "pick nation" dialog,
|
||
|
; random nation selection, and possibly ruleset behaviour.
|
||
|
; random nation selection, and possibly ruleset behavior.
|
||
|
; It`s OK to not define any nation groups at all.
|
||
|
; name = name of the group (used adjectivally)
|
||
|
; hidden = TRUE to not include this group in the "pick nation" dialog
|
||
| data/helpdata.txt | ||
|---|---|---|
|
these must all be made merely unhappy before any unhappy citizens can \
|
||
|
be made content, but in all other respects behave as unhappy citizens.\
|
||
|
"),
|
||
|
; Behaviour of angry citizens is actually a bit more complicated than
|
||
|
; Behavior of angry citizens is actually a bit more complicated than
|
||
|
; this. See city_refresh_from_main_map() in common/city.c.
|
||
|
_("\
|
||
|
Luxury makes citizens happy. For every two luxury points a city \
|
||
| data/ruledit/comments-3.3.txt | ||
|---|---|---|
|
\n\
|
||
|
; Descriptions of nation groups\n\
|
||
|
; These are more cosmetic than sets; they affect the \"pick nation\" dialog,\n\
|
||
|
; random nation selection, and possibly ruleset behaviour.\n\
|
||
|
; random nation selection, and possibly ruleset behavior.\n\
|
||
|
; It`s OK to not define any nation groups at all.\n\
|
||
|
; name = name of the group (used adjectivally)\n\
|
||
|
; hidden = TRUE to not include this group in the \"pick nation\" dialog\n\
|
||
| data/stub/nations.ruleset | ||
|---|---|---|
|
; Descriptions of nation groups
|
||
|
; These are more cosmetic than sets; they affect the "pick nation" dialog,
|
||
|
; random nation selection, and possibly ruleset behaviour.
|
||
|
; random nation selection, and possibly ruleset behavior.
|
||
|
; It`s OK to not define any nation groups at all.
|
||
|
; name = name of the group (used adjectivally)
|
||
|
; hidden = TRUE to not include this group in the "pick nation" dialog
|
||
| doc/FAQ | ||
|---|---|---|
|
So the goal of compatibility is mainly used as a limiting factor in
|
||
|
development: when a new feature is added to Freeciv that makes gameplay
|
||
|
different, it is generally implemented in such a way that the
|
||
|
"traditional" behaviour remains available as an option. However, we're
|
||
|
"traditional" behavior remains available as an option. However, we're
|
||
|
not aiming for absolute 100% compatibility; in particular, we're not
|
||
|
aiming for bug-compatibility.
|
||
| doc/HACKING | ||
|---|---|---|
|
Tile ownership is decided only by the server, and sent to the clients, which
|
||
|
draw border lines between tiles of differing ownership. Owner information is
|
||
|
sent for all tiles that are known by a client, whether or not they are fogged.
|
||
|
A patch to convert this to "semi-fogged" behaviour, whereby clients receive
|
||
|
A patch to convert this to "semi-fogged" behavior, whereby clients receive
|
||
|
limited information about non-neighboring and unseen enemies, is available
|
||
|
at http://freecivac.sf.net/.
|
||
| doc/README.AI | ||
|---|---|---|
|
probably better described by statistical mechanics than by logic.
|
||
|
Both ferries and prospective passenger (PP) move around in what looks
|
||
|
like a random fashion, trying to get closer to each other. On
|
||
|
average, they succeed. This behaviour has good reasons behind it, is
|
||
|
average, they succeed. This behavior has good reasons behind it, is
|
||
|
hell to debug but means that small bugs don't affect overall picture
|
||
|
visibly (and stay unfixed as a result).
|
||
| ... | ... | |
|
prior arrangements is the only good strategy -- it means that a boat
|
||
|
will not rely on the PP to notify it when it's not needed anymore.
|
||
|
This is not very effective but can only be changed when the PPs behave
|
||
|
more responsibly. See diplomat code for more responsible behaviour --
|
||
|
more responsibly. See diplomat code for more responsible behavior --
|
||
|
they try to check if the old target is still good before trying to
|
||
|
find a new one.
|
||
| ... | ... | |
|
DIPLOMACY
|
||
|
=========
|
||
|
The AI's diplomatic behaviour is current only regulated by the
|
||
|
The AI's diplomatic behavior is current only regulated by the
|
||
|
'diplomacy' server setting.
|
||
|
Easier AI levels propose cease-fire on first contact.
|
||
| doc/README.rulesets | ||
|---|---|---|
|
- To play Freeciv normally: don't do anything special; the new
|
||
|
features all have defaults which give the standard Freeciv
|
||
|
behaviour.
|
||
|
behavior.
|
||
|
- To play a game with rules more like Civ1, start the server with:
|
||
|
./fcser -r data/civ1.serv
|
||
| server/cityturn.c | ||
|---|---|---|
|
/* History can decrease, but never go below zero */
|
||
|
pcity->history = MAX(pcity->history, 0);
|
||
|
/* Keep old behaviour when building new improvement could keep
|
||
|
/* Keep old behavior when building new improvement could keep
|
||
|
city celebrating */
|
||
|
if (!is_happy) {
|
||
|
is_happy = city_happy(pcity);
|
||
| server/savegame/savecompat.c | ||
|---|---|---|
|
for (p = 0; p < maxslots; p++) {
|
||
|
l = p / 32;
|
||
|
for (x = 0; x < xsize; x++) {
|
||
|
/* This test causes bit-shifts of >=32 (undefined behaviour), but
|
||
|
/* This test causes bit-shifts of >=32 (undefined behavior), but
|
||
|
* on common platforms, information happens not to be lost, just
|
||
|
* oddly arranged. */
|
||
|
if (known_row_old[l * xsize + x] & (1u << (p - l * 8))) {
|
||
| ... | ... | |
|
/* In 2.3.x and prior, saveturns=0 meant no turn-based saves.
|
||
|
* This is now controlled by the "autosaves" setting. */
|
||
|
if (!fc_strcasecmp("saveturns", name)) {
|
||
|
/* XXX: hardcodes details from GAME_AUTOSAVES_DEFAULT
|
||
|
/* XXX: Hardcodes details from GAME_AUTOSAVES_DEFAULT
|
||
|
* and settings.c:autosaves_name() (but these defaults reflect
|
||
|
* 2.3's behaviour). */
|
||
|
* 2.3's behavior). */
|
||
|
const char *const nosave = "GAMEOVER|QUITIDLE|INTERRUPT";
|
||
|
const char *const save = "TURN|GAMEOVER|QUITIDLE|INTERRUPT";
|
||
|
int nturns;
|
||
| server/unittools.c | ||
|---|---|---|
|
* knock some levels off. */
|
||
|
lvls = utype_veteran_system(to_unit)->levels - 1;
|
||
|
punit->veteran = MIN(punit->veteran, lvls);
|
||
|
/* Keeping the old behaviour, so first clip top, then reduce */
|
||
|
/* Keeping the old behavior, so first clip top, then reduce */
|
||
|
punit->veteran = MAX(punit->veteran - vet_loss, 0);
|
||
|
/* Scale HP and MP, rounding down. Be careful with integer arithmetic,
|
||
| utility/fc_utf8.c | ||
|---|---|---|
|
number of used bytes, used strlen() instead.
|
||
|
NB: 'utf8_string' must be UTF-8 valid (see fc_utf8_validate()), or the
|
||
|
behaviour of this function will be unknown.
|
||
|
behavior of this function will be unknown.
|
||
|
****************************************************************************/
|
||
|
size_t fc_utf8_strlen(const char *utf8_string)
|
||
|
{
|
||
| utility/iterator.h | ||
|---|---|---|
|
Iterator base class. "Derived" iterators must have this struct as
|
||
|
their first member (as a "vtable") and provide implementations of the
|
||
|
"pure virtual" member functions. See the function comment headers
|
||
|
below for the expected behaviour of these functions.
|
||
|
below for the expected behavior of these functions.
|
||
|
***********************************************************************/
|
||
|
struct iterator {
|
||
|
void (*next)(struct iterator *it);
|
||
| utility/rand.c | ||
|---|---|---|
|
/*********************************************************************//**
|
||
|
Test one aspect of randomness, using n numbers.
|
||
|
Reports results to LOG_TEST; with good randomness, behaviourchange
|
||
|
and behavioursame should be about the same size.
|
||
|
Reports results to LOG_TEST; with good randomness, behaviorchange
|
||
|
and behaviorsame should be about the same size.
|
||
|
Tests current random state; saves and restores state, so can call
|
||
|
without interrupting current sequence.
|
||
|
*************************************************************************/
|
||
| ... | ... | |
|
RANDOM_STATE saved_state;
|
||
|
int i, old_value = 0, new_value;
|
||
|
bool didchange, olddidchange = FALSE;
|
||
|
int behaviourchange = 0, behavioursame = 0;
|
||
|
int behaviorchange = 0, behaviorsame = 0;
|
||
|
saved_state = fc_rand_state();
|
||
|
/* fc_srand(time(nullptr)); */ /* Use current state */
|
||
| ... | ... | |
|
didchange = (new_value != old_value);
|
||
|
if (i > 1) { /* Have olddidchange */
|
||
|
if (didchange != olddidchange) {
|
||
|
behaviourchange++;
|
||
|
behaviorchange++;
|
||
|
} else {
|
||
|
behavioursame++;
|
||
|
behaviorsame++;
|
||
|
}
|
||
|
}
|
||
|
olddidchange = didchange;
|
||
| ... | ... | |
|
old_value = new_value;
|
||
|
}
|
||
|
log_test("test_random1(%d) same: %d, change: %d",
|
||
|
n, behavioursame, behaviourchange);
|
||
|
n, behaviorsame, behaviorchange);
|
||
|
/* Restore state: */
|
||
|
fc_rand_set_state(saved_state);
|
||
| utility/support.c | ||
|---|---|---|
|
truncation occurred.
|
||
|
Not sure about the asserts below, but they are easier than
|
||
|
trying to ensure correct behaviour on strange inputs.
|
||
|
trying to ensure correct behavior on strange inputs.
|
||
|
In particular note that n == 0 is prohibited (e.g., since there
|
||
|
must at least be room for a nul); could consider other options.
|
||
|
****************************************************************************/
|
||