linux.c 4.4 KB
Newer Older
1 2
/* contrib/arm-neon/linux.c
 *
3
 * Last changed in libpng 1.6.31 [July 27, 2017]
4 5
 * Copyright (c) 2014, 2017 Glenn Randers-Pehrson
 * Written by John Bowler, 2014, 2017.
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This code is released under the libpng license.
 * For conditions of distribution and use, see the disclaimer
 * and license in png.h
 *
 * SEE contrib/arm-neon/README before reporting bugs
 *
 * STATUS: SUPPORTED
 * BUG REPORTS: png-mng-implement@sourceforge.net
 *
 * png_have_neon implemented for Linux by reading the widely available
 * pseudo-file /proc/cpuinfo.
 *
19 20
 * This code is strict ANSI-C and is probably moderately portable; it does
 * however use <stdio.h> and it assumes that /proc/cpuinfo is never localized.
21 22 23 24 25 26 27 28 29 30 31 32 33
 */
#include <stdio.h>

static int
png_have_neon(png_structp png_ptr)
{
   FILE *f = fopen("/proc/cpuinfo", "rb");

   if (f != NULL)
   {
      /* This is a simple state machine which reads the input byte-by-byte until
       * it gets a match on the 'neon' feature or reaches the end of the stream.
       */
34
      static const char ch_feature[] = { 70, 69, 65, 84, 85, 82, 69, 83 };
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
      static const char ch_neon[] = { 78, 69, 79, 78 };

      enum
      {
         StartLine, Feature, Colon, StartTag, Neon, HaveNeon, SkipTag, SkipLine
      }  state;
      int counter;

      for (state=StartLine, counter=0;;)
      {
         int ch = fgetc(f);

         if (ch == EOF)
         {
            /* EOF means error or end-of-file, return false; neon at EOF is
             * assumed to be a mistake.
             */
            fclose(f);
            return 0;
         }

         switch (state)
         {
            case StartLine:
               /* Match spaces at the start of line */
               if (ch <= 32) /* skip control characters and space */
                  break;

               counter=0;
               state = Feature;
65
               /* FALLTHROUGH */
66 67 68

            case Feature:
               /* Match 'FEATURE', ASCII case insensitive. */
69
               if ((ch & ~0x20) == ch_feature[counter])
70 71 72 73 74
               {
                  if (++counter == (sizeof ch_feature))
                     state = Colon;
                  break;
               }
75

76 77
               /* did not match 'feature' */
               state = SkipLine;
78
               /* FALLTHROUGH */
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112

            case SkipLine:
            skipLine:
               /* Skip everything until we see linefeed or carriage return */
               if (ch != 10 && ch != 13)
                  break;

               state = StartLine;
               break;

            case Colon:
               /* Match any number of space or tab followed by ':' */
               if (ch == 32 || ch == 9)
                  break;

               if (ch == 58) /* i.e. ':' */
               {
                  state = StartTag;
                  break;
               }

               /* Either a bad line format or a 'feature' prefix followed by
                * other characters.
                */
               state = SkipLine;
               goto skipLine;

            case StartTag:
               /* Skip space characters before a tag */
               if (ch == 32 || ch == 9)
                  break;

               state = Neon;
               counter = 0;
113
               /* FALLTHROUGH */
114 115 116

            case Neon:
               /* Look for 'neon' tag */
117
               if ((ch & ~0x20) == ch_neon[counter])
118 119 120 121 122 123 124
               {
                  if (++counter == (sizeof ch_neon))
                     state = HaveNeon;
                  break;
               }

               state = SkipTag;
125
               /* FALLTHROUGH */
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154

            case SkipTag:
               /* Skip non-space characters */
               if (ch == 10 || ch == 13)
                  state = StartLine;

               else if (ch == 32 || ch == 9)
                  state = StartTag;
               break;

            case HaveNeon:
               /* Have seen a 'neon' prefix, but there must be a space or new
                * line character to terminate it.
                */
               if (ch == 10 || ch == 13 || ch == 32 || ch == 9)
               {
                  fclose(f);
                  return 1;
               }

               state = SkipTag;
               break;

            default:
               png_error(png_ptr, "png_have_neon: internal error (bug)");
         }
      }
   }

155
#ifdef PNG_WARNINGS_SUPPORTED
156 157
   else
      png_warning(png_ptr, "/proc/cpuinfo open failed");
158
#endif
159 160 161

   return 0;
}