/* make_strings Copyright (C) 2002 Free Software Foundation, Inc. Written by: Alexander Malmberg Created: 2002 This file is part of the GNUstep Project This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program; see the file COPYINGv3. If not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "make_strings.h" #include "StringsFile.h" #include "SourceEntry.h" #include "StringsEntry.h" int verbose,aggressive_import,aggressive_match,aggressive_remove; typedef struct { const char *func_name; int num_args; int key_index,comment_index,table_index; } loc_func_t; /* List of functions we should look for (easy to extend). */ static loc_func_t loc_funcs[]= { {"_" , 1, 0,-1,-1}, {"NSLocalizedString" , 2, 0, 1,-1}, {"NSLocalizedStringFromTable" , 3, 0, 2, 1}, {"NSLocalizedStringFromTableInBundle" , 4, 0, 3, 1}, {"__" , 1, 0,-1,-1}, {"NSLocalizedStaticString" , 2, 0, 1,-1}, {}, }; #define MAX_ARGS 4 static int isname1(unsigned char ch) { if (ch=='_' || (ch>='a' && ch<='z') || (ch>='A' && ch<='Z')) return 1; return 0; } static int isname(unsigned char ch) { if (isname1(ch)) return 1; if (ch>='0' && ch<='9') return 1; return 0; } /* This function attempts to parse the specified file and adds any calls to tables. To avoid excessive complexity and to easily handle comments and strings everywhere, it's written as a state machine. Things that can fool it: - Stupid use of pre-processor stuff, like '#define foo bar('. Solution: Don't do that. - Nested localization calls, like: 'NSLocalizedString(@"foo",NSLocalizedString(@"bar",@"zot"))'. Solution: don't do that (with the current functions, there should never be any reason to). */ #define add_arg_ch(ch)\ {\ if (arg_len[num_args]+1>=arg_size[num_args])\ {\ arg_size[num_args]+=512;\ args[num_args]=realloc(args[num_args],arg_size[num_args]);\ if (!args[num_args])\ {\ NSLog(@"out of memory!\n");\ exit(1);\ }\ }\ args[num_args][arg_len[num_args]++]=ch;\ args[num_args][arg_len[num_args]]=0;\ } static int ParseFile(const char *filename,NSMutableDictionary *tables) { FILE *f; NSString *filenamestr; /* 0: normal parsing 1: in '//' comment 2: in '/ *' comment 3: in string 5: parsing potentially interesting name 6: parsing uninteresting name 7: got name, wait for '(' 8: parsing arguments */ int state,old_state,skip; int ch,nch; int name=-1,nindex=0; int cur_line; unsigned char *args[MAX_ARGS]; int arg_size[MAX_ARGS],arg_len[MAX_ARGS]; int arg_ok[MAX_ARGS]; int num_args; int i; int depth=0; filenamestr = [NSString stringWithCString: filename encoding: [NSString defaultCStringEncoding]]; if (verbose) printf("Parsing '%s'.\n", filename); f=fopen(filename,"rt"); if (!f) { NSLog(@"Unable to open '%@': %m\n",filenamestr); return 1; } old_state=state=0; skip=0; cur_line=1; num_args=-1; for (i=0;i32) state=0; continue; } if (state==8) { if (depth) { if (ch==')' || ch==']' || ch=='}') depth--; continue; } if (ch=='(' || ch=='[' || ch=='{') { arg_ok[num_args]=0; depth++; continue; } if (ch==')') { num_args++; /* { printf("got call to '%s', %i args\n",loc_funcs[name].func_name,num_args); for (i=0;ikey_index] && (lf->comment_index==-1 || arg_ok[lf->comment_index]) && (lf->table_index==-1 || arg_ok[lf->table_index])) { SourceEntry *e; NSString *key,*comment,*table; /* TODO: let user specify source file encoding */ key=[NSString stringWithCString: (char*)args[lf->key_index]]; if (lf->comment_index==-1 || !arg_len[lf->comment_index]) comment=nil; else comment=[NSString stringWithCString: (char*)args[lf->comment_index]]; if (lf->table_index==-1) table=@"Localizable"; /* TODO: customizable? */ else table=[NSString stringWithCString: (char*)args[lf->table_index]]; e=[[SourceEntry alloc] initWithKey: key comment: comment file: filenamestr line: cur_line]; [tables addEntry: e toTable: table]; [e release]; } else { NSLog(@"unable to parse call to '%s' at %s:%i\n",lf->func_name,filename,cur_line); } } num_args=-1; state=0; continue; } if (ch==',') { num_args++; if (num_args==MAX_ARGS) state=0; continue; } if (ch>32 && ch!='@') arg_ok[num_args]=0; continue; } } for (i=0;i= 0; k--) { NSString *language = [languages objectAtIndex: k]; if ([language isEqualToString: @""]) { [languages removeObjectAtIndex: k]; } } } if (![languages count]) { NSLog (@"No languages specified!\n"); return 1; } if (argc == 1) { NSLog (@"No files specified!\n"); return 1; } source_entries = [[NSMutableDictionary alloc] init]; error = 0; { int i; for (i = 1; i < argc; i++) error += ParseFile (argv[i], source_entries); } if (!error) { int i, c = [languages count]; for (i = 0; i < c; i++) { HandleLanguage ([languages objectAtIndex: i], source_entries); } } #if GS_WITH_GC == 0 DESTROY(arp); #endif if (error) return 1; else return 0; }