Correct test case result

Correct test case result

// TESTING: copysign
// TESTING: fabs
// TESTING: isfinite
// TESTING: isinf
// TESTING: isnan
// TESTING: isnormal
// TESTING: signbit
// TESTING: ilogb
// TESTING: ldexp

#if __clang_major__ == 3 && __clang_minor__ < 4
typedef const char* string;     /* for backward compatibility */
#else
typedef constant char* string;
#endif

#define IMPLEMENT_BODY_V(NAME, BODY, SIZE,                              \
                         VTYPE, STYPE, ITYPE, SITYPE, JTYPE, SJTYPE)    \
  void NAME##_##VTYPE()                                                 \
  {                                                                     \
    typedef VTYPE vtype;                                                \
    typedef STYPE stype;                                                \
    typedef ITYPE itype;                                                \
    typedef SITYPE sitype;                                              \
    typedef JTYPE jtype;                                                \
    typedef SJTYPE sjtype;                                              \
    string const typename = #VTYPE;                                     \
    const int vecsize = SIZE;                                           \
    BODY;                                                               \
  }
#define DEFINE_BODY_V(NAME, EXPR)                                       \
  IMPLEMENT_BODY_V(NAME, EXPR,  1, float   , float , int  , int, int   , int ) \
  IMPLEMENT_BODY_V(NAME, EXPR,  2, float2  , float , int2 , int, int2  , int ) \
  IMPLEMENT_BODY_V(NAME, EXPR,  3, float3  , float , int3 , int, int3  , int ) \
  IMPLEMENT_BODY_V(NAME, EXPR,  4, float4  , float , int4 , int, int4  , int ) \
  IMPLEMENT_BODY_V(NAME, EXPR,  8, float8  , float , int8 , int, int8  , int ) \
  IMPLEMENT_BODY_V(NAME, EXPR, 16, float16 , float , int16, int, int16 , int ) \
  __IF_FP64(                                                            \
  IMPLEMENT_BODY_V(NAME, EXPR,  1, double  , double, int  , int, long  , long) \
  IMPLEMENT_BODY_V(NAME, EXPR,  2, double2 , double, int2 , int, long2 , long) \
  IMPLEMENT_BODY_V(NAME, EXPR,  3, double3 , double, int3 , int, long3 , long) \
  IMPLEMENT_BODY_V(NAME, EXPR,  4, double4 , double, int4 , int, long4 , long) \
  IMPLEMENT_BODY_V(NAME, EXPR,  8, double8 , double, int8 , int, long8 , long) \
  IMPLEMENT_BODY_V(NAME, EXPR, 16, double16, double, int16, int, long16, long))

