<?xml version="1.0"?>
<rss version="2.0">
	<channel>
		<title>4.3 error handling</title>
		<link>http://www.allegro.cc/forums/view/585786</link>
		<description>Allegro.cc Forum Thread</description>
		<webMaster>matthew@allegro.cc (Matthew Leverton)</webMaster>
		<lastBuildDate>Sat, 17 Jun 2006 07:01:18 +0000</lastBuildDate>
	</channel>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Because SF is giving problems with the mailing list, and I could always use more feedback, I thought I&#39;d toss up my idea about error handling in 4.3 here.</p><p>My initial email follows (with [code] blocks added for your sanity <img src="http://www.allegro.cc/forums/smileys/tongue.gif" alt=":P" />)
</p><div class="quote_container"><div class="title">My original message said:</div><div class="quote"><p>
While playing around with the sound code again, I thought it&#39;d be nice if it had some error handling abilities. I came up with this in about 15 to 30 minutes. I was just wondering if this is a good direction to put it in, or if you wanted something else. Here&#39;s the main code:</p><div class="source-code"><div class="toolbar"></div><div class="inner"><table width="100%"><tbody><tr><td class="number">1</td><td><span class="c">/****** Quick'n'dirty error API ******/</span></td></tr><tr><td class="number">2</td><td>&#160;</td></tr><tr><td class="number">3</td><td><span class="p">#include &lt;setjmp.h&gt;</span></td></tr><tr><td class="number">4</td><td><span class="p">#include &lt;signal.h&gt;</span></td></tr><tr><td class="number">5</td><td><span class="p">#include &lt;stdio.h&gt;</span></td></tr><tr><td class="number">6</td><td>&#160;</td></tr><tr><td class="number">7</td><td><span class="c">/* public */</span></td></tr><tr><td class="number">8</td><td><span class="k1">typedef</span> <span class="k1">enum</span> <span class="k2">{</span></td></tr><tr><td class="number">9</td><td>        AL_NO_ERROR       <span class="k3">=</span> <span class="n">0</span>,</td></tr><tr><td class="number">10</td><td>        AL_INVALID_PARAM  <span class="k3">=</span> <span class="n">1</span>,</td></tr><tr><td class="number">11</td><td>        AL_INVALID_OBJECT <span class="k3">=</span> <span class="n">2</span>,</td></tr><tr><td class="number">12</td><td>&#160;</td></tr><tr><td class="number">13</td><td>        AL_GENERIC_ERROR  <span class="k3">=</span> <span class="n">256</span></td></tr><tr><td class="number">14</td><td><span class="k2">}</span> AL_ERROR_ENUM<span class="k2">;</span></td></tr><tr><td class="number">15</td><td>&#160;</td></tr><tr><td class="number">16</td><td>AL_ERROR_ENUM al_get_last_error<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">17</td><td><span class="k1">void</span> al_enable_error_throws<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">18</td><td><span class="k1">void</span> al_disable_error_throws<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">19</td><td><span class="k1">void</span> al_error_throw<span class="k2">(</span>AL_ERROR_ENUM code<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">20</td><td>AL_ERROR_ENUM al_get_last_error<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">21</td><td>&#160;</td></tr><tr><td class="number">22</td><td><span class="p">#define al_error_try \</span></td></tr><tr><td class="number">23</td><td><span class="p">if(!setjmp(*_al_get_next_jump_point())  \ </span></td></tr><tr><td class="number">24</td><td><span class="p">{ </span></td></tr><tr><td class="number">25</td><td>&#160;</td></tr><tr><td class="number">26</td><td><span class="p">#define al_error_catch \</span></td></tr><tr><td class="number">27</td><td><span class="p">        _al_clear_last_error_point();   \ </span></td></tr><tr><td class="number">28</td><td><span class="p">}       \ </span></td></tr><tr><td class="number">29</td><td><span class="p">else </span></td></tr><tr><td class="number">30</td><td>&#160;</td></tr><tr><td class="number">31</td><td>&#160;</td></tr><tr><td class="number">32</td><td><span class="c">/* internal */</span></td></tr><tr><td class="number">33</td><td>jmp_buf <span class="k3">*</span>_al_get_next_jump_point<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">34</td><td><span class="k1">void</span> _al_clear_last_error_point<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">35</td><td>&#160;</td></tr><tr><td class="number">36</td><td>&#160;</td></tr><tr><td class="number">37</td><td><span class="c">/* source only */</span></td></tr><tr><td class="number">38</td><td><span class="k1">static</span> __thread AL_ERROR_ENUM _al_errcode<span class="k2">;</span></td></tr><tr><td class="number">39</td><td>&#160;</td></tr><tr><td class="number">40</td><td><span class="k1">static</span> __thread size_t _al_num_jump_points<span class="k2">;</span></td></tr><tr><td class="number">41</td><td><span class="k1">static</span> __thread jmp_buf _al_jump_points<span class="k2">[</span><span class="n">16</span><span class="k2">]</span><span class="k2">;</span></td></tr><tr><td class="number">42</td><td>&#160;</td></tr><tr><td class="number">43</td><td><span class="k1">static</span> __thread <span class="k1">bool</span> _al_throw_errors <span class="k3">=</span> <span class="k1">true</span><span class="k2">;</span></td></tr><tr><td class="number">44</td><td>&#160;</td></tr><tr><td class="number">45</td><td>&#160;</td></tr><tr><td class="number">46</td><td><span class="k1">static</span> <span class="k1">void</span> _unhandled_allegro_error<span class="k2">(</span><span class="k2">)</span></td></tr><tr><td class="number">47</td><td><span class="k2">{</span></td></tr><tr><td class="number">48</td><td>    <span class="c">/* This would obviously use system-specific methods (popup box, whatever),</span></td></tr><tr><td class="number">49</td><td><span class="c">       with more proper cleanup */</span></td></tr><tr><td class="number">50</td><td>    <a href="http://www.delorie.com/djgpp/doc/libc/libc_345.html" target="_blank">fprintf</a><span class="k2">(</span>stderr, <span class="s">"An unhandled error (code: %d) was caught!\nAborting\n"</span>, </td></tr><tr><td class="number">51</td><td>al_get_last_error<span class="k2">(</span><span class="k2">)</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">52</td><td>    <a href="http://www.delorie.com/djgpp/doc/libc/libc_636.html" target="_blank">raise</a><span class="k2">(</span>SIGABRT<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">53</td><td><span class="k2">}</span></td></tr><tr><td class="number">54</td><td>&#160;</td></tr><tr><td class="number">55</td><td><span class="k1">static</span> jmp_buf <span class="k3">*</span>get_last_jump_point<span class="k2">(</span><span class="k2">)</span></td></tr><tr><td class="number">56</td><td><span class="k2">{</span></td></tr><tr><td class="number">57</td><td>    <span class="k1">if</span><span class="k2">(</span>_al_num_jump_points <span class="k3">=</span><span class="k3">=</span> <span class="n">0</span><span class="k2">)</span></td></tr><tr><td class="number">58</td><td>        _unhandled_allegro_error<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">59</td><td>    <span class="k1">return</span> <span class="k3">&amp;</span>_al_jump_points<span class="k2">[</span><span class="k3">-</span><span class="k3">-</span>_al_num_jump_points<span class="k2">]</span><span class="k2">;</span></td></tr><tr><td class="number">60</td><td><span class="k2">}</span></td></tr><tr><td class="number">61</td><td>&#160;</td></tr><tr><td class="number">62</td><td>jmp_buf <span class="k3">*</span>_al_get_next_jump_point<span class="k2">(</span><span class="k2">)</span></td></tr><tr><td class="number">63</td><td><span class="k2">{</span></td></tr><tr><td class="number">64</td><td>    <span class="k1">if</span><span class="k2">(</span>_al_num_jump_points <span class="k3">&gt;</span><span class="k3">=</span> <span class="n">16</span><span class="k2">)</span></td></tr><tr><td class="number">65</td><td>        al_error_throw<span class="k2">(</span>AL_GENERIC_ERROR<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">66</td><td>    <span class="k1">return</span> <span class="k3">&amp;</span>_al_jump_points<span class="k2">[</span>_al_num_jump_points<span class="k3">+</span><span class="k3">+</span><span class="k2">]</span><span class="k2">;</span></td></tr><tr><td class="number">67</td><td><span class="k2">}</span></td></tr><tr><td class="number">68</td><td>&#160;</td></tr><tr><td class="number">69</td><td><span class="k1">void</span> _al_clear_last_error_point<span class="k2">(</span><span class="k2">)</span></td></tr><tr><td class="number">70</td><td><span class="k2">{</span></td></tr><tr><td class="number">71</td><td>    <span class="k1">if</span><span class="k2">(</span>_al_num_jump_points <span class="k3">=</span><span class="k3">=</span> <span class="n">0</span><span class="k2">)</span></td></tr><tr><td class="number">72</td><td>        _unhandled_allegro_error<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">73</td><td>    <span class="k3">-</span><span class="k3">-</span>_al_num_jump_points<span class="k2">;</span></td></tr><tr><td class="number">74</td><td><span class="k2">}</span></td></tr><tr><td class="number">75</td><td>&#160;</td></tr><tr><td class="number">76</td><td><span class="k1">void</span> al_enable_error_throws<span class="k2">(</span><span class="k2">)</span></td></tr><tr><td class="number">77</td><td><span class="k2">{</span></td></tr><tr><td class="number">78</td><td>    _al_throw_errors <span class="k3">=</span> <span class="k1">true</span><span class="k2">;</span></td></tr><tr><td class="number">79</td><td><span class="k2">}</span></td></tr><tr><td class="number">80</td><td>&#160;</td></tr><tr><td class="number">81</td><td><span class="k1">void</span> al_disable_error_throws<span class="k2">(</span><span class="k2">)</span></td></tr><tr><td class="number">82</td><td><span class="k2">{</span></td></tr><tr><td class="number">83</td><td>    _al_throw_errors <span class="k3">=</span> <span class="k1">false</span><span class="k2">;</span></td></tr><tr><td class="number">84</td><td><span class="k2">}</span></td></tr><tr><td class="number">85</td><td>&#160;</td></tr><tr><td class="number">86</td><td><span class="k1">void</span> al_error_throw<span class="k2">(</span>AL_ERROR_ENUM code<span class="k2">)</span></td></tr><tr><td class="number">87</td><td><span class="k2">{</span></td></tr><tr><td class="number">88</td><td>    _al_errcode <span class="k3">=</span> code<span class="k2">;</span></td></tr><tr><td class="number">89</td><td>    <span class="k1">if</span><span class="k2">(</span>_al_throw_errors<span class="k2">)</span></td></tr><tr><td class="number">90</td><td>        <a href="http://www.delorie.com/djgpp/doc/libc/libc_546.html" target="_blank">longjmp</a><span class="k2">(</span><span class="k3">*</span>get_last_jump_point<span class="k2">(</span><span class="k2">)</span>, code<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">91</td><td><span class="k2">}</span></td></tr><tr><td class="number">92</td><td>&#160;</td></tr><tr><td class="number">93</td><td>AL_ERROR_ENUM al_get_last_error<span class="k2">(</span><span class="k2">)</span></td></tr><tr><td class="number">94</td><td><span class="k2">{</span></td></tr><tr><td class="number">95</td><td>    AL_ERROR_ENUM err <span class="k3">=</span> _al_errcode<span class="k2">;</span></td></tr><tr><td class="number">96</td><td>    _al_errcode <span class="k3">=</span> AL_NO_ERROR<span class="k2">;</span></td></tr><tr><td class="number">97</td><td>    <span class="k1">return</span> err<span class="k2">;</span></td></tr><tr><td class="number">98</td><td><span class="k2">}</span></td></tr><tr><td class="number">99</td><td>&#160;</td></tr><tr><td class="number">100</td><td><span class="c">/*************/</span></td></tr></tbody></table></div></div><p>

