|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 27190 (0x6a36) Types: TextFile Names: »string.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─⟦this⟧ »EUUGD11/gnu-31mar87/scheme/microcode/string.c«
/* Hey EMACS, this is -*- C -*- code! */ /**************************************************************** * * * Copyright (c) 1984 * * Massachusetts Institute of Technology * * * * This material was developed by the Scheme project at the * * Massachusetts Institute of Technology, Department of * * Electrical Engineering and Computer Science. Permission to * * copy this software, to redistribute it, and to use it for any * * purpose is granted, subject to the following restrictions and * * understandings. * * * * 1. Any copy made of this software must include this copyright * * notice in full. * * * * 2. Users of this software agree to make their best efforts (a)* * to return to the MIT Scheme project any improvements or * * extensions that they make, so that these may be included in * * future releases; and (b) to inform MIT of noteworthy uses of * * this software. * * * * 3. All materials developed as a consequence of the use of * * this software shall duly acknowledge such use, in accordance * * with the usual standards of acknowledging credit in academic * * research. * * * * 4. MIT has made no warrantee or representation that the * * operation of this software will be error-free, and MIT is * * under no obligation to provide any services, by way of * * maintenance, update, or otherwise. * * * * 5. In conjunction with products arising from the use of this * * material, there shall be no use of the name of the * * Massachusetts Institute of Technology nor of any adaptation * * thereof in any advertising, promotional, or sales literature * * without prior written consent from MIT in each case. * * * ****************************************************************/ \f /* File: STRING.C * * Support for strings and conversion to and from lists of characters. */ #include "scheme.h" #include "primitive.h" /****************************/ /* Making Character Strings */ /****************************/ #define Empty_String() \ Pointer_Count = 2 + 1 + (Get_Integer(Arg1)/sizeof(Pointer)); \ Primitive_GC_If_Needed(Free + Pointer_Count); \ Free[STRING_HEADER] = \ Make_Non_Pointer(TC_MANIFEST_NM_VECTOR, Pointer_Count-1); \ Free[STRING_LENGTH] = FIXNUM_0; \ /* put a null in first character position */ \ (*((char *) (Free + STRING_CHARS))) = '\0'; \ Free += Pointer_Count; Built_In_Primitive(Prim_Make_Empty_String, 1, "MAKE-EMPTY-STRING") { long Pointer_Count; Primitive_1_Arg(); Arg_1_Type(TC_FIXNUM); Empty_String(); return Make_Pointer(TC_CHARACTER_STRING, Free-Pointer_Count); } \f Built_In_Primitive(Prim_Make_Fld_String, 2, "MAKE-FILLED-STRING") { Pointer Result; long C, i, Pointer_Count, Count; char *P; Primitive_2_Args(); Arg_1_Type(TC_FIXNUM); Arg_2_Type(TC_FIXNUM); Range_Check(C, Arg2, 0, 255, ERR_ARG_2_BAD_RANGE); Empty_String(); Result = Make_Pointer(TC_CHARACTER_STRING, Free-Pointer_Count); P = (char *) Nth_Vector_Loc(Result, STRING_CHARS); Count = Get_Integer(Arg1); for (i=0; i < Count; i++) *P++ = C; *P++ = '\0'; /* Add null */ Vector_Set(Result, STRING_LENGTH, FIXNUM_0+Count); return Make_Pointer(TC_CHARACTER_STRING, Free-Pointer_Count); } /* Bit Blit. Moves an arbitrary string of bits to an arbitrary place Given: Pointer to source string, Pointer to a pointer to destination string, Source offset, a pointer to destination offset and the number of bits to be moved. Updates the destination pointer and offset. */ #define Down_Shift(Word,Offset) \ (((Word) >> Offset) & ((1 << (POINTER_LENGTH-Offset))-1)) #define Up_Shift(Word,Offset) \ ((Word) << Offset) \f Shift_Bit_String(Source, Dest_Ptr, Source_Offset, Dest_Offset_Ptr, Bit_Count) long *Source, **Dest_Ptr, Source_Offset, *Dest_Offset_Ptr, Bit_Count; { long Offset, Count, Shift, Mask, i, Remainder_Bits, *Dest = *Dest_Ptr, D_Offset = *Dest_Offset_Ptr; Offset = Source_Offset-D_Offset; if (Offset == 0) if(Bit_Count+Source_Offset <= POINTER_LENGTH) { Mask=(1 << Bit_Count)-1; Mask=(Mask << Source_Offset); *Dest = (*Source & Mask) | (*Dest & ~Mask); if(Bit_Count+Source_Offset == POINTER_LENGTH) Dest++; *Dest_Offset_Ptr = (*Dest_Offset_Ptr+Bit_Count)%POINTER_LENGTH; *Dest_Ptr = Dest; return; } /* Special Case */ else { Mask = (1 << Source_Offset)-1, Remainder_Bits; *Dest = (*Source & ~Mask) | (*Dest & Mask); /* First Word */ *Dest++; *Source++; Count = (Source_Offset+Bit_Count)/32-1; Remainder_Bits = (Source_Offset+Bit_Count)%POINTER_LENGTH; for(i=0; i<Count; i++) *Dest++ = *Source++; Mask = (1 << Remainder_Bits)-1; *Dest = (*Source & Mask) | (*Dest & ~Mask); *Dest_Offset_Ptr = (*Dest_Offset_Ptr+Bit_Count)%POINTER_LENGTH; *Dest_Ptr = Dest; return; } /* Shift_Bit_String continues on the next page */ \f /* Shift_Bit_String, continued */ else switch(Offset > 0) { case 1: /* Source_Offset > D_Offset */ if(D_Offset+Bit_Count <= POINTER_LENGTH) { long Temp; Mask=(1 << Bit_Count)-1; Mask = (Mask << D_Offset); Shift = POINTER_LENGTH-Offset; Temp=Down_Shift(*Source, Offset); if (Source_Offset+Bit_Count > POINTER_LENGTH) Temp |= Up_Shift(*++Source,Shift); *Dest=(Mask & Temp) | (*Dest & ~Mask); if(D_Offset+Bit_Count == POINTER_LENGTH) Dest++; D_Offset += Bit_Count%POINTER_LENGTH; *Dest_Offset_Ptr = (*Dest_Offset_Ptr+Bit_Count)%POINTER_LENGTH; *Dest_Ptr = Dest; return; } else { long Count_1, Count_2; Mask=(1 << D_Offset)-1; *Dest &= Mask; *Dest |= Down_Shift(*Source++,Offset) & ~Mask; /* Take care of first word */ Shift=POINTER_LENGTH-Offset; Mask=(1 << Shift)-1; Count_1=(Source_Offset+Bit_Count)/POINTER_LENGTH-1; Count_2=(D_Offset+Bit_Count)/POINTER_LENGTH-1; Remainder_Bits=(D_Offset+Bit_Count)%POINTER_LENGTH; if(Count_1 == Count_2) { for(i=0; i<Count_1; i++) /* Middle words */ { *Dest++ |= Up_Shift(*Source,Shift); *Dest = (*Source++ >> Offset) & Mask; } *Dest++ |= Up_Shift(*Source,Shift); /* Last Word(s) */ Mask=(1 << Remainder_Bits)-1; *Dest = (Down_Shift(*Source, Offset) & Mask) | (*Dest & ~Mask); } /* Shift_Bit_String continues on the next page */ \f /* Shift_Bit_String, continued */ else { for(i=0; i<Count_2; i++) /* Middle words */ { *Dest++ |= Up_Shift(*Source,Shift); *Dest = (*Source++ >> Offset) & Mask; } *Dest++ |= Up_Shift(*Source,Shift); /* Last Word(s) */ Mask = (1 << Remainder_Bits)-1; *Dest &= ~Mask; *Dest |= Down_Shift(*Source++,Offset) & Mask; *Dest |= Up_Shift(*Source,Shift) & Mask; } *Dest_Offset_Ptr = (*Dest_Offset_Ptr+Bit_Count) % POINTER_LENGTH; *Dest_Ptr = Dest; return; } case 0: /* Source_Offset < D_Offset */ Offset = -Offset; if(D_Offset+Bit_Count <= POINTER_LENGTH) { Mask=(1 << Bit_Count)-1; Mask=(Mask << D_Offset); *Dest = (*Dest & ~Mask) | (Mask & (*Source << Offset)); if(D_Offset+Bit_Count == POINTER_LENGTH) Dest++; D_Offset += Bit_Count%POINTER_LENGTH; *Dest_Offset_Ptr = (*Dest_Offset_Ptr+Bit_Count)%POINTER_LENGTH; *Dest_Ptr = Dest; return; } /* Shift_Bit_String continues on the next page */ \f /* Shift_Bit_String, continued */ else { Mask=(1 << D_Offset)-1; Shift=POINTER_LENGTH-Offset; Remainder_Bits=(D_Offset+Bit_Count)%POINTER_LENGTH; *Dest &= Mask; *Dest++ |= (*Source << Offset) & ~Mask; /* First Word */ Mask=(1 << Offset)-1; Count= (Bit_Count-(POINTER_LENGTH-D_Offset))/POINTER_LENGTH; for(i=0; i<Count; i++) /* Middle Words */ { *Dest = (*Source++ >> Shift) & Mask; *Dest++ |= (*Source << Offset); } if(Remainder_Bits > 0) /* Last Word patched up */ { Mask=(1 << Remainder_Bits)-1; *Dest = (Down_Shift(*Source++,Shift) & Mask) | (*Dest &= ~Mask); *Dest |= Up_Shift(*Source,Offset) & Mask; *Dest_Offset_Ptr = (*Dest_Offset_Ptr+Bit_Count) % POINTER_LENGTH; *Dest_Ptr = Dest; return; } else *Dest_Offset_Ptr = (*Dest_Offset_Ptr+Bit_Count)%POINTER_LENGTH; *Dest_Ptr = Dest; return; } } } \f /* (BUILD_STRING_FROM_LIST LIST) [Primitive number 0x5F] Takes a list of the ASCII codes for characters and converts it into a string containing those characters. For example, on input '(#/A #/B #/C) it returns "ABC". */ Built_In_Primitive(Prim_Build_String_From_List, 1, "BUILD-STRING-FROM-LIST") { Pointer Result; /* The work is done by Make_String, in file FASLOAD.C */ Primitive_1_Arg(); return Make_String(Arg1); } \f /* (EQUAL_STRING_TO_LIST STRING LIST) [Primitive number 0x60] Compares characters from the string with ASCII character codes from the LIST. Returns #!TRUE if the string and the list have the same number of characters and all the characters match. Returns NIL otherwise. */ Built_In_Primitive(Prim_Equal_String_To_List, 2, "EQUAL-STRING-TO-LIST") { long Count, i; char *Next; Pointer Next_List; Primitive_2_Args(); Arg_1_Type(TC_CHARACTER_STRING); Count = Get_Integer(Fast_Vector_Ref(Arg1, STRING_LENGTH)); Next = (char *) Nth_Vector_Loc(Arg1, STRING_CHARS); Touch_In_Primitive(Arg2, Next_List); for (i=0; (i < Count) && (Type_Code(Next_List) == TC_LIST); i++) { fast Pointer Next_Val; Touch_In_Primitive(Vector_Ref(Next_List, CONS_CAR), Next_Val); if (Type_Code(Next_Val) != TC_CHARACTER) Primitive_Error(ERR_ARG_2_WRONG_TYPE); if (*Next++ != Get_Integer(Next_Val)) return NIL; Touch_In_Primitive(Vector_Ref(Next_List, CONS_CDR), Next_List); } if ((i==Count) && (Next_List==NIL)) return TRUTH; if ((Next_List != NIL) && (Type_Code(Next_List) != TC_LIST)) Primitive_Error(ERR_ARG_2_WRONG_TYPE); return NIL; } \f /* (INSERT_STRING ORIG-STRING N INSERTION) [Primitive number 0x1D] ORIG-STRING and INSERTION must be strings. A new string is created which contains INSERTION between the (N-1)st and Nth characters of ORIG-STRING. If N is 0, this is the concatenation of INSERTION followed by ORIG-STRING. If N is (STRING_LENGTH ORIG_STRING) it is the concatenation of ORIG-STRING followed by INSERTION. Both strings are copied in the process (i.e. the new string never shares characters with the original ones). */ Built_In_Primitive(Prim_Insert_String, 3, "INSERT-STRING") { char *To, *From_New, *From_Old; long Index, Old_Length, New_Length, Length, i, Pointer_Count; Primitive_3_Args(); Arg_1_Type(TC_CHARACTER_STRING); Arg_2_Type(TC_FIXNUM); Arg_3_Type(TC_CHARACTER_STRING); Old_Length = Get_Integer(Fast_Vector_Ref(Arg1, STRING_LENGTH)); New_Length = Get_Integer(Fast_Vector_Ref(Arg3, STRING_LENGTH)); Range_Check(Index, Arg2, 0, Old_Length, ERR_ARG_2_BAD_RANGE); From_Old = (char *) Nth_Vector_Loc(Arg1, STRING_CHARS); From_New = (char *) Nth_Vector_Loc(Arg3, STRING_CHARS); To = ((char *) (Free+2)); if (Old_Length-Index >= New_Length) Length = Old_Length; else Length = Old_Length + New_Length; Pointer_Count= (sizeof(Pointer) + Length*sizeof(char))/ sizeof(Pointer); Primitive_GC_If_Needed(Free + Pointer_Count + 1); Free[NM_VECTOR_HEADER] = Make_Non_Pointer(TC_MANIFEST_NM_VECTOR, Pointer_Count+1); Free[NM_ENTRY_COUNT] = FIXNUM_0+Length; for (i=0; i < Index; i++) *To++ = *From_Old++; for (i=0; i < New_Length; i++) *To++ = *From_New++; for (i=Index; i < Old_Length; i++) *To++ = *From_Old++; *To++ = '\0'; /* Add the null */ Free += (Pointer_Count + 2); return Make_Pointer(TC_CHARACTER_STRING, Free-(Pointer_Count+2)); } \f /* (STRING_EQUAL STRING-1 STRING-2) [Primitive number 0x0E] Compare two strings for equality. This comparison is case-sensitive. */ Built_In_Primitive(Prim_String_Equal, 2, "STRING-EQUAL") { char *Finger_1, *Finger_2; long Length_1, Length_2, i; Primitive_2_Args(); Arg_1_Type(TC_CHARACTER_STRING); Arg_2_Type(TC_CHARACTER_STRING); Length_1 = Get_Integer(Fast_Vector_Ref(Arg1, STRING_LENGTH)); Length_2 = Get_Integer(Fast_Vector_Ref(Arg2, STRING_LENGTH)); if (Length_1 != Length_2) return NIL; Finger_1 = (char *) Nth_Vector_Loc(Arg1, STRING_CHARS); Finger_2 = (char *) Nth_Vector_Loc(Arg2, STRING_CHARS); for (i=0; i < Length_1; i++) if (*Finger_1++ != *Finger_2++) return NIL; return TRUTH; } \f /* (OVERWRITE_STRING ORIG-STRING POSITION NEW-STRING) [Primitive number 0x2B] Side-effects the ORIG-STRING by replacing characters starting at POSITION with characters from NEW-STRING. If POSITION is 0, the replacement is at the start of the string, and so on. It is not possible to extend the length of a string this way unless the string contains room for more characters than it currently has, which should be priviledged information. The value returned is ORIG-STRING, which will have been modified. */ Built_In_Primitive(Prim_Overwrite_String, 3, "OVERWRITE-STRING") { char *To, *From; long Max_Length, Old_Length, Addition, New_Length, Index, i; Primitive_3_Args(); Arg_1_Type(TC_CHARACTER_STRING); Arg_2_Type(TC_FIXNUM); Arg_3_Type(TC_CHARACTER_STRING); Max_Length = ((Get_Integer(Fast_Vector_Ref(Arg1, STRING_HEADER)) - 1) * (sizeof(Pointer))) - 1; Old_Length = Get_Integer(Fast_Vector_Ref(Arg1, STRING_LENGTH)); Addition = Get_Integer(Fast_Vector_Ref(Arg3, STRING_LENGTH)); Index = Get_Integer(Arg2); if (Index > Old_Length) Primitive_Error(ERR_ARG_2_BAD_RANGE); if ((New_Length = Index + Addition) > Max_Length) Primitive_Error(ERR_ARG_3_BAD_RANGE); From = (char *) Nth_Vector_Loc(Arg3, STRING_CHARS); To = (char *) Nth_Vector_Loc(Arg1, STRING_CHARS); To += Index; for (i=0; i < Addition; i++) *To++ = *From++; /* If we have gone past the bounds of the old string, add Null and adjust string length. */ if (New_Length > Old_Length) { *To++ = '\0'; Vector_Ref(Arg1, STRING_LENGTH) = FIXNUM_0 + New_Length; } for (i=0; i < New_Length; i++) *To++ = *From++; return Arg1; } \f /* (SUBSTRING STRING FROM TO) [Primitive number 0x45] Extracts the substring of STRING beginning with the FROMth character and continuing to (but not including) the TOth character. Thus (SUBSTRING S 0 (STRING_LENGTH S)) returns a copy of all of S. */ Built_In_Primitive(Prim_Substring, 3, "SUBSTRING") { char *To, *From; long Low, High, Length, Elements, i, Pointer_Count; Primitive_3_Args(); Arg_1_Type(TC_CHARACTER_STRING); Arg_2_Type(TC_FIXNUM); Arg_3_Type(TC_FIXNUM); Length = Get_Integer(Fast_Vector_Ref(Arg1, STRING_LENGTH)); Range_Check(Low, Arg2, 0, Length, ERR_ARG_2_BAD_RANGE); Range_Check(High, Arg3, 0, Length, ERR_ARG_3_BAD_RANGE); Elements = High-Low; Pointer_Count= (sizeof(Pointer) + Elements*sizeof(char))/ sizeof(Pointer); Primitive_GC_If_Needed(Free + Pointer_Count + 1); Free[0]=Make_Non_Pointer(TC_MANIFEST_NM_VECTOR, Pointer_Count+1); Free[1]=FIXNUM_0+Elements; if (Low > High) Primitive_Error(ERR_ARG_3_BAD_RANGE); To = ((char *) (Free+2)); From = (char *) Nth_Vector_Loc(Arg1, STRING_CHARS); From += Low; for (i=0; i < Elements; i++) *To++ = *From++; *To++ = '\0'; /* Add the null */ Free += Pointer_Count + 2; return Make_Pointer(TC_CHARACTER_STRING, Free-(Pointer_Count+2)); } \f /* (SUBSTRING_SEARCH STRING SUBSTRING) [Primitive number 0xB8] Returns the character position in STRING where the first occurrence of SUBSTRING begins. The search is case-sensitive. Returns NIL if the SUBSTRING does not occur. */ Built_In_Primitive(Prim_Substring_Search, 2, "SUBSTRING-SEARCH") { char *String, *Sub; long String_Length, Sub_Length, Stop_At, i, j; Primitive_2_Args(); Arg_1_Type(TC_CHARACTER_STRING); Arg_2_Type(TC_CHARACTER_STRING); String = (char *) Nth_Vector_Loc(Arg1, STRING_CHARS); Sub = (char *) Nth_Vector_Loc(Arg2, STRING_CHARS); String_Length = Get_Integer(Fast_Vector_Ref(Arg1, STRING_LENGTH)); Sub_Length = Get_Integer(Fast_Vector_Ref(Arg2, STRING_LENGTH)); Stop_At = String_Length-Sub_Length; for (i=0; i <= Stop_At; i++) { for (j=0; j < Sub_Length; j++) if (String[i+j] != Sub[j]) break; if (j == Sub_Length) return FIXNUM_0+i; } return NIL; } \f /* (SUBSTRING_TO_LIST STRING FROM TO) [Primitive number 0x4A] The same as SUBSTRING, except the result is a list of ASCII character codes rather than a string. */ Built_In_Primitive(Prim_Substring_To_List, 3, "SUBSTRING->LIST") { char *Finger; long Low, High, Length, Elements, i; Pointer Result; Primitive_3_Args(); Arg_1_Type(TC_CHARACTER_STRING); Arg_2_Type(TC_FIXNUM); Arg_3_Type(TC_FIXNUM); Length = Get_Integer(Fast_Vector_Ref(Arg1, STRING_LENGTH)); Range_Check(Low, Arg2, 0, (Length == 0)? 0 : Length-1, ERR_ARG_2_BAD_RANGE); Range_Check(High, Arg3, Low, Length, ERR_ARG_3_BAD_RANGE); Elements = High-Low; Primitive_GC_If_Needed(Free + 2 * Elements); if (Elements==0) return NIL; Finger = (char *) Nth_Vector_Loc(Arg1, STRING_CHARS); Finger += Low; Result = Make_Pointer(TC_LIST, Free); for (i=0; i < Elements; i++, Free++) { *Free++ = FIXNUM_0+(MAX_CHAR & *Finger++); *Free = Make_Pointer(TC_LIST, Free+1); } Free[-1] = NIL; return Result; } \f /* (RAISE_STRING STRING) [Primitive number 0xB3] Returns a copy of STRING with all lower-case letters changed to upper-case. */ Built_In_Primitive(Prim_Raise_String, 1, "RAISE-STRING") { long Length, Word_Length, i; char *From, *To; Primitive_1_Arg(); Arg_1_Type(TC_CHARACTER_STRING); Word_Length = 1 + Get_Integer(Fast_Vector_Ref(Arg1, STRING_HEADER)); Primitive_GC_If_Needed(Free + Word_Length); Length = Get_Integer(Fast_Vector_Ref(Arg1, STRING_LENGTH)); Free[STRING_HEADER] = Fast_Vector_Ref(Arg1, STRING_HEADER); Free[STRING_LENGTH] = FIXNUM_0+Length; From = (char *) Nth_Vector_Loc(Arg1, STRING_CHARS); To = (char *) &Free[STRING_CHARS]; for (i=0; i < Length; i++, From++, To++) { fast char c = *From; if ((c >= 'a') && (c <= 'z')) *To = c-'a'+'A'; else *To = c; } *To++ = '\0'; /* Add the null */ Free += Word_Length; return Make_Pointer(TC_CHARACTER_STRING, Free-Word_Length); } /* (RAISE_CHAR CHAR-CODE) [Primitive number 0x64] If CHAR-CODE is the ASCII code for a lower-case letter, returns the ASCII code for the upper-case letter. Otherwise returns CHAR-CODE unchanged. */ Built_In_Primitive(Prim_Raise_Char, 1, "RAISE-CHAR") { long Value; Primitive_1_Arg(); Arg_1_Type(TC_FIXNUM); Range_Check(Value, Arg1, 0, MAX_CHAR, ERR_ARG_1_BAD_RANGE); if (Value >= 'a' && Value <= 'z') Value += 'A'-'a'; return FIXNUM_0+Value; } \f /* (STRING_HASH STRING) [Primitive number 0x83] Return a hash value for a string. This uses the hashing algorithm used for interning symbols. It is intended for use by the reader in creating interned symbols. */ Built_In_Primitive(Prim_String_Hash, 1, "STRING-HASH") { Primitive_1_Arg(); Arg_1_Type(TC_CHARACTER_STRING); /* The work is done by Hash, in file FASLOAD.C */ return Hash(Arg1); } /* (STRING_LESS STRING-1 STRING-2) [Primitive number 0x59] Returns #!TRUE if STRING-1 < STRING-2 using the ASCII character code collating sequence. The test is case-sensitive. */ Built_In_Primitive(Prim_String_Less, 2, "STRING-LESS") { char *Finger_1, *Finger_2; long Length_1, Length_2, i, Count; Primitive_2_Args(); Arg_1_Type(TC_CHARACTER_STRING); Arg_2_Type(TC_CHARACTER_STRING); Length_1 = Get_Integer(Fast_Vector_Ref(Arg1, STRING_LENGTH)); Length_2 = Get_Integer(Fast_Vector_Ref(Arg2, STRING_LENGTH)); if (Length_1 < Length_2) Count=Length_1; else Count=Length_2; Finger_1 = (char *) Nth_Vector_Loc(Arg1, STRING_CHARS); Finger_2 = (char *) Nth_Vector_Loc(Arg2, STRING_CHARS); for (i=0; i<Count; i++, Finger_1++, Finger_2++) if (*Finger_1 == *Finger_2) continue; else return (*Finger_1 < *Finger_2) ? TRUTH : NIL; if (Length_1 < Length_2) return TRUTH; else return NIL; } \f /* (STRING_POSITION STRING MASK CHARACTER) [Primitive number 0x58] Scans STRING one character at a time looking for a character which is the same as CHARACTER when both are compared after masking them with MASK. If MASK=255 (the usual case) it will look for an exact match. If MASK=255-32=223 then it "ignores" the bit which (in ASCII) differentiates upper and lower case letters, etc. Returns the position of the match, or NIL if one isn't found. */ Built_In_Primitive(Prim_String_Position, 3, "STRING-POSITION") { char *Finger; long Length, Character, Mask, i; Primitive_3_Args(); Arg_1_Type(TC_CHARACTER_STRING); Arg_2_Type(TC_FIXNUM); Arg_3_Type(TC_FIXNUM); Range_Check(Mask, Arg2, 0, MAX_CHAR, ERR_ARG_2_BAD_RANGE); Range_Check(Character, Arg3, 0, MAX_CHAR, ERR_ARG_3_BAD_RANGE); Length = Get_Integer(Fast_Vector_Ref(Arg1, STRING_LENGTH)); Finger= (char *) Nth_Vector_Loc(Arg1, STRING_CHARS); /* The test is made by finding all bits where the character from the string and the argument character differ (using XOR, ^). This is then masked and tested to see if the only differences are in bits that the mask ignores. */ for (i=0; i<Length; i++) if ((Mask & (*Finger++ ^ Character)) == 0) return FIXNUM_0+i; return NIL; } \f /* (TRUNCATE_STRING STRING INDEX) [Primitive number 0x44] A side-effecting string primitive. Lops off the characters in STRING from INDEX on, leaving the maximum size (i.e. the GC size) of STRING the same. Returns STRING. */ Built_In_Primitive(Prim_Truncate_String, 2, "TRUNCATE-STRING") { long Length, Index, i; char *To; Primitive_2_Args(); Arg_1_Type(TC_CHARACTER_STRING); Arg_2_Type(TC_FIXNUM); Length = Get_Integer(Fast_Vector_Ref(Arg1, STRING_LENGTH)); Sign_Extend(Arg2, Index); if (Index < 0) Primitive_Error(ERR_ARG_2_BAD_RANGE); if (Index <= Length) Vector_Ref(Arg1,STRING_LENGTH) = FIXNUM_0+Index; /* Now add a null after the last valid positon */ To = (char *) &Vector_Ref(Arg1, STRING_CHARS); for (i=0; i < Index; i++) To++; *To = '\0'; return Arg1; } \f /* (VECTOR_8B? OBJECT) [Primitive number 0xA4] Returns #!TRUE if OBJECT is an 8-bit vector (a string). */ Built_In_Primitive(Prim_Vector_8b, 1, "VECTOR-8B?") { Primitive_1_Arg(); Touch_In_Primitive(Arg1, Arg1); return (Type_Code(Arg1) == TC_VECTOR_8B) ? TRUTH : NIL; } /* (VECTOR_8B_CONS LENGTH) [Primitive number 0xA3] Creates an uninitialized 8-bit vector (string) to hold LENGTH characters. */ Built_In_Primitive(Prim_Vector_8b_Cons, 1, "VECTOR-8B-CONS") { long Length; Primitive_1_Arg(); Arg_1_Type(TC_FIXNUM); Length = NM_HEADER_LENGTH + (sizeof(char)*Get_Integer(Arg1)) / sizeof(Pointer) + 1; Primitive_GC_If_Needed(Free+Length); Free[NM_VECTOR_HEADER] = Make_Non_Pointer(TC_MANIFEST_NM_VECTOR, Length-1); Free[NM_ENTRY_COUNT] = FIXNUM_0+Get_Integer(Arg1); Free += Length; return Make_Pointer(TC_VECTOR_8B, Free-Length); } \f /* (VECTOR_8B_REF STRING OFFSET) [Primitive number 0xA5] Returns the OFFSETth entry (character) in the 8-bit vector (string). Entries are numbered from 0. */ Built_In_Primitive(Prim_Vector_8b_Ref, 2, "VECTOR-8B-REF") { long Index; char *String_Ptr; Primitive_2_Args(); Arg_1_Type(TC_VECTOR_8B); Arg_2_Type(TC_FIXNUM); Range_Check(Index, Arg2, 0, Get_Integer(Fast_Vector_Ref(Arg1,STRING_LENGTH))-1, ERR_ARG_2_BAD_RANGE); String_Ptr = (char *) Nth_Vector_Loc(Arg1, STRING_CHARS); return Make_Non_Pointer(TC_CHARACTER, (String_Ptr[Index]) & MAX_CHAR); } /* (VECTOR_8B_SET STRING OFFSET VALUE) [Primitive number 0xA6] Stores VALUE (which must be a fixnum between 0 and 255) as the OFFSETth entry (character) in the 8-bit vector (string). Returns (bad style to rely on this) the previous value of the entry. */ Built_In_Primitive(Prim_Vec_8b_Set, 3, "VECTOR-8B-SET!") { long Index, Value; char *String_Ptr; Primitive_3_Args(); Arg_1_Type(TC_VECTOR_8B); Arg_2_Type(TC_FIXNUM); Range_Check(Index, Arg2, 0, Get_Integer(Fast_Vector_Ref(Arg1,STRING_LENGTH))-1, ERR_ARG_2_BAD_RANGE); Arg_3_Type(TC_CHARACTER); Range_Check(Value, Arg3, 0, MAX_CHAR, ERR_ARG_3_BAD_RANGE); String_Ptr = (char *) Nth_Vector_Loc(Arg1, STRING_CHARS); Value = Make_Non_Pointer(TC_CHARACTER, (String_Ptr[Index]) & MAX_CHAR); String_Ptr[Index] = (char) Get_Integer(Arg3); return Value; } \f /* (VECTOR_8B_SIZE STRING) [Primitive number 0xAD] Returns the number of entries (characters) in the 8-bit vector (string). */ Built_In_Primitive(Prim_Vec_8b_Size, 1, "VECTOR-8B-SIZE") { Primitive_1_Arg(); Arg_1_Type(TC_VECTOR_8B); return Fast_Vector_Ref(Arg1, NM_ENTRY_COUNT); }