How To Sort in C++

... So I was attempting to write an extremely obscure out-of-the-way function in C++: I wanted — send the children from the room! — to sort lines of text without case sensitivity! ... Since you will doubtless be unaware of the subtleties of this super-computer-science secret decoder ring idea, case-sorted strings are like this —

I
am
frend
your

— while strings sorted without regard to case are like

am
frend
I
your

... Tricky, eh? ... Gotta fly in programmers from the coast, right? ... But please note: our problem domain is C++. ... I don’t want to sort barbaric insect-level C strings, no no; any fool can do that with qsort! ... No, I want to sort an EZ-to-use C++ string list, aka “std::list<std::string>”....

... So I googled and googled for hours and hours, and was reminded of the deathless sentiment of a fellow I worked with at Satellite Transmission Systems so many golden years hence: “you ask for the time, and he tells you how to build a watch”. ... The most useful page I found claimed to explain a “naive” way to accomplish the goal — without actually showing a working example — but then cautioned that, regardless of the seeming incomprehensibility of the solution, it wouldn’t work with text containing a ü,1 and then proceeded to outline several additional bad solutions + various complexities, and when I gave-up I think was moving on to Superstring theory — but no working example....

... And that was the best I found. ... Excluding the outstandingly scammy “experts exchange” where you can submit your credit card to find out what they don’t know. ... After hours of search I could not find a single demonstration of case-insenitive C++ string list sorting....

... So I will divulge this innermost hermetic secret I discovered with my own primitive text editor and a few compilers. ... I realize my example is a little lengthy, as it includes comments — an exotic little-used programming element — but after my hours of googling I thought it was worth a shot. ... Anyway, here is how I and now you can case-insensitive sort a string list in C++ (and here is a little zip of the code):2

/**************************************************
howtosort.cpp
Wed 2/28/2007 6:42 pm creation
Mon 4/16/2007 6:51 pm discovered strcasecmp!

Reveals the hidden secret of the ages,
the uttermost hermetic gnostic truth:
how to do case-insensitive string sort
in C--.

Please note this code compiled successfully under
obsolete Borland Builder C++ version 5, and the
utterly update-to-date Macintosh X 10.4 g++!

j.g. owen * * * * * * * * * * * * * * * * * * *
web:   http://owenlabs.home.att.net/
email: owen_bda4@yahoo.com
* * * * * * * * * * * * * * * * * * * * * * * *

**************************************************/

#include <stdio.h>
#include <string>
#include <list>

using namespace std;

typedef list<string> JSTRINGLIST;

#if defined(__GNUC__) && (__GNUC__ >= 4)
  #define stricmp strcasecmp
#endif

int jstringicmp(const string &one, const string &two) {
  return stricmp(two.c_str(),one.c_str());
}

bool mysort(const string &a, const string &b) {
  return jstringicmp(a,b)>0;
}

bool myrevsort(const string &a, const string &b) {
  return jstringicmp(a,b)<=0;
}

int main(void) {

  JSTRINGLIST what;

  what.push_back("drive_crazed");
  what.push_back("hey");
  what.push_back("Hey");
  what.push_back("Babe");
  what.push_back("drive");
  what.push_back("Me");
  what.push_back("crazed");
  what.push_back("Drive_crazed");
  what.push_back("Drive");

  what.sort(mysort);

  JSTRINGLIST::iterator i;

  for (i=what.begin(); i!=what.end(); ++i) {
    printf("%s\n",i->c_str());
  }

  what.sort(myrevsort);
  printf("\nBackwards:\n\n");

  for (i=what.begin(); i!=what.end(); ++i) {
    printf("%s\n",i->c_str());
  }

  return 0;

}

... I must concede there are a number of things obviously wrong with the example, clearly violating the ISO Hermetic Drivel Standard:

  1. It isn’t drowned, positively smothered covered oily scunged, in mumbo-jumbo.
  2. I don’t even refer to my doctorate, my seven other web sites, the university where I teach, and the really huge corporate buds I pal-around with.
  3. It works and is obvious.

... An actual fact: one reason it took me so long to decode the totally-opaque mumbo-jumbo of the web experts was because I had a bug in jstringicmp where I forgot to exit a for loop (no longer with us2), causing puzzling and annoying errors when I wandered out of range — these difficulties were of course made so obvious by the helpful transparent C++ errors and source debugging (translation: I spent a lot of time in STL “.h” files which are, of course, blindingly clear and easy-to-understand)....

