summaryrefslogtreecommitdiff
path: root/contrib/arm-neon/linux.c
blob: abae9e33bf68d78ae37cec2738d84308c12a0f52 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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
113
114
115
116
117
118
119
120
121
122
123
124
125
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
155
156
157
158
159
160
161
/* contrib/arm-neon/linux.c
 *
 * Copyright (c) 2014 Glenn Randers-Pehrson
 * Written by John Bowler, 2014.
 * Last changed in libpng 1.6.16 [December 22, 2014]
 *
 * 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.
 *
 * 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.
 */
#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.
       */
      static const char ch_feature[] = { 70, 69, 65, 84, 85, 82, 69, 83 };
      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;
               /* FALL THROUGH */

            case Feature:
               /* Match 'FEATURE', ASCII case insensitive. */
               if ((ch & ~0x20) == ch_feature[counter])
               {
                  if (++counter == (sizeof ch_feature))
                     state = Colon;
                  break;
               }
               
               /* did not match 'feature' */
               state = SkipLine;
               /* FALL THROUGH */

            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;
               /* FALL THROUGH */

            case Neon:
               /* Look for 'neon' tag */
               if ((ch & ~0x20) == ch_neon[counter])
               {
                  if (++counter == (sizeof ch_neon))
                     state = HaveNeon;
                  break;
               }

               state = SkipTag;
               /* FALL THROUGH */

            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)");
         }
      }
   }

#ifdef PNG_WARNINGS_SUPPORTED
   else
      png_warning(png_ptr, "/proc/cpuinfo open failed");
#endif

   return 0;
}