001: /*
002: * StringFunctions.java
003: *
004: * Copyright (C) 2003-2004 Peter Graves
005: * $Id: StringFunctions.java,v 1.28 2004/09/21 00:39:47 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.lisp;
023:
024: public final class StringFunctions extends Lisp {
025: // ### %string=
026: // Case sensitive.
027: private static final Primitive _STRING_EQUAL = new Primitive(
028: "%string=", PACKAGE_SYS, false) {
029: public LispObject execute(LispObject[] args)
030: throws ConditionThrowable {
031: if (args.length != 6)
032: return signal(new WrongNumberOfArgumentsException(this ));
033: char[] array1 = args[0].STRING().getStringChars();
034: char[] array2 = args[1].STRING().getStringChars();
035: int start1, end1, start2, end2;
036: try {
037: start1 = ((Fixnum) args[2]).value;
038: } catch (ClassCastException e) {
039: return signal(new TypeError(args[2], Symbol.FIXNUM));
040: }
041: if (args[3] == NIL) {
042: end1 = array1.length;
043: } else {
044: try {
045: end1 = ((Fixnum) args[3]).value;
046: } catch (ClassCastException e) {
047: return signal(new TypeError(args[3], Symbol.FIXNUM));
048: }
049: }
050: try {
051: start2 = ((Fixnum) args[4]).value;
052: } catch (ClassCastException e) {
053: return signal(new TypeError(args[4], Symbol.FIXNUM));
054: }
055: if (args[5] == NIL) {
056: end2 = array2.length;
057: } else {
058: try {
059: end2 = ((Fixnum) args[5]).value;
060: } catch (ClassCastException e) {
061: return signal(new TypeError(args[5], Symbol.FIXNUM));
062: }
063: }
064: if ((end1 - start1) != (end2 - start2))
065: return NIL;
066: try {
067: for (int i = start1, j = start2; i < end1; i++, j++) {
068: if (array1[i] != array2[j])
069: return NIL;
070: }
071: } catch (ArrayIndexOutOfBoundsException e) {
072: // Shouldn't happen.
073: Debug.trace(e);
074: return NIL;
075: }
076: return T;
077: }
078: };
079:
080: // ### %%string=
081: // Case sensitive.
082: private static final Primitive2 __STRING_EQUAL = new Primitive2(
083: "%%string=", PACKAGE_SYS, false) {
084: public LispObject execute(LispObject first, LispObject second)
085: throws ConditionThrowable {
086: char[] array1 = first.STRING().getStringChars();
087: char[] array2 = second.STRING().getStringChars();
088: if (array1.length != array2.length)
089: return NIL;
090: for (int i = array1.length; i-- > 0;) {
091: if (array1[i] != array2[i])
092: return NIL;
093: }
094: return T;
095: }
096: };
097:
098: // ### %string/=
099: // Case sensitive.
100: private static final Primitive _STRING_NOT_EQUAL = new Primitive(
101: "%string/=", PACKAGE_SYS, true) {
102: public LispObject execute(LispObject[] args)
103: throws ConditionThrowable {
104: if (args.length != 6)
105: return signal(new WrongNumberOfArgumentsException(this ));
106: char[] array1 = args[0].STRING().getStringChars();
107: char[] array2 = args[1].STRING().getStringChars();
108: int start1 = Fixnum.getInt(args[2]);
109: int end1 = Fixnum.getInt(args[3]);
110: int start2 = Fixnum.getInt(args[4]);
111: int end2 = Fixnum.getInt(args[5]);
112: int i = start1;
113: int j = start2;
114: while (true) {
115: if (i == end1) {
116: // Reached end of string1.
117: if (j == end2)
118: return NIL; // Strings are identical.
119: return new Fixnum(i);
120: }
121: if (j == end2) {
122: // Reached end of string2 before end of string1.
123: return new Fixnum(i);
124: }
125: if (array1[i] != array2[j])
126: return new Fixnum(i);
127: ++i;
128: ++j;
129: }
130: }
131: };
132:
133: // ### %string-equal
134: // Case insensitive.
135: private static final Primitive _STRING_EQUAL_IGNORE_CASE = new Primitive(
136: "%string-equal", PACKAGE_SYS, true) {
137: public LispObject execute(LispObject[] args)
138: throws ConditionThrowable {
139: if (args.length != 6)
140: return signal(new WrongNumberOfArgumentsException(this ));
141: char[] array1 = args[0].STRING().getStringChars();
142: char[] array2 = args[1].STRING().getStringChars();
143: int start1 = Fixnum.getInt(args[2]);
144: int end1 = Fixnum.getInt(args[3]);
145: int start2 = Fixnum.getInt(args[4]);
146: int end2 = Fixnum.getInt(args[5]);
147: if ((end1 - start1) != (end2 - start2))
148: return NIL;
149: int i, j;
150: for (i = start1, j = start2; i < end1; i++, j++) {
151: char c1 = array1[i];
152: char c2 = array2[j];
153: if (c1 == c2)
154: continue;
155: if (Utilities.toUpperCase(c1) == Utilities
156: .toUpperCase(c2))
157: continue;
158: if (Utilities.toLowerCase(c1) == Utilities
159: .toLowerCase(c2))
160: continue;
161: return NIL;
162: }
163: return T;
164: }
165: };
166:
167: // ### %string-not-equal
168: // Case sensitive.
169: private static final Primitive _STRING_NOT_EQUAL_IGNORE_CASE = new Primitive(
170: "%string-not-equal", PACKAGE_SYS, true) {
171: public LispObject execute(LispObject[] args)
172: throws ConditionThrowable {
173: if (args.length != 6)
174: return signal(new WrongNumberOfArgumentsException(this ));
175: char[] array1 = args[0].STRING().getStringChars();
176: char[] array2 = args[1].STRING().getStringChars();
177: int start1 = Fixnum.getInt(args[2]);
178: int end1 = Fixnum.getInt(args[3]);
179: int start2 = Fixnum.getInt(args[4]);
180: int end2 = Fixnum.getInt(args[5]);
181: int i = start1;
182: int j = start2;
183: while (true) {
184: if (i == end1) {
185: // Reached end of string1.
186: if (j == end2)
187: return NIL; // Strings are identical.
188: return new Fixnum(i);
189: }
190: if (j == end2) {
191: // Reached end of string2.
192: return new Fixnum(i);
193: }
194: char c1 = array1[i];
195: char c2 = array2[j];
196: if (c1 == c2
197: || Utilities.toUpperCase(c1) == Utilities
198: .toUpperCase(c2)
199: || Utilities.toLowerCase(c1) == Utilities
200: .toLowerCase(c2)) {
201: ++i;
202: ++j;
203: continue;
204: }
205: return new Fixnum(i);
206: }
207: }
208: };
209:
210: // ### %string<
211: // Case sensitive.
212: private static final Primitive _STRING_LESS_THAN = new Primitive(
213: "%string<", PACKAGE_SYS, true) {
214: public LispObject execute(LispObject[] args)
215: throws ConditionThrowable {
216: if (args.length != 6)
217: return signal(new WrongNumberOfArgumentsException(this ));
218: char[] array1 = args[0].STRING().getStringChars();
219: char[] array2 = args[1].STRING().getStringChars();
220: int start1 = Fixnum.getInt(args[2]);
221: int end1 = Fixnum.getInt(args[3]);
222: int start2 = Fixnum.getInt(args[4]);
223: int end2 = Fixnum.getInt(args[5]);
224: int i = start1;
225: int j = start2;
226: while (true) {
227: if (i == end1) {
228: // Reached end of string1.
229: if (j == end2)
230: return NIL; // Strings are identical.
231: return new Fixnum(i);
232: }
233: if (j == end2) {
234: // Reached end of string2.
235: return NIL;
236: }
237: char c1 = array1[i];
238: char c2 = array2[j];
239: if (c1 == c2) {
240: ++i;
241: ++j;
242: continue;
243: }
244: if (c1 < c2)
245: return new Fixnum(i);
246: // c1 > c2
247: return NIL;
248: }
249: }
250: };
251:
252: // ### %string<=
253: // Case sensitive.
254: private static final Primitive _STRING_GREATER_THAN = new Primitive(
255: "%string>", PACKAGE_SYS, true) {
256: public LispObject execute(LispObject[] args)
257: throws ConditionThrowable {
258: if (args.length != 6)
259: return signal(new WrongNumberOfArgumentsException(this ));
260: char[] array1 = args[0].STRING().getStringChars();
261: char[] array2 = args[1].STRING().getStringChars();
262: int start1 = Fixnum.getInt(args[2]);
263: int end1 = Fixnum.getInt(args[3]);
264: int start2 = Fixnum.getInt(args[4]);
265: int end2 = Fixnum.getInt(args[5]);
266: int i = start1;
267: int j = start2;
268: while (true) {
269: if (i == end1) {
270: // Reached end of string1.
271: return NIL;
272: }
273: if (j == end2) {
274: // Reached end of string2.
275: return new Fixnum(i);
276: }
277: char c1 = array1[i];
278: char c2 = array2[j];
279: if (c1 == c2) {
280: ++i;
281: ++j;
282: continue;
283: }
284: if (c1 < c2)
285: return NIL;
286: // c1 > c2
287: return new Fixnum(i);
288: }
289: }
290: };
291:
292: // ### %string<=
293: // Case sensitive.
294: private static final Primitive _STRING_LE = new Primitive(
295: "%string<=", PACKAGE_SYS, true) {
296: public LispObject execute(LispObject[] args)
297: throws ConditionThrowable {
298: if (args.length != 6)
299: return signal(new WrongNumberOfArgumentsException(this ));
300: char[] array1 = args[0].STRING().getStringChars();
301: char[] array2 = args[1].STRING().getStringChars();
302: int start1 = Fixnum.getInt(args[2]);
303: int end1 = Fixnum.getInt(args[3]);
304: int start2 = Fixnum.getInt(args[4]);
305: int end2 = Fixnum.getInt(args[5]);
306: int i = start1;
307: int j = start2;
308: while (true) {
309: if (i == end1) {
310: // Reached end of string1.
311: return new Fixnum(i);
312: }
313: if (j == end2) {
314: // Reached end of string2.
315: return NIL;
316: }
317: char c1 = array1[i];
318: char c2 = array2[j];
319: if (c1 == c2) {
320: ++i;
321: ++j;
322: continue;
323: }
324: if (c1 > c2)
325: return NIL;
326: // c1 < c2
327: return new Fixnum(i);
328: }
329: }
330: };
331:
332: // ### %string<=
333: // Case sensitive.
334: private static final Primitive _STRING_GE = new Primitive(
335: "%string>=", PACKAGE_SYS, true) {
336: public LispObject execute(LispObject[] args)
337: throws ConditionThrowable {
338: if (args.length != 6)
339: return signal(new WrongNumberOfArgumentsException(this ));
340: char[] array1 = args[0].STRING().getStringChars();
341: char[] array2 = args[1].STRING().getStringChars();
342: int start1 = Fixnum.getInt(args[2]);
343: int end1 = Fixnum.getInt(args[3]);
344: int start2 = Fixnum.getInt(args[4]);
345: int end2 = Fixnum.getInt(args[5]);
346: int i = start1;
347: int j = start2;
348: while (true) {
349: if (i == end1) {
350: // Reached end of string1.
351: if (j == end2)
352: return new Fixnum(i); // Strings are identical.
353: return NIL;
354: }
355: if (j == end2) {
356: // Reached end of string2.
357: return new Fixnum(i);
358: }
359: char c1 = array1[i];
360: char c2 = array2[j];
361: if (c1 == c2) {
362: ++i;
363: ++j;
364: continue;
365: }
366: if (c1 < c2)
367: return NIL;
368: // c1 > c2
369: return new Fixnum(i);
370: }
371: }
372: };
373:
374: // ### %string-lessp
375: // Case insensitive.
376: private static final Primitive _STRING_LESSP = new Primitive(
377: "%string-lessp", PACKAGE_SYS, true) {
378: public LispObject execute(LispObject[] args)
379: throws ConditionThrowable {
380: if (args.length != 6)
381: return signal(new WrongNumberOfArgumentsException(this ));
382: char[] array1 = args[0].STRING().getStringChars();
383: char[] array2 = args[1].STRING().getStringChars();
384: int start1 = Fixnum.getInt(args[2]);
385: int end1 = Fixnum.getInt(args[3]);
386: int start2 = Fixnum.getInt(args[4]);
387: int end2 = Fixnum.getInt(args[5]);
388: int i = start1;
389: int j = start2;
390: while (true) {
391: if (i == end1) {
392: // Reached end of string1.
393: if (j == end2)
394: return NIL; // Strings are identical.
395: return new Fixnum(i);
396: }
397: if (j == end2) {
398: // Reached end of string2.
399: return NIL;
400: }
401: char c1 = Utilities.toUpperCase(array1[i]);
402: char c2 = Utilities.toUpperCase(array2[j]);
403: if (c1 == c2) {
404: ++i;
405: ++j;
406: continue;
407: }
408: if (c1 > c2)
409: return NIL;
410: // c1 < c2
411: return new Fixnum(i);
412: }
413: }
414: };
415:
416: // ### %string-greaterp
417: // Case insensitive.
418: private static final Primitive _STRING_GREATERP = new Primitive(
419: "%string-greaterp", PACKAGE_SYS, true) {
420: public LispObject execute(LispObject[] args)
421: throws ConditionThrowable {
422: if (args.length != 6)
423: return signal(new WrongNumberOfArgumentsException(this ));
424: char[] array1 = args[0].STRING().getStringChars();
425: char[] array2 = args[1].STRING().getStringChars();
426: int start1 = Fixnum.getInt(args[2]);
427: int end1 = Fixnum.getInt(args[3]);
428: int start2 = Fixnum.getInt(args[4]);
429: int end2 = Fixnum.getInt(args[5]);
430: int i = start1;
431: int j = start2;
432: while (true) {
433: if (i == end1) {
434: // Reached end of string1.
435: return NIL;
436: }
437: if (j == end2) {
438: // Reached end of string2.
439: return new Fixnum(i);
440: }
441: char c1 = Utilities.toUpperCase(array1[i]);
442: char c2 = Utilities.toUpperCase(array2[j]);
443: if (c1 == c2) {
444: ++i;
445: ++j;
446: continue;
447: }
448: if (c1 < c2)
449: return NIL;
450: // c1 > c2
451: return new Fixnum(i);
452: }
453: }
454: };
455:
456: // ### %string-not-lessp
457: // Case insensitive.
458: private static final Primitive _STRING_NOT_LESSP = new Primitive(
459: "%string-not-lessp", PACKAGE_SYS, true) {
460: public LispObject execute(LispObject[] args)
461: throws ConditionThrowable {
462: if (args.length != 6)
463: return signal(new WrongNumberOfArgumentsException(this ));
464: char[] array1 = args[0].STRING().getStringChars();
465: char[] array2 = args[1].STRING().getStringChars();
466: int start1 = Fixnum.getInt(args[2]);
467: int end1 = Fixnum.getInt(args[3]);
468: int start2 = Fixnum.getInt(args[4]);
469: int end2 = Fixnum.getInt(args[5]);
470: int i = start1;
471: int j = start2;
472: while (true) {
473: if (i == end1) {
474: // Reached end of string1.
475: if (j == end2)
476: return new Fixnum(i); // Strings are identical.
477: return NIL;
478: }
479: if (j == end2) {
480: // Reached end of string2.
481: return new Fixnum(i);
482: }
483: char c1 = Utilities.toUpperCase(array1[i]);
484: char c2 = Utilities.toUpperCase(array2[j]);
485: if (c1 == c2) {
486: ++i;
487: ++j;
488: continue;
489: }
490: if (c1 > c2)
491: return new Fixnum(i);
492: // c1 < c2
493: return NIL;
494: }
495: }
496: };
497:
498: // ### %string-not-greaterp
499: // Case insensitive.
500: private static final Primitive _STRING_NOT_GREATERP = new Primitive(
501: "%string-not-greaterp", PACKAGE_SYS, true) {
502: public LispObject execute(LispObject[] args)
503: throws ConditionThrowable {
504: if (args.length != 6)
505: return signal(new WrongNumberOfArgumentsException(this ));
506: char[] array1 = args[0].STRING().getStringChars();
507: char[] array2 = args[1].STRING().getStringChars();
508: int start1 = Fixnum.getInt(args[2]);
509: int end1 = Fixnum.getInt(args[3]);
510: int start2 = Fixnum.getInt(args[4]);
511: int end2 = Fixnum.getInt(args[5]);
512: int i = start1;
513: int j = start2;
514: while (true) {
515: if (i == end1) {
516: // Reached end of string1.
517: return new Fixnum(i);
518: }
519: if (j == end2) {
520: // Reached end of string2.
521: return NIL;
522: }
523: char c1 = Utilities.toUpperCase(array1[i]);
524: char c2 = Utilities.toUpperCase(array2[j]);
525: if (c1 == c2) {
526: ++i;
527: ++j;
528: continue;
529: }
530: if (c1 > c2)
531: return NIL;
532: // c1 < c2
533: return new Fixnum(i);
534: }
535: }
536: };
537:
538: // ### %string-upcase
539: private static final Primitive3 _STRING_UPCASE = new Primitive3(
540: "%string-upcase", PACKAGE_SYS, true) {
541: public LispObject execute(LispObject first, LispObject second,
542: LispObject third) throws ConditionThrowable {
543: LispObject s = first.STRING();
544: final int length = s.length();
545: int start = (int) Fixnum.getValue(second);
546: if (start < 0 || start > length)
547: return signal(new TypeError("Invalid start position "
548: + start + "."));
549: int end;
550: if (third == NIL)
551: end = length;
552: else
553: end = (int) Fixnum.getValue(third);
554: if (end < 0 || end > length)
555: return signal(new TypeError("Invalid end position "
556: + start + "."));
557: if (start > end)
558: return signal(new TypeError("Start (" + start
559: + ") is greater than end (" + end + ")."));
560: StringBuffer sb = new StringBuffer(length);
561: char[] array = s.getStringChars();
562: int i;
563: for (i = 0; i < start; i++)
564: sb.append(array[i]);
565: for (i = start; i < end; i++)
566: sb.append(Utilities.toUpperCase(array[i]));
567: for (i = end; i < length; i++)
568: sb.append(array[i]);
569: return new SimpleString(sb);
570: }
571: };
572:
573: // ### %string-downcase
574: private static final Primitive3 _STRING_DOWNCASE = new Primitive3(
575: "%string-downcase", PACKAGE_SYS, true) {
576: public LispObject execute(LispObject first, LispObject second,
577: LispObject third) throws ConditionThrowable {
578: LispObject s = first.STRING();
579: final int length = s.length();
580: int start = (int) Fixnum.getValue(second);
581: if (start < 0 || start > length)
582: return signal(new TypeError("Invalid start position "
583: + start + "."));
584: int end;
585: if (third == NIL)
586: end = length;
587: else
588: end = (int) Fixnum.getValue(third);
589: if (end < 0 || end > length)
590: return signal(new TypeError("Invalid end position "
591: + start + "."));
592: if (start > end)
593: return signal(new TypeError("Start (" + start
594: + ") is greater than end (" + end + ")."));
595: StringBuffer sb = new StringBuffer(length);
596: char[] array = s.getStringChars();
597: int i;
598: for (i = 0; i < start; i++)
599: sb.append(array[i]);
600: for (i = start; i < end; i++)
601: sb.append(Utilities.toLowerCase(array[i]));
602: for (i = end; i < length; i++)
603: sb.append(array[i]);
604: return new SimpleString(sb);
605: }
606: };
607:
608: // ### %string-capitalize
609: private static final Primitive3 _STRING_CAPITALIZE = new Primitive3(
610: "%string-capitalize", PACKAGE_SYS, true) {
611: public LispObject execute(LispObject first, LispObject second,
612: LispObject third) throws ConditionThrowable {
613: LispObject s = first.STRING();
614: final int length = s.length();
615: int start = (int) Fixnum.getValue(second);
616: if (start < 0 || start > length)
617: return signal(new TypeError("Invalid start position "
618: + start + "."));
619: int end;
620: if (third == NIL)
621: end = length;
622: else
623: end = (int) Fixnum.getValue(third);
624: if (end < 0 || end > length)
625: return signal(new TypeError("Invalid end position "
626: + start + "."));
627: if (start > end)
628: return signal(new TypeError("Start (" + start
629: + ") is greater than end (" + end + ")."));
630: StringBuffer sb = new StringBuffer(length);
631: char[] array = s.getStringChars();
632: boolean lastCharWasAlphanumeric = false;
633: int i;
634: for (i = 0; i < start; i++)
635: sb.append(array[i]);
636: for (i = start; i < end; i++) {
637: char c = array[i];
638: if (Character.isLowerCase(c)) {
639: sb.append(lastCharWasAlphanumeric ? c : Utilities
640: .toUpperCase(c));
641: lastCharWasAlphanumeric = true;
642: } else if (Character.isUpperCase(c)) {
643: sb.append(lastCharWasAlphanumeric ? Utilities
644: .toLowerCase(c) : c);
645: lastCharWasAlphanumeric = true;
646: } else {
647: sb.append(c);
648: lastCharWasAlphanumeric = Character.isDigit(c);
649: }
650: }
651: for (i = end; i < length; i++)
652: sb.append(array[i]);
653: return new SimpleString(sb);
654: }
655: };
656:
657: // ### %nstring-upcase
658: private static final Primitive3 _NSTRING_UPCASE = new Primitive3(
659: "%nstring-upcase", PACKAGE_SYS, true) {
660: public LispObject execute(LispObject first, LispObject second,
661: LispObject third) throws ConditionThrowable {
662: AbstractString string;
663: try {
664: string = (AbstractString) first;
665: } catch (ClassCastException e) {
666: return signal(new TypeError(first, Symbol.STRING));
667: }
668: final int length = string.length();
669: int start = (int) Fixnum.getValue(second);
670: if (start < 0 || start > length)
671: return signal(new TypeError("Invalid start position "
672: + start + "."));
673: int end;
674: if (third == NIL)
675: end = length;
676: else
677: end = (int) Fixnum.getValue(third);
678: if (end < 0 || end > length)
679: return signal(new TypeError("Invalid end position "
680: + start + "."));
681: if (start > end)
682: return signal(new TypeError("Start (" + start
683: + ") is greater than end (" + end + ")."));
684: for (int i = start; i < end; i++)
685: string.setChar(i, Utilities.toUpperCase(string
686: .getChar(i)));
687: return string;
688: }
689: };
690:
691: // ### %nstring-downcase
692: private static final Primitive3 _NSTRING_DOWNCASE = new Primitive3(
693: "%nstring-downcase", PACKAGE_SYS, true) {
694: public LispObject execute(LispObject first, LispObject second,
695: LispObject third) throws ConditionThrowable {
696: AbstractString string;
697: try {
698: string = (AbstractString) first;
699: } catch (ClassCastException e) {
700: return signal(new TypeError(first, Symbol.STRING));
701: }
702: final int length = string.length();
703: int start = (int) Fixnum.getValue(second);
704: if (start < 0 || start > length)
705: return signal(new TypeError("Invalid start position "
706: + start + "."));
707: int end;
708: if (third == NIL)
709: end = length;
710: else
711: end = (int) Fixnum.getValue(third);
712: if (end < 0 || end > length)
713: return signal(new TypeError("Invalid end position "
714: + start + "."));
715: if (start > end)
716: return signal(new TypeError("Start (" + start
717: + ") is greater than end (" + end + ")."));
718: for (int i = start; i < end; i++)
719: string.setChar(i, Utilities.toLowerCase(string
720: .getChar(i)));
721: return string;
722: }
723: };
724:
725: // ### %nstring-capitalize
726: private static final Primitive3 _NSTRING_CAPITALIZE = new Primitive3(
727: "%nstring-capitalize", PACKAGE_SYS, true) {
728: public LispObject execute(LispObject first, LispObject second,
729: LispObject third) throws ConditionThrowable {
730: AbstractString string;
731: try {
732: string = (AbstractString) first;
733: } catch (ClassCastException e) {
734: return signal(new TypeError(first, Symbol.STRING));
735: }
736: final int length = string.length();
737: int start = (int) Fixnum.getValue(second);
738: if (start < 0 || start > length)
739: return signal(new TypeError("Invalid start position "
740: + start + "."));
741: int end;
742: if (third == NIL)
743: end = length;
744: else
745: end = (int) Fixnum.getValue(third);
746: if (end < 0 || end > length)
747: return signal(new TypeError("Invalid end position "
748: + start + "."));
749: if (start > end)
750: return signal(new TypeError("Start (" + start
751: + ") is greater than end (" + end + ")."));
752: boolean lastCharWasAlphanumeric = false;
753: for (int i = start; i < end; i++) {
754: char c = string.getChar(i);
755: if (Character.isLowerCase(c)) {
756: if (!lastCharWasAlphanumeric)
757: string.setChar(i, Utilities.toUpperCase(c));
758: lastCharWasAlphanumeric = true;
759: } else if (Character.isUpperCase(c)) {
760: if (lastCharWasAlphanumeric)
761: string.setChar(i, Utilities.toLowerCase(c));
762: lastCharWasAlphanumeric = true;
763: } else
764: lastCharWasAlphanumeric = Character.isDigit(c);
765: }
766: return string;
767: }
768: };
769:
770: // ### stringp
771: public static final Primitive1 STRINGP = new Primitive1("stringp",
772: "object") {
773: public LispObject execute(LispObject arg)
774: throws ConditionThrowable {
775: return arg.STRINGP();
776: }
777: };
778:
779: // ### simple-string-p
780: public static final Primitive1 SIMPLE_STRING_P = new Primitive1(
781: "simple-string-p", "object") {
782: public LispObject execute(LispObject arg)
783: throws ConditionThrowable {
784: return arg.SIMPLE_STRING_P();
785: }
786: };
787:
788: // ### %make-string
789: // %make-string size initial-element element-type => string
790: // Returns a simple string.
791: private static final Primitive3 _MAKE_STRING = new Primitive3(
792: "%make-string", PACKAGE_SYS, false) {
793: public LispObject execute(LispObject size,
794: LispObject initialElement, LispObject elementType)
795: throws ConditionThrowable {
796: final int n;
797: try {
798: n = ((Fixnum) size).value;
799: } catch (ClassCastException e) {
800: return signal(new TypeError(size, Symbol.FIXNUM));
801: }
802: if (n < 0 || n >= ARRAY_DIMENSION_MAX) {
803: StringBuffer sb = new StringBuffer();
804: sb.append("The size specified for this string (");
805: sb.append(n);
806: sb.append(')');
807: if (n >= ARRAY_DIMENSION_MAX) {
808: sb.append(" is >= ARRAY-DIMENSION-LIMIT (");
809: sb.append(ARRAY_DIMENSION_MAX);
810: sb.append(").");
811: } else
812: sb.append(" is negative.");
813: return signal(new LispError(sb.toString()));
814: }
815: // Ignore elementType.
816: SimpleString string = new SimpleString(n);
817: if (initialElement != NIL) {
818: // Initial element was specified.
819: char c = checkCharacter(initialElement).getValue();
820: string.fill(c);
821: }
822: return string;
823: }
824: };
825:
826: // ### char
827: private static final Primitive2 CHAR = new Primitive2("char",
828: "string index") {
829: public LispObject execute(LispObject first, LispObject second)
830: throws ConditionThrowable {
831: try {
832: return ((AbstractString) first)
833: .getRowMajor(((Fixnum) second).value);
834: } catch (ClassCastException e) {
835: if (first instanceof AbstractString)
836: return signal(new TypeError(second, Symbol.FIXNUM));
837: else
838: return signal(new TypeError(first, Symbol.STRING));
839: }
840: }
841: };
842:
843: // ### %set-char
844: private static final Primitive3 _SET_CHAR = new Primitive3(
845: "%set-char", PACKAGE_SYS, false) {
846: public LispObject execute(LispObject first, LispObject second,
847: LispObject third) throws ConditionThrowable {
848: try {
849: ((AbstractString) first).setRowMajor(
850: ((Fixnum) second).value,
851: ((LispCharacter) third));
852: return third;
853: } catch (ClassCastException e) {
854: if (!(first instanceof AbstractString))
855: return signal(new TypeError(first, Symbol.STRING));
856: else if (!(second instanceof Fixnum))
857: return signal(new TypeError(second, Symbol.FIXNUM));
858: else
859: return signal(new TypeError(third, Symbol.CHARACTER));
860: }
861: }
862: };
863:
864: // ### string-position
865: private static final Primitive3 STRING_POSITION = new Primitive3(
866: "string-position", PACKAGE_EXT, true) {
867: public LispObject execute(LispObject first, LispObject second,
868: LispObject third) throws ConditionThrowable {
869: char c = LispCharacter.getValue(first);
870: AbstractString string;
871: if (second instanceof AbstractString)
872: string = (AbstractString) second;
873: else
874: return signal(new TypeError(second, Symbol.STRING));
875: int start = Fixnum.getValue(third);
876: for (int i = start, limit = string.length(); i < limit; i++) {
877: if (string.getChar(i) == c)
878: return number(i);
879: }
880: return NIL;
881: }
882: };
883:
884: // ### simple-string-search pattern string => position
885: // Searches string for a substring that matches pattern.
886: private static final Primitive2 SIMPLE_STRING_SEARCH = new Primitive2(
887: "simple-string-search", PACKAGE_EXT, true) {
888: public LispObject execute(LispObject first, LispObject second)
889: throws ConditionThrowable {
890: // FIXME Don't call getStringValue() here! (Just look at the chars.)
891: int index = second.getStringValue().indexOf(
892: first.getStringValue());
893: return index >= 0 ? new Fixnum(index) : NIL;
894: }
895: };
896:
897: // ### simple-string-fill string character => string
898: private static final Primitive2 STRING_FILL = new Primitive2(
899: "simple-string-fill", PACKAGE_EXT, true) {
900: public LispObject execute(LispObject first, LispObject second)
901: throws ConditionThrowable {
902: try {
903: AbstractString s = (AbstractString) first;
904: s.fill(LispCharacter.getValue(second));
905: return first;
906: } catch (ClassCastException e) {
907: return signal(new TypeError(first, Symbol.SIMPLE_STRING));
908: }
909: }
910: };
911: }
|