#define CALL_FUNC_V(NAME)                       \
  NAME##_float   ();                            \
  NAME##_float2  ();                            \
  NAME##_float3  ();                            \
  NAME##_float4  ();                            \
  NAME##_float8  ();                            \
  NAME##_float16 ();                            \
  __IF_FP64(                                    \
  NAME##_double  ();                            \
  NAME##_double2 ();                            \
  NAME##_double3 ();                            \
  NAME##_double4 ();                            \
  NAME##_double8 ();                            \
  NAME##_double16();)

#if __has_extension(c_generic_selections)
 #ifdef cl_khr_fp64
 # define is_floating(T) _Generic((T)0, float: 1, double: 1, default: 0)
 #else
 # define is_floating(T) _Generic((T)0, float: 1, default: 0)
 #endif
#else
# define is_floating(T) ((T)0.1f > (T)0.0f)
#endif
#define is_signed(T)   ((T)-1 < (T)+1)
#define count_bits(T)  (CHAR_BIT * sizeof(T))

#define ISNAN(x) (isnan(x) || as_int((float)(x)) == as_int((float)NAN))
#define ISEQ(x, y) (ISNAN(x) == ISNAN(y) && (ISNAN(x) || (x)==(y)))

DEFINE_BODY_V
(test_fabs,
 ({
   _CL_STATIC_ASSERT(stype, is_floating(stype));
   float const values[] = {
     0.0f,
     0.1f,
     0.9f,
     1.0f,
     1.1f,
     10.0f,
     1000000.0f,
     1000000000000.0f,
     MAXFLOAT,
     HUGE_VALF,
     INFINITY,
     NAN,
     FLT_MAX,
     FLT_MIN,
     FLT_EPSILON,
   };
   int const nvalues = sizeof(values) / sizeof(*values);
   int ninputs = 1;
#ifdef cl_khr_fp64
   double const dvalues[] = {
     0.0,
     0.1,
     0.9,
     1.0,
     1.1,
     10.0,
     1000000.0,
     1000000000000.0,
     1000000000000000000000000.0,
     HUGE_VAL,
     INFINITY,
     NAN,
     DBL_MAX,
     DBL_MIN,
     DBL_EPSILON,
   };
   int const ndvalues = sizeof(dvalues) / sizeof(*dvalues);
   ++ninputs;
#endif

   for (int input=0; input<ninputs; ++input) {
     for (int iter=0; iter<nvalues; ++iter) {
       for (int sign=-1; sign<=+1; sign+=2) {
         typedef union {
           vtype v;
           stype s[16];
         } Tvec;
         Tvec val, good, val2;
         for (int n=0; n<vecsize; ++n) {
           if (input==0) {
             val.s[n]  = sign * values[(iter+n) % nvalues];
             good.s[n] =        values[(iter+n) % nvalues];
             val2.s[n] =        values[(iter+n+1) % nvalues];
           } else {
#ifdef cl_khr_fp64
             val.s[n]  = sign * dvalues[(iter+n) % ndvalues];
             good.s[n] =        dvalues[(iter+n) % ndvalues];
             val2.s[n] =        dvalues[(iter+n+1) % ndvalues];
#endif
           }
         }
         Tvec res;
         bool equal;
         typedef union {
           stype  s;
           sjtype sj;
         } S;
         typedef union {
           itype  v;
           sitype s[16];
         } Ivec;
         typedef union {
           jtype  v;
           sjtype s[16];
         } Jvec;
         /* fabs */
         res.v = fabs(val.v);
         equal = true;
         for (int n=0; n<vecsize; ++n) {
           S r, g;
           r.s = res.s[n];
           g.s = good.s[n];
           equal = equal && (ISNAN(val.s[n]) || r.sj == g.sj);
         }
         if (!equal) {
           for (int n=0; n<vecsize; ++n) {
             printf("FAIL: fabs type=%s val=%.17g res=%.17g good=%.17g\n",
                    typename, val.s[n], res.s[n], good.s[n]);
           }
           return;
         }
         /* signbit */
         Jvec jres;
         jres.v = signbit(val.v);
         equal = true;
         for (int n=0; n<vecsize; ++n) {
           equal = equal &&
             (ISNAN(val.s[n]) ||
              jres.s[n] == (sign>0 ? 0 : vecsize==1 ? +1 : -1));
         }
         if (!equal) {
           for (int n=0; n<vecsize; ++n) {
             printf("FAIL: signbit type=%s val=%.17g res=%d good=%d\n",
                    typename, val.s[n], (int)jres.s[n],
                    (sign>0 ? 0 : vecsize==1 ? +1 : -1));
           }
           return;
         }
         /* isfinite */
         jres.v = isfinite(val.v);
         equal = true;
         for (int n=0; n<vecsize; ++n) {
           equal = equal &&
             jres.s[n] == (isfinite(val.s[n]) ? (vecsize==1 ? +1 : -1) : 0);
         }
         if (!equal) {
           for (int n=0; n<vecsize; ++n) {
             printf("FAIL: isfinite type=%s val=%.17g res=%d good=%d\n",
                    typename, val.s[n], (int)jres.s[n],
                    (isfinite(val.s[n]) ? (vecsize==1 ? +1 : -1) : 0));
           }
           return;
         }
         /* isinf */
         jres.v = isinf(val.v);
         equal = true;
         for (int n=0; n<vecsize; ++n) {
           equal = equal &&
             jres.s[n] == (isinf(val.s[n]) ? (vecsize==1 ? +1 : -1) : 0);
         }
         if (!equal) {
           for (int n=0; n<vecsize; ++n) {
             printf("FAIL: isinf type=%s val=%.17g res=%d good=%d\n",
                    typename, val.s[n], (int)jres.s[n],
                    (isinf(val.s[n]) ? (vecsize==1 ? +1 : -1) : 0));
           }
           return;
         }
         /* isnan */
         jres.v = isnan(val.v);
         equal = true;
         for (int n=0; n<vecsize; ++n) {
           equal = equal &&
             jres.s[n] == (isnan(val.s[n]) ? (vecsize==1 ? +1 : -1) : 0);
         }
         if (!equal) {
           for (int n=0; n<vecsize; ++n) {
             printf("FAIL: isnan type=%s val=%.17g res=%d good=%d\n",
                    typename, val.s[n], (int)jres.s[n],
                    (isnan(val.s[n]) ? (vecsize==1 ? +1 : -1) : 0));
           }
           return;
         }
         /* isnormal */
         jres.v = isnormal(val.v);
         equal = true;
         for (int n=0; n<vecsize; ++n) {
           equal = equal &&
             jres.s[n] == (isnormal(val.s[n]) ? (vecsize==1 ? +1 : -1) : 0);
         }
         if (!equal) {
           for (int n=0; n<vecsize; ++n) {
             printf("FAIL: isnormal type=%s val=%.17g res=%d good=%d\n",
                    typename, val.s[n], (int)jres.s[n],
                    (isnormal(val.s[n]) ? (vecsize==1 ? +1 : -1) : 0));
           }
           return;
         }
         /* copysign */
         for (int sign2=-1; sign2<=+1; sign2+=2) {
           res.v = copysign(val.v, (stype)sign2*val2.v);
           equal = true;
           for (int n=0; n<vecsize; ++n) {
             S r, g;
             r.s = res.s[n];
             g.s = sign2*good.s[n];
             equal = equal &&
               (ISNAN(val.s[n]) || ISNAN(val2.s[n]) || r.sj == g.sj);
           }
           if (!equal) {
             for (int n=0; n<vecsize; ++n) {
               printf("FAIL: copysign type=%s val=%.17g sign=%.17g res=%.17g good=%.17g\n",
                      typename, val.s[n], sign2*val2.s[n], res.s[n], good.s[n]);
             }
             return;
           }
         }
         /* ilogb */
         Ivec ires;
         ires.v = ilogb(val.v);
         Ivec igoodres;
         equal = true;
         for (int n=0; n<vecsize; ++n) {
           if (ISNAN(val.s[n])) {
             igoodres.s[n] = FP_ILOGBNAN;
           } else if (val.s[n] == (stype)0) {
             igoodres.s[n] = FP_ILOGB0;
           } else if (isinf(val.s[n])) {
             igoodres.s[n] = INT_MAX;
           } else {
             // We round down to "correct" for inaccuracies in log2
             // We divide by 2 since log2 is wrong for large inputs
             igoodres.s[n] = 1+rint(floor(0.999999f*log2(0.5*fabs(val.s[n]))));
           }
           equal = equal && ires.s[n] == igoodres.s[n];
         }
         if (!equal) {
           for (int n=0; n<vecsize; ++n) {
             printf("FAIL: ilogb type=%s val=%.17g res=%d good=%d\n",
                    typename, val.s[n], (int)ires.s[n], (int)igoodres.s[n]);
           }
           return;
         }
         /* ldexp */
         Ivec ival2;
         ival2.v = (itype)4;
         res.v = ldexp(val.v, ival2.v);
         Tvec goodres;
         equal = true;
         for (int n=0; n<vecsize; ++n) {
           if (ISNAN(val.s[n])) {
             goodres.s[n] = NAN;
           } else if (val.s[n] == (stype)0) {
             goodres.s[n] = val.s[n];
           } else if (isinf(val.s[n])) {
             goodres.s[n] = val.s[n];
           } else {
             goodres.s[n] = val.s[n] * pow(2.0, ival2.s[n]);
           }
           equal = equal && ISEQ(res.s[n], goodres.s[n]);
         }
         if (!equal) {
           for (int n=0; n<vecsize; ++n) {
             printf("FAIL: ldexp type=%s val=%.17g val2=%d res=%.17g good=%.17g\n",
                    typename, val.s[n], (int)ival2.s[n], res.s[n], goodres.s[n]);
           }
           return;
         }
       }
     }
   }
 })
 )

kernel void test_fabs()
{
  CALL_FUNC_V(test_fabs)
}

// TESTING: copysign
// TESTING: fabs
// TESTING: isfinite
// TESTING: isinf
// TESTING: isnan
// TESTING: isnormal
// TESTING: signbit
// TESTING: ilogb
// TESTING: ldexp

#if __clang_major__ == 3 && __clang_minor__ < 4
typedef const char* string;     /* for backward compatibility */
#else
typedef constant char* string;
#endif

#define IMPLEMENT_BODY_V(NAME, BODY, SIZE,                              \
                         VTYPE, STYPE, ITYPE, SITYPE, JTYPE, SJTYPE)    \
  void NAME##_##VTYPE()                                                 \
  {                                                                     \
    typedef VTYPE vtype;                                                \
    typedef STYPE stype;                                                \
    typedef ITYPE itype;                                                \
    typedef SITYPE sitype;                                              \
    typedef JTYPE jtype;                                                \
    typedef SJTYPE sjtype;                                              \
    string const typename = #VTYPE;                                     \
    const int vecsize = SIZE;                                           \
    BODY;                                                               \
  }
