Formatting
[jalview.git] / src / jalview / util / Format.java
1 /*\r
2  * Cay S. Horstmann & Gary Cornell, Core Java\r
3  * Published By Sun Microsystems Press/Prentice-Hall\r
4  * Copyright (C) 1997 Sun Microsystems Inc.\r
5  * All Rights Reserved.\r
6  *\r
7  * Permission to use, copy, modify, and distribute this\r
8  * software and its documentation for NON-COMMERCIAL purposes\r
9  * and without fee is hereby granted provided that this\r
10  * copyright notice appears in all copies.\r
11  *\r
12  * THE AUTHORS AND PUBLISHER MAKE NO REPRESENTATIONS OR\r
13  * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER\r
14  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\r
15  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\r
16  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. THE AUTHORS\r
17  * AND PUBLISHER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED\r
18  * BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING\r
19  * THIS SOFTWARE OR ITS DERIVATIVES.\r
20  */\r
21 \r
22 /**\r
23  * A class for formatting numbers that follows printf conventions.\r
24  * Also implements C-like atoi and atof functions\r
25  * @version 1.03 25 Oct 1997\r
26  * @author Cay Horstmann\r
27  */\r
28 package jalview.util;\r
29 \r
30 /**\r
31  * DOCUMENT ME!\r
32  *\r
33  * @author $author$\r
34  * @version $Revision$\r
35  */\r
36 public class Format\r
37 {\r
38   private int width;\r
39   private int precision;\r
40   private String pre;\r
41   private String post;\r
42   private boolean leading_zeroes;\r
43   private boolean show_plus;\r
44   private boolean alternate;\r
45   private boolean show_space;\r
46   private boolean left_align;\r
47   private char fmt; // one of cdeEfgGiosxXos\r
48 \r
49   /**\r
50    * Creates a new Format object.\r
51    *\r
52    * @param s DOCUMENT ME!\r
53    */\r
54   public Format(String s)\r
55   {\r
56     width = 0;\r
57     precision = -1;\r
58     pre = "";\r
59     post = "";\r
60     leading_zeroes = false;\r
61     show_plus = false;\r
62     alternate = false;\r
63     show_space = false;\r
64     left_align = false;\r
65     fmt = ' ';\r
66 \r
67     int length = s.length();\r
68     int parse_state = 0;\r
69 \r
70     // 0 = prefix, 1 = flags, 2 = width, 3 = precision,\r
71     // 4 = format, 5 = end\r
72     int i = 0;\r
73 \r
74     while (parse_state == 0)\r
75     {\r
76       if (i >= length)\r
77       {\r
78         parse_state = 5;\r
79       }\r
80       else if (s.charAt(i) == '%')\r
81       {\r
82         if (i < (length - 1))\r
83         {\r
84           if (s.charAt(i + 1) == '%')\r
85           {\r
86             pre = pre + '%';\r
87             i++;\r
88           }\r
89           else\r
90           {\r
91             parse_state = 1;\r
92           }\r
93         }\r
94         else\r
95         {\r
96           throw new java.lang.IllegalArgumentException();\r
97         }\r
98       }\r
99       else\r
100       {\r
101         pre = pre + s.charAt(i);\r
102       }\r
103 \r
104       i++;\r
105     }\r
106 \r
107     while (parse_state == 1)\r
108     {\r
109       if (i >= length)\r
110       {\r
111         parse_state = 5;\r
112       }\r
113       else if (s.charAt(i) == ' ')\r
114       {\r
115         show_space = true;\r
116       }\r
117       else if (s.charAt(i) == '-')\r
118       {\r
119         left_align = true;\r
120       }\r
121       else if (s.charAt(i) == '+')\r
122       {\r
123         show_plus = true;\r
124       }\r
125       else if (s.charAt(i) == '0')\r
126       {\r
127         leading_zeroes = true;\r
128       }\r
129       else if (s.charAt(i) == '#')\r
130       {\r
131         alternate = true;\r
132       }\r
133       else\r
134       {\r
135         parse_state = 2;\r
136         i--;\r
137       }\r
138 \r
139       i++;\r
140     }\r
141 \r
142     while (parse_state == 2)\r
143     {\r
144       if (i >= length)\r
145       {\r
146         parse_state = 5;\r
147       }\r
148       else if ( ('0' <= s.charAt(i)) && (s.charAt(i) <= '9'))\r
149       {\r
150         width = ( (width * 10) + s.charAt(i)) - '0';\r
151         i++;\r
152       }\r
153       else if (s.charAt(i) == '.')\r
154       {\r
155         parse_state = 3;\r
156         precision = 0;\r
157         i++;\r
158       }\r
159       else\r
160       {\r
161         parse_state = 4;\r
162       }\r
163     }\r
164 \r
165     while (parse_state == 3)\r
166     {\r
167       if (i >= length)\r
168       {\r
169         parse_state = 5;\r
170       }\r
171       else if ( ('0' <= s.charAt(i)) && (s.charAt(i) <= '9'))\r
172       {\r
173         precision = ( (precision * 10) + s.charAt(i)) - '0';\r
174         i++;\r
175       }\r
176       else\r
177       {\r
178         parse_state = 4;\r
179       }\r
180     }\r
181 \r
182     if (parse_state == 4)\r
183     {\r
184       if (i >= length)\r
185       {\r
186         parse_state = 5;\r
187       }\r
188       else\r
189       {\r
190         fmt = s.charAt(i);\r
191       }\r
192 \r
193       i++;\r
194     }\r
195 \r
196     if (i < length)\r
197     {\r
198       post = s.substring(i, length);\r
199     }\r
200   }\r
201 \r
202   /**\r
203    * Formats the number following printf conventions.\r
204    * Main limitation: Can only handle one format parameter at a time\r
205    * Use multiple Format objects to format more than one number\r
206    * @param s the format string following printf conventions\r
207    * The string has a prefix, a format code and a suffix. The prefix and suffix\r
208    * become part of the formatted output. The format code directs the\r
209    * formatting of the (single) parameter to be formatted. The code has the\r
210    * following structure\r
211    * <ul>\r
212    * <li> a % (required)\r
213    * <li> a modifier (optional)\r
214    * <dl>\r
215    * <dt> + <dd> forces display of + for positive numbers\r
216    * <dt> 0 <dd> show leading zeroes\r
217    * <dt> - <dd> align left in the field\r
218    * <dt> space <dd> prepend a space in front of positive numbers\r
219    * <dt> # <dd> use "alternate" format. Add 0 or 0x for octal or hexadecimal numbers. Don't suppress trailing zeroes in general floating point format.\r
220    * </dl>\r
221    * <li> an integer denoting field width (optional)\r
222    * <li> a period followed by an integer denoting precision (optional)\r
223    * <li> a format descriptor (required)\r
224    * <dl>\r
225    * <dt>f <dd> floating point number in fixed format\r
226    * <dt>e, E <dd> floating point number in exponential notation (scientific format). The E format results in an uppercase E for the exponent (1.14130E+003), the e format in a lowercase e.\r
227    * <dt>g, G <dd> floating point number in general format (fixed format for small numbers, exponential format for large numbers). Trailing zeroes are suppressed. The G format results in an uppercase E for the exponent (if any), the g format in a lowercase e.\r
228    * <dt>d, i <dd> integer in decimal\r
229    * <dt>x <dd> integer in hexadecimal\r
230    * <dt>o <dd> integer in octal\r
231    * <dt>s <dd> string\r
232    * <dt>c <dd> character\r
233    * </dl>\r
234    * </ul>\r
235    * @exception IllegalArgumentException if bad format\r
236    *\r
237    */\r
238   public static String getHexString(java.awt.Color color)\r
239   {\r
240     String r;\r
241     String g;\r
242     String b;\r
243     r = Integer.toHexString(color.getRed());\r
244 \r
245     if (r.length() < 2)\r
246     {\r
247       r = "0" + r;\r
248     }\r
249 \r
250     g = Integer.toHexString(color.getGreen());\r
251 \r
252     if (g.length() < 2)\r
253     {\r
254       g = "0" + g;\r
255     }\r
256 \r
257     b = Integer.toHexString(color.getBlue());\r
258 \r
259     if (b.length() < 2)\r
260     {\r
261       b = "0" + b;\r
262     }\r
263 \r
264     return r + g + b;\r
265   }\r
266 \r
267   /**\r
268    * prints a formatted number following printf conventions\r
269    * @param s a PrintStream\r
270    * @param fmt the format string\r
271    * @param x the double to print\r
272    */\r
273   public static void print(java.io.PrintStream s, String fmt, double x)\r
274   {\r
275     s.print(new Format(fmt).form(x));\r
276   }\r
277 \r
278   /**\r
279    * prints a formatted number following printf conventions\r
280    * @param s a PrintStream\r
281    * @param fmt the format string\r
282    * @param x the long to print\r
283    */\r
284   public static void print(java.io.PrintStream s, String fmt, long x)\r
285   {\r
286     s.print(new Format(fmt).form(x));\r
287   }\r
288 \r
289   /**\r
290    * prints a formatted number following printf conventions\r
291    * @param s a PrintStream\r
292    * @param fmt the format string\r
293    * @param x the character to\r
294    */\r
295   public static void print(java.io.PrintStream s, String fmt, char x)\r
296   {\r
297     s.print(new Format(fmt).form(x));\r
298   }\r
299 \r
300   /**\r
301    * prints a formatted number following printf conventions\r
302    * @param s a PrintStream, fmt the format string\r
303    * @param x a string that represents the digits to print\r
304    */\r
305   public static void print(java.io.PrintStream s, String fmt, String x)\r
306   {\r
307     s.print(new Format(fmt).form(x));\r
308   }\r
309 \r
310   /**\r
311    * Converts a string of digits (decimal, octal or hex) to an integer\r
312    * @param s a string\r
313    * @return the numeric value of the prefix of s representing a base 10 integer\r
314    */\r
315   public static int atoi(String s)\r
316   {\r
317     return (int) atol(s);\r
318   }\r
319 \r
320   /**\r
321    * Converts a string of digits (decimal, octal or hex) to a long integer\r
322    * @param s a string\r
323    * @return the numeric value of the prefix of s representing a base 10 integer\r
324    */\r
325   public static long atol(String s)\r
326   {\r
327     int i = 0;\r
328 \r
329     while ( (i < s.length()) && Character.isWhitespace(s.charAt(i)))\r
330     {\r
331       i++;\r
332     }\r
333 \r
334     if ( (i < s.length()) && (s.charAt(i) == '0'))\r
335     {\r
336       if ( ( (i + 1) < s.length()) &&\r
337           ( (s.charAt(i + 1) == 'x') || (s.charAt(i + 1) == 'X')))\r
338       {\r
339         return parseLong(s.substring(i + 2), 16);\r
340       }\r
341       else\r
342       {\r
343         return parseLong(s, 8);\r
344       }\r
345     }\r
346     else\r
347     {\r
348       return parseLong(s, 10);\r
349     }\r
350   }\r
351 \r
352   /**\r
353    * DOCUMENT ME!\r
354    *\r
355    * @param s DOCUMENT ME!\r
356    * @param base DOCUMENT ME!\r
357    *\r
358    * @return DOCUMENT ME!\r
359    */\r
360   private static long parseLong(String s, int base)\r
361   {\r
362     int i = 0;\r
363     int sign = 1;\r
364     long r = 0;\r
365 \r
366     while ( (i < s.length()) && Character.isWhitespace(s.charAt(i)))\r
367     {\r
368       i++;\r
369     }\r
370 \r
371     if ( (i < s.length()) && (s.charAt(i) == '-'))\r
372     {\r
373       sign = -1;\r
374       i++;\r
375     }\r
376     else if ( (i < s.length()) && (s.charAt(i) == '+'))\r
377     {\r
378       i++;\r
379     }\r
380 \r
381     while (i < s.length())\r
382     {\r
383       char ch = s.charAt(i);\r
384 \r
385       if ( ('0' <= ch) && (ch < ('0' + base)))\r
386       {\r
387         r = ( (r * base) + ch) - '0';\r
388       }\r
389       else if ( ('A' <= ch) && (ch < ( ('A' + base) - 10)))\r
390       {\r
391         r = ( (r * base) + ch) - 'A' + 10;\r
392       }\r
393       else if ( ('a' <= ch) && (ch < ( ('a' + base) - 10)))\r
394       {\r
395         r = ( (r * base) + ch) - 'a' + 10;\r
396       }\r
397       else\r
398       {\r
399         return r * sign;\r
400       }\r
401 \r
402       i++;\r
403     }\r
404 \r
405     return r * sign;\r
406   }\r
407 \r
408   /**\r
409    * Converts a string of digits to an double\r
410    * @param s a string\r
411    */\r
412   public static double atof(String s)\r
413   {\r
414     int i = 0;\r
415     int sign = 1;\r
416     double r = 0; // integer part\r
417     //double f = 0; // fractional part\r
418     double p = 1; // exponent of fractional part\r
419     int state = 0; // 0 = int part, 1 = frac part\r
420 \r
421     while ( (i < s.length()) && Character.isWhitespace(s.charAt(i)))\r
422     {\r
423       i++;\r
424     }\r
425 \r
426     if ( (i < s.length()) && (s.charAt(i) == '-'))\r
427     {\r
428       sign = -1;\r
429       i++;\r
430     }\r
431     else if ( (i < s.length()) && (s.charAt(i) == '+'))\r
432     {\r
433       i++;\r
434     }\r
435 \r
436     while (i < s.length())\r
437     {\r
438       char ch = s.charAt(i);\r
439 \r
440       if ( ('0' <= ch) && (ch <= '9'))\r
441       {\r
442         if (state == 0)\r
443         {\r
444           r = ( (r * 10) + ch) - '0';\r
445         }\r
446         else if (state == 1)\r
447         {\r
448           p = p / 10;\r
449           r = r + (p * (ch - '0'));\r
450         }\r
451       }\r
452       else if (ch == '.')\r
453       {\r
454         if (state == 0)\r
455         {\r
456           state = 1;\r
457         }\r
458         else\r
459         {\r
460           return sign * r;\r
461         }\r
462       }\r
463       else if ( (ch == 'e') || (ch == 'E'))\r
464       {\r
465         long e = (int) parseLong(s.substring(i + 1), 10);\r
466 \r
467         return sign * r * Math.pow(10, e);\r
468       }\r
469       else\r
470       {\r
471         return sign * r;\r
472       }\r
473 \r
474       i++;\r
475     }\r
476 \r
477     return sign * r;\r
478   }\r
479 \r
480   /**\r
481    * Formats a double into a string (like sprintf in C)\r
482    * @param x the number to format\r
483    * @return the formatted string\r
484    * @exception IllegalArgumentException if bad argument\r
485    */\r
486   public String form(double x)\r
487   {\r
488     String r;\r
489 \r
490     if (precision < 0)\r
491     {\r
492       precision = 6;\r
493     }\r
494 \r
495     int s = 1;\r
496 \r
497     if (x < 0)\r
498     {\r
499       x = -x;\r
500       s = -1;\r
501     }\r
502 \r
503     if (fmt == 'f')\r
504     {\r
505       r = fixed_format(x);\r
506     }\r
507     else if ( (fmt == 'e') || (fmt == 'E') || (fmt == 'g') || (fmt == 'G'))\r
508     {\r
509       r = exp_format(x);\r
510     }\r
511     else\r
512     {\r
513       throw new java.lang.IllegalArgumentException();\r
514     }\r
515 \r
516     return pad(sign(s, r));\r
517   }\r
518 \r
519   /**\r
520    * Formats a long integer into a string (like sprintf in C)\r
521    * @param x the number to format\r
522    * @return the formatted string\r
523    */\r
524   public String form(long x)\r
525   {\r
526     String r;\r
527     int s = 0;\r
528 \r
529     if ( (fmt == 'd') || (fmt == 'i'))\r
530     {\r
531       if (x < 0)\r
532       {\r
533         r = ("" + x).substring(1);\r
534         s = -1;\r
535       }\r
536       else\r
537       {\r
538         r = "" + x;\r
539         s = 1;\r
540       }\r
541     }\r
542     else if (fmt == 'o')\r
543     {\r
544       r = convert(x, 3, 7, "01234567");\r
545     }\r
546     else if (fmt == 'x')\r
547     {\r
548       r = convert(x, 4, 15, "0123456789abcdef");\r
549     }\r
550     else if (fmt == 'X')\r
551     {\r
552       r = convert(x, 4, 15, "0123456789ABCDEF");\r
553     }\r
554     else\r
555     {\r
556       throw new java.lang.IllegalArgumentException();\r
557     }\r
558 \r
559     return pad(sign(s, r));\r
560   }\r
561 \r
562   /**\r
563    * Formats a character into a string (like sprintf in C)\r
564    * @param x the value to format\r
565    * @return the formatted string\r
566    */\r
567   public String form(char c)\r
568   {\r
569     if (fmt != 'c')\r
570     {\r
571       throw new java.lang.IllegalArgumentException();\r
572     }\r
573 \r
574     String r = "" + c;\r
575 \r
576     return pad(r);\r
577   }\r
578 \r
579   /**\r
580    * Formats a string into a larger string (like sprintf in C)\r
581    * @param x the value to format\r
582    * @return the formatted string\r
583    */\r
584   public String form(String s)\r
585   {\r
586     if (fmt != 's')\r
587     {\r
588       throw new java.lang.IllegalArgumentException();\r
589     }\r
590 \r
591     if (precision >= 0)\r
592     {\r
593       s = s.substring(0, precision);\r
594     }\r
595 \r
596     return pad(s);\r
597   }\r
598 \r
599   /**\r
600    * DOCUMENT ME!\r
601    *\r
602    * @param c DOCUMENT ME!\r
603    * @param n DOCUMENT ME!\r
604    *\r
605    * @return DOCUMENT ME!\r
606    */\r
607   private static String repeat(char c, int n)\r
608   {\r
609     if (n <= 0)\r
610     {\r
611       return "";\r
612     }\r
613 \r
614     StringBuffer s = new StringBuffer(n);\r
615 \r
616     for (int i = 0; i < n; i++)\r
617     {\r
618       s.append(c);\r
619     }\r
620 \r
621     return s.toString();\r
622   }\r
623 \r
624   /**\r
625    * DOCUMENT ME!\r
626    *\r
627    * @param x DOCUMENT ME!\r
628    * @param n DOCUMENT ME!\r
629    * @param m DOCUMENT ME!\r
630    * @param d DOCUMENT ME!\r
631    *\r
632    * @return DOCUMENT ME!\r
633    */\r
634   private static String convert(long x, int n, int m, String d)\r
635   {\r
636     if (x == 0)\r
637     {\r
638       return "0";\r
639     }\r
640 \r
641     String r = "";\r
642 \r
643     while (x != 0)\r
644     {\r
645       r = d.charAt( (int) (x & m)) + r;\r
646       x = x >>> n;\r
647     }\r
648 \r
649     return r;\r
650   }\r
651 \r
652   /**\r
653    * DOCUMENT ME!\r
654    *\r
655    * @param r DOCUMENT ME!\r
656    *\r
657    * @return DOCUMENT ME!\r
658    */\r
659   private String pad(String r)\r
660   {\r
661     String p = repeat(' ', width - r.length());\r
662 \r
663     if (left_align)\r
664     {\r
665       return pre + r + p + post;\r
666     }\r
667     else\r
668     {\r
669       return pre + p + r + post;\r
670     }\r
671   }\r
672 \r
673   /**\r
674    * DOCUMENT ME!\r
675    *\r
676    * @param s DOCUMENT ME!\r
677    * @param r DOCUMENT ME!\r
678    *\r
679    * @return DOCUMENT ME!\r
680    */\r
681   private String sign(int s, String r)\r
682   {\r
683     String p = "";\r
684 \r
685     if (s < 0)\r
686     {\r
687       p = "-";\r
688     }\r
689     else if (s > 0)\r
690     {\r
691       if (show_plus)\r
692       {\r
693         p = "+";\r
694       }\r
695       else if (show_space)\r
696       {\r
697         p = " ";\r
698       }\r
699     }\r
700     else\r
701     {\r
702       if ( (fmt == 'o') && alternate && (r.length() > 0) &&\r
703           (r.charAt(0) != '0'))\r
704       {\r
705         p = "0";\r
706       }\r
707       else if ( (fmt == 'x') && alternate)\r
708       {\r
709         p = "0x";\r
710       }\r
711       else if ( (fmt == 'X') && alternate)\r
712       {\r
713         p = "0X";\r
714       }\r
715     }\r
716 \r
717     int w = 0;\r
718 \r
719     if (leading_zeroes)\r
720     {\r
721       w = width;\r
722     }\r
723     else if ( ( (fmt == 'd') || (fmt == 'i') || (fmt == 'x') || (fmt == 'X') ||\r
724                (fmt == 'o')) && (precision > 0))\r
725     {\r
726       w = precision;\r
727     }\r
728 \r
729     return p + repeat('0', w - p.length() - r.length()) + r;\r
730   }\r
731 \r
732   /**\r
733    * DOCUMENT ME!\r
734    *\r
735    * @param d DOCUMENT ME!\r
736    *\r
737    * @return DOCUMENT ME!\r
738    */\r
739   private String fixed_format(double d)\r
740   {\r
741     boolean removeTrailing = ( (fmt == 'G') || (fmt == 'g')) && !alternate;\r
742 \r
743     // remove trailing zeroes and decimal point\r
744     if (d > 0x7FFFFFFFFFFFFFFFL)\r
745     {\r
746       return exp_format(d);\r
747     }\r
748 \r
749     if (precision == 0)\r
750     {\r
751       return (long) (d + 0.5) + (removeTrailing ? "" : ".");\r
752     }\r
753 \r
754     long whole = (long) d;\r
755     double fr = d - whole; // fractional part\r
756 \r
757     if ( (fr >= 1) || (fr < 0))\r
758     {\r
759       return exp_format(d);\r
760     }\r
761 \r
762     double factor = 1;\r
763     String leading_zeroes = "";\r
764 \r
765     for (int i = 1; (i <= precision) && (factor <= 0x7FFFFFFFFFFFFFFFL);\r
766          i++)\r
767     {\r
768       factor *= 10;\r
769       leading_zeroes = leading_zeroes + "0";\r
770     }\r
771 \r
772     long l = (long) ( (factor * fr) + 0.5);\r
773 \r
774     if (l >= factor)\r
775     {\r
776       l = 0;\r
777       whole++;\r
778     }\r
779 \r
780     // CSH 10-25-97\r
781     String z = leading_zeroes + l;\r
782     z = "." + z.substring(z.length() - precision, z.length());\r
783 \r
784     if (removeTrailing)\r
785     {\r
786       int t = z.length() - 1;\r
787 \r
788       while ( (t >= 0) && (z.charAt(t) == '0'))\r
789       {\r
790         t--;\r
791       }\r
792 \r
793       if ( (t >= 0) && (z.charAt(t) == '.'))\r
794       {\r
795         t--;\r
796       }\r
797 \r
798       z = z.substring(0, t + 1);\r
799     }\r
800 \r
801     return whole + z;\r
802   }\r
803 \r
804   /**\r
805    * DOCUMENT ME!\r
806    *\r
807    * @param d DOCUMENT ME!\r
808    *\r
809    * @return DOCUMENT ME!\r
810    */\r
811   private String exp_format(double d)\r
812   {\r
813     String f = "";\r
814     int e = 0;\r
815     double dd = d;\r
816     double factor = 1;\r
817 \r
818     if (d != 0)\r
819     {\r
820       while (dd > 10)\r
821       {\r
822         e++;\r
823         factor /= 10;\r
824         dd = dd / 10;\r
825       }\r
826 \r
827       while (dd < 1)\r
828       {\r
829         e--;\r
830         factor *= 10;\r
831         dd = dd * 10;\r
832       }\r
833     }\r
834 \r
835     if ( ( (fmt == 'g') || (fmt == 'G')) && (e >= -4) && (e < precision))\r
836     {\r
837       return fixed_format(d);\r
838     }\r
839 \r
840     d = d * factor;\r
841     f = f + fixed_format(d);\r
842 \r
843     if ( (fmt == 'e') || (fmt == 'g'))\r
844     {\r
845       f = f + "e";\r
846     }\r
847     else\r
848     {\r
849       f = f + "E";\r
850     }\r
851 \r
852     String p = "000";\r
853 \r
854     if (e >= 0)\r
855     {\r
856       f = f + "+";\r
857       p = p + e;\r
858     }\r
859     else\r
860     {\r
861       f = f + "-";\r
862       p = p + ( -e);\r
863     }\r
864 \r
865     return f + p.substring(p.length() - 3, p.length());\r
866   }\r
867 }\r