transcode compile error – preprocessor macros vs attributes

Had a problem compiling transcode 1.0.4 on my OS X Tiger (PPC).

In file included from /usr/include/math.h:26,
from pvnglobals.h:26,
from pvn.h:15,
from import_pvn.c:39:
/usr/include/architecture/ppc/math.h:179: error: parse error before '__attribute__'
/usr/include/architecture/ppc/math.h:179: error: parse error before 'inline'
/usr/include/architecture/ppc/math.h:180: error: parse error before '__attribute__'
/usr/include/architecture/ppc/math.h:180: error: parse error before 'inline'

… and so forth. The whole math.h business is a red herring; or rather, it’s a symptom, not the cause.

The issue appears to stem from a preprocessor macro problem in src/transcode.h. Around line 85 or so, find the block

#ifndef always_inline
#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0)
# define always_inline __attribute__((always_inline)) inline
#else
# define always_inline inline
#endif
#endif

A rather odd and potentially problematic thing to do, because now in math.h:83, we note:

#define __MATH_H_ALWAYS_INLINE__ __attribute__ ((always_inline))

which later gets used in math.h:179, 180, and so forth.

Now, because of the first #define, it seems we’re likely to cause __MATH_H_ALWAYS_INLINE__ to become something like __attribute__((__attribute__ ((always_inline)) inline)). Unlikely to compile cleanly.

One possible solution is to swap around the header orders so that math.h is included before transcode.h clobbers the always_inline definition.

Another workaround: comment out in the inner #if and preserve only the else-branch in transcode.h:

#ifndef always_inline
# define always_inline inline
#endif

It fixes the compilation problem, presumably because it no longer causes the always_inline definition to conflict with the one in math.h. Unfortunately, it also changes the meaning of __attribute__ ((always_inline)) in math.h. The first solution is preferable, even though it might be more tedious to trace the include blowups that result.

The moral of the story is that it’s usually bad to screw with built-in keywords via preprocessor macros.

Getting custom HTTP variables out of PHP

PHP 5.0 stores HTTP headers in the $_SERVER variable as key-value pairs. It mangles their field names, however, by:

  • prepending “HTTP_” to the key
  • replacing “-” with “_” in the key
  • uppercasing all letters

Say that your custom HTTP client sends X-Hello: World as a header. To retrieve the value (e.g. “world”) from PHP, the correct key to use is $_SERVER["HTTP_X_HELLO"].

This does fit with the existing access pattern (User-Agent: is retrieved by $_SERVER['HTTP_USER_AGENT']). But it was not well documented in corresponding page for reserved variables (as of today, October 7, 2007). Took a bit of trial and error for me to figure this out.

I’m sure that amongst the insanely numerous and ill-organized set of functions that PHP provides, there is one to do this exact task without reverse-engineering its key-mangling algorithm. But this way works too.

Entourage: thwarting archival strategies since 2004

So I use Microsoft Entourage as my main email client, and had been wanting for some time to get my messages exported out of my local drive. As much I trust my laptop and my backups, one good earthquake later and all of that would be futile.

Getting my message archives preserved (with all metadata intact, like Sent and Received dates, etc) was the easy part. Grabbing all future messages was the hard one. Of course, Microsoft, in its infinite wisdom, didn’t include an auto-bcc for Entourage.

I had this setup going on to automatically redirect most messages I send to a repository for later search and retrieval. I had a process set up where, except for select messages that I mark as confidential, the above rule gets triggered.

A month later, by pure chance, I realized that Entourage wasn’t quite deactivating the CC field on the redirect for archival. There is a bug that resends the message to all CC’ed emails on redirect. For example, if I were sending to [email protected], cc’ed to [email protected], and redirecting to [email protected]:

1. the first copy goes out to a and b.
2. Then, the redirected copy will be sent to archive and b, as b appears on the CC list.
3. End result: a receives 1 copy, b receives 2 copies, and archive receives 1 copy.

In essence, all the people I cc’ed on anything got spammed with a duplicate every time I sent a redirected copy via Entourage’s Outgoing rule. This is stupid, and Microsoft’s website doesn’t warn you about this. Try it for yourself if you don’t believe me.

Had I been more diligent at searching the web or even just testing out this archival strategy, this wouldn’t have happened. Plus, I would have noticed one fellow complaining that all contacts on the CC list, for every email, received a copy of his archived messages. Ouch. I’m glad I didn’t try redirecting all of my sent box (there is another strategy, which I will outline sometime, is far easier – but it can’t do real-time, auto-bcc).

To all the people whom I inadvertently spammed, I’m awfully sorry. This won’t happen again.

Windows IE 6 ignores text/plain mimetype

A fairly border-case scenario that probably rarely comes up, but appears to be another gotcha. So apparently IE 6 for Windows, on occasion, decides it knows better than the web server what format a file is. Instead of using the mimetype supplied by the web server, as all good browsers tend to do, IE performs some heuristics on the file and overrides the mimetype with its own guess. The type text/plain is one such stupid circumstance.

Annoyingly, IE will insist on downloading plaintext files in some cases, instead of rendering it in browser. This usually occurs if a script is attempting to generate a “text/plain” document on the fly, but can also happen under other circumstances if the IE hard-coded heuristics comes up with a different result than the server-proclaimed mimetype.

A client-side workaround for text/plain is possible. You’d need to edit the Windows Registry (oh joy). In HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings, add the DWORD key IsTextPlainHonored and set value to 0x1. This will make IE behave correctly for text/plain mimetypes. This solution comes per the MS Knowledgebase article, “Text/Plain” Content-Type Header Field Is Ignored. There are also some further explanations on how mimetypes are resolved in the MSDN article, on mimetype detection in IE.

