Home | History | Annotate | Download | only in arm-neon
      1 /* contrib/arm-neon/linux.c
      2  *
      3  * Copyright (c) 2014 Glenn Randers-Pehrson
      4  * Written by John Bowler, 2014.
      5  * Last changed in libpng 1.6.16 [December 22, 2014]
      6  *
      7  * This code is released under the libpng license.
      8  * For conditions of distribution and use, see the disclaimer
      9  * and license in png.h
     10  *
     11  * SEE contrib/arm-neon/README before reporting bugs
     12  *
     13  * STATUS: SUPPORTED
     14  * BUG REPORTS: png-mng-implement (at) sourceforge.net
     15  *
     16  * png_have_neon implemented for Linux by reading the widely available
     17  * pseudo-file /proc/cpuinfo.
     18  *
     19  * This code is strict ANSI-C and is probably moderately portable; it does
     20  * however use <stdio.h> and it assumes that /proc/cpuinfo is never localized.
     21  */
     22 #include <stdio.h>
     23 
     24 static int
     25 png_have_neon(png_structp png_ptr)
     26 {
     27    FILE *f = fopen("/proc/cpuinfo", "rb");
     28 
     29    if (f != NULL)
     30    {
     31       /* This is a simple state machine which reads the input byte-by-byte until
     32        * it gets a match on the 'neon' feature or reaches the end of the stream.
     33        */
     34       static const char ch_feature[] = { 70, 69, 65, 84, 85, 82, 69, 83 };
     35       static const char ch_neon[] = { 78, 69, 79, 78 };
     36 
     37       enum
     38       {
     39          StartLine, Feature, Colon, StartTag, Neon, HaveNeon, SkipTag, SkipLine
     40       }  state;
     41       int counter;
     42 
     43       for (state=StartLine, counter=0;;)
     44       {
     45          int ch = fgetc(f);
     46 
     47          if (ch == EOF)
     48          {
     49             /* EOF means error or end-of-file, return false; neon at EOF is
     50              * assumed to be a mistake.
     51              */
     52             fclose(f);
     53             return 0;
     54          }
     55 
     56          switch (state)
     57          {
     58             case StartLine:
     59                /* Match spaces at the start of line */
     60                if (ch <= 32) /* skip control characters and space */
     61                   break;
     62 
     63                counter=0;
     64                state = Feature;
     65                /* FALL THROUGH */
     66 
     67             case Feature:
     68                /* Match 'FEATURE', ASCII case insensitive. */
     69                if ((ch & ~0x20) == ch_feature[counter])
     70                {
     71                   if (++counter == (sizeof ch_feature))
     72                      state = Colon;
     73                   break;
     74                }
     75 
     76                /* did not match 'feature' */
     77                state = SkipLine;
     78                /* FALL THROUGH */
     79 
     80             case SkipLine:
     81             skipLine:
     82                /* Skip everything until we see linefeed or carriage return */
     83                if (ch != 10 && ch != 13)
     84                   break;
     85 
     86                state = StartLine;
     87                break;
     88 
     89             case Colon:
     90                /* Match any number of space or tab followed by ':' */
     91                if (ch == 32 || ch == 9)
     92                   break;
     93 
     94                if (ch == 58) /* i.e. ':' */
     95                {
     96                   state = StartTag;
     97                   break;
     98                }
     99 
    100                /* Either a bad line format or a 'feature' prefix followed by
    101                 * other characters.
    102                 */
    103                state = SkipLine;
    104                goto skipLine;
    105 
    106             case StartTag:
    107                /* Skip space characters before a tag */
    108                if (ch == 32 || ch == 9)
    109                   break;
    110 
    111                state = Neon;
    112                counter = 0;
    113                /* FALL THROUGH */
    114 
    115             case Neon:
    116                /* Look for 'neon' tag */
    117                if ((ch & ~0x20) == ch_neon[counter])
    118                {
    119                   if (++counter == (sizeof ch_neon))
    120                      state = HaveNeon;
    121                   break;
    122                }
    123 
    124                state = SkipTag;
    125                /* FALL THROUGH */
    126 
    127             case SkipTag:
    128                /* Skip non-space characters */
    129                if (ch == 10 || ch == 13)
    130                   state = StartLine;
    131 
    132                else if (ch == 32 || ch == 9)
    133                   state = StartTag;
    134                break;
    135 
    136             case HaveNeon:
    137                /* Have seen a 'neon' prefix, but there must be a space or new
    138                 * line character to terminate it.
    139                 */
    140                if (ch == 10 || ch == 13 || ch == 32 || ch == 9)
    141                {
    142                   fclose(f);
    143                   return 1;
    144                }
    145 
    146                state = SkipTag;
    147                break;
    148 
    149             default:
    150                png_error(png_ptr, "png_have_neon: internal error (bug)");
    151          }
    152       }
    153    }
    154 
    155 #ifdef PNG_WARNINGS_SUPPORTED
    156    else
    157       png_warning(png_ptr, "/proc/cpuinfo open failed");
    158 #endif
    159 
    160    return 0;
    161 }
    162