/* 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 2 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 COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include "make_strings.h" #include "StringsFile.h" #include "SourceEntry.h" #include "StringsEntry.h" int verbose,aggressive_import,aggressive_match; 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). */ 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; static void add_arg_ch(int 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; } filenamestr=[NSString stringWithCString: filename]; if (verbose) printf("Parsing '%s'.\n", [filenamestr cString]); f=fopen(filename,"rt"); if (!f) { NSLog(@"Unable to open '%s': %m\n",filename); 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: args[lf->key_index]]; if (lf->comment_index==-1 || !arg_len[lf->comment_index]) comment=nil; else comment=[NSString stringWithCString: args[lf->comment_index]]; if (lf->table_index==-1) table=@"Localizable"; /* TODO: customizable? */ else table=[NSString stringWithCString: 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