Building Quincy 2000

Dr. Dobb's Journal November 2000

By Al Stevens

Al is DDJ's senior contributing editor and can be contacted at astevens@ddj.com.

It had to happen. In April 1991, I introduced in this column a user interface C function library project that would run in monthly installments for a year and a half. The project was to be called "D-Flat." Why such an odd name for a function library? I explained it thusly then:

Because all the really good C-oriented puns have already been taken (C-Worthy, C-Scape, and so on), I will call the package "D-Flat," which is another way of saying "C-Sharp." I will not use "C-Sharp" itself because there is almost certain to be someone out there with a trademark registration and a lawyer on the payroll. D-Flat sounds safer somehow.

As it turns out, there was no C-Sharp, and I could have used the name without worry. Until lately, that is. Last month's issue of DDJ includes an article by Scott Wiltamuth about Microsoft's new programming language for Internet applications with the highly original name "C#," which, as any musician knows, is C-Sharp. The article even points out that C# is to be pronounced, "C-Sharp."

A scary trend is developing. In September 1991, DDJ published David Betz's tiny object-oriented programming language named "Bob." Not long afterward, Microsoft published its operating environment also named "Bob." I named my operating environment library D-Flat as a pseudonym for C-Sharp. Microsoft waited nine years and named its tiny object-oriented programming language C# as shorthand for C-Sharp.

Nine years. It doesn't often take the kids at Redmond this long to rip off a good idea. They're usually sharper than that.

Upgrading Quincy

I just started upgrading Quincy 99 to Quincy 2000. I discussed some of this a few months ago with good intentions of getting started then, but the effort got sidetracked. For newcomers to the column, Quincy is an Integrated Development Environment (IDE) that hosts the GNU C/C++ compiler suite of tools on the Win32 platform. I included Quincy 99 on the companion CD-ROMs with two C++ books that I published this year. Earlier versions of Quincy (96, 97) accompanied earlier editions of the books and the Al Stevens C/C++ Cram Course CD-ROM that DDJ produced and marketed.

I'm upgrading Quincy to a major new release for two reasons: First, there are several features I have been wanting to add, for example, a better programmer's editor. Second, I am in the process of organizing, editing, and compiling a new book based on the content and code of this column for the past 12 years. This book will be a retrospective of sorts, and a kind of history of how technology has changed and grown and how this column has moved with it. My books traditionally include a compiler along with source code, so naturally I wanted to maintain the tradition and use Quincy. But Quincy 99 is a bit long in the tooth and needs a facelift.

The past dozen years marked a lot of paradigm shifts in desktop system development -- text mode to GUI applications, functional to object-oriented programming, C to C++, 16- to 32-bit applications, the 640K memory limit to unlimited virtual memory, slow platforms needing a lot of hardware optimizations in the software to fast systems that support device independence, and so on. The new book, with the cumbersome working title of "The Dr. Dobb's Journal C Programming Column: A Twelve Year Retrospective," will include lots of narrative and code from the column, organized in a way that demonstrates these shifts, and with plenty of retrospective comments to add today's perspective to the somewhat aged content.

The book will include a CD-ROM, and the CD-ROM will include a compiler and the code from the column. Ideally, the compiler compiles all the code, but that might not be the case here. A lot of the code from times past reflects what programmers did in times past to get PCs to work. There are TSRs (remember them) and all kinds of low-level hardware access. Some of these programs intercept interrupts by hooking and chaining interrupt vectors. Many of them directly access the PC's BIOS by issuing programmed interrupts. Most of them directly access video memory and even do hardware tricks to avoid video flicker when they write characters to the screen. There are programs that do their own overlaying. There are programs that have to know about the PC's real mode segmented memory architecture. And on and on. I can't believe we used to routinely write code that necessarily did that kind of stuff or that we even had to know about it.

These programs use low-level functions that every C compiler included but that are not part of any standard. Functions with cryptic names such as int86, setvect, and so on. Compiler vendors contrived their own function names for these things and they seldom agreed. It's a wonder we ever got anything done. Not surprisingly, contemporary compilers tend not to support these low-level primitives. Most of the code I published in the first several years of this column will not compile on any contemporary compiler, as near as I can tell, much less on the free GNU compiler that I usually include.

But a lot of the code does compile with Quincy's GNU compiler. Surprisingly, the very first program I published in my first column in August 1988 compiles clean under Quincy and runs correctly without needing any changes to bring it up to speed. Some of the others might not -- or will not. I haven't decided how hard I'll try to get some of that older code working.

It's like having an old bicycle from the 1950s. It might be an interesting project to get it running smoothly again, but when you are finished, all you have is an old bicycle from the 1950s.

Quincy 99

Quincy 99 is an MFC application that uses the Win32 Multiple Document Interface (MDI). The documents can be an application's project file, which lists the source-code modules that build the application, and the application's source-code files themselves. The editor works only with the source-code files. Quincy 99 employs the MFC document/view architecture in Figure 1. The editor's document class, CTextDocument, is derived from MFC's CDocument class. It uses MFC's CEditView::SerializeRaw function to read and write text. The only really interesting thing it does is convert single line-feed characters into carriage return and line-feed pairs in the input text data in the Serialize function. Quincy's document view class, CTextView, is derived from the MFC CEditView class to use the base class's CEdit control to manage text editing. CTextView includes a bunch of code that supports the IDE's program build and executes menu commands and some other processes to support displaying breakpoints and the program counter during debugging. If you want to examine this code, download Quincy 99's source code from DDJ (see "Resource Center," page 5) or http://www.midifitz.com/alstevens/ quincy99/.