Unfortunately, this is not a solution if this behavior comes up in a web-based tool for external use – as every client machine registry will have to be thus modified. This change may also carry security implications (actually, I’m completely guessing here, because I don’t quite see why the IE team decided to “not honor” mimetypes for text/plain…).

The context:

A PHP script in a project I maintain pulls a text file from a remote location, and then prints it to the browser as Content-type: text/plain. A hack to be sure, but simple enough to get the job done. This works out fine in Firefox, etc, but not in Windows IE. IE insists that this is a PHP script file that must be downloaded. Of course, once downloaded, you can fire up Notepad and see that it’s bloody plaintext. Firefox et al will render it in browser as expected.

In this case, the script was only used for internal testing, so I switched all the test machines to honor plaintext mimetypes. A longer term workaround would probably involve porting the output to XML instead.

/Library/Java/Extensions, MATLAB errors, and you

If you installed MATLAB 2006b on OS X and encountered this error when Matlab starts up:

java.lang.IllegalArgumentException: http://java.sun.com/xml/jaxp/properties/schemaSource
at org.apache.xerces.jaxp.DocumentBuilderFactoryImpl.setAttribute(DocumentBuilderFactoryImpl.java:118)
at com.mathworks.xml.XMLValidator.validateFile(XMLValidator.java:54)
at com.mathworks.mlwidgets.util.productinfo.Product.getItems(Product.java:310)
at com.mathworks.mlwidgets.util.productinfo.ProductInfoUtils.pathChanged(ProductInfoUtils.java:160)
at com.mathworks.mlwidgets.util.productinfo.ProductInfoUtils.<init>(ProductInfoUtils.java:67)
at com.mathworks.mlwidgets.util.productinfo.ProductInfoUtils.getAllProductsInfo(ProductInfoUtils.java:910)
at com.mathworks.mlwidgets.util.productinfo.ProductInfoUtils.<clinit>(ProductInfoUtils.java:53)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:164)
at com.mathworks.mde.desk.StartupClassLoader.callClassForName(StartupClassLoader.java:304)
at com.mathworks.mde.desk.StartupClassLoader.access$000(StartupClassLoader.java:27)
at com.mathworks.mde.desk.StartupClassLoader$LoadInfo.<init>(StartupClassLoader.java:80)
at com.mathworks.mde.desk.StartupClassLoader.addLoadInfo(StartupClassLoader.java:219)
at com.mathworks.mde.desk.StartupClassLoader.createLoadInfos(StartupClassLoader.java:195)
at com.mathworks.mde.desk.StartupClassLoader.access$500(StartupClassLoader.java:27)
at com.mathworks.mde.desk.StartupClassLoader$2.run(StartupClassLoader.java:147)
at java.util.TimerThread.mainLoop(Timer.java:512)
at java.util.TimerThread.run(Timer.java:462)
Exception in thread "Timer-2" java.lang.ExceptionInInitializerError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:164)
at com.mathworks.mde.desk.StartupClassLoader.callClassForName(StartupClassLoader.java:304)
at com.mathworks.mde.desk.StartupClassLoader.access$000(StartupClassLoader.java:27)
at com.mathworks.mde.desk.StartupClassLoader$LoadInfo.<init>(StartupClassLoader.java:80)
at com.mathworks.mde.desk.StartupClassLoader.addLoadInfo(StartupClassLoader.java:219)
at com.mathworks.mde.desk.StartupClassLoader.createLoadInfos(StartupClassLoader.java:195)
at com.mathworks.mde.desk.StartupClassLoader.access$500(StartupClassLoader.java:27)
at com.mathworks.mde.desk.StartupClassLoader$2.run(StartupClassLoader.java:147)
at java.util.TimerThread.mainLoop(Timer.java:512)
at java.util.TimerThread.run(Timer.java:462)
Caused by: java.lang.NullPointerException
at com.mathworks.mlwidgets.util.productinfo.Product.getItems(Product.java:317)
at com.mathworks.mlwidgets.util.productinfo.ProductInfoUtils.pathChanged(ProductInfoUtils.java:160)
at com.mathworks.mlwidgets.util.productinfo.ProductInfoUtils.<init>(ProductInfoUtils.java:67)
at com.mathworks.mlwidgets.util.productinfo.ProductInfoUtils.getAllProductsInfo(ProductInfoUtils.java:910)
at com.mathworks.mlwidgets.util.productinfo.ProductInfoUtils.<clinit>(ProductInfoUtils.java:53)
... 11 more

or something similar, you may have hit one of the mysterious gotchas of Mac OS X 10.4. In /Library/Java/Extensions (or another one of these system Java directories), you have a conflicting copy of xerces.jar, probably from another software package that rudely installed these extensions without informing you of it. Due to the way Java classpaths are being resolved, apparently the copy in Extensions overrides the copy in Matlab’s directory.

The symptoms of this: among other things, Matlab will throw these exceptions at startup; you can’t open certain panels or windows via the menu bar; you also cannot select certain panels in the Preferences window. Whenever you perform one of these operations, you’ll receive a NoClassDefFoundError on one of the Matlab widget classes, even though it already exists in the Matlab directory.

This is a rather classic gotcha, but a lot of people wouldn’t even realize /Library/Java/Extensions actually exists. If you went off chasing the red herring of the NoClassDefFound exception, or went tracing StartupClassLoader.java, you’d never realize the core cause of the issue.

/Library is sometimes an incomprehensible morass of things that cause mysterious failures in other applications (InputManagers, anyone?) and end up exceedingly difficult to trace.