C99 defines __thread, and Windows has a similar specifier. So as you can see, it uses TLS, meaning seperate threads erroring won&#39;t conflict with each other. To use it, you have these methods:</p><p>** Method #1 (the lazy/newbie approach):
</p><div class="source-code snippet"><div class="inner"><pre>sound_driver <span class="k3">=</span> al_audio_init_driver<span class="k2">(</span>NULL<span class="k2">)</span><span class="k2">;</span>
<span class="c">/* Allegro will have SIGABRT'd by now if there was a problem,</span>
<span class="c">   we can continue assuming everything's okay */</span>
..more game code..
</pre></div></div><p>

** Method #2 (the C++ approach):
</p><div class="source-code snippet"><div class="inner"><pre>al_error_try <span class="k2">(</span>
   sound_driver <span class="k3">=</span> al_audio_init_driver<span class="k2">(</span>NULL<span class="k2">)</span><span class="k2">;</span>
   ..more related code..
<span class="k2">}</span>
al_error_catch <span class="k2">{</span>
   AL_ERROR_ENUM code <span class="k3">=</span> al_get_last_error<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span>
   <span class="c">/* We only handle invalid parameter errors */</span>
   <span class="k1">if</span><span class="k2">(</span>code <span class="k3">!</span><span class="k3">=</span> AL_INVALID_PARAM<span class="k2">)</span>
      al_error_throw<span class="k2">(</span>code<span class="k2">)</span><span class="k2">;</span>
   show_my_error<span class="k2">(</span><span class="s">"Could not init sound!"</span><span class="k2">)</span><span class="k2">;</span>
<span class="k2">}</span>
..more game code..
</pre></div></div><p>

** Method #3 (the C approach):
</p><div class="source-code snippet"><div class="inner"><pre>al_error_disable_throws<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span>

sound_driver <span class="k3">=</span> al_audio_init_driver<span class="k2">(</span>NULL<span class="k2">)</span><span class="k2">;</span>
<span class="k1">if</span><span class="k2">(</span><span class="k3">!</span>sound_driver<span class="k2">)</span>
<span class="k2">{</span>
   AL_ERROR_ENUM code <span class="k3">=</span> al_get_last_error<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span>
   <span class="k1">if</span><span class="k2">(</span>code <span class="k3">!</span><span class="k3">=</span> AL_INVALID_PARAM<span class="k2">)</span>
   <span class="k2">{</span>
      al_error_enable_throws<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span>
      al_error_throw<span class="k2">(</span>code<span class="k2">)</span><span class="k2">;</span>
   <span class="k2">}</span>
   show_my_error<span class="k2">(</span><span class="s">"Could not init sound!"</span><span class="k2">)</span><span class="k2">;</span>
<span class="k2">}</span>

al_error_enable_throws<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span>
..more game code..
</pre></div></div><p>

So, what do you think? I kinda like it, but it may be too hacky for some people&#39;s tastes. I believe it&#39;s logically sound though, so it shouldn&#39;t cause problems..
</p></div></div><p>