— the ever-delving programmer
Tuesday, April 17, 2007


1. Sorting solutions involving toupper() will never be happy with ü; probably not ¥ either. ... That would probably be because of its relentlessly ASCII nature. ... The point is, would the guru’s case-insensitive sorting solution work flawlessly with Japanese? ... And who cares? ... Obviously the Japanese would, but they’re clever people and will doubtlessly figure these things out; as will the Germans. ... I just don’t understand why I have to....

2. A version of this with my own slow-and-stupid version of stricmp was here for some months because g++ on my iMini (X 10.4) didn’t have one! ... Then the world turned and whaddya know!? ... They didn’t off stricmp; they just renamed it, to the incredibly intuitive “strcasecmp”! ... That is just so useful: the old cryptic STRing Ignore CoMPare exchanged for the obviously wrong STRing ignore(?!) CASE CoMPare! ... I suppose I should credit my source for this revelation: objective C propaganda from Apple (The Objective-C Programming Language, “ObjC.pdf”) used the so-appropriately-named strcasecmp in an example, and from my eyes the scales fell!


The Sins of C++

The programming magazines are disappearing — and the jobs — and the remaining suspects concentrate on amazing new interpreted script thingeys. ... Why is that?! ... Oh Why!?!?...

Well ... J’accuse! ... It’s because it didn’t work! ... The whole C++ megilla! — the derivation, the polymorphism, the wretched templates — it was all a colossal waste of time! ... Oh, Owen, calm down, watch the blood pressure! ... Well OK of course there were doubtless many other factors in the collapse of my little professional interest-area, including the dot-com catastrophe and ever-menacing outsourcing. ... But still — so much language innovation — so little to show for it! ... Random example: the two best articles in a recent issue of the poor devolving Dr. Dobb’s were (1.) an autumnal shot from Petzold on the latest “XAML” nonsense in Vista (XMLish graphics elements that sometimes auto-position themselves just like Java!), and (2.) Programming the Cell Processor, with code entirely in C! ... Hardly an inheritor nor polymorph in sight!...

... Consequently, hereon out I resolve to turn kinder thoughts on those pertinacious promoters who were after all, professors of my profession, toilers in my vineyard. ... It didn’t work out, whatever their sins, and even ’though they lied and lied as hard as they could! ... Now the dust and smoke has cleared and so little remains! ... Below I summarize, for perhaps the final go-round, a hit parade of some C/C++ sins, and then turn away, so much more in sorrow than in anger ... and move on....

The $Billion Bug: #if UNDEF

In real software there are often “conditionals” which are used, for instance, to make it so one giant chunk of code can be compiled for two or more different versions of Unix. The C language supports this with “conditional expressions” including “#ifdef” and “#if”. I’ve always assumed #ifdef came first (because some primitive compilers include it, but omit #if), but in the 1978 K&R book The C Programming Language they’re both described on the same page (208). They’re used like

#ifdef NUCLEAR_THREAT
  printf("flee! death!");
#endif

#if NUCLEAR_THREAT
  printf("death! disaster!");
#endif

But what if the programmer’s an idiot like me, and typos

    #if NUCLER_THREAT
      printf("flee! death!");
    #endif

(i.e., typos “NUCLER” for “NUCLEAR”?) what happens? ... What happens is — at least in generations of C compilers I have known and reviled — even ’though the typo “NUCLER_THREAT” symbol-name is not defined anywhere in the program, it nevertheless quietly compiles, conditionalizing-out the “flee! death” warning, and a small third-world country like Cincinnati is incinerated....

... For contrast, there are analogous thingeys in assembler (aka “The Language of The Gods”) which work; in assembler

    if NUCLER_THREAT
      ldx #threat_message
      jsr print_string
    endif

would in fact emit a nasty error message during assembly when NUCLER_THREAT wasn’t defined, and refuse to assemble the program — which is exactly what should happen — and doesn’t — in C-language! ... For some reason the ancient gurus of C-language felt that the #if should act just like the #ifdef if the thing in question wasn’t defined. ... I don’t know why they felt this way; I suppose you had to be there. ... I once queried Plauger the Great, and he was uninterested. ... And of course most software won’t incinerate Cincinnati! ... No, it’ll just quietly erase your Excel spreadsheet or lock your Mercedes. ... The only way I can see this not being true is if all the programmers are smarter than me and never use #if — but aside from being smarter, they’d also have to be a lot less lazy, and that I won’t believe....

