sheepy

build system (sheepy) and package manager (spm) for C
git clone https://spartatek.se/git/sheepy.git
Log | Files | Refs | README | LICENSE

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"