After this, Elias responded:
</p><div class="quote_container"><div class="title">His response said:</div><div class="quote"><p>
I think, for C code, those #defines are really ugly.. at least to me they do look ugly. If I wanted to use #2, then I would use C++, not C.</p><p>And actual C++ users wouldn&#39;t benefit from setjmp/longjmp and those #defines, since real exceptions should be raised for C++. I&#39;d say, the best idea for C++ is a wrapper, where al_sound::init would raise an exception.</p><p>The TLS error code and NULL return is all that seems needed to me for C. For the #1 approach, we could have a flag to al_init, like al_init(ABORT_ON_ERROR). And then Allegro would automatically abort on error - just like in your code.</p><p>The #3 approach looks much simpler than the #2 approach to me anyway, so I don&#39;t think anything is wrong with it <img src="http://www.allegro.cc/forums/smileys/smiley.gif" alt=":)" /></p><p>One idea similar to setjmp/longjmp might be an error callback, something like:<br /><span class="source-code"><span class="k1">void</span> al_set_error_callback<span class="k2">(</span><span class="k1">void</span> <span class="k3">*</span><span class="k2">(</span>user_error_handler<span class="k2">)</span><span class="k2">(</span>AL_ERROR error<span class="k2">)</span><span class="k2">)</span><span class="k2">;</span></span><br />Users could set it to their own function, and it gets called with the error code. That way, it would be possible for users to use setjmp/longjmp inside the callback if they so wish (I think at least, I never fully could grasp how setjmp/longjmp works), or also raise C++ exceptions (unless, C++ exceptions can&#39;t be raised from a C callback, I remember something in that direction). Or they could simply have abort in there, then we wouldn&#39;t even need an extra flag for it in al_init.
</p></div></div><p>
To which I responded:
</p><div class="quote_container"><div class="title">My response said:</div><div class="quote"><p>
[quote He]I think, for C code, those #defines are really ugly.. at least to me they do look ugly. If I wanted to use #2, then I would use C++, not C.
</p></div></div><p>
But Allegro doesn&#39;t use C++. Since Allegro is going to use C (AFAIK), or at least expose a C-only API, it wouldn&#39;t be able to properly throw real exceptions.</p><p>Besides, with the way that code is, you can use any of the three at any time. Don&#39;t want to use the try/catch defines? Then just call al_error_disable_throws() once at the beginning of your program and don&#39;t think anything of them (just be sure to check for failure return codes). Too lazy to do your own error checking? Leave throws enabled and don&#39;t worry about the try and catch defines.</p><p>There&#39;s many times I wish I could just execute a string of commands and not have to check the return code of each one individually. But I&#39;d still like to be able to handle the errors manually myself, without having to use a seperate callback function. Something like:
</p><div class="source-code"><div class="toolbar"></div><div class="inner"><table width="100%"><tbody><tr><td class="number">1</td><td>al_error_try <span class="k2">{</span></td></tr><tr><td class="number">2</td><td>   audio_driver <span class="k3">=</span> al_audio_init_driver<span class="k2">(</span>NULL<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">3</td><td>&#160;</td></tr><tr><td class="number">4</td><td>   main_voice <span class="k3">=</span> al_voice_create<span class="k2">(</span>audio_driver, <span class="n">44100</span>, AL_AUDIO_16_BIT_INT, </td></tr><tr><td class="number">5</td><td>AL_AUDIO_4_CH, <span class="n">0</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">6</td><td>   al_voice_get_long<span class="k2">(</span>main_voice, AL_AUDIO_FREQUENCY, <span class="k3">&amp;</span>voice_freq<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">7</td><td>   al_voice_get_enum<span class="k2">(</span>main_voice, AL_AUDIO_CHANNELS, <span class="k3">&amp;</span>channels<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">8</td><td>&#160;</td></tr><tr><td class="number">9</td><td>   main_mixer <span class="k3">=</span> al_mixer_create<span class="k2">(</span>voice_freq, AL_AUDIO_32_BIT_FLOAT, channels<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">10</td><td>&#160;</td></tr><tr><td class="number">11</td><td>   al_voice_attach_mixer<span class="k2">(</span>main_voice, main_mixer<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">12</td><td><span class="k2">}</span></td></tr><tr><td class="number">13</td><td>al_error_catch <span class="k2">{</span></td></tr><tr><td class="number">14</td><td>   AL_ERROR code <span class="k3">=</span> al_get_last_error<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">15</td><td>   show_my_error<span class="k2">(</span><span class="s">"Error initializing sound!\n%s\n"</span>, al_get_error_string<span class="k2">(</span><span class="k2">)</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">16</td><td>   <span class="k1">if</span><span class="k2">(</span>no_sound_is_fatal<span class="k2">)</span></td></tr><tr><td class="number">17</td><td>      al_error_throw<span class="k2">(</span>code<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">18</td><td><span class="k2">}</span></td></tr></tbody></table></div></div><p>
Having to check each function in that try block manually and basically call the same error-handling code would be very wasteful. And putting those few lines into a seperate function to install as a callback temporarilly would not be very clean (plus the trouble of being able to save and restore a previous callback, if one was installed, and optionally continue from outside of the &quot;error zone&quot;).</p><p>NOTE: The al_get_error_string function I threw in up there isn&#39;t in the code I posted, but it would be useful to have a human-readable string of the problem along with a simple error code.</p><div class="quote_container"><div class="title">He said:</div><div class="quote"><p>
And actual C++ users wouldn&#39;t benefit from setjmp/longjmp and those #defines, since real exceptions should be raised for C++. I&#39;d say, the best idea for C++ is a wrapper, where al_sound::init would raise an exception.
</p></div></div><p>
A C++ wrapper could still raise real exceptions:
</p><div class="source-code snippet"><div class="inner"><pre>al_audio::init<span class="k2">(</span><span class="k2">)</span>
<span class="k2">{</span>
   al_error_try <span class="k2">{</span>
      driver <span class="k3">=</span> al_audio_init_driver<span class="k2">(</span>NULL<span class="k2">)</span><span class="k2">;</span>
   <span class="k2">}</span>
   al_error_catch <span class="k2">{</span>
      <span class="k1">throw</span> al_get_last_error<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span>
   <span class="k2">}</span>
<span class="k2">}</span>
</pre></div></div><p>
That also has the benefit of leaving the real throwing in C++, so you needn&#39;t have to worry about C++ exceptions through C.</p><div class="quote_container"><div class="title">He said:</div><div class="quote"><p>
The TLS error code and NULL return is all that seems needed to me for C.
</p></div></div><p>
Then that&#39;s all you have to use. Just call al_error_disable_throws() and do it the C way.</p><div class="quote_container"><div class="title">He said:</div><div class="quote"><p>
For the #1 approach, we could have a flag to al_init, like al_init(ABORT_ON_ERROR). And then Allegro would automatically abort on error - just like in your code.
</p></div></div><p>
My code has the benefit of being able to turn such aborts on and off at will. Like, say, if you want to init video without doing specific error checking, but then check the errors while initializing sound. It&#39;s also transparent, so you could put in a single try/catch around the whole initialization section without having to change the initialization code itself.</p><div class="quote_container"><div class="title">He said:</div><div class="quote"><p>
The #3 approach looks much simpler than the #2 approach to me anyway, so I don&#39;t think anything is wrong with it <img src="http://www.allegro.cc/forums/smileys/smiley.gif" alt=":)" />
</p></div></div><p>
Then, again, you&#39;re free to use it. <img src="http://www.allegro.cc/forums/smileys/smiley.gif" alt=":)" /> Nothing&#39;s forcing you to have to do it the first or second way.</p><div class="quote_container"><div class="title">He said:</div><div class="quote"><p>
One idea similar to setjmp/longjmp might be an error callback, something like:</p><p><span class="source-code"><span class="k1">void</span> al_set_error_callback<span class="k2">(</span><span class="k1">void</span> <span class="k3">*</span><span class="k2">(</span>user_error_handler<span class="k2">)</span><span class="k2">(</span>AL_ERROR error<span class="k2">)</span><span class="k2">)</span><span class="k2">;</span></span>
</p></div></div><p>
It might be a good idea to use that anyway, for uncaught errors (eg. if an error is generated and either throws are disabled, or not within a try block). The error handler can then return non-0 to tell Allegro to clean up and SIGABRT, or 0 to tell it to keep going. Though it probably shouldn&#39;t be allowed to keep going if throws are enabled.</p><div class="quote_container"><div class="title">He said:</div><div class="quote"><p>
Or they could simply have abort in there, then we wouldn&#39;t even need an extra flag for it in al_init.
</p></div></div><p>
Allegro knows best how to clean itself up (as long as it can keep track of its <br />own state, anyway). There should always be a way to tell Allegro to exit <br />cleanly <i>now</i>, and raise a signal for debuggers.</p><p>That said, however, I do see a <i>small</i> problem with my code. You wouldn&#39;t be <br />able to jump out from the try block (via goto, a caught exception, another <br />longjmp, etc) and continue using Allegro code, or else the code will throw to <br />the wrong setjmp point later on. Though I don&#39;t think it&#39;s that big of a deal <br />to simply note that you can&#39;t do that, if something like this is used. You <br />could always throw a custom allegro error in the try block and check for it <br />in the catch block, where you can jump out however you want.<br />&lt;/quote&gt;<br />That second message hasn&#39;t made it to the SF mailing list yet (despite the fact that I sent it over 13 hours ago and counting <img src="http://www.allegro.cc/forums/smileys/lipsrsealed.gif" alt=":-X" />).
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Kitty Cat)</author>
		<pubDate>Tue, 06 Jun 2006 17:44:42 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Here is a simple, thread safe and easy to use C way that I believe might be a better compromise.<br />This is actually 3 files mixed together (except.h, except.c and extry.c) but it will compile and run as is (for testing purposes of course) <img src="http://www.allegro.cc/forums/smileys/wink.gif" alt=";)" /></p><div class="source-code"><div class="toolbar"></div><div class="inner"><table width="100%"><tbody><tr><td class="number">1</td><td><span class="c">/*</span></td></tr><tr><td class="number">2</td><td><span class="c"> * I was inspired by the discussion in the mailing list and</span></td></tr><tr><td class="number">3</td><td><span class="c"> * thought I'd throw ;) this in.  It might be a good compromise</span></td></tr><tr><td class="number">4</td><td><span class="c"> * that everyone may be able to agree on and may turn out to be</span></td></tr><tr><td class="number">5</td><td><span class="c"> * very useful.</span></td></tr><tr><td class="number">6</td><td><span class="c"> *</span></td></tr><tr><td class="number">7</td><td><span class="c"> * Some proposed exception handling.</span></td></tr><tr><td class="number">8</td><td><span class="c"> * by Ron Novy</span></td></tr><tr><td class="number">9</td><td><span class="c"> *</span></td></tr><tr><td class="number">10</td><td><span class="c"> * Thanks to Chris and the others for there inspiration.</span></td></tr><tr><td class="number">11</td><td><span class="c"> *</span></td></tr><tr><td class="number">12</td><td><span class="c"> * This makes use of __FILE__ and __LINE__ to give useful information to the</span></td></tr><tr><td class="number">13</td><td><span class="c"> * user about what went wrong.  It is also thread safe and doesn't require any</span></td></tr><tr><td class="number">14</td><td><span class="c"> * extra memory or unnecessary function calls to try and emulate the C++ style</span></td></tr><tr><td class="number">15</td><td><span class="c"> * of exception handling.  It's very simple and easy to use too.</span></td></tr><tr><td class="number">16</td><td><span class="c"> *</span></td></tr><tr><td class="number">17</td><td><span class="c"> * The only cons I can think of are that it's not real exception handling and</span></td></tr><tr><td class="number">18</td><td><span class="c"> * its not C++ style.  But as this is C, are those really cons?</span></td></tr><tr><td class="number">19</td><td><span class="c"> *</span></td></tr><tr><td class="number">20</td><td><span class="c"> * this is 3 files mixed together (except.h, except.c and extry.c) but</span></td></tr><tr><td class="number">21</td><td><span class="c"> * it will compile and run as is (for testing ;)</span></td></tr><tr><td class="number">22</td><td><span class="c"> */</span></td></tr><tr><td class="number">23</td><td><span class="c">/* ----=== except.h start ===---- */</span></td></tr><tr><td class="number">24</td><td><span class="p">#include &lt;allegro.h&gt;</span></td></tr><tr><td class="number">25</td><td>&#160;</td></tr><tr><td class="number">26</td><td>&#160;</td></tr><tr><td class="number">27</td><td><span class="c">/* extended version */</span></td></tr><tr><td class="number">28</td><td><span class="p">#define AL_TRY_EX(condition, str, exception_handler)  \</span></td></tr><tr><td class="number">29</td><td><span class="p">   {                                                  \ </span></td></tr><tr><td class="number">30</td><td><span class="p">      if (condition)                                  \ </span></td></tr><tr><td class="number">31</td><td><span class="p">         exception_handler(str, __FILE__, __LINE__);  \ </span></td></tr><tr><td class="number">32</td><td><span class="p">   } </span></td></tr><tr><td class="number">33</td><td>&#160;</td></tr><tr><td class="number">34</td><td>&#160;</td></tr><tr><td class="number">35</td><td><span class="c">/* default version */</span></td></tr><tr><td class="number">36</td><td><span class="p">#define AL_TRY(condition, str)                        \</span></td></tr><tr><td class="number">37</td><td><span class="p">   AL_TRY_EX(condition, str, al_default_exception) </span></td></tr><tr><td class="number">38</td><td>&#160;</td></tr><tr><td class="number">39</td><td>&#160;</td></tr><tr><td class="number">40</td><td><span class="c">/* non-fatal GUI version */</span></td></tr><tr><td class="number">41</td><td><span class="p">#define AL_TRY_GUI(condition, str)                    \</span></td></tr><tr><td class="number">42</td><td><span class="p">   AL_TRY_EX(condition, str, al_gui_exception) </span></td></tr><tr><td class="number">43</td><td>&#160;</td></tr><tr><td class="number">44</td><td>&#160;</td></tr><tr><td class="number">45</td><td><span class="c">/* fatal GUI version */</span></td></tr><tr><td class="number">46</td><td><span class="p">#define AL_TRY_FGUI(condition, str)                   \</span></td></tr><tr><td class="number">47</td><td><span class="p">   AL_TRY_EX(condition, str, al_gui_fatal_exception) </span></td></tr><tr><td class="number">48</td><td>&#160;</td></tr><tr><td class="number">49</td><td><span class="c">/* ----=== except.h end ===---- */</span></td></tr><tr><td class="number">50</td><td>&#160;</td></tr><tr><td class="number">51</td><td>&#160;</td></tr><tr><td class="number">52</td><td>&#160;</td></tr><tr><td class="number">53</td><td><span class="c">/* ----=== except.c start ===---- */</span></td></tr><tr><td class="number">54</td><td><span class="c">//#include &lt;allegro.h&gt;</span></td></tr><tr><td class="number">55</td><td>&#160;</td></tr><tr><td class="number">56</td><td><span class="c">/* al_default_exception:</span></td></tr><tr><td class="number">57</td><td><span class="c"> *  This is used as a default exception handler.  This default implies a fatal</span></td></tr><tr><td class="number">58</td><td><span class="c"> *  exception and will exit the program.</span></td></tr><tr><td class="number">59</td><td><span class="c"> */</span></td></tr><tr><td class="number">60</td><td><span class="k1">void</span> al_default_exception<span class="k2">(</span>AL_CONST <span class="k1">char</span> <span class="k3">*</span>str, AL_CONST <span class="k1">char</span> <span class="k3">*</span>file, <span class="k1">int</span> <a href="http://www.allegro.cc/manual/line" target="_blank"><span class="a">line</span></a><span class="k2">)</span></td></tr><tr><td class="number">61</td><td><span class="k2">{</span></td></tr><tr><td class="number">62</td><td>   <a href="http://www.allegro.cc/manual/set_gfx_mode" target="_blank"><span class="a">set_gfx_mode</span></a><span class="k2">(</span>GFX_TEXT, <span class="n">0</span>, <span class="n">0</span>, <span class="n">0</span>, <span class="n">0</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">63</td><td>   <a href="http://www.allegro.cc/manual/allegro_message" target="_blank"><span class="a">allegro_message</span></a><span class="k2">(</span><span class="s">"Exception in File '%s' at Line: %d\n%s\n"</span>,</td></tr><tr><td class="number">64</td><td>                   file, <a href="http://www.allegro.cc/manual/line" target="_blank"><span class="a">line</span></a>,</td></tr><tr><td class="number">65</td><td>                   <span class="k2">(</span><span class="k2">(</span>str<span class="k2">)</span> ? str <span class="k2">:</span> <span class="s">"Allegro: Unknown exception occurred!"</span><span class="k2">)</span> <span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">66</td><td>   <a href="http://www.delorie.com/djgpp/doc/libc/libc_298.html" target="_blank">exit</a><span class="k2">(</span><span class="n">0</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">67</td><td><span class="k2">}</span></td></tr><tr><td class="number">68</td><td>&#160;</td></tr><tr><td class="number">69</td><td>&#160;</td></tr><tr><td class="number">70</td><td>&#160;</td></tr><tr><td class="number">71</td><td><span class="c">/* al_gui_exception:</span></td></tr><tr><td class="number">72</td><td><span class="c"> *  This can be used as an alternative to the default exception handler.</span></td></tr><tr><td class="number">73</td><td><span class="c"> *  This version can be used when the program is in a graphics mode and you can</span></td></tr><tr><td class="number">74</td><td><span class="c"> *  access Allegro's GUI system.</span></td></tr><tr><td class="number">75</td><td><span class="c"> */</span></td></tr><tr><td class="number">76</td><td><span class="k1">void</span> al_gui_exception<span class="k2">(</span>AL_CONST <span class="k1">char</span> <span class="k3">*</span>str, AL_CONST <span class="k1">char</span> <span class="k3">*</span>file, <span class="k1">int</span> <a href="http://www.allegro.cc/manual/line" target="_blank"><span class="a">line</span></a><span class="k2">)</span></td></tr><tr><td class="number">77</td><td><span class="k2">{</span></td></tr><tr><td class="number">78</td><td>   <span class="k1">int</span>  r<span class="k2">;</span></td></tr><tr><td class="number">79</td><td>   <span class="k1">char</span> tmp<span class="k2">[</span><span class="n">512</span><span class="k2">]</span><span class="k2">;</span></td></tr><tr><td class="number">80</td><td>&#160;</td></tr><tr><td class="number">81</td><td>   <a href="http://www.allegro.cc/manual/uszprintf" target="_blank"><span class="a">uszprintf</span></a><span class="k2">(</span>tmp, <span class="k1">sizeof</span><span class="k2">(</span>tmp<span class="k2">)</span>,</td></tr><tr><td class="number">82</td><td>             <span class="s">"Exception in file '%s' at line: %d."</span>,</td></tr><tr><td class="number">83</td><td>             file, <a href="http://www.allegro.cc/manual/line" target="_blank"><span class="a">line</span></a><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">84</td><td>&#160;</td></tr><tr><td class="number">85</td><td>   r <span class="k3">=</span> <a href="http://www.allegro.cc/manual/alert" target="_blank"><span class="a">alert</span></a><span class="k2">(</span>tmp,</td></tr><tr><td class="number">86</td><td>             <span class="k2">(</span><span class="k2">(</span>str<span class="k2">)</span> ? str <span class="k2">:</span> <span class="s">"Allegro: Unknown exception occurred!"</span><span class="k2">)</span>,</td></tr><tr><td class="number">87</td><td>             <span class="s">"It may be possible to continue (but at your own risk)."</span>,</td></tr><tr><td class="number">88</td><td>             <span class="s">" &amp;Continue "</span>, <span class="s">" &amp;Exit "</span>, <span class="s">'c'</span>, <span class="s">'e'</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">89</td><td>&#160;</td></tr><tr><td class="number">90</td><td>   <span class="k1">if</span> <span class="k2">(</span>r <span class="k3">=</span><span class="k3">=</span> <span class="n">2</span><span class="k2">)</span></td></tr><tr><td class="number">91</td><td>      <a href="http://www.delorie.com/djgpp/doc/libc/libc_298.html" target="_blank">exit</a><span class="k2">(</span><span class="n">1</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">92</td><td><span class="k2">}</span></td></tr><tr><td class="number">93</td><td>&#160;</td></tr><tr><td class="number">94</td><td>&#160;</td></tr><tr><td class="number">95</td><td>&#160;</td></tr><tr><td class="number">96</td><td>&#160;</td></tr><tr><td class="number">97</td><td><span class="c">/* al_gui_fatal_exception:</span></td></tr><tr><td class="number">98</td><td><span class="c"> *  This is the same as al_gui_exception except ;) that it is always fatal.</span></td></tr><tr><td class="number">99</td><td><span class="c"> */</span></td></tr><tr><td class="number">100</td><td><span class="k1">void</span> al_gui_fatal_exception<span class="k2">(</span>AL_CONST <span class="k1">char</span> <span class="k3">*</span>str, AL_CONST <span class="k1">char</span> <span class="k3">*</span>file, <span class="k1">int</span> <a href="http://www.allegro.cc/manual/line" target="_blank"><span class="a">line</span></a><span class="k2">)</span></td></tr><tr><td class="number">101</td><td><span class="k2">{</span></td></tr><tr><td class="number">102</td><td>   <span class="k1">char</span> tmp<span class="k2">[</span><span class="n">512</span><span class="k2">]</span><span class="k2">;</span></td></tr><tr><td class="number">103</td><td>&#160;</td></tr><tr><td class="number">104</td><td>   <a href="http://www.allegro.cc/manual/uszprintf" target="_blank"><span class="a">uszprintf</span></a><span class="k2">(</span>tmp, <span class="k1">sizeof</span><span class="k2">(</span>tmp<span class="k2">)</span>,</td></tr><tr><td class="number">105</td><td>             <span class="s">"Fatal exception in file '%s' at line: %d."</span>,</td></tr><tr><td class="number">106</td><td>             file, <a href="http://www.allegro.cc/manual/line" target="_blank"><span class="a">line</span></a><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">107</td><td>&#160;</td></tr><tr><td class="number">108</td><td>   <a href="http://www.allegro.cc/manual/alert" target="_blank"><span class="a">alert</span></a><span class="k2">(</span>tmp,</td></tr><tr><td class="number">109</td><td>         <span class="k2">(</span><span class="k2">(</span>str<span class="k2">)</span> ? str <span class="k2">:</span> <span class="s">"Allegro: Unknown fatal exception occurred!"</span><span class="k2">)</span>,</td></tr><tr><td class="number">110</td><td>         <span class="s">"The program must be shutdown."</span>,</td></tr><tr><td class="number">111</td><td>         <span class="s">" &amp;Exit "</span>, NULL, <span class="s">'e'</span>, <span class="s">'x'</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">112</td><td><span class="k2">}</span></td></tr><tr><td class="number">113</td><td>&#160;</td></tr><tr><td class="number">114</td><td><span class="c">/* ----=== except.c end ===---- */</span></td></tr><tr><td class="number">115</td><td>&#160;</td></tr><tr><td class="number">116</td><td>&#160;</td></tr><tr><td class="number">117</td><td><span class="c">/* ----=== extry.c start ===---- */</span></td></tr><tr><td class="number">118</td><td><span class="c">/*</span></td></tr><tr><td class="number">119</td><td><span class="c"> *   Example program for simple Allegro exception handling.</span></td></tr><tr><td class="number">120</td><td><span class="c"> *   by Ron Novy</span></td></tr><tr><td class="number">121</td><td><span class="c"> *</span></td></tr><tr><td class="number">122</td><td><span class="c"> *   Try this, that, and everything... Try your patience ;)</span></td></tr><tr><td class="number">123</td><td><span class="c"> *   This example may go too far as it uses AL_TRY on everything including</span></td></tr><tr><td class="number">124</td><td><span class="c"> *   install_keyboard, install_mouse, ..., but it gives a good example of</span></td></tr><tr><td class="number">125</td><td><span class="c"> *   how it works and other ways you can use it.</span></td></tr><tr><td class="number">126</td><td><span class="c"> *</span></td></tr><tr><td class="number">127</td><td><span class="c"> */</span></td></tr><tr><td class="number">128</td><td>&#160;</td></tr><tr><td class="number">129</td><td>&#160;</td></tr><tr><td class="number">130</td><td><span class="p">#include &lt;allegro.h&gt;</span></td></tr><tr><td class="number">131</td><td>&#160;</td></tr><tr><td class="number">132</td><td>&#160;</td></tr><tr><td class="number">133</td><td>&#160;</td></tr><tr><td class="number">134</td><td><span class="c">/* simple function to just get into any gfx mode.</span></td></tr><tr><td class="number">135</td><td><span class="c"> * Returns TRUE if a mode was set or FALSE if an error occurred.</span></td></tr><tr><td class="number">136</td><td><span class="c"> */</span></td></tr><tr><td class="number">137</td><td><span class="k1">int</span> my_set_gfx_mode<span class="k2">(</span><span class="k1">int</span> width, <span class="k1">int</span> height<span class="k2">)</span></td></tr><tr><td class="number">138</td><td><span class="k2">{</span></td></tr><tr><td class="number">139</td><td>   <span class="k1">int</span> desk_depth <span class="k3">=</span> <a href="http://www.allegro.cc/manual/desktop_color_depth" target="_blank"><span class="a">desktop_color_depth</span></a><span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">140</td><td>&#160;</td></tr><tr><td class="number">141</td><td>   <span class="k1">if</span> <span class="k2">(</span>desk_depth <span class="k3">!</span><span class="k3">=</span> <span class="n">0</span><span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">142</td><td>      <a href="http://www.allegro.cc/manual/set_color_depth" target="_blank"><span class="a">set_color_depth</span></a><span class="k2">(</span>desk_depth<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">143</td><td>&#160;</td></tr><tr><td class="number">144</td><td>      <span class="k1">if</span> <span class="k2">(</span><a href="http://www.allegro.cc/manual/set_gfx_mode" target="_blank"><span class="a">set_gfx_mode</span></a><span class="k2">(</span>GFX_AUTODETECT, width, height, <span class="n">0</span>, <span class="n">0</span><span class="k2">)</span> <span class="k3">=</span><span class="k3">=</span> <span class="n">0</span><span class="k2">)</span></td></tr><tr><td class="number">145</td><td>         <span class="k1">return</span> TRUE<span class="k2">;</span></td></tr><tr><td class="number">146</td><td>   <span class="k2">}</span></td></tr><tr><td class="number">147</td><td>&#160;</td></tr><tr><td class="number">148</td><td>   <a href="http://www.allegro.cc/manual/set_color_depth" target="_blank"><span class="a">set_color_depth</span></a><span class="k2">(</span><span class="n">32</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">149</td><td>   <span class="k1">if</span> <span class="k2">(</span><a href="http://www.allegro.cc/manual/set_gfx_mode" target="_blank"><span class="a">set_gfx_mode</span></a><span class="k2">(</span>GFX_AUTODETECT, width, height, <span class="n">0</span>, <span class="n">0</span><span class="k2">)</span> <span class="k3">=</span><span class="k3">=</span> <span class="n">0</span><span class="k2">)</span></td></tr><tr><td class="number">150</td><td>      <span class="k1">return</span> TRUE<span class="k2">;</span></td></tr><tr><td class="number">151</td><td>&#160;</td></tr><tr><td class="number">152</td><td>   <a href="http://www.allegro.cc/manual/set_color_depth" target="_blank"><span class="a">set_color_depth</span></a><span class="k2">(</span><span class="n">24</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">153</td><td>   <span class="k1">if</span> <span class="k2">(</span><a href="http://www.allegro.cc/manual/set_gfx_mode" target="_blank"><span class="a">set_gfx_mode</span></a><span class="k2">(</span>GFX_AUTODETECT, width, height, <span class="n">0</span>, <span class="n">0</span><span class="k2">)</span> <span class="k3">=</span><span class="k3">=</span> <span class="n">0</span><span class="k2">)</span></td></tr><tr><td class="number">154</td><td>      <span class="k1">return</span> TRUE<span class="k2">;</span></td></tr><tr><td class="number">155</td><td>&#160;</td></tr><tr><td class="number">156</td><td>   <a href="http://www.allegro.cc/manual/set_color_depth" target="_blank"><span class="a">set_color_depth</span></a><span class="k2">(</span><span class="n">16</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">157</td><td>   <span class="k1">if</span> <span class="k2">(</span><a href="http://www.allegro.cc/manual/set_gfx_mode" target="_blank"><span class="a">set_gfx_mode</span></a><span class="k2">(</span>GFX_AUTODETECT, width, height, <span class="n">0</span>, <span class="n">0</span><span class="k2">)</span> <span class="k3">=</span><span class="k3">=</span> <span class="n">0</span><span class="k2">)</span></td></tr><tr><td class="number">158</td><td>      <span class="k1">return</span> TRUE<span class="k2">;</span></td></tr><tr><td class="number">159</td><td>&#160;</td></tr><tr><td class="number">160</td><td>   <a href="http://www.allegro.cc/manual/set_color_depth" target="_blank"><span class="a">set_color_depth</span></a><span class="k2">(</span><span class="n">15</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">161</td><td>   <span class="k1">if</span> <span class="k2">(</span><a href="http://www.allegro.cc/manual/set_gfx_mode" target="_blank"><span class="a">set_gfx_mode</span></a><span class="k2">(</span>GFX_AUTODETECT, width, height, <span class="n">0</span>, <span class="n">0</span><span class="k2">)</span> <span class="k3">=</span><span class="k3">=</span> <span class="n">0</span><span class="k2">)</span></td></tr><tr><td class="number">162</td><td>      <span class="k1">return</span> TRUE<span class="k2">;</span></td></tr><tr><td class="number">163</td><td>&#160;</td></tr><tr><td class="number">164</td><td>   <a href="http://www.allegro.cc/manual/set_color_depth" target="_blank"><span class="a">set_color_depth</span></a><span class="k2">(</span><span class="n">8</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">165</td><td>   <span class="k1">if</span> <span class="k2">(</span><a href="http://www.allegro.cc/manual/set_gfx_mode" target="_blank"><span class="a">set_gfx_mode</span></a><span class="k2">(</span>GFX_AUTODETECT, width, height, <span class="n">0</span>, <span class="n">0</span><span class="k2">)</span> <span class="k3">=</span><span class="k3">=</span> <span class="n">0</span><span class="k2">)</span></td></tr><tr><td class="number">166</td><td>      <span class="k1">return</span> TRUE<span class="k2">;</span></td></tr><tr><td class="number">167</td><td>&#160;</td></tr><tr><td class="number">168</td><td>   <span class="k1">return</span> FALSE<span class="k2">;</span></td></tr><tr><td class="number">169</td><td><span class="k2">}</span></td></tr><tr><td class="number">170</td><td>&#160;</td></tr><tr><td class="number">171</td><td>&#160;</td></tr><tr><td class="number">172</td><td>&#160;</td></tr><tr><td class="number">173</td><td><span class="k1">void</span> my_gui_exception_handler<span class="k2">(</span>AL_CONST <span class="k1">char</span> <span class="k3">*</span>str, AL_CONST <span class="k1">char</span> <span class="k3">*</span>file, <span class="k1">int</span> <a href="http://www.allegro.cc/manual/line" target="_blank"><span class="a">line</span></a><span class="k2">)</span></td></tr><tr><td class="number">174</td><td><span class="k2">{</span></td></tr><tr><td class="number">175</td><td>   <span class="k1">char</span> tmp<span class="k2">[</span><span class="n">1024</span><span class="k2">]</span><span class="k2">;</span> <span class="c">/* 1024 ?  Just make it work Bill. */</span></td></tr><tr><td class="number">176</td><td>&#160;</td></tr><tr><td class="number">177</td><td>   <a href="http://www.allegro.cc/manual/uszprintf" target="_blank"><span class="a">uszprintf</span></a><span class="k2">(</span>tmp, <span class="k1">sizeof</span><span class="k2">(</span>tmp<span class="k2">)</span>,</td></tr><tr><td class="number">178</td><td>             <span class="s">"My gui exception in file '%s' at line %d."</span>,</td></tr><tr><td class="number">179</td><td>             file, <a href="http://www.allegro.cc/manual/line" target="_blank"><span class="a">line</span></a><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">180</td><td>&#160;</td></tr><tr><td class="number">181</td><td>   <a href="http://www.allegro.cc/manual/alert" target="_blank"><span class="a">alert</span></a><span class="k2">(</span>tmp, str, <span class="s">"Just click OK to continue."</span>, <span class="s">" &amp;OK "</span>, NULL, <span class="s">'o'</span>, <span class="s">'k'</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">182</td><td><span class="k2">}</span></td></tr><tr><td class="number">183</td><td>&#160;</td></tr><tr><td class="number">184</td><td>&#160;</td></tr><tr><td class="number">185</td><td>&#160;</td></tr><tr><td class="number">186</td><td><span class="c">/* Custom define to make custom exceptions easier */</span></td></tr><tr><td class="number">187</td><td><span class="p">#define MY_AL_TRY_GUI(condition, str)                   \</span></td></tr><tr><td class="number">188</td><td><span class="p">   AL_TRY_EX(condition, str, my_gui_exception_handler) </span></td></tr><tr><td class="number">189</td><td>&#160;</td></tr><tr><td class="number">190</td><td>&#160;</td></tr><tr><td class="number">191</td><td>&#160;</td></tr><tr><td class="number">192</td><td><span class="k1">int</span> main<span class="k2">(</span><span class="k1">int</span> argc, <span class="k1">char</span> <span class="k3">*</span>argv<span class="k2">[</span><span class="k2">]</span><span class="k2">)</span></td></tr><tr><td class="number">193</td><td><span class="k2">{</span></td></tr><tr><td class="number">194</td><td>   <span class="k1">int</span> x <span class="k3">=</span> <span class="n">0</span>, y <span class="k3">=</span> <span class="n">1</span><span class="k2">;</span></td></tr><tr><td class="number">195</td><td>   </td></tr><tr><td class="number">196</td><td>   AL_TRY<span class="k2">(</span><a href="http://www.allegro.cc/manual/allegro_init" target="_blank"><span class="a">allegro_init</span></a><span class="k2">(</span><span class="k2">)</span>, <span class="s">"Could not initialize allegro!"</span><span class="k2">)</span></td></tr><tr><td class="number">197</td><td>   AL_TRY<span class="k2">(</span><a href="http://www.allegro.cc/manual/install_timer" target="_blank"><span class="a">install_timer</span></a><span class="k2">(</span><span class="k2">)</span>, <span class="s">"Could not install allegro timers!"</span><span class="k2">)</span></td></tr><tr><td class="number">198</td><td>   AL_TRY<span class="k2">(</span><a href="http://www.allegro.cc/manual/install_keyboard" target="_blank"><span class="a">install_keyboard</span></a><span class="k2">(</span><span class="k2">)</span>, <span class="s">"Could not install allegro keyboard driver!"</span><span class="k2">)</span></td></tr><tr><td class="number">199</td><td>   AL_TRY<span class="k2">(</span><a href="http://www.allegro.cc/manual/install_mouse" target="_blank"><span class="a">install_mouse</span></a><span class="k2">(</span><span class="k2">)</span> <span class="k3">=</span><span class="k3">=</span> <span class="k3">-</span><span class="n">1</span>, <span class="s">"Could not install allegro mouse driver!"</span><span class="k2">)</span></td></tr><tr><td class="number">200</td><td>&#160;</td></tr><tr><td class="number">201</td><td>   <span class="c">/* try to set a gfx mode */</span></td></tr><tr><td class="number">202</td><td>   AL_TRY<span class="k2">(</span><span class="k3">!</span>my_set_gfx_mode<span class="k2">(</span><span class="n">640</span>, <span class="n">480</span><span class="k2">)</span>, <a href="http://www.allegro.cc/manual/allegro_error" target="_blank"><span class="a">allegro_error</span></a><span class="k2">)</span></td></tr><tr><td class="number">203</td><td>&#160;</td></tr><tr><td class="number">204</td><td>&#160;</td></tr><tr><td class="number">205</td><td>   <span class="c">/* we're in graphics mode so try the gui exception handler */</span></td></tr><tr><td class="number">206</td><td>   AL_TRY_GUI<span class="k2">(</span>x <span class="k3">!</span><span class="k3">=</span> y, <span class="s">"'x' is not equal to 'y'."</span><span class="k2">)</span></td></tr><tr><td class="number">207</td><td>&#160;</td></tr><tr><td class="number">208</td><td>&#160;</td></tr><tr><td class="number">209</td><td>   <span class="c">/* make x equal to y */</span></td></tr><tr><td class="number">210</td><td>   x <span class="k3">=</span> y<span class="k2">;</span></td></tr><tr><td class="number">211</td><td>&#160;</td></tr><tr><td class="number">212</td><td>   <span class="c">/* now try our own little handler we defined above */</span></td></tr><tr><td class="number">213</td><td>   MY_AL_TRY_GUI<span class="k2">(</span>x <span class="k3">=</span><span class="k3">=</span> y, <span class="s">"'x' is equal to 'y'."</span><span class="k2">)</span></td></tr><tr><td class="number">214</td><td>&#160;</td></tr><tr><td class="number">215</td><td>&#160;</td></tr><tr><td class="number">216</td><td>   <span class="c">/* now show the unknown exception message */</span></td></tr><tr><td class="number">217</td><td>   AL_TRY<span class="k2">(</span>x <span class="k3">=</span><span class="k3">=</span> y, NULL<span class="k2">)</span></td></tr><tr><td class="number">218</td><td>&#160;</td></tr><tr><td class="number">219</td><td>   <span class="c">/* this next bit of code should never execute */</span></td></tr><tr><td class="number">220</td><td>   <a href="http://www.allegro.cc/manual/alert" target="_blank"><span class="a">alert</span></a><span class="k2">(</span><span class="s">"We made it?"</span>,</td></tr><tr><td class="number">221</td><td>         <span class="s">"How on earth did that happen?"</span>,</td></tr><tr><td class="number">222</td><td>         <span class="s">"This code should be unreachable in extry.c"</span>,</td></tr><tr><td class="number">223</td><td>         <span class="s">"&amp;OK"</span>, NULL, <span class="s">'o'</span>, <span class="s">'k'</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">224</td><td>&#160;</td></tr><tr><td class="number">225</td><td>   <span class="k1">return</span> <span class="n">0</span><span class="k2">;</span></td></tr><tr><td class="number">226</td><td><span class="k2">}</span></td></tr><tr><td class="number">227</td><td><a href="http://www.allegro.cc/manual/END_OF_MAIN" target="_blank"><span class="a">END_OF_MAIN</span></a><span class="k2">(</span><span class="k2">)</span></td></tr><tr><td class="number">228</td><td>&#160;</td></tr><tr><td class="number">229</td><td><span class="c">/* ----=== extry.c end ===---- */</span></td></tr></tbody></table></div></div><p>

Any way check it out, compile it then let me know what you think.</p><p>[EDIT] I attached a new version that does a lot of ascii-&gt;current text format conversions.  I&#39;m not sure if they would be necessary but it works just as well.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Ron Novy)</author>
		<pubDate>Thu, 15 Jun 2006 00:09:32 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>I dont really see how that helps. What if you want to perform some cleanup at the end of a block of code?</p><div class="source-code snippet"><div class="inner"><pre>FILE <span class="k3">*</span> f <span class="k3">=</span> <a href="http://www.delorie.com/djgpp/doc/libc/libc_337.html" target="_blank">fopen</a><span class="k2">(</span> <span class="s">"foobar"</span> <span class="k2">)</span><span class="k2">;</span>
<span class="k1">try</span><span class="k2">{</span>
  method1<span class="k2">(</span>f<span class="k2">)</span><span class="k2">;</span> <span class="c">// could throw error</span>
  method2<span class="k2">(</span>f<span class="k2">)</span><span class="k2">;</span> <span class="c">// could throw error</span>
  method3<span class="k2">(</span>f<span class="k2">)</span><span class="k2">;</span> <span class="c">// could throw error</span>
  <span class="k1">return</span> f<span class="k2">;</span>
<span class="k2">}</span> <span class="k1">catch</span> <span class="k2">(</span> whatever <span class="k2">)</span><span class="k2">{</span>
   <a href="http://www.delorie.com/djgpp/doc/libc/libc_308.html" target="_blank">fclose</a><span class="k2">(</span> f <span class="k2">)</span><span class="k2">;</span>
<span class="k2">}</span>
<span class="k1">return</span> NULL<span class="k2">;</span>
</pre></div></div><p>

How can you emulate that by putting a TRY{} thing around each statement? The point is to put all of the error code in one place.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (kazzmir)</author>
		<pubDate>Thu, 15 Jun 2006 04:26:45 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>There seems to be a question over whether setjmp/longjmp is actually safe to use with local variables lying around. As I understand it, local variables are supposed to be on the stack, and can be put into registers for speed optimizations. Since they&#39;re supposed to be on the stack, I&#39;d think the compiler would be smart enough to not do anything dangerous around setjmp/longjmp that would compromise that (eg. copying vars from registers into the proper stack location before longjmp completes, and having the vars reloaded from the stack into the proper registers before setjmp returns non-0). Does anyone have any info that might clear this up?</p><p>Also another idea might be to include a C++ exception throwing callback for errors (eg. an error occurs, Allegro calls a callback, etc), and have an al_init option to use it by default. However, the issue with that seems to be thus:
</p><ul><li><p>You need -fexceptions to be able to throw exceptions from C++, through C code, and back to C++, using GCC. Do other compilers support a similar option?</p></li><li><p>MSVC vs GCC. Would throwing an exception from GCC-generated code through an MSVC DLL (or vice-versa) cause problems?</p></li></ul><p>&lt;/li&gt;
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Kitty Cat)</author>
		<pubDate>Thu, 15 Jun 2006 06:46:38 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>I&#39;ve always been suspicious of libraries that try to over extend the language into something it&#39;s not. I think if someone really wants exception handling, they should use C++ and a wrapper over Allegro that provides that. And yes, I realize that doesn&#39;t help out people writing core Allegro routines.</p><p>But if your proposed system did work on every compiler under all situations, I wouldn&#39;t see any harm in it. I&#39;d still think it didn&#39;t belong, but I&#39;m not the one writing code...
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Matthew Leverton)</author>
		<pubDate>Thu, 15 Jun 2006 08:28:19 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
