"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.11/make-errors.sh" (8 Aug 2018, 15360 Bytes) of package /linux/misc/s-nail-14.9.11.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Bash source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "make-errors.sh": 14.9.9_vs_14.9.10.

    1 #!/bin/sh -
    2 #@ Create gen-errors.h.  And see auxlily.c.
    3 # Public Domain
    4 
    5 # Acceptable "longest distance" from hash-modulo-index to key
    6 MAXDISTANCE_PENALTY=5
    7 
    8 # Generate a more verbose output.  Not for shipout versions.
    9 VERB=1
   10 
   11 MAILX='LC_ALL=C s-nail -#:/'
   12 OUT="${SRCDIR}"gen-errors.h
   13 
   14 ##
   15 
   16 LC_ALL=C
   17 export LC_ALL MAXDISTANCE_PENALTY VERB MAILX OUT
   18 
   19 [ -n "${awk}" ] || awk=awk
   20 
   21 # The set of errors we support
   22 ERRORS="\
   23    NONE='No error' \
   24    2BIG='Argument list too long' \
   25    ACCES='Permission denied' \
   26    ADDRINUSE='Address already in use' \
   27    ADDRNOTAVAIL='Cannot assign requested address' \
   28    AFNOSUPPORT='Address family not supported by protocol family' \
   29    AGAIN='Resource temporarily unavailable' \
   30    ALREADY='Operation already in progress' \
   31    BADF='Bad file descriptor' \
   32    BADMSG='Bad message' \
   33    BUSY='Device busy' \
   34    CANCELED='Operation canceled' \
   35    CHILD='No child processes' \
   36    CONNABORTED='Software caused connection abort' \
   37    CONNREFUSED='Connection refused' \
   38    CONNRESET='Connection reset by peer' \
   39    DEADLK='Resource deadlock avoided' \
   40    DESTADDRREQ='Destination address required' \
   41    DOM='Numerical argument out of domain' \
   42    DQUOT='Disc quota exceeded' \
   43    EXIST='File exists' \
   44    FAULT='Bad address' \
   45    FBIG='File too large' \
   46    HOSTUNREACH='No route to host' \
   47    IDRM='Identifier removed' \
   48    ILSEQ='Illegal byte sequence' \
   49    INPROGRESS='Operation now in progress' \
   50    INTR='Interrupted system call' \
   51    INVAL='Invalid argument' \
   52    IO='Input/output error' \
   53    ISCONN='Socket is already connected' \
   54    ISDIR='Is a directory' \
   55    MFILE='Too many open files' \
   56    MLINK='Too many links' \
   57    MSGSIZE='Message too long' \
   58    MULTIHOP='Multihop attempted' \
   59    NAMETOOLONG='File name too long' \
   60    NETDOWN='Network is down' \
   61    NETRESET='Network dropped connection on reset' \
   62    NETUNREACH='Network is unreachable' \
   63    NFILE='Too many open files in system' \
   64    NOBUFS='No buffer space available' \
   65    NODATA='No data available' \
   66    NODEV='Operation not supported by device' \
   67    NOENT='No such entry, file or directory' \
   68    NOEXEC='Exec format error' \
   69    NOLCK='No locks available' \
   70    NOLINK='Link has been severed' \
   71    NOMEM='Cannot allocate memory' \
   72    NOMSG='No message of desired type' \
   73    NOPROTOOPT='Protocol not available' \
   74    NOSPC='No space left on device' \
   75    NOSR='Out of streams resource' \
   76    NOSTR='Device not a stream' \
   77    NOSYS='Function not implemented' \
   78    NOTCONN='Socket is not connected' \
   79    NOTDIR='Not a directory' \
   80    NOTEMPTY='Directory not empty' \
   81    NOTOBACCO='Snorkeling on empty pipe' \
   82    NOTSOCK='Socket operation on non-socket' \
   83    NOTSUP='Operation not supported' \
   84    NOTTY='Inappropriate ioctl for device' \
   85    NXIO='Device not configured' \
   86    OPNOTSUPP='Operation not supported' \
   87    OVERFLOW='Value too large to be stored in data type' \
   88    PERM='Operation not permitted' \
   89    PIPE='Broken pipe' \
   90    PROTO='Protocol error' \
   91    PROTONOSUPPORT='Protocol not supported' \
   92    PROTOTYPE='Protocol wrong type for socket' \
   93    RANGE='Result too large' \
   94    ROFS='Read-only filesystem' \
   95    SPIPE='Invalid seek' \
   96    SRCH='No such process' \
   97    STALE='Stale NFS file handle' \
   98    TIME='Timer expired' \
   99    TIMEDOUT='Operation timed out' \
  100    TXTBSY='Text file busy' \
  101    WOULDBLOCK='Operation would block' \
  102    XDEV='Cross-device link' \
  103 "
  104 export ERRORS
  105 
  106 error_parse() {
  107    j=\'
  108    ${awk} -v dodoc="${1}" -v incnone="${2}" -v input="${ERRORS}" '
  109       BEGIN{
  110          for(i = 0;;){
  111             voff = match(input, /[[:alnum:]_]+(='${j}'[^'${j}']+)?/)
  112             if(voff == 0)
  113                break
  114             v = substr(input, voff, RLENGTH)
  115             input = substr(input, voff + RLENGTH)
  116             doff = index(v, "=")
  117             if(doff > 0){
  118                d = substr(v, doff + 2, length(v) - doff - 1)
  119                v = substr(v, 1, doff - 1)
  120             }
  121             if(!incnone && v == "NONE")
  122                continue
  123             print dodoc ? d : v
  124          }
  125       }
  126    '
  127 }
  128 
  129 config() {
  130    [ -n "${TARGET}" ] || {
  131       echo >&2 'Invalid usage'
  132       exit 1
  133    }
  134    # Note this may be ISO C89, so we cannot 
  135    cat <<__EOT__
  136    #include <errno.h>
  137    #include <limits.h>
  138    #include <stdio.h>
  139    #include <stdlib.h>
  140    #include <string.h>
  141    #if defined __STDC_VERSION__ && __STDC_VERSION__ + 0 >= 199901L
  142    # include <stdint.h>
  143    #else
  144    # include <inttypes.h>
  145    #endif
  146    #ifdef UINT32_MAX
  147    typedef uint32_t ui32_t;
  148    typedef int32_t si32_t;
  149    #elif ULONG_MAX == 0xFFFFFFFFu
  150    typedef unsigned long int ui32_t;
  151    typedef signed long int si32_t;
  152    #else
  153    typedef unsigned int ui32_t;
  154    typedef signed int si32_t;
  155    #endif
  156    struct a_in {struct a_in *next; char const *name; si32_t no; ui32_t uno;};
  157    static int a_sortin(void const *a, void const *b){
  158       return (*(struct a_in const* const *)a)->uno -
  159          (*(struct a_in const* const *)b)->uno;
  160    }
  161    int main(void){
  162       char line[1024], *lp;
  163       struct a_in *head, *tail, *np, **nap;
  164       ui32_t maxsub, umax;
  165       si32_t xavail = 0, total = 1, imin = 0, imax = 0, voidoff = 0,
  166          i, telloff, j;
  167       FILE *ifp = fopen("${OUT}", "r"), *ofp = fopen("${TARGET}", "a");
  168       if(ifp == NULL || ofp == NULL){
  169          fprintf(stderr, "ERROR: cannot open in- or output\n");
  170          return 1;
  171       }
  172 
  173       /* Create a list of all errors */
  174       head = tail = malloc(sizeof *head);
  175       head->next = NULL; head->name = "n_ERR_NONE"; head->no = 0;
  176 __EOT__
  177    for n in `error_parse 0 0`; do
  178       cat <<__EOT__
  179       ++total;
  180       #ifdef E${n}
  181       i = E${n};
  182       #else
  183       i = --xavail;
  184       #endif
  185       if(imin > i) imin = i; if(imax < i) imax = i;
  186       np = malloc(sizeof *np);
  187       np->next = NULL; np->name = "n_ERR_${n}"; np->no = i;
  188       tail->next = np; tail = np;
  189 __EOT__
  190    done
  191    cat <<__EOT__
  192       /* The unsigned type used for storage */
  193 
  194       fputs("#define n__ERR_NUMBER_TYPE ", ofp);
  195       if((ui32_t)imax <= 0xFFu && (ui32_t)-imin <= 0xFFu){
  196          fputs("ui8_t\n", ofp);
  197          maxsub = 0xFFu;
  198       }else if(((ui32_t)imax <= 0xFFFFu && (ui32_t)-imin <= 0xFFFFu)){
  199          fputs("ui16_t\n", ofp);
  200          maxsub = 0xFFFFu;
  201       }else{
  202          fputs("ui32_t\n", ofp);
  203          maxsub = 0xFFFFFFFFu;
  204       }
  205 
  206       /* Now that we know the storage type, create the unsigned numbers */
  207       for(umax = 0, np = head; np != NULL; np = np->next){
  208          if(np->no < 0)
  209             np->uno = maxsub + np->no + 1;
  210          else
  211             np->uno = np->no;
  212          if(np->uno > umax)
  213             umax = np->uno;
  214       }
  215       if(umax <= (ui32_t)imax){
  216          fprintf(stderr, "ERROR: errno ranges overlap\n");
  217          return 1;
  218       }
  219 
  220       /* Sort this list */
  221 
  222       nap = malloc(sizeof(*nap) * (unsigned)total);
  223       for(i = 0, np = head; np != NULL; ++i, np = np->next)
  224          nap[i] = np;
  225       if(i != total){
  226          fprintf(stderr, "ERROR: implementation error i != total\n");
  227          return 1;
  228       }
  229       qsort(nap, (ui32_t)i, sizeof *nap, &a_sortin);
  230 
  231       /* The enumeration of numbers */
  232 
  233       fputs("enum n_err_number{\\n", ofp);
  234       for(i = 0; i < total; ++i)
  235          fprintf(ofp, "   %s = %lu,\\n",
  236             nap[i]->name, (unsigned long)nap[i]->uno);
  237       fprintf(ofp, "   n__ERR_NUMBER = %ld\\n", (long)total);
  238       fputs("};\\n", ofp);
  239 
  240       /* The binary search mapping table from OS error value to our internal
  241        * a_aux_err_map[] error description table */
  242 
  243       /* A real hack to have a fast NUMBER -> MAP mapping without compiling
  244        * and running a second C program during config */
  245       while((lp = fgets(line, sizeof line, ifp)) != NULL &&
  246             strstr(lp, "a_aux_err_map[]") == NULL)
  247          ;
  248       if(feof(ifp) || ferror(ifp)){
  249          fprintf(stderr, "ERROR: I/O error when reading \"ifp\"\n");
  250          return 1;
  251       }
  252       telloff = (int)ftell(ifp);
  253 
  254       fprintf(ofp, "#define n__ERR_NUMBER_TO_MAPOFF \\\\\\n");
  255       for(xavail = 0, i = 0; i < total; ++i){
  256          if(i == 0 || nap[i]->no != nap[i - 1]->no){
  257             if(fseek(ifp, telloff, SEEK_SET) == -1){
  258                fprintf(stderr, "ERROR: I/O error when searching \"ifp\", I.\n");
  259                return 1;
  260             }
  261             j = 0;
  262             while((lp = fgets(line, sizeof line, ifp)) != NULL &&
  263                   strstr(lp, nap[i]->name) == NULL)
  264                ++j;
  265             if(feof(ifp) || ferror(ifp)){
  266                fprintf(stderr, "ERROR: I/O error when reading \"ifp\", II.\n");
  267                return 1;
  268             }
  269             fprintf(ofp, "\ta_X(%lu, %lu) %s%s%s\\\\\\n",
  270                (unsigned long)nap[i]->uno, (long)(ui32_t)j,
  271                ((${VERB}) ? "/* " : ""), ((${VERB}) ? nap[i]->name : ""),
  272                   ((${VERB}) ? " */ " : ""));
  273             if(!strcmp("n_ERR_NOTOBACCO", nap[i]->name))
  274                voidoff = j;
  275             ++xavail;
  276          }
  277       }
  278       fprintf(ofp, "\\t/* %ld unique members */\\n", (long)xavail);
  279       fprintf(ofp, "#define n__ERR_NUMBER_VOIDOFF %ld\\n", (long)voidoff);
  280       fclose(ofp);
  281 
  282       while((np = head) != NULL){
  283          head = np->next;
  284          free(np);
  285       }
  286       free(nap);
  287       return 0;
  288    }
  289 __EOT__
  290    exit 0
  291 }
  292 
  293 if [ ${#} -ne 0 ]; then
  294    if [ "${1}" = noverbose ]; then
  295       shift
  296       VERB=0
  297       export VERB
  298    fi
  299 fi
  300 
  301 if [ ${#} -eq 1 ]; then
  302    [ "${1}" = config ] && config
  303 elif [ ${#} -eq 0 ]; then
  304    # Now start perl(1) without PERL5OPT set to avoid multibyte sequence errors
  305    PERL5OPT= PERL5LIB= exec perl -x "${0}"
  306 fi
  307 echo >&2 'Invalid usage'
  308 exit 1
  309 
  310 # Thanks to perl(5) and it's -x / #! perl / __END__ mechanism!
  311 # Why can env(1) not be used for such easy things in #!?
  312 #!perl
  313 
  314 use diagnostics -verbose;
  315 use strict;
  316 use warnings;
  317 
  318 use FileHandle;
  319 use IPC::Open2;
  320 
  321 use sigtrap qw(handler cleanup normal-signals);
  322 
  323 my ($S, @ENTS, $CTOOL, $CTOOL_EXE) = ($ENV{VERB} ? '   ' : '');
  324 
  325 sub main_fun{
  326    create_ents();
  327 
  328    create_c_tool();
  329 
  330    hash_em();
  331 
  332    dump_map();
  333 
  334    reverser();
  335 
  336    cleanup(undef);
  337    exit 0
  338 }
  339 
  340 sub cleanup{
  341    die "$CTOOL_EXE: couldn't unlink: $^E"
  342       if $CTOOL_EXE && -f $CTOOL_EXE && 1 != unlink $CTOOL_EXE;
  343    die "$CTOOL: couldn't unlink: $^E"
  344       if $CTOOL && -f $CTOOL && 1 != unlink $CTOOL;
  345    die "Terminating due to signal $_[0]" if $_[0]
  346 }
  347 
  348 sub create_ents{
  349    my $input = $ENV{ERRORS};
  350    while($input =~ /([[:alnum:]_]+)='([^']+)'(.*)/){
  351       $input = $3;
  352       my %vals;
  353       $vals{name} = $1;
  354       $vals{doc} = $2;
  355       push @ENTS, \%vals
  356    }
  357 }
  358 
  359 sub create_c_tool{
  360    $CTOOL = './tmp-errors-tool-' . $$ . '.c';
  361    $CTOOL_EXE = $CTOOL . '.exe';
  362 
  363    die "$CTOOL: open: $^E" unless open F, '>', $CTOOL;
  364    print F '#define MAX_DISTANCE_PENALTY ', $ENV{MAXDISTANCE_PENALTY}, "\n";
  365 # >>>>>>>>>>>>>>>>>>>
  366    print F <<'_EOT';
  367 #define __CREATE_ERRORS_SH
  368 #include <stdint.h>
  369 #include <stdlib.h>
  370 #include <stdio.h>
  371 #include <string.h>
  372 
  373 #define n_NELEM(A) (sizeof(A) / sizeof(A[0]))
  374 
  375 #define ui32_t uint32_t
  376 #define si32_t int32_t
  377 #define ui16_t uint16_t
  378 #define ui8_t uint8_t
  379 
  380 struct a_aux_err_map{
  381    ui32_t aem_hash;     /* Hash of name */
  382    ui32_t aem_nameoff;  /* Into a_aux_err_names[] */
  383    ui32_t aem_docoff;   /* Into a_aux_err docs[] */
  384    si32_t aem_errno;    /* The OS errno value for this one */
  385 };
  386 
  387 #include "gen-errors.h"
  388 
  389 static ui8_t seen_wraparound;
  390 static size_t longest_distance;
  391 
  392 static size_t
  393 next_prime(size_t no){ /* blush (brute force) */
  394 jredo:
  395    ++no;
  396    for(size_t i = 3; i < no; i += 2)
  397       if(no % i == 0)
  398          goto jredo;
  399    return no;
  400 }
  401 
  402 static size_t *
  403 reversy(size_t size){
  404    struct a_aux_err_map const *aemp = a_aux_err_map,
  405       *aemaxp = aemp + n_NELEM(a_aux_err_map);
  406    size_t ldist = 0, *arr;
  407 
  408    arr = malloc(sizeof *arr * size);
  409    for(size_t i = 0; i < size; ++i)
  410       arr[i] = n_NELEM(a_aux_err_map);
  411 
  412    seen_wraparound = 0;
  413    longest_distance = 0;
  414 
  415    while(aemp < aemaxp){
  416       ui32_t hash = aemp->aem_hash, i = hash % size, l;
  417 
  418       for(l = 0; arr[i] != n_NELEM(a_aux_err_map); ++l)
  419          if(++i == size){
  420             seen_wraparound = 1;
  421             i = 0;
  422          }
  423       if(l > longest_distance)
  424          longest_distance = l;
  425       arr[i] = (size_t)(aemp++ - a_aux_err_map);
  426    }
  427    return arr;
  428 }
  429 
  430 int
  431 main(int argc, char **argv){
  432    size_t *arr, size = n_NELEM(a_aux_err_map);
  433 
  434    fprintf(stderr, "Starting reversy, okeys=%zu\n", size);
  435    for(;;){
  436       arr = reversy(size = next_prime(size));
  437       fprintf(stderr, " - size=%zu longest_distance=%zu seen_wraparound=%d\n",
  438          size, longest_distance, seen_wraparound);
  439       if(longest_distance <= MAX_DISTANCE_PENALTY)
  440          break;
  441       free(arr);
  442    }
  443 
  444    printf(
  445       "#define a_AUX_ERR_REV_ILL %zuu\n"
  446       "#define a_AUX_ERR_REV_PRIME %zuu\n"
  447       "#define a_AUX_ERR_REV_LONGEST %zuu\n"
  448       "#define a_AUX_ERR_REV_WRAPAROUND %d\n"
  449       "static %s const a_aux_err_revmap[a_AUX_ERR_REV_PRIME] = {\n%s",
  450       n_NELEM(a_aux_err_map), size, longest_distance, seen_wraparound,
  451       argv[1], (argc > 2 ? "  " : ""));
  452    for(size_t i = 0; i < size; ++i)
  453       printf("%s%zuu", (i == 0 ? ""
  454          : (i % 10 == 0 ? (argc > 2 ? ",\n  " : ",\n")
  455             : (argc > 2 ? ", " : ","))),
  456          arr[i]);
  457    printf("\n};\n");
  458    return 0;
  459 }
  460 _EOT
  461 # <<<<<<<<<<<<<<<<<<<
  462    close F
  463 }
  464 
  465 sub hash_em{
  466    die "hash_em: open: $^E"
  467       unless my $pid = open2 *RFD, *WFD, $ENV{MAILX};
  468    foreach my $e (@ENTS){
  469       print WFD "vexpr hash $e->{name}\n";
  470       my $h = <RFD>;
  471       chomp $h;
  472       $e->{hash} = $h
  473    }
  474    print WFD "x\n";
  475    waitpid $pid, 0;
  476 }
  477 
  478 sub dump_map{
  479    die "$ENV{OUT}: open: $^E" unless open F, '>', $ENV{OUT};
  480    print F "/*@ $ENV{OUT}, generated by $0.\n",
  481       " *@ See auxlily.c for more */\n\n";
  482 
  483    print F 'static char const a_aux_err_names[] = {', "\n";
  484    my ($i, $alen) = (0, 0);
  485    foreach my $e (@ENTS){
  486       $e->{nameoff} = $alen;
  487       my $k = $e->{name};
  488       my $l = length $k;
  489       my $a = join '\',\'', split(//, $k);
  490       my (@fa);
  491       print F "${S}/* $i. [$alen]+$l $k */\n" if $ENV{VERB};
  492       print F "${S}'$a','\\0',\n";
  493       ++$i;
  494       $alen += $l + 1
  495    }
  496    print F '};', "\n\n";
  497 
  498    print F '#ifdef HAVE_DOCSTRINGS', "\n";
  499    print F '#undef a_X', "\n", '#define a_X(X)', "\n";
  500    print F 'static char const a_aux_err_docs[] = {', "\n";
  501    ($i, $alen) = (0, 0);
  502    foreach my $e (@ENTS){
  503       $e->{docoff} = $alen;
  504       my $k = $e->{doc};
  505       my $l = length $k;
  506       my $a = join '\',\'', split(//, $k);
  507       my (@fa);
  508       print F "${S}/* $i. [$alen]+$l $e->{name} */ ",
  509          "a_X(N_(\"$e->{doc}\"))\n" if $ENV{VERB};
  510       print F "${S}'$a','\\0',\n";
  511       ++$i;
  512       $alen += $l + 1
  513    }
  514    print F '};', "\n", '#undef a_X', "\n#endif /* HAVE_DOCSTRINGS */\n\n";
  515 
  516    print F <<_EOT;
  517 #undef a_X
  518 #ifndef __CREATE_ERRORS_SH
  519 # define a_X(X) X
  520 #else
  521 # define a_X(X) 0
  522 #endif
  523 static struct a_aux_err_map const a_aux_err_map[] = {
  524 _EOT
  525    foreach my $e (@ENTS){
  526       print F "${S}{$e->{hash}u, $e->{nameoff}u, $e->{docoff}u, ",
  527          "a_X(n_ERR_$e->{name})},\n"
  528    }
  529    print F '};', "\n", '#undef a_X', "\n\n";
  530 
  531    die "$ENV{OUT}: close: $^E" unless close F
  532 }
  533 
  534 sub reverser{
  535    my $argv2 = $ENV{VERB} ? ' verb' : '';
  536    system("\$CC -I. -o $CTOOL_EXE $CTOOL");
  537    my $t = (@ENTS < 0xFF ? 'ui8_t' : (@ENTS < 0xFFFF ? 'ui16_t' : 'ui32_t'));
  538    `$CTOOL_EXE $t$argv2 >> $ENV{OUT}`
  539 }
  540 
  541 {package main; main_fun()}
  542 
  543 # s-it-mode