Skip to content
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
966cfac
doc cmdInput (1)
wlammen Mar 3, 2022
50bd232
copy preconditions of cmdInput to cmdInput1
wlammen Mar 3, 2022
4804d23
fix description of return in cmdInput
wlammen Mar 3, 2022
254c77c
document the role of CTRL-D in cmdInput
wlammen Mar 3, 2022
125f652
clarify some points
wlammen Mar 4, 2022
60c1181
better understand hyperlinking in doxygen
wlammen Mar 4, 2022
34533da
explain cmdIput1, next version
wlammen Mar 4, 2022
35e8952
explain cmdIput1, next version
wlammen Mar 4, 2022
e5e5cd2
explain cmdIput1, next version
wlammen Mar 4, 2022
83c4919
doc log file
wlammen Mar 4, 2022
39b356c
point out copy problems of pointers
wlammen Mar 4, 2022
1017b3d
doc addToUsedPool
wlammen Mar 4, 2022
da73b5c
fix incorrect usage of memUsedPool in case of full blocks
wlammen Mar 4, 2022
67fa533
clarify post cond. of addToUsedPool
wlammen Mar 4, 2022
ac1dc02
fix description of memUsedPool
wlammen Mar 4, 2022
49af905
doc poolFree
wlammen Mar 5, 2022
0fcfc29
add pre post conditions
wlammen Mar 5, 2022
7beeb0e
doc poolMalloc and others
wlammen Mar 5, 2022
61a4c78
fix doc of getPoolStats
wlammen Mar 5, 2022
702ca83
doc pntrTempAlloc
wlammen Mar 5, 2022
1dda3d7
fine tuning
wlammen Mar 5, 2022
023eda4
be more precise with temp_pntrString
wlammen Mar 5, 2022
ff8f9d1
improve doc of poolMalloc
wlammen Mar 5, 2022
c58210d
do the best to ref to bug()
wlammen Mar 6, 2022
d7ebf77
better doc early phase of pntrString allocation
wlammen Mar 6, 2022
bc48424
describe temporary stacks in more detail
wlammen Mar 6, 2022
0f3adf2
extend description of pntrTempAllocStack
wlammen Mar 6, 2022
9149544
improve doc of pntrLet
wlammen Mar 6, 2022
42fa455
improve doc of pntrLet
wlammen Mar 6, 2022
515fec4
fix doc of let
wlammen Mar 6, 2022
8ba2356
fix spelling errors
wlammen Mar 6, 2022
733456f
doc pntrAddElement
wlammen Mar 6, 2022
7f66022
doc submit mode in cmdInput1
wlammen Mar 6, 2022
251d2b5
finished doc of cmdInput1
wlammen Mar 6, 2022
677d6a7
the final edits were not saved, so here they are
wlammen Mar 6, 2022
d4d1faa
fix review issues
wlammen Mar 7, 2022
3021161
rm a LF
wlammen Mar 7, 2022
c9b3a49
add pre to pntrAddElement
wlammen Mar 7, 2022
91b9cd6
rm more unnecessary LF
wlammen Mar 7, 2022
80af6db
resolve merge conflicts
wlammen Mar 7, 2022
ff2ba42
fix dangling conflict marker
wlammen Mar 7, 2022
e9d586b
fix indentation
wlammen Mar 7, 2022
da19baf
css for customizing p tags
wlammen Mar 8, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/metamath.c
Original file line number Diff line number Diff line change
Expand Up @@ -723,16 +723,16 @@ void command(int argc, char *argv[]);
/*! \fn int main(int argc, char *argv[])
* \brief entry point of the metamath program
* \param argc int number of command line parameters
* \param argv (char*)[] array of \a argc command line parameters, followed by NULL
* \param argv (char*)[] array of \p argc command line parameters, followed by NULL
* \return success 0 else failure
*
* Running metamath
* ./metamath 'read set.mm' 'verify proof *'
* will start main with \a argc set to 2, argv[0] to "read set.mm", argv[1]
* will start main with \p argc set to 2, argv[0] to "read set.mm", argv[1]
* to "verify proof *" (both without quotes) and argv[2] to NULL.
* Returning 0 indicates successful completion, anything else some kind of
failure.
* For details see \ref https://en.cppreference.com/w/cpp/language/main_function.
* failure.
* For details see https://en.cppreference.com/w/cpp/language/main_function.
*/
int main(int argc, char *argv[]) {

Expand Down
4 changes: 2 additions & 2 deletions src/mmcmdl.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ extern flag g_commandEcho; /* Echo full command */
/*!
* \brief indicates whether the user has turned MEMORY STATUS on.
*
* If the user issues SET MEMORY_STATUS ON this \a flag is set to 1. It is
* If the user issues SET MEMORY_STATUS ON this \ref flag is set to 1. It is
* reset to 0 again on a SET MEMORY_STATUS OFF command. When 1, certain
* memory de/allocations are monitored - see \a db3.
* memory de/allocations are monitored - see \ref db3.
*/
extern flag g_memoryStatus; /* Always show memory */

Expand Down
169 changes: 127 additions & 42 deletions src/mmdata.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,10 @@ vstring g_qsortKey; /* Used by qsortStringCmp; pointer only, do not deallocate *
* During execution chunks of memory, either complete \ref block "blocks" or
* \ref fragmentation "fragments" thereof, become free again. The suballocator
* adds them then to internal **pools** for reuse, one dedicated to totally
* free blocks (\a memFreePool), the other to fragmented ones (\a memUsedPool).
* We call these pools **free block array** and **used block array** in this
* documentation. Fully occupied blocks are not tracked by the suballocator.
* free blocks (\ref memFreePool), the other to fragmented ones
* (\ref memUsedPool). We call these pools **free block array** and
* **used block array** in this documentation. Fully occupied blocks are not
* tracked by the suballocator.
*
* Although the suballocator tries to avoid returning memory to the system, it
* can do so under extreme memory constraints, or when built-in limits are
Expand Down Expand Up @@ -138,10 +139,11 @@ vstring g_qsortKey; /* Used by qsortStringCmp; pointer only, do not deallocate *
*
* offset -3:\n
* If this block has free space at the end (is \ref fragmentation
* "fragmented"), then it contains its index in the used blocks array, see
* \a memUsedPool. A value of -1 indicates it is either fully occupied or
* totally free. In any of these cases it is not kept in the used blocks
* array.
* "fragmented"), then this value contains its index in the used blocks
* array, see \ref memUsedPool. A value of -1 indicates it is either fully
* occupied or totally free. It is not kept in the used blocks array then.
* If this block becomes full in the course of events, it is not
* automatically removed from \ref memUsedPool, though.
*/

/*! \page Pool
Expand All @@ -152,8 +154,8 @@ vstring g_qsortKey; /* Used by qsortStringCmp; pointer only, do not deallocate *
* In Metamath a pool has no gaps in between.
*
* The \ref suballocation "suballocator" uses two pools:
* - the **free block array** pointed to by \a memFreePool;
* - the **used block array** pointed to by \a memUsedPool.
* - the **free block array** pointed to by \ref memFreePool;
* - the **used block array** pointed to by \ref memUsedPool.
*/

/*! \page stack Temporary Allocated Memory
Expand All @@ -165,17 +167,32 @@ vstring g_qsortKey; /* Used by qsortStringCmp; pointer only, do not deallocate *
* ubiquitous and frequent, that the processor, and all relevant program
* languages provide simple mechanisms for de/allocation of such __local__
* data. Metamath is no exception to this.
*
* While the C compiler silently cares about __local__ variables, it must not
* interfere with data managed by a \ref suballocation "Suballocator". Instead
* of tracking all __locally__ created memory individually for later
* deallocation, a stack like \ref Pool "pool" allows a command like
* `free all memory` that has been created after a certain point. This greatly
* automatizes handling of these data.
* deallocation, a stack like \ref Pool "pool" is used to automate this
* handling.
*
* Stacks of temporary data only contain pointers to dynamically allocated
* memory from the heap or the \ref suballocator. This stack functions like an
* operand stack. A final result depends on fragments, temporary results and
* similar, all pushed onto this stack. When the final operation is executed,
* and its result is persisted in some variable, the dependency on its
* temporary operands ceases. Consequently, they should be freed again. To
* automate this operation, such a stack maintains a __start__ index. A
* client saves this value and sets it to the current stack top, then starts
* pushing dynamically allocated operands on the stack. After the result is
* persisted, all entries beginning with the element at index __start__ are
* deallocated again, and the stack top is reset to the __start__ value, while
* the __start__ value is reset to the saved value, to accomodate nesting of
* this procedure.
*
* A stack is not the same as a \ref block "block", though similar. Like a
* block it is defined as an array of elements, but it comes with no hidden
* header. Instead openly accessible stack pointer (actually indices) directly
* support stack semantics.
* This scheme needs a few conditions to be met:
* - No operand is used in more than one evaluation context;
* - Operations are executed strictly sequential, or in a nested manner. No two
* operations interleave pushing operands.
* push operands interleaved
*/

/* Memory pools are used to reduce the number of malloc and alloc calls that
Expand All @@ -196,14 +213,31 @@ vstring g_qsortKey; /* Used by qsortStringCmp; pointer only, do not deallocate *
The pointer to an array always points to element 0 (recast to right size).
*/

/*!
* \def MEM_POOL_GROW
* Amount that \ref memUsedPool and \ref memFreePool grows when it overflows.
*/
#define MEM_POOL_GROW 1000 /* Amount that a pool grows when it overflows. */
/*??? Let user set this from menu. */
/*!
* \var long poolAbsoluteMax
* The value is a memory amount in bytes.
* \n
* The \ref suballocator scheme must not hold more memory than is short term
* useful. To the operating system all memory in \ref memFreePool appears as
* allocated, although it is not really in use. To prevent the system from
* taking unnecessary action such as saving RAM to disk, a limit to the amount
* of free memory managed by the suballocator can be set up. This limit is
* checked in frequent operations, and an automatic purge process is initiated
* in \ref memFreePoolPurge should \ref poolTotalFree exceed this value.
*/
long poolAbsoluteMax = 1000000; /* Pools will be purged when this is reached */
/*!
* \var long poolTotalFree
* contains the number of free space available in bytes, in both pools
* \a memFreePool and \a memUsedPool, never counting the hidden headers at the
* beginning of each block, see \ref block.
* \ref memFreePool and \ref memUsedPool, never counting the hidden headers at
* the beginning of each block, see \ref block. Exceeding \ref poolAbsoluteMax
* may trigger an automatic purge process by \ref memFreePoolPurge.
*/
long poolTotalFree = 0; /* Total amount of free space allocated in pool */
/*E*/long i1,j1_,k1; /* 'j1' is a built-in function */
Expand All @@ -224,7 +258,9 @@ long poolTotalFree = 0; /* Total amount of free space allocated in pool */
*
* The used block array may only be partially occupied, in which case elements
* at the end of the array are unused. Its current usage is given by
* \a memUsedPoolSize. Its capacity is given by \a memUsedPoolMax.
* \ref memUsedPoolSize. Its capacity is given by \ref memUsedPoolMax.
*
* \attention The pool may contain full \ref block "blocks".
*
* \invariant Each block in the used blocks array has its index noted in its
* hidden header, for backward reference.
Expand All @@ -241,9 +277,9 @@ void **memUsedPool = NULL;
* The Metamath suballocator holds fragmented blocks in a used block array.
* The number of occupied entries is kept in this variable. Elements at the
* end of the used block array may be unused. The fill size is given by this
* variable. For further information see \a memUsedPool.
* variable. For further information see \ref memUsedPool.
*
* \invariant memUsedPoolSize <= \a memUsedPoolMax.
* \invariant memUsedPoolSize <= \ref memUsedPoolMax.
*/
long memUsedPoolSize = 0; /* Current # of partially filled arrays in use */
/*!
Expand All @@ -253,11 +289,11 @@ long memUsedPoolSize = 0; /* Current # of partially filled arrays in use */
*
* The Metamath suballocator holds fragmented blocks in the used block
* array. This array may only partially be occupied. Its total capacity is
* kept in this variable. For further information see \a memUsedPool.
* kept in this variable. For further information see \ref memUsedPool.
*
* This variable may grow during a reallocation process.
*
* \invariant (memUsedPoolMax > 0) == (\a memUsedPool != 0)
* \invariant (memUsedPoolMax > 0) == (\ref memUsedPool != 0)
*/
long memUsedPoolMax = 0; /* Maximum # of entries in 'in use' table (grows
as necessary) */
Expand All @@ -274,9 +310,9 @@ long memUsedPoolMax = 0; /* Maximum # of entries in 'in use' table (grows
* The **free block array** contains only totally free \ref block "blocks".
* This array may only be partially occupied, in which case the elements at the
* end are the unused ones. Its current fill size is given by
* \a memFreePoolSize. Its capacity is given by \a memFreePoolMax.
* \ref memFreePoolSize. Its capacity is given by \ref memFreePoolMax.
*
* Fragmented blocks are kept in a separate \a memUsedPool. The suballocator
* Fragmented blocks are kept in a separate \ref memUsedPool. The suballocator
* never tracks fully used blocks.
*/
void **memFreePool = NULL;
Expand All @@ -288,9 +324,9 @@ void **memFreePool = NULL;
* The Metamath suballocator holds free blocks in a free block array. The
* number of occupied entries is kept in this variable. Elements at the end of
* the free block array may not be used. The fill size is given by this
* variable. For further information see \a memFreePool.
* variable. For further information see \ref memFreePool.
*
* \invariant memFreePoolSize <= \a memFreePoolMax.
* \invariant memFreePoolSize <= \ref memFreePoolMax.
*/
long memFreePoolSize = 0; /* Current # of available, allocated arrays */
/*!
Expand All @@ -300,11 +336,11 @@ long memFreePoolSize = 0; /* Current # of available, allocated arrays */
*
* The Metamath suballocator holds free blocks in a **free block array**. It
* may only be partially occupied. Its total capacity is kept in this variable. For
* further information see \a memFreePool.
* further information see \ref memFreePool.
*
* This variable may grow during a reallocation process.
*
* \invariant (memFreePoolMax > 0) == (\a memFreePool != 0)
* \invariant (memFreePoolMax > 0) == (\ref memFreePool != 0)
*/
long memFreePoolMax = 0; /* Maximum # of entries in 'free' table (grows
as necessary) */
Expand Down Expand Up @@ -548,6 +584,21 @@ void addToUsedPool(void *ptr)
}