There seems to be a question over whether setjmp/longjmp is actually safe to use with local variables lying around.
</p></div></div><p>

It&#39;s not a question.  Try this program:</p><div class="source-code"><div class="toolbar"></div><div class="inner"><table width="100%"><tbody><tr><td class="number">1</td><td><span class="p">#include &lt;setjmp.h&gt;</span></td></tr><tr><td class="number">2</td><td><span class="p">#include &lt;stdio.h&gt;</span></td></tr><tr><td class="number">3</td><td>&#160;</td></tr><tr><td class="number">4</td><td>jmp_buf env<span class="k2">;</span></td></tr><tr><td class="number">5</td><td>&#160;</td></tr><tr><td class="number">6</td><td><span class="k1">int</span> f<span class="k2">(</span><span class="k1">void</span><span class="k2">)</span></td></tr><tr><td class="number">7</td><td><span class="k2">{</span></td></tr><tr><td class="number">8</td><td>    <span class="k1">int</span> c <span class="k3">=</span> <span class="n">0</span><span class="k2">;</span></td></tr><tr><td class="number">9</td><td>    <span class="k1">if</span> <span class="k2">(</span><a href="http://www.delorie.com/djgpp/doc/libc/libc_703.html" target="_blank">setjmp</a><span class="k2">(</span>env<span class="k2">)</span><span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">10</td><td>        <span class="k1">return</span> c<span class="k2">;</span></td></tr><tr><td class="number">11</td><td>    <span class="k2">}</span> <span class="k1">else</span> <span class="k2">{</span></td></tr><tr><td class="number">12</td><td>        c<span class="k3">+</span><span class="k3">+</span><span class="k2">;</span></td></tr><tr><td class="number">13</td><td>        <a href="http://www.delorie.com/djgpp/doc/libc/libc_546.html" target="_blank">longjmp</a><span class="k2">(</span>env, <span class="n">1</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">14</td><td>    <span class="k2">}</span></td></tr><tr><td class="number">15</td><td><span class="k2">}</span></td></tr><tr><td class="number">16</td><td>&#160;</td></tr><tr><td class="number">17</td><td><span class="k1">int</span> main<span class="k2">(</span><span class="k1">void</span><span class="k2">)</span></td></tr><tr><td class="number">18</td><td><span class="k2">{</span></td></tr><tr><td class="number">19</td><td>    <a href="http://www.delorie.com/djgpp/doc/libc/libc_624.html" target="_blank">printf</a><span class="k2">(</span><span class="s">"%d\n"</span>, f<span class="k2">(</span><span class="k2">)</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">20</td><td>    <span class="k1">return</span> <span class="n">0</span><span class="k2">;</span></td></tr><tr><td class="number">21</td><td><span class="k2">}</span></td></tr></tbody></table></div></div><p>

