/* * Coroutine mechanics used in PuTTY's SSH code. */ #ifndef PUTTY_SSHCR_H #define PUTTY_SSHCR_H /* * If these macros look impenetrable to you, you might find it helpful * to read * * https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html * * which explains the theory behind these macros. * * In particular, if you are getting `case expression not constant' * errors when building with MS Visual Studio, this is because MS's * Edit and Continue debugging feature causes their compiler to * violate ANSI C. To disable Edit and Continue debugging: * * - right-click ssh.c in the FileView * - click Settings * - select the C/C++ tab and the General category * - under `Debug info:', select anything _other_ than `Program * Database for Edit and Continue'. */ #define crBegin(v) do { int *crLine = &v; switch(v) { case 0: #define crBeginState crBegin(s->crLine) #define crStateP(t, v) \ struct t *s; \ if (!(v)) { s = (v) = snew(struct t); s->crLine = 0; } \ s = (v); #define crState(t) crStateP(t, ssh->t) #define crFinish(z) } *crLine = 0; return (z); } while (0) #define crFinishV } *crLine = 0; return; } while (0) #define crFinishFreed(z) } return (z); } while (0) #define crFinishFreedV } return; } while (0) #define crFinishFree(z) } sfree(s); return (z); } while (0) #define crFinishFreeV } sfree(s); return; } while (0) #define crReturn(z) \ do {\ *crLine =__LINE__; return (z); case __LINE__:;\ } while (0) #define crReturnV \ do {\ *crLine=__LINE__; return; case __LINE__:;\ } while (0) #define crStop(z) do{ *crLine = 0; return (z); }while(0) #define crStopV do{ *crLine = 0; return; }while(0) /* * The crMaybeWaitUntil macros could have been more easily written in * terms of the simple crReturn above, by writing things like * * while (!condition) { crReturn(whatever); } * * (or do-while in the case of crWaitUntil). But it's better to do it * directly by writing _once_ to crLine before first testing the * condition, because this way it's robust against the condition check * potentially freeing the entire coroutine state structure as a side * effect (as long as it also evaluates false if it does that), * because we don't write into crLine between the condition evaluating * to false and the 'return' statement. */ #define crMaybeWaitUntil(c) \ do { \ *crLine =__LINE__; \ case __LINE__: if (!(c)) return 0; \ } while (0) #define crMaybeWaitUntilV(c) \ do { \ *crLine =__LINE__; \ case __LINE__: if (!(c)) return; \ } while (0) #define crWaitUntil(c) \ do { \ *crLine =__LINE__; return; \ case __LINE__: if (!(c)) return 0; \ } while (0) #define crWaitUntilV(c) \ do { \ *crLine =__LINE__; return; \ case __LINE__: if (!(c)) return; \ } while (0) #endif /* PUTTY_SSHCR_H */