The Linux Solution: GNU gcc “-Wundef”

Recent up-to-date compilers — the kind I never use — at least have a warning: i.e., the GNU/Linux compiler option

    -wUndef Warn if an unidentified identifier is evaluated in an #if directive

which would also, I imagine, explain how it is that the kernel bunch has, it is said, banned #ifdef in favor of #ifs. ... Frankly, I am unable to discover if a recent Microsoft compiler has such a warning, at least in the brief time allocated to me on this earth. ... Wait whoa my VS 2005 includes the Microsoft compiler. ... Sadly, the “Warnings and Errors” page in the MSDN help is blank. ... If it’s in there, I couldn’t find it in 10 minutes. I did verify it’ll compile “#if UNDEF” with no complaint. ...

Delphi too

Oh my poor proprietary Borland Delphi! Recent versions have an “if” syntax which does the same thing:

{$if UNDEFINED}
#error:
{$endif}

It produces no error. ... I’m so disappointed....

C++ References: Misfeature?

There are (at least) two ways to pass arguments to program subroutines in a computer language: by value, and by reference. ... There might be code like

    int x;
    ...
    A_function(x); //by value; can’t change x.
    B_function(x); //by reference; can change x.
    ...

where “A_function” does something to x, but nevertheless leaves the original x unchanged, while B_function might, if it felt like it, add 17 to x, and the change would persist even after B_function departed. ... In such a case, it is said that B_function’s argument is treated as a reference, while “A_function” is passed x by value: a copy of x is supplied to “A_function”, and whatever it does with it won’t affect the original x....

... Now obviously a situation like that depicted above is bad, because when we’re reading the code, we can’t tell that one of the functions uses a reference, the other, a value. ... But, as a feature, C++ lets you do that. ... The standard K&R C, from whose forehead C++ sprang, doesn’t....

Bug/feature? It was commonplace for ignorant C++ propaganda to pretend that K&R C was too stupid to support references. ... But to those of us who know anything it’s obvious K&R was deliberately contrived that way, among other things, to avoid the ambiguity of “invisible” reference/value distinctions. ... So, in standard C, the above would be required to look like

    int x;
    ...
    A_function(x);
    B_function(&x); //ampersand means the value
                    //can be changed by the function.
    ...

... It’s unimportant what the “&” does; what’s important is it forces a distinction between the two kinds of argument-passing, thus making standard C inherently less buggy than C++ in this particular area; and it’s not because Dennis Ritchie was too dumb to know any better, but indeed was itself an ingenious and useful innovation over cruder languages. ...

The STL1 Templates: Perfect Reusable Code

It’s a fundamental truth about the historical software concept known as reusable code (also, sometimes, as the “Holy Grail”): sadly, as opposed to relentless propaganda, reusable code like everything else in this vale of tears has costs along with its benefits. ... Numerous modern software lunacies have foolishly denied the cost part in their puffery: C-language libraries of yore, the “components” of Delphi and other languages — the latest Vista tripe follows the dishonorable tradition. ... I could pick at the STL’s particular annoyances, its incomprehensible error messages from the dark side, the ease and pleasure of debugging in it — but the truth is, it’s no different from the parade of language features down the wandering years: the good parts aren’t free! ... Judging by the reality today, something in C++ — and I’ll nominate templates and the STL, simply because they’re an order of complexity weirder than the rest of the language — was judged too costly by the language-consuming public....

& C++ is Ugly

Finally, observe this pretty-much random example:

    copy(diffs.begin(),diffs.end(),
    ostream_iterator<int,char,char_traits<char> >(cout," "));

... And this is an example! ... Please; it is not good that a computer language looks like line noise2 — despite the gushing opinions of the guru-ocracy....

... But Still Useful

I do not wish to leave the impression that C/C++ is an evil pointless thing; it is still my favorite programming language, at least, and it is still widely used — the Linux kernel, probably the most prominent software project of our times, is C-language and likely to remain so. ... But not C++. ... I suspect the majority of C/C++ is still really C, no matter the “.cpp” extension; I know I often use C++ as a “super-syntax” checker to tidy-up my C code, and probably others do too. ... But I have nothing against the enhancements that C++ offers, and I’ll whip-up a class or use a built-in (kind-of) like the string type when it’s convenient....

