1 /**
2 * Copyright 1981-2016 ECMWF.
3 *
4 * This software is licensed under the terms of the Apache Licence
5 * Version 2.0 which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6 *
7 * In applying this licence, ECMWF does not waive the privileges and immunities
8 * granted to it by virtue of its status as an intergovernmental organisation
9 * nor does it submit to any jurisdiction.
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <ctype.h>
16
17 #include "bitmap.h"
18 #include "common/fortint.h"
19
20 #define BUFFLEN 50000
21 #define NOTSET -1
22
MAKEMAP(char * filename,fortint * n,fortint * m,char ** mybitmap,fortint filenameLength)23 fortint MAKEMAP(
24 char * filename,
25 fortint *n,
26 fortint *m,
27 char ** mybitmap,
28 fortint filenameLength) {
29 /*
30 // Builds a bitmap in memory from the definition in a file.
31 //
32 // Called from FORTRAN:
33 //
34 // STATUS = MAKEMAP(FILENAME,N,M,BITMAP)
35 //
36 // where:
37 //
38 // FILENAME is a FORTRAN CHARACTER variable containing the file name.
39 //
40 // Returns:
41 //
42 // N is the number of rows in the bitmap.
43 // M is the number of columns in the bitmap.
44 // BITMAP is the binary map expanded in memory.
45 //
46 // STATUS = 0 if the processing is successful.
47 //
48 */
49 FILE * in;
50 char * bitmap;
51 char buffer[BUFFLEN];
52 int rowCount, columnCount;
53 int start, finish, defaultValue, size, i;
54 int firstColumn, lastColumn, rowNumber, columnNumber;
55 char defaultValueSetting, delimiter = '\1', previousDelimiter = '\0';
56 static int oldRow = NOTSET;
57 char * fileName, *p;
58
59 /*
60 // Open and read the file containing the bitmap definition.
61 */
62 fileName = (char *) malloc(filenameLength+1);
63 if( fileName == NULL ) {
64 perror("MAKEMAP: malloc error (fileName)");
65 exit(1);
66 }
67 strncpy(fileName,filename,filenameLength);
68 fileName[filenameLength] = '\0';
69 p = fileName + filenameLength - 1;
70 while ( *p == ' ' ) *(p--) = '\0';
71
72 in = fopen(fileName,"r");
73 if( in == NULL ) {
74 printf("MAKEMAP: Problem opening bitmap file: %s\n",fileName);
75 perror("MAKEMAP: File open error");
76 return 1;
77 }
78 free(fileName);
79
80 fread(buffer, 1, BUFFLEN, in);
81 if( ! feof(in) ) {
82 printf("MAKEMAP: Internal buffer size too small = %d bytes\n", BUFFLEN);
83 return 2;
84 }
85
86 /*
87 // Check for "SPEC,SIZE="
88 */
89 if( strncmp(buffer,"SPEC",4) != 0 ) {
90 printf("MAKEMAP: Specification does not start with SPEC\n");
91 return 3;
92 }
93
94 start = 5;
95
96 if( strncmp((buffer+start),"SIZE=",5) != 0 ) {
97 printf("MAKEMAP: In specification, SPEC not followed by SIZE=\n");
98 return 4;
99 }
100
101 /*
102 // Get count of rows and columns
103 */
104 start = 1 + findCharacter(buffer,BUFFLEN,start,'=');
105 if( start == 0 ) {
106 printf("MAKEMAP: '=' missing in SIZE specification\n");
107 return 5;
108 }
109
110 finish = findCharacter(buffer,BUFFLEN,start,':');
111 if( finish == 0 ) {
112 printf("MAKEMAP: ':' missing in SIZE specification\n");
113 return 6;
114 }
115 rowCount = findNumber(buffer,BUFFLEN,start,&finish,':');
116 *n = rowCount;
117
118 start = 1 + finish;
119 finish = findCharacter(buffer,BUFFLEN,start,',');
120 if( finish == 0 ) {
121 printf("MAKEMAP: ',' missing after SIZE specification\n");
122 return 7;
123 }
124 columnCount = findNumber(buffer,BUFFLEN,start,&finish,',');
125 *m = columnCount;
126
127 /*
128 // Find default VALUE (OFF/ON)
129 */
130 start = 1 + finish;
131 if( strncmp((buffer+start),"VALUES=",7) != 0 ) {
132 printf("MAKEMAP: In specification, SIZE not followed by VALUES=\n");
133 return 8;
134 }
135 start += 7;
136 if( strncmp((buffer+start),"ON",2) == 0 ) {
137 defaultValueSetting = 0xff;
138 defaultValue = 1;
139 }
140 else {
141 defaultValueSetting = 0;
142 defaultValue = 0;
143 }
144
145 /*
146 // Claim memory for bitmap and fill it with default setting
147 */
148 size = (rowCount*columnCount+7)/8;
149 bitmap = (char *) malloc(size);
150 if( bitmap == NULL ) {
151 perror("MAKEMAP: malloc error (bitmap)");
152 exit(1);
153 }
154 *mybitmap = bitmap;
155 for( i = 0; i < size; i++ )
156 bitmap[i] = defaultValueSetting;
157
158 /*
159 // Fill in the bits
160 */
161 start = findCharacter(buffer,BUFFLEN,start,'P');
162 if( start == 0 ) {
163 printf("MAKEMAP: '=' POINTS missing in specification\n");
164 return 9;
165 }
166 if( strncmp((buffer+start),"POINTS=",7) != 0 ) {
167 printf("MAKEMAP: In specification, VALUES= not followed by POINTS=\n");
168 return 10;
169 }
170
171 finish = start + 6;
172
173 /*
174 // Work through POINTS specification
175 */
176
177 do {
178 previousDelimiter = delimiter;
179 start = 1 + finish;
180 delimiter = findDelimiter(buffer,BUFFLEN,start);
181 if( delimiter == 0 ) {
182 fclose(in);
183 return 0;
184 }
185
186 switch( delimiter ) {
187
188 case '-': /* eg 03-08 */
189 firstColumn = findNumber(buffer,BUFFLEN,start,&finish,delimiter);
190 start = 1 + finish;
191 delimiter = findDelimiter(buffer,BUFFLEN,start);
192 lastColumn = findNumber(buffer,BUFFLEN,start,&finish,delimiter);
193 for(columnNumber=firstColumn; columnNumber<=lastColumn; columnNumber++)
194 setBit(bitmap,defaultValue,columnCount,rowNumber,columnNumber);
195 break;
196
197 case '/': /* eg 03/04 */
198 columnNumber = findNumber(buffer,BUFFLEN,start,&finish,delimiter);
199 setBit(bitmap,defaultValue,columnCount,rowNumber,columnNumber);
200 break;
201
202 case '\n': /* eg 03\n */
203 if( previousDelimiter == ',' ) {
204 finish++;
205 break;
206 }
207 if( previousDelimiter == '\n' ) {
208 if( (oldRow < rowCount) && (oldRow != NOTSET) ) {
209 int loop;
210
211 for( loop = (oldRow+1); loop <= rowCount; loop++ )
212 copyRow(bitmap, columnCount, oldRow, loop, defaultValue);
213 }
214 oldRow = rowCount;
215 fclose(in);
216 return 0;
217 }
218
219 case ',': /* eg 03, */
220 columnNumber = findNumber(buffer,BUFFLEN,start,&finish,delimiter);
221 if( columnNumber != 0 )
222 setBit(bitmap,defaultValue,columnCount,rowNumber,columnNumber);
223 break;
224
225 case ':': /* eg 01: */
226 rowNumber = findNumber(buffer,BUFFLEN,start,&finish,delimiter);
227 if( (oldRow < rowNumber) && (oldRow != NOTSET) ) {
228 int loop;
229
230 for( loop = (oldRow+1); loop < rowNumber; loop++ )
231 copyRow(bitmap, columnCount, oldRow, loop, defaultValue);
232 }
233 oldRow = rowNumber;
234 break;
235
236 default:
237 break;
238
239 }
240
241 } while( 1 );
242
243 }
244
findNumber(char * buffer,int length,int start,int * finish,char delimiter)245 int findNumber(char * buffer,int length,int start,int * finish,char delimiter) {
246 char number[20];
247 int end;
248
249 end = findCharacter(buffer,length,start,delimiter);
250 *finish = end;
251 strncpy(number,(buffer+start),(end-start));
252 number[(end-start)] = '\0';
253 return atoi(number);
254
255 }
256
findDelimiter(char * buffer,int length,int point)257 char findDelimiter(char * buffer, int length, int point) {
258 int i, j;
259 char delimiter[5] = {'-','/',',','\n',':'};
260
261 for( i = point; i < length; i++ )
262 for( j = 0; j < 5; j++ )
263 if( buffer[i] == delimiter[j] ) return buffer[i];
264
265 return (char) 0;
266 }
267
findCharacter(char * buffer,int length,int point,char character)268 int findCharacter(char * buffer, int length, int point, char character) {
269 int i;
270
271 for( i = point; i < length; i++ )
272 if( buffer[i] == character ) return i;
273
274 return 0;
275 }
276
setBit(char * buffer,int value,int columnCount,int row,int column)277 void setBit(char * buffer, int value, int columnCount, int row, int column) {
278 int bitNumber, byte, bit;
279 char mask[8] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
280
281 bitNumber = (row - 1)*columnCount + (column - 1);
282 byte = bitNumber / 8;
283 bit = bitNumber % 8;
284
285 if( value == 1 )
286 buffer[byte] &= (char) ~mask[bit];
287 else
288 buffer[byte] |= (char) mask[bit];
289
290 return;
291 }
292
copyRow(char * buffer,int columnCount,int oldRow,int newRow,int value)293 void copyRow(char * buffer, int columnCount, int oldRow, int newRow, int value) {
294 int oldByte, oldBit, newByte, newBit, bitNumber;
295 char oldValue, newValue, mask;
296 int loop;
297
298 for( loop = 0; loop < columnCount; loop++ ) {
299 bitNumber = (oldRow - 1)*columnCount + loop;
300 oldByte = bitNumber / 8;
301 oldBit = bitNumber % 8;
302 oldValue = (char) ((buffer[oldByte] >> (7-oldBit)) & 0x01);
303
304 bitNumber = (newRow - 1)*columnCount + loop;
305 newByte = bitNumber / 8;
306 newBit = bitNumber % 8;
307
308 newValue = oldValue << (7-newBit);
309 if( value == 1 ) {
310 mask = 1 << (7-newBit);
311 buffer[newByte] &= (char) ~mask;
312 buffer[newByte] |= (char) newValue;
313 }
314 else
315 buffer[newByte] |= newValue;
316 }
317
318 }
319
320