1 | /* zpblind.c
2 | - Diplomacy Blind Parsing - main program - Version 0.8
3 | */
4 |
5 | /*
6 | * Coded by H. Moreira (henrique@moreira.dnsalias.net) in Apr 2003
7 | * included in njudge package.
8 | */
9 |
10 | #define yZPBLIND_VERSION "v0.8"
11 |
12 | #include <stdio.h>
13 | #include <stdlib.h>
14 | #include <string.h>
15 | #include "zparseb.h"
16 |
17 | #ifdef yLINUX
18 | #include <signal.h>
19 | #endif
20 |
21 | /* --------------------------------------------------------
22 | Signal - faultHandler
23 | */
24 | static char myTempFilename[1000];
25 |
26 | void faultHandler (int thisSignalId)
27 | {
28 | fprintf(stderr,"Abnormal program exit! (%d)\n\
29 | Removing file [%s]\n",thisSignalId,myTempFilename);
30 | if ( myTempFilename[0]!=0 ) {
31 | remove(myTempFilename);
32 | }
33 | exit(1);
34 | }
35 |
36 | /* --------------------------------------------------------
37 | Debug stuff
38 | */
39 |
40 | /* --------------------------------------------------------
41 | Main function
42 | */
43 | int go (IoOptions* ioPtr)
44 | {
45 | unsigned iter, pos;
46 | int error, len;
47 | FILE* fIn = ioPtr->fIn;
48 | FILE* fOut = ioPtr->fOut;
49 | FILE* fTemp = ioPtr->fTemp;
50 | char* str;
51 | char aChr;
52 | t_uchar buf[2048];
53 | unsigned nEmptyLines = 0;
54 |
55 | static ArrayResStr lStr;
56 |
57 | ASSERTION(fIn!=nil,"fIn!=nil");
58 |
59 | ASSERTION(lStr.dblColonIdxFirst==0,"lStr.dblColonIdxFirst==0");
60 | ASSERTION(lStr.dblColonIdxSecond==0,"lStr.dblColonIdxSecond==0");
61 | ASSERTION(lStr.theLastIdx==0,"lStr.theLastIdx==0");
62 |
63 | ASSERTION(ioPtr->powerName!=nil && ioPtr->powerName[0]!=0,"optIO.powerName!=nil");
64 | ASSERTION(ioPtr->powerAdj!=nil && ioPtr->powerAdj[0]!=0,"optIO.powerAdj!=nil");
65 |
66 | #ifdef yLINUX
67 | // Using temporary file xxx
68 | if ( fTemp==nil ) {
69 | ASSERTION(ioPtr->tempFilename==nil,"ioPtr->tempFilename==nil");
70 |
71 | sprintf(myTempFilename,"%s/%s","/tmp","zbXXXXXX");
72 | ioPtr->tempFilename = mktemp( myTempFilename );
73 |
74 | #ifdef DEBUG_VERBOSE
75 | printf("CREATED TEMPORARY FILE: [%s|%s]\n",ioPtr->tempFilename,myTempFilename);
76 | #endif
77 |
78 | ASSERTION(ioPtr->tempFilename!=nil && ioPtr->tempFilename[0]!=0,"tempFilename not alloc'd");
79 | fTemp = ioPtr->fTemp = fopen(ioPtr->tempFilename,"wt");
80 | if ( fTemp==nil ) {
81 | fprintf(stderr,"Cannot write temporary file %s\n",ioPtr->tempFilename);
82 | return 1;
83 | }
84 | }
85 | #else
86 | #error yLINUX must be defined!
87 | #endif
88 |
89 | // The first task is pre-parsing:
90 | // picking only ':: Judge:' until 'The next phase of'
91 | ;
92 | // Read input
93 | while ( fgets(buf,2048,fIn)!=nil ) {
94 | str = buf;
95 | len = strlen(str);
96 | if ( len==0 )
97 | continue;
98 | ASSERTION(str[len-1]=='\n',"str[len-1]=='\\n'");
99 | str[--len] = 0;
100 | if ( len>0 && str[--len]=='\r' ) str[len] = 0;
101 | len--;
102 | // Trim right -- This is VERY IMPORTANT!
103 | while ( len>=0 && (str[len]==' ' || str[len]=='\t') )
104 | str[len--] = 0;
105 | // Write temporary file
106 | fprintf(fTemp,"%s\n",str);
107 | ASSERTION(len<2048,"strlen(buf)<2048");
108 | lStr.size++;
109 | pos = FindString(":: ",str);
110 | if ( pos==1 ) {
111 | if ( lStr.dblColonIdxFirst==0 ) {
112 | lStr.dblColonIdxFirst = lStr.size;
113 | }
114 | else {
115 | lStr.dblColonIdxSecond = lStr.size;
116 | }
117 | }
118 | else {
119 | pos = FindString("The next phase of ",str);
120 | if ( pos==1 ) {
121 | lStr.theLastIdx = lStr.size;
122 | }
123 | }
124 | }
125 |
126 | if ( lStr.theLastIdx==0 )
127 | lStr.theLastIdx = lStr.size;
128 |
129 | fclose(fTemp);
130 |
131 | ASSERTION(ioPtr->tempFilename!=nil && ioPtr->tempFilename[0]!=0,"tempFilename!=nil");
132 | fTemp = ioPtr->fTemp = fopen(ioPtr->tempFilename,"rt");
133 | ASSERTION(fTemp!=nil,"fTemp!=nil");
134 |
135 | // Check first read
136 | if ( lStr.dblColonIdxFirst==0 ) {
137 | fprintf(stderr,"Cannot find '::' string.\n");
138 | return 1;
139 | }
140 | ASSERTION(lStr.dblColonIdxFirst>0 && lStr.dblColonIdxSecond>0,"lStr.dblColonIdxFirst>0 && lStr.dblColonIdxSecond>0");
141 | ASSERTION(lStr.dblColonIdxFirst+1==lStr.dblColonIdxSecond,"lStr.dblColonIdxFirst+1==lStr.dblColonIdxSecond");
142 |
143 | // Build the array lStr
144 | lStr.s = (t_uchar**)calloc( lStr.size+1, sizeof(t_uchar*) );
145 | ASSERTION(lStr.s!=nil,"lStr.s!=nil");
146 | lStr.s[0] = nil;
147 | for (iter=1; iter<=lStr.size; iter++) {
148 | fgets(buf,2048,fTemp);
149 | len = strlen(buf);
150 | ASSERTION(len>0,"len>0");
151 | str = buf;
152 | ASSERTION(str[len-1]=='\n',"str[len-1]=='\\n' <- error reading temporary file!");
153 | str[len-1] = 0;
154 | lStr.s[iter] = strdup(str);
155 | }
156 | fclose(fTemp);
157 | fTemp = ioPtr->fTemp = nil;
158 |
159 | if ( ioPtr->doDeleteTempFile )
160 | remove( ioPtr->tempFilename );
161 |
162 | #ifdef DEBUG
163 | fprintf(fDebug,"%u lines\t:: at %u,%u (last=%u)\n%s\n%s<==\n",
164 | lStr.size,
165 | lStr.dblColonIdxFirst,
166 | lStr.dblColonIdxSecond,
167 | lStr.theLastIdx,
168 | lStr.s[lStr.dblColonIdxFirst],
169 | lStr.s[lStr.dblColonIdxSecond]);
170 | if ( lStr.theLastIdx<lStr.size )
171 | fprintf(fDebug,"%s<==\n",lStr.s[lStr.theLastIdx]);
172 | else
173 | fprintf(fDebug,"No next phase [%s]<==\n",lStr.s[lStr.theLastIdx]);
174 | #endif
175 |
176 | error = ParseInput(&lStr,ioPtr);
177 |
178 | #ifdef DEBUG_VERBOSE
179 | printf("ParseInput() returned %d for %u lines\n",error,lStr.size);
180 | #endif
181 |
182 | // Blinded/hidden by ? and @ will not go to the output file
183 | for (iter=1; error==0 && iter<=lStr.size; iter++) {
184 | bool isEmpty;
185 |
186 | str = lStr.s[iter];
187 | aChr = str[0];
188 | isEmpty = aChr==0;
189 |
190 | switch ( aChr ) {
191 | case '?':
192 | case '@':
193 | break;
194 | default:
195 | // Avoid printing out two consecutive empty lines
196 | if ( isEmpty ) {
197 | nEmptyLines++;
198 | if ( nEmptyLines>=2 ) {
199 | #ifdef DEBUG_OUTPUT
200 | printf("[%u]:Avoid empty line. (%u)\n",iter,nEmptyLines);
201 | #endif
202 | continue;
203 | }
204 | }
205 | else {
206 | nEmptyLines = 0;
207 | }
208 | fprintf(fOut,"%s\n",str);
209 | break;
210 | }
211 | }
212 |
213 | ArrayDelete(&lStr);
214 |
215 | return error;
216 | }
217 |
218 | /* --------------------------------------------------------
219 | Auxiliary functions
220 | */
221 | int OpenFileInput (IoOptions* ioPtr, char* str)
222 | {
223 | ioPtr->doUseFileIn = true;
224 | ASSERTION(ioPtr!=0 && str!=0 && str[0]!=0,"ioPtr!=0 && str!=0 && str[0]!=0");
225 | ioPtr->fIn = fopen(str,"rt");
226 | if ( ioPtr->fIn==nil ) {
227 | fprintf(stderr,"Cannot open file %s\n",str);
228 | return 1;
229 | }
230 | #ifdef DEBUG
231 | fprintf(fDebug,"Using input file %s\n",str);
232 | #endif
233 | ioPtr->inputFilename = str;
234 | return 0;
235 | }
236 |
237 | /* --------------------------------------------------------
238 | Debug-only functions
239 | */
240 | #ifdef DEBUG_AUTOCOUNTRY
241 | const char* tblCountryNonAdjective[9]={
242 | nil,
243 | "Austria",
244 | "England",
245 | "France",
246 | "Germany",
247 | "Italy",
248 | "Russia",
249 | "Turkey",
250 | nil
251 | };
252 |
253 | const char* tblCountryAdjective[9]={
254 | nil,
255 | "Austrian",
256 | "English",
257 | "French",
258 | "German",
259 | "Italian",
260 | "Russian",
261 | "Turkish",
262 | nil
263 | };
264 |
265 | const char* GetCountryAdjectiveFromCountry (char* aCountryStr)
266 | {
267 | const char* tblCountry;
268 | unsigned short iter;
269 |
270 | for (iter=1;
271 | (tblCountry = tblCountryNonAdjective[iter])!=nil;
272 | iter++) {
273 | if ( strcmp(aCountryStr,tblCountry)==0 )
274 | return tblCountryAdjective[iter];
275 | }
276 | return nil;
277 | }
278 | #endif //DEBUG_AUTOCOUNTRY
279 |
280 | /* --------------------------------------------------------
281 | Main program
282 | */
283 | int main (int argc, char* argv[], char** envp)
284 | {
285 | int i, n = argc-1;
286 | int error = 0;
287 |
288 | unsigned argCount;
289 | char* str;
290 |
291 | static IoOptions optIO;
292 |
293 | bool hasDash, hasEqual;
294 | char chr;
295 |
296 | ASSERTION(argv!=nil,"argv!=nil");
297 | ASSERTION(envp!=nil,"envp!=nil");
298 | ASSERTION(n>=0,"n>=0");
299 |
300 | ASSERTION(optIO.fIn==nil,"optIO.fIn==nil");
301 | ASSERTION(optIO.fOut==nil,"optIO.fOut==nil");
302 |
303 | optIO.fIn = stdin;
304 | optIO.fOut = stdout;
305 | optIO.doPreParsing = true;
306 | optIO.doDeleteTempFile = true;
307 | // Variant specifics
308 | optIO.doPreParsing = false;
309 |
310 | #ifdef yLINUX
311 | signal(SIGINT, faultHandler);
312 | signal(SIGQUIT, faultHandler);
313 | signal(SIGUSR1, faultHandler);
314 | signal(SIGALRM, faultHandler);
315 | signal(SIGSEGV, faultHandler);
316 | /*signal(SIGCLD, SIG_IGN);*/
317 | #endif
318 |
319 | #ifdef DEBUG_AUTOCOUNTRY
320 | n++;
321 | #endif
322 |
323 | // Parse args
324 | if ( n<2 ) {
325 | printf("zpblind - Parse input and generate output of 'blind' variant - %s\n\
326 | \n\
327 | Usage:\n\
328 | zpblind [options] <power-noun> <power-adjective> [inputFile]\n\
329 | \n\
330 | where\n\
331 | <power-noun> is power name\n\
332 | <power-adjective> is power's possesive adjective.\n\
333 | \n\
334 | Options are:\n\
335 | -i=InputFile Choose input file\n\
336 | -o=OutputFile Choose output file\n\
337 | -t=TemporaryFile Choose specific temporary file (not needed)\n\
338 | -v=HideAll Variant is hide all centres\n\
339 | \n",yZPBLIND_VERSION);
340 |
341 | #ifdef yLINUX
342 | printf("yLINUX defined.\n");
343 | #else
344 | printf("non-yLINUX defined.\n");
345 | #endif
346 | #ifdef DEBUG
347 | printf("DEBUG define.\n");
348 | #endif
349 | return 0;
350 | }
351 |
352 | for (i=1, argCount=0; i<=n; i++) {
353 | str = argv[i];
354 | #ifdef DEBUG_AUTOCOUNTRY
355 | if ( str==nil )
356 | str = (char*)GetCountryAdjectiveFromCountry( optIO.powerName );
357 | #endif
358 | ASSERTION(str!=nil,"str!=nil");
359 | hasDash = str[0]=='-';
360 | hasEqual = hasDash && str[2]=='=';
361 | chr = hasDash ? str[1] : '\0';
362 | if ( hasEqual ) {
363 | str += 3;
364 | ASSERTION(str!=nil && str[0]!=0,"str!=nil && str[0]!=0");
365 | }
366 | if ( hasEqual ) {
367 | ASSERTION(str!=nil && str[0]!=0,"str!=nil && str[0]!=0");
368 | switch ( chr ) {
369 | case 'i':
370 | if ( OpenFileInput(&optIO,str)!=0 )
371 | return 1;
372 | break;
373 | case 'v':
374 | if ( strcmp(str,"HideAll")==0 || strcmp(str,"hide")==0 ) {
375 | optIO.varHideAllCentre = true;
376 | }
377 | else {
378 | fprintf(stderr,"Invalid variant specified with -v: %s\n",str);
379 | }
380 | break;
381 | case 'o':
382 | optIO.doUseFileOut = true;
383 | //
384 | optIO.fOut = fopen(str,"wt");
385 | if ( optIO.fOut==nil ) {
386 | fprintf(stderr,"Cannot rewrite file %s\n",str);
387 | return 1;
388 | }
389 | fclose( optIO.fOut );
390 | #ifdef DEBUG
391 | fprintf(fDebug,"Using output file %s\n",str);
392 | #endif
393 | optIO.outputFilename = str;
394 | remove( str );
395 | optIO.fOut = fopen(str,"wt");
396 | break;
397 | case 't':
398 | optIO.fTemp = fopen(str,"wt");
399 | if ( optIO.fTemp==nil ) {
400 | fprintf(stderr,"Cannot use/write temporary file %s\n",str);
401 | return 1;
402 | }
403 | fclose( optIO.fTemp );
404 | optIO.tempFilename = str;
405 | remove( str );
406 | optIO.fTemp = fopen(optIO.tempFilename,"wt");
407 | ASSERTION(optIO.fTemp!=nil,"optIO.fTemp!=nil");
408 | optIO.doDeleteTempFile = false;
409 | break;
410 | default:
411 | fprintf(stderr,"Bad option '%c'\n",chr);
412 | break;
413 | }
414 | }
415 | else {
416 | argCount++;
417 | switch ( argCount ) {
418 | case 1:
419 | optIO.powerName = str;
420 | break;
421 | case 2:
422 | optIO.powerAdj = str;
423 | break;
424 | case 3:
425 | if ( optIO.doUseFileIn ) {
426 | fprintf(stderr,"Too many arguments.\n(Input file already specified!)\n");
427 | return 1;
428 | }
429 | if ( OpenFileInput(&optIO,str)!=0 ) {
430 | return 1;
431 | }
432 | break;
433 | default:
434 | fprintf(stderr,"Too many arguments.\n");
435 | return 1;
436 | }
437 | }
438 | }
439 |
440 | error = go(&optIO);
441 |
442 | /* Close all files
443 | */
444 | if ( optIO.doUseFileIn ) {
445 | ASSERTION(optIO.fIn!=stdin,"optIO.fIn!=stdin");
446 | fclose(optIO.fIn);
447 | }
448 | if ( optIO.doUseFileOut && optIO.fOut!=nil && optIO.fOut!=stdout ) {
449 | fclose(optIO.fOut);
450 | }
451 | if ( optIO.fTemp ) {
452 | #ifdef DEBUG_VERBOSE
453 | fprintf(fDebug,"Closing temporary file %s\n",optIO.tempFilename);
454 | #endif
455 | fclose(optIO.fTemp);
456 | }
457 |
458 | return error;
459 | }
460 |