├── .gitattributes ├── .github ├── FUNDING.yml └── workflows │ └── main.yml ├── .gitignore ├── .gitmodules ├── README.md ├── docs ├── CException.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md └── ThrowTheSwitchCodingStandard.md ├── lib ├── CException.c ├── CException.h └── meson.build ├── license.txt ├── meson.build ├── project.yml └── test ├── TestException.c └── support └── CExceptionConfig.h /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | # These files are text and should be normalized (convert crlf to lf) 4 | *.rb text 5 | *.test text 6 | *.c text 7 | *.cpp text 8 | *.h text 9 | *.txt text 10 | *.yml text 11 | *.s79 text 12 | *.bat text 13 | *.xcl text 14 | *.inc text 15 | *.info text 16 | *.md text 17 | makefile text 18 | rakefile text 19 | 20 | 21 | #These files are binary and should not be normalized 22 | *.doc binary 23 | *.odt binary 24 | *.pdf binary 25 | *.ewd binary 26 | *.eww binary 27 | *.dni binary 28 | *.wsdt binary 29 | *.dbgdt binary 30 | *.mac binary 31 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: ThrowTheSwitch 2 | #patreon: # Replace with a single Patreon username 3 | #open_collective: # Replace with a single Open Collective username 4 | #ko_fi: # Replace with a single Ko-fi username 5 | #tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 6 | #community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 7 | #liberapay: # Replace with a single Liberapay username 8 | #issuehunt: # Replace with a single IssueHunt username 9 | #lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 10 | #polar: # Replace with a single Polar username 11 | #buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 12 | #thanks_dev: # Replace with a single thanks.dev username 13 | #custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Continuous Integration Workflow: Test case suite run + validation build check 3 | name: CI 4 | 5 | # Controls when the action will run. 6 | # Triggers the workflow on push or pull request events but only for the master branch 7 | on: 8 | push: 9 | branches: [ master ] 10 | pull_request: 11 | branches: [ master ] 12 | 13 | jobs: 14 | # Job: Unit test suite 15 | unit-tests: 16 | name: "Unit Tests" 17 | runs-on: ubuntu-latest 18 | steps: 19 | # Checks out repository under $GITHUB_WORKSPACE 20 | - name: Checkout Latest Repo 21 | uses: actions/checkout@v4 22 | with: 23 | submodules: recursive 24 | 25 | # Install Ceedling 26 | - name: Install Ceedling 27 | run: | 28 | sudo gem install ceedling 29 | 30 | # Run Tests 31 | - name: Run All Self Tests 32 | run: | 33 | ceedling clobber test:all 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *.sublime-* -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThrowTheSwitch/CException/37673b75954b33ebd593d180993c64d3bef45bc0/.gitmodules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CException ![CI](https://github.com/ThrowTheSwitch/CException/workflows/CI/badge.svg) 2 | ========== 3 | 4 | _This Documentation Is Released Under a Creative Commons 3.0 Attribution Share-Alike License_ 5 | 6 | CException is simple exception handling in C. It is significantly faster than full-blown C++ exception handling 7 | but loses some flexibility. It is portable to any platform supporting `setjmp`/`longjmp`. 8 | 9 | Getting Started 10 | ================ 11 | 12 | The simplest way to get started is to just grab the code and pull it into your project: 13 | 14 | ``` 15 | git clone https://github.com/throwtheswitch/cexception.git 16 | ``` 17 | 18 | If you want to contribute to this project, you'll also need to have Ruby and Ceedling installed to run the unit tests. 19 | 20 | Usage 21 | ===== 22 | 23 | ### So what's it good for? 24 | 25 | Mostly error handling. Passing errors down a long chain of function calls gets ugly. Sometimes really ugly. 26 | So what if you could just specify certain places where you want to handle errors, and all your errors were 27 | transferred there? Let's try a lame example: 28 | 29 | CException uses C standard library functions setjmp and longjmp to operate. As long as the target system 30 | has these two functions defined, this library should be useable with very little configuration. It even 31 | supports environments where multiple program flows are in use, such as real-time operating systems... 32 | we started this project for use in embedded systems... but it obviously can be used for larger systems too. 33 | 34 | ### Error Handling with CException: 35 | 36 | ``` 37 | void functionC(void) { 38 | //do some stuff 39 | if (there_was_a_problem) 40 | Throw(ERR_BAD_BREATH); 41 | //this stuff never gets called because of error 42 | } 43 | ``` 44 | 45 | There are about a gajillion exception frameworks using a similar setjmp/longjmp method out there... and there 46 | will probably be more in the future. Unfortunately, when we started our last embedded project, all those that 47 | existed either (a) did not support multiple tasks (therefore multiple stacks) or (b) were way more complex 48 | than we really wanted. CException was born. 49 | 50 | Why? 51 | ==== 52 | 53 | ### It's ANSI C 54 | 55 | ...and it beats passing error codes around. 56 | 57 | ### You want something simple... 58 | 59 | CException throws a single id. You can define those ID's to be whatever you like. 60 | You might even choose which type that number is for your project. But that's as far as it goes. We weren't interested 61 | in passing objects or structs or strings... just simple error codes. Fast. Easy to Use. Easy to Understand. 62 | 63 | ### Performance... 64 | 65 | CException can be configured for single tasking or multitasking. In single tasking, there is 66 | very little overhead past the setjmp/longjmp calls (which are already fast). In multitasking, your only additional 67 | overhead is the time it takes you to determine a unique task id (0 to num_tasks). 68 | 69 | How? 70 | ==== 71 | 72 | Code that is to be protected are wrapped in `Try { }` blocks. The code inside the Try block is _protected_, 73 | meaning that if any Throws occur, program control is directly transferred to the start of the Catch block. 74 | The Catch block immediately follows the Try block. It's ignored if no errors have occurred. 75 | 76 | A numerical exception ID is included with Throw, and is passed into the Catch block. This allows you to handle 77 | errors differently or to report which error has occurred... or maybe it just makes debugging easier so you 78 | know where the problem was Thrown. 79 | 80 | Throws can occur from anywhere inside the Try block, directly in the function you're testing or even within 81 | function calls (nested as deeply as you like). There can be as many Throws as you like, just remember that 82 | execution of the guts of your Try block ends as soon as the first Throw is triggered. Once you throw, you're 83 | transferred to the Catch block. A silly example: 84 | 85 | ``` 86 | void SillyExampleWhichPrintsZeroThroughFive(void) { 87 | volatile CEXCEPTION_T e; 88 | int i; 89 | while (i = 0; i < 6; i++) { 90 | Try { 91 | Throw(i); 92 | //This spot is never reached 93 | } 94 | Catch(e) { 95 | printf(“%i “, e); 96 | } 97 | } 98 | } 99 | ``` 100 | 101 | Limitations 102 | =========== 103 | 104 | This library was made to be as fast as possible, and provide basic exception handling. It is not a full-blown 105 | exception library like C++. Because of this, there are a few limitations that should be observed in order to 106 | successfully utilize this library: 107 | 108 | ### Return & Goto 109 | 110 | Do not directly `return` from within a `Try` block, nor `goto` into or out of a `Try` block. 111 | The `Try` macro allocates some local memory and alters a global pointer. These are cleaned up at the 112 | top of the `Catch` macro. Gotos and returns would bypass some of these steps, resulting in memory leaks 113 | or unpredictable behavior. 114 | 115 | ### Local Variables 116 | 117 | If (a) you change local (stack) variables within your `Try` block, and (b) wish to make use of the updated 118 | values after an exception is thrown, those variables should be made `volatile`. 119 | 120 | Note that this is ONLY for locals and ONLY when you need access to them after a `Throw`. 121 | 122 | Compilers optimize (and thank goodness they do). There is no way to guarantee that the actual memory 123 | location was updated and not just a register unless the variable is marked volatile. 124 | 125 | ### Memory Management 126 | 127 | Memory which is `malloc`'d within a `Try` block is not automatically released when an error is thrown. This 128 | will sometimes be desirable, and other times may not. It will be the responsibility of the code you put in 129 | the `Catch` block to perform this kind of cleanup. 130 | 131 | There's just no easy way to track `malloc`'d memory, etc., without replacing or wrapping `malloc` 132 | calls or something like that. This is a lightweight framework, so these options were not desirable. 133 | 134 | CException API 135 | ============== 136 | 137 | ### `Try { ... }` 138 | 139 | `Try` is a macro which starts a protected block. It MUST be followed by a pair of braces or a single 140 | protected line (similar to an 'if'), enclosing the data that is to be protected. It MUST be followed by 141 | a `Catch` block (don't worry, you'll get compiler errors to let you know if you mess any of that up). 142 | 143 | The `Try` block is your protected block. It contains your main program flow, where you can ignore errors 144 | (other than a quick `Throw` call). You may nest multiple `Try` blocks if you want to handle errors at 145 | multiple levels, and you can even rethrow an error from within a nested `Catch`. 146 | 147 | ### `Catch(e) { }` 148 | 149 | `Catch` is a macro which ends the `Try` block and starts the error handling block. The `Catch` block 150 | is executed if and only if an exception was thrown while within the `Try` block. This error was thrown 151 | by a `Throw` call somewhere within `Try` (or within a function called within `Try`, or a function called 152 | by a function called within `Try`... you get the idea.). 153 | 154 | `Catch` receives a single id of type `CEXCEPTION_T` which you can ignore or use to handle the error in 155 | some way. You may throw errors from within Catches, but they will be caught by a `Try` wrapping the `Catch`, 156 | not the one immediately preceeding. 157 | 158 | ### `Throw(e)` 159 | 160 | `Throw` is the method used to throw an error. `Throw`s should only occur from within a protected 161 | (`Try`...`Catch`) block, though it may easily be nested many function calls deep without an impact 162 | on performance or functionality. `Throw` takes a single argument, which is an exception id which will be 163 | passed to `Catch` as the reason for the error. If you wish to _re-throw_ an error, this can be done by 164 | calling `Throw(e)` with the error code you just caught. It _IS_ valid to throw from a `Catch` block. 165 | 166 | ### `ExitTry()` 167 | 168 | `ExitTry` is a method used to immediately exit your current Try block but NOT treat this as an error. Don't 169 | run the Catch. Just start executing from after the Catch as if nothing had happened. 170 | 171 | Configuration 172 | ============= 173 | 174 | CException is a mostly portable library. It has one universal dependency, plus some macros which are required if 175 | working in a multi-tasking environment. 176 | 177 | The standard C library setjmp must be available. Since this is part of the standard library, it's all good. 178 | 179 | If working in a multitasking environment, you need a stack frame for each task. Therefore, you must define 180 | methods for obtaining an index into an array of frames and to get the overall number of id's are required. If 181 | the OS supports a method to retrieve task ID's, and those tasks are number 0, 1, 2... you are in an ideal 182 | situation. Otherwise, a more creative mapping function may be required. Note that this function is likely to 183 | be called twice for each protected block and once during a throw. This is the only added overhead in the system. 184 | 185 | You have options for configuring the library, if the defaults aren't good enough for you. You can add defines 186 | at the command prompt directly. You can always include a configuration file before including `CException.h`. 187 | You can make sure `CEXCEPTION_USE_CONFIG_FILE` is defined, which will force make CException look for 188 | `CExceptionConfig.h`, where you can define whatever you like. However you do it, you can override any or 189 | all of the following: 190 | 191 | ### `CEXCEPTION_T` 192 | 193 | Set this to the type you want your exception id's to be. Defaults to an 'unsigned int'. 194 | 195 | ### `CEXCEPTION_NONE` 196 | 197 | Set this to a number which will never be an exception id in your system. Defaults to `0x5a5a5a5a`. 198 | 199 | ### `CEXCEPTION_GET_ID` 200 | 201 | If in a multi-tasking environment, this should be set to be a call to the function described in #2 above. 202 | It defaults to just return 0 all the time (good for single tasking environments, not so good otherwise). 203 | 204 | ### `CEXCEPTION_NUM_ID` 205 | 206 | If in a multi-tasking environment, this should be set to the number of ID's required (usually the number 207 | of tasks in the system). Defaults to 1 (good for single tasking environments or systems where you will only 208 | use this from one task). 209 | 210 | ### `CEXCEPTION_NO_CATCH_HANDLER (id)` 211 | 212 | This macro can be optionally specified. It allows you to specify code to be called when a Throw is made 213 | outside of Try...Catch protection. Consider this the emergency fallback plan for when something has gone 214 | terribly wrong. 215 | 216 | ### And More! 217 | 218 | You may also want to include any header files which will commonly be needed by the rest of your application 219 | where it uses exception handling here. For example, OS header files or exception codes would be useful. 220 | 221 | Finally, there are some hook macros which you can implement to inject your own target-specific code in 222 | particular places. It is a rare instance where you will need these, but they are here if you need them: 223 | 224 | * `CEXCEPTION_HOOK_START_TRY` - called immediately before the Try block 225 | * `CEXCEPTION_HOOK_HAPPY_TRY` - called immediately after the Try block if no exception was thrown 226 | * `CEXCEPTION_HOOK_AFTER_TRY` - called immediately after the Try block OR before an exception is caught 227 | * `CEXCEPTION_HOOK_START_CATCH` - called immediately before the catch 228 | 229 | Testing 230 | ======= 231 | 232 | If you want to validate that CException works with your tools or that it works with your custom 233 | configuration, you may want to run the included test suite. This is the test suite (along with real 234 | projects we've used it on) that we use to make sure that things actually work the way we claim. 235 | The test suite makes use of Ceedling, which uses the Unity Test Framework. It will require a native C compiler. 236 | The example makefile and rakefile both use gcc. 237 | -------------------------------------------------------------------------------- /docs/CException.md: -------------------------------------------------------------------------------- 1 | CException 2 | ========== 3 | 4 | CException is a basic exception framework for C, suitable for use in 5 | embedded applications. It provides an exception framework similar in 6 | use to C++, but with much less overhead. 7 | 8 | CException uses C standard library functions `setjmp` and `longjmp` to 9 | operate. As long as the target system has these two functions defined, 10 | this library should be useable with very little configuration. It 11 | even supports environments where multiple program flows are in use, 12 | such as real-time operating systems. 13 | 14 | There are about a gabillion exception frameworks using a similar 15 | setjmp/longjmp method out there... and there will probably be more 16 | in the future. Unfortunately, when we started our last embedded 17 | project, all those that existed either (a) did not support multiple 18 | tasks (therefore multiple stacks) or (b) were way more complex than 19 | we really wanted. CException was born. 20 | 21 | *Why use CException?* 22 | 23 | 0. It's ANSI C, and it beats passing error codes around. 24 | 1. You want something simple... CException throws a single id. You can 25 | define those ID's to be whatever you like. You might even choose which 26 | type that number is for your project. But that's as far as it goes. 27 | We weren't interested in passing objects or structs or strings... 28 | just simple error codes. 29 | 2. Performance... CException can be configured for single tasking or 30 | multitasking. In single tasking, there is very little overhead past 31 | the setjmp/longjmp calls (which are already fast). In multitasking, 32 | your only additional overhead is the time it takes you to determine 33 | a unique task id 0 - num_tasks. 34 | 35 | For the latest version, go to [ThrowTheSwitch.org](http://throwtheswitch.org) 36 | 37 | CONTENTS OF THIS DOCUMENT 38 | ========================= 39 | 40 | * Usage 41 | * Limitations 42 | * API 43 | * Configuration 44 | * Testing 45 | * License 46 | 47 | 48 | Usage 49 | ----- 50 | 51 | Code that is to be protected are wrapped in `Try { } Catch { }` blocks. 52 | The code directly following the Try call is "protected", meaning that 53 | if any Throws occur, program control is directly transferred to the 54 | start of the Catch block. 55 | 56 | A numerical exception ID is included with Throw, and is made accessible 57 | from the Catch block. 58 | 59 | Throws can occur from within function calls (nested as deeply as you 60 | like) or directly from within the function itself. 61 | 62 | Limitations 63 | ----------- 64 | 65 | This library was made to be as fast as possible, and provide basic 66 | exception handling. It is not a full-blown exception library. Because 67 | of this, there are a few limitations that should be observed in order 68 | to successfully utilize this library: 69 | 70 | 1. Do not directly "return" from within a `Try` block, nor `goto` 71 | into or out of a `Try` block. 72 | 73 | *Why?* 74 | 75 | The `Try` macro allocates some local memory and alters a global 76 | pointer. These are cleaned up at the top of the `Catch` macro. 77 | Gotos and returns would bypass some of these steps, resulting in 78 | memory leaks or unpredictable behavior. 79 | 80 | 81 | 2. If (a) you change local (stack) variables within your `Try` block, 82 | AND (b) wish to make use of the updated values after an exception 83 | is thrown, those variables should be made `volatile`. Note that this 84 | is ONLY for locals and ONLY when you need access to them after a 85 | `Throw`. 86 | 87 | *Why?* 88 | 89 | Compilers optimize. There is no way to guarantee that the actual 90 | memory location was updated and not just a register unless the 91 | variable is marked volatile. 92 | 93 | As an example, if we had the following code, the value `b` is 94 | very likely at risk. It is assigned to the value `3` inside the 95 | `Try` block, but the compiler may or may not have written that 96 | variable to an actual memory location when the Throw happens. If 97 | it did, the `printf` will have a `3` for the second value. If not, 98 | it will still have a `0`. Changing `b` to `volatile` would 99 | guarantee it is the correct value. 100 | 101 | ``` 102 | void func(int *a) 103 | { 104 | // ... 105 | int b = 0; 106 | Try { 107 | *a += 2; 108 | b = *a; 109 | Throw(MY_EX); 110 | } Catch(e) { 111 | // ... 112 | } 113 | printf("%d ?= %d", a, b); 114 | } 115 | void main() 116 | { 117 | int x = 1; 118 | func(&x); 119 | printf("%d", x); 120 | } 121 | ``` 122 | 123 | With most compilers, the `*a` and `x` values are NOT at risk. 124 | We're dereferencing the pointer, which usually will force 125 | memory interaction. Optimizing compilers DO optimize, though, 126 | and it IS possible that even these values may have been cached 127 | and not written to the final memory location. In those instances, 128 | they would both report `1`. 129 | 130 | If you have a lot of situations like this and a strong optimizing 131 | compiler, it is best to reduce the optimization level when using 132 | CException. 133 | 134 | 3. Memory which is `malloc`'d or `new`'d is not automatically released 135 | when an error is thrown. This will sometimes be desirable, and 136 | other times may not. It will be the responsibility of the `Catch` 137 | block to perform this kind of cleanup. 138 | 139 | *Why?* 140 | 141 | There's just no easy way to track `malloc`'d memory, etc., without 142 | replacing or wrapping malloc calls or something like that. This 143 | is a light framework, so these options were not desirable. 144 | 145 | API 146 | --- 147 | 148 | ###Try 149 | 150 | `Try` is a macro which starts a protected block. It MUST be followed by 151 | a pair of braces or a single protected line (similar to an 'if'), 152 | enclosing the data that is to be protected. It **must** be followed by a 153 | `Catch` block (don't worry, you'll get compiler errors to let you know if 154 | you mess any of that up). 155 | 156 | 157 | ###Catch(e) 158 | 159 | `Catch` is a macro which ends the `Try` block and starts the error handling 160 | block. The `Catch` block is called if and only if an exception was thrown 161 | while within the `Try` block. This error was thrown by a `Throw` call 162 | somewhere within `Try` (or within a function called within `Try`, or a function 163 | called by a function called within `Try`, etc). 164 | 165 | The single parameter `e` is filled with the error code which was thrown. 166 | This can be used for reporting, conditional cleanup, etc. (or you can just 167 | ignore it if you really want... people ignore return codes all the time, 168 | right?). `e` should be of type `EXCEPTION_T` 169 | 170 | 171 | ###Throw(e) 172 | 173 | This is the method of throwing an error. A `Throw` should only occur from within a 174 | protected (`Try` ... `Catch`) block, though it may easily be nested many function 175 | calls deep without an impact on performance or functionality. `Throw` takes 176 | a single argument, which is an exception id which will be passed to `Catch` 177 | as the reason for the error. 178 | 179 | If you wish to rethrow an error, this can be done by calling `Throw(e)` with 180 | the error code you just caught. It **is** valid to throw from a catch block. 181 | 182 | 183 | ###ExitTry() 184 | 185 | On rare occasion, you might want to immediately exit your current `Try` block 186 | but **not** treat this as an error. Don't run the `Catch`. Just start executing 187 | from after the `Catch` as if nothing had happened... That's what `ExitTry` is 188 | for. 189 | 190 | 191 | CONFIGURATION 192 | ------------- 193 | 194 | CException is a mostly portable library. It has one universal 195 | dependency, and some macros which are required if working in a 196 | multi-tasking environment. 197 | 198 | 1. The standard C library setjmp must be available. Since this is part 199 | of the standard library, chances are good that you'll be fine. 200 | 201 | 2. If working in a multitasking environment, methods for obtaining an 202 | index into an array of frames and to get the overall number of 203 | id's are required. If the OS supports a method to retrieve Task 204 | ID's, and those Tasks are number 0, 1, 2... you are in an ideal 205 | situation. Otherwise, a more creative mapping function may be 206 | required. Note that this function is likely to be called twice 207 | for each protected block and once during a throw. This is the 208 | only overhead in the system. 209 | 210 | 211 | Exception.h 212 | ----------- 213 | 214 | By convention, most projects include `Exception.h` which defines any 215 | further requirements, then calls `CException.h` to do the gruntwork. All 216 | of these are optional. You could directly include `CException.h` if 217 | you wanted and just use the defaults provided. 218 | 219 | * `CEXCEPTION_T` 220 | * Set this to the type you want your exception id's to be. Defaults to 'unsigned int'. 221 | 222 | * `CEXCEPTION_NONE` 223 | * Set this to a number which will never be an exception id in your system. Defaults to `0x5a5a5a5a`. 224 | 225 | * `CEXCEPTION_GET_ID` 226 | * If in a multi-tasking environment, this should be 227 | set to be a call to the function described in #2 above. 228 | Defaults to just return `0` all the time (good for 229 | single tasking environments) 230 | 231 | * `CEXCEPTION_NUM_ID` 232 | * If in a multi-tasking environment, this should be set 233 | to the number of ID's required (usually the number of 234 | tasks in the system). Defaults to `1` (for single 235 | tasking environments). 236 | 237 | * `CEXCEPTION_NO_CATCH_HANDLER(id)` 238 | * This macro can be optionally specified. 239 | It allows you to specify code to be called when a Throw 240 | is made outside of `Try` ... `Catch` protection. Consider 241 | this the emergency fallback plan for when something has 242 | gone terribly wrong. 243 | 244 | You may also want to include any header files which will commonly be 245 | needed by the rest of your application where it uses exception handling 246 | here. For example, OS header files or exception codes would be useful. 247 | 248 | 249 | Finally, there are some hook macros which you can implement to inject 250 | your own target-specific code in particular places. It is a rare instance 251 | where you will need these, but they are here if you need them: 252 | 253 | 254 | * `CEXCEPTION_HOOK_START_TRY` 255 | * called immediately before the Try block 256 | 257 | * `CEXCEPTION_HOOK_HAPPY_TRY` 258 | * called immediately after the Try block if no exception was thrown 259 | 260 | * `CEXCEPTION_HOOK_AFTER_TRY` 261 | * called immediately after the Try block OR before an exception is caught 262 | 263 | * `CEXCEPTION_HOOK_START_CATCH` 264 | * called immediately before the catch 265 | 266 | 267 | TESTING 268 | ------- 269 | 270 | If you want to validate that CException works with your tools or that 271 | it works with your custom configuration, you may want to run the test 272 | suite. 273 | 274 | 275 | The test suite included makes use of the `Unity` Test Framework. It will 276 | require a native C compiler. The example makefile uses MinGW's gcc. 277 | Modify the makefile to include the proper paths to tools, then run `make` 278 | to compile and run the test application. 279 | 280 | * `C_COMPILER` 281 | * The C compiler to use to perform the tests 282 | 283 | * `C_LIBS` 284 | * The path to the C libraries (including setjmp) 285 | 286 | * `UNITY_DIR` 287 | * The path to the Unity framework (required to run tests) 288 | (get it at [ThrowTheSwitch.org](http://throwtheswitch.org)) 289 | 290 | -------------------------------------------------------------------------------- /docs/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | # ThrowTheSwitch.org Code of Conduct 3 | 4 | Thank you for participating in a ThrowTheSwitch.org community project! We want 5 | this to continue to be a warm and inviting place for everyone to share ideas 6 | and get help. To accomplish this goal, we've developed this Code of Conduct. 7 | 8 | ## Our Pledge 9 | 10 | We as members, contributors, and leaders pledge to make participation in our 11 | community a harassment-free experience for everyone, regardless of age, body 12 | size, visible or invisible disability, ethnicity, sex characteristics, gender 13 | identity and expression, level of experience, education, socio-economic status, 14 | nationality, personal appearance, race, caste, color, religion, or sexual 15 | identity and orientation. 16 | 17 | We pledge to act and interact in ways that contribute to an open, welcoming, 18 | diverse, inclusive, and healthy community. 19 | 20 | ## Our Standards 21 | 22 | Examples of behavior that contributes to a positive environment for our 23 | community include: 24 | 25 | * Demonstrating empathy and kindness toward other people 26 | * Being respectful of differing opinions, viewpoints, and experiences 27 | * Giving and gracefully accepting constructive feedback 28 | * Accepting responsibility and apologizing to those affected by our mistakes, 29 | and learning from the experience 30 | * Focusing on what is best not just for us as individuals, but for the overall 31 | community 32 | 33 | Examples of unacceptable behavior include: 34 | 35 | * The use of sexualized language or imagery, and sexual attention or advances of 36 | any kind 37 | * Trolling, insulting or derogatory comments, and personal or political attacks 38 | * Public or private harassment 39 | * Publishing others' private information, such as a physical or email address, 40 | without their explicit permission 41 | * Other conduct which could reasonably be considered inappropriate in a 42 | professional setting 43 | 44 | ## Enforcement Responsibilities 45 | 46 | Community leaders are responsible for clarifying and enforcing our standards of 47 | acceptable behavior and will take appropriate and fair corrective action in 48 | response to any behavior that they deem inappropriate, threatening, offensive, 49 | or harmful. 50 | 51 | Community leaders have the right and responsibility to remove, edit, or reject 52 | comments, commits, code, wiki edits, issues, and other contributions that are 53 | not aligned to this Code of Conduct, and will communicate reasons for moderation 54 | decisions when appropriate. 55 | 56 | ## Scope 57 | 58 | This Code of Conduct applies within all community spaces, and also applies when 59 | an individual is officially representing the community in public spaces. 60 | Examples of representing our community include using an official email address, 61 | posting via an official social media account, or acting as an appointed 62 | representative at an online or offline event. 63 | 64 | ## Enforcement 65 | 66 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 67 | reported to the community leaders responsible for enforcement at 68 | hello@thingamabyte.com. 69 | 70 | All complaints will be reviewed and investigated promptly and fairly. 71 | 72 | All community leaders are obligated to respect the privacy and security of the 73 | reporter of any incident. 74 | 75 | ## Enforcement Guidelines 76 | 77 | Community leaders will follow these Community Impact Guidelines in determining 78 | the consequences for any action they deem in violation of this Code of Conduct: 79 | 80 | ### 1. Correction 81 | 82 | **Community Impact**: Use of inappropriate language or other behavior deemed 83 | unprofessional or unwelcome in the community. 84 | 85 | **Consequence**: A private, written warning from community leaders, providing 86 | clarity around the nature of the violation and an explanation of why the 87 | behavior was inappropriate. A public apology may be requested. 88 | 89 | ### 2. Warning 90 | 91 | **Community Impact**: A violation through a single incident or series of 92 | actions. 93 | 94 | **Consequence**: A warning with consequences for continued behavior. No 95 | interaction with the people involved, including unsolicited interaction with 96 | those enforcing the Code of Conduct, for a specified period of time. This 97 | includes avoiding interactions in community spaces as well as external channels 98 | like social media. Violating these terms may lead to a temporary or permanent 99 | ban. 100 | 101 | ### 3. Temporary Ban 102 | 103 | **Community Impact**: A serious violation of community standards, including 104 | sustained inappropriate behavior. 105 | 106 | **Consequence**: A temporary ban from any sort of interaction or public 107 | communication with the community for a specified period of time. No public or 108 | private interaction with the people involved, including unsolicited interaction 109 | with those enforcing the Code of Conduct, is allowed during this period. 110 | Violating these terms may lead to a permanent ban. 111 | 112 | ### 4. Permanent Ban 113 | 114 | **Community Impact**: Demonstrating a pattern of violation of community 115 | standards, including sustained inappropriate behavior, harassment of an 116 | individual, or aggression toward or disparagement of classes of individuals. 117 | 118 | **Consequence**: A permanent ban from any sort of public interaction within the 119 | community. 120 | 121 | ## Attribution 122 | 123 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 124 | version 2.1, available at 125 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 126 | 127 | Community Impact Guidelines were inspired by 128 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 129 | 130 | For answers to common questions about this code of conduct, see the FAQ at 131 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 132 | [https://www.contributor-covenant.org/translations][translations]. 133 | 134 | [homepage]: https://www.contributor-covenant.org 135 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 136 | [Mozilla CoC]: https://github.com/mozilla/diversity 137 | [FAQ]: https://www.contributor-covenant.org/faq 138 | [translations]: https://www.contributor-covenant.org/translations 139 | -------------------------------------------------------------------------------- /docs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to a ThrowTheSwitch.org Project 2 | 3 | 👍🎉 _First off, thanks for taking the time to contribute!_ 🎉👍 4 | 5 | The following is a set of guidelines for contributing to any of ThrowTheSwitch.org's projects or the website itself, hosted at throwtheswitch.org or ThrowTheSwitch's organization on GitHub. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request. 6 | 7 | ### Table Of Contents 8 | 9 | - [Code of Conduct](#book-code-of-conduct) 10 | - [Asking Questions](#bulb-asking-questions) 11 | - [Opening an Issue](#inbox_tray-opening-an-issue) 12 | - [Feature Requests](#love_letter-feature-requests) 13 | - [Triaging Issues](#mag-triaging-issues) 14 | - [Submitting Pull Requests](#repeat-submitting-pull-requests) 15 | - [Writing Commit Messages](#memo-writing-commit-messages) 16 | - [Code Review](#white_check_mark-code-review) 17 | - [Coding Style](#nail_care-coding-style) 18 | - [Certificate of Origin](#medal_sports-certificate-of-origin) 19 | - [Credits](#pray-credits) 20 | 21 | ## :book: Code of Conduct 22 | 23 | Please review our [Code of Conduct](CODE_OF_CONDUCT.md). It is in effect at all times. We expect it to be honored by everyone who contributes to this project. Be a Good Human! 24 | 25 | ## :bulb: Asking Questions 26 | 27 | > **Note:** Please don't file an issue to ask a question. We have an official forum where the community chimes in with helpful advice if you have questions. 28 | 29 | * [ThrowTheSwitch Forums](https://throwtheswitch.org/forums) 30 | 31 | ### What should I know before I get started? 32 | 33 | ThrowTheSwitch hosts a number of open source projects — Ceedling is the entrypoint for many users. Ceedling is actually built upon the foundation of Unity Test (a flexible C testing framework) and CMock (a mocking tool for C) and it coordinates many other open source and proprietary tools. Please do your best to focus your ideas and questions at the correct tool. We'll do our best to help you find your way, but there will be times where we'll have to direct your attention to another subtool. 34 | 35 | Here are some of the main projects hosted by ThrowTheSwitch.org: 36 | 37 | - [Ceedling](https://www.github.com/throwtheswitch/ceedling) -- Build coordinator for testing C applications, especially embedded C (and optionally your release build too!) 38 | - [CMock](https://www.github.com/throwtheswitch/cmock) -- Mocking tool for automatically creating stubs, mocks, and skeletons in C 39 | - [Unity](https://www.github.com/throwtheswitch/unity) -- Unit Testing framework for C, specially embedded C. 40 | - [MadScienceLabDocker](https://www.github.com/throwtheswitch/madsciencelabdocker) -- Docker image giving you a shortcut to getting running with Ceedling 41 | - [CException](https://www.github.com/throwtheswitch/cexception) -- An exception framework for using simple exceptions in C. 42 | 43 | There are many more, but this list should be a good starting point. 44 | 45 | ## :inbox_tray: Opening an Issue 46 | 47 | Before [creating an issue](https://help.github.com/en/github/managing-your-work-on-github/creating-an-issue), check if you are using the latest version of the project. If you are not up-to-date, see if updating fixes your issue first. 48 | 49 | ### :beetle: Bug Reports and Other Issues 50 | 51 | A great way to contribute to the project is to send a detailed issue when you encounter a problem. We always appreciate a well-written, thorough bug report. :v: 52 | 53 | In short, since you are most likely a developer, **provide a ticket that you would like to receive**. 54 | 55 | - **Review the documentation** before opening a new issue. 56 | 57 | - **Do not open a duplicate issue!** Search through existing issues to see if your issue has previously been reported. If your issue exists, comment with any additional information you have. You may simply note "I have this problem too", which helps prioritize the most common problems and requests. 58 | 59 | - **Prefer using [reactions](https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/)**, not comments, if you simply want to "+1" an existing issue. 60 | 61 | - **Fully complete the provided issue template.** The bug report template requests all the information we need to quickly and efficiently address your issue. Be clear, concise, and descriptive. Provide as much information as you can, including steps to reproduce, stack traces, compiler errors, library versions, OS versions, and screenshots (if applicable). 62 | 63 | - **Use [GitHub-flavored Markdown](https://help.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax).** Especially put code blocks and console outputs in backticks (```). This improves readability. 64 | 65 | ## :seedling: Feature Requests 66 | 67 | Feature requests are welcome! We don't have all the answers and we truly love the collaborative experience of building software together! That being said, we cannot guarantee your request will be accepted. We want to avoid [feature creep](https://en.wikipedia.org/wiki/Feature_creep). Your idea may be great, but also out-of-scope for the project. If accepted, we'll do our best to tackle it in a timely manner, but cannot make any commitments regarding the timeline for implementation and release. However, you are welcome to submit a pull request to help! 68 | 69 | - **Please don't open a duplicate feature request.** Search for existing feature requests first. If you find your feature (or one very similar) previously requested, comment on that issue. 70 | 71 | - **Fully complete the provided issue template.** The feature request template asks for all necessary information for us to begin a productive conversation. 72 | 73 | - Be precise about the proposed outcome of the feature and how it relates to existing features. Include implementation details if possible. 74 | 75 | ## :mag: Triaging Issues 76 | 77 | You can triage issues which may include reproducing bug reports or asking for additional information, such as version numbers or reproduction instructions. Any help you can provide to quickly resolve an issue is very much appreciated! 78 | 79 | ## :repeat: Submitting Pull Requests 80 | 81 | We **love** pull requests! Before [forking the repo](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) and [creating a pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/proposing-changes-to-your-work-with-pull-requests) for non-trivial changes, it is usually best to first open an issue to discuss the changes, or discuss your intended approach for solving the problem in the comments for an existing issue. 82 | 83 | For most contributions, after your first pull request is accepted and merged, you will be [invited to the project](https://help.github.com/en/github/setting-up-and-managing-your-github-user-account/inviting-collaborators-to-a-personal-repository) and given **push access**. :tada: 84 | 85 | *Note: All contributions will be licensed under the project's license.* 86 | 87 | - **Smaller is better.** Submit **one** pull request per bug fix or feature. A pull request should contain isolated changes pertaining to a single bug fix or feature implementation. **Do not** refactor or reformat code that is unrelated to your change. It is better to **submit many small pull requests** rather than a single large one. Enormous pull requests will take enormous amounts of time to review, or may be rejected altogether. 88 | 89 | - **Coordinate bigger changes.** For large and non-trivial changes, open an issue to discuss a strategy with the maintainers. Otherwise, you risk doing a lot of work for nothing! 90 | 91 | - **Prioritize understanding over cleverness.** Write code clearly and concisely. Remember that source code usually gets written once and read often. Ensure the code is clear to the reader. The purpose and logic should be obvious to a reasonably skilled developer, otherwise you should add a comment that explains it. 92 | 93 | - **Follow existing coding style and conventions.** Keep your code consistent with the style, formatting, and conventions in the rest of the code base. When possible, these will be enforced with a linter. Consistency makes it easier to review and modify in the future. 94 | 95 | - **Include test coverage.** Add unit tests when possible. Follow existing patterns for implementing tests. 96 | 97 | - **Update the example project** if one exists to exercise any new functionality you have added. 98 | 99 | - **Add documentation.** Document your changes with code doc comments or in existing guides. 100 | 101 | - **Update the CHANGELOG** for all enhancements and bug fixes. Include the corresponding issue number if one exists, and your GitHub username. (example: "- Fixed crash in profile view. #123 @jessesquires") 102 | 103 | - **Use the repo's default branch.** Branch from and [submit your pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork) to the repo's default branch. Usually this is `main`, but it could be `dev`, `develop`, or `master`. 104 | 105 | - **[Resolve any merge conflicts](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/resolving-a-merge-conflict-on-github)** that occur. 106 | 107 | - **Promptly address any CI failures**. If your pull request fails to build or pass tests, please push another commit to fix it. 108 | 109 | - When writing comments, use properly constructed sentences, including punctuation. 110 | 111 | - Use spaces, not tabs. 112 | 113 | ## :memo: Writing Commit Messages 114 | 115 | Please [write a great commit message](https://chris.beams.io/posts/git-commit/). 116 | 117 | 1. Separate subject from body with a blank line 118 | 1. Limit the subject line to 50 characters 119 | 1. Capitalize the subject line 120 | 1. Do not end the subject line with a period 121 | 1. Wrap the body at _about_ 72 characters 122 | 1. Use the body to explain **why**, *not what and how* (the code shows that!) 123 | 1. If applicable, prefix the title with the relevant component name or emoji (see below. examples: "[Docs] Fix typo", "[Profile] Fix missing avatar") 124 | 125 | ``` 126 | :palm_tree: Summary of Amazing Feature Here 127 | 128 | Add a more detailed explanation here, if necessary. Possibly give 129 | some background about the issue being fixed, etc. The body of the 130 | commit message can be several paragraphs. Further paragraphs come 131 | after blank lines and please do proper word-wrap. 132 | 133 | Wrap it to about 72 characters or so. In some contexts, 134 | the first line is treated as the subject of the commit and the 135 | rest of the text as the body. The blank line separating the summary 136 | from the body is critical (unless you omit the body entirely); 137 | various tools like `log`, `shortlog` and `rebase` can get confused 138 | if you run the two together. 139 | 140 | Explain the problem that this commit is solving. Focus on why you 141 | are making this change as opposed to how or what. The code explains 142 | how or what. Reviewers and your future self can read the patch, 143 | but might not understand why a particular solution was implemented. 144 | Are there side effects or other unintuitive consequences of this 145 | change? Here's the place to explain them. 146 | 147 | - Bullet points are awesome, too 148 | 149 | - A hyphen should be used for the bullet, preceded 150 | by a single space, with blank lines in between 151 | 152 | Note the fixed or relevant GitHub issues at the end: 153 | 154 | Resolves: #123 155 | See also: #456, #789 156 | ``` 157 | 158 | ## :heart: Who Loves Emoji? 159 | 160 | Commit comments, Issues, Feature Requests... they can all use a little sprucing up, right? Consider using the following emoji for a mix of function and :sparkles: dazzle! 161 | 162 | - actions 163 | - :seedling: `:seedling:` (or other plants) when growing new features. Choose your fav! :cactus: :herb: :evergreen_tree: :palm_tree: :deciduous_tree: :blossom: 164 | - :art: `:art:` when improving the format/structure of the code 165 | - :racehorse: `:racehorse:` when improving performance 166 | - :non-potable_water: `:non-potable_water:` when plugging memory leaks 167 | - :memo: `:memo:` when writing docs 168 | - :bug: `:bug:` (or other insects) when fixing a bug. Maybe :beetle: :ant: or :honeybee: ? 169 | - :fire: `:fire:` when removing code or files 170 | - :green_heart: `:green_heart:` when fixing the CI build 171 | - :white_check_mark: `:white_check_mark:` when adding tests 172 | - :lock: `:lock:` when dealing with security 173 | - :arrow_up: `:arrow_up:` when upgrading dependencies 174 | - :arrow_down: `:arrow_down:` when downgrading dependencies 175 | - :shirt: `:shirt:` when removing linter warnings 176 | 177 | - platforms 178 | - :penguin: `:penguin:` when fixing something on Linux 179 | - :apple: `:apple:` when fixing something on macOS 180 | - :checkered_flag: `:checkered_flag:` when fixing something on Windows 181 | 182 | ## :white_check_mark: Code Review 183 | 184 | - **Review the code, not the author.** Look for and suggest improvements without disparaging or insulting the author. Provide actionable feedback and explain your reasoning. 185 | 186 | - **You are not your code.** When your code is critiqued, questioned, or constructively criticized, remember that you are not your code. Do not take code review personally. 187 | 188 | - **Always do your best.** No one writes bugs on purpose. Do your best, and learn from your mistakes. 189 | 190 | - Kindly note any violations to the guidelines specified in this document. 191 | 192 | ## :violin: Coding Style 193 | 194 | Consistency is the most important. Following the existing style, formatting, and naming conventions of the file you are modifying and of the overall project. Failure to do so will result in a prolonged review process that has to focus on updating the superficial aspects of your code, rather than improving its functionality and performance. 195 | 196 | For example, if all private properties are prefixed with an underscore `_`, then new ones you add should be prefixed in the same way. Or, if methods are named using camelcase, like `thisIsMyNewMethod`, then do not diverge from that by writing `this_is_my_new_method`. You get the idea. If in doubt, please ask or search the codebase for something similar. 197 | 198 | When possible, style and format will be enforced with a linter. 199 | 200 | ### C Styleguide 201 | 202 | C code is linted with [AStyle](https://astyle.sourceforge.net/). 203 | 204 | ### Ruby Styleguide 205 | 206 | Ruby code is linted with [Rubocop](https://github.com/rubocop/rubocop) 207 | 208 | ## :medal_sports: Certificate of Origin 209 | 210 | *Developer's Certificate of Origin 1.1* 211 | 212 | By making a contribution to this project, I certify that: 213 | 214 | > 1. The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or 215 | > 1. The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or 216 | > 1. The contribution was provided directly to me by some other person who certified (1), (2) or (3) and I have not modified it. 217 | > 1. I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. 218 | 219 | ## [No Brown M&M's](https://en.wikipedia.org/wiki/Van_Halen#Contract_riders) 220 | 221 | If you are reading this, bravo dear user and (hopefully) contributor for making it this far! You are awesome. :100: 222 | 223 | To confirm that you have read this guide and are following it as best as possible, **include this emoji at the top** of your issue or pull request: :pineapple: `:pineapple:` 224 | 225 | ## :pray: Credits 226 | 227 | Written by [@jessesquires](https://github.com/jessesquires). Lovingly adapted to ThrowTheSwitch.org by [@mvandervoord](https://github.com/mvandervoord). 228 | 229 | **Please feel free to adopt this guide in your own projects. Fork it wholesale or remix it for your needs.** 230 | 231 | *Many of the ideas and prose for the statements in this document were based on or inspired by work from the following communities:* 232 | 233 | - [Alamofire](https://github.com/Alamofire/Alamofire/blob/master/CONTRIBUTING.md) 234 | - [CocoaPods](https://github.com/CocoaPods/CocoaPods/blob/master/CONTRIBUTING.md) 235 | - [Docker](https://github.com/moby/moby/blob/master/CONTRIBUTING.md) 236 | - [Linux](https://elinux.org/Developer_Certificate_Of_Origin) 237 | 238 | *We commend them for their efforts to facilitate collaboration in their projects.* 239 | -------------------------------------------------------------------------------- /docs/ThrowTheSwitchCodingStandard.md: -------------------------------------------------------------------------------- 1 | # ThrowTheSwitch.org Coding Standard 2 | 3 | Hi. Welcome to the coding standard for ThrowTheSwitch.org. For the most part, 4 | we try to follow these standards to unify our contributors' code into a cohesive 5 | unit (puns intended). You might find places where these standards aren't 6 | followed. We're not perfect. Please be polite where you notice these discrepancies 7 | and we'll try to be polite when we notice yours. 8 | 9 | ;) 10 | 11 | 12 | ## Why Have A Coding Standard? 13 | 14 | Being consistent makes code easier to understand. We've made an attempt to keep 15 | our standard simple because we also believe that we can only expect someone to 16 | follow something that is understandable. Please do your best. 17 | 18 | 19 | ## Our Philosophy 20 | 21 | Before we get into details on syntax, let's take a moment to talk about our 22 | vision for these tools. We're C developers and embedded software developers. 23 | These tools are great to test any C code, but catering to embedded software has 24 | made us more tolerant of compiler quirks. There are a LOT of quirky compilers 25 | out there. By quirky I mean "doesn't follow standards because they feel like 26 | they have a license to do as they wish." 27 | 28 | Our philosophy is "support every compiler we can". Most often, this means that 29 | we aim for writing C code that is standards compliant (often C89... that seems 30 | to be a sweet spot that is almost always compatible). But it also means these 31 | tools are tolerant of things that aren't common. Some that aren't even 32 | compliant. There are configuration options to override the size of standard 33 | types. There are configuration options to force Unity to not use certain 34 | standard library functions. A lot of Unity is configurable and we have worked 35 | hard to make it not TOO ugly in the process. 36 | 37 | Similarly, our tools that parse C do their best. They aren't full C parsers 38 | (yet) and, even if they were, they would still have to accept non-standard 39 | additions like gcc extensions or specifying `@0x1000` to force a variable to 40 | compile to a particular location. It's just what we do, because we like 41 | everything to Just Work™. 42 | 43 | Speaking of having things Just Work™, that's our second philosophy. By that, we 44 | mean that we do our best to have EVERY configuration option have a logical 45 | default. We believe that if you're working with a simple compiler and target, 46 | you shouldn't need to configure very much... we try to make the tools guess as 47 | much as they can, but give the user the power to override it when it's wrong. 48 | 49 | 50 | ## Naming Things 51 | 52 | Let's talk about naming things. Programming is all about naming things. We name 53 | files, functions, variables, and so much more. While we're not always going to 54 | find the best name for something, we actually put quite a bit of effort into 55 | finding *What Something WANTS to be Called*™. 56 | 57 | When naming things, we more or less follow this hierarchy, the first being the 58 | most important to us (but we do all four whenever possible): 59 | 1. Readable 60 | 2. Descriptive 61 | 3. Consistent 62 | 4. Memorable 63 | 64 | 65 | #### Readable 66 | 67 | We want to read our code. This means we like names and flow that are more 68 | naturally read. We try to avoid double negatives. We try to avoid cryptic 69 | abbreviations (sticking to ones we feel are common). 70 | 71 | 72 | #### Descriptive 73 | 74 | We like descriptive names for things, especially functions and variables. 75 | Finding the right name for something is an important endeavor. You might notice 76 | from poking around our code that this often results in names that are a little 77 | longer than the average. Guilty. We're okay with a tiny bit more typing if it 78 | means our code is easier to understand. 79 | 80 | There are two exceptions to this rule that we also stick to as religiously as 81 | possible: 82 | 83 | First, while we realize hungarian notation (and similar systems for encoding 84 | type information into variable names) is providing a more descriptive name, we 85 | feel that (for the average developer) it takes away from readability and 86 | therefore is to be avoided. 87 | 88 | Second, loop counters and other local throw-away variables often have a purpose 89 | which is obvious. There's no need, therefore, to get carried away with complex 90 | naming. We find i, j, and k are better loop counters than loopCounterVar or 91 | whatnot. We only break this rule when we see that more description could improve 92 | understanding of an algorithm. 93 | 94 | 95 | #### Consistent 96 | 97 | We like consistency, but we're not really obsessed with it. We try to name our 98 | configuration macros in a consistent fashion... you'll notice a repeated use of 99 | UNITY_EXCLUDE_BLAH or UNITY_USES_BLAH macros. This helps users avoid having to 100 | remember each macro's details. 101 | 102 | 103 | #### Memorable 104 | 105 | Where ever it doesn't violate the above principles, we try to apply memorable 106 | names. Sometimes this means using something that is simply descriptive, but 107 | often we strive for descriptive AND unique... we like quirky names that stand 108 | out in our memory and are easier to search for. Take a look through the file 109 | names in Ceedling and you'll get a good idea of what we are talking about here. 110 | Why use preprocess when you can use preprocessinator? Or what better describes a 111 | module in charge of invoking tasks during releases than release_invoker? Don't 112 | get carried away. The names are still descriptive and fulfill the above 113 | requirements, but they don't feel stale. 114 | 115 | 116 | ## C and C++ Details 117 | 118 | We don't really want to add to the style battles out there. Tabs or spaces? 119 | How many spaces? Where do the braces go? These are age-old questions that will 120 | never be answered... or at least not answered in a way that will make everyone 121 | happy. 122 | 123 | We've decided on our own style preferences. If you'd like to contribute to these 124 | projects (and we hope that you do), then we ask if you do your best to follow 125 | the same. It will only hurt a little. We promise. 126 | 127 | 128 | #### Whitespace 129 | 130 | Our C-style is to use spaces and to use 4 of them per indent level. It's a nice 131 | power-of-2 number that looks decent on a wide screen. We have no more reason 132 | than that. We break that rule when we have lines that wrap (macros or function 133 | arguments or whatnot). When that happens, we like to indent further to line 134 | things up in nice tidy columns. 135 | 136 | ```C 137 | if (stuff_happened) 138 | { 139 | do_something(); 140 | } 141 | ``` 142 | 143 | 144 | #### Case 145 | 146 | - Files - all lower case with underscores. 147 | - Variables - all lower case with underscores 148 | - Macros - all caps with underscores. 149 | - Typedefs - all caps with underscores. (also ends with _T). 150 | - Functions - camel cased. Usually named ModuleName_FuncName 151 | - Constants and Globals - camel cased. 152 | 153 | 154 | #### Braces 155 | 156 | The left brace is on the next line after the declaration. The right brace is 157 | directly below that. Everything in between in indented one level. If you're 158 | catching an error and you have a one-line, go ahead and to it on the same line. 159 | 160 | ```C 161 | while (blah) 162 | { 163 | //Like so. Even if only one line, we use braces. 164 | } 165 | ``` 166 | 167 | 168 | #### Comments 169 | 170 | Do you know what we hate? Old-school C block comments. BUT, we're using them 171 | anyway. As we mentioned, our goal is to support every compiler we can, 172 | especially embedded compilers. There are STILL C compilers out there that only 173 | support old-school block comments. So that is what we're using. We apologize. We 174 | think they are ugly too. 175 | 176 | 177 | ## Ruby Details 178 | 179 | Is there really such thing as a Ruby coding standard? Ruby is such a free form 180 | language, it seems almost sacrilegious to suggest that people should comply to 181 | one method! We'll keep it really brief! 182 | 183 | 184 | #### Whitespace 185 | 186 | Our Ruby style is to use spaces and to use 2 of them per indent level. It's a 187 | nice power-of-2 number that really grooves with Ruby's compact style. We have no 188 | more reason than that. We break that rule when we have lines that wrap. When 189 | that happens, we like to indent further to line things up in nice tidy columns. 190 | 191 | 192 | #### Case 193 | 194 | - Files - all lower case with underscores. 195 | - Variables - all lower case with underscores 196 | - Classes, Modules, etc - Camel cased. 197 | - Functions - all lower case with underscores 198 | - Constants - all upper case with underscores 199 | 200 | 201 | ## Documentation 202 | 203 | Egad. Really? We use markdown and we like pdf files because they can be made to 204 | look nice while still being portable. Good enough? 205 | 206 | 207 | *Find The Latest of This And More at [ThrowTheSwitch.org](https://throwtheswitch.org)* 208 | -------------------------------------------------------------------------------- /lib/CException.c: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | CException - Simple Exception Handling in C 3 | ThrowTheSwitch.org 4 | Copyright (c) 2007-24 Mark VanderVoord 5 | SPDX-License-Identifier: MIT 6 | ========================================================================= */ 7 | 8 | #include "CException.h" 9 | 10 | #ifdef __GNUC__ 11 | #pragma GCC diagnostic push 12 | #pragma GCC diagnostic ignored "-Wmissing-field-initializers" 13 | #endif 14 | 15 | volatile CEXCEPTION_FRAME_T CExceptionFrames[CEXCEPTION_NUM_ID] = {{ 0 }}; 16 | 17 | #ifdef __GNUC__ 18 | #pragma GCC diagnostic pop 19 | #endif 20 | 21 | //------------------------------------------------------------------------------------------ 22 | // Throw 23 | //------------------------------------------------------------------------------------------ 24 | void Throw(CEXCEPTION_T ExceptionID) 25 | { 26 | unsigned int MY_ID = CEXCEPTION_GET_ID; 27 | CExceptionFrames[MY_ID].Exception = ExceptionID; 28 | if (CExceptionFrames[MY_ID].pFrame) 29 | { 30 | longjmp(*CExceptionFrames[MY_ID].pFrame, 1); 31 | } 32 | CEXCEPTION_NO_CATCH_HANDLER(ExceptionID); 33 | } 34 | 35 | //------------------------------------------------------------------------------------------ 36 | // Explanation of what it's all for: 37 | //------------------------------------------------------------------------------------------ 38 | /* 39 | #define Try 40 | { <- give us some local scope. most compilers are happy with this 41 | jmp_buf *PrevFrame, NewFrame; <- prev frame points to the last try block's frame. new frame gets created on stack for this Try block 42 | unsigned int MY_ID = CEXCEPTION_GET_ID; <- look up this task's id for use in frame array. always 0 if single-tasking 43 | PrevFrame = CExceptionFrames[CEXCEPTION_GET_ID].pFrame; <- set pointer to point at old frame (which array is currently pointing at) 44 | CExceptionFrames[MY_ID].pFrame = &NewFrame; <- set array to point at my new frame instead, now 45 | CExceptionFrames[MY_ID].Exception = CEXCEPTION_NONE; <- initialize my exception id to be NONE 46 | if (setjmp(NewFrame) == 0) { <- do setjmp. it returns 1 if longjump called, otherwise 0 47 | if (&PrevFrame) <- this is here to force proper scoping. it requires braces or a single line to be but after Try, otherwise won't compile. This is always true at this point. 48 | 49 | #define Catch(e) 50 | else { } <- this also forces proper scoping. Without this they could stick their own 'else' in and it would get ugly 51 | CExceptionFrames[MY_ID].Exception = CEXCEPTION_NONE; <- no errors happened, so just set the exception id to NONE (in case it was corrupted) 52 | } 53 | else <- an exception occurred 54 | { e = CExceptionFrames[MY_ID].Exception; e=e;} <- assign the caught exception id to the variable passed in. 55 | CExceptionFrames[MY_ID].pFrame = PrevFrame; <- make the pointer in the array point at the previous frame again, as if NewFrame never existed. 56 | } <- finish off that local scope we created to have our own variables 57 | if (CExceptionFrames[CEXCEPTION_GET_ID].Exception != CEXCEPTION_NONE) <- start the actual 'catch' processing if we have an exception id saved away 58 | */ 59 | 60 | -------------------------------------------------------------------------------- /lib/CException.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | CException - Simple Exception Handling in C 3 | ThrowTheSwitch.org 4 | Copyright (c) 2007-24 Mark VanderVoord 5 | SPDX-License-Identifier: MIT 6 | ========================================================================= */ 7 | 8 | #ifndef _CEXCEPTION_H 9 | #define _CEXCEPTION_H 10 | 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" 15 | { 16 | #endif 17 | 18 | 19 | #define CEXCEPTION_VERSION_MAJOR 1 20 | #define CEXCEPTION_VERSION_MINOR 3 21 | #define CEXCEPTION_VERSION_BUILD 4 22 | #define CEXCEPTION_VERSION ((CEXCEPTION_VERSION_MAJOR << 16) | (CEXCEPTION_VERSION_MINOR << 8) | CEXCEPTION_VERSION_BUILD) 23 | 24 | //To Use CException, you have a number of options: 25 | //1. Just include it and run with the defaults 26 | //2. Define any of the following symbols at the command line to override them 27 | //3. Include a header file before CException.h everywhere which defines any of these 28 | //4. Create an Exception.h in your path, and just define EXCEPTION_USE_CONFIG_FILE first 29 | 30 | #ifdef CEXCEPTION_USE_CONFIG_FILE 31 | #include "CExceptionConfig.h" 32 | #endif 33 | 34 | //This is the value to assign when there isn't an exception 35 | #ifndef CEXCEPTION_NONE 36 | #define CEXCEPTION_NONE (0x5A5A5A5A) 37 | #endif 38 | 39 | //This is number of exception stacks to keep track of (one per task) 40 | #ifndef CEXCEPTION_NUM_ID 41 | #define CEXCEPTION_NUM_ID (1) //there is only the one stack by default 42 | #endif 43 | 44 | //This is the method of getting the current exception stack index (0 if only one stack) 45 | #ifndef CEXCEPTION_GET_ID 46 | #define CEXCEPTION_GET_ID (0) //use the first index always because there is only one anyway 47 | #endif 48 | 49 | //The type to use to store the exception values. 50 | #ifndef CEXCEPTION_T 51 | #define CEXCEPTION_T unsigned int 52 | #endif 53 | 54 | //This is an optional special handler for when there is no global Catch 55 | #ifndef CEXCEPTION_NO_CATCH_HANDLER 56 | #define CEXCEPTION_NO_CATCH_HANDLER(id) 57 | #endif 58 | 59 | //These hooks allow you to inject custom code into places, particularly useful for saving and restoring additional state 60 | #ifndef CEXCEPTION_HOOK_START_TRY 61 | #define CEXCEPTION_HOOK_START_TRY 62 | #endif 63 | #ifndef CEXCEPTION_HOOK_HAPPY_TRY 64 | #define CEXCEPTION_HOOK_HAPPY_TRY 65 | #endif 66 | #ifndef CEXCEPTION_HOOK_AFTER_TRY 67 | #define CEXCEPTION_HOOK_AFTER_TRY 68 | #endif 69 | #ifndef CEXCEPTION_HOOK_START_CATCH 70 | #define CEXCEPTION_HOOK_START_CATCH 71 | #endif 72 | 73 | //exception frame structures 74 | typedef struct { 75 | jmp_buf* pFrame; 76 | CEXCEPTION_T volatile Exception; 77 | } CEXCEPTION_FRAME_T; 78 | 79 | //actual root frame storage (only one if single-tasking) 80 | extern volatile CEXCEPTION_FRAME_T CExceptionFrames[]; 81 | 82 | //Try (see C file for explanation) 83 | #define Try \ 84 | { \ 85 | jmp_buf *PrevFrame, NewFrame; \ 86 | unsigned int MY_ID = CEXCEPTION_GET_ID; \ 87 | PrevFrame = CExceptionFrames[MY_ID].pFrame; \ 88 | CExceptionFrames[MY_ID].pFrame = (jmp_buf*)(&NewFrame); \ 89 | CExceptionFrames[MY_ID].Exception = CEXCEPTION_NONE; \ 90 | CEXCEPTION_HOOK_START_TRY; \ 91 | if (setjmp(NewFrame) == 0) { \ 92 | if (1) 93 | 94 | //Catch (see C file for explanation) 95 | #define Catch(e) \ 96 | else { } \ 97 | CExceptionFrames[MY_ID].Exception = CEXCEPTION_NONE; \ 98 | CEXCEPTION_HOOK_HAPPY_TRY; \ 99 | } \ 100 | else \ 101 | { \ 102 | e = CExceptionFrames[MY_ID].Exception; \ 103 | (void)e; \ 104 | CEXCEPTION_HOOK_START_CATCH; \ 105 | } \ 106 | CExceptionFrames[MY_ID].pFrame = PrevFrame; \ 107 | CEXCEPTION_HOOK_AFTER_TRY; \ 108 | } \ 109 | if (CExceptionFrames[CEXCEPTION_GET_ID].Exception != CEXCEPTION_NONE) 110 | 111 | //Throw an Error 112 | void Throw(CEXCEPTION_T ExceptionID); 113 | 114 | //Just exit the Try block and skip the Catch. 115 | #define ExitTry() Throw(CEXCEPTION_NONE) 116 | 117 | #ifdef __cplusplus 118 | } // extern "C" 119 | #endif 120 | 121 | 122 | #endif // _CEXCEPTION_H 123 | -------------------------------------------------------------------------------- /lib/meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # build script written by : Michael Brockus. 3 | # github repo author: Mark VanderVoord. 4 | # 5 | # license: MIT 6 | # 7 | cexception_dir = include_directories('.') 8 | 9 | cexception_lib = static_library(meson.project_name(), 10 | files('CException.c'), 11 | include_directories : cexception_dir) 12 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007-2024 Mark VanderVoord 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | # 2 | # build script written by : Michael Brockus. 3 | # github repo author: Mark VanderVoord. 4 | # 5 | # license: MIT 6 | # 7 | project('cexception', 'c', 8 | license: 'MIT', 9 | meson_version: '>=0.53.0', 10 | default_options: ['werror=true', 'c_std=c11'] 11 | ) 12 | 13 | subdir('lib') 14 | cexception_dep = declare_dependency(link_with: cexception_lib, include_directories: cexception_dir) 15 | -------------------------------------------------------------------------------- /project.yml: -------------------------------------------------------------------------------- 1 | # ========================================================================= 2 | # CException - Simple Exception Handling in C 3 | # ThrowTheSwitch.org 4 | # Copyright (c) 2007-24 Mark VanderVoord 5 | # SPDX-License-Identifier: MIT 6 | # ========================================================================= 7 | 8 | --- 9 | 10 | # This project file is for using Ceedling to run CException's self-tests. The 11 | # only requirement for USING CException is in the lib folder. 12 | 13 | :project: 14 | # how to use ceedling. If you're not sure, leave this as `gem` and `?` 15 | :which_ceedling: gem 16 | :ceedling_version: '1.0.0' 17 | 18 | # optional features. If you don't need them, keep them turned off for performance 19 | :use_mocks: TRUE 20 | :use_test_preprocessor: :none 21 | :use_backtrace: :simple 22 | 23 | # tweak the way ceedling handles automatic tasks 24 | :build_root: build 25 | :test_file_prefix: Test 26 | :default_tasks: 27 | - clobber 28 | - test:all 29 | 30 | # performance options. If your tools start giving mysterious errors, consider 31 | # dropping this to 1 to force single-tasking 32 | :test_threads: 8 33 | :compile_threads: 8 34 | 35 | # enable release build (more details in release_build section below) 36 | :release_build: FALSE 37 | 38 | # Specify where to find mixins and any that should be enabled automatically 39 | :mixins: 40 | :enabled: [] 41 | :load_paths: [] 42 | 43 | # further details to configure the way Ceedling handles test code 44 | :test_build: 45 | :use_assembly: FALSE 46 | 47 | # Plugins are optional Ceedling features which can be enabled. Ceedling supports 48 | # a variety of plugins which may effect the way things are compiled, reported, 49 | # or may provide new command options. Refer to the readme in each plugin for 50 | # details on how to use it. 51 | :plugins: 52 | :load_paths: [] 53 | :enabled: 54 | #- beep # beeps when finished, so you don't waste time waiting for ceedling 55 | - module_generator # handy for quickly creating source, header, and test templates 56 | #- gcov # test coverage using gcov. Requires gcc, gcov, and a coverage analyzer like gcovr 57 | #- bullseye # test coverage using bullseye. Requires bullseye for your platform 58 | #- command_hooks # write custom actions to be called at different points during the build process 59 | #- compile_commands_json_db # generate a compile_commands.json file 60 | #- dependencies # automatically fetch 3rd party libraries, etc. 61 | #- subprojects # managing builds and test for static libraries 62 | #- fake_function_framework # use FFF instead of CMock 63 | 64 | # Report options (You'll want to choose one stdout option, but may choose multiple stored options if desired) 65 | #- report_build_warnings_log 66 | #- report_tests_gtestlike_stdout 67 | #- report_tests_ide_stdout 68 | #- report_tests_log_factory 69 | - report_tests_pretty_stdout 70 | #- report_tests_raw_output_log 71 | #- report_tests_teamcity_stdout 72 | 73 | # Specify which reports you'd like from the log factory 74 | :report_tests_log_factory: 75 | :reports: 76 | - json 77 | - junit 78 | - cppunit 79 | - html 80 | 81 | # override the default extensions for your system and toolchain 82 | :extension: 83 | #:header: .h 84 | #:source: .c 85 | #:assembly: .s 86 | #:dependencies: .d 87 | #:object: .o 88 | :executable: .out 89 | #:testpass: .pass 90 | #:testfail: .fail 91 | #:subprojects: .a 92 | 93 | # This is where Ceedling should look for your source and test files. 94 | # see documentation for the many options for specifying this. 95 | :paths: 96 | :test: 97 | - +:test/** 98 | - -:test/support 99 | :source: 100 | - lib/** 101 | :include: 102 | - lib/** # In simple projects, this entry often duplicates :source 103 | :support: 104 | - test/support 105 | :libraries: [] 106 | 107 | # You can even specify specific files to add or remove from your test 108 | # and release collections. Usually it's better to use paths and let 109 | # Ceedling do the work for you! 110 | :files: 111 | :test: [] 112 | :source: [] 113 | 114 | # Compilation symbols to be injected into builds 115 | # See documentation for advanced options: 116 | # - Test name matchers for different symbols per test executable build 117 | # - Referencing symbols in multiple lists using advanced YAML 118 | # - Specifiying symbols used during test preprocessing 119 | :defines: 120 | :test: 121 | - TEST 122 | - CEXCEPTION_USE_CONFIG_FILE 123 | :test_preprocess: 124 | - TEST 125 | - CEXCEPTION_USE_CONFIG_FILE 126 | 127 | # Enable to inject name of a test as a unique compilation symbol into its respective executable build. 128 | :use_test_definition: FALSE 129 | 130 | # Configure additional command line flags provided to tools used in each build step 131 | # :flags: 132 | # :release: 133 | # :compile: # Add '-Wall' and '--02' to compilation of all files in release target 134 | # - -Wall 135 | # - --O2 136 | # :test: 137 | # :compile: 138 | # '(_|-)special': # Add '-pedantic' to compilation of all files in all test executables with '_special' or '-special' in their names 139 | # - -pedantic 140 | # '*': # Add '-foo' to compilation of all files in all test executables 141 | # - -foo 142 | 143 | # Configuration Options specific to CMock. See CMock docs for details 144 | :cmock: 145 | # Core conffiguration 146 | :plugins: # What plugins should be used by CMock? 147 | - :ignore 148 | - :callback 149 | :verbosity: 2 # the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose 150 | :when_no_prototypes: :warn # the options being :ignore, :warn, or :erro 151 | 152 | # File configuration 153 | :skeleton_path: '' # Subdirectory to store stubs when generated (default: '') 154 | :mock_prefix: 'mock_' # Prefix to append to filenames for mocks 155 | :mock_suffix: '' # Suffix to append to filenames for mocks 156 | 157 | # Parser configuration 158 | :strippables: ['(?:__attribute__\s*\([ (]*.*?[ )]*\)+)'] 159 | :attributes: 160 | - __ramfunc 161 | - __irq 162 | - __fiq 163 | - register 164 | - extern 165 | :c_calling_conventions: 166 | - __stdcall 167 | - __cdecl 168 | - __fastcall 169 | :treat_externs: :exclude # the options being :include or :exclud 170 | :treat_inlines: :exclude # the options being :include or :exclud 171 | 172 | # Type handling configuration 173 | #:unity_helper_path: '' # specify a string of where to find a unity_helper.h file to discover custom type assertions 174 | :treat_as: # optionally add additional types to map custom types 175 | uint8: HEX8 176 | uint16: HEX16 177 | uint32: UINT32 178 | int8: INT8 179 | bool: UINT8 180 | #:treat_as_array: {} # hint to cmock that these types are pointers to something 181 | #:treat_as_void: [] # hint to cmock that these types are actually aliases of void 182 | :memcmp_if_unknown: true # allow cmock to use the memory comparison assertions for unknown types 183 | :when_ptr: :compare_data # hint to cmock how to handle pointers in general, the options being :compare_ptr, :compare_data, or :smart 184 | 185 | # Mock generation configuration 186 | :weak: '' # Symbol to use to declare weak functions 187 | :enforce_strict_ordering: true # Do we want cmock to enforce ordering of all function calls? 188 | :fail_on_unexpected_calls: true # Do we want cmock to fail when it encounters a function call that wasn't expected? 189 | :callback_include_count: true # Do we want cmock to include the number of calls to this callback, when using callbacks? 190 | :callback_after_arg_check: false # Do we want cmock to enforce an argument check first when using a callback? 191 | #:includes: [] # You can add additional includes here, or specify the location with the options below 192 | #:includes_h_pre_orig_header: [] 193 | #:includes_h_post_orig_header: [] 194 | #:includes_c_pre_header: [] 195 | #:includes_c_post_header: [] 196 | #:array_size_type: [] # Specify a type or types that should be used for array lengths 197 | #:array_size_name: 'size|len' # Specify a name or names that CMock might automatically recognize as the length of an array 198 | :exclude_setjmp_h: false # Don't use setjmp when running CMock. Note that this might result in late reporting or out-of-order failures. 199 | 200 | # Configuration options specific to Unity. 201 | :unity: 202 | :defines: 203 | - UNITY_EXCLUDE_FLOAT 204 | 205 | # You can optionally have ceedling create environment variables for you before 206 | # performing the rest of its tasks. 207 | :environment: [] 208 | 209 | # LIBRARIES 210 | # These libraries are automatically injected into the build process. Those specified as 211 | # common will be used in all types of builds. Otherwise, libraries can be injected in just 212 | # tests or releases. These options are MERGED with the options in supplemental yaml files. 213 | :libraries: 214 | :placement: :end 215 | :flag: "-l${1}" 216 | :path_flag: "-L ${1}" 217 | :system: [] # for example, you might list 'm' to grab the math library 218 | :test: [] 219 | :release: [] 220 | 221 | ################################################################ 222 | # PLUGIN CONFIGURATION 223 | ################################################################ 224 | 225 | # Add -gcov to the plugins list to make sure of the gcov plugin 226 | # You will need to have gcov and gcovr both installed to make it work. 227 | # For more information on these options, see docs in plugins/gcov 228 | :gcov: 229 | :utilities: 230 | - gcovr # Use gcovr to create the specified reports (default). 231 | #- ReportGenerator # Use ReportGenerator to create the specified reports. 232 | :reports: # Specify one or more reports to generate. 233 | # Make an HTML summary report. 234 | - HtmlBasic 235 | # - HtmlDetailed 236 | # - Text 237 | # - Cobertura 238 | # - SonarQube 239 | # - JSON 240 | # - HtmlInline 241 | # - HtmlInlineAzure 242 | # - HtmlInlineAzureDark 243 | # - HtmlChart 244 | # - MHtml 245 | # - Badges 246 | # - CsvSummary 247 | # - Latex 248 | # - LatexSummary 249 | # - PngChart 250 | # - TeamCitySummary 251 | # - lcov 252 | # - Xml 253 | # - XmlSummary 254 | :gcovr: 255 | # :html_artifact_filename: TestCoverageReport.html 256 | # :html_title: Test Coverage Report 257 | :html_medium_threshold: 75 258 | :html_high_threshold: 90 259 | # :html_absolute_paths: TRUE 260 | # :html_encoding: UTF-8 261 | 262 | 263 | ... 264 | -------------------------------------------------------------------------------- /test/TestException.c: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | CException - Simple Exception Handling in C 3 | ThrowTheSwitch.org 4 | Copyright (c) 2007-24 Mark VanderVoord 5 | SPDX-License-Identifier: MIT 6 | ========================================================================= */ 7 | 8 | #include "unity.h" 9 | #include "CException.h" 10 | 11 | volatile int TestingTheFallback; 12 | volatile int TestingTheFallbackId; 13 | 14 | void setUp(void) 15 | { 16 | CExceptionFrames[0].pFrame = NULL; 17 | TestingTheFallback = 0; 18 | } 19 | 20 | void tearDown(void) 21 | { 22 | } 23 | 24 | void test_BasicTryDoesNothingIfNoThrow(void) 25 | { 26 | int i = 0; 27 | CEXCEPTION_T e = 0x5a; 28 | 29 | Try 30 | { 31 | i += 1; 32 | } 33 | Catch(e) 34 | { 35 | TEST_FAIL_MESSAGE("Should Not Enter Catch If Not Thrown"); 36 | } 37 | 38 | //verify that e was untouched 39 | TEST_ASSERT_EQUAL(0x5a, e); 40 | 41 | // verify that i was incremented once 42 | TEST_ASSERT_EQUAL(1, i); 43 | } 44 | 45 | void test_BasicThrowAndCatch(void) 46 | { 47 | CEXCEPTION_T e; 48 | 49 | Try 50 | { 51 | Throw(0xBE); 52 | TEST_FAIL_MESSAGE("Should Have Thrown An Error"); 53 | } 54 | Catch(e) 55 | { 56 | //verify that e has the right data 57 | TEST_ASSERT_EQUAL(0xBE, e); 58 | } 59 | 60 | //verify that e STILL has the right data 61 | TEST_ASSERT_EQUAL(0xBE, e); 62 | } 63 | 64 | void test_BasicThrowAndCatch_WithMiniSyntax(void) 65 | { 66 | CEXCEPTION_T e; 67 | 68 | //Mini Throw and Catch 69 | Try 70 | Throw(0xEF); 71 | Catch(e) 72 | TEST_ASSERT_EQUAL(0xEF, e); 73 | TEST_ASSERT_EQUAL(0xEF, e); 74 | 75 | //Mini Passthrough 76 | Try 77 | e = 0; 78 | Catch(e) 79 | TEST_FAIL_MESSAGE("I shouldn't be caught because there was no throw"); 80 | 81 | TEST_ASSERT_EQUAL(0, e); 82 | } 83 | 84 | void test_VerifyVolatilesSurviveThrowAndCatch(void) 85 | { 86 | volatile unsigned int VolVal = 0; 87 | CEXCEPTION_T e; 88 | 89 | Try 90 | { 91 | VolVal = 2; 92 | Throw(0xBF); 93 | TEST_FAIL_MESSAGE("Should Have Thrown An Error"); 94 | } 95 | Catch(e) 96 | { 97 | VolVal += 2; 98 | TEST_ASSERT_EQUAL(0xBF, e); 99 | } 100 | 101 | TEST_ASSERT_EQUAL(4, VolVal); 102 | TEST_ASSERT_EQUAL(0xBF, e); 103 | } 104 | 105 | void HappyExceptionThrower(unsigned int ID) 106 | { 107 | if (ID != 0) 108 | { 109 | Throw(ID); 110 | } 111 | } 112 | 113 | void test_ThrowFromASubFunctionAndCatchInRootFunc(void) 114 | { 115 | volatile unsigned int ID = 0; 116 | CEXCEPTION_T e; 117 | 118 | Try 119 | { 120 | 121 | HappyExceptionThrower(0xBA); 122 | TEST_FAIL_MESSAGE("Should Have Thrown An Exception"); 123 | } 124 | Catch(e) 125 | { 126 | ID = e; 127 | } 128 | 129 | //verify that I can pass that value to something else 130 | TEST_ASSERT_EQUAL(0xBA, e); 131 | //verify that ID and e have the same value 132 | TEST_ASSERT_EQUAL(ID, e); 133 | } 134 | 135 | void HappyExceptionRethrower(unsigned int ID) 136 | { 137 | CEXCEPTION_T e; 138 | 139 | Try 140 | { 141 | Throw(ID); 142 | } 143 | Catch(e) 144 | { 145 | switch (e) 146 | { 147 | case 0xBD: 148 | Throw(0xBF); 149 | break; 150 | default: 151 | break; 152 | } 153 | } 154 | } 155 | 156 | void test_ThrowAndCatchFromASubFunctionAndRethrowToCatchInRootFunc(void) 157 | { 158 | volatile unsigned int ID = 0; 159 | CEXCEPTION_T e; 160 | 161 | Try 162 | { 163 | HappyExceptionRethrower(0xBD); 164 | TEST_FAIL_MESSAGE("Should Have Rethrown Exception"); 165 | } 166 | Catch(e) 167 | { 168 | ID = 1; 169 | } 170 | 171 | TEST_ASSERT_EQUAL(0xBF, e); 172 | TEST_ASSERT_EQUAL(1, ID); 173 | } 174 | 175 | void test_ThrowAndCatchFromASubFunctionAndNoRethrowToCatchInRootFunc(void) 176 | { 177 | CEXCEPTION_T e = 3; 178 | 179 | Try 180 | { 181 | HappyExceptionRethrower(0xBF); 182 | } 183 | Catch(e) 184 | { 185 | TEST_FAIL_MESSAGE("Should Not Have Re-thrown Error (it should have already been caught)"); 186 | } 187 | 188 | //verify that THIS e is still untouched, even though subfunction was touched 189 | TEST_ASSERT_EQUAL(3, e); 190 | } 191 | 192 | void test_ThrowAnErrorThenEnterATryBlockFromWithinCatch_VerifyThisDoesntCorruptExceptionId(void) 193 | { 194 | CEXCEPTION_T e; 195 | 196 | Try 197 | { 198 | HappyExceptionThrower(0xBF); 199 | TEST_FAIL_MESSAGE("Should Have Thrown Exception"); 200 | } 201 | Catch(e) 202 | { 203 | TEST_ASSERT_EQUAL(0xBF, e); 204 | HappyExceptionRethrower(0x12); 205 | TEST_ASSERT_EQUAL(0xBF, e); 206 | } 207 | TEST_ASSERT_EQUAL(0xBF, e); 208 | } 209 | 210 | void test_ThrowAnErrorThenEnterATryBlockFromWithinCatch_VerifyThatEachExceptionIdIndependent(void) 211 | { 212 | CEXCEPTION_T e1, e2; 213 | 214 | Try 215 | { 216 | HappyExceptionThrower(0xBF); 217 | TEST_FAIL_MESSAGE("Should Have Thrown Exception"); 218 | } 219 | Catch(e1) 220 | { 221 | TEST_ASSERT_EQUAL(0xBF, e1); 222 | Try 223 | { 224 | HappyExceptionThrower(0x12); 225 | } 226 | Catch(e2) 227 | { 228 | TEST_ASSERT_EQUAL(0x12, e2); 229 | } 230 | TEST_ASSERT_EQUAL(0x12, e2); 231 | TEST_ASSERT_EQUAL(0xBF, e1); 232 | } 233 | TEST_ASSERT_EQUAL(0x12, e2); 234 | TEST_ASSERT_EQUAL(0xBF, e1); 235 | } 236 | 237 | void test_CanHaveMultipleTryBlocksInASingleFunction(void) 238 | { 239 | CEXCEPTION_T e; 240 | 241 | Try 242 | { 243 | HappyExceptionThrower(0x01); 244 | TEST_FAIL_MESSAGE("Should Have Thrown Exception"); 245 | } 246 | Catch(e) 247 | { 248 | TEST_ASSERT_EQUAL(0x01, e); 249 | } 250 | 251 | Try 252 | { 253 | HappyExceptionThrower(0xF0); 254 | TEST_FAIL_MESSAGE("Should Have Thrown Exception"); 255 | } 256 | Catch(e) 257 | { 258 | TEST_ASSERT_EQUAL(0xF0, e); 259 | } 260 | } 261 | 262 | void test_CanHaveNestedTryBlocksInASingleFunction_ThrowInside(void) 263 | { 264 | int i = 0; 265 | CEXCEPTION_T e; 266 | 267 | Try 268 | { 269 | Try 270 | { 271 | HappyExceptionThrower(0x01); 272 | i = 1; 273 | TEST_FAIL_MESSAGE("Should Have Rethrown Exception"); 274 | } 275 | Catch(e) 276 | { 277 | TEST_ASSERT_EQUAL(0x01, e); 278 | } 279 | } 280 | Catch(e) 281 | { 282 | TEST_FAIL_MESSAGE("Should Have Been Caught By Inside Catch"); 283 | } 284 | 285 | // verify that i is still zero 286 | TEST_ASSERT_EQUAL(0, i); 287 | } 288 | 289 | void test_CanHaveNestedTryBlocksInASingleFunction_ThrowOutside(void) 290 | { 291 | volatile int i = 0; 292 | CEXCEPTION_T e; 293 | 294 | Try 295 | { 296 | Try 297 | { 298 | i = 2; 299 | } 300 | Catch(e) 301 | { 302 | TEST_FAIL_MESSAGE("Should Not Be Caught Here"); 303 | } 304 | HappyExceptionThrower(0x01); 305 | TEST_FAIL_MESSAGE("Should Have Rethrown Exception"); 306 | } 307 | Catch(e) 308 | { 309 | TEST_ASSERT_EQUAL(0x01, e); 310 | } 311 | 312 | // verify that i is 2 313 | TEST_ASSERT_EQUAL(2, i); 314 | } 315 | 316 | void test_AThrowWithoutATryCatchWillUseDefaultHandlerIfSpecified(void) 317 | { 318 | //Let the fallback handler know we're expecting it to get called this time, so don't fail 319 | TestingTheFallback = 1; 320 | 321 | Throw(0xBE); 322 | 323 | //We know the fallback was run because it decrements the counter above 324 | TEST_ASSERT_FALSE(TestingTheFallback); 325 | TEST_ASSERT_EQUAL(0xBE, TestingTheFallbackId); 326 | } 327 | 328 | void test_AThrowWithoutOutsideATryCatchWillUseDefaultHandlerEvenAfterTryCatch(void) 329 | { 330 | CEXCEPTION_T e; 331 | 332 | Try 333 | { 334 | //It's not really important that we do anything here. 335 | } 336 | Catch(e) 337 | { 338 | //The entire purpose here is just to make sure things get set back to using the default handler when done 339 | } 340 | 341 | //Let the fallback handler know we're expecting it to get called this time, so don't fail 342 | TestingTheFallback = 1; 343 | 344 | Throw(0xBE); 345 | 346 | //We know the fallback was run because it decrements the counter above 347 | TEST_ASSERT_FALSE(TestingTheFallback); 348 | TEST_ASSERT_EQUAL(0xBE, TestingTheFallbackId); 349 | } 350 | 351 | void test_AbilityToExitTryWithoutThrowingAnError(void) 352 | { 353 | volatile int i=0; 354 | CEXCEPTION_T e; 355 | 356 | Try 357 | { 358 | ExitTry(); 359 | i = 1; 360 | TEST_FAIL_MESSAGE("Should Have Exited Try Before This"); 361 | } 362 | Catch(e) 363 | { 364 | i = 2; 365 | TEST_FAIL_MESSAGE("Should Not Have Been Caught"); 366 | } 367 | 368 | // verify that i is still zero 369 | TEST_ASSERT_EQUAL(0, i); 370 | } 371 | 372 | void test_AbilityToExitTryWillOnlyExitOneLevel(void) 373 | { 374 | volatile int i=0; 375 | CEXCEPTION_T e; 376 | CEXCEPTION_T e2; 377 | 378 | Try 379 | { 380 | Try 381 | { 382 | ExitTry(); 383 | TEST_FAIL_MESSAGE("Should Have Exited Try Before This"); 384 | } 385 | Catch(e) 386 | { 387 | TEST_FAIL_MESSAGE("Should Not Have Been Caught By Inside"); 388 | } 389 | i = 1; 390 | } 391 | Catch(e2) 392 | { 393 | TEST_FAIL_MESSAGE("Should Not Have Been Caught By Outside"); 394 | } 395 | 396 | // verify that we picked up and ran after first Try 397 | TEST_ASSERT_EQUAL(1, i); 398 | } 399 | -------------------------------------------------------------------------------- /test/support/CExceptionConfig.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | CException - Simple Exception Handling in C 3 | ThrowTheSwitch.org 4 | Copyright (c) 2007-24 Mark VanderVoord 5 | SPDX-License-Identifier: MIT 6 | ========================================================================= */ 7 | 8 | #ifndef _EXCEPTION_H 9 | #define _EXCEPTION_H 10 | 11 | #include "unity.h" 12 | 13 | extern volatile int TestingTheFallback; 14 | extern volatile int TestingTheFallbackId; 15 | 16 | //Optionally define the exception type (something like an int which can be directly assigned) 17 | #define CEXCEPTION_T int 18 | 19 | // Optionally define the reserved value representing NO EXCEPTION 20 | #define CEXCEPTION_NONE (1234) 21 | 22 | // Optionally define a special handler for unhandled exceptions 23 | #define CEXCEPTION_NO_CATCH_HANDLER(id) \ 24 | { \ 25 | if (!TestingTheFallback) \ 26 | { \ 27 | TEST_FAIL_MESSAGE("Unexpected Exception!"); \ 28 | } \ 29 | else \ 30 | { \ 31 | TestingTheFallbackId = id; \ 32 | TestingTheFallback--; \ 33 | } \ 34 | } 35 | 36 | // Multi-Tasking environments will need a couple of macros defined to make this library 37 | // properly handle multiple exception stacks. You will need to include and required 38 | // definitions, then define the following macros: 39 | // EXCEPTION_GET_ID - returns the id of the current task indexed 0 to (numtasks - 1) 40 | // EXCEPTION_NUM_ID - returns the number of tasks that might be returned 41 | // 42 | // For example, Quadros might include the following implementation: 43 | #ifndef TEST 44 | #include "OSAPI.h" 45 | #define CEXCEPTION_GET_ID (KS_GetTaskID()) 46 | #define CEXCEPTION_NUM_ID (NTASKS + 1) 47 | #endif 48 | 49 | //This could be a good place to define/include some error ID's: 50 | #define ERROR_ID_EVERYTHING_IS_BROKEN (0x88) 51 | #define ERROR_ID_ONLY_THIS_IS_BROKEN (0x77) 52 | 53 | #endif // _EXCEPTION_H 54 | --------------------------------------------------------------------------------