mirror of https://gitlab.com/rnger/amath
488 lines
13 KiB
Groff
488 lines
13 KiB
Groff
.\" Copyright (c) 2014-2018 Carsten Sonne Larsen <cs@innolan.net>
|
|
.\" All rights reserved.
|
|
.\"
|
|
.\" Redistribution and use in source and binary forms, with or without
|
|
.\" modification, are permitted provided that the following conditions
|
|
.\" are met:
|
|
.\" 1. Redistributions of source code must retain the above copyright
|
|
.\" notice, this list of conditions and the following disclaimer.
|
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
|
.\" notice, this list of conditions and the following disclaimer in the
|
|
.\" documentation and/or other materials provided with the distribution.
|
|
.\"
|
|
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
.TH "amathc.h" 3 "Version 1.8.4" "August 05 2018"
|
|
.SH NAME
|
|
amathc.h \- C functions for manipulating strings and memory
|
|
.SH SYNOPSIS
|
|
.br
|
|
.PP
|
|
\fC#include \fB"amathc\&.h"\fP
|
|
.SS "Data Structures"
|
|
.in +1c
|
|
.ti -1c
|
|
.RI "struct \fBtexttag\fP"
|
|
.br
|
|
.in -1c
|
|
.SS "Functions"
|
|
.in +1c
|
|
.ti -1c
|
|
.RI "void * \fBAllocMemSafe\fP (size_t)"
|
|
.br
|
|
.RI "\fIAllocate memory and add it to the global memory list\&. \fP"
|
|
.ti -1c
|
|
.RI "void \fBFreeMemSafe\fP (void *)"
|
|
.br
|
|
.RI "\fIDeallocate memory from the global memory list\&. \fP"
|
|
.ti -1c
|
|
.RI "void \fBDetachMemSafe\fP (void *)"
|
|
.br
|
|
.RI "\fIDetach an allocated memory from the global memory list\&. \fP"
|
|
.ti -1c
|
|
.RI "void \fBFreeAllSafe\fP ()"
|
|
.br
|
|
.RI "\fIDeallocate all memory in the global memory list\&. \fP"
|
|
.ti -1c
|
|
.RI "void \fBMemUsage\fP (long *, long *, long *)"
|
|
.br
|
|
.RI "\fIGet memory usage in the global memory list\&. \fP"
|
|
.ti -1c
|
|
.RI "int \fBStrLen\fP (const char *string)"
|
|
.br
|
|
.RI "\fIGet the length of a null terminated string\&. \fP"
|
|
.ti -1c
|
|
.RI "bool \fBStrIsEqual\fP (const char *s1, const char *s2)"
|
|
.br
|
|
.RI "\fICompare two null terminated strings to each other\&. \fP"
|
|
.ti -1c
|
|
.RI "void \fBMemSet\fP (void *destination, int c0, unsigned int length)"
|
|
.br
|
|
.RI "\fIFill block of memory with a constant value\&. \fP"
|
|
.ti -1c
|
|
.RI "void \fBMemCopy\fP (void *destination, const void *source, unsigned int length)"
|
|
.br
|
|
.RI "\fICopy a block of memory, handling overlap\&. \fP"
|
|
.ti -1c
|
|
.RI "unsigned int \fBAllocAndCopy\fP (char **destination, const char *source)"
|
|
.br
|
|
.RI "\fIAllocate memory and copy a string into the array\&. \fP"
|
|
.ti -1c
|
|
.RI "void \fBUntag\fP (char *destination, const char *source, \fBtexttag\fP tags[], unsigned int tagcount)"
|
|
.br
|
|
.SH DESCRIPTION
|
|
.PP
|
|
.SS "unsigned int AllocAndCopy (char ** destination, const char * source)"
|
|
.PP
|
|
Allocate memory and copy a string into the array\&.
|
|
.PP
|
|
Definition at line 40 of file alloccpy\&.c\&.
|
|
.PP
|
|
.nf
|
|
41 {
|
|
42 char *i, *s, *d;
|
|
43 unsigned int n, size;
|
|
44
|
|
45 if (source == nullptr)
|
|
46 {
|
|
47 *destination = nullptr;
|
|
48 return 0;
|
|
49 }
|
|
50
|
|
51 i = (char*)source;
|
|
52 s = (char*)source;
|
|
53 while (*i)
|
|
54 i++;
|
|
55
|
|
56 n = (unsigned int)(i - s + 1);
|
|
57 size = n;
|
|
58 *destination = AllocMemSafe(size);
|
|
59 d = *destination;
|
|
60
|
|
64 while (n--)
|
|
65 *d++ = *s++;
|
|
67
|
|
68 return size;
|
|
69 }
|
|
.fi
|
|
.SS "void* AllocMemSafe (size_t)"
|
|
.PP
|
|
Allocate memory and add it to the global memory list\&.
|
|
.PP
|
|
Definition at line 86 of file mem\&.c\&.
|
|
.PP
|
|
.nf
|
|
87 {
|
|
88 struct MemoryBlock* newblock;
|
|
89 size_t allocsize;
|
|
90
|
|
91 if (list == nullptr)
|
|
92 {
|
|
93 list = (struct MemoryList*)ALLOC_MEM(sizeof(struct MemoryList));
|
|
94 if (!list)
|
|
95 {
|
|
96 alloc_error("list", sizeof(struct MemoryList));
|
|
97 return 0;
|
|
98 }
|
|
99
|
|
100 list->first = nullptr;
|
|
101 list->peak = 0;
|
|
102 list->size = 0;
|
|
103 list->count = 0;
|
|
104 }
|
|
105
|
|
106 #ifdef P64BIT
|
|
107 // Align to bytes of 8
|
|
108 allocsize = (size + 7) & ~0x07;
|
|
109 #else
|
|
110 // Align to bytes of 4
|
|
111 allocsize = (size + 3) & ~0x03;
|
|
112 #endif
|
|
113
|
|
114 newblock = (struct MemoryBlock*)ALLOC_MEM(sizeof(struct MemoryBlock));
|
|
115 if (!newblock)
|
|
116 {
|
|
117 alloc_error("block", sizeof(struct MemoryBlock));
|
|
118 return 0;
|
|
119 }
|
|
120
|
|
121 newblock->address = (struct MemoryBlock*)ALLOC_MEM(allocsize);
|
|
122 if (!newblock->address)
|
|
123 {
|
|
124 FREE_MEM(newblock);
|
|
125 alloc_error("memory", allocsize);
|
|
126 return 0;
|
|
127 }
|
|
128
|
|
129 newblock->size = allocsize;
|
|
130 newblock->next = list->first;
|
|
131 list->first = newblock;
|
|
132 list->size += allocsize;
|
|
133 list->count++;
|
|
134
|
|
135 if (list->size > list->peak)
|
|
136 {
|
|
137 list->peak = list->size;
|
|
138 }
|
|
139
|
|
140 // Memory allocated
|
|
141 return newblock->address;
|
|
142 }
|
|
.fi
|
|
.SS "void DetachMemSafe (void * block)"
|
|
.PP
|
|
Detach an allocated memory from the global memory list\&. The memory block is only detached, not deallocated\&.
|
|
.PP
|
|
Definition at line 209 of file mem\&.c\&.
|
|
.PP
|
|
.nf
|
|
210 {
|
|
211 RemoveMemSafe(block, false);
|
|
212 }
|
|
.fi
|
|
.SS "void FreeAllSafe ()"
|
|
.PP
|
|
Deallocate all memory in the global memory list\&.
|
|
.PP
|
|
Definition at line 217 of file mem\&.c\&.
|
|
.PP
|
|
.nf
|
|
218 {
|
|
219 struct MemoryBlock *current, *next;
|
|
220
|
|
221 if (list == nullptr)
|
|
222 {
|
|
223 return;
|
|
224 }
|
|
225
|
|
226 current = list->first;
|
|
227 while (current != nullptr)
|
|
228 {
|
|
229 next = current->next;
|
|
230 FREE_MEM(current->address);
|
|
231 FREE_MEM(current);
|
|
232 current = next;
|
|
233 }
|
|
234
|
|
235 FREE_MEM(list);
|
|
236 list = nullptr;
|
|
237 }
|
|
.fi
|
|
.SS "void FreeMemSafe (void *)"
|
|
.PP
|
|
Deallocate memory from the global memory list\&.
|
|
.PP
|
|
Definition at line 200 of file mem\&.c\&.
|
|
.PP
|
|
.nf
|
|
201 {
|
|
202 RemoveMemSafe(block, true);
|
|
203 }
|
|
.fi
|
|
.SS "void MemCopy (void * destination, const void * source, unsigned int length)"
|
|
.PP
|
|
Copy a block of memory, handling overlap\&.
|
|
.PP
|
|
Definition at line 75 of file memcpy\&.c\&.
|
|
.PP
|
|
.nf
|
|
76 {
|
|
77 char* dst = (char*) destination;
|
|
78 const char* src = (const char*) source;
|
|
79 unsigned int t;
|
|
80
|
|
81 if (length == 0 || dst == src) // nothing to do
|
|
82 return;
|
|
83
|
|
84 if ((mem_ptr)dst < (mem_ptr)src)
|
|
85 {
|
|
86 // Copy forward
|
|
90 t = (mem_ptr)src; // only need low bits
|
|
91 if ((t | (mem_ptr)dst) & wmask)
|
|
92 {
|
|
93 // Try to align operands\&. This cannot be done unless the low bits match\&.
|
|
94 if ((t ^ (mem_ptr)dst) & wmask || length < wsize)
|
|
95 t = length;
|
|
96 else
|
|
97 t = wsize - (t & wmask);
|
|
98 length -= t;
|
|
99
|
|
100 TLOOP1(*dst++ = *src++);
|
|
101 }
|
|
102
|
|
103 // Copy whole words, then mop up any trailing bytes\&.
|
|
104 t = length / wsize;
|
|
105 TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize);
|
|
106
|
|
107 t = length & wmask;
|
|
108 TLOOP(*dst++ = *src++);
|
|
110 }
|
|
111 else
|
|
112 {
|
|
113 // Copy backwards\&. Otherwise essentially the same\&.
|
|
114 // Alignment works as before, except that it takes
|
|
115 // (t&wmask) bytes to align, not wsize-(t&wmask)\&.
|
|
116 src += length;
|
|
117 dst += length;
|
|
118 t = (mem_ptr)src;
|
|
119 if ((t | (mem_ptr)dst) & wmask)
|
|
120 {
|
|
121 if ((t ^ (mem_ptr)dst) & wmask || length <= wsize)
|
|
122 t = length;
|
|
123 else
|
|
124 t &= wmask;
|
|
125 length -= t;
|
|
126
|
|
127 TLOOP1(*--dst = *--src);
|
|
128 }
|
|
129
|
|
130 t = length / wsize;
|
|
131 TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src);
|
|
132
|
|
133 t = length & wmask;
|
|
134 TLOOP(*--dst = *--src);
|
|
135 }
|
|
136 }
|
|
.fi
|
|
.SS "void MemSet (void * destination, int c0, unsigned int length)"
|
|
.PP
|
|
Fill block of memory with a constant value\&.
|
|
.PP
|
|
Definition at line 56 of file memset\&.c\&.
|
|
.PP
|
|
.nf
|
|
57 {
|
|
58 unsigned char* dst = (unsigned char*) dst0;
|
|
59 unsigned int t;
|
|
60 unsigned int c;
|
|
61
|
|
62 /*
|
|
63 * If not enough words, just fill bytes\&. A length >= 2 words
|
|
64 * guarantees that at least one of them is `complete' after
|
|
65 * any necessary alignment\&. For instance:
|
|
66 *
|
|
67 * |-----------|-----------|-----------|
|
|
68 * |00|01|02|03|04|05|06|07|08|09|0A|00|
|
|
69 * ^---------------------^
|
|
70 * dst dst+length-1
|
|
71 *
|
|
72 * but we use a minimum of 3 here since the overhead of the code
|
|
73 * to do word writes is substantial\&.
|
|
74 */
|
|
75 if (length < 3 * wsize)
|
|
76 {
|
|
77 while (length != 0)
|
|
78 {
|
|
79 *dst++ = c0;
|
|
80 --length;
|
|
81 }
|
|
82 }
|
|
83
|
|
84 if ((c = (unsigned char)c0) != 0)
|
|
85 { /* Fill the word\&. */
|
|
86 c = (c << 8) | c; /* u_int is 16 bits\&. */
|
|
87 #if UINT_MAX > 0xffff
|
|
88 c = (c << 16) | c; /* u_int is 32 bits\&. */
|
|
89 #endif
|
|
90 #if UINT_MAX > 0xffffffff
|
|
91 c = (c << 32) | c; /* u_int is 64 bits\&. */
|
|
92 #endif
|
|
93 }
|
|
94
|
|
95 /* Align destination by filling in bytes\&. */
|
|
96 if ((t = (mem_ptr)dst & wmask) != 0)
|
|
97 {
|
|
98 t = wsize - t;
|
|
99 length -= t;
|
|
100 do
|
|
101 {
|
|
102 *dst++ = c0;
|
|
103 }
|
|
104 while (--t != 0);
|
|
105 }
|
|
106
|
|
107 /* Fill words\&. Length was >= 2*words so we know t >= 1 here\&. */
|
|
108 t = length / wsize;
|
|
109 do
|
|
110 {
|
|
111 *(unsigned int*)dst = c;
|
|
112 dst += wsize;
|
|
113 }
|
|
114 while (--t != 0);
|
|
115
|
|
116 /* Mop up trailing bytes, if any\&. */
|
|
117 t = length & wmask;
|
|
118 if (t != 0)
|
|
119 do
|
|
120 {
|
|
121 *dst++ = c0;
|
|
122 }
|
|
123 while (--t != 0);
|
|
124 }
|
|
.fi
|
|
.SS "void MemUsage (long *, long *, long *)"
|
|
.PP
|
|
Get memory usage in the global memory list\&.
|
|
.PP
|
|
Definition at line 242 of file mem\&.c\&.
|
|
.PP
|
|
.nf
|
|
243 {
|
|
244 *blocks = list->count;
|
|
245 *size = (long)list->size;
|
|
246 *peak = (long)list->peak;;
|
|
247 }
|
|
.fi
|
|
.SS "bool StrIsEqual (const char * s1, const char * s2)"
|
|
.PP
|
|
Compare two null terminated strings to each other\&.
|
|
.PP
|
|
Definition at line 50 of file strcmp\&.c\&.
|
|
.PP
|
|
.nf
|
|
51 {
|
|
52 int r;
|
|
53
|
|
54 while (*s1 == *s2++)
|
|
55 if (*s1++ == '\0')
|
|
56 return true;
|
|
57
|
|
58 r = (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1));
|
|
59
|
|
60 return r == 0;
|
|
61 }
|
|
.fi
|
|
.SS "int StrLen (const char * string)"
|
|
.PP
|
|
Get the length of a null terminated string\&.
|
|
.PP
|
|
Definition at line 34 of file strlen\&.c\&.
|
|
.PP
|
|
.nf
|
|
35 {
|
|
36 char* i = (char*)string;
|
|
37 char* s = i;
|
|
38 while (*i)
|
|
39 i++;
|
|
40 return (int)(i - s);
|
|
41 }
|
|
.fi
|
|
.SS "void Untag (char * destination, const char * source, \fBtexttag\fP tags[], unsigned int tagcount)"
|
|
.PP
|
|
Definition at line 32 of file untag\&.c\&.
|
|
.PP
|
|
.nf
|
|
33 {
|
|
34 const char *pos, *tmp, *tag;
|
|
35 char* dest;
|
|
36 int unsigned i, j, found;
|
|
37
|
|
38 pos = source;
|
|
39 dest = destination;
|
|
40
|
|
41 while (*pos != '\0')
|
|
42 {
|
|
43 if (*pos != '#')
|
|
44 {
|
|
45 (*dest++ = *pos++);
|
|
46 }
|
|
47 else
|
|
48 {
|
|
49 // Try to replace tag
|
|
50 found = 0;
|
|
51 for (i = 0; i < tagcount; i++)
|
|
52 {
|
|
53 tag = tags[i]\&.tag;
|
|
54 tmp = pos;
|
|
55 j = 0;
|
|
56 while (*tmp != '\0' && *tag != '\0' && *tmp == *tag)
|
|
57 {
|
|
58 tmp++;
|
|
59 tag++;
|
|
60 j++;
|
|
61 }
|
|
62
|
|
63 if (j > 1 && *(--tag) == '#')
|
|
64 {
|
|
65 // Tag found\&. Now replace\&.
|
|
66 tag = tags[i]\&.text;
|
|
67 while ((*dest++ = *tag++));
|
|
68 dest--;
|
|
69 pos = tmp;
|
|
70 found = 1;
|
|
71 break;
|
|
72 }
|
|
73 }
|
|
74
|
|
75 if (!found)
|
|
76 {
|
|
77 (*dest++ = *pos++);
|
|
78 }
|
|
79 }
|
|
80 }
|
|
81 *dest = '\0';
|
|
82 }
|
|
.fi
|
|
.SH HOMEPAGE
|
|
https://amath.innolan.net/
|
|
.SH AUTHORS
|
|
.PP
|
|
Written by Carsten Sonne Larsen <cs@innolan.net>. The code in MemSet and
|
|
MemCopy is derived from software contributed to Berkeley by Mike Hibler and
|
|
Chris Torek.
|
|
.SH COPYRIGHT
|
|
Copyright (c) 2014-2018 Carsten Sonne Larsen <cs@innolan.net>
|
|
.br
|
|
Copyright (c) 2007 The NetBSD Foundation, Inc.
|
|
.br
|
|
Copyright (c) 1990, 1993 The Regents of the University of California
|
|
.SH SEE ALSO
|
|
amath(1), amathr(3), amathi(3) |