├── LICENSE.md ├── Makefile ├── README.md ├── compats.c ├── configure ├── diff.3 ├── diff.c ├── diff.h ├── diffchars.c ├── diffwords.c └── tests.c /LICENSE.md: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a 2 | copy of this software and associated documentation files (the 3 | "Software"), to deal in the Software without restriction, including 4 | without limitation the rights to use, copy, modify, merge, publish, 5 | distribute, sublicense, and/or sell copies of the Software, and to 6 | permit persons to whom the Software is furnished to do so, subject to 7 | the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included 10 | in all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 13 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 14 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 15 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 16 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 17 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 18 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include Makefile.configure 2 | 3 | VERSION = 0.1.0 4 | DOTAR = LICENSE.md \ 5 | Makefile \ 6 | README.md \ 7 | compats.c \ 8 | diff.3 \ 9 | diff.c \ 10 | diff.h \ 11 | diffchars.c \ 12 | diffwords.c \ 13 | tests.c 14 | WWWDIR = /var/www/vhosts/kristaps.bsd.lv/htdocs/libdiff 15 | 16 | all: libdiff.a diffchars diffwords 17 | 18 | www: libdiff.tar.gz 19 | 20 | install: all 21 | mkdir -p $(DESTDIR)$(LIBDIR) 22 | mkdir -p $(DESTDIR)$(INCLUDEDIR) 23 | mkdir -p $(DESTDIR)$(MANDIR)/man3 24 | $(INSTALL_LIB) libdiff.a $(DESTDIR)$(LIBDIR) 25 | $(INSTALL_DATA) diff.h $(DESTDIR)$(INCLUDEDIR) 26 | $(INSTALL_MAN) diff.3 $(DESTDIR)$(MANDIR)/man3 27 | 28 | installwww: www 29 | mkdir -p $(WWWDIR)/snapshots 30 | install -m 0444 libdiff.tar.gz $(WWWDIR)/snapshots 31 | install -m 0444 libdiff.tar.gz $(WWWDIR)/snapshots/libdiff-$(VERSION).tar.gz 32 | 33 | libdiff.tar.gz: 34 | mkdir -p .dist/libdiff-$(VERSION)/ 35 | install -m 0644 $(DOTAR) .dist/libdiff-$(VERSION) 36 | install -m 0755 configure .dist/libdiff-$(VERSION) 37 | ( cd .dist/ && tar zcf ../$@ ./ ) 38 | rm -rf .dist/ 39 | 40 | diffchars: diff.o compats.o diffchars.o 41 | $(CC) -o $@ diff.o diffchars.o compats.o 42 | 43 | diffwords: diff.o compats.o diffwords.o 44 | $(CC) -o $@ diff.o diffwords.o compats.o 45 | 46 | libdiff.a: diff.o compats.o 47 | $(AR) rs $@ diff.o compats.o 48 | 49 | clean: 50 | rm -f libdiff.a diff.o compats.o libdiff.tar.gz 51 | rm -f diffchars diffchars.o 52 | rm -f diffwords diffwords.o 53 | 54 | distclean: clean 55 | rm -f config.log config.h Makefile.configure 56 | 57 | diff.o main.o: diff.h config.h 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Synopsis 2 | 3 | *libdiff* is a C library generating the shortest edit script, longest common 4 | subsequence, and edit distance between arbitrary sequences of bytes. It 5 | derives from Tatsuhiko Kubo's [onp](https://github.com/cubicdaiya/onp) and 6 | [dtl](https://github.com/cubicdaiya/dtl). 7 | 8 | To compile on any modern UNIX system, run `./configure`, then `make` and 9 | `make install`. 10 | 11 | The library (one function) is documented in its manpage. 12 | 13 | Version snapshots are available at https://kristaps.bsd.lv/libdiff/snapshots. 14 | 15 | ## License 16 | 17 | All sources use the MIT license. 18 | See the [LICENSE.md](LICENSE.md) file for details. 19 | -------------------------------------------------------------------------------- /compats.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #if !HAVE_ERR 3 | /* 4 | * Copyright (c) 1993 5 | * The Regents of the University of California. All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 3. Neither the name of the University nor the names of its contributors 16 | * may be used to endorse or promote products derived from this software 17 | * without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | * SUCH DAMAGE. 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | void 39 | vwarnx(const char *fmt, va_list ap) 40 | { 41 | fprintf(stderr, "%s: ", getprogname()); 42 | if (fmt != NULL) 43 | vfprintf(stderr, fmt, ap); 44 | } 45 | 46 | void 47 | vwarn(const char *fmt, va_list ap) 48 | { 49 | int sverrno; 50 | 51 | sverrno = errno; 52 | vwarnx(fmt, ap); 53 | if (fmt != NULL) 54 | fputs(": ", stderr); 55 | fprintf(stderr, "%s\n", strerror(sverrno)); 56 | } 57 | 58 | void 59 | err(int eval, const char *fmt, ...) 60 | { 61 | va_list ap; 62 | 63 | va_start(ap, fmt); 64 | vwarn(fmt, ap); 65 | va_end(ap); 66 | exit(eval); 67 | } 68 | 69 | void 70 | errx(int eval, const char *fmt, ...) 71 | { 72 | va_list ap; 73 | 74 | va_start(ap, fmt); 75 | vwarnx(fmt, ap); 76 | va_end(ap); 77 | fputc('\n', stderr); 78 | exit(eval); 79 | } 80 | 81 | void 82 | warn(const char *fmt, ...) 83 | { 84 | va_list ap; 85 | 86 | va_start(ap, fmt); 87 | vwarn(fmt, ap); 88 | va_end(ap); 89 | } 90 | 91 | void 92 | warnx(const char *fmt, ...) 93 | { 94 | va_list ap; 95 | 96 | va_start(ap, fmt); 97 | vwarnx(fmt, ap); 98 | va_end(ap); 99 | fputc('\n', stderr); 100 | } 101 | #endif /* !HAVE_ERR */ 102 | #if !HAVE_EXPLICIT_BZERO 103 | /* OPENBSD ORIGINAL: lib/libc/string/explicit_bzero.c */ 104 | /* 105 | * Public domain. 106 | * Written by Ted Unangst 107 | */ 108 | 109 | #include 110 | 111 | /* 112 | * explicit_bzero - don't let the compiler optimize away bzero 113 | */ 114 | 115 | #if HAVE_MEMSET_S 116 | 117 | void 118 | explicit_bzero(void *p, size_t n) 119 | { 120 | if (n == 0) 121 | return; 122 | (void)memset_s(p, n, 0, n); 123 | } 124 | 125 | #else /* HAVE_MEMSET_S */ 126 | 127 | /* 128 | * Indirect bzero through a volatile pointer to hopefully avoid 129 | * dead-store optimisation eliminating the call. 130 | */ 131 | static void (* volatile ssh_bzero)(void *, size_t) = bzero; 132 | 133 | void 134 | explicit_bzero(void *p, size_t n) 135 | { 136 | if (n == 0) 137 | return; 138 | /* 139 | * clang -fsanitize=memory needs to intercept memset-like functions 140 | * to correctly detect memory initialisation. Make sure one is called 141 | * directly since our indirection trick above sucessfully confuses it. 142 | */ 143 | #if defined(__has_feature) 144 | # if __has_feature(memory_sanitizer) 145 | memset(p, 0, n); 146 | # endif 147 | #endif 148 | 149 | ssh_bzero(p, n); 150 | } 151 | 152 | #endif /* HAVE_MEMSET_S */ 153 | #endif /* !HAVE_EXPLICIT_BZERO */ 154 | #if !HAVE_GETPROGNAME 155 | /* 156 | * Copyright (c) 2016 Nicholas Marriott 157 | * Copyright (c) 2017 Kristaps Dzonsons 158 | * 159 | * Permission to use, copy, modify, and distribute this software for any 160 | * purpose with or without fee is hereby granted, provided that the above 161 | * copyright notice and this permission notice appear in all copies. 162 | * 163 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 164 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 165 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 166 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 167 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 168 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 169 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 170 | */ 171 | 172 | #include 173 | 174 | #include 175 | 176 | #if HAVE_PROGRAM_INVOCATION_SHORT_NAME 177 | const char * 178 | getprogname(void) 179 | { 180 | return (program_invocation_short_name); 181 | } 182 | #elif HAVE___PROGNAME 183 | const char * 184 | getprogname(void) 185 | { 186 | extern char *__progname; 187 | 188 | return (__progname); 189 | } 190 | #else 191 | #error No getprogname available. 192 | #endif 193 | #endif /* !HAVE_GETPROGNAME */ 194 | #if !HAVE_MD5 195 | /* 196 | * This code implements the MD5 message-digest algorithm. 197 | * The algorithm is due to Ron Rivest. This code was 198 | * written by Colin Plumb in 1993, no copyright is claimed. 199 | * This code is in the public domain; do with it what you wish. 200 | * 201 | * Equivalent code is available from RSA Data Security, Inc. 202 | * This code has been tested against that, and is equivalent, 203 | * except that you don't need to include two pages of legalese 204 | * with every copy. 205 | * 206 | * To compute the message digest of a chunk of bytes, declare an 207 | * MD5Context structure, pass it to MD5Init, call MD5Update as 208 | * needed on buffers full of bytes, and then call MD5Final, which 209 | * will fill a supplied 16-byte array with the digest. 210 | */ 211 | 212 | #include 213 | #include 214 | #include 215 | 216 | #define PUT_64BIT_LE(cp, value) do { \ 217 | (cp)[7] = (value) >> 56; \ 218 | (cp)[6] = (value) >> 48; \ 219 | (cp)[5] = (value) >> 40; \ 220 | (cp)[4] = (value) >> 32; \ 221 | (cp)[3] = (value) >> 24; \ 222 | (cp)[2] = (value) >> 16; \ 223 | (cp)[1] = (value) >> 8; \ 224 | (cp)[0] = (value); } while (0) 225 | 226 | #define PUT_32BIT_LE(cp, value) do { \ 227 | (cp)[3] = (value) >> 24; \ 228 | (cp)[2] = (value) >> 16; \ 229 | (cp)[1] = (value) >> 8; \ 230 | (cp)[0] = (value); } while (0) 231 | 232 | static u_int8_t PADDING[MD5_BLOCK_LENGTH] = { 233 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 235 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 236 | }; 237 | 238 | /* 239 | * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious 240 | * initialization constants. 241 | */ 242 | void 243 | MD5Init(MD5_CTX *ctx) 244 | { 245 | ctx->count = 0; 246 | ctx->state[0] = 0x67452301; 247 | ctx->state[1] = 0xefcdab89; 248 | ctx->state[2] = 0x98badcfe; 249 | ctx->state[3] = 0x10325476; 250 | } 251 | 252 | /* 253 | * Update context to reflect the concatenation of another buffer full 254 | * of bytes. 255 | */ 256 | void 257 | MD5Update(MD5_CTX *ctx, const unsigned char *input, size_t len) 258 | { 259 | size_t have, need; 260 | 261 | /* Check how many bytes we already have and how many more we need. */ 262 | have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1)); 263 | need = MD5_BLOCK_LENGTH - have; 264 | 265 | /* Update bitcount */ 266 | ctx->count += (u_int64_t)len << 3; 267 | 268 | if (len >= need) { 269 | if (have != 0) { 270 | memcpy(ctx->buffer + have, input, need); 271 | MD5Transform(ctx->state, ctx->buffer); 272 | input += need; 273 | len -= need; 274 | have = 0; 275 | } 276 | 277 | /* Process data in MD5_BLOCK_LENGTH-byte chunks. */ 278 | while (len >= MD5_BLOCK_LENGTH) { 279 | MD5Transform(ctx->state, input); 280 | input += MD5_BLOCK_LENGTH; 281 | len -= MD5_BLOCK_LENGTH; 282 | } 283 | } 284 | 285 | /* Handle any remaining bytes of data. */ 286 | if (len != 0) 287 | memcpy(ctx->buffer + have, input, len); 288 | } 289 | 290 | /* 291 | * Pad pad to 64-byte boundary with the bit pattern 292 | * 1 0* (64-bit count of bits processed, MSB-first) 293 | */ 294 | void 295 | MD5Pad(MD5_CTX *ctx) 296 | { 297 | u_int8_t count[8]; 298 | size_t padlen; 299 | 300 | /* Convert count to 8 bytes in little endian order. */ 301 | PUT_64BIT_LE(count, ctx->count); 302 | 303 | /* Pad out to 56 mod 64. */ 304 | padlen = MD5_BLOCK_LENGTH - 305 | ((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1)); 306 | if (padlen < 1 + 8) 307 | padlen += MD5_BLOCK_LENGTH; 308 | MD5Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */ 309 | MD5Update(ctx, count, 8); 310 | } 311 | 312 | /* 313 | * Final wrapup--call MD5Pad, fill in digest and zero out ctx. 314 | */ 315 | void 316 | MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx) 317 | { 318 | int i; 319 | 320 | MD5Pad(ctx); 321 | for (i = 0; i < 4; i++) 322 | PUT_32BIT_LE(digest + i * 4, ctx->state[i]); 323 | memset(ctx, 0, sizeof(*ctx)); 324 | } 325 | 326 | 327 | /* The four core functions - F1 is optimized somewhat */ 328 | 329 | /* #define F1(x, y, z) (x & y | ~x & z) */ 330 | #define F1(x, y, z) (z ^ (x & (y ^ z))) 331 | #define F2(x, y, z) F1(z, x, y) 332 | #define F3(x, y, z) (x ^ y ^ z) 333 | #define F4(x, y, z) (y ^ (x | ~z)) 334 | 335 | /* This is the central step in the MD5 algorithm. */ 336 | #define MD5STEP(f, w, x, y, z, data, s) \ 337 | ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) 338 | 339 | /* 340 | * The core of the MD5 algorithm, this alters an existing MD5 hash to 341 | * reflect the addition of 16 longwords of new data. MD5Update blocks 342 | * the data and converts bytes into longwords for this routine. 343 | */ 344 | void 345 | MD5Transform(u_int32_t state[4], const u_int8_t block[MD5_BLOCK_LENGTH]) 346 | { 347 | u_int32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4]; 348 | 349 | #if BYTE_ORDER == LITTLE_ENDIAN 350 | memcpy(in, block, sizeof(in)); 351 | #else 352 | for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) { 353 | in[a] = (u_int32_t)( 354 | (u_int32_t)(block[a * 4 + 0]) | 355 | (u_int32_t)(block[a * 4 + 1]) << 8 | 356 | (u_int32_t)(block[a * 4 + 2]) << 16 | 357 | (u_int32_t)(block[a * 4 + 3]) << 24); 358 | } 359 | #endif 360 | 361 | a = state[0]; 362 | b = state[1]; 363 | c = state[2]; 364 | d = state[3]; 365 | 366 | MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478, 7); 367 | MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12); 368 | MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17); 369 | MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22); 370 | MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf, 7); 371 | MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12); 372 | MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17); 373 | MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22); 374 | MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8, 7); 375 | MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12); 376 | MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); 377 | MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); 378 | MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); 379 | MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); 380 | MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); 381 | MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); 382 | 383 | MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562, 5); 384 | MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340, 9); 385 | MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); 386 | MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20); 387 | MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d, 5); 388 | MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); 389 | MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); 390 | MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20); 391 | MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6, 5); 392 | MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); 393 | MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14); 394 | MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20); 395 | MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); 396 | MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8, 9); 397 | MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14); 398 | MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); 399 | 400 | MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942, 4); 401 | MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11); 402 | MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); 403 | MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); 404 | MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44, 4); 405 | MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11); 406 | MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16); 407 | MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); 408 | MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); 409 | MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11); 410 | MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16); 411 | MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23); 412 | MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039, 4); 413 | MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); 414 | MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); 415 | MD5STEP(F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23); 416 | 417 | MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244, 6); 418 | MD5STEP(F4, d, a, b, c, in[7 ] + 0x432aff97, 10); 419 | MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); 420 | MD5STEP(F4, b, c, d, a, in[5 ] + 0xfc93a039, 21); 421 | MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); 422 | MD5STEP(F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10); 423 | MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); 424 | MD5STEP(F4, b, c, d, a, in[1 ] + 0x85845dd1, 21); 425 | MD5STEP(F4, a, b, c, d, in[8 ] + 0x6fa87e4f, 6); 426 | MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); 427 | MD5STEP(F4, c, d, a, b, in[6 ] + 0xa3014314, 15); 428 | MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); 429 | MD5STEP(F4, a, b, c, d, in[4 ] + 0xf7537e82, 6); 430 | MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); 431 | MD5STEP(F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15); 432 | MD5STEP(F4, b, c, d, a, in[9 ] + 0xeb86d391, 21); 433 | 434 | state[0] += a; 435 | state[1] += b; 436 | state[2] += c; 437 | state[3] += d; 438 | } 439 | 440 | char * 441 | MD5End(MD5_CTX *ctx, char *buf) 442 | { 443 | int i; 444 | unsigned char digest[MD5_DIGEST_LENGTH]; 445 | static const char hex[]="0123456789abcdef"; 446 | 447 | if (!buf) 448 | buf = malloc(2*MD5_DIGEST_LENGTH + 1); 449 | if (!buf) 450 | return 0; 451 | MD5Final(digest, ctx); 452 | for (i = 0; i < MD5_DIGEST_LENGTH; i++) { 453 | buf[i+i] = hex[digest[i] >> 4]; 454 | buf[i+i+1] = hex[digest[i] & 0x0f]; 455 | } 456 | buf[i+i] = '\0'; 457 | return buf; 458 | } 459 | #endif /* !HAVE_MD5 */ 460 | #if !HAVE_MEMMEM 461 | /*- 462 | * Copyright (c) 2005 Pascal Gloor 463 | * 464 | * Redistribution and use in source and binary forms, with or without 465 | * modification, are permitted provided that the following conditions 466 | * are met: 467 | * 1. Redistributions of source code must retain the above copyright 468 | * notice, this list of conditions and the following disclaimer. 469 | * 2. Redistributions in binary form must reproduce the above copyright 470 | * notice, this list of conditions and the following disclaimer in 471 | * the documentation and/or other materials provided with the 472 | * distribution. 473 | * 3. The name of the author may not be used to endorse or promote 474 | * products derived from this software without specific prior written 475 | * permission. 476 | * 477 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' 478 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 479 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 480 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR 481 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 482 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 483 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 484 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 485 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 486 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 487 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 488 | */ 489 | /* 490 | * Find the first occurrence of the byte string s in byte string l. 491 | */ 492 | void * 493 | memmem(const void *l, size_t l_len, const void *s, size_t s_len) 494 | { 495 | const char *cur, *last; 496 | const char *cl = l; 497 | const char *cs = s; 498 | 499 | /* a zero length needle should just return the haystack */ 500 | if (l_len == 0) 501 | return (void *)cl; 502 | 503 | /* "s" must be smaller or equal to "l" */ 504 | if (l_len < s_len) 505 | return NULL; 506 | 507 | /* special case where s_len == 1 */ 508 | if (s_len == 1) 509 | return memchr(l, *cs, l_len); 510 | 511 | /* the last position where its possible to find "s" in "l" */ 512 | last = cl + l_len - s_len; 513 | 514 | for (cur = cl; cur <= last; cur++) 515 | if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0) 516 | return (void *)cur; 517 | 518 | return NULL; 519 | } 520 | #endif /* !HAVE_MEMMEM */ 521 | #if !HAVE_MEMRCHR 522 | /* 523 | * Copyright (c) 2007 Todd C. Miller 524 | * 525 | * Permission to use, copy, modify, and distribute this software for any 526 | * purpose with or without fee is hereby granted, provided that the above 527 | * copyright notice and this permission notice appear in all copies. 528 | * 529 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 530 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 531 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 532 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 533 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 534 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 535 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 536 | * 537 | */ 538 | 539 | #include 540 | 541 | /* 542 | * Reverse memchr() 543 | * Find the last occurrence of 'c' in the buffer 's' of size 'n'. 544 | */ 545 | void * 546 | memrchr(const void *s, int c, size_t n) 547 | { 548 | const unsigned char *cp; 549 | 550 | if (n != 0) { 551 | cp = (unsigned char *)s + n; 552 | do { 553 | if (*(--cp) == (unsigned char)c) 554 | return((void *)cp); 555 | } while (--n != 0); 556 | } 557 | return(NULL); 558 | } 559 | #endif /* !HAVE_MEMRCHR */ 560 | #if !HAVE_REALLOCARRAY 561 | /* 562 | * Copyright (c) 2008 Otto Moerbeek 563 | * 564 | * Permission to use, copy, modify, and distribute this software for any 565 | * purpose with or without fee is hereby granted, provided that the above 566 | * copyright notice and this permission notice appear in all copies. 567 | * 568 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 569 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 570 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 571 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 572 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 573 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 574 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 575 | */ 576 | 577 | #include 578 | #include 579 | #include 580 | #include 581 | 582 | /* 583 | * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX 584 | * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW 585 | */ 586 | #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) 587 | 588 | void * 589 | reallocarray(void *optr, size_t nmemb, size_t size) 590 | { 591 | if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && 592 | nmemb > 0 && SIZE_MAX / nmemb < size) { 593 | errno = ENOMEM; 594 | return NULL; 595 | } 596 | return realloc(optr, size * nmemb); 597 | } 598 | #endif /* !HAVE_REALLOCARRAY */ 599 | #if !HAVE_RECALLOCARRAY 600 | /* 601 | * Copyright (c) 2008, 2017 Otto Moerbeek 602 | * 603 | * Permission to use, copy, modify, and distribute this software for any 604 | * purpose with or without fee is hereby granted, provided that the above 605 | * copyright notice and this permission notice appear in all copies. 606 | * 607 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 608 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 609 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 610 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 611 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 612 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 613 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 614 | */ 615 | 616 | /* OPENBSD ORIGINAL: lib/libc/stdlib/recallocarray.c */ 617 | 618 | #include 619 | #include 620 | #include 621 | #include 622 | #include 623 | 624 | /* 625 | * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX 626 | * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW 627 | */ 628 | #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) 629 | 630 | void * 631 | recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) 632 | { 633 | size_t oldsize, newsize; 634 | void *newptr; 635 | 636 | if (ptr == NULL) 637 | return calloc(newnmemb, size); 638 | 639 | if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && 640 | newnmemb > 0 && SIZE_MAX / newnmemb < size) { 641 | errno = ENOMEM; 642 | return NULL; 643 | } 644 | newsize = newnmemb * size; 645 | 646 | if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && 647 | oldnmemb > 0 && SIZE_MAX / oldnmemb < size) { 648 | errno = EINVAL; 649 | return NULL; 650 | } 651 | oldsize = oldnmemb * size; 652 | 653 | /* 654 | * Don't bother too much if we're shrinking just a bit, 655 | * we do not shrink for series of small steps, oh well. 656 | */ 657 | if (newsize <= oldsize) { 658 | size_t d = oldsize - newsize; 659 | 660 | if (d < oldsize / 2 && d < (size_t)getpagesize()) { 661 | memset((char *)ptr + newsize, 0, d); 662 | return ptr; 663 | } 664 | } 665 | 666 | newptr = malloc(newsize); 667 | if (newptr == NULL) 668 | return NULL; 669 | 670 | if (newsize > oldsize) { 671 | memcpy(newptr, ptr, oldsize); 672 | memset((char *)newptr + oldsize, 0, newsize - oldsize); 673 | } else 674 | memcpy(newptr, ptr, newsize); 675 | 676 | explicit_bzero(ptr, oldsize); 677 | free(ptr); 678 | 679 | return newptr; 680 | } 681 | #endif /* !HAVE_RECALLOCARRAY */ 682 | #if !HAVE_STRLCAT 683 | /* 684 | * Copyright (c) 1998 Todd C. Miller 685 | * 686 | * Permission to use, copy, modify, and distribute this software for any 687 | * purpose with or without fee is hereby granted, provided that the above 688 | * copyright notice and this permission notice appear in all copies. 689 | * 690 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 691 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 692 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 693 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 694 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 695 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 696 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 697 | */ 698 | 699 | #include 700 | #include 701 | 702 | /* 703 | * Appends src to string dst of size siz (unlike strncat, siz is the 704 | * full size of dst, not space left). At most siz-1 characters 705 | * will be copied. Always NUL terminates (unless siz <= strlen(dst)). 706 | * Returns strlen(src) + MIN(siz, strlen(initial dst)). 707 | * If retval >= siz, truncation occurred. 708 | */ 709 | size_t 710 | strlcat(char *dst, const char *src, size_t siz) 711 | { 712 | char *d = dst; 713 | const char *s = src; 714 | size_t n = siz; 715 | size_t dlen; 716 | 717 | /* Find the end of dst and adjust bytes left but don't go past end */ 718 | while (n-- != 0 && *d != '\0') 719 | d++; 720 | dlen = d - dst; 721 | n = siz - dlen; 722 | 723 | if (n == 0) 724 | return(dlen + strlen(s)); 725 | while (*s != '\0') { 726 | if (n != 1) { 727 | *d++ = *s; 728 | n--; 729 | } 730 | s++; 731 | } 732 | *d = '\0'; 733 | 734 | return(dlen + (s - src)); /* count does not include NUL */ 735 | } 736 | #endif /* !HAVE_STRLCAT */ 737 | #if !HAVE_STRLCPY 738 | /* 739 | * Copyright (c) 1998 Todd C. Miller 740 | * 741 | * Permission to use, copy, modify, and distribute this software for any 742 | * purpose with or without fee is hereby granted, provided that the above 743 | * copyright notice and this permission notice appear in all copies. 744 | * 745 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 746 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 747 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 748 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 749 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 750 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 751 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 752 | */ 753 | 754 | #include 755 | #include 756 | 757 | /* 758 | * Copy src to string dst of size siz. At most siz-1 characters 759 | * will be copied. Always NUL terminates (unless siz == 0). 760 | * Returns strlen(src); if retval >= siz, truncation occurred. 761 | */ 762 | size_t 763 | strlcpy(char *dst, const char *src, size_t siz) 764 | { 765 | char *d = dst; 766 | const char *s = src; 767 | size_t n = siz; 768 | 769 | /* Copy as many bytes as will fit */ 770 | if (n != 0) { 771 | while (--n != 0) { 772 | if ((*d++ = *s++) == '\0') 773 | break; 774 | } 775 | } 776 | 777 | /* Not enough room in dst, add NUL and traverse rest of src */ 778 | if (n == 0) { 779 | if (siz != 0) 780 | *d = '\0'; /* NUL-terminate dst */ 781 | while (*s++) 782 | ; 783 | } 784 | 785 | return(s - src - 1); /* count does not include NUL */ 786 | } 787 | #endif /* !HAVE_STRLCPY */ 788 | #if !HAVE_STRNDUP 789 | /* $OpenBSD$ */ 790 | /* 791 | * Copyright (c) 2010 Todd C. Miller 792 | * 793 | * Permission to use, copy, modify, and distribute this software for any 794 | * purpose with or without fee is hereby granted, provided that the above 795 | * copyright notice and this permission notice appear in all copies. 796 | * 797 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 798 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 799 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 800 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 801 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 802 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 803 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 804 | */ 805 | 806 | #include 807 | 808 | #include 809 | #include 810 | #include 811 | 812 | char * 813 | strndup(const char *str, size_t maxlen) 814 | { 815 | char *copy; 816 | size_t len; 817 | 818 | len = strnlen(str, maxlen); 819 | copy = malloc(len + 1); 820 | if (copy != NULL) { 821 | (void)memcpy(copy, str, len); 822 | copy[len] = '\0'; 823 | } 824 | 825 | return copy; 826 | } 827 | #endif /* !HAVE_STRNDUP */ 828 | #if !HAVE_STRNLEN 829 | /* $OpenBSD$ */ 830 | 831 | /* 832 | * Copyright (c) 2010 Todd C. Miller 833 | * 834 | * Permission to use, copy, modify, and distribute this software for any 835 | * purpose with or without fee is hereby granted, provided that the above 836 | * copyright notice and this permission notice appear in all copies. 837 | * 838 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 839 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 840 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 841 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 842 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 843 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 844 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 845 | */ 846 | 847 | #include 848 | #include 849 | 850 | size_t 851 | strnlen(const char *str, size_t maxlen) 852 | { 853 | const char *cp; 854 | 855 | for (cp = str; maxlen != 0 && *cp != '\0'; cp++, maxlen--) 856 | ; 857 | 858 | return (size_t)(cp - str); 859 | } 860 | #endif /* !HAVE_STRNLEN */ 861 | #if !HAVE_STRTONUM 862 | /* 863 | * Copyright (c) 2004 Ted Unangst and Todd Miller 864 | * All rights reserved. 865 | * 866 | * Permission to use, copy, modify, and distribute this software for any 867 | * purpose with or without fee is hereby granted, provided that the above 868 | * copyright notice and this permission notice appear in all copies. 869 | * 870 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 871 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 872 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 873 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 874 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 875 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 876 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 877 | */ 878 | 879 | #include 880 | #include 881 | #include 882 | 883 | #define INVALID 1 884 | #define TOOSMALL 2 885 | #define TOOLARGE 3 886 | 887 | long long 888 | strtonum(const char *numstr, long long minval, long long maxval, 889 | const char **errstrp) 890 | { 891 | long long ll = 0; 892 | int error = 0; 893 | char *ep; 894 | struct errval { 895 | const char *errstr; 896 | int err; 897 | } ev[4] = { 898 | { NULL, 0 }, 899 | { "invalid", EINVAL }, 900 | { "too small", ERANGE }, 901 | { "too large", ERANGE }, 902 | }; 903 | 904 | ev[0].err = errno; 905 | errno = 0; 906 | if (minval > maxval) { 907 | error = INVALID; 908 | } else { 909 | ll = strtoll(numstr, &ep, 10); 910 | if (numstr == ep || *ep != '\0') 911 | error = INVALID; 912 | else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) 913 | error = TOOSMALL; 914 | else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) 915 | error = TOOLARGE; 916 | } 917 | if (errstrp != NULL) 918 | *errstrp = ev[error].errstr; 919 | errno = ev[error].err; 920 | if (error) 921 | ll = 0; 922 | 923 | return (ll); 924 | } 925 | #endif /* !HAVE_STRTONUM */ 926 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # 3 | # Copyright (c) 2014, 2015, 2016 Ingo Schwarze 4 | # Copyright (c) 2017 Kristaps Dzonsons 5 | # 6 | # Permission to use, copy, modify, and distribute this software for any 7 | # purpose with or without fee is hereby granted, provided that the above 8 | # copyright notice and this permission notice appear in all copies. 9 | # 10 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | 18 | OCONFIGURE_VERSION="0.1.3" 19 | 20 | # 21 | # This script outputs two files: config.h and Makefile.configure. 22 | # It tries to read from configure.local, which contains predefined 23 | # values we won't autoconfigure. 24 | # 25 | # If you want to use configure with your project, have your GNUmakefile 26 | # or BSDmakefile---whichever---try to import/include Makefile.configure 27 | # at the beginning of the file. 28 | # 29 | # Like so (note no quotes, no period, etc.): 30 | # 31 | # include Makefile.configure 32 | # 33 | # If it exists, configure was run; otherwise, it wasn't. 34 | # 35 | # You'll probably want to change parts of this file. I've noted the 36 | # parts that you'll probably change in the section documentation. 37 | # 38 | # See https://github.com/kristapsdz/oconfigure for more. 39 | 40 | set -e 41 | 42 | #---------------------------------------------------------------------- 43 | # Prepare for running: move aside previous configure runs. 44 | # Output file descriptor usage: 45 | # 1 (stdout): config.h or Makefile.configure 46 | # 2 (stderr): original stderr, usually to the console 47 | # 3: config.log 48 | # You DO NOT want to change this. 49 | #---------------------------------------------------------------------- 50 | 51 | [ -w config.log ] && mv config.log config.log.old 52 | [ -w config.h ] && mv config.h config.h.old 53 | 54 | exec 3> config.log 55 | echo "config.log: writing..." 56 | 57 | #---------------------------------------------------------------------- 58 | # Initialize all variables here such that nothing can leak in from the 59 | # environment except for CC and CFLAGS, which we might have passed in. 60 | #---------------------------------------------------------------------- 61 | 62 | CC=`printf "all:\\n\\t@echo \\\$(CC)\\n" | make -sf -` 63 | CFLAGS=`printf "all:\\n\\t@echo \\\$(CFLAGS)\\n" | make -sf -` 64 | CFLAGS="${CFLAGS} -g -W -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes" 65 | CFLAGS="${CFLAGS} -Wwrite-strings -Wno-unused-parameter" 66 | LDADD= 67 | CPPFLAGS= 68 | LDFLAGS= 69 | DESTDIR= 70 | PREFIX="/usr/local" 71 | BINDIR= 72 | SBINDIR= 73 | INCLUDEDIR= 74 | LIBDIR= 75 | MANDIR= 76 | SHAREDIR= 77 | INSTALL="install" 78 | INSTALL_PROGRAM= 79 | INSTALL_LIB= 80 | INSTALL_MAN= 81 | INSTALL_DATA= 82 | 83 | #---------------------------------------------------------------------- 84 | # Allow certain variables to be overriden on the command line. 85 | #---------------------------------------------------------------------- 86 | 87 | for keyvals in "$@" 88 | do 89 | key=`echo $keyvals | cut -s -d '=' -f 1` 90 | if [ -z "$key" ] 91 | then 92 | echo "$0: invalid key-value: $keyvals" 1>&2 93 | exit 1 94 | fi 95 | val=`echo $keyvals | cut -d '=' -f 2-` 96 | case "$key" in 97 | LDADD) 98 | LDADD="$val" ;; 99 | LDFLAGS) 100 | LDFLAGS="$val" ;; 101 | CPPFLAGS) 102 | CPPFLAGS="$val" ;; 103 | DESTDIR) 104 | DESTDIR="$val" ;; 105 | PREFIX) 106 | PREFIX="$val" ;; 107 | MANDIR) 108 | MANDIR="$val" ;; 109 | LIBDIR) 110 | LIBDIR="$val" ;; 111 | BINDIR) 112 | BINDIR="$val" ;; 113 | SHAREDIR) 114 | SHAREDIR="$val" ;; 115 | SBINDIR) 116 | SBINDIR="$val" ;; 117 | INCLUDEDIR) 118 | INCLUDEDIR="$val" ;; 119 | *) 120 | echo "$0: invalid key: $key" 1>&2 121 | exit 1 122 | esac 123 | done 124 | 125 | 126 | #---------------------------------------------------------------------- 127 | # These are the values that will be pushed into config.h after we test 128 | # for whether they're supported or not. 129 | # Each of these must have a runtest(), below. 130 | # Please sort by alpha, for clarity. 131 | # You WANT to change this. 132 | #---------------------------------------------------------------------- 133 | 134 | HAVE_ARC4RANDOM= 135 | HAVE_CAPSICUM= 136 | HAVE_ERR= 137 | HAVE_EXPLICIT_BZERO= 138 | HAVE_GETPROGNAME= 139 | HAVE_INFTIM= 140 | HAVE_MD5= 141 | HAVE_MEMMEM= 142 | HAVE_MEMRCHR= 143 | HAVE_MEMSET_S= 144 | HAVE_PATH_MAX= 145 | HAVE_PLEDGE= 146 | HAVE_PROGRAM_INVOCATION_SHORT_NAME= 147 | HAVE_REALLOCARRAY= 148 | HAVE_RECALLOCARRAY= 149 | HAVE_SANDBOX_INIT= 150 | HAVE_SECCOMP_FILTER= 151 | HAVE_SOCK_NONBLOCK= 152 | HAVE_STRLCAT= 153 | HAVE_STRLCPY= 154 | HAVE_STRTONUM= 155 | HAVE_SYSTRACE= 156 | HAVE___PROGNAME= 157 | 158 | #---------------------------------------------------------------------- 159 | # Allow configure.local to override all variables, default settings, 160 | # command-line arguments, and tested features, above. 161 | # You PROBABLY DO NOT want to change this. 162 | #---------------------------------------------------------------------- 163 | 164 | if [ -r ./configure.local ]; then 165 | echo "configure.local: reading..." 1>&2 166 | echo "configure.local: reading..." 1>&3 167 | cat ./configure.local 1>&3 168 | . ./configure.local 169 | else 170 | echo "configure.local: no (fully automatic configuration)" 1>&2 171 | echo "configure.local: no (fully automatic configuration)" 1>&3 172 | fi 173 | 174 | echo 1>&3 175 | 176 | #---------------------------------------------------------------------- 177 | # Infrastructure for running tests. 178 | # These consists of a series of functions that will attempt to run the 179 | # given test file and record its exit into a HAVE_xxx variable. 180 | # You DO NOT want to change this. 181 | #---------------------------------------------------------------------- 182 | 183 | COMP="${CC} ${CFLAGS} ${CPPFLAGS} -Wno-unused -Werror" 184 | 185 | # Check whether this HAVE_ setting is manually overridden. 186 | # If yes, use the override, if no, do not decide anything yet. 187 | # Arguments: lower-case test name, manual value 188 | 189 | ismanual() { 190 | [ -z "${3}" ] && return 1 191 | echo "${1}: manual (HAVE_${2}=${3})" 1>&2 192 | echo "${1}: manual (HAVE_${2}=${3})" 1>&3 193 | echo 1>&3 194 | return 0 195 | } 196 | 197 | # Run a single autoconfiguration test. 198 | # In case of success, enable the feature. 199 | # In case of failure, do not decide anything yet. 200 | # Arguments: lower-case test name, upper-case test name, additional 201 | # CFLAGS, additional LIBS. 202 | 203 | singletest() { 204 | cat 1>&3 << __HEREDOC__ 205 | ${1}: testing... 206 | ${COMP} -DTEST_${2} ${3} -o test-${1} tests.c ${4} 207 | __HEREDOC__ 208 | 209 | if ${COMP} -DTEST_${2} ${3} -o "test-${1}" tests.c ${4} 1>&3 2>&3; then 210 | echo "${1}: ${CC} succeeded" 1>&3 211 | else 212 | echo "${1}: ${CC} failed with $?" 1>&3 213 | echo 1>&3 214 | return 1 215 | fi 216 | 217 | if ./test-${1} 1>&3 2>&3; then 218 | echo "${1}: yes" 1>&2 219 | echo "${1}: yes" 1>&3 220 | echo 1>&3 221 | eval HAVE_${2}=1 222 | rm "test-${1}" 223 | return 0 224 | else 225 | echo "${1}: execution failed with $?" 1>&3 226 | echo 1>&3 227 | rm "test-${1}" 228 | return 1 229 | fi 230 | } 231 | 232 | # Run a complete autoconfiguration test, including the check for 233 | # a manual override and disabling the feature on failure. 234 | # Arguments: lower case name, upper case name, additional CFLAGS 235 | 236 | runtest() { 237 | eval _manual=\${HAVE_${2}} 238 | ismanual "${1}" "${2}" "${_manual}" && return 0 239 | singletest "${1}" "${2}" "${3}" "${4}" "${test}" && return 0 240 | echo "${1}: no" 1>&2 241 | eval HAVE_${2}=0 242 | return 1 243 | } 244 | 245 | #---------------------------------------------------------------------- 246 | # Begin running the tests themselves. 247 | # All of your tests must be defined here. 248 | # Please sort as the HAVE_xxxx values were defined. 249 | # You WANT to change this. 250 | #---------------------------------------------------------------------- 251 | 252 | runtest arc4random ARC4RANDOM || true 253 | runtest capsicum CAPSICUM || true 254 | runtest err ERR || true 255 | runtest explicit_bzero EXPLICIT_BZERO || true 256 | runtest getprogname GETPROGNAME || true 257 | runtest INFTIM INFTIM || true 258 | runtest md5 MD5 || true 259 | runtest memmem MEMMEM || true 260 | runtest memrchr MEMRCHR || true 261 | runtest memset_s MEMSET_S || true 262 | runtest PATH_MAX PATH_MAX || true 263 | runtest pledge PLEDGE || true 264 | runtest program_invocation_short_name PROGRAM_INVOCATION_SHORT_NAME || true 265 | runtest reallocarray REALLOCARRAY || true 266 | runtest recallocarray RECALLOCARRAY || true 267 | runtest sandbox_init SANDBOX_INIT "-Wno-deprecated" || true 268 | runtest seccomp-filter SECCOMP_FILTER || true 269 | runtest SOCK_NONBLOCK SOCK_NONBLOCK || true 270 | runtest strlcat STRLCAT || true 271 | runtest strlcpy STRLCPY || true 272 | runtest strndup STRNDUP || true 273 | runtest strnlen STRNLEN || true 274 | runtest strtonum STRTONUM || true 275 | runtest systrace SYSTRACE || true 276 | runtest zlib ZLIB "" "-lz" || true 277 | runtest __progname __PROGNAME || true 278 | 279 | #---------------------------------------------------------------------- 280 | # Output writing: generate the config.h file. 281 | # This file contains all of the HAVE_xxxx variables necessary for 282 | # compiling your source. 283 | # You must include "config.h" BEFORE any other variables. 284 | # You WANT to change this. 285 | #---------------------------------------------------------------------- 286 | 287 | exec > config.h 288 | 289 | # Start with prologue. 290 | 291 | cat << __HEREDOC__ 292 | #ifdef __cplusplus 293 | #error "Do not use C++: this is a C application." 294 | #endif 295 | #if !defined(__GNUC__) || (__GNUC__ < 4) 296 | #define __attribute__(x) 297 | #endif 298 | #if defined(__linux__) || defined(__MINT__) 299 | #define _GNU_SOURCE /* See test-*.c what needs this. */ 300 | #endif 301 | #if !defined(__BEGIN_DECLS) 302 | # define __BEGIN_DECLS 303 | #endif 304 | #if !defined(__END_DECLS) 305 | # define __END_DECLS 306 | #endif 307 | __HEREDOC__ 308 | 309 | # For the function declaration variables... 310 | 311 | [ ${HAVE_MD5} -eq 0 -o \ 312 | ${HAVE_REALLOCARRAY} -eq 0 -o \ 313 | ${HAVE_RECALLOCARRAY} -eq 0 -o \ 314 | ${HAVE_STRLCAT} -eq 0 -o \ 315 | ${HAVE_STRLCPY} -eq 0 -o \ 316 | ${HAVE_STRNDUP} -eq 0 -o \ 317 | ${HAVE_STRNLEN} -eq 0 ] \ 318 | && echo "#include " 319 | 320 | [ ${HAVE_ERR} -eq 0 ] \ 321 | && echo "#include " 322 | 323 | # Now we handle our HAVE_xxxx values. 324 | # Most will just be defined as 0 or 1. 325 | 326 | [ ${HAVE_PATH_MAX} -eq 0 ] \ 327 | && echo "#define PATH_MAX 4096" 328 | 329 | [ ${HAVE_INFTIM} -eq 0 ] \ 330 | && echo "#define INFTIM (-1)" 331 | 332 | cat << __HEREDOC__ 333 | #define HAVE_ARC4RANDOM ${HAVE_ARC4RANDOM} 334 | #define HAVE_CAPSICUM ${HAVE_CAPSICUM} 335 | #define HAVE_ERR ${HAVE_ERR} 336 | #define HAVE_EXPLICIT_BZERO ${HAVE_EXPLICIT_BZERO} 337 | #define HAVE_GETPROGNAME ${HAVE_GETPROGNAME} 338 | #define HAVE_INFTIM ${HAVE_INFTIM} 339 | #define HAVE_MD5 ${HAVE_MD5} 340 | #define HAVE_MEMMEM ${HAVE_MEMMEM} 341 | #define HAVE_MEMRCHR ${HAVE_MEMRCHR} 342 | #define HAVE_MEMSET_S ${HAVE_MEMSET_S} 343 | #define HAVE_PATH_MAX ${HAVE_PATH_MAX} 344 | #define HAVE_PLEDGE ${HAVE_PLEDGE} 345 | #define HAVE_PROGRAM_INVOCATION_SHORT_NAME ${HAVE_PROGRAM_INVOCATION_SHORT_NAME} 346 | #define HAVE_REALLOCARRAY ${HAVE_REALLOCARRAY} 347 | #define HAVE_RECALLOCARRAY ${HAVE_RECALLOCARRAY} 348 | #define HAVE_SANDBOX_INIT ${HAVE_SANDBOX_INIT} 349 | #define HAVE_SECCOMP_FILTER ${HAVE_SECCOMP_FILTER} 350 | #define HAVE_SOCK_NONBLOCK ${HAVE_SOCK_NONBLOCK} 351 | #define HAVE_STRLCAT ${HAVE_STRLCAT} 352 | #define HAVE_STRLCPY ${HAVE_STRLCPY} 353 | #define HAVE_STRNDUP ${HAVE_STRNDUP} 354 | #define HAVE_STRNLEN ${HAVE_STRNLEN} 355 | #define HAVE_STRTONUM ${HAVE_STRTONUM} 356 | #define HAVE_SYSTRACE ${HAVE_SYSTRACE} 357 | #define HAVE_ZLIB ${HAVE_ZLIB} 358 | #define HAVE___PROGNAME ${HAVE___PROGNAME} 359 | __HEREDOC__ 360 | 361 | # Now we do our function declarations for missing functions. 362 | 363 | if [ ${HAVE_ERR} -eq 0 ]; then 364 | echo "extern void err(int, const char *, ...);" 365 | echo "extern void errx(int, const char *, ...);" 366 | echo "extern void warn(const char *, ...);" 367 | echo "extern void warnx(const char *, ...);" 368 | echo "extern void vwarn(const char *, va_list);" 369 | echo "extern void vwarnx(const char *, va_list);" 370 | fi 371 | 372 | if [ ${HAVE_MD5} -eq 0 ]; then 373 | echo "#define MD5_BLOCK_LENGTH 64" 374 | echo "#define MD5_DIGEST_LENGTH 16" 375 | echo "#define MD5_DIGEST_STRING_LENGTH (MD5_DIGEST_LENGTH * 2 + 1)" 376 | cat </dev/null || echo unknown` 393 | case "$arch" in 394 | x86_64) 395 | echo "#define SECCOMP_AUDIT_ARCH AUDIT_ARCH_X86_64" 396 | ;; 397 | i*86) 398 | echo "#define SECCOMP_AUDIT_ARCH AUDIT_ARCH_I386" 399 | ;; 400 | arm*) 401 | echo "#define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARM" 402 | ;; 403 | esac 404 | fi 405 | 406 | if [ ${HAVE_EXPLICIT_BZERO} -eq 0 ]; then 407 | echo "extern void explicit_bzero(void *, size_t);" 408 | fi 409 | 410 | if [ ${HAVE_MEMMEM} -eq 0 ]; then 411 | echo "void *memmem(const void *, size_t, const void *, size_t);" 412 | fi 413 | 414 | if [ ${HAVE_MEMRCHR} -eq 0 ]; then 415 | echo "void *memrchr(const void *b, int, size_t);" 416 | fi 417 | 418 | if [ ${HAVE_GETPROGNAME} -eq 0 ]; then 419 | echo "extern const char *getprogname(void);" 420 | fi 421 | 422 | if [ ${HAVE_REALLOCARRAY} -eq 0 ]; then 423 | echo "extern void *reallocarray(void *, size_t, size_t);" 424 | fi 425 | 426 | if [ ${HAVE_RECALLOCARRAY} -eq 0 ]; then 427 | echo "extern void *recallocarray(void *, size_t, size_t, size_t);" 428 | fi 429 | 430 | if [ ${HAVE_STRLCAT} -eq 0 ]; then 431 | echo "extern size_t strlcat(char *, const char *, size_t);" 432 | fi 433 | 434 | if [ ${HAVE_STRLCPY} -eq 0 ]; then 435 | echo "extern size_t strlcpy(char *, const char *, size_t);" 436 | fi 437 | 438 | if [ ${HAVE_STRNDUP} -eq 0 ]; then 439 | echo "extern char *strndup(const char *, size_t);" 440 | fi 441 | 442 | if [ ${HAVE_STRNLEN} -eq 0 ]; then 443 | echo "extern size_t strnlen(const char *, size_t);" 444 | fi 445 | 446 | if [ ${HAVE_STRTONUM} -eq 0 ]; then 447 | echo "extern long long strtonum(const char *, long long, long long, const char **);" 448 | fi 449 | 450 | echo "config.h: written" 1>&2 451 | echo "config.h: written" 1>&3 452 | 453 | #---------------------------------------------------------------------- 454 | # Now we go to generate our Makefile.configure. 455 | # This file is simply a bunch of Makefile variables. 456 | # They'll work in both GNUmakefile and BSDmakefile. 457 | # You MIGHT want to change this. 458 | #---------------------------------------------------------------------- 459 | 460 | exec > Makefile.configure 461 | 462 | [ -z "${BINDIR}" ] && BINDIR="${PREFIX}/bin" 463 | [ -z "${SBINDIR}" ] && SBINDIR="${PREFIX}/sbin" 464 | [ -z "${INCLUDEDIR}" ] && INCLUDEDIR="${PREFIX}/include" 465 | [ -z "${LIBDIR}" ] && LIBDIR="${PREFIX}/lib" 466 | [ -z "${MANDIR}" ] && MANDIR="${PREFIX}/man" 467 | [ -z "${SHAREDIR}" ] && SHAREDIR="${PREFIX}/share" 468 | 469 | [ -z "${INSTALL_PROGRAM}" ] && INSTALL_PROGRAM="${INSTALL} -m 0555" 470 | [ -z "${INSTALL_LIB}" ] && INSTALL_LIB="${INSTALL} -m 0444" 471 | [ -z "${INSTALL_MAN}" ] && INSTALL_MAN="${INSTALL} -m 0444" 472 | [ -z "${INSTALL_DATA}" ] && INSTALL_DATA="${INSTALL} -m 0444" 473 | 474 | cat << __HEREDOC__ 475 | CC = ${CC} 476 | CFLAGS = ${CFLAGS} 477 | CPPFLAGS = ${CPPFLAGS} 478 | LDADD = ${LDADD} 479 | LDFLAGS = ${LDFLAGS} 480 | STATIC = ${STATIC} 481 | PREFIX = ${PREFIX} 482 | BINDIR = ${BINDIR} 483 | SHAREDIR = ${SHAREDIR} 484 | SBINDIR = ${SBINDIR} 485 | INCLUDEDIR = ${INCLUDEDIR} 486 | LIBDIR = ${LIBDIR} 487 | MANDIR = ${MANDIR} 488 | INSTALL = ${INSTALL} 489 | INSTALL_PROGRAM = ${INSTALL_PROGRAM} 490 | INSTALL_LIB = ${INSTALL_LIB} 491 | INSTALL_MAN = ${INSTALL_MAN} 492 | INSTALL_DATA = ${INSTALL_DATA} 493 | __HEREDOC__ 494 | 495 | echo "Makefile.configure: written" 1>&2 496 | echo "Makefile.configure: written" 1>&3 497 | 498 | exit 0 499 | -------------------------------------------------------------------------------- /diff.3: -------------------------------------------------------------------------------- 1 | .\" $Id$ 2 | .\" 3 | .\" Copyright (c) 2018 Kristaps Dzonsons 4 | .\" 5 | .\" Permission is hereby granted, free of charge, to any person obtaining 6 | .\" a copy of this software and associated documentation files (the 7 | .\" "Software"), to deal in the Software without restriction, including 8 | .\" without limitation the rights to use, copy, modify, merge, publish, 9 | .\" distribute, sublicense, and/or sell copies of the Software, and to 10 | .\" permit persons to whom the Software is furnished to do so, subject to 11 | .\" the following conditions: 12 | .\" 13 | .\" The above copyright notice and this permission notice shall be 14 | .\" included in all copies or substantial portions of the Software. 15 | .\" 16 | .\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | .\" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | .\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | .\" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 20 | .\" BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 21 | .\" ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | .\" CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | .\" SOFTWARE. 24 | .\" 25 | .Dd $Mdocdate$ 26 | .Dt DIFF 3 27 | .Os 28 | .Sh NAME 29 | .Nm diff 30 | .Nd generate arbitrary sequence diffs 31 | .Sh LIBRARY 32 | .Lb libdiff 33 | .Sh SYNOPSIS 34 | .In diff.h 35 | .Ft int 36 | .Fo diff 37 | .Fa "struct diff *p" 38 | .Fa "int (*cmp)(const void *, const void *)" 39 | .Fa "size_t size" 40 | .Fa "const void *base1" 41 | .Fa "size_t nmemb1" 42 | .Fa "const void *base2" 43 | .Fa "size_t nmemb2" 44 | .Fc 45 | .Sh DESCRIPTION 46 | The 47 | .Fn diff 48 | function generates the shortest edit script, longest common subsequence, 49 | and edit distance going from an origin array of 50 | .Fa nmemb1 51 | objects, the initial member of which is pointed to as 52 | .Fa base1 ; 53 | to the target array of 54 | .Fa nmemb2 55 | objects with initial member 56 | .Fa base2 . 57 | The size of each object is specified by 58 | .Fa size . 59 | Objects are compared by 60 | .Fa cmp , 61 | which requires two arguments pointing to the objects being compared. 62 | It returns zero if the objects are the same, non-zero otherwise. 63 | .Pp 64 | On success, 65 | .Fn diff 66 | sets the edit distance in 67 | .Fa p->editdist . 68 | It allocates the 69 | .Fa p->ses 70 | array of length 71 | .Fa p->sessz 72 | and fills it with the shortest common subsequence. 73 | It also allocates the 74 | .Fa p->lcs 75 | array of length 76 | .Fa p->lcssz 77 | and fills it with the longest common subsequence. 78 | Both arrays must be passed to 79 | .Xr free 3 80 | by the caller. 81 | .Sh RETURN VALUES 82 | The 83 | .Fn diff 84 | function returns <0 on memory allocation failure, 0 if the sequence is 85 | too complicated to generate, or >0 otherwise on success. 86 | .\" For sections 2, 3, and 9 function return values only. 87 | .\" .Sh ENVIRONMENT 88 | .\" For sections 1, 6, 7, and 8 only. 89 | .\" .Sh FILES 90 | .\" .Sh EXIT STATUS 91 | .\" For sections 1, 6, and 8 only. 92 | .Sh EXAMPLES 93 | The following example takes two strings, 94 | .Qq asdf 95 | and 96 | .Qq fdsa , 97 | and displays the edit script to go from the first to the second. 98 | .Bd -literal 99 | int cmp(const void *p1, const void *p2) { 100 | return *(const char *)p1 == *(const char *)p2; 101 | } 102 | 103 | void compute(void) { 104 | size_t i; 105 | int rc; 106 | struct diff p; 107 | 108 | rc = diff(&p, cmp, 1, "asdf", 4, "fdsa", 4); 109 | 110 | if (rc < 0) 111 | err(EXIT_FAILURE, NULL); 112 | if (0 == rc) 113 | errx(EXIT_FAILURE, "cannot compute distance"); 114 | 115 | for (i = 0; i < p.sessz; i++) 116 | printf("%s%c\en", 117 | DIFF_ADD == p.ses[i].type ? "+" : 118 | DIFF_DELETE == p.ses[i].type ? "-" : " ", 119 | *(const char *)p.ses[i].e); 120 | free(p.ses); 121 | free(p.lcs); 122 | } 123 | .Ed 124 | .Pp 125 | The second example looks for difference in words. 126 | .Bd -literal 127 | int cmp(const void *p1, const void *p2) { 128 | return 0 == strcmp 129 | (*(const char **)p1, *(const char **)p2); 130 | } 131 | 132 | void compute(void) { 133 | size_t i; 134 | int rc; 135 | struct diff p; 136 | const char *origin[] = { "hello", "there" }; 137 | const char *target[] = { "hello", "world" }; 138 | 139 | rc = diff(&p, cmp, sizeof(char *), origin, 2, target, 2); 140 | 141 | if (rc < 0) 142 | err(EXIT_FAILURE, NULL); 143 | if (0 == rc) 144 | errx(EXIT_FAILURE, "cannot compute distance"); 145 | 146 | for (i = 0; i < p.sessz; i++) 147 | printf("%s%s\en", 148 | DIFF_ADD == p.ses[i].type ? "+" : 149 | DIFF_DELETE == p.ses[i].type ? "-" : " ", 150 | *(const char **)p.ses[i].e); 151 | free(p.ses); 152 | free(p.lcs); 153 | } 154 | .Ed 155 | .\" .Sh DIAGNOSTICS 156 | .\" For sections 1, 4, 6, 7, 8, and 9 printf/stderr messages only. 157 | .\" .Sh ERRORS 158 | .\" For sections 2, 3, 4, and 9 errno settings only. 159 | .Sh SEE ALSO 160 | .Rs 161 | .%A Wu Sun 162 | .%A Manber Udi 163 | .%A Myers Gene 164 | .%T An O(NP) sequence comparison algorithm 165 | .%J Information Processing Letters 166 | .%V Volume 35 167 | .%I Issue 6 168 | .%D 1990 169 | .Re 170 | .\" .Xr foobar 1 171 | .\" .Sh STANDARDS 172 | .\" .Sh HISTORY 173 | .\" .Sh AUTHORS 174 | .\" .Sh CAVEATS 175 | .\" .Sh BUGS 176 | -------------------------------------------------------------------------------- /diff.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Tatsuhiko Kubo 3 | * Copyright (c) 2018 Kristaps Dzonsons 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 20 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 21 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #include "config.h" 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include "diff.h" 32 | 33 | struct onp_coord { 34 | int x; 35 | int y; 36 | int k; 37 | }; 38 | 39 | struct onp_diff { 40 | const void *a; /* shorter subsequence */ 41 | const void *b; /* longer subsequence */ 42 | size_t m; /* length of "a" */ 43 | size_t n; /* length of "b" */ 44 | diff_cmp cmp; /* comparison function */ 45 | int *path; 46 | size_t delta; 47 | size_t offset; 48 | size_t size; /* matrix size */ 49 | size_t sz; /* data element width */ 50 | struct onp_coord *pathcoords; 51 | size_t pathcoordsz; 52 | int swapped; /* seqs swapped from input */ 53 | struct diff *result; 54 | }; 55 | 56 | #define ONP_CMP(_d, _o1, _o2) \ 57 | ((_d)->cmp((_d)->a + (_d)->sz * (_o1), \ 58 | (_d)->b + (_d)->sz * (_o2))) 59 | 60 | /* 61 | * Search shortest path and record the path. 62 | */ 63 | static int 64 | onp_snake(struct onp_diff *diff, int k, int above, int below) 65 | { 66 | int r, y, x; 67 | void *pp; 68 | 69 | y = above > below ? above : below; 70 | x = y - k; 71 | 72 | r = above > below ? 73 | diff->path[k - 1 + diff->offset] : 74 | diff->path[k + 1 + diff->offset]; 75 | 76 | while (x < (int)diff->m && y < (int)diff->n && 77 | ONP_CMP(diff, x, y)) { 78 | ++x; 79 | ++y; 80 | } 81 | 82 | diff->path[k + diff->offset] = diff->pathcoordsz; 83 | 84 | pp = reallocarray 85 | (diff->pathcoords, 86 | diff->pathcoordsz + 1, 87 | sizeof(struct onp_coord)); 88 | if (NULL == pp) 89 | return -1; 90 | diff->pathcoords = pp; 91 | 92 | assert(x >= 0); 93 | assert(y >= 0); 94 | 95 | diff->pathcoords[diff->pathcoordsz].x = x; 96 | diff->pathcoords[diff->pathcoordsz].y = y; 97 | diff->pathcoords[diff->pathcoordsz].k = r; 98 | diff->pathcoordsz++; 99 | 100 | return y; 101 | } 102 | 103 | static int 104 | onp_addlcs(struct onp_diff *diff, const void *e) 105 | { 106 | void *pp; 107 | 108 | pp = reallocarray 109 | (diff->result->lcs, 110 | diff->result->lcssz + 1, 111 | sizeof(void *)); 112 | if (NULL == pp) 113 | return 0; 114 | diff->result->lcs = pp; 115 | diff->result->lcs[diff->result->lcssz] = e; 116 | diff->result->lcssz++; 117 | return 1; 118 | } 119 | 120 | static int 121 | onp_addses(struct onp_diff *diff, const void *e, 122 | size_t originIdx, size_t targetIdx, enum difft type) 123 | { 124 | void *pp; 125 | 126 | pp = reallocarray 127 | (diff->result->ses, 128 | diff->result->sessz + 1, 129 | sizeof(struct diff_ses)); 130 | if (NULL == pp) 131 | return 0; 132 | diff->result->ses = pp; 133 | diff->result->ses[diff->result->sessz].originIdx = originIdx; 134 | diff->result->ses[diff->result->sessz].targetIdx = targetIdx; 135 | diff->result->ses[diff->result->sessz].type = type; 136 | diff->result->ses[diff->result->sessz].e = e; 137 | diff->result->sessz++; 138 | return 1; 139 | } 140 | 141 | static int 142 | onp_genseq(struct onp_diff *diff, const struct onp_coord* v, size_t vsz) 143 | { 144 | size_t xpos, ypos; 145 | size_t x_idx, y_idx; /* offset+1 numbers */ 146 | int px_idx, py_idx; /* coordinates */ 147 | int complete = 0; 148 | int rc; 149 | size_t i; 150 | 151 | x_idx = y_idx = 1; 152 | px_idx = py_idx = 0; 153 | xpos = ypos = 0; 154 | 155 | assert(vsz); 156 | 157 | for (i = vsz - 1; ! complete; --i) { 158 | while (px_idx < v[i].x || py_idx < v[i].y) { 159 | if (v[i].y - v[i].x > py_idx - px_idx) { 160 | rc = ! diff->swapped ? 161 | onp_addses(diff, 162 | diff->b + (ypos * diff->sz), 163 | 0, y_idx, DIFF_ADD) : 164 | onp_addses(diff, 165 | diff->b + (ypos * diff->sz), 166 | y_idx, 0, DIFF_DELETE); 167 | ++ypos; 168 | ++y_idx; 169 | ++py_idx; 170 | } else if (v[i].y - v[i].x < py_idx - px_idx) { 171 | rc = ! diff->swapped ? 172 | onp_addses(diff, 173 | diff->a + (xpos * diff->sz), 174 | x_idx, 0, DIFF_DELETE) : 175 | onp_addses(diff, 176 | diff->a + (xpos * diff->sz), 177 | 0, x_idx, DIFF_ADD); 178 | ++xpos; 179 | ++x_idx; 180 | ++px_idx; 181 | } else { 182 | rc = ! diff->swapped ? 183 | onp_addses(diff, 184 | diff->a + (xpos * diff->sz), 185 | x_idx, y_idx, DIFF_COMMON) : 186 | onp_addses(diff, 187 | diff->b + (ypos * diff->sz), 188 | y_idx, x_idx, DIFF_COMMON); 189 | if (rc) 190 | rc = ! diff->swapped ? 191 | onp_addlcs(diff, diff->a + 192 | (xpos * diff->sz)) : 193 | onp_addlcs(diff, diff->b + 194 | (ypos * diff->sz)); 195 | ++xpos; 196 | ++ypos; 197 | ++x_idx; 198 | ++y_idx; 199 | ++px_idx; 200 | ++py_idx; 201 | } 202 | if ( ! rc) 203 | return -1; 204 | } 205 | complete = 0 == i; 206 | } 207 | 208 | return x_idx > diff->m && y_idx > diff->n; 209 | } 210 | 211 | static struct onp_diff * 212 | onp_alloc(diff_cmp cmp, size_t sz, 213 | const void *a, size_t alen, 214 | const void *b, size_t blen) 215 | { 216 | struct onp_diff *diff; 217 | 218 | diff = calloc(1, sizeof(struct onp_diff)); 219 | 220 | if (NULL == diff) 221 | return NULL; 222 | 223 | if (alen > blen) { 224 | diff->a = b; 225 | diff->b = a; 226 | diff->m = blen; 227 | diff->n = alen; 228 | diff->swapped = 1; 229 | } else { 230 | diff->a = a; 231 | diff->b = b; 232 | diff->m = alen; 233 | diff->n = blen; 234 | diff->swapped = 0; 235 | } 236 | 237 | assert(diff->n >= diff->m); 238 | diff->cmp = cmp; 239 | diff->sz = sz; 240 | diff->delta = diff->n - diff->m; 241 | diff->offset = diff->m + 1; 242 | diff->size = diff->m + diff->n + 3; 243 | 244 | return diff; 245 | } 246 | 247 | static void 248 | onp_free(struct onp_diff *diff) 249 | { 250 | 251 | free(diff->path); 252 | free(diff->pathcoords); 253 | free(diff); 254 | } 255 | 256 | static int 257 | onp_compose(struct onp_diff *diff, struct diff *result) 258 | { 259 | int rc = 0; 260 | int p = -1; 261 | int k; 262 | int *fp = NULL; 263 | int r; 264 | struct onp_coord *epc = NULL; 265 | size_t epcsz = 0; 266 | size_t i; 267 | void *pp; 268 | 269 | /* Initialise the path from origin to target. */ 270 | 271 | fp = malloc(sizeof(int) * diff->size); 272 | diff->path = malloc(sizeof(int) * diff->size); 273 | diff->result = result; 274 | 275 | if (NULL == fp || NULL == diff->path) 276 | goto out; 277 | 278 | for (i = 0; i < diff->size; i++) 279 | fp[i] = diff->path[i] = -1; 280 | 281 | /* 282 | * Run the actual algorithm. 283 | * This computes the full path in diff->path from the origin to 284 | * the target. 285 | */ 286 | 287 | do { 288 | p++; 289 | for (k = -p; 290 | k <= (ssize_t)diff->delta - 1; k++) { 291 | fp[k + diff->offset] = onp_snake(diff, k, 292 | fp[k - 1 + diff->offset] + 1, 293 | fp[k + 1 + diff->offset]); 294 | if (fp[k + diff->offset] < 0) 295 | goto out; 296 | } 297 | for (k = diff->delta + p; 298 | k >= (ssize_t)diff->delta + 1; k--) { 299 | fp[k + diff->offset] = onp_snake(diff, k, 300 | fp[k - 1 + diff->offset] + 1, 301 | fp[k + 1 + diff->offset]); 302 | if (fp[k + diff->offset] < 0) 303 | goto out; 304 | } 305 | 306 | fp[diff->delta + diff->offset] = 307 | onp_snake(diff, diff->delta, 308 | fp[diff->delta - 1 + diff->offset] + 1, 309 | fp[diff->delta + 1 + diff->offset]); 310 | if (fp[diff->delta + diff->offset] < 0) 311 | goto out; 312 | } while (fp[diff->delta + diff->offset] != (ssize_t)diff->n); 313 | 314 | /* Now compute edit distance. */ 315 | 316 | assert(p >= 0); 317 | diff->result->editdist = diff->delta + 2 * p; 318 | 319 | /* 320 | * Here we compute the shortest edit script and the least common 321 | * subsequence from the path. 322 | */ 323 | 324 | r = diff->path[diff->delta + diff->offset]; 325 | 326 | while(-1 != r) { 327 | pp = reallocarray 328 | (epc, epcsz + 1, 329 | sizeof(struct onp_coord)); 330 | if (NULL == pp) 331 | goto out; 332 | epc = pp; 333 | epc[epcsz].x = diff->pathcoords[r].x; 334 | epc[epcsz].y = diff->pathcoords[r].y; 335 | epcsz++; 336 | r = diff->pathcoords[r].k; 337 | } 338 | 339 | if (epcsz) 340 | onp_genseq(diff, epc, epcsz); 341 | 342 | rc = 1; 343 | out: 344 | free(fp); 345 | free(epc); 346 | return rc; 347 | } 348 | 349 | int 350 | diff(struct diff *d, diff_cmp cmp, size_t size, 351 | const void *base1, size_t nmemb1, 352 | const void *base2, size_t nmemb2) 353 | { 354 | struct onp_diff *p; 355 | int rc; 356 | 357 | if (NULL == d) 358 | return 0; 359 | 360 | memset(d, 0, sizeof(struct diff)); 361 | 362 | p = onp_alloc(cmp, size, base1, nmemb1, base2, nmemb2); 363 | if (NULL == p) 364 | return -1; 365 | 366 | rc = onp_compose(p, d); 367 | onp_free(p); 368 | 369 | if (0 == rc) { 370 | free(d->ses); 371 | return -1; 372 | } 373 | 374 | return 1; 375 | } 376 | -------------------------------------------------------------------------------- /diff.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Tatsuhiko Kubo 3 | * Copyright (c) 2018 Kristaps Dzonsons 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 20 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 21 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #ifndef DIFF_H 26 | #define DIFF_H 27 | 28 | typedef int (*diff_cmp)(const void *, const void *); 29 | 30 | enum difft { 31 | DIFF_ADD, 32 | DIFF_DELETE, 33 | DIFF_COMMON 34 | }; 35 | 36 | struct diff_ses { 37 | size_t originIdx; /* if >0, index+1 in origin array */ 38 | size_t targetIdx; /* if >0, index+1 in target array */ 39 | enum difft type; /* type of edit */ 40 | const void *e; /* pointer to object */ 41 | }; 42 | 43 | struct diff { 44 | const void **lcs; /* longest common subsequence */ 45 | size_t lcssz; 46 | struct diff_ses *ses; /* shortest edit script */ 47 | size_t sessz; 48 | size_t editdist; /* edit distance */ 49 | }; 50 | 51 | int diff(struct diff *, diff_cmp, size_t, 52 | const void *, size_t, const void *, size_t); 53 | 54 | #endif /* ! DIFF_H */ 55 | -------------------------------------------------------------------------------- /diffchars.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Kristaps Dzonsons 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #include "config.h" 25 | 26 | #ifdef HAVE_ERR 27 | # include 28 | #endif 29 | #include 30 | #include 31 | #include 32 | 33 | #include "diff.h" 34 | 35 | static int 36 | char_cmp(const void *p1, const void *p2) 37 | { 38 | 39 | return *(const char *)p1 == *(const char *)p2; 40 | } 41 | 42 | int 43 | main(int argc, char *argv[]) 44 | { 45 | size_t i; 46 | int rc; 47 | struct diff p; 48 | 49 | if (argc < 3) { 50 | fprintf(stderr, "usage: %s origin target\n", 51 | getprogname()); 52 | return EXIT_FAILURE; 53 | } 54 | 55 | rc = diff(&p, char_cmp, sizeof(char), 56 | argv[1], strlen(argv[1]), 57 | argv[2], strlen(argv[2])); 58 | 59 | if (rc < 0) 60 | err(EXIT_FAILURE, NULL); 61 | if (0 == rc) 62 | errx(EXIT_FAILURE, "cannot compute difference"); 63 | 64 | puts("Shortest edit script:"); 65 | for (i = 0; i < p.sessz; i++) 66 | printf("%s%c\n", 67 | DIFF_ADD == p.ses[i].type ? "+" : 68 | DIFF_DELETE == p.ses[i].type ? "-" : " ", 69 | *(const char *)p.ses[i].e); 70 | 71 | printf("Longest common subsequence: "); 72 | for (i = 0; i < p.lcssz; i++) 73 | printf("%c", *(const char *)p.lcs[i]); 74 | puts(""); 75 | 76 | printf("Edit distance: %zu\n", p.editdist); 77 | 78 | free(p.ses); 79 | free(p.lcs); 80 | return EXIT_SUCCESS; 81 | } 82 | -------------------------------------------------------------------------------- /diffwords.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Kristaps Dzonsons 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #include "config.h" 25 | 26 | #ifdef HAVE_ERR 27 | # include 28 | #endif 29 | #include 30 | #include 31 | #include 32 | 33 | #include "diff.h" 34 | 35 | static int 36 | word_cmp(const void *p1, const void *p2) 37 | { 38 | 39 | return 0 == strcmp(*(const char **)p1, *(const char **)p2); 40 | } 41 | 42 | static void 43 | tokenise(char *input, char ***out, size_t *outsz) 44 | { 45 | char *cp; 46 | 47 | while (NULL != (cp = strsep(&input, " "))) { 48 | if ('\0' == *cp) 49 | continue; 50 | *out = reallocarray 51 | (*out, *outsz + 1, sizeof(char *)); 52 | if (NULL == *out) 53 | err(EXIT_FAILURE, NULL); 54 | (*out)[*outsz] = cp; 55 | (*outsz)++; 56 | } 57 | } 58 | 59 | int 60 | main(int argc, char *argv[]) 61 | { 62 | size_t i; 63 | int rc; 64 | struct diff p; 65 | char **origin = NULL, **target = NULL; 66 | size_t originsz = 0, targetsz = 0; 67 | 68 | if (argc < 3) { 69 | fprintf(stderr, "usage: %s origin target\n", 70 | getprogname()); 71 | return EXIT_FAILURE; 72 | } 73 | 74 | tokenise(argv[1], &origin, &originsz); 75 | tokenise(argv[2], &target, &targetsz); 76 | 77 | rc = diff(&p, word_cmp, sizeof(char *), 78 | origin, originsz, 79 | target, targetsz); 80 | 81 | if (rc < 0) 82 | err(EXIT_FAILURE, NULL); 83 | if (0 == rc) 84 | errx(EXIT_FAILURE, "cannot compute difference"); 85 | 86 | puts("Shortest edit script:"); 87 | for (i = 0; i < p.sessz; i++) 88 | printf("%s%s\n", 89 | DIFF_ADD == p.ses[i].type ? "+" : 90 | DIFF_DELETE == p.ses[i].type ? "-" : " ", 91 | *(const char **)p.ses[i].e); 92 | 93 | puts("Longest common subsequence:"); 94 | for (i = 0; i < p.lcssz; i++) 95 | printf(" %s\n", *(const char **)p.lcs[i]); 96 | 97 | printf("Edit distance: %zu\n", p.editdist); 98 | 99 | free(p.ses); 100 | free(p.lcs); 101 | free(origin); 102 | free(target); 103 | return EXIT_SUCCESS; 104 | } 105 | -------------------------------------------------------------------------------- /tests.c: -------------------------------------------------------------------------------- 1 | #if TEST___PROGNAME 2 | int 3 | main(void) 4 | { 5 | extern char *__progname; 6 | 7 | return !__progname; 8 | } 9 | #endif /* TEST___PROGNAME */ 10 | #if TEST_ARC4RANDOM 11 | #include 12 | 13 | int 14 | main(void) 15 | { 16 | return (arc4random() + 1) ? 0 : 1; 17 | } 18 | #endif /* TEST_ARC4RANDOM */ 19 | #if TEST_CAPSICUM 20 | #include 21 | 22 | int 23 | main(void) 24 | { 25 | cap_enter(); 26 | return(0); 27 | } 28 | #endif /* TEST_CAPSICUM */ 29 | #if TEST_ERR 30 | /* 31 | * Copyright (c) 2015 Ingo Schwarze 32 | * 33 | * Permission to use, copy, modify, and distribute this software for any 34 | * purpose with or without fee is hereby granted, provided that the above 35 | * copyright notice and this permission notice appear in all copies. 36 | * 37 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 38 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 39 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 40 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 41 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 42 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 43 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 44 | */ 45 | 46 | #include 47 | 48 | int 49 | main(void) 50 | { 51 | warnx("%d. warnx", 1); 52 | warn("%d. warn", 2); 53 | err(0, "%d. err", 3); 54 | /* NOTREACHED */ 55 | return 1; 56 | } 57 | #endif /* TEST_ERR */ 58 | #if TEST_EXPLICIT_BZERO 59 | #include 60 | 61 | int 62 | main(void) 63 | { 64 | char foo[10]; 65 | 66 | explicit_bzero(foo, sizeof(foo)); 67 | return(0); 68 | } 69 | #endif /* TEST_EXPLICIT_BZERO */ 70 | #if TEST_GETPROGNAME 71 | #include 72 | 73 | int 74 | main(void) 75 | { 76 | const char * progname; 77 | 78 | progname = getprogname(); 79 | return progname == NULL; 80 | } 81 | #endif /* TEST_GETPROGNAME */ 82 | #if TEST_INFTIM 83 | /* 84 | * Linux doesn't (always?) have this. 85 | */ 86 | 87 | #include 88 | #include 89 | 90 | int 91 | main(void) 92 | { 93 | printf("INFTIM is defined to be %ld\n", (long)INFTIM); 94 | return 0; 95 | } 96 | #endif /* TEST_INFTIM */ 97 | #if TEST_MD5 98 | #include 99 | #include 100 | 101 | int main(void) 102 | { 103 | MD5_CTX ctx; 104 | 105 | MD5Init(&ctx); 106 | MD5Update(&ctx, "abcd", 4); 107 | 108 | return 0; 109 | } 110 | #endif /* TEST_MD5 */ 111 | #if TEST_MEMMEM 112 | #define _GNU_SOURCE 113 | #include 114 | 115 | int 116 | main(void) 117 | { 118 | char *a = memmem("hello, world", strlen("hello, world"), "world", strlen("world")); 119 | return(NULL == a); 120 | } 121 | #endif /* TEST_MEMMEM */ 122 | #if TEST_MEMRCHR 123 | #if defined(__linux__) || defined(__MINT__) 124 | #define _GNU_SOURCE /* See test-*.c what needs this. */ 125 | #endif 126 | #include 127 | 128 | int 129 | main(void) 130 | { 131 | const char *buf = "abcdef"; 132 | void *res; 133 | 134 | res = memrchr(buf, 'a', strlen(buf)); 135 | return(NULL == res ? 1 : 0); 136 | } 137 | #endif /* TEST_MEMRCHR */ 138 | #if TEST_MEMSET_S 139 | #include 140 | 141 | int main(void) 142 | { 143 | char buf[10]; 144 | memset_s(buf, 0, 'c', sizeof(buf)); 145 | return 0; 146 | } 147 | #endif /* TEST_MEMSET_S */ 148 | #if TEST_PATH_MAX 149 | /* 150 | * POSIX allows PATH_MAX to not be defined, see 151 | * http://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html; 152 | * the GNU Hurd is an example of a system not having it. 153 | * 154 | * Arguably, it would be better to test sysconf(_SC_PATH_MAX), 155 | * but since the individual *.c files include "config.h" before 156 | * , overriding an excessive value of PATH_MAX from 157 | * "config.h" is impossible anyway, so for now, the simplest 158 | * fix is to provide a value only on systems not having any. 159 | * So far, we encountered no system defining PATH_MAX to an 160 | * impractically large value, even though POSIX explicitly 161 | * allows that. 162 | * 163 | * The real fix would be to replace all static buffers of size 164 | * PATH_MAX by dynamically allocated buffers. But that is 165 | * somewhat intrusive because it touches several files and 166 | * because it requires changing struct mlink in mandocdb.c. 167 | * So i'm postponing that for now. 168 | */ 169 | 170 | #include 171 | #include 172 | 173 | int 174 | main(void) 175 | { 176 | printf("PATH_MAX is defined to be %ld\n", (long)PATH_MAX); 177 | return 0; 178 | } 179 | #endif /* TEST_PATH_MAX */ 180 | #if TEST_PLEDGE 181 | #include 182 | 183 | int 184 | main(void) 185 | { 186 | return !!pledge("stdio", NULL); 187 | } 188 | #endif /* TEST_PLEDGE */ 189 | #if TEST_PROGRAM_INVOCATION_SHORT_NAME 190 | #define _GNU_SOURCE /* See feature_test_macros(7) */ 191 | #include 192 | 193 | int 194 | main(void) 195 | { 196 | 197 | return !program_invocation_short_name; 198 | } 199 | #endif /* TEST_PROGRAM_INVOCATION_SHORT_NAME */ 200 | #if TEST_REALLOCARRAY 201 | #include 202 | 203 | int 204 | main(void) 205 | { 206 | return !reallocarray(NULL, 2, 2); 207 | } 208 | #endif /* TEST_REALLOCARRAY */ 209 | #if TEST_RECALLOCARRAY 210 | #include 211 | 212 | int 213 | main(void) 214 | { 215 | return !recallocarray(NULL, 0, 2, 2); 216 | } 217 | #endif /* TEST_RECALLOCARRAY */ 218 | #if TEST_SANDBOX_INIT 219 | #include 220 | 221 | int 222 | main(void) 223 | { 224 | char *ep; 225 | int rc; 226 | 227 | rc = sandbox_init(kSBXProfileNoInternet, SANDBOX_NAMED, &ep); 228 | if (-1 == rc) 229 | sandbox_free_error(ep); 230 | return(-1 == rc); 231 | } 232 | #endif /* TEST_SANDBOX_INIT */ 233 | #if TEST_SECCOMP_FILTER 234 | #include 235 | #include 236 | #include 237 | 238 | int 239 | main(void) 240 | { 241 | 242 | prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, 0); 243 | return(EFAULT == errno ? 0 : 1); 244 | } 245 | #endif /* TEST_SECCOMP_FILTER */ 246 | #if TEST_SOCK_NONBLOCK 247 | /* 248 | * Linux doesn't (always?) have this. 249 | */ 250 | 251 | #include 252 | 253 | int 254 | main(void) 255 | { 256 | int fd[2]; 257 | socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK, 0, fd); 258 | return 0; 259 | } 260 | #endif /* TEST_SOCK_NONBLOCK */ 261 | #if TEST_STRLCAT 262 | #include 263 | 264 | int 265 | main(void) 266 | { 267 | char buf[3] = "a"; 268 | return ! (strlcat(buf, "b", sizeof(buf)) == 2 && 269 | buf[0] == 'a' && buf[1] == 'b' && buf[2] == '\0'); 270 | } 271 | #endif /* TEST_STRLCAT */ 272 | #if TEST_STRLCPY 273 | #include 274 | 275 | int 276 | main(void) 277 | { 278 | char buf[2] = ""; 279 | return ! (strlcpy(buf, "a", sizeof(buf)) == 1 && 280 | buf[0] == 'a' && buf[1] == '\0'); 281 | } 282 | #endif /* TEST_STRLCPY */ 283 | #if TEST_STRNDUP 284 | #include 285 | 286 | int 287 | main(void) 288 | { 289 | const char *foo = "bar"; 290 | char *baz; 291 | 292 | baz = strndup(foo, 1); 293 | return(0 != strcmp(baz, "b")); 294 | } 295 | #endif /* TEST_STRNDUP */ 296 | #if TEST_STRNLEN 297 | #include 298 | 299 | int 300 | main(void) 301 | { 302 | const char *foo = "bar"; 303 | size_t sz; 304 | 305 | sz = strnlen(foo, 1); 306 | return(1 != sz); 307 | } 308 | #endif /* TEST_STRNLEN */ 309 | #if TEST_STRTONUM 310 | /* 311 | * Copyright (c) 2015 Ingo Schwarze 312 | * 313 | * Permission to use, copy, modify, and distribute this software for any 314 | * purpose with or without fee is hereby granted, provided that the above 315 | * copyright notice and this permission notice appear in all copies. 316 | * 317 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 318 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 319 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 320 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 321 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 322 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 323 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 324 | */ 325 | 326 | #include 327 | 328 | int 329 | main(void) 330 | { 331 | const char *errstr; 332 | 333 | if (strtonum("1", 0, 2, &errstr) != 1) 334 | return 1; 335 | if (errstr != NULL) 336 | return 2; 337 | if (strtonum("1x", 0, 2, &errstr) != 0) 338 | return 3; 339 | if (errstr == NULL) 340 | return 4; 341 | if (strtonum("2", 0, 1, &errstr) != 0) 342 | return 5; 343 | if (errstr == NULL) 344 | return 6; 345 | if (strtonum("0", 1, 2, &errstr) != 0) 346 | return 7; 347 | if (errstr == NULL) 348 | return 8; 349 | return 0; 350 | } 351 | #endif /* TEST_STRTONUM */ 352 | #if TEST_SYSTRACE 353 | #include 354 | #include 355 | 356 | #include 357 | 358 | int 359 | main(void) 360 | { 361 | 362 | return(0); 363 | } 364 | #endif /* TEST_SYSTRACE */ 365 | #if TEST_ZLIB 366 | #include 367 | #include 368 | 369 | int 370 | main(void) 371 | { 372 | gzFile gz; 373 | 374 | if (NULL == (gz = gzopen("/dev/null", "w"))) 375 | return(1); 376 | gzputs(gz, "foo"); 377 | gzclose(gz); 378 | return(0); 379 | } 380 | #endif /* TEST_ZLIB */ 381 | --------------------------------------------------------------------------------