... But what I wish, and what I’m fairly certain is not going to happen, is that C++ features were actually as easy-to-use as, say, the 1995 Delphi! ... That C++ features aren’t easy-to-use and indeed are significantly more annoying than newer and older languages — that’s the disappointment and, what with the passing of time and all, seems likely to remain so....

— the sometimes-professional programmer
Wednesday, March 21, 2007 10:26 am


1. If you have a copy of Borland’s C++Builder version 5, there is a charming antique directory of STL examples somewhere around c:\Program Files\Borland\CBuilder5\Examples\StdLib\; they never finished the GUI demo program there, but I did — more-or-less — and here it is; you have to replace their std1.* with the three source files in jgostl.zip; see comments in my std1.cpp....

2. Knowing what “line noise” means shows I’ve been failing to measure-up since RS232 terminals were popular; noise would produce amusing trails of meaningless punctuation and odd characters — i.e., just like powerful modern programming languages....


C++ INI Files!

Just to show I’m a really smart fellow and there’re no hard feelings about those C-- sins ’n’ all, here is the beautiful and talented JDB.ZIP including the complete C++ source for a Windows-style INI file implementation. ... Which, when I was looking for one a few weeks ago, I couldn’t find for love or money — well, maybe for money, although who can tell? ... Anyway, over the years I’ve found Windows-style INI files an easy and predictable way to provide options for my software, so I wrote my own C++ version. ... + you get the “jdb” utility which as well as demonstrating my jIni class implements a little database feature using an INI file.

Wonders to Behold!

Finally — you may want to sit down for this — I am so smart that JDB compiles with Borland’s pitiful C++Builder, and a recent ming GNU compiler I got hold of for Windows, and — ta-da! — the g++ that comes with the Macintosh OS X in my imini! ... All with a single source! ... Totally portable! ... Today only!

And now — compiles in Microsoft Visual Studio 2005! ... Will the wonders never cease?!

— the humble programmer
Thursday, May 10, 2007 3:40 pm

Another kind of C: Apple’s Xcode IDE

The promoters of these things, the book writers and gurus, the web authorities, the manufacturer and all the usual suspects, do everything they can to keep difficulties obscure. ... But not me! I revel in them! ... And so today’s topic is Apple’s amazing Xcode “Cocoa” environment, the future of the Macintosh!

... As shown in the compelling illustration, if you use Apple’s Xcode IDE with the “Cocoa” framework — i.e. the Apple-recommended way to write new software for the Mac — you just draw connections from the cute Macintosh GUI forms and buttons and controls to your software! ... To heck with that boring code writing! You just click this and that, draw some lines, click a “Connect” button and Voila! ... It’s all done! ... Indeed, practically all the Objective C Code for my very first Macintosh program is

#import "HelloController.h"

@implementation HelloController
- (IBAction)sayTheThang:(id)sender {
  [helloSayer setStringValue:@"Apres dumb"];
  [text2_outlet setStringValue:@"2 dumb"];
}
@end

And that’s it! ... Of course, one problem with such incredibly EZ-does-it graphical techniques is they’re cryptic! ... I mean, what the heck is “helloSayer”? ... It turns-out the only place it’s named is in “HelloController.h” like

  IBOutlet NSTextField *helloSayer;
  IBOutlet NSTextField *text2_outlet;

+ that cute little graphical thingey up there, when I selected it in the “connections” gadget. Presumably the wild ’n’ crazy Objective C run-time fills them in, perhaps from the instructions in the “NIB” file that the EZ graphical stuff created, and points them to actual graphical text fields somewhere in space somehow....

Forbidden Knowledge

... But what, I plea, panting and sweating, what if I want to know where they really are, what their real names are, huh huh? ... “Why would you want to know that?” the all-knowing guru snarls with a sneer; “that is not for you, mere programmer!” as, in a swirling black cape, she leaves the programming dungeon, perhaps flicking a cattle-prod at a private part on the way....

