Skip to main content

curses setjmp/longjmp

In 1992, I was maintaining a UNIX inventory system that was developed around a screen template system that used the curses library to implement a pretty standard menu tree with data screens as leafs:

My job was to add a new screen, the red box, and the red transition lines to do a master-detail pair of screens. 

The way this system worked is that a set of screen definition files would be run through a code generation program to generate the C code that would keep track of the menu path and the fields in the data screens.

Each of these screens would have a 80x24 template with field names following by a special replacement character for different field types.  For example, you could have a part of the screen say:
Ship Date: MM/DD/YY
or
Comments: @@@@@@@@@@@@@@@@@@@
and the code generator would create all of the code necessary to define structures that had a ship_date members and a comments member, handle moving from field to field with the tab key, etc. along with very simple character based data validation (MM was 01-12, DD was 01-31, @ was any text character).

The underlying custom library had two interesting features which complicated development:

  1. Moving between the menu and data screens was done via setjmp()/longjmp(). When leaving the menu definitions, the code would call setjmp().  When the changes were completed or aborted in the data screens, the code would call longjmp() to return.  This simplified the screen code generation because it didn't need to keep track of the various paths.  It was an implementation of GOTO considered harmful in the wild.
  2. Event tracking in the C code was for individual key strokes and it was tied quite closely to the curses interface.
This created the following issues I needed to overcome:
  • I now had two levels of setjmp()/longjmp(), so I needed a way to execute the right longjmp() buffer when existing screens.
  • I also had the possibility of a loop in the screens because the new requirements allowed moving from one data screen to another.
With the benefit of coding in X-Windows, Motif, Java Swing, and more AJAX libraries than I care to remember, the best practice way to deal with this problem would have been to implement a reactor pattern that would have moved the state management out of the C stack and into a real data structure.

But I didn't know that then, so that's not what I did.  What I did was break more rules.

First, I created a global stack data structure of pointers to setjmp()/longjmp() buffers.  This way, when I entered a page, in addition to calling setjmp(), I would also push the buffer onto the stack.  When I left the page I could pop the next buffer off of the stack and be ready for the next longjmp() call.

Second, I had to deal with the possibility that the user could move back and forth from data screen to data screen, each time adding a buffer entry to the stack.  I worked around that problem by generating synthetic events that would move from screen to screen via the existing menu structure:
So transitioning from one data screen to another performed the expected longjmp() call which was then followed by made up events to navigate back down to the correct screen, breaking the graph cycle and making the design work correctly.

What to take away from this tale?
  • Don't make a library boundary something that prevents you from finding a better solution to a problem.  The whole refactoring methodologies and practices have been created specifically so you don't make this same mistake.
  • If refactoring isn't an option, you can work around technical boundaries, but you may have to break some rules to do so.

 

Comments

Popular posts from this blog

Spring Boot native builds when internet downloads are blocked made simple

 No direct access to the internet If you work at a company that controls their software bill of materials, it's quite common to be blocked from directly downloading from: Maven Central Docker hub GitHub (the public parts) Getting the bits Maven Maven is first, because without it, you won't be able to compile your Spring Boot application, let alone move on to turning it into a native docker image. I will be showing changes need to work with artifactory, but you should be able to adapt it to other mirror solutions.  repositories {   maven {     name = "central"     url = "https://artifactory.example.com/central"     credentials {       username = "${project.ext.properties.artifactory_username}"       password = "${project.ext.properties.artifactory_apikey}"     }   } } With this configuration change, you should be able to download your plugins and dependencies, allowing you to compile and ...

Kotlin Notebook when you're blocked from Maven Central

 TLDR; If you are blocked getting to maven central when first using Kotlin Notebooks because of company firewalls, you can use a tool like Fiddler Tool to redirect to a different network location. Kotlin Notebooks Kotlin Notebooks are a JDK based environment that brings the Python based Jupyter Notebooks  expressiveness to IntelliJ. From the blog post announcing the plugin, it looks like this: At home, the installation of jar files looked like this: I played around with it at home, but I couldn't use it at work.  Many companies, mine included, do not allow software components to be used when downloaded directly from the internet. In my companies case, we use a product called Artifactory, which allows you to mirror the content from Maven Central while still applying policies like CVE scanning, tracking, etc. The way it should work IntelliJ, as one of the leading IDE's, generally supports this quite well.  In fact, there is a whole setting page dedicated to dealing wi...

Active vs. Passive Log4jShell remediation

 Log4jShell  All computer professionals should be aware of the Log4jShell ( CVE-2021-44228 ) and it follow on defects.  There is no shortage of opinions and lessons to be be learned: The difficulty of performing safe interpretation The problems when assumptions are not clearly documented.  I, for one, was completely shocked to find out that a logging system would actually attempt to do variable substitution in an actual message. The difficulty of finding and resolving issues with such a common library that is not provided by an OS package manager. IT'S A LOG4J CHRISTMAS One of my favorite podcasts, Security Now - episode 850 , discussed an analysis by Google regarding the depth of log4j dependencies.  From the show notes : One contributing reason is because Log4j is, more often than not, an indirect dependency. Java libraries are built by writing some code which uses functions from other Java libraries, which are built by writing some code which uses functions f...