<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-19552152</id><updated>2011-04-22T02:05:49.443+02:00</updated><title type='text'>Elegance of Reason</title><subtitle type='html'>My thoughts about the notion of elegance applied to a number of fields, including computer programming and information technology. With occasional digressions.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://eleganceofreason.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://eleganceofreason.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Davide Bolcioni</name><uri>http://www.blogger.com/profile/06027807192913516675</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>9</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-19552152.post-115075490446103224</id><published>2006-06-19T23:21:00.000+02:00</published><updated>2006-06-20T00:42:20.630+02:00</updated><title type='text'>The Good, the Bad and the Ugly, part 5</title><content type='html'>&lt;div style="text-align: justify;"&gt;Last time, reporting about &lt;a href="http://www.opengroup.org/onlinepubs/009695399/functions/errno.html"&gt;&lt;code&gt;errno&lt;/code&gt;&lt;/a&gt; brought the example code to new depths of ugliness. It is about time to introduce some relief.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;The most obvious target is the repeated use (abuse ?) of &lt;code&gt;fprintf&lt;/code&gt;, which can be addressed by using a simple wrapper function. Even the simplest function, however, introduces a new word in the vocabulary used to describe the solution to the problem implemented by the program - to describe it to a fellow programmer (which might be your future self), that is: the compiler is just as happy with the code as it stands. In other words, each function introduces an &lt;em&gt;abstraction&lt;/em&gt; and as such it is essential to pick its name judiciously, so that it is not &lt;em&gt;always&lt;/em&gt; necessary to reach for the actual source of the function in order to understand what it does.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;  /* Report an error on stderr */&lt;br /&gt;  void err_printf(const char *format, ...) {&lt;br /&gt;    va_list args;&lt;br /&gt;&lt;br /&gt;    va_start(args, format);&lt;br /&gt;    (void) vfprintf(stderr, format, args);&lt;br /&gt;    va_end(args);&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Now, the somewhat verbose &lt;code&gt;err_printf()&lt;/code&gt; might not appeal old &lt;acronym&gt;UNIX&lt;/acronym&gt; hands, but this is my best effort at conveying what the function is supposed to do. I once read that the inability to come up with a name describing what a function does is a telltale sign that said function is attempting to do too many things at once; hopefully, the above function does not.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;In doing its job, &lt;code&gt;err_printf()&lt;/code&gt; embeds a decision: we are not interested in the return value of &lt;code&gt;vfprintf&lt;/code&gt;, which is documented to be the same value that would be returned by the equivalent &lt;code&gt;fprintf&lt;/code&gt;. In other words, the caller will get no information about the success or failure of the function; as briefly suggested last time, should he choose to invoke it, it will either be because he's genuinely uninterested in the outcome, or because he's confident that whatever the outcome subsequent execution of the program will satisfy his requirements.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Please note the above does not tell the reader of a non trivial fragment of code using &lt;code&gt;err_printf()&lt;/code&gt; which of the above was the actual intent, i.e. if the programmer was merely uninterested in the outcome or actually confident in its non-relevance. The latter gets problematic if code maintenance adds code afterwards which depends on the successful execution of &lt;code&gt;err_printf&lt;/code&gt;, such as a followup message with more details about the problem.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;However, even by itself, &lt;code&gt;err_printf&lt;/code&gt; brings some measurable improvement to the example code:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;/*&lt;br /&gt; popen-test: experiment with popen(), Part 5.&lt;br /&gt;&lt;br /&gt; Copyright © 2006  Davide Bolcioni &amp;lt;dbolcion@libero.it&amp;gt;&lt;br /&gt;                                                                              &lt;br /&gt; Distributed under the GPL,&lt;br /&gt; see http://www.gnu.org/copyleft/gpl.html.&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;#include &amp;lt;errno.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdarg.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;&lt;br /&gt;void err_printf(const char* format, ...)&lt;br /&gt;{&lt;br /&gt;  va_list args;&lt;br /&gt;&lt;br /&gt;  va_start(args, format);&lt;br /&gt;  (void) vfprintf(stderr, format, args);&lt;br /&gt;  va_end(args);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(int argc, char* argv[])&lt;br /&gt;{&lt;br /&gt;  int rc = EXIT_FAILURE; /* Optimist */&lt;br /&gt;&lt;br /&gt;  if (argc &amp;gt; 1) {&lt;br /&gt;    FILE* sink;&lt;br /&gt;&lt;br /&gt;    if (fflush(NULL) != EOF) { /* all open files */&lt;br /&gt;      sink = popen(argv[1], "w");&lt;br /&gt;&lt;br /&gt;      if (sink) {&lt;br /&gt;        int status;&lt;br /&gt;        int i;&lt;br /&gt;&lt;br /&gt;        /* NB: deliberately allow to test for no output sent */&lt;br /&gt;&lt;br /&gt;        for (i = 2; i &amp;lt; argc; i++) {&lt;br /&gt;          if (fputs(argv[i], sink) == EOF) {&lt;br /&gt;            err_printf("%s: fputs(\"%s\") failed: ",&lt;br /&gt;                       argv[0], argv[i]);&lt;br /&gt;            perror("");&lt;br /&gt;            break;&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        status = pclose(sink);&lt;br /&gt;    &lt;br /&gt;        /* The return value is funny */&lt;br /&gt;&lt;br /&gt;        if (status == -1) {&lt;br /&gt;          err_printf("%s: pclose() failed: ",&lt;br /&gt;                     argv[0]);&lt;br /&gt;          perror("");&lt;br /&gt;        }&lt;br /&gt;        else if (WIFEXITED(status)) {&lt;br /&gt;          rc = WEXITSTATUS(status);&lt;br /&gt;          err_printf("%s: child did an exit(%d).\n",&lt;br /&gt;                     argv[0], rc);&lt;br /&gt;        }&lt;br /&gt;        else if (WIFSIGNALED(status)) {&lt;br /&gt;          err_printf("%s: child terminated by signal %d.\n",&lt;br /&gt;                     argv[0], WTERMSIG(status));&lt;br /&gt;        }&lt;br /&gt;        else if (WIFSTOPPED(status)) {&lt;br /&gt;          err_printf("%s: child stopped with signal %d.\n",&lt;br /&gt;                     argv[0], WSTOPSIG(status));&lt;br /&gt;        }&lt;br /&gt;        else {&lt;br /&gt;          err_printf(&lt;br /&gt;            "%s: I don't think we're in Kansas anymore, Toto.\n",&lt;br /&gt;            argv[0]&lt;br /&gt;          );&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;      else {&lt;br /&gt;        err_printf("%s: popen(\"%s\") failed: ",&lt;br /&gt;                    argv[0], argv[1]);&lt;br /&gt;        perror("");&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    else {&lt;br /&gt;      err_printf("%s: fflush(NULL) failed: ",&lt;br /&gt;                 argv[0]);&lt;br /&gt;      perror("");&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  else {&lt;br /&gt;    err_printf("Usage: %s &amp;lt;command&amp;gt; [&amp;lt;arg&amp;gt;]...\n",&lt;br /&gt;               argv[0]);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return rc;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; vim:sw=2:nowrap&lt;br /&gt;*/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;The more observant among you might notice that the above code has two problems: it falls afoul of the "what happens after" syndrome discussed above&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;      ...&lt;br /&gt;&lt;br /&gt;      else {&lt;br /&gt;        err_printf("%s: popen(\"%s\") failed: ",&lt;br /&gt;                    argv[0], argv[1]);&lt;br /&gt;        perror("");&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;and might trash &lt;code&gt;errno&lt;/code&gt; within &lt;code&gt;err_printf()&lt;/code&gt;. This second problem is easily fixed&lt;sup&gt;1&lt;/sup&gt;:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;  /* Report an error on stderr */&lt;br /&gt;  void err_printf(const char *format, ...) {&lt;br /&gt;    int saved_errno = errno;&lt;br /&gt;    va_list args;&lt;br /&gt;    &lt;br /&gt;&lt;br /&gt;    va_start(args, format);&lt;br /&gt;    (void) vfprintf(stderr, format, args);&lt;br /&gt;    va_end(args);&lt;br /&gt;    errno = saved_errno;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;which compares favorably against messing around with saving and restoring &lt;code&gt;errno&lt;/code&gt; all over the program. It might be tempting to add &lt;code&gt;perror()&lt;/code&gt; to the mix also:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;  /* Report an error on stderr */&lt;br /&gt;  void err_printf(const char *format, ...) {&lt;br /&gt;    int saved_errno = errno;&lt;br /&gt;    va_list args;&lt;br /&gt;    &lt;br /&gt;&lt;br /&gt;    va_start(args, format);&lt;br /&gt;    (void) vfprintf(stderr, format, args);&lt;br /&gt;    va_end(args);&lt;br /&gt;&lt;br /&gt;    if (saved_errno) {&lt;br /&gt;      errno = saved_errno;&lt;br /&gt;      perror("");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    errno = saved_errno;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Since it's not exactly clear what &lt;code&gt;perror()&lt;/code&gt; is going to print in case of no error, the above code studiously avoids to trigger that. The next installment will attempt to discuss if the above is really an improvement.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify; font-size:smaller"&gt;Note [1]: as long as &lt;code&gt;err_printf()&lt;/code&gt; and all its clients are compiled with the same threading flags.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19552152-115075490446103224?l=eleganceofreason.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eleganceofreason.blogspot.com/feeds/115075490446103224/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19552152&amp;postID=115075490446103224' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/115075490446103224'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/115075490446103224'/><link rel='alternate' type='text/html' href='http://eleganceofreason.blogspot.com/2006/06/good-bad-and-ugly-part-5.html' title='The Good, the Bad and the Ugly, part 5'/><author><name>Davide Bolcioni</name><uri>http://www.blogger.com/profile/06027807192913516675</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19552152.post-114773027988948623</id><published>2006-05-15T23:06:00.000+02:00</published><updated>2006-06-20T00:48:32.743+02:00</updated><title type='text'>The Good, the Bad and the Ugly, part 4</title><content type='html'>&lt;div style="text-align: justify;"&gt;If you thought the code in part 3 was ugly, this installment will make you reconsider: we'll discuss the use of &lt;a href="http://www.opengroup.org/onlinepubs/009695399/functions/errno.html"&gt;&lt;code&gt;errno&lt;/code&gt;&lt;/a&gt;.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Apparently, there is little to say about &lt;code&gt;errno&lt;/code&gt;; when a function returns failure, it sets the global variable&lt;sup&gt;1&lt;/sup&gt; &lt;code&gt;errno&lt;/code&gt; to some numeric value which is supposed to give more details about what went wrong. When it returns success, you should not look at the value of &lt;code&gt;errno&lt;/code&gt; because it might have changed anyway. Suppose we write a mightily uninteresting &lt;code&gt;frobble()&lt;/code&gt; function:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;  /* The frobble() function returns 0 on success and -1 on failure */&lt;br /&gt;  int frobble() {&lt;br /&gt;    return -1;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Now, &lt;code&gt;frobble()&lt;/code&gt; is documented to fail but there is no sign of it affecting &lt;code&gt;errno&lt;/code&gt; in any way; the handling of &lt;code&gt;errno&lt;/code&gt; is a &lt;em&gt;convention&lt;/em&gt;, which dates back to the beginnings of &lt;code&gt;C&lt;/code&gt; and &lt;acronym&gt;UNIX&lt;/acronym&gt;, so functions have to be explicitly written to follow this convention and should be documented accordingly: system calls and library functions often do, but the only way to tell is to read the documentation.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;The reason we're discussing &lt;code&gt;errno&lt;/code&gt; lies in a problem with our toy program. Suppose we had the following run:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;  [db@centaur ~] ./popen-test /bin/true&lt;br /&gt;  [db@centaur ~] ./popen-test: popen("/bin/true") failed.&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;We get no clue about the &lt;em&gt;reason&lt;/em&gt; which caused &lt;code&gt;popen()&lt;/code&gt; to fail; whatever information &lt;code&gt;errno&lt;/code&gt; might have conveyed is not made available. All too often, when programs fail they do not bother to tell you &lt;em&gt;why&lt;/em&gt;, which makes the life of your system administrator friends either very simple (just blame you, the developer) or very complicated.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;To rectify this, our task is conceptually simple: whenever we invoke a function which sets &lt;code&gt;errno&lt;/code&gt; on failure, just make sure its value is included in the error message. Since the value is just an integer, which is not very user-friendly, we might want to carry this a step further and provide some kind of explanatory message using &lt;code&gt;perror()&lt;/code&gt; (we'll get more sophisticated later). Note that we're not referencing &lt;code&gt;errno&lt;/code&gt; in our code, just invoking &lt;code&gt;perror()&lt;/code&gt;.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;/*&lt;br /&gt; popen-test: experiment with popen(), Part 4.&lt;br /&gt;&lt;br /&gt; Copyright © 2006  Davide Bolcioni &amp;lt;dbolcion@libero.it&amp;gt;&lt;br /&gt;                                                                              &lt;br /&gt; Distributed under the GPL,&lt;br /&gt; see http://www.gnu.org/copyleft/gpl.html.&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int main(int argc, char* argv[])&lt;br /&gt;{&lt;br /&gt;  int rc = EXIT_FAILURE; /* Optimist */&lt;br /&gt;&lt;br /&gt;  if (argc &amp;gt; 1) {&lt;br /&gt;    FILE* sink;&lt;br /&gt;&lt;br /&gt;    if (fflush(NULL) != EOF) { /* all open files */&lt;br /&gt;      sink = popen(argv[1], "w");&lt;br /&gt;&lt;br /&gt;      if (sink) {&lt;br /&gt;        int status;&lt;br /&gt;        int i;&lt;br /&gt;&lt;br /&gt;        /* NB: deliberately allow to test for no output sent */&lt;br /&gt;&lt;br /&gt;        for (i = 2; i &amp;lt; argc; i++) {&lt;br /&gt;          (void)fputs(argv[i], sink);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        status = pclose(sink);&lt;br /&gt;    &lt;br /&gt;        /* The return value is funny */&lt;br /&gt;&lt;br /&gt;        if (status == -1) {&lt;br /&gt;          (void)fprintf(stderr,&lt;br /&gt;                "%s: pclose() failed: ",&lt;br /&gt;                argv[0]);&lt;br /&gt;          perror("");&lt;br /&gt;        }&lt;br /&gt;        else if (WIFEXITED(status)) {&lt;br /&gt;          rc = WEXITSTATUS(status);&lt;br /&gt;          (void)fprintf(stderr,&lt;br /&gt;                "%s: child did an exit(%d).\n",&lt;br /&gt;                argv[0], rc);&lt;br /&gt;        }&lt;br /&gt;        else if (WIFSIGNALED(status)) {&lt;br /&gt;          (void)fprintf(stderr,&lt;br /&gt;                "%s: child terminated by signal %d.\n",&lt;br /&gt;                argv[0], WTERMSIG(status));&lt;br /&gt;        }&lt;br /&gt;        else if (WIFSTOPPED(status)) {&lt;br /&gt;          (void)fprintf(stderr,&lt;br /&gt;                "%s: child stopped with signal %d.\n",&lt;br /&gt;                argv[0], WSTOPSIG(status));&lt;br /&gt;        }&lt;br /&gt;        else {&lt;br /&gt;          (void)fprintf(stderr,&lt;br /&gt;                "%s: I don't think we're in Kansas anymore, Toto.\n",&lt;br /&gt;                argv[0]);&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;      else {&lt;br /&gt;        (void)fprintf(stderr,&lt;br /&gt;              "%s: popen(\"%s\") failed: ",&lt;br /&gt;              argv[0], argv[1]);&lt;br /&gt;        perror("");&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    else {&lt;br /&gt;      (void)fprintf(stderr,&lt;br /&gt;            "%s: fflush(NULL) failed: ",&lt;br /&gt;            argv[0]);&lt;br /&gt;      perror("");&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  else {&lt;br /&gt;    (void)fprintf(stderr,&lt;br /&gt;          "Usage: %s &amp;lt;command&amp;gt; [&amp;lt;arg&amp;gt;]...\n", argv[0]);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return rc;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; vim:sw=2:nowrap&lt;br /&gt;*/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;The more observant among you might notice that we're blindly ignoring failures, and the attendant value of &lt;code&gt;errno&lt;/code&gt;, resulting from the invocations of &lt;code&gt;fputs()&lt;/code&gt; in the &lt;code&gt;for&lt;/code&gt; loop. This illustrates why casting away error handling to &lt;code&gt;void&lt;/code&gt; is slightly better than silently ignoring error conditions: it is easier to spot even after some time. In the code above, we should probably leave the loop as soon as the first &lt;code&gt;fputs()&lt;/code&gt; fails and report the value of &lt;code&gt;errno&lt;/code&gt;:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;        ...&lt;br /&gt;&lt;br /&gt;        /* NB: deliberately allow to test for no output sent */&lt;br /&gt;&lt;br /&gt;        for (i = 2; i &amp;lt; argc; i++) {&lt;br /&gt;          if (fputs(argv[i], sink) == EOF) {&lt;br /&gt;            int errno_from_fputs = errno;&lt;br /&gt;            (void)fprintf(stderr, "%s: fputs(\"%s\") failed: ",&lt;br /&gt;                          argv[0],&lt;br /&gt;                          argv[i]);&lt;br /&gt;            errno = errno_from_fputs;&lt;br /&gt;            perror("");&lt;br /&gt;            break;&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        status = pclose(sink);&lt;br /&gt;&lt;br /&gt;        ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;As you can see, in ugliness contests global variables such as &lt;code&gt;errno&lt;/code&gt; have a head start: because &lt;code&gt;fprintf()&lt;/code&gt; might affect &lt;code&gt;errno&lt;/code&gt; even when not failing, we have to save it and then restore it back for the use of &lt;code&gt;perror()&lt;/code&gt;.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Note that we had to change a few &lt;code&gt;\n&lt;/code&gt; in our &lt;code&gt;fprintf()&lt;/code&gt; format strings to a colon followed by a space, so that &lt;code&gt;perror()&lt;/code&gt; output follows the message on the same line; if supplied an non-empty argument &lt;code&gt;perror()&lt;/code&gt; would do just that on its own, but this would require us to format the message as a string, with all the attendant complications.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Next time, our toy program will attempt to climb back up from the pits of ugliness it sank to.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify; font-size:smaller"&gt;Note [1]: this is not entirely correct, because &lt;code&gt;errno&lt;/code&gt; is documented as an &lt;em&gt;lvalue&lt;/em&gt; and might be a macro which expands to some funny construct intended to carry over all the above in the world of &lt;acronym&gt;POSIX&lt;/acronym&gt; threads without too much pain. For this reason, &lt;code&gt;errno&lt;/code&gt; should be accessed only after explicitly including &amp;lt;errno.h&amp;gt; even if &lt;code&gt;perror()&lt;/code&gt; in all likelyhood already includes it.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19552152-114773027988948623?l=eleganceofreason.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eleganceofreason.blogspot.com/feeds/114773027988948623/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19552152&amp;postID=114773027988948623' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/114773027988948623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/114773027988948623'/><link rel='alternate' type='text/html' href='http://eleganceofreason.blogspot.com/2006/05/good-bad-and-ugly-part-4.html' title='The Good, the Bad and the Ugly, part 4'/><author><name>Davide Bolcioni</name><uri>http://www.blogger.com/profile/06027807192913516675</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19552152.post-114099170411372508</id><published>2006-02-26T21:14:00.000+01:00</published><updated>2006-02-27T00:19:45.996+01:00</updated><title type='text'>The Good, the Bad and the Ugly, part 3</title><content type='html'>&lt;div style="text-align: justify;"&gt;Making &lt;code&gt;fprintf()&lt;/code&gt; to standard error an example of why not checking return codes is bad is admittedly somewhat contrived, but this installment is going to amend for that by addressing another problem in the original code.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Before calling &lt;code&gt;popen()&lt;/code&gt;, you may notice, the code invokes &lt;code&gt;(void)fflush(NULL)&lt;/code&gt; - ignoring the result. The reason for this is &lt;a href="http://www.opengroup.org/onlinepubs/007908799/xsh/stdio.html"&gt;somewhat involved&lt;/a&gt;, but easily explained: C standard I/O is &lt;em&gt;buffered&lt;/em&gt;, so you might output a few characters, so few that they would sit in your &lt;code&gt;stdout&lt;/code&gt; buffer waiting for more, invoke through &lt;code&gt;popen()&lt;/code&gt; a program which sends output to standard output on its own, and this output would appear &lt;em&gt;before&lt;/em&gt; the output your program produced before the call, which would be still sitting in its buffer. Calling &lt;code&gt;fflush(NULL)&lt;/code&gt; flushes all open streams, so it's a kind of blanket prevention for the problem &lt;em&gt;with output&lt;/em&gt;; when reading from standard input and invoking a program which itself reads from standard input (an input filter), the problem gets harder and will not be discussed here, and the same goes for similar problems associated with file descriptors.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;You might wonder why &lt;code&gt;popen()&lt;/code&gt; does not perform the equivalent operation by itself; the only reason I can offer you is that the standard says it does not need to. In a few specific cases, such as ours by the way, &lt;code&gt;fflush()&lt;/code&gt; is superfluous: at the point in code where it's called, no output has been produced yet so no output could possibly be sitting in a buffer - but in this case &lt;code&gt;fflush()&lt;/code&gt; should complete with little fuss anyway.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;The real reason, in my opinion, is not visible under the microscope we're using to dissect this toy program, because it's much larger than that. In real code you don't call &lt;code&gt;fflush(NULL)&lt;/code&gt; and ignore the result; an error would mean that some data that you thought you output might have failed to make it from the buffer to its intended destination. Can you say &lt;em&gt;data loss&lt;/em&gt; ? I thought you could.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;In real code, we would track each stream and would know within our code whether it needs to be flushed and, most important of all, what to do in case calling &lt;code&gt;fflush()&lt;/code&gt; on it failed; this might include charging along into &lt;code&gt;popen()&lt;/code&gt;, but chances are you would want to do more than that, and &lt;code&gt;fflush(NULL)&lt;/code&gt; does not even tell you &lt;em&gt;which&lt;/em&gt; stream had a problem, nor can help you address the case when more than one had a problem, and they were not the same problem.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;In our toy program, &lt;code&gt;fflush(NULL)&lt;/code&gt; should not do anything, much less fail. In part 2, two strategies for handling "should not happen" circumstances have been shown: cast to &lt;code&gt;void&lt;/code&gt; or &lt;code&gt;assert()&lt;/code&gt;. Note that our toy program already handles the case of &lt;code&gt;popen()&lt;/code&gt; not providing a stream explicitly; the focus here is on handling the "should not happen" case instead.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;A cast to &lt;code&gt;void&lt;/code&gt; results in the program charging on&lt;br /&gt;&lt;em&gt;as if the call succeeded&lt;/em&gt; (not quite, in fact, as we'll discover when discussing what happens to &lt;code&gt;errno&lt;/code&gt;). The writer is making a statement to the effect that&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;there is no interest in any of the circumstances reported&lt;/li&gt;&lt;br /&gt;&lt;li&gt;any reported circumstance does not invalidate the satisfactory operation of the code which follows&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;and while the first is entirely within the writer's judgement, the second inevitably includes a dose of wishful thinking, unless the definition of "satisfactory operation" is very accomodating. &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;The above paragraph should not be construed as banning the casting approach altogether; our toy program from part 2, for example, invokes &lt;code&gt;fprintf()&lt;/code&gt; at most once in its operation, and then exits. If the invocation fails, there is little we can do (writing an error message just failed, after all) so carrying on as if the problem did not occur is appropriate: there is no interest in the circumstance, and a fair amount of confidence that it will not impact the program exiting shortly thereafter.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;In the case of &lt;code&gt;fflush(NULL)&lt;/code&gt;, however, there is no such confidence that &lt;code&gt;popen()&lt;/code&gt; will be guaranteed to function as advertised; on the contrary, such an unlikely failure would suggest nasty problems with the execution environment, so carrying along as if nothing happened does not cut it. The acknowledged intent of &lt;code&gt;assert()&lt;/code&gt;, however, is guarding against inconsistencies in "our" code, not in the execution environment: on failure &lt;code&gt;assert()&lt;/code&gt; aborts execution, which is an operation tied to the execution environment if there is one. So this is a circumstance that must be handled explicitly:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;/*&lt;br /&gt; popen-test: experiment with popen(), Part 3.&lt;br /&gt;&lt;br /&gt; Copyright © 2006  Davide Bolcioni &amp;lt;dbolcion@libero.it&amp;gt;&lt;br /&gt;                                                                              &lt;br /&gt; Distributed under the GPL,&lt;br /&gt; see http://www.gnu.org/copyleft/gpl.html.&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int main(int argc, char* argv[])&lt;br /&gt;{&lt;br /&gt;  int rc = EXIT_FAILURE; /* Optimist */&lt;br /&gt;&lt;br /&gt;  if (argc &amp;gt; 1) {&lt;br /&gt;    FILE* sink;&lt;br /&gt;&lt;br /&gt;    if (fflush(NULL) != EOF) { /* all open files */&lt;br /&gt;      sink = popen(argv[1], "w");&lt;br /&gt;&lt;br /&gt;      if (sink) {&lt;br /&gt;        int status;&lt;br /&gt;        int i;&lt;br /&gt;&lt;br /&gt;        /* NB: deliberately allow to test for no output sent */&lt;br /&gt;&lt;br /&gt;        for (i = 2; i &amp;lt; argc; i++) {&lt;br /&gt;          (void)fputs(argv[i], sink);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        status = pclose(sink);&lt;br /&gt;    &lt;br /&gt;        /* The return value is funny */&lt;br /&gt;&lt;br /&gt;        if (status == -1) {&lt;br /&gt;          (void)fprintf(stderr,&lt;br /&gt;                "%s: pclose() failed.\n",&lt;br /&gt;                argv[0]);&lt;br /&gt;        }&lt;br /&gt;        else if (WIFEXITED(status)) {&lt;br /&gt;          rc = WEXITSTATUS(status);&lt;br /&gt;          (void)fprintf(stderr,&lt;br /&gt;                "%s: child did an exit(%d).\n",&lt;br /&gt;                argv[0], rc);&lt;br /&gt;        }&lt;br /&gt;        else if (WIFSIGNALED(status)) {&lt;br /&gt;          (void)fprintf(stderr,&lt;br /&gt;                "%s: child terminated by signal %d.\n",&lt;br /&gt;                argv[0], WTERMSIG(status));&lt;br /&gt;        }&lt;br /&gt;        else if (WIFSTOPPED(status)) {&lt;br /&gt;          (void)fprintf(stderr,&lt;br /&gt;                "%s: child stopped with signal %d.\n",&lt;br /&gt;                argv[0], WSTOPSIG(status));&lt;br /&gt;        }&lt;br /&gt;        else {&lt;br /&gt;          (void)fprintf(stderr,&lt;br /&gt;                "%s: I don't think we're in Kansas anymore, Toto.\n",&lt;br /&gt;                argv[0]);&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;      else {&lt;br /&gt;        (void)fprintf(stderr,&lt;br /&gt;              "%s: popen(\"%s\") failed.\n",&lt;br /&gt;              argv[0], argv[1]);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    else {&lt;br /&gt;      (void)fprintf(stderr,&lt;br /&gt;            "%s: fflush(NULL) failed.\n",&lt;br /&gt;            argv[0]);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  else {&lt;br /&gt;    (void)fprintf(stderr,&lt;br /&gt;          "Usage: %s &amp;lt;command&amp;gt; [&amp;lt;arg&amp;gt;]...\n", argv[0]);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return rc;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; vim:sw=2:nowrap&lt;br /&gt;*/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;The code gets uglier still, but at least it's handling the case when unforeseen external occurrences prevent it from proceeding further. One cause of badness, ignoring the result of functions called for their side effects, has been addressed; in the next installment we'll have a look at the handling of &lt;code&gt;errno&lt;/code&gt; and at programs that don't tell you why they fail.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19552152-114099170411372508?l=eleganceofreason.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eleganceofreason.blogspot.com/feeds/114099170411372508/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19552152&amp;postID=114099170411372508' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/114099170411372508'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/114099170411372508'/><link rel='alternate' type='text/html' href='http://eleganceofreason.blogspot.com/2006/02/good-bad-and-ugly-part-3.html' title='The Good, the Bad and the Ugly, part 3'/><author><name>Davide Bolcioni</name><uri>http://www.blogger.com/profile/06027807192913516675</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19552152.post-113856796213329366</id><published>2006-01-29T21:20:00.000+01:00</published><updated>2006-01-29T21:53:58.470+01:00</updated><title type='text'>What Was Old is New Again</title><content type='html'>&lt;div style="text-align: justify;"&gt;I don't know if blogs are going to kill Usenet, but today even I  got to realize that the overlap is significant - better late than never, I guess. Usenet was network &lt;em&gt;news&lt;/em&gt;, and you subscribed to the groups carrying topics of interest in order to get informed of novel developments.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Now, one of my interests is programming language design and evolution, and today's news came from blogs: a presentation about &lt;a href="http://www.peakpeak.com/~tromey/blog/2006/01/27#interp-lang"&gt;speculations about the future of Java&lt;/a&gt; in an otherwise unrelated posting over at &lt;a href="http://www.peakpeak.com/~tromey/blog/"&gt;The Cliffs of Inanity&lt;/a&gt;, and a &lt;a href="http://www.eptacom.net/blog/2006/01/something-new-from-bjarne.html"&gt;very promising concept&lt;/a&gt; from none other than Bjarne Stroustrup himself from &lt;a href="http://www.eptacom.net/blog/blog.html"&gt;the blog of Carlo Pescio&lt;/a&gt;. This was the kind of news that was usually found on Usenet, possibly buried in a thread flaming one language over the other; this was the kind of news that made Usenet an useful source of news.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Now, don't get me wrong: Usenet had a number of cool features, and news dissemination was only one of them; for example, the news might be actually somewhat ... old, but it was brought up while discussing a topic of interest and often to illustrate a point, giving it context and depth; in the above cases, for example, the link about Java lacks this, but there is at least a glimmer of hope that Pescio will write about Bjarne's work in depth at a later date.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19552152-113856796213329366?l=eleganceofreason.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eleganceofreason.blogspot.com/feeds/113856796213329366/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19552152&amp;postID=113856796213329366' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/113856796213329366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/113856796213329366'/><link rel='alternate' type='text/html' href='http://eleganceofreason.blogspot.com/2006/01/what-was-old-is-new-again.html' title='What Was Old is New Again'/><author><name>Davide Bolcioni</name><uri>http://www.blogger.com/profile/06027807192913516675</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19552152.post-113844152922562349</id><published>2006-01-28T10:45:00.000+01:00</published><updated>2006-01-28T15:50:09.266+01:00</updated><title type='text'>Why the Anti GNU Movement ?</title><content type='html'>&lt;div style="text-align: justify;"&gt;Following a link from a news site, I found the &lt;a href="http://antignu.blogspot.com/"&gt;Anti GNU Movement&lt;/a&gt; and read the two posts there. The author, apparently, wants to convince fellow programmers that they should not release code under the &lt;acronym&gt;GPL&lt;/acronym&gt;. Since the code I post is usually under such license, I feel compelled to state my reasons.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;For context, please note that I fail to be incensed, one way or the other, at "communism". I live in what is considered a traditionally "communist" region of Italy, yet I used to vote against communism because of the chance it might somehow help the Soviet Union; when that risk went away, I lost interest. I thought the same should happen to most people, except maybe a few extremists, but over the following years I kept noticing that communism had became a recurrent &lt;span style="font-weight:bold;"&gt;scare word&lt;/span&gt;.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;At first guess, I believe this is because a number of people who enjoy some degree of power over others (a communist might use "employer" and "workers" as examples, but this is so 20th century) would &lt;em&gt;lose&lt;/em&gt; such power should those who are subjected to such power make good of their numbers and together oppose its exercise. The notion that such concerted effort has often a leader, which becomes the one wielding power, is of no comfort to those who risk losing whatever power they have; and losing something you have is an undisputed source of fear.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Having something to lose would explain why some software companies actively oppose the &lt;acronym&gt;GPL&lt;/acronym&gt;. Microsoft, for example, is probably afraid of losing the &lt;em&gt;control&lt;/em&gt; it enjoys over its desktop users, and possibly acrimonious because its attempt to gain control of the server failed; there's no indication that Microsoft is losing money under any shape or form, so it's not about money, it's about control.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;However, although Microsoft got the ball rolling, they're not alone in saying that the &lt;acronym&gt;GPL&lt;/acronym&gt; is communism; a number of voices over the Internet sing to the same tune, and the above blog is but one.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Unless this is another case of &lt;a href="http://en.wikipedia.org/wiki/Astroturfing"&gt;astroturfing&lt;/a&gt;, one would be tempted to think that some opponents of the &lt;acronym&gt;GPL&lt;/acronym&gt;, especially among small companies and professional freelancers, actually resent the fact that the &lt;acronym&gt;GPL&lt;/acronym&gt; makes building something they can sell on top of the work of others, without giving neither money nor code back, riskier than they would like.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Yet, opponents of the &lt;acronym&gt;GPL&lt;/acronym&gt; include, for example, Alexander Terekhov, whose postings on subjects such as POSIX thread programming make it hard to believe he would need to sink that low. I cannot dismiss the possibility, therefore, that opposition to the &lt;acronym&gt;GPL&lt;/acronym&gt; may be borne of purely ideological reasons; after all, it &lt;em&gt;is&lt;/em&gt; a document where ideology plays a substantial role.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;As you might have noticed, this author has not stated yet his reasons for using the &lt;acronym&gt;GPL&lt;/acronym&gt;; for one, unlike the above, I am not at risk of losing something from doing so - I fail to see how I would incur any inconvenience should Microsoft lose control of the desktop, for example. Furthermore, I cannot help but regard those who would like to exploit somebody else's &lt;acronym&gt;GPL&lt;/acronym&gt; code without giving back as parasites, so any step taken to hinder such activities looks to me as the moral equivalent of basic hygiene. Last, the activities of others releasing &lt;em&gt;their&lt;/em&gt; code under the &lt;acronym&gt;GPL&lt;/acronym&gt; provided me with a computing environment which I find more desiderable than other alternatives, so I have reason to believe that in doing the same I might be able to contribute back, thus furthering my own interests. It's as simple as that.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19552152-113844152922562349?l=eleganceofreason.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eleganceofreason.blogspot.com/feeds/113844152922562349/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19552152&amp;postID=113844152922562349' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/113844152922562349'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/113844152922562349'/><link rel='alternate' type='text/html' href='http://eleganceofreason.blogspot.com/2006/01/why-anti-gnu-movement.html' title='Why the Anti GNU Movement ?'/><author><name>Davide Bolcioni</name><uri>http://www.blogger.com/profile/06027807192913516675</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19552152.post-113797191348462297</id><published>2006-01-22T22:52:00.000+01:00</published><updated>2006-01-24T22:23:53.486+01:00</updated><title type='text'>The Good, the Bad and the Ugly, Part 2</title><content type='html'>&lt;div style="text-align: justify;"&gt;Why was the code from Part 1 bad ? For example, it did not check the result of a number of function invocations. Although in the strictest sense there is nothing actually wrong with that, as it is envisioned by the C language, more often than not all it tells the reader is that the writer just didn't think of it. The language also provides the way to tell the maintenance programmer "I am really not interested in the result, only in the side effects" (if you're not interested in the result of a function without side effects, there is no point in calling it, does it ?): cast the result to &lt;code&gt;void&lt;/code&gt;, e.g.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;/*&lt;br /&gt; popen-test: experiment with popen(), Part 2.&lt;br /&gt;&lt;br /&gt; Copyright © 2006  Davide Bolcioni &amp;lt;dbolcion@libero.it&amp;gt;&lt;br /&gt;                                                                              &lt;br /&gt; Distributed under the GPL,&lt;br /&gt; see http://www.gnu.org/copyleft/gpl.html.&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int main(int argc, char* argv[])&lt;br /&gt;{&lt;br /&gt; int rc = EXIT_FAILURE; /* Optimist */&lt;br /&gt;&lt;br /&gt; if (argc &amp;gt; 1) {&lt;br /&gt;   FILE* sink;&lt;br /&gt;&lt;br /&gt;   (void)fflush(NULL); /* all open files */&lt;br /&gt;   sink = popen(argv[1], "w");&lt;br /&gt;&lt;br /&gt;   if (sink) {&lt;br /&gt;     int status;&lt;br /&gt;     int i;&lt;br /&gt;&lt;br /&gt;     /* NB: deliberately allow to test for no output sent */&lt;br /&gt;&lt;br /&gt;     for (i = 2; i &amp;lt; argc; i++) {&lt;br /&gt;       (void)fputs(argv[i], sink);&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     status = pclose(sink);&lt;br /&gt;    &lt;br /&gt;     /* The return value is funny */&lt;br /&gt;&lt;br /&gt;     if (status == -1) {&lt;br /&gt;       (void)fprintf(stderr,&lt;br /&gt;               "%s: pclose() failed.\n",&lt;br /&gt;               argv[0]);&lt;br /&gt;     }&lt;br /&gt;     else if (WIFEXITED(status)) {&lt;br /&gt;       rc = WEXITSTATUS(status);&lt;br /&gt;       (void)fprintf(stderr,&lt;br /&gt;               "%s: child did an exit(%d).\n",&lt;br /&gt;               argv[0], rc);&lt;br /&gt;     }&lt;br /&gt;     else if (WIFSIGNALED(status)) {&lt;br /&gt;       (void)fprintf(stderr,&lt;br /&gt;               "%s: child terminated by signal %d.\n",&lt;br /&gt;               argv[0], WTERMSIG(status));&lt;br /&gt;     }&lt;br /&gt;     else if (WIFSTOPPED(status)) {&lt;br /&gt;       (void)fprintf(stderr,&lt;br /&gt;               "%s: child stopped with signal %d.\n",&lt;br /&gt;               argv[0], WSTOPSIG(status));&lt;br /&gt;     }&lt;br /&gt;     else {&lt;br /&gt;       (void)fprintf(stderr,&lt;br /&gt;               "%s: I don't think we're in Kansas anymore, Toto.\n",&lt;br /&gt;               argv[0]);&lt;br /&gt;     }&lt;br /&gt;   }&lt;br /&gt;   else {&lt;br /&gt;     (void)fprintf(stderr,&lt;br /&gt;             "%s: popen(\"%s\") failed.\n",&lt;br /&gt;             argv[0], argv[1]);&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt; else {&lt;br /&gt;   (void)fprintf(stderr,&lt;br /&gt;           "Usage: %s &amp;lt;command&amp;gt; [&amp;lt;arg&amp;gt;]...\n", argv[0]);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; return rc;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; vim:sw=2:nowrap&lt;br /&gt;*/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;As you can see, the code is definitely getting uglier. The above tells us that the writer was not interested in the result of the functions, but tells us very little about &lt;em&gt;why&lt;/em&gt;: he might be ignoring a result he should heed.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Handling the result of a function which is called primarily for its side effects is harder than it seems, because the result typically tells if the function was "successful", i.e. the intended side effects actually occurred. If the function returns failure, the caller must handle the fact; as we'll see in the next part, this significantly complicates the code.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Because of the effort involved in handling failures, there is a strong temptation to pretend that side effect causing functions cannot fail; some of you might even say that in the above concrete case, the &lt;code&gt;fprintf()&lt;/code&gt; invocations &lt;em&gt;cannot&lt;/em&gt; fail. To let the maintenance programmer know that a specific invocation cannot fail, just use &lt;code&gt;assert()&lt;/code&gt;:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;   assert(fprintf(stderr,&lt;br /&gt;          "Usage: %s &amp;lt;command&amp;gt; [&amp;lt;arg&amp;gt;]...\n", argv[0]) &amp;gt; 0);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;This code is actually &lt;strong&gt;wrong&lt;/strong&gt;; if the code is built with &lt;code&gt;NDEBUG&lt;/code&gt;, the &lt;code&gt;assert()&lt;/code&gt; gets removed during preprocessing and no &lt;code&gt;fprintf()&lt;/code&gt; invocation would occur in its place. The ugly-as-hell but correct option is to remember the result in a variable:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;  int written = fprintf(stderr,&lt;br /&gt;                "Usage: %s &amp;lt;command&amp;gt; [&amp;lt;arg&amp;gt;]...\n", argv[0]);&lt;br /&gt;  assert(written &gt; 0);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;which, unless we want to get into reusing variables or to devise a different variable name for each invocation of &lt;code&gt;fprintf()&lt;/code&gt;, gets uglier still:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;  {&lt;br /&gt;    int written = fprintf(stderr,&lt;br /&gt;                  "Usage: %s &amp;lt;command&amp;gt; [&amp;lt;arg&amp;gt;]...\n", argv[0]);&lt;br /&gt;    assert(written &gt; 0);&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;The &lt;code&gt;assert()&lt;/code&gt; condition in the examples above is not very tight, since &lt;code&gt;fprintf&lt;/code&gt; returns the number of characters written; we're essentially saying that we're positive that &lt;code&gt;fprintf()&lt;/code&gt; wrote &lt;em&gt;something&lt;/em&gt;. If we wanted to say that we're sure that &lt;code&gt;fprintf()&lt;/code&gt; unfailingly wrote &lt;em&gt;everything&lt;/em&gt;, we'd have to write a much more involved condition.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;There is a trap hidden in there, as in the example below&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;  {&lt;br /&gt;    int written = fprintf(stderr,&lt;br /&gt;                  "%s", argv[1]);&lt;br /&gt;    assert(written &gt; 0);&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;the assertion would fire incorrectly if &lt;code&gt;argv[1]&lt;/code&gt; had zero length, and the maintenance programmer would have to decide whether the original author did not look up what the return value of &lt;code&gt;fprintf()&lt;/code&gt; means, or &lt;code&gt;argv[1]&lt;/code&gt; was supposed to have a positive length.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;So, when handling results for functions called for their side effect, we can state our convincement that a failure cannot occur with &lt;code&gt;assert()&lt;/code&gt;, admit our lack of interest in the matter by casting to &lt;code&gt;void&lt;/code&gt;, or handle the failure ourselves, which we'll discuss in Part 3.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19552152-113797191348462297?l=eleganceofreason.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eleganceofreason.blogspot.com/feeds/113797191348462297/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19552152&amp;postID=113797191348462297' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/113797191348462297'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/113797191348462297'/><link rel='alternate' type='text/html' href='http://eleganceofreason.blogspot.com/2006/01/good-bad-and-ugly-part-2.html' title='The Good, the Bad and the Ugly, Part 2'/><author><name>Davide Bolcioni</name><uri>http://www.blogger.com/profile/06027807192913516675</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19552152.post-113727934299597468</id><published>2006-01-14T22:41:00.000+01:00</published><updated>2006-01-21T22:41:55.606+01:00</updated><title type='text'>The Good, the Bad and the Ugly, Part 1</title><content type='html'>&lt;div style="text-align: justify;"&gt;This is a detour from shell programming to the halcyon days of C programming, initially born of the necessity to investigate a surprising incident involving &lt;code&gt;popen()&lt;/code&gt;, which however I am turning into a kind of mini-series. Consider the following code:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;/*&lt;br /&gt;  popen-test: experiment with popen().&lt;br /&gt;&lt;br /&gt;  Copyright &amp;copy; 2006  Davide Bolcioni &amp;lt;dbolcion@libero.it&amp;gt;&lt;br /&gt;                                                                                &lt;br /&gt;  Distributed under the GPL,&lt;br /&gt;  see http://www.gnu.org/copyleft/gpl.html.&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int main(int argc, char* argv[])&lt;br /&gt;{&lt;br /&gt;  int rc = EXIT_FAILURE; /* Optimist */&lt;br /&gt;&lt;br /&gt;  if (argc &amp;gt; 1) {&lt;br /&gt;    FILE* sink;&lt;br /&gt;&lt;br /&gt;    fflush(NULL); /* all open files */&lt;br /&gt;    sink = popen(argv[1], "w");&lt;br /&gt;&lt;br /&gt;    if (sink) {&lt;br /&gt;      int status;&lt;br /&gt;      int i;&lt;br /&gt;&lt;br /&gt;      /* NB: deliberately allow to test for no output sent */&lt;br /&gt;&lt;br /&gt;      for (i = 2; i &amp;lt; argc; i++) {&lt;br /&gt;        fputs(argv[i], sink);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      status = pclose(sink);&lt;br /&gt;      &lt;br /&gt;      /* The return value is funny */&lt;br /&gt;&lt;br /&gt;      if (status == -1) {&lt;br /&gt;        fprintf(stderr, &lt;br /&gt;                "%s: pclose() failed.\n",&lt;br /&gt;                argv[0]);&lt;br /&gt;      }&lt;br /&gt;      else if (WIFEXITED(status)) {&lt;br /&gt;        rc = WEXITSTATUS(status);&lt;br /&gt;        fprintf(stderr,&lt;br /&gt;                "%s: child did an exit(%d).\n",&lt;br /&gt;                argv[0], rc);&lt;br /&gt;      }&lt;br /&gt;      else if (WIFSIGNALED(status)) {&lt;br /&gt;        fprintf(stderr,&lt;br /&gt;                "%s: child terminated by signal %d.\n",&lt;br /&gt;                argv[0], WTERMSIG(status));&lt;br /&gt;      }&lt;br /&gt;      else if (WIFSTOPPED(status)) {&lt;br /&gt;        fprintf(stderr,&lt;br /&gt;                "%s: child stopped with signal %d.\n",&lt;br /&gt;                argv[0], WSTOPSIG(status));&lt;br /&gt;      }&lt;br /&gt;      else {&lt;br /&gt;        fprintf(stderr,&lt;br /&gt;                "%s: I don't think we're in Kansas anymore, Toto.\n",&lt;br /&gt;                argv[0]);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    else {&lt;br /&gt;      fprintf(stderr,&lt;br /&gt;              "%s: popen(\"%s\") failed.\n", &lt;br /&gt;              argv[0], argv[1]);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  else {&lt;br /&gt;    fprintf(stderr, &lt;br /&gt;            "Usage: %s &amp;lt;command&amp;gt; [&amp;lt;arg&amp;gt;]...\n", argv[0]);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return rc;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;  vim:sw=2:nowrap&lt;br /&gt; */&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;If you excuse the poor formatting of &lt;code&gt;fprintf()&lt;/code&gt;, the above code seems to get the job done: it allows you to experiment with &lt;code&gt;popen()&lt;/code&gt; by launching the &lt;em&gt;command&lt;/em&gt; specified as first argument and piping the remaining command line arguments, one by one, into its standard input. The result of &lt;code&gt;pclose()&lt;/code&gt; is then cracked using a few macros from &lt;code&gt;&amp;lt;sys/wait.h&amp;gt;&lt;/code&gt;.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;This is, however, &lt;strong&gt;bad&lt;/strong&gt; code; it appears to work, fulfills the intended purpose and, because of this, tempts the casual onlooker into believing that it can be reused as is, or as an example of using &lt;code&gt;popen()&lt;/code&gt;. If it didn't work, or didn't fit its initial purpose, it would be discarded with little harm done.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;In subsequent entries, it is my intent to pick at its defects and address them one by one; what I mean to show over the course of the series, however, is that getting code that works and fulfills its intended purpose is only the beginning of the journey. Code should also be &lt;em&gt;correct&lt;/em&gt;, by which I do not mean "proven correct"; for those of us who are not into correcteness proofs, "at least not sloppy" would be enough. After getting past the "not sloppy" milestone, the result will be &lt;strong&gt;ugly&lt;/strong&gt; code (yes, uglier than that) which will need a dose of ... elegance to obtain &lt;strong&gt;good&lt;/strong&gt; code.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Whether this author will be up to the task, of course, remains to be seen.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19552152-113727934299597468?l=eleganceofreason.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eleganceofreason.blogspot.com/feeds/113727934299597468/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19552152&amp;postID=113727934299597468' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/113727934299597468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/113727934299597468'/><link rel='alternate' type='text/html' href='http://eleganceofreason.blogspot.com/2006/01/good-bad-and-ugly-part-1.html' title='The Good, the Bad and the Ugly, Part 1'/><author><name>Davide Bolcioni</name><uri>http://www.blogger.com/profile/06027807192913516675</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19552152.post-113390988343823573</id><published>2005-12-06T23:36:00.000+01:00</published><updated>2005-12-07T00:03:45.973+01:00</updated><title type='text'>Portability Interlude</title><content type='html'>&lt;div style="text-align: justify;"&gt;In the previous post, the syntax &lt;code&gt;${2:-1}&lt;/code&gt; was used in the implementation of &lt;code&gt;die()&lt;/code&gt; in the usual sense of providing a default value of &lt;code&gt;1&lt;/code&gt; if parameter &lt;code&gt;$2&lt;/code&gt; is null or unset.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;According to &lt;a href="http://www.opengroup.org/onlinepubs/007908799/xcu/chap2.html#tag_001_006_002"&gt;The Single UNIX Specification&lt;/a&gt;, the above syntax is the standard-blessed way to obtain the intended effect; according to the &lt;a href="http://sources.redhat.com/autobook/autobook/autobook_217.html#SEC217"&gt;Autobook&lt;/a&gt;, however, the notation &lt;code&gt;${2-1}&lt;/code&gt; would be more portable. Experimentation with a few &lt;code&gt;sh&lt;/code&gt;-derived shells, shows that none chokes on either syntax; on the matter of portability it is always wise to acknowledge consolidated practice, so the implementation of &lt;code&gt;die()&lt;/code&gt; is hereby changed accordingly.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;warn() {&lt;br /&gt;  echo 1&amp;gt;&amp;amp;2 "$0: $1"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;die() {&lt;br /&gt;  warn "$1"; exit ${2-1}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19552152-113390988343823573?l=eleganceofreason.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eleganceofreason.blogspot.com/feeds/113390988343823573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19552152&amp;postID=113390988343823573' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/113390988343823573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/113390988343823573'/><link rel='alternate' type='text/html' href='http://eleganceofreason.blogspot.com/2005/12/portability-interlude.html' title='Portability Interlude'/><author><name>Davide Bolcioni</name><uri>http://www.blogger.com/profile/06027807192913516675</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19552152.post-113364914296948088</id><published>2005-12-03T22:40:00.000+01:00</published><updated>2005-12-04T00:01:15.816+01:00</updated><title type='text'>Improving shell scripts</title><content type='html'>&lt;div style="text-align: justify;"&gt;Although there is no reason to exempt shell scripts from good programming practices, many scripts showing signs of such neglect can readily be found over the Internet. This is sad, because it brings shell programming down to the level of Visual Basic, and because it can be easily avoided.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Consider a common task: upon encountering a condition which does not allow script execution to continue, show a diagnostic and exit. Most scripts do that, it's &lt;span style="font-style: italic;"&gt;how&lt;/span&gt; they do it that could use some improvement. Consider a first attempt:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;warn() {&lt;br /&gt;  echo 1&amp;gt;&amp;amp;2 "$0: $1"&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;die() {&lt;br /&gt;  warn "$1"; exit ${2:-1}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Here the &lt;code&gt;warn()&lt;/code&gt; function anticipates a variation of the initial use case: the script encountered a condition which is supposedly of some interest to the user, but does not prevent the script from proceeding with execution. The &lt;code&gt;die()&lt;/code&gt; function, also borrowed from Perl, just puts it to good use and exits.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;The message is printed on standard error: this is an important and too often overlooked behavior, which makes parsing standard output easier and therefore the script more useful in pipelines.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Furthermore, according to Unix conventions, the message begins with the command name &lt;code&gt;$0&lt;/code&gt; followed by a semicolon, a space, and the diagnostic proper; this helps when a script is invoked by another script, to sort out who produced the diagnostic.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align:justify;"&gt;Last, &lt;code&gt;die()&lt;/code&gt; exits the script with a non-zero return code, again according to Unix conventions. The actual exit code can be left unspecified, for the convenience of the caller in code such as:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="border: thin solid ; padding-left: 2em;"&gt;&lt;pre&gt;&lt;br /&gt;tar --version &gt;/dev/null 2&amp;gt;&amp;amp;1 || die "cannot find tar(1)"&lt;br /&gt;tar -c -f /dev/nst0 /opt || warn "Backup failed"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align:justify;"&gt;The above code is not completely satisfying, but at least offers a starting point for putting some self-respect in shell scripts. The Perl module &lt;code&gt;Pod::Usage&lt;/code&gt; provides some directions which can be borrowed to improve it, and there is also an instance of poor quoting, which will be fixed in a forthcoming post.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19552152-113364914296948088?l=eleganceofreason.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eleganceofreason.blogspot.com/feeds/113364914296948088/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19552152&amp;postID=113364914296948088' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/113364914296948088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19552152/posts/default/113364914296948088'/><link rel='alternate' type='text/html' href='http://eleganceofreason.blogspot.com/2005/12/improving-shell-scripts.html' title='Improving shell scripts'/><author><name>Davide Bolcioni</name><uri>http://www.blogger.com/profile/06027807192913516675</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
