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  |