On my system, compiling with `gcc -O0&#39; prints &quot;0&quot;. Compiling with `gcc -O&#39; or above prints &quot;1&quot;.  You really do need to declare `c&#39; as `volatile&#39;.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Peter Wang)</author>
		<pubDate>Thu, 15 Jun 2006 08:47:34 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Of course, if allegro were to use c++, this whole chain of arguments would be a nonissue. (Or better yet, the core allegro code is in C, then a C++ wrapper is written to interact with the &quot;core&quot; (Depending on design, one could even write a C wrapper as well that abstracts some of the technicalities away from the core)).  So, you basically make the core library require as verbose of arguments as possible (don&#39;t assume things based on previous settings and such unless the function&#39;s nature requires it), and write wrappers to abstract things away from the complicated core library (so, for example, in the core library, you might only have one version of create_bitmap, that takes width, height, and color depth arguments.  The wrapper library can handle global colordepths externally to the core library).
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Carrus85)</author>
		<pubDate>Thu, 15 Jun 2006 11:16:14 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>I&#39;m not sure if setjump is thread-safe though.  Imagine that multiple threads tried to use setjump at the same time. The results would then be undefined.  After my previous post I searched through allegro.c and discovered that my code was very similar to allegro&#39;s ASSERT code.  Maybe there could be a solution that would jump using a #define macro instead of calling a function directly.</p><div class="source-code"><div class="toolbar"></div><div class="inner"><table width="100%"><tbody><tr><td class="number">1</td><td><span class="p">#define AL_TRY(condition, jump) \</span></td></tr><tr><td class="number">2</td><td><span class="p">   if (!(condition))            \ </span></td></tr><tr><td class="number">3</td><td><span class="p">      goto jump; </span></td></tr><tr><td class="number">4</td><td>&#160;</td></tr><tr><td class="number">5</td><td><span class="k1">int</span> myfunc<span class="k2">(</span><span class="k1">int</span> stuff<span class="k2">)</span></td></tr><tr><td class="number">6</td><td><span class="k2">{</span></td></tr><tr><td class="number">7</td><td>   <span class="c">/* instead of assert which compiles to nothing in non-debug versions */</span></td></tr><tr><td class="number">8</td><td>   AL_TRY<span class="k2">(</span>stuff, myfunc_exception<span class="k2">)</span></td></tr><tr><td class="number">9</td><td>   <span class="k1">return</span> TRUE<span class="k2">;</span> <span class="c">/* All is well */</span></td></tr><tr><td class="number">10</td><td>&#160;</td></tr><tr><td class="number">11</td><td>myfunc_exception:</td></tr><tr><td class="number">12</td><td>   my_exception_message_proc<span class="k2">(</span><span class="s">"An exception occurred!"</span>, __FILE__, __LINE__<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">13</td><td>   <span class="k1">return</span> FALSE<span class="k2">;</span></td></tr><tr><td class="number">14</td><td><span class="k2">}</span></td></tr></tbody></table></div></div><p>