... Anyway, there are numerous one-way GUI tools available for various platforms, which you can use to create your interface when you start writing a program; but then subsequently they’re not very useful as you elaborate the code and, presumably, how it looks. ... That is, if you never change the user interface, these one-way things work great! ... And the Apple gadget is one of them — even ’though the Xcode propaganda uniformly observes omerta on the subject — and I know this because I deleted the second text field in the GUI editor, compiled and ran, and nothing complained! ... Worked great! ... Even ’though the code was now referencing a presumably “nil” pointer (which, apparently, is a strength of Objective C, it’s so clever1) — or perhaps my code writes to an invisible text box which now will never die!?! ... (For more on GUI programming automation, see my newly-coined GUIRAD term.)

Owen Tip ’n’ Trick: Unknown Nameless Connections

One of the intensely puzzling things about the EZ-draw Xcode GUI is; how do you discover what you connected — i.e., later? ... Or, Heaven forfend, you’re not the original brilliant wunderkind author!? ... In Delphi or the fabulous .NET GUIRADs, you’d look at the event panel of the button or something, and there’d be exactly what code it was supposed to call when it was clicked or whatever; double-clicking this field’ll typically throw you into the code editor at the code — which code, in turn, would reference named things like Edit1 or Image1....

... Nothing like that happens in Xcode; there is no event panel, and it’s not that easy to see what’s connected to what! ... I’m sure somewhere in the nine million doc pages this is made blindingly clear (?), but I just couldn’t make those blue lines reappear! ... Well weep no more my lovelies, after the application of extreme stubborness I discovered at least one way is

  1. You get the NIB file showing (probably by double-clicking on a projects .NIB file, which starts-up the Xcode Interface Builder program).
  2. squiggle-shift-I to get the inspector.
  3. Click on the purple cube to select it.
  4. In the inspector, select “Connections”, “Outlets”.
  5. In the inspector, click on one of the outlets.
  6. Click on the same outlet again — DON’T double-click; just wait a while, and then click the highlighted thingey again.
  7. The connection bursts into a vividly colored line! ... If you click on the other outlet, the other connection will be shown. (To make the line disappear, click on the purple cube or the window or something.)
  8. If you want to see a target/action — a button connection — apparently the above won’t work; you have to click on the button with the inspector/connections page visible. Or something....

... And there you go! All is revealed!2...

A Yellow Triangle

Sometimes the cube or some other thing will display a tiny yellow circle (with an even tinier exclamation point inside), which is a complaint you’re supposed to fix — although it is completely unclear how. So http:// homepage.mac.com/ cp_stevenson/ 2005/ 11/ index.html has this helpful suggestion:

You can track down bad/missing connections in Interface Builder by changing the view in the nib window from icon view to list view (click the little tab in the top right of the window, right above the scrollbar) and disclosing items with the little exclamation mark by them.

Sadly, I had a yellow triangle and the helpful tip didn’t help, but at least I know what it thinks is wrong — I suspect it is sometimes delusional about these things. ... Ha la! Right again Owen! ... After opening the disclosure triangles until I got to the tippy tippy yellow triangle, hovering over it disclosed a tool tip which claimed my TableView was pining for a dataSource! ... This is odd because it’s been that way for weeks; I think adding another object to my menagerie today convinced the thing that the new object ought to be a data source or something. ... I of course set the data source programmatically to my main controller, which is so much more fun because that way I can mush everything together in a huge blob. ... There’s probably some way to do it with the magic blue lines and make the yellow exclamation point go away — but I couldn’t figure it out....

The Purple Cube

And just to finish-out this exhaustive explication, the “HelloController” cube represents your object which Xcode created for you: a little smidgeon of code which you presumably added-to/modified, if only a tiny bit, like above. ... The lovely “outlets” we were blue-lining are fields in that object, into which the omniscient Xcode magician has placed pointers to, in this case, text fields (i.e., in HelloController.h, as above) which your code will reference, to send the Xcode objects “messages” like [text2_outlet setStringValue:@“text”]....

... So simple, eh?

More Xcode Tips ’n’ Tricks ...

Command-Line Arguments & the Custom Executable: If you want to debug an average command-line console program in the Xcode environment, you just select “Command Line Utility” “C++ Tool” (or “Standard Tool” might do unincremented C) in the new project thing. Adding files was agonizing (a dialog for each!) until I realized I was supposed to drag them from the finder. ... And of course I had to delete the dummy “main.cpp” they install. ... But to run your executable with arguments I had to do “Project / New Custom Executable”; there’s help which more-or-less explains things (hint: they imply you might need several of these, but for changing command-line args at least just edit the single one; and oh yes, the executable target, which you must specify, might be in the build/debug folder off the project). ... Sadly they wouldn’t tell me how to use my custom executable, which I will now reveal: “Project / Set Active Executable”. ... So easy when you know how! ... If your command-line program for some reason desires console input, you can type it in the little “Run Log” window that shows-up. ...