Editor

In January 1999, I published in this column a standalone programmer's editor unimaginatively called "Editor." My intentions were to get it working on its own and then move it into the Quincy IDE. I did get it working some time ago, but the move has only just begun.

The Editor program itself was an exercise in using the Standard C++ STL containers to implement the insides of a programmer's editor, and I was pleased with the result. This column addresses the pain and suffering I endured porting Editor into a working IDE.

Editor, like Quincy 99, is an MDI application that uses MFC's document/view architecture shown in Figure 2. The Editor's document class, CEditorDoc, also derives from MFC's CDocument class. But this class does a lot more. Since Quincy 2000 does not use the CEditView class, CEditorDoc has to do its own text input and output. It also has to manage the internal format of the text data and take care of inserting, replacing, and deleting text in response to user action as managed by the view class. CEditorDoc also manages the interface with the undo/redo actions, which I implemented by using a generic undo/redo template class library, which I published in November 1998.

Editor's view class, CEditorView, derives from MFC's CView class, which means it has to do everything involved with displaying a text document on the screen. It draws the text, reads the keyboard and mouse, positions the insertion caret, manages text find/replace commands, pages and scrolls the text, handles clipboard operations, marks selected blocks of text, prints and print previews, and processes user-editing actions by interacting with the CEditorDoc class. In other words, it includes all the stuff that the hidden CEditView class does for Quincy 99, only better. In addition, CEditorView implements keyboard macros and syntax color highlighting.

The Editor program's source code is available electronically from DDJ (see "Resource Center," page 5) or http://www .midifitz.com/alstevens/editor/.

Integrating Quincy 2000 and Editor

The first job in building Quincy 2000 is to replace its editor, which uses the Win32 Edit control, which limits file sizes to about 32K, and which is generic text editing -- no smart indenting, syntax coloring, macros, or the like. The Editor program has these features, so Editor is the editor of choice to upgrade Quincy. That is no accident. I designed Editor with that objective in mind. I designed the standalone Editor program to be integrated with Quincy, not as a launched program but as an integral part of the IDE.

Look again at Figure 1. CTextDocument manages those things about a text document that are unique to its participation in an IDE. Likewise CTextView deals with the aspects of the view that support the IDE. Neither one is particularly involved in the text or its editing because the MFC classes that implement the Win32 Edit control take care of that.

Now look at Figure 2. CEditorDoc and CEditorView deal with the document and view aspects of text editing and have no knowledge of what an IDE needs. If I did a proper job in the design of the two programs, integrating them should be a simple matter of replacing MFC's CEditView class with its higher level CView class and then sandwiching Editor's document and view classes into the design as Figure 3 shows. After that, it would simply be a matter of putting the editor's commands on the menus.

Of course there was bound to be some overlap. Some of what Quincy 99's classes do are replaced by Editor's classes. The two WinApp-derived application classes had to be merged, too. But the effort should be minimal.

Well, I almost did a proper design job. Figure 3 does indeed represent Quincy 2000's document/view architecture. But the integration wasn't that clean. At first it seemed like a smooth ride. I did the port as the figures indicate, resolved the code conflicts, and got a clean compile. Bless me, the darn thing ran first time right out of the chute. Quincy 2000 opened itself up with a source-code file with syntax coloring. I did some text edits and they all worked. Cut, copy, paste, undo, and redo all worked. The macros worked. I was ready to declare victory and publish.

Line Dancing

Then I ran the debugger. That's when I found out what a really sloppy job I had done with Quincy in the first place. It has to do with line numbers. There are many places in an IDE that concern themselves with document line numbers. The program has to display text lines based on the current scroll position. It has to record line numbers to set and process breakpoints. It has to display the current line number where the debugger is stepping. It has to associate the line numbers of each source code file with their executable memory addresses. It has a lot to do with line numbers.

There are two ways a program can reference line numbers -- relative to 0 and relative to 1. There are many line-number data points in a GUI editor -- the current line number in the text that the insertion caret points to, the text line number displayed at the top of the text window, the inclusive line numbers of a marked text block, and on and on. There are two data representations of line numbers in a GUI application -- the text line number and the window's pixel row number. There are the number of text lines and pixel rows in a window's client area.

I am sad to report that Quincy 99 is a mish-mash of all these line-number configurations. Somehow, it all works, because as I carefully crafted the original Quincy IDE to these many years ago, I knew at each step along the way, maybe only subconsciously, which line number representation was involved at any given point. I had none of this in mind when I built the Editor program. Consequently, when I ported the editor to Quincy 2000, the fragile interface between the debugger, which manages where the program counter and breakpoints are, and the editor, which displays them, came crashing down.

Testing, debugging, and repairing the line-number anomalies is a nightmare. Each time I find a program counter, breakpoint, or insertion cursor being displayed on the wrong line (or completely out of sight), I carefully repair the code that positions it, only to find that I have broken some other place where things used to work. I have taken time out from this tedious task to write this column, deadlines being deadlines. I am resolved, however, to get it all to work, even if it means ripping apart some really deep, dark code that has been working for years.

By the time you read this, Quincy 2000, Build 1 (at least) with the new editor will be available electronically from DDJ and from http://www.midifitz.com/alstevens/ quincy2000/. It's open source. If you download it and the line numbers don't work, please fix the program and send it in to the magazine. I will by then have been outfitted in a tight-fitting white canvas jacket with wrap-around sleeve straps and tossed in somewhere where the walls are padded so I can't hurt myself, and insulated so you can't hear my screams.

DDJ