#define DEFINE_BODY_V(NAME, EXPR)                                       \
  IMPLEMENT_BODY_V(NAME, EXPR,  1, float   , float , int  , int, int   , int ) \
  IMPLEMENT_BODY_V(NAME, EXPR,  2, float2  , float , int2 , int, int2  , int ) \
  IMPLEMENT_BODY_V(NAME, EXPR,  3, float3  , float , int3 , int, int3  , int ) \
  IMPLEMENT_BODY_V(NAME, EXPR,  4, float4  , float , int4 , int, int4  , int ) \
  IMPLEMENT_BODY_V(NAME, EXPR,  8, float8  , float , int8 , int, int8  , int ) \
  IMPLEMENT_BODY_V(NAME, EXPR, 16, float16 , float , int16, int, int16 , int ) \
  __IF_FP64(                                                            \
  IMPLEMENT_BODY_V(NAME, EXPR,  1, double  , double, int  , int, long  , long) \
  IMPLEMENT_BODY_V(NAME, EXPR,  2, double2 , double, int2 , int, long2 , long) \
  IMPLEMENT_BODY_V(NAME, EXPR,  3, double3 , double, int3 , int, long3 , long) \
  IMPLEMENT_BODY_V(NAME, EXPR,  4, double4 , double, int4 , int, long4 , long) \
  IMPLEMENT_BODY_V(NAME, EXPR,  8, double8 , double, int8 , int, long8 , long) \
  IMPLEMENT_BODY_V(NAME, EXPR, 16, double16, double, int16, int, long16, long))