/* Free all arrays in the free pool. */
/*!
* \fn void memFreePoolPurge(flag untilOK)
* \brief returns memory held in \ref memFreePool
* Starting with the last entry in \ref memFreePool, memory held in that pool
* is returned to the system until all, or at least a sufficient amount is
* freed again (see \p untilOK).
* \param[in] untilOK if 1 freeing \ref block "blocks" stops the moment
* \ref poolTotalFree gets within the range of \ref poolAbsoluteMax again.
* Note that it is not guaranteed that the limit \ref poolAbsoluteMax is
* undercut because still too much free memory might be held in the
* \ref memUsedPool.
* \n
* If 0, all \ref memFreePool entries are freed, and the pool itself is
* shrunk back to \ref MEM_POOL_GROW size.
*/
void memFreePoolPurge(flag untilOK)
{
/*E*/if(db9)getPoolStats(&i1,&j1_,&k1); if(db9)printf("e0: pool %ld stat %ld\n",poolTotalFree,i1+j1_);
Expand Down Expand Up @@ -2413,16 +2464,48 @@ long g_pntrStartTempAllocStack = 0; /* Where to start freeing temporary alloca
when pntrLet() is called (normally 0, except in
special nested vstring functions) */
/*!
* \var pntrTempAllocStack
* \brief a \ref stack "stack" of \a temp_pntrString.
* \var pntrString *pntrTempAllocStack[]
* \brief a \ref stack "stack" of \ref temp_pntrString.
*
* Holds pointers to temporarily allocated data of type \a pntrString. Such a
* \ref stack "stack" contains strictly __local__ data of a function, not
* accessed from outer levels.
* Holds pointers to temporarily allocated data of type \ref temp_pntrString. Such
* a \ref stack "stack" is primarily designed to operate like one for temporary
* allocated ad hoc operands, as described in \ref stack. The stack top index
* is \ref g_pntrTempAllocStackTop, always refering to the next push position.
* The \ref g_pntrStartTempAllocStack supports nested operations by indicating
* where the operands for the upcoming operation start from.
* \attention A \ref pntrString consists of an array of pointers. These
* pointers may themself refer data that needs a clean up, when the last
* reference to it disappears (such as deallocating memory for example).
* There is no automatic procedure handling such cases when pointers are
* popped off the stack to be freed.
* \bug The element type should be temp_pntrString, because a NULL_PNTRSTRING
* must not be pushed on the stack.
*/
pntrString *pntrTempAllocStack[M_MAX_ALLOC_STACK];


/*!
* \fn temp_pntrString *pntrTempAlloc(long size)
* \par size > 0
* allocates a \ref block capable of holding \p size \ref pntrString entries
* and pushes it onto the \ref pntrTempAllocStack.
* \par size == 0
* pops off all entries from index \ref g_pntrStartTempAllocStack on from
* \ref pntrTempAllocStack and adds them to the \ref memFreePool.
* \param[in] size count of \ref pntrString entries. This value must include
* a terminal NULL pointer if needed.
* \return a pointer to the allocated \ref block, or NULL if deallocation
* requested
* \pre
* \p size ==0: all entries in from \ref pntrTempAllocStack from
* \ref g_pntrStartTempAllocStack do not contain relevant data any more.
* \post
* - \p size > 0: memory for \p size entries is reserved in the \ref block
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* - \p size > 0: memory for \p size entries is reserved in the \ref block
* - `size > 0`: memory for `size` entries is reserved in the \ref block

IMO markdown code spans look nicer in code than \p or \c, and also handle the multi-word case better.

Copy link
Contributor Author

@wlammen wlammen Mar 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again a best practice issue... But you are right, the results for \p are not that convincing. It is just standard. Added this to the todos.
Instead of changing the tag, which is at least a semantic mark, too, try to change the format of its display. Never done that before, though. From my point of view this should be investigated (or perhaps someone knows a doxygen guru, who can provide the best solution).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a general principle ruling documentation systems (and to some lesser extent modern web development, too, see CSS guide lines):
The contents is strictly separated from its formatting. The person writing the contents must not be concerned with how it is presented on different media like HTML, PDF or Latex. This looks perhaps a bit weird to Microsoft Word addicts, who are used to paint individual sentences much to their liking - some in green, others in red and so on. Professionals have a different attitude: If a word is underlined, there is a reason for it, and only that reason is given by a semantic mark. The underlining is finally added by the documentation system. That way all of the papers appear consistently styled, and the reader intuitively knows how to interpret the formatting after a few pages..
There is even more than conformity to it: Should you ever upgrade to a next-level-fancy-eyecandy system, chances are, the input of doxygen can be automatically interpreted, if it depends on semantic mark-up only.
So how should something like "size > 0" be handled? This is a bit of a border case. On one hand is size a parameter and should receive the \p prefix. But it is used in a formula context, which is tagged differently. I am sure people with more experience can tell: You are in the long run better off using ... . I am not. I feel a bit reluctant to change the size > 0 (and only that!) for a bit of change in appearance.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a simple rule: code or "math" text goes in code spans. This is semantic markup in the sense you are referring to: Using code in text like > 0 will cause it to be interpreted by renderers, screen readers, etc. as English text, but it isn't. (If you wanted English text you would write "greater than zero".) That goes even more so for size == 0 since == is a clear C-ism. The only time I make an exception to that rule is for linked code spans, but you can still work around it to some extent such as size > 0.

Unresolving the conversation because there are a ton of resolved conversations on this page that are still accumulating responses, and github makes it hard to find them when you do this.

Copy link
Contributor Author

@wlammen wlammen Mar 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In src/mmdata.c, line 2515:

I have a simple rule: code or "math" text goes in code spans.

I have another simple rule: Prefer semantic tags over formatting

The only time I make an exception to that rule is for linked code spans,..

This occurs more often than perhaps expected: Here is an example \invariant \ref g_startTempAllocStack <= \ref g_tempAllocStackTop in mmvstr.h, others could be "length + 1", and the "size == 0". Whether a C-ism is acceptable in C source documentation, is again a matter of taste.

My problem is: This pull request is held up by, as it seems, formatting issues only. There is no contention about contents like "You forgot this precondition" or "even for a draft this is too misleading".

That's why I do not unresolve this issue. I want to document the source, and ideally I need not care in the least about formatting, because the documentation system handles it transparently for me.

Ok reality isn't that forthcoming. That's what I introduced the doc-todo page for. Here suggestions can be gathered for regular review and rewrite in an extra swoop.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR is held up by my not having time to review. If you don't have strong feelings about this, I am happy to merge it and make changes later. For your examples, it is possible to write those examples using words, i.e. "invariant: \ref g_startTempAllocStack is at most \ref g_tempAllocStackTop", or to use code and follow up with words: "invariant: g_startTempAllocStack <= g_tempAllocStackTop, where \ref g_startTempAllocStack and \ref g_tempAllocStackTop are global variables". Or you could just use <= in text or split the spans or something else. There are lots of options and I would take it on a case by case basis.

My worry is that you are taking a strong stance on this and would be opposed to changes to it later. There seems to be a mixture of things you haven't had time or the wherewithal to optimize presentation-wise in here, along with things written very deliberately in accordance with your philosophy of code documentation, and so I'm not sure whether to push back now or accept early and submit a change later addressing some particular thing like changing all the code spans.

Copy link
Contributor Author

@wlammen wlammen Mar 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"My worry is that you are taking a strong stance on this.." I am not opposed to changes of others. This is not my first contribution to open source projects, and I can provide examples where my original text/code was rewritten by others both here and in other projects. During the review of PR #9 I was more than once completely at a loss to decide (for me) whether something was in a correct/acceptable shape or not. I felt I should address this shortcoming, and started documenting the code (but deliberately not rewriting it!). Documentation imo has two sides to it: 1. get the contents right; 2. present it in a way understandable to a majority. Both aspects are important in the end, but whereas facts can be verified right from the start, best practices are subject to taste and maturing. If I wait for the second aspect to be clarified in all detail in advance, I am stopped dead for, say, a couple of months. I rely to some extent on the documentation system Doxygen to provide a good and established starting point, even to a beginner with limited time resources like me.

The documentation style with its pre-/postconditions and invariants focus on program state. If done thoroughly enough, one can sort of prove the correctness of a program. I thought this is appealing to the particular audience here. Of course, one can advocate something different. Well, move on then.

* "block's" header, but the data is still random.
* - updates \ref db2
* - Exits on out-of-memory
* \bug it is unfortunate that the same function is used for opposite
* operations like de-/allocation.
*/
temp_pntrString *pntrTempAlloc(long size) {
/* pntrString memory allocation/deallocation */
/* When "size" is >0, "size" instances of pntrString are allocated. */
Expand Down Expand Up @@ -2665,13 +2748,13 @@ void pntrZapLen(pntrString *s, long length) {
/* Copy a string to another (pre-allocated) string */
/* Dangerous for general purpose use */
/*!
* \brief copies a null pointer terminated \a pntrString to a destination
* \a pntrString.
* \brief copies a null pointer terminated \ref pntrString to a destination
* \ref pntrString.
*
* This function determines the length of the source \p t by scanning for a
* terminating null pointer element. The destination \p s must have enough
* space for receiving this amount of pointers, including the terminal null
* pointer. Then the source pointers are copied beginning with that at the
* terminal null pointer element. The destination \p s must have enough space
* for receiving this amount of pointers, including the terminal null pointer.
* Then the source pointers are copied beginning with that at the
* lowest address to the destination area \p t, including the terminal null
* pointer.
*
Expand All @@ -2687,11 +2770,13 @@ void pntrZapLen(pntrString *s, long length) {
* - \p t is terminated by the first null pointer element.
* - the target array \p s must have enough free space to hold the source array
* \p t including the terminal null pointer.
* - \p s and \p t can overlap if \p t points to a later element than \a s
* (move left semantics)
* - \p s and \p t can overlap if \p t points to a later or same element than
* \p s (move left semantics).
* \invariant
* If \p s is contained in a \ref block "block", its administrative header is
* NOT updated.
* \warning The thoughtless use of this function has the potential to create
* risks mentioned in the warning of \ref pntrString.
*/
void pntrCpy(pntrString *s, const pntrString *t) {
long i;
Expand Down
Loading