Books: Step Into Xcode didn’t really thrill me,5 but my next attempt, O’Reilly’s Learning Cocoa with Objective-C (Davidson) was better: assumes C expertise, teaches OC. ... True, it’s dated — but so will they all be, when the next version of OS X shows-up just as soon as Jobs stops fooling with that iphone....

So EZ! Obj-C & C++: I was pleasantly surprised, however, to discover that mixing C++/C and Objective-C code is easy! (I offer an example below.) ... I was going through all kinds of conniptions trying to get cdecl3 to work so I could call C++ code from the C-like Objective C, when all I had to do was rename my controller file from the “.m” Objective-C extension to “.mm” for Obj-C++! ... Subsequently, I could call entry points in my .cpp files — and, as an added benefit, the make would complain if the callee was not prototyped! ... In boring unincremented Obj-C, you apparently can call anything, at least in the debug version, and the ingenious “zerolink” dev speed-up feature won’t complain until you actually run!4

Xcode Help: It’s not completely useless like Visual Studio, but ... well I had all kinds of theories, but I give-up; it’s erratic. ... I’ve taken to browsing online; it’s all up there somewhere — and you can change the type size in Firefox, for that geezer tiny type problem! ... However, neither shows you the methods, thoughts, and feelings of any classes what you’re trying to understand might’ve derived-from! ... Which makes it pathologically anti-useful. ... NSTextView, for instance, has a crucial method “setString” which I discovered by accident (sets the content) but why should that be in the help for NSTextView, eh!?!?! ... Well lookee they do say “Many of the methods that you’ll use most frequently are declared by the superclass; see the NSText class specification for details” and there’s setString! — so it’s all copacetic....

And At Last My Own Mac Program: IPW

Finally, you can get hold of my very own Xcode project, a password program, with Xcode source! ... Even better, OC++ and C++ source (BSD license), showing at least one not totally catastrophic attempt to use C++ strings and such with Xcode’s preferred OC. ... And now the source includes ipwbuts.png/ipwbuts.txt — actual documentation of the buttons and fields in the program! A star system first!

— the often dubious programmer
Friday, August 17, 2007 12:42 pm


1. Not only will Objective-C send messages to nil, it’ll happily compile “[7 bingo]! (It does warn.) ... Long ago there were C compilers that’d let you go “7()” — it’s actually necessary for some embedded stuff — but my current menagerie isn’t so tolerant. ... But OC will compile, run, and crash[7 bingo]! ... On the iMini!...

2. I used to think Apple provided an alternative to the blue line, involving the text you assign the fields and buttons — but that’s nonsense. Apparently, Interface Builder and the blue lines are all you got.

3. cdecl is apparently banned from Xcode; at least when I grepped in a bunch of .H files, the only thing I found was somebody #defineing it out of existence. ... And of course the compiler complains....

4. And I couldn’t turn-off the zerolink feature; actually it was unchecked in the options, suggesting Apple has already had second thoughts, but regardless, I couldn’t get link complaints until I ingeniously switched Xcode to the “release” version, which actually links everything — or tries too....

5. Fritz Anderson’s Step Into Xcode could be pretty-good for how Xcode and the Interface Builder (IB) do GUI programs, but it assumed for some reason I was an expert Objective C programmer! ... It also assumed I wished to drink deeply of the OC Koolaid, and write software whose objects are intimately entangled with OC, IB, and all it entails. ... But I don’t; if you do, you might like it. ... His grand “Linear” example wouldn’t build because of a nested function, which feature apparently departed this vale of tears at the arrival of the Intel Mac. ... Google for “Fritz Anderson” to find his home page and errata which, in this case, was basically to change it to a C macro.

DVD Data: Use DVD+R

Yup; just a little detail they forgot to tell me. ... Wasn’t I surprised when so many of my DVD-R data copies didn’t verify? ... Oh silly me. ... I’d guess stealing movies, the usual DVDR role, works great with + or -....

— the apoplectic programmer
Friday, November 14, 2008 5:30 pm