#define CALL_FUNC_V(NAME)                       \
  NAME##_float   ();                            \
  NAME##_float2  ();                            \
  NAME##_float3  ();                            \
  NAME##_float4  ();                            \
  NAME##_float8  ();                            \
  NAME##_float16 ();                            \
  __IF_FP64(                                    \
  NAME##_double  ();                            \
  NAME##_double2 ();                            \
  NAME##_double3 ();                            \
  NAME##_double4 ();                            \
  NAME##_double8 ();                            \
  NAME##_double16();)

#if __has_extension(c_generic_selections)
 #ifdef cl_khr_fp64
 # define is_floating(T) _Generic((T)0, float: 1, double: 1, default: 0)
 #else
 # define is_floating(T) _Generic((T)0, float: 1, default: 0)
 #endif
#else
# define is_floating(T) ((T)0.1f > (T)0.0f)
#endif
#define is_signed(T)   ((T)-1 < (T)+1)
#define count_bits(T)  (CHAR_BIT * sizeof(T))

#define ISNAN(x) (isnan(x) || as_int((float)(x)) == as_int((float)NAN))
#define ISEQ(x, y) (ISNAN(x) == ISNAN(y) && (ISNAN(x) || (x)==(y)))

DEFINE_BODY_V
(test_fabs,
 ({
   _CL_STATIC_ASSERT(stype, is_floating(stype));
   float const values[] = {
     0.0f,
     0.1f,
     0.9f,
     1.0f,
     1.1f,
     10.0f,
     1000000.0f,
     1000000000000.0f,
     MAXFLOAT,
     HUGE_VALF,
     INFINITY,
     NAN,
     FLT_MAX,
     FLT_MIN,
     FLT_EPSILON,
   };
   int const nvalues = sizeof(values) / sizeof(*values);
   int ninputs = 1;
#ifdef cl_khr_fp64
   double const dvalues[] = {
     0.0,
     0.1,
     0.9,
     1.0,
     1.1,
     10.0,
     1000000.0,
     1000000000000.0,
     1000000000000000000000000.0,
     HUGE_VAL,
     INFINITY,
     NAN,
     DBL_MAX,
     DBL_MIN,
     DBL_EPSILON,
   };
   int const ndvalues = sizeof(dvalues) / sizeof(*dvalues);
   ++ninputs;
#endif

   for (int input=0; input<ninputs; ++input) {
     for (int iter=0; iter<nvalues; ++iter) {
       for (int sign=-1; sign<=+1; sign+=2) {
         typedef union {
           vtype v;
           stype s[16];
         } Tvec;
         Tvec val, good, val2;
         for (int n=0; n<vecsize; ++n) {
           if (input==0) {
             val.s[n]  = sign * values[(iter+n) % nvalues];
             good.s[n] =        values[(iter+n) % nvalues];
             val2.s[n] =        values[(iter+n+1) % nvalues];
           } else {
#ifdef cl_khr_fp64
             val.s[n]  = sign * dvalues[(iter+n) % ndvalues];
             good.s[n] =        dvalues[(iter+n) % ndvalues];
             val2.s[n] =        dvalues[(iter+n+1) % ndvalues];
#endif
           }
         }
         Tvec res;
         bool equal;
         typedef union {
           stype  s;
           sjtype sj;
         } S;
         typedef union {
           itype  v;
           sitype s[16];
         } Ivec;
         typedef union {
           jtype  v;
           sjtype s[16];
         } Jvec;
         /* fabs */
         res.v = fabs(val.v);
         equal = true;
         for (int n=0; n<vecsize; ++n) {
           S r, g;
           r.s = res.s[n];
           g.s = good.s[n];
           equal = equal && (ISNAN(val.s[n]) || r.sj == g.sj);
         }
         if (!equal) {
           for (int n=0; n<vecsize; ++n) {
             printf("FAIL: fabs type=%s val=%.17g res=%.17g good=%.17g\n",
                    typename, val.s[n], res.s[n], good.s[n]);
           }
           return;
         }
         /* signbit */
         Jvec jres;
         jres.v = signbit(val.v);
         equal = true;
         for (int n=0; n<vecsize; ++n) {
           equal = equal &&
             (ISNAN(val.s[n]) ||
              jres.s[n] == (sign>0 ? 0 : vecsize==1 ? +1 : -1));
         }
         if (!equal) {
           for (int n=0; n<vecsize; ++n) {
             printf("FAIL: signbit type=%s val=%.17g res=%d good=%d\n",
                    typename, val.s[n], (int)jres.s[n],
                    (sign>0 ? 0 : vecsize==1 ? +1 : -1));
           }
           return;
         }
         /* isfinite */
         jres.v = isfinite(val.v);
         equal = true;
         for (int n=0; n<vecsize; ++n) {
           equal = equal &&
             jres.s[n] == (isfinite(val.s[n]) ? (vecsize==1 ? +1 : -1) : 0);
         }
         if (!equal) {
           for (int n=0; n<vecsize; ++n) {
             printf("FAIL: isfinite type=%s val=%.17g res=%d good=%d\n",
                    typename, val.s[n], (int)jres.s[n],
                    (isfinite(val.s[n]) ? (vecsize==1 ? +1 : -1) : 0));
           }
           return;
         }
         /* isinf */
         jres.v = isinf(val.v);
         equal = true;
         for (int n=0; n<vecsize; ++n) {
           equal = equal &&
             jres.s[n] == (isinf(val.s[n]) ? (vecsize==1 ? +1 : -1) : 0);
         }
         if (!equal) {
           for (int n=0; n<vecsize; ++n) {
             printf("FAIL: isinf type=%s val=%.17g res=%d good=%d\n",
                    typename, val.s[n], (int)jres.s[n],
                    (isinf(val.s[n]) ? (vecsize==1 ? +1 : -1) : 0));
           }
           return;
         }
         /* isnan */
         jres.v = isnan(val.v);
         equal = true;
         for (int n=0; n<vecsize; ++n) {
           equal = equal &&
             jres.s[n] == (isnan(val.s[n]) ? (vecsize==1 ? +1 : -1) : 0);
         }
         if (!equal) {
           for (int n=0; n<vecsize; ++n) {
             printf("FAIL: isnan type=%s val=%.17g res=%d good=%d\n",
                    typename, val.s[n], (int)jres.s[n],
                    (isnan(val.s[n]) ? (vecsize==1 ? +1 : -1) : 0));
           }
           return;
         }
         /* isnormal */
         jres.v = isnormal(val.v);
         equal = true;
         for (int n=0; n<vecsize; ++n) {
           equal = equal &&
             jres.s[n] == (isnormal(val.s[n]) ? (vecsize==1 ? +1 : -1) : 0);
         }
         if (!equal) {
           for (int n=0; n<vecsize; ++n) {
             printf("FAIL: isnormal type=%s val=%.17g res=%d good=%d\n",
                    typename, val.s[n], (int)jres.s[n],
                    (isnormal(val.s[n]) ? (vecsize==1 ? +1 : -1) : 0));
           }
           return;
         }
         /* copysign */
         for (int sign2=-1; sign2<=+1; sign2+=2) {
           res.v = copysign(val.v, (stype)sign2*val2.v);
           equal = true;
           for (int n=0; n<vecsize; ++n) {
             S r, g;
             r.s = res.s[n];
             g.s = sign2*good.s[n];
             equal = equal &&
               (ISNAN(val.s[n]) || ISNAN(val2.s[n]) || r.sj == g.sj);
           }
           if (!equal) {
             for (int n=0; n<vecsize; ++n) {
               printf("FAIL: copysign type=%s val=%.17g sign=%.17g res=%.17g good=%.17g\n",
                      typename, val.s[n], sign2*val2.s[n], res.s[n], good.s[n]);
             }
             return;
           }
         }
         /* ilogb */
         Ivec ires;
         ires.v = ilogb(val.v);
         Ivec igoodres;
         equal = true;
         for (int n=0; n<vecsize; ++n) {
           if (ISNAN(val.s[n])) {
             igoodres.s[n] = FP_ILOGBNAN;
           } else if (val.s[n] == (stype)0) {
             igoodres.s[n] = FP_ILOGB0;
           } else if (isinf(val.s[n])) {
             igoodres.s[n] = INT_MAX;
           } else {
             // We round down to "correct" for inaccuracies in log2
             igoodres.s[n] = rint(floor(0.999999f*log2(fabs(val.s[n]))));
           }
           equal = equal && ires.s[n] == igoodres.s[n];
         }
         if (!equal) {
           for (int n=0; n<vecsize; ++n) {
             printf("FAIL: ilogb type=%s val=%.17g res=%d good=%d\n",
                    typename, val.s[n], (int)ires.s[n], (int)igoodres.s[n]);
           }
           return;
         }
         /* ldexp */
         Ivec ival2;
         ival2.v = (itype)4;
         res.v = ldexp(val.v, ival2.v);
         Tvec goodres;
         equal = true;
         for (int n=0; n<vecsize; ++n) {
           if (ISNAN(val.s[n])) {
             goodres.s[n] = NAN;
           } else if (val.s[n] == (stype)0) {
             goodres.s[n] = val.s[n];
           } else if (isinf(val.s[n])) {
             goodres.s[n] = val.s[n];
           } else {
             goodres.s[n] = val.s[n] * pow(2.0, ival2.s[n]);
           }
           equal = equal && ISEQ(res.s[n], goodres.s[n]);
         }
         if (!equal) {
           for (int n=0; n<vecsize; ++n) {
             printf("FAIL: ldexp type=%s val=%.17g val2=%d res=%.17g good=%.17g\n",
                    typename, val.s[n], (int)ival2.s[n], res.s[n], goodres.s[n]);
           }
           return;
         }
       }
     }
   }
 })
 )

kernel void test_fabs()
{
  CALL_FUNC_V(test_fabs)
}


Add support for blending operations

Add support for blending operations


Wrote GVFInit

Wrote GVFInit

__kernel void GVFInit(__read_only image3d_t volume, __write_only image3d_t vector_field ) {
    // gradient of volume and store it in vector_field
    // Calculate gradient using a 1D central difference for each dimension, with spacing 1
    int4 pos = {get_global_id(0), get_global_id(1), get_global_id(2), 0};

    int f = read_imagei(volume, sampler, pos).x;
    int fx1 = read_imagei(volume, sampler, pos + (int4)(1,0,0,0)).x;
    int fx_1 = read_imagei(volume, sampler, pos - (int4)(1,0,0,0)).x;
    int fy1 = read_imagei(volume, sampler, pos + (int4)(0,1,0,0)).x;
    int fy_1 = read_imagei(volume, sampler, pos - (int4)(0,1,0,0)).x;
    int fz1 = read_imagei(volume, sampler, pos + (int4)(0,0,1,0)).x;
    int fz_1 = read_imagei(volume, sampler, pos - (int4)(0,0,1,0)).x;

    int4 gradient = {
        fx1 - 2*f + fx_1,
        fy1 - 2*f + fy_1,
        fz1 - 2*f + fz_1,
        0};

    gradient.w = gradient.x*gradient.x + gradient.y*gradient.y + gradient.z*gradient-z;

    write_imagei(vector_field, pos, gradient);

}

__kernel void GVFIteration(__read_only image3d_t read_vector_field, __write_only image3d_t write_vector_field, __private float mu) {
    // Enforce mirror boundary conditions

    // Update the vector field

    // Calculate laplacian using a 3D central difference scheme
}

__kernel void GVFInit(__read_only image3d_t volume, __write_only image3d_t vector_field ) {
    // gradient of volume and store it in vector_field
}

__kernel void GVFIteration(__read_only image3d_t read_vector_field, __write_only image3d_t write_vector_field, __private float mu) {
    // Enforce mirror boundary conditions

    // Update the vector field
}


fix comment indents in lpp.cl

fix comment indents in lpp.cl

(defstruct param type name deref funcset)
(defstruct funcdef funcset funcname params returntype)

(setq preprocessor-file-extension "lpp")
(setq begin-marker-left "^^^BEGINREPLACE:")
(setq begin-marker-right "^^^")
(setq end-marker "^^^ENDREPLACE^^^")
(setq auto-header-marker "^^^AUTOGENHEADER^^^")
(setq token-marker #\^)
(setq token-arg-marker #\:)
(setq token-arg-delimiter #\,)

(defstruct lppmacro macro filter)

(setq macro-hash (make-hash-table :test 'equal))
(defun add-macro (&rest args)
  (let ((m (apply #'make-lppmacro args)))
    (setf (gethash (lppmacro-macro m) macro-hash) m)
    )
  )
(defun get-macro (key) (gethash key macro-hash))

(setq void-param-hash (make-hash-table :test 'equal))
(defun add-void-param (&rest args)
  (let* ((p (apply #'make-param args))
         (funcset-name (param-funcset p))
         )
    (cond ((not (null funcset-name))
           (setf (gethash funcset-name void-param-hash) p)
           )
          (t (error "Must provide :funcset for add-void-param"))
          )
    )
  )
(defun get-void-param (funcset-name) (gethash funcset-name void-param-hash))

(add-macro :macro "RETURN"      :filter (lambda (fd len args vp) (funcdef-returntype fd)))
(add-macro :macro "FUNC"        :filter (lambda (fd len args vp) (funcdef-funcname fd)))
(add-macro :macro "PARAMS"      :filter (lambda (fd len args vp) (format-params (funcdef-params fd) len args vp)))
;; PARAMS arguments: types, names, deref, ref, void, voidonly, nowrap
;;;;;;;;;;;;;;;;;;

(defun partial (func &rest args1)
  (lambda (&rest args2) (apply func (append args1 args2)))
  )

(defun newline ()
  (write-string (format nil "~%"))
  )

(defun concat-string-list (s)
  (format nil "~{~A~^~%~}" s)
  )

(defun replace-all (string part replacement &key (test #'char=))
  "Returns a new string in which all the occurences of the part
is replaced with replacement."
  (with-output-to-string (out)
    (loop with part-length = (length part)
       for old-pos = 0 then (+ pos part-length)
       for pos = (search part string
                         :start2 old-pos
                         :test test)
       do (write-string string out
                        :start old-pos
                        :end (or pos (length string)))
       when pos do (write-string replacement out)
       while pos))
  )

(defun is-arg-set (target-arg args)
  (not (null (find target-arg args :test 'equal)))
  )

(defun format-paramitem-type (args p)
  (format nil "~A" (param-type p))
  )

(defun format-paramitem-name (args p)
  ;;in name only format, we can dereference the argument (pointer)
  ;;but only if the macro argument requested it
  ;;and this parameter can be dereferenced
  (if (and (is-arg-set "deref" args) (param-deref p))
      ;;then
      (format nil "*~A" (param-name p))
      ;;else
      (format nil "~A" (param-name p))
      )
  )

(defun format-paramitem-full (args p)
  (let* ((type-decl (param-type p))
         (last-index (1- (length type-decl)))
         )
    (format nil "~A ~A"
            ;;if macro requested reference mode,
            ;; this parameter is dereferencable,
            ;; and the last char is a *
            (if (and (is-arg-set "ref" args) (param-deref p) (equal "*" (subseq type-decl last-index)))
                ;;then, replace the last * with a &
                (concatenate 'string (subseq type-decl 0 last-index) "&")
                ;;else
                type-decl
                )
            (param-name p))
    )
  )

(defun error-if-null (var errmsg) (when (null var) (error errmsg)))

(defun format-params (params token-start-length args void-param)
  ;;full, types, names, deref, ref, void, voidonly, nowrap
  (let*  ((arg-types      (is-arg-set "types" args))
          (arg-names      (is-arg-set "names" args))
          (arg-deref      (is-arg-set "deref" args))
          (arg-ref        (is-arg-set "ref" args))
          (arg-void       (is-arg-set "void" args))
          (arg-voidonly   (is-arg-set "voidonly" args))
          (arg-wrap       (is-arg-set "wrap" args))
          (arg-nowrap     (is-arg-set "nowrap" args))
          (filtered-params (cond  (arg-voidonly
                                   (error-if-null void-param "Void param must be set to use void argument")
                                   (cons void-param nil)) ;;only the void-param
                                  (arg-void
                                   (error-if-null void-param "Void param must be set to use void argument")
                                   (cons void-param params)) ;;prepend the void-param
                                  (t params) ;;default, just use params
                                  )
            )
          (types-only (and arg-types (not arg-names)))
          (names-only (and arg-names (not arg-types)))
          (full-decl  (not (xor arg-names arg-types)))
          (format-param-func (cond  (full-decl  #'format-paramitem-full)
                                    (types-only #'format-paramitem-type)
                                    (names-only #'format-paramitem-name)
                                    ))
          (do-wrap    (or arg-wrap (not (or names-only arg-nowrap))))
          (format-line (if do-wrap "~{~A~^,~%~}" "~{~A~^, ~}"))
          )
    (when filtered-params
      (format nil format-line
              (cons
               ;;first parameter => no indentation
               (apply format-param-func (list args (car filtered-params)))
               (mapcar
                (lambda (p)
                  (concatenate 'string
                               ;;second parameter, indent according to wrap policy
                               (when do-wrap (make-string token-start-length :initial-element #\ ))
                               (apply format-param-func (list args p))
                               )
                  )
                (cdr filtered-params)
                )
               )
              )
      )
    )
  )

(defun split-by-delimiter (string delimiter)
  (loop   for start = 0 then (1+ finish)
     for finish = (position delimiter string :start start)
     if (and (not (eq (length string) start)) (not (eq start finish))) collect (subseq string start finish)
     until (null finish)
       )
  )

(defun process-tokens (line funcdata void-param &optional (line-length 0))
  (let ((token-marker-left (position token-marker line))
        )
    (if (null token-marker-left)
        ;;then, no left token marker. return line
        line
        ;;else, process more
        (let* ((token-start (1+ token-marker-left))
               (token-stop (position token-marker line :start token-start))
               )
          (if (null token-stop)
              ;;then, no right token marker. return line
              line
              ;;else, process more

              (let* ((token-full (subseq line token-start token-stop))
                     (seperator-index (position token-arg-marker token-full))
                     (token (subseq token-full 0 seperator-index))
                     (token-args (if (not (null seperator-index))
                                     (split-by-delimiter (subseq token-full (1+ seperator-index) nil) token-arg-delimiter)
                                     '(nil)
                                     ))
                     (line-begin (subseq line 0 token-marker-left))
                     (line-end (subseq line (1+ token-stop) nil))
                     (m (get-macro token))
                     )
                ;;m (the macro struct) is nil if no macro found for the token
                (if (null m)
                    ;;then
                    line
                    ;;else
                    (let* ((token-start-length (+ line-length token-marker-left))
                           (expanded-token (funcall (lppmacro-filter m) funcdata token-start-length token-args void-param))
                           )
                      (concatenate 'string
                                   line-begin
                                   expanded-token
                                   (process-tokens line-end funcdata void-param (+ token-start-length (length expanded-token)))
                                   )
                      )
                    )
                )
              ))))
  )

(defun expand-template (template-list func-data void-param)
  (concat-string-list
   (mapcar
    (lambda (template-line) (process-tokens template-line func-data void-param))
    template-list
    )
   )
  )

(defun expand-methods-with-template (template-list funcset-name)
  (remove nil ;;filter out the nil values (from wrong funcsets)
          (mapcar
           (lambda (func-data)
             (cond ;;only expand this function if it belongs to the target funcset
               ((equal funcset-name (funcdef-funcset func-data))
                (expand-template template-list func-data (get-void-param funcset-name))
                )
               ;;otherwise return nil
               (t nil)
               )
             )
           funcs
           )
          )
  )

(defun clear-funcs ()
  (setq funcs nil)
  (setq funcs-tail funcs)
  )
(clear-funcs)

(defun add-func (&rest args)
  (let ((func-data (apply #'make-funcdef args)))
    (if (endp funcs)
        ;;then
        (progn
          (setq funcs (cons func-data nil))
          (setq funcs-tail funcs)
          )
        ;;else
        (progn
          (setf (cdr funcs-tail) (cons func-data nil))
          (setq funcs-tail (cdr funcs-tail))
          )
        )
    )
  )

(defun outputfuncs (f)
  (write-line (concat-string-list f))
  )

(defun filter-line (line filename)
  (replace-all line auto-header-marker (format nil "THIS FILE AUTO-GENERATED FROM ~A. DO NOT EDIT." filename))
  )

(defmacro prepend-into (var value)
  `(setq ,var (cons ,value ,var))
  )

(defun strip-end-characters (str numChars)
  (let ((index (- (length str) numChars)))
    (if (>= index 1)
        (subseq str 0 index)
        nil
        )
    )
  )

(defun get-funcset-from-begin-marker (line)
  (let ((start-index (search begin-marker-left line)))
    (cond ;;no begin marker, return nil
      ((null start-index) nil)

      ;;begin marker must be at start of line
      ((not (= start-index 0)) nil)

      ;;left side is good
      (t (let*  ((start-param-index (+ start-index (length begin-marker-left)))
                 (end-index (search begin-marker-right line :start2 start-param-index)))
           (cond ;;no right side marker, return nil
             ((null end-index) nil)

             ;;right marker must be at end of line
             ((not (= (length line) (+ end-index (length begin-marker-right)))) nil)

             ;;markers but no funcset parameter, can't process
             ((= start-param-index end-index) nil)
             ;;we have a begin-marker and funcset parameter!
             (t (values (subseq line start-param-index end-index) start-param-index end-index))
             )
           )
         )
      )
    )
  )

(defun is-end-marker (line)
  (equal line end-marker)
  )

(defun in-to-out-filename (fn)
  (strip-end-characters fn 4)
  )

(defun process-file (infilename)
  (let ((infile (open infilename :if-does-not-exist nil))
        (outfile (open (in-to-out-filename infilename) :direction :output :if-exists :supersede))
        (filelines nil)
        (templatelines nil)
        (funcset-name nil)
        )
    (when infile
      (loop
         for line = (read-line infile nil)
         while line
         do
           (cond   ;;outside of a replace block
             ((null funcset-name)
              ;;look for a begin-replace marker (funcset name becomes not nil)
              (setq funcset-name (get-funcset-from-begin-marker line))
              ;;if still no funcset-name
              (when (null funcset-name)
                ;;accumulate filtered lines to filelines
                (prepend-into filelines (filter-line line (file-namestring infilename)))
                )
              )

             ;;all below: funcset-name is not nil -- inside of a replace block
             ;;check for end marker
             ((is-end-marker line)
              ;;since we have a full template, expand template it
              (mapcar
               (lambda (v) (prepend-into filelines v))
               (expand-methods-with-template (reverse templatelines) funcset-name)
               )
              (setq funcset-name nil) ;;clear funcset-name -- return to normal operation above
              )
             ;;inside replace block, accumulate template
             (t (prepend-into templatelines line))
             )
           )
      (loop for line in (reverse filelines)
         do (write-line line outfile)
           )
      (close infile)
      (close outfile))
    )
  )

(load "apidef.cl" :verbose nil)
(load "cl-fad/load.lisp" :verbose nil)

(defun mapc-directory-tree (fn directory)
  (dolist (entry (cl-fad:list-directory directory))
    (when (cl-fad:directory-pathname-p entry)
      (mapc-directory-tree fn entry))
    (funcall fn entry)
    )
  )

(defun _ () (load "lpp.cl" :verbose nil))

(defun process (dir)
  (let ((target-directory (if (null dir)
                              (ext:cd)
                              dir
                              )))
    (write-line (format nil "Base directory: ~A~%" target-directory))
    (mapc-directory-tree (lambda (x)
                           (when (equal (pathname-type x) preprocessor-file-extension)
                             (write-line (format nil "~A => ~A"
                                                 (enough-namestring x target-directory)
                                                 (in-to-out-filename (file-namestring x))))
                             (process-file (namestring x))
                             )
                           )
                         target-directory
                         )
    )
  )
(process (car *args*))

(defstruct param type name deref funcset)
(defstruct funcdef funcset funcname params returntype)

(setq preprocessor-file-extension "lpp")
(setq begin-marker-left "^^^BEGINREPLACE:")
(setq begin-marker-right "^^^")
(setq end-marker "^^^ENDREPLACE^^^")
(setq auto-header-marker "^^^AUTOGENHEADER^^^")
(setq token-marker #\^)
(setq token-arg-marker #\:)
(setq token-arg-delimiter #\,)

(defstruct lppmacro macro filter)

(setq macro-hash (make-hash-table :test 'equal))
(defun add-macro (&rest args)
  (let ((m (apply #'make-lppmacro args)))
    (setf (gethash (lppmacro-macro m) macro-hash) m)
    )
  )
(defun get-macro (key) (gethash key macro-hash))

(setq void-param-hash (make-hash-table :test 'equal))
(defun add-void-param (&rest args)
  (let* ((p (apply #'make-param args))
         (funcset-name (param-funcset p))
         )
    (cond ((not (null funcset-name))
           (setf (gethash funcset-name void-param-hash) p)
           )
          (t (error "Must provide :funcset for add-void-param"))
          )
    )
  )
(defun get-void-param (funcset-name) (gethash funcset-name void-param-hash))

(add-macro :macro "RETURN"      :filter (lambda (fd len args vp) (funcdef-returntype fd)))
(add-macro :macro "FUNC"        :filter (lambda (fd len args vp) (funcdef-funcname fd)))
(add-macro :macro "PARAMS"      :filter (lambda (fd len args vp) (format-params (funcdef-params fd) len args vp)))
                                        ; PARAMS arguments: types, names, deref, ref, void, voidonly, nowrap
;;;;;;;;;

(defun partial (func &rest args1)
  (lambda (&rest args2) (apply func (append args1 args2)))
  )

(defun newline ()
  (write-string (format nil "~%"))
  )

(defun concat-string-list (s)
  (format nil "~{~A~^~%~}" s)
  )

(defun replace-all (string part replacement &key (test #'char=))
  "Returns a new string in which all the occurences of the part
is replaced with replacement."
  (with-output-to-string (out)
    (loop with part-length = (length part)
       for old-pos = 0 then (+ pos part-length)
       for pos = (search part string
                         :start2 old-pos
                         :test test)
       do (write-string string out
                        :start old-pos
                        :end (or pos (length string)))
       when pos do (write-string replacement out)
       while pos))
  )

(defun is-arg-set (target-arg args)
  (not (null (find target-arg args :test 'equal)))
  )

(defun format-paramitem-type (args p)
  (format nil "~A" (param-type p))
  )

(defun format-paramitem-name (args p)
                                        ;in name only format, we can dereference the argument (pointer)
                                        ;but only if the macro argument requested it
                                        ;and this parameter can be dereferenced
  (if (and (is-arg-set "deref" args) (param-deref p))
                                        ;then
      (format nil "*~A" (param-name p))
                                        ;else
      (format nil "~A" (param-name p))
      )
  )

(defun format-paramitem-full (args p)
  (let* ((type-decl (param-type p))
         (last-index (1- (length type-decl)))
         )
    (format nil "~A ~A"
                                        ;if macro requested reference mode,
                                        ; this parameter is dereferencable,
                                        ; and the last char is a *
            (if (and (is-arg-set "ref" args) (param-deref p) (equal "*" (subseq type-decl last-index)))
                                        ;then, replace the last * with a &
                (concatenate 'string (subseq type-decl 0 last-index) "&")
                                        ;else
                type-decl
                )
            (param-name p))
    )
  )

(defun error-if-null (var errmsg) (when (null var) (error errmsg)))

(defun format-params (params token-start-length args void-param)
                                        ;full, types, names, deref, ref, void, voidonly, nowrap
  (let*  ((arg-types      (is-arg-set "types" args))
          (arg-names      (is-arg-set "names" args))
          (arg-deref      (is-arg-set "deref" args))
          (arg-ref        (is-arg-set "ref" args))
          (arg-void       (is-arg-set "void" args))
          (arg-voidonly   (is-arg-set "voidonly" args))
          (arg-wrap       (is-arg-set "wrap" args))
          (arg-nowrap     (is-arg-set "nowrap" args))
          (filtered-params (cond  (arg-voidonly
                                   (error-if-null void-param "Void param must be set to use void argument")
                                   (cons void-param nil)) ;only the void-param
                                  (arg-void
                                   (error-if-null void-param "Void param must be set to use void argument")
                                   (cons void-param params)) ;prepend the void-param
                                  (t params) ;default, just use params
                                  )
            )
          (types-only (and arg-types (not arg-names)))
          (names-only (and arg-names (not arg-types)))
          (full-decl  (not (xor arg-names arg-types)))
          (format-param-func (cond  (full-decl  #'format-paramitem-full)
                                    (types-only #'format-paramitem-type)
                                    (names-only #'format-paramitem-name)
                                    ))
          (do-wrap    (or arg-wrap (not (or names-only arg-nowrap))))
          (format-line (if do-wrap "~{~A~^,~%~}" "~{~A~^, ~}"))
          )
    (when filtered-params
      (format nil format-line
              (cons
                                        ;first parameter => no indentation
               (apply format-param-func (list args (car filtered-params)))
               (mapcar
                (lambda (p)
                  (concatenate 'string
                                        ;second parameter, indent according to wrap policy
                               (when do-wrap (make-string token-start-length :initial-element #\ ))
                               (apply format-param-func (list args p))
                               )
                  )
                (cdr filtered-params)
                )
               )
              )
      )
    )
  )

(defun split-by-delimiter (string delimiter)
  (loop   for start = 0 then (1+ finish)
     for finish = (position delimiter string :start start)
     if (and (not (eq (length string) start)) (not (eq start finish))) collect (subseq string start finish)
     until (null finish)
       )
  )

(defun process-tokens (line funcdata void-param &optional (line-length 0))
  (let ((token-marker-left (position token-marker line))
        )
    (if (null token-marker-left)
                                        ;then, no left token marker. return line
        line
                                        ;else, process more
        (let* ((token-start (1+ token-marker-left))
               (token-stop (position token-marker line :start token-start))
               )
          (if (null token-stop)
                                        ;then, no right token marker. return line
              line
                                        ;else, process more

              (let* ((token-full (subseq line token-start token-stop))
                     (seperator-index (position token-arg-marker token-full))
                     (token (subseq token-full 0 seperator-index))
                     (token-args (if (not (null seperator-index))
                                     (split-by-delimiter (subseq token-full (1+ seperator-index) nil) token-arg-delimiter)
                                     '(nil)
                                     ))
                     (line-begin (subseq line 0 token-marker-left))
                     (line-end (subseq line (1+ token-stop) nil))
                     (m (get-macro token))
                     )
                                        ;m (the macro struct) is nil if no macro found for the token
                (if (null m)
                                        ;then
                    line
                                        ;else
                    (let* ((token-start-length (+ line-length token-marker-left))
                           (expanded-token (funcall (lppmacro-filter m) funcdata token-start-length token-args void-param))
                           )
                      (concatenate 'string
                                   line-begin
                                   expanded-token
                                   (process-tokens line-end funcdata void-param (+ token-start-length (length expanded-token)))
                                   )
                      )
                    )
                )
              ))))
  )

(defun expand-template (template-list func-data void-param)
  (concat-string-list
   (mapcar
    (lambda (template-line) (process-tokens template-line func-data void-param))
    template-list
    )
   )
  )

(defun expand-methods-with-template (template-list funcset-name)
  (remove nil ;filter out the nil values (from wrong funcsets)
          (mapcar
           (lambda (func-data)
             (cond ;only expand this function if it belongs to the target funcset
               ((equal funcset-name (funcdef-funcset func-data))
                (expand-template template-list func-data (get-void-param funcset-name))
                )
                                        ;otherwise return nil
               (t nil)
               )
             )
           funcs
           )
          )
  )

(defun clear-funcs ()
  (setq funcs nil)
  (setq funcs-tail funcs)
  )
(clear-funcs)

(defun add-func (&rest args)
  (let ((func-data (apply #'make-funcdef args)))
    (if (endp funcs)
                                        ;then
        (progn
          (setq funcs (cons func-data nil))
          (setq funcs-tail funcs)
          )
                                        ;else
        (progn
          (setf (cdr funcs-tail) (cons func-data nil))
          (setq funcs-tail (cdr funcs-tail))
          )
        )
    )
  )

(defun outputfuncs (f)
  (write-line (concat-string-list f))
  )

(defun filter-line (line filename)
  (replace-all line auto-header-marker (format nil "THIS FILE AUTO-GENERATED FROM ~A. DO NOT EDIT." filename))
  )

(defmacro prepend-into (var value)
  `(setq ,var (cons ,value ,var))
  )

(defun strip-end-characters (str numChars)
  (let ((index (- (length str) numChars)))
    (if (>= index 1)
        (subseq str 0 index)
        nil
        )
    )
  )

(defun get-funcset-from-begin-marker (line)
  (let ((start-index (search begin-marker-left line)))
    (cond ;no begin marker, return nil
      ((null start-index) nil)

                                        ;begin marker must be at start of line
      ((not (= start-index 0)) nil)

                                        ;left side is good
      (t (let*  ((start-param-index (+ start-index (length begin-marker-left)))
                 (end-index (search begin-marker-right line :start2 start-param-index)))
           (cond ;no right side marker, return nil
             ((null end-index) nil)

                                        ;right marker must be at end of line
             ((not (= (length line) (+ end-index (length begin-marker-right)))) nil)

                                        ;markers but no funcset parameter, can't process
             ((= start-param-index end-index) nil)
                                        ;we have a begin-marker and funcset parameter!
             (t (values (subseq line start-param-index end-index) start-param-index end-index))
             )
           )
         )
      )
    )
  )

(defun is-end-marker (line)
  (equal line end-marker)
  )

(defun in-to-out-filename (fn)
  (strip-end-characters fn 4)
  )

(defun process-file (infilename)
  (let ((infile (open infilename :if-does-not-exist nil))
        (outfile (open (in-to-out-filename infilename) :direction :output :if-exists :supersede))
        (filelines nil)
        (templatelines nil)
        (funcset-name nil)
        )
    (when infile
      (loop
         for line = (read-line infile nil)
         while line
         do
           (cond   ;outside of a replace block
             ((null funcset-name)
                                        ;look for a begin-replace marker (funcset name becomes not nil)
              (setq funcset-name (get-funcset-from-begin-marker line))
                                        ;if still no funcset-name
              (when (null funcset-name)
                                        ;accumulate filtered lines to filelines
                (prepend-into filelines (filter-line line (file-namestring infilename)))
                )
              )

                                        ;all below: funcset-name is not nil -- inside of a replace block
                                        ;check for end marker
             ((is-end-marker line)
                                        ;since we have a full template, expand template it
              (mapcar
               (lambda (v) (prepend-into filelines v))
               (expand-methods-with-template (reverse templatelines) funcset-name)
               )
              (setq funcset-name nil) ;clear funcset-name -- return to normal operation above
              )
                                        ;inside replace block, accumulate template
             (t (prepend-into templatelines line))
             )
           )
      (loop for line in (reverse filelines)
         do (write-line line outfile)
           )
      (close infile)
      (close outfile))
    )
  )

(load "apidef.cl" :verbose nil)
(load "cl-fad/load.lisp" :verbose nil)

(defun mapc-directory-tree (fn directory)
  (dolist (entry (cl-fad:list-directory directory))
    (when (cl-fad:directory-pathname-p entry)
      (mapc-directory-tree fn entry))
    (funcall fn entry)
    )
  )

(defun _ () (load "lpp.cl" :verbose nil))

(defun process (dir)
  (let ((target-directory (if (null dir)
                              (ext:cd)
                              dir
                              )))
    (write-line (format nil "Base directory: ~A~%" target-directory))
    (mapc-directory-tree (lambda (x)
                           (when (equal (pathname-type x) preprocessor-file-extension)
                             (write-line (format nil "~A => ~A"
                                                 (enough-namestring x target-directory)
                                                 (in-to-out-filename (file-namestring x))))
                             (process-file (namestring x))
                             )
                           )
                         target-directory
                         )
    )
  )
(process (car *args*))