sheepy.h (16793B)
1 // MIT License 2 // 3 // Copyright (c) 2026 Remy Noulin 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 // 12 // The above copyright notice and this permission notice shall be included in all 13 // copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 // SOFTWARE. 22 23 struct { 24 int compileLib; 25 int compileOnly; 26 int dontCompileExe; 27 int clean; 28 int test; 29 int memcheck; 30 int libsheepyMemcheck; 31 int asan; 32 int libsheepyAsan; 33 int new; 34 int showExe; 35 int removeBuild; 36 int parallel; 37 int cclass; 38 int genTest; 39 int debugExe; 40 } sheepyParams; 41 42 // MacOS definition 43 #ifndef PATH_MAX 44 #define PATH_MAX 1024 45 #endif 46 47 48 #define H_CLASS_TEMPLATE "#pragma once\n\ 49 \n\ 50 /* Libsheepy documentation: https://spartatek.se/libsheepy/ */\n\ 51 /* Add class methods and class data where there are the TODOs (TODO)*/\n\ 52 \n\ 53 /* TODO add generics: #define amethodG(obj) (obj)->f->amethod(obj) */\n\ 54 \n\ 55 #include \"libsheepyObject.h\"\n\ 56 \n\ 57 /* Class classTemplate */\n\ 58 typ struct classTemplate classTemplatet;\n\ 59 \n\ 60 #define isOClassTemplate(obj) isOType(obj, \"classTemplate\")\n\ 61 #define isOClassTemplateG isOClassTemplate\n\ 62 \n\ 63 /* for object inheriting classTemplate, cast to classTemplate to be able to use this class functions and generics*/\n\ 64 #define cClassTemplate(self) ( (classTemplatet*) self )\n\ 65 \n\ 66 typ void (*freeClassTemplateFt) (classTemplatet *self);\n\ 67 typ void (*terminateClassTemplateFt) (classTemplatet **self);\n\ 68 typ char* (*toStringClassTemplateFt) (classTemplatet *self);\n\ 69 typ classTemplatet* (*duplicateClassTemplateFt) (classTemplatet *self);\n\ 70 typ void (*smashClassTemplateFt) (classTemplatet **self);\n\ 71 \n\ 72 /**\n\ 73 * free classTemplate\n\ 74 */\n\ 75 typ void (*finishClassTemplateFt) (classTemplatet **self);\n\ 76 \n\ 77 typ const char* (*helpClassTemplateFt) (classTemplatet *self);\n\ 78 /* TODO add function typ with pattern: functionNameClassTemplateFt */\n\ 79 \n\ 80 /**\n\ 81 * class functions\n\ 82 * allocated once for all objects\n\ 83 *\n\ 84 * freed with finalizeClassTemplate\n\ 85 */\n\ 86 \n\ 87 /**\n\ 88 * use this define in child classes and add the new function after this class functions\n\ 89 *\n\ 90 * in this define, add the methods after <finishClassTemplateFt finish;>\n\ 91 *\n\ 92 * Example:\n\ 93 * #define RINGFUNCTIONST \\n\ 94 * CLASSTEMPLATEFUNCTIONST; \\n\ 95 * setSizeRingFt setSize\n\ 96 */\n\ 97 #define CLASSTEMPLATEFUNCTIONST \\\n\ 98 helpClassTemplateFt help\n\ 99 /* TODO ADD METHODS AFTER <finishClassTemplateFt finish;> HERE */\n\ 100 \n\ 101 typ struct {\n\ 102 freeClassTemplateFt free;\n\ 103 terminateClassTemplateFt terminate;\n\ 104 toStringClassTemplateFt toString;\n\ 105 duplicateClassTemplateFt duplicate;\n\ 106 smashClassTemplateFt smash;\n\ 107 finishClassTemplateFt finish;\n\ 108 CLASSTEMPLATEFUNCTIONST;\n\ 109 } classTemplateFunctionst;\n\ 110 \n\ 111 /**\n\ 112 * class\n\ 113 */\n\ 114 struct classTemplate {\n\ 115 const char *type;\n\ 116 classTemplateFunctionst *f;\n\ 117 /* TODO add class data */\n\ 118 };\n\ 119 \n\ 120 /* classTemplate */\n\ 121 \n\ 122 /** return true when this object file was compiled with current libsheepy version */\n\ 123 #define isClassTemplateCompiledWithCurrentLisheepyVersion checkLibsheepyVersionClassTemplate(LIBSHEEPY_VERSION)\n\ 124 bool checkLibsheepyVersionClassTemplate(const char *currentLibsheepyVersion);\n\ 125 \n\ 126 #define createClassTemplate(obj) ;classTemplatet obj; initiateClassTemplate(&obj)\n\ 127 #define createAllocateClassTemplate(obj) ;classTemplatet *obj; initiateAllocateClassTemplate(&obj)\n\ 128 \n\ 129 void initiateClassTemplate(classTemplatet *self);\n\ 130 void initiateAllocateClassTemplate(classTemplatet **self);\n\ 131 void finalizeClassTemplate(void);\n\ 132 \n\ 133 /* initialize class methods, call registerMethodsClassTemplate from classes inheriting this class */\n\ 134 void registerMethodsClassTemplate(classTemplateFunctionst *f);\n\ 135 \n\ 136 classTemplatet* allocClassTemplate(void/*TODO INIT DATA */);\n\ 137 \n\ 138 /* terminate classTemplatet val when it is out of scope */\n\ 139 void cleanUpClassTemplateTerminateG(classTemplatet **val);\n\ 140 \n\ 141 /* free classTemplatet val when it is out of scope */\n\ 142 void cleanUpClassTemplateFreeG(classTemplatet *val);\n\ 143 \n\ 144 /* finish classTemplatet val when it is out of scope */\n\ 145 void cleanUpClassTemplateFinishG(classTemplatet *val);\n\ 146 \n\ 147 /**\n\ 148 * declare pointer name with Type classTemplatet and terminate name when it is out of scope\n\ 149 */\n\ 150 #define cleanClassTemplateP(name) classTemplatet *name CLEANUP(cleanUpClassTemplateTerminateG)\n\ 151 \n\ 152 /**\n\ 153 * allocate ClassTemplate (pointer) and clean up when it is out of scope\n\ 154 */\n\ 155 #define cleanAllocateClassTemplate(obj) ;cleanClassTemplateP(obj); initiateAllocateClassTemplate(&obj)\n\ 156 \n\ 157 /**\n\ 158 * declare local object name with Type classTemplatet and free name when it is out of scope\n\ 159 */\n\ 160 #define cleanClassTemplate(name) classTemplatet name CLEANUP(cleanUpClassTemplateFreeG); initiateClassTemplate(&name)\n\ 161 \n\ 162 /**\n\ 163 * declare pointer name with Type classTemplatet and finish name when it is out of scope\n\ 164 */\n\ 165 #define cleanFinishClassTemplateP(name) classTemplatet *name CLEANUP(cleanUpClassTemplateFinishG)\n\ 166 \n\ 167 /* end class classTemplate*/\n\ 168 // vim: set expandtab ts=2 sw=2:" 169 170 171 172 #define C_CLASS_TEMPLATE "\n\ 173 \n\ 174 /* Libsheepy documentation: https://spartatek.se/libsheepy/ */\n\ 175 /* Add class methods and modify the base functions (free, duplicate, ...) where there are the TODOs (TODO)*/\n\ 176 \n\ 177 #include \"libsheepyObject.h\"\n\ 178 #include \"classTemplate.h\"\n\ 179 #include \"classTemplateInternal.h\"\n\ 180 \n\ 181 void initiateClassTemplate(classTemplatet *self);\n\ 182 void registerMethodsClassTemplate(classTemplateFunctionst *f);\n\ 183 void initiateAllocateClassTemplate(classTemplatet **self);\n\ 184 void finalizeClassTemplate(void);\n\ 185 classTemplatet* allocClassTemplate(void);\n\ 186 local void freeClassTemplate(classTemplatet *self);\n\ 187 local void terminateClassTemplate(classTemplatet **self);\n\ 188 local char* toStringClassTemplate(classTemplatet *self);\n\ 189 local classTemplatet* duplicateClassTemplate(classTemplatet *self);\n\ 190 local void smashClassTemplate(classTemplatet **self);\n\ 191 local void finishClassTemplate(classTemplatet **self);\n\ 192 local const char* helpClassTemplate(classTemplatet *self);\n\ 193 /* TODO add prototypes */\n\ 194 \n\ 195 /* enable/disable logging */\n\ 196 /* #undef pLog */\n\ 197 /* #define pLog(...) */\n\ 198 \n\ 199 bool checkLibsheepyVersionClassTemplate(const char *currentLibsheepyVersion) {\n\ 200 return eqG(currentLibsheepyVersion, LIBSHEEPY_VERSION);\n\ 201 }\n\ 202 \n\ 203 void initiateClassTemplate(classTemplatet *self) {\n\ 204 \n\ 205 self->type = \"classTemplate\";\n\ 206 if (!classTemplateF) {\n\ 207 isError(classTemplateF, malloc(sizeof(classTemplateFunctionst))) {\n\ 208 self->f = NULL;\n\ 209 return;\n\ 210 }\n\ 211 registerMethodsClassTemplate(classTemplateF);\n\ 212 pErrorNot0(atexit(finalizeClassTemplate));\n\ 213 }\n\ 214 self->f = classTemplateF;\n\ 215 /* TODO Initialize object data */\n\ 216 }\n\ 217 \n\ 218 void registerMethodsClassTemplate(classTemplateFunctionst *f) {\n\ 219 \n\ 220 f->free = freeClassTemplate;\n\ 221 f->terminate = terminateClassTemplate;\n\ 222 f->toString = toStringClassTemplate;\n\ 223 f->duplicate = duplicateClassTemplate;\n\ 224 f->smash = smashClassTemplate;\n\ 225 f->finish = finishClassTemplate;\n\ 226 f->help = helpClassTemplate;\n\ 227 /* TODO add class functions */\n\ 228 }\n\ 229 \n\ 230 void initiateAllocateClassTemplate(classTemplatet **self) {\n\ 231 \n\ 232 if (self) {\n\ 233 isError(*self, malloc(sizeof(classTemplatet))) return;\n\ 234 if (*self) {\n\ 235 initiateClassTemplate(*self);\n\ 236 if (!(*self)->f) {\n\ 237 finishClassTemplate(self);\n\ 238 }\n\ 239 }\n\ 240 }\n\ 241 }\n\ 242 \n\ 243 void finalizeClassTemplate(void) {\n\ 244 \n\ 245 if (classTemplateF) {\n\ 246 freen(classTemplateF);\n\ 247 }\n\ 248 }\n\ 249 \n\ 250 classTemplatet* allocClassTemplate(void/* TODO change parameter to get the initial data for the object */) {\n\ 251 classTemplatet *r = NULL;\n\ 252 \n\ 253 initiateAllocateClassTemplate(&r);\n\ 254 if (!r) return NULL;\n\ 255 /* TODO copy data given in parameter to the object */\n\ 256 ret r;\n\ 257 }\n\ 258 \n\ 259 \n\ 260 void cleanUpClassTemplateTerminateG(classTemplatet **val) {\n\ 261 terminateO(*val);\n\ 262 }\n\ 263 \n\ 264 void cleanUpClassTemplateFreeG(classTemplatet *val) {\n\ 265 freeO(val);\n\ 266 }\n\ 267 \n\ 268 void cleanUpClassTemplateFinishG(classTemplatet *val) {\n\ 269 finishO(val);\n\ 270 }\n\ 271 \n\ 272 local void freeClassTemplate(classTemplatet *self) {\n\ 273 \n\ 274 /* TODO free internal data (not the structure holding the function pointers) */\n\ 275 }\n\ 276 \n\ 277 local void terminateClassTemplate(classTemplatet **self) {\n\ 278 \n\ 279 freeClassTemplate(*self);\n\ 280 finishClassTemplate(self);\n\ 281 }\n\ 282 \n\ 283 \n\ 284 local char* toStringClassTemplate(classTemplatet *self) {\n\ 285 \n\ 286 /* TODO convert object data to string */\n\ 287 ret strdup(\"TODO - classTemplate\");\n\ 288 }\n\ 289 \n\ 290 local classTemplatet* duplicateClassTemplate(classTemplatet *self) {\n\ 291 \n\ 292 createAllocateClassTemplate(dup);\n\ 293 if (!dup) return NULL;\n\ 294 /* TODO COPY data */\n\ 295 ret dup;\n\ 296 }\n\ 297 \n\ 298 local void smashClassTemplate(classTemplatet **self) {\n\ 299 \n\ 300 finishClassTemplate(self);\n\ 301 }\n\ 302 \n\ 303 #if NFreeStackCheck\n\ 304 local void finishClassTemplate(classTemplatet **self) {\n\ 305 \n\ 306 register u64 rsp asm(\"rsp\");\n\ 307 if ((u64)*self > rsp) {\n\ 308 logW(\"Probably trying to free a classTemplate on stack: \"BLD PRIx64 RST\" sp: \"BLD PRIx64 RST, *self, rsp);\n\ 309 logBtrace;\n\ 310 }\n\ 311 else {\n\ 312 freen(*self);\n\ 313 }\n\ 314 }\n\ 315 #else\n\ 316 // #if NFreeStackCheck\n\ 317 local void finishClassTemplate(classTemplatet **self) {\n\ 318 \n\ 319 freen(*self);\n\ 320 }\n\ 321 #endif\n\ 322 // #if NFreeStackCheck\n\ 323 \n\ 324 local const char* helpClassTemplate(classTemplatet UNUSED *self) {\n\ 325 ret \"TODO - classTemplate help\";\n\ 326 }\n\ 327 /* TODO add method implementations */\n\ 328 // vim: set expandtab ts=2 sw=2:" 329 330 331 #define INTERNAL_H_CLASS_TEMPLATE "#pragma once\n\ 332 \n\ 333 static classTemplateFunctionst *classTemplateF = NULL;\n\ 334 \n\ 335 /* TODO declare structs for private data and add a void pointer to the private data in the class declaration */\n\ 336 \n\ 337 // vim: set expandtab ts=2 sw=2:" 338 339 #define C_TEST_TEMPLATE ""\ 340 "#! /usr/bin/env sheepy\n"\ 341 "/* or direct path to sheepy: #! /usr/local/bin/sheepy */\n"\ 342 "\n"\ 343 "/** \\file\n"\ 344 " * Each test must be independent and self contained\n"\ 345 " */\n"\ 346 "\n"\ 347 "#include <check.h>\n"\ 348 "\n"\ 349 "//START MEM TEST ANCHOR\n"\ 350 "\n"\ 351 "#include \"libsheepyObject.h\"\n"\ 352 "//TODO Add relevant includes\n"\ 353 "\n"\ 354 "int argc; char **argv;\n"\ 355 "\n"\ 356 "// TODO Declare an object of the class under test\n"\ 357 "\n"\ 358 "\n"\ 359 "START_TEST(basetT)\n"\ 360 "\n"\ 361 " // STEPS\n"\ 362 " // init\n"\ 363 " // init allocate\n"\ 364 " // terminate\n"\ 365 " // allocate\n"\ 366 " // string\n"\ 367 " // duplicate\n"\ 368 "\n"\ 369 " // init\n"\ 370 " //TODO initiate();\n"\ 371 " //TODO freeO();\n"\ 372 "\n"\ 373 " // init allocate\n"\ 374 " //TODO declare object pointer\n"\ 375 " //TODO initiateAllocate();\n"\ 376 "\n"\ 377 " // terminate\n"\ 378 " //TODO terminateO();\n"\ 379 "\n"\ 380 " // allocate\n"\ 381 " //TODO = alloc();\n"\ 382 "\n"\ 383 " // string\n"\ 384 " //TODO char *s = toStringO();\n"\ 385 "\n"\ 386 " //TODO ck_assert_str_eq(s, \"TODO - \");\n"\ 387 " //TODO free(s);\n"\ 388 "\n"\ 389 " // duplicate\n"\ 390 " //TODO class *oDup = duplicateO();\n"\ 391 " //TODO terminateO(oDup);\n"\ 392 " //TODO terminateO();\n"\ 393 "\n"\ 394 "END_TEST\n"\ 395 "\n"\ 396 "//TODO add more tests\n"\ 397 "\n"\ 398 "Suite * testTemplateSuite(void) {\n"\ 399 " Suite *s;\n"\ 400 " TCase *tc_core;\n"\ 401 "\n"\ 402 " s = suite_create(\"testTemplate\");\n"\ 403 "\n"\ 404 " /* Core test case */\n"\ 405 " tc_core = tcase_create(\"Core\");\n"\ 406 "\n"\ 407 "\n"\ 408 " tcase_add_test(tc_core, basetT);\n"\ 409 "\n"\ 410 " //TODO register tests\n"\ 411 "\n"\ 412 " suite_add_tcase(s, tc_core);\n"\ 413 "\n"\ 414 " ret s;\n"\ 415 "}\n"\ 416 "\n"\ 417 "int main(int ARGC, char** ARGV) {\n"\ 418 "\n"\ 419 " argc = ARGC; argv = ARGV;\n"\ 420 "\n"\ 421 " //dont initialize libsheepy, it conflicts with libcheck - initLibsheepy(ARGV[0]);\n"\ 422 " setLogMode(LOG_FUNC);\n"\ 423 "\n"\ 424 " int number_failed;\n"\ 425 " Suite *s;\n"\ 426 " SRunner *sr;\n"\ 427 "\n"\ 428 " s = testTemplateSuite();\n"\ 429 " sr = srunner_create(s);\n"\ 430 "\n"\ 431 " srunner_run_all(sr, CK_NORMAL);\n"\ 432 " number_failed = srunner_ntests_failed(sr);\n"\ 433 " srunner_free(sr);\n"\ 434 "\n"\ 435 " exit((number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE);\n"\ 436 "}\n"\ 437 "// vim: set expandtab ts=2 sw=2:" 438 439 #define MEMTEST_C_TEMPLATE_NAME "memTest.c.template" 440 #define MEMTEST_C_TEMPLATE "\ 441 #include <stdlib.h>\n\ 442 #include <stdio.h>\n\ 443 #include <string.h>\n\ 444 \n\ 445 #define ck_assert_str_eq(a,b) a;b;\n\ 446 #define ck_assert_str_ne(a,b) a;b;\n\ 447 #define ck_assert_ptr_eq(a,b) a;b;\n\ 448 #define ck_assert_ptr_ne(a,b) a;b;\n\ 449 #define ck_assert_uint_eq(a,b) a;b;\n\ 450 #define ck_assert_uint_ne(a,b) a;b;\n\ 451 #define ck_assert_int_eq(a,b) a;b;\n\ 452 #define ck_assert_int_ne(a,b) a;b;\n\ 453 #define ck_assert(a) a;\n\ 454 \n\ 455 __tests\n\ 456 \n\ 457 int main(int n, char**v) {\n\ 458 \n\ 459 initLibsheepy(v[0]);\n\ 460 setLogMode(LOG_FUNC);\n\ 461 \n\ 462 __calls\n\ 463 }\ 464 " 465 466 #define RUNMEMTEST_TEMPLATE_NAME "runMemtest.c" 467 #define RUNMEMTEST_TEMPLATE ""\ 468 "#! /usr/bin/env sheepy\n"\ 469 "/* or direct path to sheepy: #! /usr/local/bin/sheepy */\n"\ 470 "\n"\ 471 "//\n"\ 472 "// in unit test file, add line:\n"\ 473 "// //START MEM TEST ANCHOR\n"\ 474 "//\n"\ 475 "//\n"\ 476 "\n"\ 477 "#include \"libsheepyObject.h\"\n"\ 478 "\n"\ 479 "#include <stdlib.h>\n"\ 480 "#include <stdio.h>\n"\ 481 "\n"\ 482 "int argc; char **argv;\n"\ 483 "\n"\ 484 "enum {START, TEST, TESTEND, SEARCH};\n"\ 485 "\n"\ 486 "int main(int ARGC, char** ARGV) {\n"\ 487 " char **list = NULL;\n"\ 488 " char **tests = NULL;\n"\ 489 " char **functions = NULL;\n"\ 490 " char **result = NULL;\n"\ 491 "\n"\ 492 " argc = ARGC; argv = ARGV;\n"\ 493 "\n"\ 494 " initLibsheepy(argv[0]);\n"\ 495 "\n"\ 496 " if (argc < 4) {\n"\ 497 " printf(\"Give 3 parameters: unit test c file, template file and output file\");\n"\ 498 " printf(\"\\n\");\n"\ 499 " XFAILURE;\n"\ 500 " }\n"\ 501 "\n"\ 502 " // get function list from argv[1]\n"\ 503 " list = readText(argv[1]);\n"\ 504 "\n"\ 505 " int status = START;;\n"\ 506 " forEachCharP(list, e) {\n"\ 507 " if (status != START) {\n"\ 508 " if (findS(*e, \"#include\")) {\n"\ 509 " listPushS(&tests, *e);\n"\ 510 " continue;\n"\ 511 " }\n"\ 512 " if (findS(*e, \"START_TEST(\")) {\n"\ 513 " char **l = split(*e, \"(\");\n"\ 514 " char **l2 = split(l[1], \")\");;\n"\ 515 " iAppendS(&l2[0], \"();\");\n"\ 516 " listPushS(&functions, l2[0]);\n"\ 517 " listFreeManyS(l,l2);\n"\ 518 " iReplaceManyS(e, \"START_TEST(\", \"void \", \")\", \"(void) {\");\n"\ 519 " status = TEST;\n"\ 520 " }\n"\ 521 " if (findS(*e, \"END_TEST\")) {\n"\ 522 " iReplaceS(e, \"END_TEST\", \"}\",0);\n"\ 523 " status = TESTEND;\n"\ 524 " }\n"\ 525 " if (status == SEARCH) {\n"\ 526 " char *s = sliceS(*e, 0, 5);;\n"\ 527 " if (strEq(s, \"Suite\")) {\n"\ 528 " break;\n"\ 529 " }\n"\ 530 " free(s);\n"\ 531 " listPushS(&tests, *e);\n"\ 532 " continue;\n"\ 533 " }\n"\ 534 " if ((status == TEST) || (status == TESTEND)) {\n"\ 535 " listPushS(&tests, *e);\n"\ 536 " if (status == TESTEND) {\n"\ 537 " status = SEARCH;\n"\ 538 " }\n"\ 539 " }\n"\ 540 " }\n"\ 541 " else if (findS(*e, \"START MEM TEST ANCHOR\")) {\n"\ 542 " status = SEARCH;\n"\ 543 " }\n"\ 544 " }\n"\ 545 "\n"\ 546 " listFreeS(list);\n"\ 547 "\n"\ 548 " //listPrintS(tests);\n"\ 549 " //listPrintS(functions);\n"\ 550 "\n"\ 551 " // read template\n"\ 552 " char **template = readText(argv[2]);\n"\ 553 "\n"\ 554 " // process template\n"\ 555 " forEachCharP(template, e) {\n"\ 556 " if (findS(*e, \"__tests\")) {\n"\ 557 " listAppendS(&result, tests);\n"\ 558 " }\n"\ 559 " else if (findS(*e, \"__calls\")) {\n"\ 560 " listAppendS(&result, functions);\n"\ 561 " }\n"\ 562 " else {\n"\ 563 " listPushS(&result, *e);\n"\ 564 " }\n"\ 565 " }\n"\ 566 "\n"\ 567 " // save result\n"\ 568 " putsG(argv[3]);\n"\ 569 " writeText(argv[3], result);\n"\ 570 "\n"\ 571 " listFreeManyS(tests, functions, result, template);\n"\ 572 "\n"\ 573 " XSUCCESS;\n"\ 574 "}\n"\ 575 "// vim: set expandtab ts=2 sw=2:" 576 577 #define MEMCHECK_SH_TEMPLATE "\ 578 ./runMemtest.c testBin memTest.c.template memcheckBin\n\ 579 spm memcheck" 580 581 #define ASAN_SH_TEMPLATE "\ 582 ./runMemtest.c testBin memTest.c.template asanBin\n\ 583 spm asan"