Want to read Slashdot from your mobile device? Point it at m.slashdot.org and keep reading!

 



Forgot your password?
typodupeerror
×
Programming Technology

ANSI C89 and POSIX portability? 85

LordNite asks: "Here is the situation. I am maintaining a piece of source code which is written in K&R C. One of the original goals of this code was to be as portable as possible to as many platforms as possible. The code runs on UNIX and its clones as well as OS/2. The code avoids POSIX functions such as mmap(2) since at the time it was initially written (early 1990s) POSIX was not very wide spread. The code is well written, but in need of some serious fixing. As I go around fixing parts of the code I would also like to modernize it a bit. Since it is now 2004, can I rely on ANSI C89 and POSIX routines without sacrificing the portability of this code? (Yes, I do realize that the purpose of POSIX is code portability...) I am not really interested in the OS/2 port at this time. I am just interested in keeping portability with UNIX clones. To put my question another way: Are there any UNIX-like OSes in common use, which are currently developed and supported by some entity either OSS or proprietary, that do not support POSIX and ANSI C89?"
This discussion has been archived. No new comments can be posted.

ANSI C89 and POSIX portability?

Comments Filter:
  • Use autoconf. (Score:5, Insightful)

    by kyz ( 225372 ) on Saturday July 31, 2004 @12:39AM (#9850427) Homepage
    Firstly, if you read the entire autoconf manual, you know the intricacies of 90% of these niggling little compatibility differences on every UNIX variant out there.

    Secondly (with automake) it can make a build environment that automatically converts ANSI C to K&R C, if the target install environment only supports K&R C. So don't sweat it. Use mmap() if HAVE_MMAP is defined. Personally, I would abstract file I/O and do all work as abstract file operations. You can then choose after-the-fact whether to fopen()/fread()/fclose() or mmap()/memcpy().
    • Yes, and while you're at it, shoot yourself in the face. It's a lot more fun than trying to figure out autoconf. Trust me, I've done it.

      autoconf works. That's about the only good thing anyone could ever say about it.

      P.S. is there any fucking reason they feel the need to make new versions incompatible with older config files and vice versa? Have they ever heard of backward compatability?
      • Re:Use autoconf. (Score:3, Insightful)

        by kyz ( 225372 )
        autoconf is great. It's also fairly obvious if you read the manual. If M4 confuses you, learn it. Not everything has to be C, Perl or Bash syntax.

        autoconf works, autoconf works and autoconf works. Why do you use a configuration-detection script? Because you want your software to work! None of autoconf's "replacements" actually work in all scenarios. What's the point?

        Sure, this one has simpler syntax, or that one makes smaller shell scripts, but they don't work on older or obscure architectures! If I didn'
        • I agree. autoconf, and automake are very intimidating in the beginning, but after a short learning curve they seem quite simple, and elegant. Luckily there are some great resources to get going with it, thousands of examples, and autoscan(1) is your friend.
        • Re:Use autoconf. (Score:3, Interesting)

          by statusbar ( 314703 )
          Autoconf does not work. It it supposed to dynamically test the platform and figure out the appropriate way to build your app on the system. It tries to do this, but, it all comes down to the fact that it only works on the style of systems that autoconf was written for.

          What do I mean? A big one I hate autoconf for is how cross compiling is broken on almost every one as many compiler tests require the ability to run the code locally. A neat trick I found is that I can cross compile to mingwin32 from linux
      • Re:Use autoconf. (Score:3, Interesting)

        by aminorex ( 141494 )
        "Autoconf works"

        For some value of "works". Autoconf and automake are sorry hacks that should never have been undertaken.

        Instead, there should be one master "config.h" file that infers from the platform headers exactly what HAVE_xxx macros should be defined, and one master "config.c" that abstracts over differences where it is trivial to do so. Everybody shares that, and nobody needs this jiggery-pokery with autoconf, automake, dlltool running recursive m4s. For the love of God, Montressor -- m4!\

        • Re:Use autoconf. (Score:3, Interesting)

          by Asmodai ( 13932 )
          I have to agree.

          I've done autoconf maintenance for some open source projects, I contributed to the auto* projects and my final conclusion is that they are not helping.

          Instead I am just building my own detection code in a similar line as postfix' makedefs does. A lot clearer and keeps your sanity.

          • Instead I am just building my own detection code

            But then, I love that autoconf users have already built up a library of m4 macros for the typical kludges and different behaviors so that I don't have to do it again myself.

            Yes, autoconf sucks, but I haven't seen a better system that doesn't sacrifice portability.

            Now an autoconf that might check /etc/config.cache.xml or ~/.config.cache.xml might be an interesting improvement...

    • by V. Mole ( 9567 )

      ...unless you really want/need to support ancient and obscure platforms. But since the question specifically *said* modern and maintained platforms, then autoconf will just uglify and complicate your code.

      And in answer to the original question: yes, if you're talking modern unix or unix-like systems (i.e. AIX 4.3 or 5, Solaris 7 or later, Linux/glibc or BSD from the last several years, HPUX 11), then yes, you can assume POSIX and C89 (although for AIX, Solaris, and HPUX you'll need to buy a compiler or ins

  • Some thoughts... (Score:4, Insightful)

    by rjh ( 40933 ) <rjh@sixdemonbag.org> on Saturday July 31, 2004 @01:21AM (#9850646)
    • If it's working, be real careful in how you decide to 'fix' it. The old "if it ain't broke, don't fix it" adage is really true when it comes to old software.
    • Check the original assumptions. Which platforms did it have to run on originally? How many of those vendors are still around? What platforms does it have to run on now? You may discover that the only platforms you need to support all have good POSIX facilities.
    • If you've really got a wild hair to improve things, consider creating a port to $foo (Perl, Python, Java, .NET, etc.). One way to get around the lots of different incompatabilities problem is to use a language which already abstracts these things away, after all.
    • If you absolutely must have platform-specific behavior in C, then GNU Autoconf is probably your best bet. Be warned that GNU Autoconf is arguably a cure that's worse than the disease. I've yet to meet one single programmer who's thought Autoconf was a good idea--only that Autoconf was a marginally less bad idea than all the other alternatives.
    Good luck!
    • I think that Autoconf is about a bazillion times more complex than it probably needs to be. Perhaps one day I'll get to looking at it, and seeing what it really does, because it appears to do a whole bunch of mostly trivial junk, but everyone says it's insanely complex.
      • What irritates me is the plethora of tools involved. The whole automake/autoconf thing is made huge and complex because of its requirement to be a lowest common denominator.
        IMHO, a robust, easy to learn, well documented, got-everything-you-need system needs to gulp all of that automake/autoconf (and why not make, itself, while we're after reductionism?) noise down. I nominate Python.
        • by runderwo ( 609077 )
          You couldn't even compile the Python interpreter on half of the platforms that Autoconf targets.

          • You couldn't even compile the Python interpreter on half of the platforms that Autoconf targets.

            And yet Python somehow manages to run natively on that one platform that is installed on most of the world's computers, whereas AFAIKT, Autoconf just blows it off.

        • really, you'd figure that it would be able to make semi intelligent guesstimations of what resources are available just by inspecting the files within the system. god only knows what it's really doing.
  • Purpose? (Score:3, Insightful)

    by fm6 ( 162816 ) on Saturday July 31, 2004 @01:51AM (#9850760) Homepage Journal
    The code is well written, but in need of some serious fixing. As I go around fixing parts of the code I would also like to modernize it a bit.
    It seems like everybody who posts an Ask Slashdot story these days wants to know how, but hasn't thought about why. In this case, you want to "modernize" the code -- but is there any really good reason for doing so? Is the code hard to maintain in its current form? Are there efficiency issues? You don't say yes or no, but from the way you describe the project, it sounds like the answer is "no". Why risk introducing a bunch of bugs just to make the software "more modern"? Job security, perhaps?
    • Re:Purpose? (Score:5, Informative)

      by rjh ( 40933 ) <rjh@sixdemonbag.org> on Saturday July 31, 2004 @02:07AM (#9850819)
      I've known the submitter for about ten years now, a little less, so maybe I can answer your question for you.

      The reason is simple. He's a hacker. He sees something that works but is inelegant; and he'd like to be able to make it a little more elegant. It's that simple.

      So the answer to "why risk introducing a bunch of bugs just to make the software 'more modern'" is not a facetious "job security".

      The answer is elegance.

      If you can't appreciate that answer, that's a strong sign you're not qualified to have an opinion.

      Please note, by the by, that I almost agreed with you. I recommended that he be very careful in what he fixes and how. That's worlds apart from saying "leave it alone, you don't know what you're doing". Any answer of "leave it alone" is fundamentally anti-hacker.
      • Re:Purpose? (Score:1, Troll)

        by fm6 ( 162816 )

        The answer is elegance.

        If you can't appreciate that answer, that's a strong sign you're not qualified to have an opinion.

        That's pretty patronizing. Or maybe the word is fascist. If I can't understand you, than I must be out of my depth? That's a formula for ignoring anybody that disagrees with you. Since we're discussing elegance of expression, maybe you should just say "Up yours!" and let it go at that!

        Sure elegant code is better than messy code. But rewriting software that has performed reliably for

        • Mmm troll...

          A sense of software esthetic is justifiable as a means to that ends -- not an end in itself.

          It depends on whether you think programming is conceivable as an art or not.

          There is also a big difference between using the English language to write a memo for your boss and using it to write a novel.

          • I always resent being called a troll -- except maybe in this case. A troll is somebody who makes an argument he doesn't believe in just to piss off the other person. Such a person has no interest in having an actual discussion/argument. But if you think I'm such a person, why are you trying to refute me?

            Yep, novels and memos are different kinds of prose. But both benefit from elegance -- and elegance is something with esthetic value.

          • Sure elegant code is better than messy code. But rewriting software that has performed reliably for years needs a bigger justification than truisims about elegant code.

          followed by.

          • A programmer's job is to create and maintain reliable software that meets the needs of its users.

          If the code's a pain to read, and hard to understand, making it look good might very well be the first step towards making sure it is maintainable in a far more efficent fashion.


          • A sense of software esthetic is justifiable a
        • There's a difference between a programmer and a hacker.
          • That pretty snobbish. And also ignorant. Hacking is just an unstructured style of programming. It is not a synonym for "sloppy work."
        • Re:Purpose? (Score:3, Funny)

          by Omega1045 ( 584264 )
          That's pretty patronizing. Or maybe the word is fascist.

          Me thinks we have a spy, fellow Slashdotters! This person (parent comment author) sounds more like a drama student than a programmer!

      • by Anonymous Coward
        at the tire shop, i saw that your engine was running on gasoline. how barbaric, i thought, so i upgraded it to hydrogen.
      • The answer is elegance. If you can't appreciate that answer, that's a strong sign you're not qualified to have an opinion.

        I'm a professional software engineer. I'm not at all averse to refactoring or rewriting code.

        However, because I'm paid for my time, I only do things that are worthwhile to my employer. If the code is unlikely to get new requirements or features, then it's best to leave it alone just because it seems to still work. What I produce for work is a balance of business sense and elegance, n

    • Comment removed based on user account deletion
      • Rewriting old C software into POSIX C seems even more pointless. Coz if he rewrites it, wouldn't they still have the same problem 10 years later?

        If they really want to rewrite the software why do it in C of all languages? Why not python or java or even perl? At least you won't have to worry about stupid buffer overflow errors and crap like that.

        Python, Java and Perl run on quite a number of platforms the last I checked. java would run fairly fast (given enough memory...).

        Since the existing stuff works an
  • POSIX and C89 (Score:5, Informative)

    by molo ( 94384 ) on Saturday July 31, 2004 @02:46AM (#9850944) Journal
    Ok, POSIX is all about the system calls and C library functions. C89 is about compiler support. They are seperate and don't go hand-in-hand.

    About POSIX and Unix compatibility. There are a handful of Unixes that remain important and widely deployed. They are:

    Solaris
    HP-UX
    AIX
    Linux
    *BSD
    MacOSX

    They pretty much all have modern APIs in recent versions. The older unixes have recently added a bunch of Linux-like modern APIs to make portability easier. This was the reason behind HPUX 11i (the 'i' denotes "internet ready", but what they really mean is glibc/*BSD apis). This is also the reason behind the AIX 5L name (AKA 5.1, 5.2) (L = linux affinity, same deal, new GNU/*BSD apis). You know that MacOSX uses a BSD-based userland, so you're fine there. Then there's Solaris, of which recent versions (>=2.6) are in good shape. Recent versions of the proprietary unixes even have /dev/[u]random and /proc filesystems. There's a lot of common interfaces, as long as you target relatively recent releases.

    Ok, once you figure out what platforms you are targeting, you need to figure out what compilers you will support. All of the proprietary Unixes have their own C compiler (sometimes only available for a fee). Many are not fully ANSI compliant. They are definitely not all C99 compliant. That is the bad news.

    The good news is that gcc is available for all of the major platforms. This is what gcc excels at, it is highly portable. You can use this to your advantage to get things working on these platforms. If your users then want to get them working with other compilers, that is worth a shot too (non-gcc compilers often produce better optimizations, etc.).. but it will be hit or miss.

    Testing. I highly recommend the HP Testdrive program. They make available a bunch of machines with various HP hardware running various operating systems from Linux on Alpha to HPUX on IA64, including Tru64 (aka OSF/1). http://www.testdrive.compaq.com/ [compaq.com]

    Sourceforge also has a build farm which includes Solaris on sparc and x86 and MacOS X. http://sourceforge.net/docman/display_doc.php?doci d=762&group_id=1#platforms [sourceforge.net] You have to be a developer of a sourceforge project to get access, but its a good deal.

    Good luck. Hope this helps.
    -molo

    HPUX Note: Many people think that 11i is for the Itanium platform. That is not the case. 11i is version 11.11 and higher. 11.11 is for HPPA. 11.20 and higher are for IA64. Both are called 11i.
    • Re:POSIX and C89 (Score:1, Informative)

      by Anonymous Coward
      It is also worth mentioning that all currently maintained unix-like operating systems support the Single Unix Specification. The specification can be downloaded for free from www.opengroup.org. The latest version of the specification is SUSv3, but as a coder you're better off using SUSv2 (released 1998) since SUSv2 wasn't widely implemented until about 2001 and it is quite likely that some of your customers will want to run your software on older OS versions.
    • <SARCASM>

      Wait...
      I think you missed a major version of unix there. In fact the only *real* unix, SCOWare. They even own the copyright on "UNIX".

      </SARCASM>
    • Re:POSIX and C89 (Score:1, Interesting)

      by Anonymous Coward
      It's also worth mentioning that - as long as you stick to POSIX standards - you can then even compile your program for Windows by using some kind of compatibility layer (Cygwin or Microsoft SFU).

      That is to say, POSIX is an important enough standard that even the world's least compatible operating system has a choice of POSIX compatibility modes...
    • Where can I find these?

      AIX
      IRIX
      FreeBSD 5.x
      Solaris 10
      any 4.2 or 4.3 BSD
      any SVR4-MP
      any "Trusted" system
      OS/390

      I need these for an Open Source project I maintain.
      • Sorry, I don't know of any. If you find them, let me know, I'd be interested too. Thanks.

        -molo
      • Get an old black NeXTstation or NeXT cube from eBay if you want a 4.2 BSD based machine. IIRC, the original OS, NeXTstep, was based on 4.2 BSD, while the later OS, OpenStep, was based on 4.3 BSD.

        If yuo need a Silicon Graphics box to develop software on, check out http://forums.nekochan.net [nekochan.net]. Someone there can probably give you an account on a SGI IRIX 6.5.x system with gcc and/or MIPSpro. You could also buy an O2 from eBay for about $50. You'll still need to find a more recent version of IRIX, but SGI will
    • QNX? (Score:3, Informative)

      by calidoscope ( 312571 )
      QNX is still being used - the latest version now hs gcc support - versus that Watcom compiler for earlier versions (4.25 and earlier).
    • Re:POSIX and C89 (Score:3, Interesting)

      by _|()|\| ( 159991 )
      Good advice to actually seek out test platforms. I've found subtle bugs in shell scripts and POSIX-ish C code on certain platforms. Some examples:
      • The ls command returns success on OS X, even if no files were found.
      • The test command has some options, like -e, which are not portable.
      • HP-UX requires an ioctl() to detect that a slave PTY has closed.
      • AIX has fewer than 64 PTYs configured, by default, which exposed a bug in one of my programs.
      • There seems to be disagreement on the types of some socket functio
      • test -e is portable, just not with Solaris' braindead /bin/sh :-/

        have yet to figure out how to get the client's address from accept() without causing a compile warning on at least one platform.

        My guess is that it is on HP-UX with aCC? In that case you have to cast over void*:

        sockaddr_in sa;
        socklen_t sal = sizeof(sa);
        int cfd = accept(fd, (sockaddr*)(void*)&sa,&sal);
        • Actually, the -e switch doesn't work under ash and some versions of ksh (including that shipped with HP-UX), where it's a built in. I don't remember whether I found any copies of /bin/test that don't support -e.

          As I recall, the problem with accept() actually had to do with socklen_t, which isn't defined the same on all platforms. It's not a big deal, but I like to keep my code warning free.

      • Why not use Cygwin? It "fixes" the Win32 behavior you speak of and gives you back the unix/posix environment on windows. Of course it also means your code is touched by the GPL fairy, so if it's not free software then it could be a problem.
    • POSIX is all about the system calls and C library functions. C89 is about compiler support. They are seperate and don't go hand-in-hand.

      C89 refers to the version of C standardized in 1989, which devotes hundreds of pages to the Standard Library (C99 devotes over 280 of about 600 total pages to the library). While "freestanding" implementations are not required to contain any or all of the Standard Library, it's really just provided as a way out for very limited processors. Practically all C implementation

  • by DarkDust ( 239124 ) <marc@darkdust.net> on Saturday July 31, 2004 @07:51AM (#9851685) Homepage

    AFAIK really all UNIX and UNIX-like systems support at least POSIX-1988, and most even support SUS1 and higher. Heck, even Windows NT/2000 are (partly) POSIX compatible, and to my knowledge Windows XP can be made POSIX compatible with some extra package from MicroSoft, but I don't know which).

    I really recommend Advanced UNIX Programming [basepath.com], it's an excellent book which not only discusses and explains POSIX and SUS APIs but also where you can expect those APIs to be avaible and how to test for them to be sure. It was also reviewed here at Slashdot [slashdot.org].

    • Yes, windows includes partial compatibility with one catch: most of the stuff they -do- support is prefixed with an underscore. You can work around that by definingmacros as wrappers in your ifdef'ed windows specific header (kinda like glib does). Most of this is in the base windows system.

      Also, (which you also mentioned, but didn't know the name) microsoft provides Microsoft Services for UNIX (more recently known as Interix), which provides..something for UNIX compatibility (userland? maybe non-undersc
    • 'Doze services for Unix. But why? Just get MinGW. Heck I even compiled emacs from source, which was something of a tooth extraction. [emacswiki.org]
      Granted, Cygwin would've been easier, but it ain't called easemacs...
  • What part of POSIX? (Score:3, Informative)

    by hubertf ( 124995 ) on Saturday July 31, 2004 @08:06AM (#9851710) Homepage Journal
    POSIX is not a single specification, but consists of quite a number of parts. While some of the basic interfaces can be considered of widespread use, I wouldn't recommend using others like realtime handling or maybe even threads.

    - Hubert
  • Are you also including embedded systems like:
    vxWorks, QNX, pSOS, OSE, etc..
  • Comment removed (Score:3, Interesting)

    by account_deleted ( 4530225 ) on Saturday July 31, 2004 @09:19AM (#9851931)
    Comment removed based on user account deletion
    • by Anonymous Coward
      You can always try to install gcc in some temp dir. That's what I do on such castrated platforms. It goes a long way to restore sanity.
      • You can always try to install gcc in some temp dir. That's what I do on such castrated platforms. It goes a long way to restore sanity.

        Been there, done that. Also installed other GNU stuff like bash, coreutils, findutils, grep, make... "./configure --prefix=$HOME" definitely helps...

      • You can always try to install gcc in some temp dir.

        This may not be an option for the latest version of GCC. I seem to recall a mention in the release notes that you can no longer bootstrap with a K&R compiler.

    • Re:Not necessarily (Score:3, Interesting)

      by randombit ( 87792 )
      and a K&R C compiler - and not a "modernized" just-pre-ANSI one either, I mean something that choked on function prototypes in a way my Sinclair QL's Metacomco C compiler didn't back in 1995...

      In case anyone's interested, this is a HP-UX 11 (the machine is a 9000/800) system


      That C compiler is (AFAIK) only shipped for building new versions of the kernel. You can also buy a reasonably decent C99/C++98 compiler from HP for about a zillion dollars. The reason they cripple the shipped compiler is to force
      • That C compiler is (AFAIK) only shipped for building new versions of the kernel.

        One of the more prominent entries on the HP-UX FAQ (more relevant to the days when HP-UX was a contender for desktop UNIX) - was why the built-in compiler was brain-dead. The answer is what you said - it is there for building the kernel (as has been that way since HP-UX 8.x, and probably before). It was a pretty nice compiler as long as the source was strict K&R (it had code to detect ANSI C and would issue an error) - the

      • Re: (Score:3, Informative)

        Comment removed based on user account deletion
  • Plan 9 (Score:3, Interesting)

    by Leimy ( 6717 ) on Saturday July 31, 2004 @11:56AM (#9852601)
    Plan 9 [bell-labs.com]is/was the successor to Unix from the people who brought you Unix to begin with.

    It's compiler suites, which approach multiple architectures a little differently, by default don't have hardly and ANSI C or POSIX support. If you need that stuff you have to use the APE frameworks. See this [bell-labs.com] for more information.

    The fact that it's not quite ANSI C and not quite POSIX by default shouldn't discourage you from playing with the OS though or even trying to use it. Apparently the "thin client" trend is coming back and Plan 9 systems support that metaphor quite nicely where everyone has a graphical display and a private hierarchical namespace [each process can have a different namespace in fact]. The OS is meant to be distributed across many nodes, with CPU nodes and File Serving nodes being part of a grid, but you can run it standalone fairly easily as well.

    I've found that even though it doesn't have a great X implementation I can still VNC to other machines that do when I need X and that I can use ssh with their terminal emulator when I need to work with systems Plan 9 can't "mount" or "bind" into my namespace.

    As you can probably tell. I was impressed.

    If you don't want to mess with installing over you existing OS you can try Inferno [vitanuova.com] which installs on Windows, Linux, FreeBSD and even MacOS X [but if you run Panther you will probably need this patched emulator and installer [corpus-callosum.com] to make it work]. Once done you can build a multi-CPU-architecture grid all your own and learn the "Limbo" programming language and start harnessing those extra CPU cyucles. Inferno also supports thos hierarchical namespaces of Plan 9.

  • by lkaos ( 187507 ) <anthony@codemonk ... s minus math_god> on Saturday July 31, 2004 @02:53PM (#9853540) Homepage Journal
    We go through great lengths in Samba to be as portable as possible. Our build farm [samba.org] runs the most popular unices on all sorts of architectures (you'd be amazed how different Linux on x86 can be than Linux on say a s390). We support a ton of platforms including some as obscure as the Amiga.

    What I'd do if I were you is to just grep the Samba source code before you use a function. You'll likely find a list of platforms that it doesn't work on, or that simply doesn't have that particular function. You may also find workarounds for bugs in particular implementations.
  • by Asmodai ( 13932 ) on Sunday August 01, 2004 @01:39PM (#9858370) Homepage
    Just do it.

    For both TenDRA and DragonFly we're using ANSI C94 (C90 plus amendments) along with POSIX/SUS and the code in general tends to get cleaner and cleaner (and easier to understand in my opinion).

    It is amazing, since I am doing a lot of these conversions on a plethora of different old time tools, how much programming errors/mistakes the old code managed to get away with...
  • by mritunjai ( 518932 ) on Monday August 02, 2004 @06:23AM (#9861866) Homepage
    Hi there,

    You're one of the few still having a job! You've got a project at hand, and you NEED to do it well.

    DO NOT modernize if you don't have to! What you have in your hands is, as you tell, a nice *working* code. IF after your "modernization" crusade, it breaks on some platforms, even due to platform bugs, it will be YOUR neck under the guillotine. Understand THAT!

    And, no, I'm not talking this from my behind... been there, done that, got burned!!! Unnecessary modernization/elegance/optimizations/refactoring is root of all evil and prime cause of job loss! Do your job, and fix whatever is *NEEDED*... and make sure you ain't breaking anything. If you can do THAT much flawlessly, you should be thankful. In software engineering there are just too many variables and you carry the onus of working around them. All compiler/platform/libc bugs will form part of YOUR work... so be careful!
    • Funny.

      My experiences have been the total opposite of yours. The ANSIfied code in general is clearer, solved mysterious bugs present in the K&R code, and was on the whole easier to maintain than the old code.

  • One might check out FreeBSD 4.x, it defined some workaround systems for prototypes to be both Ansi and K&R usable.

"Protozoa are small, and bacteria are small, but viruses are smaller than the both put together."

Working...