[edit]<br />It&#39;s simple and pretty much the same is programming without AL_TRY but this way you get cleaner looking code with the c++ style you might be looking for.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Ron Novy)</author>
		<pubDate>Sat, 17 Jun 2006 06:39:59 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
I&#39;m not sure if setjump is thread-safe though.
</p></div></div><p>Which is why the OP suggested TLS (thread local storage, aka __thread) allong with set/longjmp.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Thomas Fjellstrom)</author>
		<pubDate>Sat, 17 Jun 2006 06:44:07 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>One of the things I was going for was a clean code execution path. So you could run some code, if it errors, stop and run some cleanup code, then continue running code. eg:
</p><div class="source-code snippet"><div class="inner"><pre>al_audio_init<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span>
al_create_voices<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span>
<span class="k1">if</span> there was an error
<span class="k2">{</span>
   al_audio_close<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span>
   warn<span class="k2">(</span><span class="s">"no sound!"</span><span class="k2">)</span><span class="k2">;</span>
<span class="k2">}</span>

more_code_here<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span>
</pre></div></div><p>
Of course, if the first function fails, you don&#39;t want to run the second. But in either case, you want to run the same error handling code, then continue on whether there was an error or not.</p><p>As well, for newbies or someone who just wants to quickly get something down, you&#39;re not going to want or know to tediously check every function for errors, so having a simple way to automatically catch errors for you, at least in the beginning, would be very helpful.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Kitty Cat)</author>
		<pubDate>Sat, 17 Jun 2006 07:01:18 +0000</pubDate>
	</item>
</rss>
