Implementing Calculations

Just to get started, I wanted to create a text editor that would detect when a mathematical expression is entered, and supply an answer. Using NSEvents’ keyDown: method, I can detect when the equal sign is entered, and then parse the expression by overriding the insertText: method:

– (void)insertText:(NSString *)input { if([input isEqual:@”=”]) {   [super insertText:input];   myCalc = [[Calculator alloc] init];   [super insertText:[myCalc calc:@”2+2″]];

So, for now I’m not parsing what the user actually enters, because I haven’t figured out how to do that yet. Instead, I initialize my Calculator object, and send it “2+2” — this is hardcore math, folks.

Here’s a conundrum. How do you implement a method that accepts a string like “2+2” — or (64+23) * 2.3 / 12 — and return the answer? I went to Google.

The first thing I came across was a library of C code that does exactly this. Excited, I downloaded the source, added it to my project, included the header file, and called the function. It worked like a charm! And that’s when I noticed the licence on this code: it’s GPL.

If you know anything about software, it’s clear to you what the problem is with the GPL. I really dig the GPL; it’s brought us a lot of great software over the years, not the least of which is Linux. But it’s a viral licence: anything that uses GPL software itself must also be GPL, which means you have to make the source code available for free. Not only would I not be able to sell my software, but people would see what a lousy coder I am! Screw that noise.

I did some more research, and discovered a tool built into OS X’s UNIX underbelly, called bc. If you open Terminal and type

echo ‘2+2’ | bc

you’ll get

4

bc is a piece of GPL software, but since I don’t have to build it into my program, I can use it without tainting my own licence. Woohoo! Now let’s implement the damned thing.

Say hello to NSTask. This is the class that lets you bring in other applications to do some work for your app. It’s best for shell apps like ditto. You declare the path to the shell app, create an NSArray of arguments, and then launch it. You specify a stdout and use the data in your own app. Cake and pie, right?

In this case, not so much. Unfortunately, bc isn’t a classic UNIX application in the common sense; it’s an interactive shell rather than a simple command line parser. This turns out to be a complicating factor when you implement it in Cocoa. So you can’t just send an argument to bc and get back an answer. You have to send it to echo, then pipe it through bc. Now, I’ve pored over Apple’s sparse documentation on using NSPipe to create pipes, but for the life of me I can’t understand it.

So far, here’s my workaround: I wrote a shell script that will take the argument and give the answer. It’s stupid simple:

!/bin/bash echo $1 | bc

Crazy simple, eh? I called it mybc, made it executable, and included it in my project. Now I just have to figure out how I can call it.