|
1 #!perl |
|
2 # createsrc |
|
3 # |
|
4 # Copyright (c) 2009 - 2010 Accenture. All rights reserved. |
|
5 # This component and the accompanying materials are made available |
|
6 # under the terms of the "Eclipse Public License v1.0" |
|
7 # which accompanies this distribution, and is available |
|
8 # at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
9 # |
|
10 # Initial Contributors: |
|
11 # Accenture - Initial contribution |
|
12 # |
|
13 |
|
14 use strict; |
|
15 use Getopt::Long; |
|
16 use Cwd; |
|
17 use FindBin; |
|
18 |
|
19 # forward decls |
|
20 sub homeDir(); |
|
21 sub processCommandLine(); |
|
22 sub Usage(); |
|
23 sub make4CharId($); |
|
24 sub caseRename($$$); |
|
25 sub renameFileCopy($$); |
|
26 sub GetMacroValue($); |
|
27 sub PromptMacro($); |
|
28 sub CheckMacro($$); |
|
29 sub CheckUid($); |
|
30 sub CheckIdentifier($); |
|
31 sub listTemplates($); |
|
32 sub getTemplates(); |
|
33 sub query($$); |
|
34 sub getConfigFileName(); |
|
35 sub getConfig($); |
|
36 sub setConfig($$); |
|
37 sub setCopyright($); |
|
38 |
|
39 |
|
40 #globals |
|
41 my $template; |
|
42 my $newName; |
|
43 my $templateDir; |
|
44 my $templateName = "SkeletonTemplate"; |
|
45 my $dest; |
|
46 my $help; |
|
47 my $verbose = 0; |
|
48 my %macroValue; |
|
49 my %macroDescription = ( 'UID' => 'a UID', 'COPYRIGHT' => 'a copyright notice' ); |
|
50 my $homeDir; |
|
51 my $listTemplates; |
|
52 my $overwrite = 0; |
|
53 my $addToPerforce = 0; |
|
54 my $addToMercurial = 0; |
|
55 my $interactive = 0; |
|
56 |
|
57 processCommandLine(); |
|
58 |
|
59 unless (defined $macroValue{'COPYRIGHT'}) { |
|
60 $macroValue{'COPYRIGHT'} = getConfig('copyright'); |
|
61 $macroValue{'COPYRIGHT'} = "Copyright (c) [[YEAR]] Accenture. All rights reserved." unless $macroValue{'COPYRIGHT'}; |
|
62 } |
|
63 |
|
64 |
|
65 $homeDir = homeDir() unless defined ($homeDir); |
|
66 |
|
67 my $year = [localtime()]->[5]+1900; |
|
68 $macroValue{'COPYRIGHT'} =~ s|\[\[YEAR\]\]|$year|g; |
|
69 |
|
70 if ($interactive) { |
|
71 my $templates = getTemplates(); |
|
72 print "Available Templates:\n"; |
|
73 my $count = 1; |
|
74 my $options=""; |
|
75 foreach my $template (@$templates) { |
|
76 print "$count) $template->[0] - $template->[1]\n"; |
|
77 $options=$options . $count; |
|
78 $count++; |
|
79 } |
|
80 do { |
|
81 print "Which template do you want to use? "; |
|
82 my $in = <>; |
|
83 chomp $in; |
|
84 my $choice; |
|
85 $choice = eval "int($in)"; |
|
86 unless ($@) { |
|
87 if (($choice>0) && ($choice <= scalar(@$templates))) { |
|
88 $template = $templates->[$choice-1]->[0]; |
|
89 } |
|
90 } |
|
91 my $max = $count-1; |
|
92 print "Please enter a number between 1 and $max\n" unless defined $template; |
|
93 } until (defined $template); |
|
94 print "Using template $template\n" if $verbose; |
|
95 |
|
96 do { |
|
97 print "Name for the new code? "; |
|
98 $newName = <>; |
|
99 chomp $newName; |
|
100 |
|
101 unless (CheckIdentifier($newName)) { |
|
102 print "$newName is not a valid C++ identifier\n"; |
|
103 undef $newName; |
|
104 } |
|
105 |
|
106 } until ((defined $newName) && (length $newName)); |
|
107 |
|
108 my $cwd = cwd(); |
|
109 print "Directoy to create new code in? [$cwd] "; |
|
110 $dest = <>; |
|
111 chomp $dest; |
|
112 $dest = $cwd unless (length $dest); |
|
113 |
|
114 } else { |
|
115 |
|
116 $dest = cwd() unless $dest; |
|
117 |
|
118 } |
|
119 |
|
120 $templateDir = $homeDir."/createsrc-templates/$template"; |
|
121 die "ERROR: Template $template not found at $templateDir\n" unless -d $templateDir; |
|
122 |
|
123 $dest =~ s|\\|/|g; |
|
124 $dest =~ s|/$||; |
|
125 print "Creating $newName at $dest from template $template at $templateDir\n" if ($verbose); |
|
126 |
|
127 # read [[MACRO]] descriptions from .txt file |
|
128 my $infoFile; |
|
129 my $infoFileName = "$templateDir.txt"; |
|
130 if ((-f $infoFileName) && (open $infoFile, $infoFileName)) { |
|
131 print "Reading $infoFileName\n" if ($verbose); |
|
132 <$infoFile>; # skip template description |
|
133 while (my $line = <$infoFile>) { |
|
134 chomp $line; |
|
135 $line =~ s|#.*||; # remove perl style comments |
|
136 if ($line =~ m|^\s*(\w[\w\d]*)\s*\:\s*(.*)$|) { |
|
137 my ($macro, $desc) = ($1, $2); |
|
138 print "Macro '$macro': '$desc'\n" if ($verbose>1); |
|
139 $macroDescription{$macro} = $desc; |
|
140 } elsif ($line =~ m|^\s*$|) { |
|
141 # blank line |
|
142 } else { |
|
143 die "Error: cannot parse line $. of $infoFileName\n"; |
|
144 } |
|
145 } |
|
146 |
|
147 close $infoFile; |
|
148 } |
|
149 |
|
150 unless (-d $dest) { |
|
151 mkdir($dest) or die "ERROR: Couldn't create directory $dest: $!\n"; |
|
152 print "Created directory $dest\n" if ($verbose>1); |
|
153 } |
|
154 |
|
155 my @dirStack; |
|
156 push @dirStack, ""; |
|
157 |
|
158 |
|
159 while ($#dirStack>=0) { |
|
160 my $dir = pop(@dirStack); |
|
161 |
|
162 my $dirName = $dir; |
|
163 $dir = "/$dir" unless ($dir eq "") || ($dir =~ m|^/|); |
|
164 |
|
165 # create destination directory |
|
166 unless (-d "$dest$dir") { |
|
167 mkdir "$dest$dir" or die "ERROR: cannot create directory $dest$dir: $!\n"; |
|
168 print "Created directory $dest$dir\n" if ($verbose); |
|
169 } |
|
170 |
|
171 # read template directory contents |
|
172 opendir DIR, "$templateDir$dir"; |
|
173 my @dirContents = readdir(DIR); |
|
174 closedir(DIR); |
|
175 |
|
176 foreach my $f (@dirContents) { |
|
177 if (-f "$templateDir$dir/$f") { |
|
178 my $newFile = caseRename($f, $templateName, $newName); |
|
179 print "Renaming from $templateDir$dir/$f to $dest$dir/$newFile\n" if ($verbose); |
|
180 renameFileCopy("$templateDir$dir/$f", "$dest$dir/$newFile"); |
|
181 } elsif (-d "$templateDir$dir/$f") { |
|
182 unless ($f =~ m|^\.\.?$|) { |
|
183 print "Adding $dirName/$f to stack\n" if ($verbose); |
|
184 push @dirStack, "$dirName/$f"; |
|
185 } |
|
186 } else { |
|
187 print "WARNING: $templateDir$dir/$f is neither a file nor a directory"; |
|
188 } |
|
189 } |
|
190 |
|
191 } |
|
192 |
|
193 |
|
194 |
|
195 sub homeDir() { |
|
196 my $homeDir = $FindBin::Bin; |
|
197 print "homeDir=$homeDir\n" if ($verbose > 1); |
|
198 return $homeDir; |
|
199 } |
|
200 |
|
201 sub processCommandLine() { |
|
202 my $setCopyright = undef; |
|
203 Getopt::Long::Configure("bundling"); |
|
204 my @macroDefs; |
|
205 GetOptions('h' => \$help, |
|
206 'v+' => \$verbose, |
|
207 'd=s' => \$dest, |
|
208 's=s' => \$homeDir, |
|
209 't=s' => \$templateName, |
|
210 'l' => \$listTemplates, |
|
211 'o' => \$overwrite, |
|
212 'p' => \$addToPerforce, |
|
213 'm' => \$addToMercurial, |
|
214 'i' => \$interactive, |
|
215 'c=s' => \$setCopyright, |
|
216 'D=s' => \@macroDefs); |
|
217 |
|
218 Usage() if ($help); |
|
219 |
|
220 listTemplates(1) if ($listTemplates); |
|
221 |
|
222 setCopyright($setCopyright) if (defined $setCopyright); |
|
223 |
|
224 unless ($interactive) { |
|
225 if ($#ARGV < 1) { |
|
226 print "Insufficient arguments; entering interactive mode\n"; |
|
227 $interactive = 1; |
|
228 } else { |
|
229 $template = shift(@ARGV); |
|
230 $newName = shift(@ARGV); |
|
231 die "$newName is not a valid C++ identifier\n" unless CheckIdentifier($newName); |
|
232 } |
|
233 } |
|
234 foreach my $d (@macroDefs) { |
|
235 if ($d =~ m|^(\w[\w\d]*)=(.*)$|) { |
|
236 my ($macro, $value) = ($1, $2); |
|
237 print "Got macro '$macro'='$value' from command line\n" if ($verbose>1); |
|
238 die "Error: '$value' is not a valid value for $macro\n" unless CheckMacro($macro, $value); |
|
239 $macroValue{$macro} = $value; |
|
240 } else { |
|
241 die "Error: Incorrect usage of -D: $d: expected a string of the format 'id=value'\n"; |
|
242 } |
|
243 } |
|
244 print "Warning: ignoring " . scalar(@ARGV) . " extra arguments\n" if scalar(@ARGV); |
|
245 } |
|
246 |
|
247 sub Usage() { |
|
248 require Pod::Text; |
|
249 my $parser = Pod::Text->new(); |
|
250 $parser->parse_from_file($0); |
|
251 exit; |
|
252 } |
|
253 |
|
254 sub make4CharId($) { |
|
255 my $longId = shift; |
|
256 while (length($longId)<2) { |
|
257 $longId = $longId . '_'; |
|
258 } |
|
259 return uc( substr($longId, 0, 2) . substr($longId, length($longId)-2, 2) ); |
|
260 } |
|
261 |
|
262 sub caseRename($$$) { |
|
263 my $string = shift; |
|
264 my $oldName = shift; |
|
265 my $newName = shift; |
|
266 |
|
267 my $oldUpper = $oldName; |
|
268 $oldUpper =~ tr/a-z/A-Z/; |
|
269 |
|
270 my $oldLower = $oldName; |
|
271 $oldLower =~ tr/A-Z/a-z/; |
|
272 |
|
273 my $oldLowerFirst = "\l$oldName;\E"; |
|
274 |
|
275 my $uppercase = $newName; |
|
276 $uppercase =~ tr/a-z/A-Z/; |
|
277 |
|
278 my $lowercase = $newName; |
|
279 $lowercase =~ tr/A-Z/a-z/; |
|
280 |
|
281 my $lowerFirst = "\l$newName\E"; |
|
282 |
|
283 my $old4Char = make4CharId($oldName); |
|
284 my $new4Char = make4CharId($newName); |
|
285 |
|
286 $string =~ s/$oldName/$newName/g; |
|
287 $string =~ s/$oldUpper/$uppercase/g; |
|
288 $string =~ s/$oldLower/$lowercase/g; |
|
289 $string =~ s/$oldLowerFirst/$lowerFirst/g; |
|
290 $string =~ s/$old4Char/$new4Char/g; |
|
291 return $string; |
|
292 } |
|
293 |
|
294 sub renameFileCopy($$) { |
|
295 my $src = shift; |
|
296 my $dest = shift; |
|
297 open SOURCE, "<$src" or die "ERROR: can't open $src for reading: $!\n"; |
|
298 unless ($overwrite) { |
|
299 die "ERROR: $dest already exists. Use -o to overwrite. Aborting.\n" if (-f $dest); |
|
300 } |
|
301 open DEST, ">$dest" or die "ERROR: can't open $dest for writing: $!\n"; |
|
302 while (my $line = <SOURCE>) { |
|
303 while ($line =~ m|\[\[(\w[\w\d]*)\]\]|) { |
|
304 my $id = $1; |
|
305 my $value = GetMacroValue($id); |
|
306 $line =~ s|\[\[$id\]\]|$value|g; |
|
307 } |
|
308 print DEST caseRename($line, $templateName, $newName); |
|
309 |
|
310 } |
|
311 close (SOURCE); |
|
312 close (DEST); |
|
313 if ($addToPerforce) { |
|
314 print "p4 add $dest\n"; |
|
315 `p4 add $dest` ; |
|
316 } |
|
317 if ($addToMercurial) { |
|
318 print "hg add $dest\n"; |
|
319 `hg add $dest` ; |
|
320 } |
|
321 } |
|
322 |
|
323 sub GetMacroValue($) { |
|
324 my $macro = shift; |
|
325 if (!defined($macroValue{$macro})) { |
|
326 $macroValue{$macro} = PromptMacro($macro); |
|
327 } |
|
328 return $macroValue{$macro}; |
|
329 } |
|
330 |
|
331 sub PromptMacro($) { |
|
332 my $macro = shift; |
|
333 my $description = $macroDescription{$macro}; |
|
334 $description = $macro unless defined $description; |
|
335 |
|
336 print "Enter $description for $newName: "; |
|
337 my $value; |
|
338 do { |
|
339 $value = <>; |
|
340 chomp $value; |
|
341 } while (!CheckMacro($macro, $value)); |
|
342 return $value; |
|
343 } |
|
344 |
|
345 sub CheckMacro($$) { |
|
346 my ($macro, $value) = @_; |
|
347 if ($macro eq 'UID') { |
|
348 return CheckUid($value); |
|
349 } |
|
350 return 1; |
|
351 } |
|
352 |
|
353 sub CheckUid($) { |
|
354 my $uid = shift; |
|
355 return 1 if ($uid =~ m|^0x[0-9a-f]{1,8}$|i); |
|
356 return 1 if ($uid =~ m|^[0-9]{1,10}$|); |
|
357 return 0; |
|
358 } |
|
359 |
|
360 sub CheckIdentifier($) { |
|
361 my $id = shift; |
|
362 return ($id =~ m|[A-Za-z_][A-Za-z_0-9]*|); |
|
363 } |
|
364 |
|
365 sub getTemplates() { |
|
366 $homeDir = homeDir() unless defined ($homeDir); |
|
367 opendir TEMPLATES, "$homeDir/createsrc-templates" or die "Can't read directory $homeDir/createsrc-templates: $!\n"; |
|
368 my @templateNames = grep((-d "$homeDir/createsrc-templates/$_")&&!(m|\.\.?|), readdir(TEMPLATES)); |
|
369 close TEMPLATES; |
|
370 die "No templates found at $homeDir/createsrc-templates\n" unless scalar(@templateNames); |
|
371 my @templates = (); |
|
372 foreach my $template (@templateNames) { |
|
373 my $desc; |
|
374 my $descFile = "$homeDir/createsrc-templates/$template.txt"; |
|
375 if ((-f $descFile)&&(open DESC, $descFile)) { |
|
376 $desc = <DESC>; |
|
377 chomp $desc; |
|
378 close DESC; |
|
379 } else { |
|
380 $desc = "<no description>"; |
|
381 } |
|
382 push @templates, [$template, $desc]; |
|
383 } |
|
384 @templates = sort {$a->[0] cmp $b->[0]} @templates; |
|
385 return \@templates; |
|
386 } |
|
387 |
|
388 sub listTemplates($) { |
|
389 my $exitWhenDone = shift; |
|
390 my $templates = getTemplates(); |
|
391 foreach my $template (@$templates) { |
|
392 print $template->[0] . " - " . $template->[1] . "\n"; |
|
393 } |
|
394 exit if $exitWhenDone; |
|
395 } |
|
396 |
|
397 sub getConfigFileName() { |
|
398 my $fn; |
|
399 if (defined $ENV{'USERPROFILE'}) { |
|
400 $fn = $ENV{'USERPROFILE'}; |
|
401 } else { |
|
402 $fn = homeDir(); |
|
403 } |
|
404 $fn =~ s|[/\\]$||; |
|
405 $fn .= "\\createsrc.cfg"; |
|
406 return $fn; |
|
407 } |
|
408 |
|
409 sub getConfig($) { |
|
410 my $findKey = shift; |
|
411 my $cfg = getConfigFileName(); |
|
412 my $foundValue = undef; |
|
413 open CFGFILE, "<$cfg" or return undef; |
|
414 print "Reading $cfg\n" if ($verbose); |
|
415 while (my $line = <CFGFILE>) { |
|
416 chomp $line; |
|
417 if ($line =~ m|^(.*?)\s*=\s*(.*)$|) { |
|
418 my ($key, $value) = ($1, $2); |
|
419 print "Read '$key'='$value'\n" if ($verbose>1); |
|
420 $foundValue = $value if ($key eq $findKey); |
|
421 } else { |
|
422 print "ignoring line '$line'\n" if ($verbose>1); |
|
423 } |
|
424 } |
|
425 return $foundValue; |
|
426 close CFGFILE; |
|
427 } |
|
428 |
|
429 sub setConfig($$) { |
|
430 my ($key, $value) = @_; |
|
431 my $cfg = getConfigFileName(); |
|
432 my @lines; |
|
433 if (open CFGFILE, "<$cfg") { |
|
434 print "Reading $cfg\n"; |
|
435 @lines = <CFGFILE>; |
|
436 close CFGFILE; |
|
437 } |
|
438 open CFGFILE, ">$cfg" or die "Cannot write to $cfg: $!\n"; |
|
439 print "Writing $cfg\n" if ($verbose); |
|
440 my $written = 0; |
|
441 foreach my $line (@lines) { |
|
442 if ($line =~ m|^(.*?)\s*=\s*(.*)$|) { |
|
443 my ($foundKey, $foundValue) = ($1, $2); |
|
444 print "Read '$foundKey'='$foundValue'\n" if ($verbose>1); |
|
445 if ($key eq $foundKey) { |
|
446 $foundValue = $value; |
|
447 $written = 1; |
|
448 print "Updated key $foundKey to '$foundValue'\n" if ($verbose>1); |
|
449 } |
|
450 print CFGFILE "$foundKey=$foundValue\n"; |
|
451 } else { |
|
452 print "ignoring line '$line'\n" if ($verbose>1); |
|
453 print CFGFILE $line; |
|
454 } |
|
455 } |
|
456 unless ($written) { |
|
457 print "Adding $key=$value\n"; |
|
458 print CFGFILE "$key=$value\n"; |
|
459 } |
|
460 close CFGFILE; |
|
461 |
|
462 } |
|
463 |
|
464 sub setCopyright($) { |
|
465 my $copyright = shift; |
|
466 print "Setting copyright notice to '$copyright'\n" if ($verbose); |
|
467 setConfig('copyright', $copyright); |
|
468 exit(1); |
|
469 } |
|
470 |
|
471 |
|
472 __END__ |
|
473 |
|
474 =head1 NAME |
|
475 |
|
476 createsrc - creates new code from templates |
|
477 |
|
478 =head1 SYNOPSIS |
|
479 |
|
480 createsrc [options] [TemplateName NewName] |
|
481 |
|
482 options: |
|
483 |
|
484 =over |
|
485 |
|
486 =item -i |
|
487 |
|
488 Use L<Interactive mode>. This will be the default if C<TemplateName> and C<NewName> are not given. |
|
489 |
|
490 =item -d <directory> |
|
491 |
|
492 Put the new code in the specified directory. Defaults to current directory. |
|
493 |
|
494 =item -DMACRO=value |
|
495 |
|
496 Specfies a value for a macro. See "Macros" section below. |
|
497 |
|
498 =item -c "Copyright Notice" |
|
499 |
|
500 Sets the default copyright to use when none other is specified. See L<Copyright Notices> below. |
|
501 |
|
502 =item -o |
|
503 |
|
504 Overwrites any existing files when creating the new code. |
|
505 |
|
506 =item -p |
|
507 |
|
508 Add the new files to perforce as they are created. |
|
509 |
|
510 =item -m |
|
511 |
|
512 Add the new files to mercurial as they are created. |
|
513 |
|
514 =item -s <directory> |
|
515 |
|
516 Specifies the home directory of the script, where the templates are located. Defaults to the directory where the script is located. |
|
517 |
|
518 =item -t <TemplateText> |
|
519 |
|
520 Specified the text to be replaced in the template. Defaults to C<SkeletonTemplate>. It's not usually necessary to change this. |
|
521 |
|
522 =item -l |
|
523 |
|
524 List available templates, then exits. |
|
525 |
|
526 =item -h |
|
527 |
|
528 Shows this help. |
|
529 |
|
530 =item -v |
|
531 |
|
532 Verbose mode (-vv very verbose). |
|
533 |
|
534 =back |
|
535 |
|
536 =head1 DESCRIPTION |
|
537 |
|
538 This script creates new projects or code snippets from templates. For example, assuming you have a template C<UiqBasic> that consists of a basic UIQ application, you could create a HelloWorld application as follows: |
|
539 |
|
540 createsrc UiqBasic HelloWorld |
|
541 |
|
542 When creating the new code, it performs the following steps: |
|
543 |
|
544 =over |
|
545 |
|
546 =item 1. |
|
547 |
|
548 Copies and renames the files as appropriate. |
|
549 |
|
550 =item 2. |
|
551 |
|
552 Replaces text within the files as appropriate. |
|
553 |
|
554 =item 3. |
|
555 |
|
556 Substitutes macros enclosed in double square brackets, C<[[MACRO]]>. |
|
557 |
|
558 =back |
|
559 |
|
560 When renaming files or substituting text withing the files, case is preseved as follows: |
|
561 |
|
562 =over |
|
563 |
|
564 =item 1. |
|
565 |
|
566 C<MixedCaseText> is preserved - i.e. C<TemplateText> becomes C<NewText>. |
|
567 |
|
568 =item 2. |
|
569 |
|
570 C<lowercasetext> is preserved - i.e. C<templatetext> becomes C<newtext>. |
|
571 |
|
572 =item 3. |
|
573 |
|
574 C<UPPERCASETEXT> is preserved - i.e. C<TEMPLATETEXT> becomes C<NEWTEXT>. |
|
575 |
|
576 =item 4. |
|
577 |
|
578 C<lowerCaseFirst> is preserved - i.e. C<templateText> becomes C<newText>. |
|
579 |
|
580 =back |
|
581 |
|
582 This should cover all forms of capitalisation used within normal Symbian code. |
|
583 |
|
584 In addition, the capitalised first and last two letters of C<TemplateText> is replaced with the same letters of C<NewText> - i.e. C<TEXT> becomes C<NEXT>. This is to support the C<NAME> value in an applications resource file, which must always have 4 letters. |
|
585 |
|
586 If the new text has less than 4 characters, it will be padded with underscores. For example, an application called C<A> will be given a C<NAME> of C<A_A_>; C<Ap> becomes C<APAP>; C<HelloWorld> becomes C<HELD> and so on. |
|
587 |
|
588 =head2 Interactive mode |
|
589 |
|
590 If the C<-i> option is given, of if no C<TemplateName> and C<TemplateText> are given, interactive mode will be used: |
|
591 |
|
592 D:\work\new>createsrc |
|
593 Insufficient arguments; entering interactive mode |
|
594 Available Templates: |
|
595 1) UiqBasic - Basic UIQ application |
|
596 2) UiqImaging - Basic UIQ application with one large control, suitable for displaying an image, a video, etc. |
|
597 3) UiqList - Basic UIQ application with a list in the view. |
|
598 4) server - Symbian 9 transient server |
|
599 Which template do you want to use? 1 |
|
600 Name for the new code? HelloWorld |
|
601 Directoy to create new code in? [D:/work/new] |
|
602 Enter a UID for HelloWorld: 0x10002000 |
|
603 |
|
604 When prompted for the directory to create the code in, simply hit enter to use the suggestion in square brackets. Or you can enter a relative or absolute path name to use instead. |
|
605 |
|
606 =head2 Macros |
|
607 |
|
608 Macros allow extra custom strings to be inserted into the generate code. Macro values can be specified on the command line using the C<-D> option; if no value is specified then it will be prompted for at runtime. |
|
609 |
|
610 There are two macros that are used by all (or most) templates: |
|
611 |
|
612 =over |
|
613 |
|
614 =item C<COPYRIGHT> |
|
615 |
|
616 Defines a copyright notice for the code, usually inserted in a comment at the top of each source file. See L<Copyright Notices> below. |
|
617 |
|
618 =item C<UID> |
|
619 |
|
620 Specifies a UID for the new code. This will be verified as a valid integer. |
|
621 |
|
622 =back |
|
623 |
|
624 Some templates may define other, custom macros. To define a macro value on the command line, use -D syntax in a similar way the a C preprocessor: |
|
625 |
|
626 createsrc -DUID=0x01234567 |
|
627 |
|
628 |
|
629 =head2 Copyright Notices |
|
630 |
|
631 Copyright notices are automatically inserted into the source files, including the current year. When using the C<-DCOPYRIGHT=...> and C<-c> options, the copyright text may include C<[[YEAR]]>, which will be replaced with the current year when the code was created. |
|
632 |
|
633 For example, |
|
634 |
|
635 createsrc -DCOPYRIGHT="Copyright (c) [[YEAR]] Joe Bloggs. All rights reserved" |
|
636 |
|
637 The default copyright notice is C<Copyright (c) [[YEAR]] Accenture. All rights reserved.> |
|
638 |
|
639 When the C<-c> option is used, the copyright notice is stored in C<%USERPROFILE%\createsrc.cfg> and so is persisted for future runs of C<createsrc>. |
|
640 |
|
641 =head2 Templates |
|
642 |
|
643 The templates are located in F<\epoc32\tools\Templates\TemplateName>. Each template usually contains an entire buildable project, but this may vary depending upon the nature of the template. The text that is replaced in template filenames and files is C<SkeletonTemplate> by default, but this can be modified with the C<-t TemplateText> option (although it is not recommended). |
|
644 |
|
645 In the template, macros are enclosed in double square brackets, for example C<[[UID]]>. Templates should make use of the standard C<[[UID]]> and C<[[COPYRIGHT]]> macros and can use others if necessary. |
|
646 |
|
647 If a F<TemplateName.txt> file is found in F<\epoc32\tools\Templates>, the first line of this file will be used as the description of the template when the C<-l> flag is given. The remainder of the file is expected to contain lines of the format: |
|
648 |
|
649 MACRO: description |
|
650 |
|
651 giving descriptions for any custom macros used in the project. The descriptions will be used instead of the macro name when prmopting the user for a value at runtime. |
|
652 |
|
653 =head1 COPYRIGHT |
|
654 |
|
655 Copyright (c) 2008-2010 Accenture. All rights reserved. |
|
656 |
|
657 =cut |
|
658 |